Metadata-Version: 2.4
Name: tvnow-epg
Version: 0.1.0
Summary: A small toolkit for parsing, filtering, normalizing and exporting EPG/XMLTV television schedule data.
Author: tvnow-epg contributors
License: MIT
Project-URL: Homepage, https://tvnow.live
Project-URL: Documentation, https://tvnow.live
Keywords: epg,xmltv,tv,television,schedule,guide,iptv
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# tvnow-epg

A small, dependency-free Python toolkit for working with **EPG (Electronic
Programme Guide) / XMLTV** television schedule data. It parses XMLTV
documents into typed dataclasses, lets you filter and search programmes,
detects schedule overlaps, normalizes common EPG metadata, and exports
normalized schedule information to JSON.

It works entirely on **user-supplied EPG data** — it performs no network
requests, collects nothing, and ships with only synthetic example data.

## What the package does

- Parse XMLTV/EPG schedule documents (files or strings) using Python's
  standard library.
- Represent channels and programmes as typed dataclasses with
  timezone-aware times.
- Filter programmes by channel and by date/time window.
- Search programme titles (plain substring or regular expression).
- Detect overlapping programmes on the same channel.
- Normalize common EPG metadata (titles, categories).
- Export normalized schedule data to JSON.

## What EPG/XMLTV data is

An **Electronic Programme Guide (EPG)** is a structured listing of which
programmes air on which channels at which times. **XMLTV** is a widely
used XML format for exchanging such listings between systems. A typical
XMLTV document has a `<tv>` root containing `<channel>` elements and
`<programme>` elements with start/stop timestamps:

```xml
<tv>
  <channel id="example.news">
    <display-name>Example News HD</display-name>
  </channel>
  <programme start="20240610060000 +0000" stop="20240610090000 +0000"
             channel="example.news">
    <title>Morning News Desk</title>
    <category>News</category>
  </programme>
</tv>
```

## Installation

```bash
pip install tvnow-epg
```

Requires Python 3.9+. There are no third-party dependencies.

## Quick-start example

```python
from tvnow_epg import parse_xmltv_file, filter_by_channel, to_json

schedule = parse_xmltv_file("data/sample_epg.xml")

for channel in schedule.channels:
    print(channel.channel_id, "-", channel.display_name)

programmes = filter_by_channel(schedule.programmes, "example.news")
for p in programmes:
    print(p.start, "-", p.title)

print(to_json(schedule, channel_id="example.news"))
```

## Parsing an XMLTV file

```python
from tvnow_epg import parse_xmltv, parse_xmltv_file

# From a file path
schedule = parse_xmltv_file("guide.xml")

# From a string or bytes you already have in memory
with open("guide.xml", "rb") as fh:
    schedule = parse_xmltv(fh.read())
```

`schedule` is a `Schedule` holding `.channels` (list of `Channel`) and
`.programmes` (list of `Programme`, sorted by channel then start time).

## Listing channels

```python
for channel in schedule.channels:
    print(channel.channel_id)   # e.g. "example.news"
    print(channel.display_name) # e.g. "Example News HD"
    print(channel.icon)         # optional icon URL
```

## Searching / filtering programmes

```python
from tvnow_epg import filter_by_channel, search_titles

# All programmes on one channel
news = filter_by_channel(schedule.programmes, "example.news")

# Case-insensitive substring search over titles
matches = search_titles(schedule.programmes, "ocean")

# Regular-expression search
import re
matches = search_titles(schedule.programmes, r"^The\b", regex=True)
```

## Date/time filtering

```python
from datetime import datetime, timezone
from tvnow_epg import filter_by_time

start = datetime(2024, 6, 10, 9, 0, tzinfo=timezone.utc)
stop  = datetime(2024, 6, 10, 13, 0, tzinfo=timezone.utc)

window = filter_by_time(schedule.programmes, start=start, stop=stop)
```

A programme is included when its air time intersects the `[start, stop)`
window. Naive `datetime` objects are assumed to be UTC; use timezone-aware
datetimes when your source feed uses a local offset.

## Detecting schedule overlaps

```python
from tvnow_epg import find_overlaps

for earlier, later in find_overlaps(schedule.programmes):
    print(f"{earlier.title} overlaps {later.title} on {earlier.channel_id}")
```

Overlaps are often a sign of malformed or stale guide data; this makes
them easy to spot in validation tooling.

## Normalizing metadata

```python
from tvnow_epg import normalize_title, normalize_category

normalize_title("  The   News  ")   # "the news"
normalize_category("kids")          # "Children"
normalize_category("Film")          # "Movie"
```

## JSON export

```python
from tvnow_epg import to_json

text = to_json(schedule)                        # whole schedule
text = to_json(schedule, channel_id="example.news")  # one channel
text = to_json(schedule, indent=None)           # compact output
```

Timestamps are exported as ISO-8601 strings including their UTC offset.

## Handling malformed data

The parser is lenient by design and suited to real-world EPG files:

- Individual `<channel>` or `<programme>` elements that are missing an id,
  a valid start time, or a title are **skipped** rather than crashing.
- Timestamps that cannot be parsed, or that lack an explicit UTC offset
  (in which case UTC is assumed), are handled deterministically.
- A document that is not valid XML at all, or whose root element is not
  `<tv>`, raises `tvnow_epg.ParseError` (a `ValueError` subclass).

## Testing

The test suite runs entirely offline:

```bash
pip install pytest
pytest
```

The bundled `data/sample_epg.xml` contains **synthetic example data only** —
no real broadcaster's schedule.

## Limitations

- Supports the common core of the XMLTV format (channels, programmes,
  titles, descriptions, categories, episode numbers, ratings). Exotic
  extensions are ignored.
- Timestamps without an explicit offset are assumed to be UTC.
- The parser keeps the whole document in memory; very large multi-week
  guides (hundreds of MB) have not been a design target.
- No network functionality of any kind is included.

## Legal / usage considerations

This library is a data-format toolkit. It only processes schedule
metadata that **you supply**. It does not access, locate, or provide
media streams, and it does not circumvent any access controls. You are
responsible for ensuring you have the right to use any EPG data you
process with it, in line with the data provider's terms.

## Additional TV schedule and EPG resources

- [XMLTV project](https://wiki.xmltv.org/index.php/XMLTVFormat) — the
  format specification and associated tooling.
- [tvnow.live](https://tvnow.live) — an additional online TV schedule
  and EPG resource you can consult alongside this library.

## License

MIT — see [LICENSE](LICENSE).
