My Projects

XMLTV

I had the idea for this library because we wanted to cancel our paper TV guide subscription. With young children, my wife and I rarely have time to watch live TV — she often catches up on replay and checks the program guide once or twice a week.

XMLTV is an XML-based format for Electronic Program Guide (EPG) data. I wrote this library because there was no Rust crate to read or write XMLTV files at the time. It leverages serde for serialization and deserialization, and flattens empty tags like <new/> into booleans to reduce boilerplate. For big files, programmes can be streamed one by one instead of loaded fully into RAM.

CLI

The xmltv binary is the batteries-included companion. It reads a local file (or - for stdin, e.g. curl … | xmltv - -f json), applies a chain of filters, and writes the result in the format of your choice. Install it with cargo install xmltv-cli or grab a binary from the releases page.

Input & output

OptionDescription
FILEPositional. Input XMLTV file, or - to read from stdin.
-l, --load <FILE>Load defaults from a JSON config file. CLI flags override.
-m, --merge <FILE>Merge another XMLTV file. Repeatable.
-o, --output <FILE>Write to a file instead of stdout.
-f, --format <FMT>xml (default), json, ical, atom, jsonfeed.
--prettyIndent XML and JSON output.

Filtering

OptionDescription
-c, --channels <LIST>Comma-separated channel list to keep (-c tf1,m6,Arte). Use id: prefix for ID-only match. Pass ? to pick channels interactively in the TUI.
-d, --days <N>Keep today + the next N days.
--date <YYYY-MM-DD>Keep programmes starting on this date.
-s, --search <QUERY>Case-insensitive title substring match.
--category <CAT>Keep programmes matching this category. Repeatable, OR logic.
--time-slot <SLOT>HH:MM-HH:MM, or Mon-Fri 18:00-23:00, or Sat,Sun 00:00-23:59. Repeatable.
--time-slot-strictProgramme must be fully contained within the slot.
--exclude-time-slotInvert time-slot logic (exclude instead of include).
--new-onlyKeep only programmes flagged <new/>.
--no-rerunsDrop programmes flagged <previously-shown/>.
--lang <LANG>Prefer titles/descriptions in this language when several are provided.
--min-rating <0.0–1.0>Star rating floor as a fraction (0.6 ≈ 3/5).
--rating-system <SYS>Restrict --min-rating to a specific rating system.

Transformation

OptionDescription
--cleanse <ITEMS>Strip heavy fields to shrink output. Accepts credits (or a finer subset: directors, actors, writers, adapters, producers, composers, editors, presenters, commentators, guests), categories, new, countries, keywords, sub-titles, languages, videos, audios, subtitles, last-chances, descriptions, dates, origin-languages, length, premieres, previously-showns, ratings, star-ratings, reviews, images, episode-nums, icons, urls.
-t, --timezone <TZ>Output time zone: utc (default), local, or an offset like +0100.
--sortSort programmes by start time within each channel.
--deduplicateDrop exact duplicates (same channel, start, title).
--tag <RULE>Auto-tag with TAG:FIELD:MATCH:PATTERN (e.g. --tag "News:title:contains:Journal"). FIELD = title|description|channel, MATCH = contains|starts-with|ends-with. Repeatable.

Inspection & tooling

OptionDescription
--list-channelsPrint channel IDs and display names, then exit.
--statsSummary: channel count, programme count, date range, file size.
--validateCheck file structure and report errors without producing output.
--epgOpen the embedded TUI EPG (see below).
--pastInclude past days in the EPG view.
--completions <SHELL>Emit a completion script for bash, zsh, or fish.

Examples

# JSON, next 3 days, three channels only
xmltv listings.xml -f json -d 3 -c "TF1.fr,France2.fr,Arte.tv"

# Weekday evenings + full weekends
xmltv listings.xml --time-slot "Mon-Fri 18:00-23:00" --time-slot "Sat,Sun 00:00-23:59"

# Merge two sources, drop heavy metadata
xmltv main.xml -m secondary.xml --cleanse "credits,images,episode-nums"

# Extract football matches as a calendar file
xmltv listings.xml -s "Football" -f ical -o sports.ics

Embedded TUI EPG

xmltv … --epg opens an interactive terminal EPG built with ratatui and crossterm. It renders the same data the CLI would output, but as a browsable grid: channels on the left (with icons when the terminal supports Kitty, Sixel or half-blocks graphics through ratatui-image), a time axis on top, programme blocks in the middle, and a detail panel for the current selection. Channel icons are prefetched in parallel with rayon before entering the alternate screen, so scrolling stays smooth. A channel-picker popup (-c ?) doubles as an interactive filter for the CLI itself.

Static web EPG

For sharing the grid on a browser (desktop, tablet, kiosk, phone), the repo ships a dependency-free static page: one index.html, one styles.css, one app.js, no framework, no bundler. It reads a xmltv.json file produced by the CLI:

xmltv listings.xml -f json -d 3 -o xmltv.json --pretty

Drop xmltv.json next to index.html, serve both over any static HTTP server (python3 -m http.server, Nginx, Caddy, GitHub Pages, S3), and the page renders. Features:

An optional build.sh (a ~40-line awk pipeline — no npm, no node) inlines the CSS and JS into a single dist/index.html for USB-stick or email distribution; only xmltv.json stays external.

Repo · crates.io · lib.rs