Seek to each offset, extract elements for *tvg_id*, return the first one currently airing. Chunk-based so it works on minified XML.
(file_path, tvg_id, offsets, now)
| 4658 | |
| 4659 | |
| 4660 | def _read_programs_at_offsets(file_path, tvg_id, offsets, now): |
| 4661 | """ |
| 4662 | Seek to each offset, extract <programme> elements for *tvg_id*, return the |
| 4663 | first one currently airing. Chunk-based so it works on minified XML. |
| 4664 | """ |
| 4665 | PROG_CLOSE = b'</programme>' |
| 4666 | CLOSE_LEN = len(PROG_CLOSE) |
| 4667 | READ_SIZE = 2 * 1024 * 1024 # 2MB per read |
| 4668 | |
| 4669 | with open(file_path, 'rb') as f: |
| 4670 | for offset in offsets: |
| 4671 | f.seek(offset) |
| 4672 | buf = bytearray() |
| 4673 | done = False |
| 4674 | |
| 4675 | while not done: |
| 4676 | chunk = f.read(READ_SIZE) |
| 4677 | if not chunk and not buf: |
| 4678 | break |
| 4679 | buf.extend(chunk) |
| 4680 | search_from = 0 |
| 4681 | |
| 4682 | while True: |
| 4683 | tag_start, tag_end = _find_programme_tag(buf, search_from) |
| 4684 | if tag_start == -1: |
| 4685 | break |
| 4686 | if tag_end == -1 and chunk: |
| 4687 | break # incomplete tag, need more data |
| 4688 | |
| 4689 | # Check channel before searching for close tag |
| 4690 | m = _CHANNEL_ATTR_RE.search( |
| 4691 | buf, |
| 4692 | tag_start, |
| 4693 | tag_end + 1 if tag_end != -1 else tag_start + _MAX_START_TAG, |
| 4694 | ) |
| 4695 | if not m: |
| 4696 | search_from = ( |
| 4697 | (tag_end + 1) |
| 4698 | if tag_end != -1 |
| 4699 | else (tag_start + _PROGRAMME_TAG_LEN) |
| 4700 | ) |
| 4701 | continue |
| 4702 | |
| 4703 | ch = _decode_channel_id(m.group(1) or m.group(2)) |
| 4704 | if ch != tvg_id: |
| 4705 | done = True # different channel, end of block |
| 4706 | break |
| 4707 | |
| 4708 | # Find the closing </programme> tag |
| 4709 | close_pos = buf.find( |
| 4710 | PROG_CLOSE, tag_end + 1 if tag_end != -1 else m.end() |
| 4711 | ) |
| 4712 | if close_pos == -1: |
| 4713 | if not chunk: |
| 4714 | done = True # EOF with no close tag |
| 4715 | break # need more data |
| 4716 | close_end = close_pos + CLOSE_LEN |
| 4717 |
no test coverage detected