Metadata-Version: 2.4
Name: mediathekwatch
Version: 0.1.0
Summary: Monitor ARD Mediathek series for new episodes and download them via yt-dlp
Author: Stefan Meinecke
License: MIT
License-File: LICENSE
Requires-Python: <4.0,>=3.10
Requires-Dist: duckdb>=1.0
Requires-Dist: requests>=2.32
Description-Content-Type: text/markdown

# 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

- Python 3.10+
- [uv](https://docs.astral.sh/uv/)
- [yt-dlp](https://github.com/yt-dlp/yt-dlp) installed and available in `$PATH`

## Installation

```bash
# 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

```bash
mediathekwatch add "https://www.ardmediathek.de/serie/feuer-und-flamme/staffel-11/Y3JpZDovL3dkci5kZS9mZXVlcnVuZGZsYW1tZQ/11" --name "Feuer und Flamme"
```

ZDF Mediathek URLs are also supported:

```bash
mediathekwatch add "https://www.zdf.de/serien/die-anstalt" --name "Die Anstalt"
```

Assign to a group (see [Groups](#groups)):

```bash
mediathekwatch add "https://www.ardmediathek.de/serie/..." --name "My Show" --group "TVShows"
```

### List monitored series

```bash
mediathekwatch list
```

### Check for new episodes (intended for cron)

```bash
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:

```bash
mediathekwatch check --silent
```

### Force redownload of a specific episode

```bash
# 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

```bash
mediathekwatch download "https://www.ardmediathek.de/serie/feuer-und-flamme/staffel-11/Y3JpZDovL3dkci5kZS9mZXVlcnVuZGZsYW1tZQ/11" --target /mnt/media/TVShows
```

Works with ZDF Mediathek too:

```bash
mediathekwatch download "https://www.zdf.de/serien/die-anstalt" --target /mnt/media/TVShows
```

### Remove a series

```bash
# 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

```bash
mediathekwatch group create "TVShows" --target /mnt/media/TVShows
```

### List groups

```bash
mediathekwatch group list
```

### Update a group

```bash
mediathekwatch group update "TVShows" --name "TV Shows" --target /mnt/media/TV
```

### Delete a group

```bash
mediathekwatch group delete "TVShows"
```

### Move a series to a group

```bash
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):

```cron
0 */6 * * * /path/to/uv run mediathekwatch check --target /mnt/media/TVShows
```

Or if installed globally:

```cron
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 folders
- `monitored_series` — series being tracked
- `downloaded_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_episodes` table; use `redownload` to override.

## Acknowledgments

- Thanks to the [MediathekView](https://mediathekview.de/) project for providing valuable insights into the structure of German public media APIs.

## Development

```bash
# Run tests
uv run pytest

# Type check
uv run pyright
```
