MediathekWatch
A Python CLI tool to monitor ARD Mediathek, ARTE.tv, and ZDF Mediathek series for new episodes and automatically download them using yt-dlp. State is tracked in a local DuckDB database.
Requirements
Installation
# Clone or navigate to the project
cd /path/to/mediathekwatch
# Install with uv
uv sync
# Or install as editable
uv pip install -e .
Usage
The tool is installed as mediathekwatch command:
Add a series to monitor
mediathekwatch add "https://www.ardmediathek.de/serie/feuer-und-flamme/staffel-11/Y3JpZDovL3dkci5kZS9mZXVlcnVuZGZsYW1tZQ/11" --name "Feuer und Flamme"
ZDF Mediathek URLs are also supported:
mediathekwatch add "https://www.zdf.de/serien/die-anstalt" --name "Die Anstalt"
Assign to a group (see Groups):
mediathekwatch add "https://www.ardmediathek.de/serie/..." --name "My Show" --group "TVShows"
List monitored series
mediathekwatch list
Check for new episodes (intended for cron)
mediathekwatch check --target /mnt/media/TVShows
# Silent mode (suppress all output)
mediathekwatch check --target /mnt/media/TVShows --silent
When groups are configured, each group downloads to its own target folder and --target is not allowed:
mediathekwatch check --silent
Force redownload of a specific episode
# By series ID
mediathekwatch redownload 1 11 5 --target /mnt/media/TVShows
# By series name
mediathekwatch redownload "Feuer und Flamme" 11 5 --target /mnt/media/TVShows
If --target is omitted, the episode downloads to the series' group folder.
Download all episodes from a series URL
mediathekwatch download "https://www.ardmediathek.de/serie/feuer-und-flamme/staffel-11/Y3JpZDovL3dkci5kZS9mZXVlcnVuZGZsYW1tZQ/11" --target /mnt/media/TVShows
Works with ZDF Mediathek too:
mediathekwatch download "https://www.zdf.de/serien/die-anstalt" --target /mnt/media/TVShows
Remove a series
# By ID
mediathekwatch remove 1
# By name
mediathekwatch remove "Feuer und Flamme"
Groups
Groups let you organize series into separate download destinations. Each group has its own target folder. When any non-default group exists, check uses group folders instead of --target.
Create a group
mediathekwatch group create "TVShows" --target /mnt/media/TVShows
List groups
mediathekwatch group list
Update a group
mediathekwatch group update "TVShows" --name "TV Shows" --target /mnt/media/TV
Delete a group
mediathekwatch group delete "TVShows"
Move a series to a group
mediathekwatch set-group "Feuer und Flamme" "TVShows"
Global Options
--db PATH— Path to DuckDB database (default:~/.config/mediathekwatch/mediathekwatch.db)--target PATH— Target folder for downloads (default: current directory)
Cron Setup
Add to your crontab (e.g., every 6 hours):
0 */6 * * * /path/to/uv run mediathekwatch check --target /mnt/media/TVShows
Or if installed globally:
0 */6 * * * /home/user/.local/bin/mediathekwatch check --target /mnt/media/TVShows
Filename Format
Downloaded episodes are organized as:
<Target Folder>/<Series Name>/S<Season>/<Series> - S<season>E<episode> - <episode name>.mkv
Example:
/mnt/media/TVShows/Feuer und Flamme/S11/Feuer und Flamme - S11E05 - Der neue Fall.mkv
Database Schema
Three tables are maintained in DuckDB:
groups— download groups with target foldersmonitored_series— series being trackeddownloaded_episodes— episodes already downloaded
Project Structure
src/mediathekwatch/
├── __init__.py # Package init
├── main.py # CLI entry point
├── cli.py # Command handlers
├── models.py # Episode/Series dataclasses
├── database.py # DuckDB interface
├── api/ # API clients (ARD, ARTE, ZDF)
└── download.py # yt-dlp wrapper & filename utils
Notes
- The tool queries ARD Mediathek, ARTE.tv EMAC, and ZDF GraphQL APIs to discover episodes.
- yt-dlp is invoked with flags for embedding thumbnails, subtitles, metadata, chapters, and info-json.
- Episodes are skipped if they already exist in the
downloaded_episodestable; useredownloadto override.
Acknowledgments
- Thanks to the MediathekView project for providing valuable insights into the structure of German public media APIs.
Development
# Run tests
uv run pytest
# Type check
uv run pyright
Metadata
Release files for mediathekwatch 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mediathekwatch-0.1.1.tar.gz | 76.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mediathekwatch-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 100.4 kB
Release files / mediathekwatch-0.1.1.tar.gz
| Download URL | mediathekwatch-0.1.1.tar.gz |
|---|---|
| Size | 76.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a367d51968daeb9bdc1ee3ca230cfdbd1d5a4874e6153d7c8d502aab74257435
|
|
BLAKE2b-256 checksum How to use checksums |
c78e651522810bda74cd39be878dc104167b190331d012c0a5ed607d7fe15c25
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / mediathekwatch-0.1.1-py3-none-any.whl
| Download URL | mediathekwatch-0.1.1-py3-none-any.whl |
|---|---|
| Size | 24.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e50074e2852c115ec6fad30379754a7cdb75c6924575014230285327c600d418
|
|
BLAKE2b-256 checksum How to use checksums |
cbf2589a25d695de965c412dc16d95d02e1deccdf8e36a1aee2b3186748423a2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|