diff --git a/Dockers/f1tv-epg/.dockerignore b/Dockers/f1tv-epg/.dockerignore new file mode 100644 index 0000000..30271e5 --- /dev/null +++ b/Dockers/f1tv-epg/.dockerignore @@ -0,0 +1,6 @@ +.git +.gitignore +.dockerignore +docker-compose*.yml +README.md +data diff --git a/Dockers/f1tv-epg/.gitignore b/Dockers/f1tv-epg/.gitignore new file mode 100644 index 0000000..0c54f60 --- /dev/null +++ b/Dockers/f1tv-epg/.gitignore @@ -0,0 +1,2 @@ +data/ +.env diff --git a/Dockers/f1tv-epg/Dockerfile b/Dockers/f1tv-epg/Dockerfile new file mode 100644 index 0000000..fde9b3c --- /dev/null +++ b/Dockers/f1tv-epg/Dockerfile @@ -0,0 +1,31 @@ +FROM python:3.12-slim + +ARG F1TV_EPG_REPO=https://github.com/J-Lich/F1TV-EPG.git +ARG F1TV_EPG_REF=main + +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + OUTPUT_DIR=/output \ + OUTPUT_FILE=guide.xml \ + REFRESH_INTERVAL_MINUTES=15 \ + RUN_ONCE=0 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends git ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +RUN git clone --depth 1 --branch "$F1TV_EPG_REF" "$F1TV_EPG_REPO" . \ + && pip install --no-cache-dir -r requirements.txt \ + && rm -rf .git .github + +COPY entrypoint.sh /app/entrypoint.sh +RUN chmod +x /app/entrypoint.sh + +VOLUME ["/output"] + +HEALTHCHECK --interval=30m --timeout=5s --start-period=5m --retries=3 \ + CMD test -s "$OUTPUT_DIR/$OUTPUT_FILE" + +ENTRYPOINT ["/app/entrypoint.sh"] diff --git a/Dockers/f1tv-epg/README.md b/Dockers/f1tv-epg/README.md new file mode 100644 index 0000000..3b2b5cc --- /dev/null +++ b/Dockers/f1tv-epg/README.md @@ -0,0 +1,93 @@ +# F1TV EPG + +Docker-wrapper rond [J-Lich/F1TV-EPG](https://github.com/J-Lich/F1TV-EPG). De container +haalt de F1TV-schema's op en schrijft een XMLTV-bestand (`guide.xml`) naar een gemount +volume. Geschikt als EPG-bron in IPTV-clients, Plex, Jellyfin, enz. + +## Snel starten + +```bash +docker build -t f1tv-epg . +docker run -d --name f1tv-epg \ + -v /pad/naar/epg:/output \ + f1tv-epg +``` + +De EPG verschijnt als `/pad/naar/epg/guide.xml`. De container blijft draaien en ververst +het bestand standaard elke 15 minuten, zodat de gids vrijwel live blijft. + +Of gebruik `docker-compose.example.yml`: + +```bash +cp docker-compose.example.yml docker-compose.yml +docker compose up -d +``` + +Het volume staat standaard op `./data`, dus de EPG komt in `./data/guide.xml`. + +## Eenmalig genereren + +Voor een cronjob of handmatige run: + +```bash +docker run --rm -e RUN_ONCE=1 -v /pad/naar/epg:/output f1tv-epg +``` + +Of met Compose: + +```bash +docker compose run --rm -e RUN_ONCE=1 f1tv-epg +``` + +## Configuratie + +| Env | Default | Betekenis | +| --- | --- | --- | +| `OUTPUT_DIR` | `/output` | Map waar het XMLTV-bestand wordt geschreven | +| `OUTPUT_FILE` | `guide.xml` | Bestandsnaam van het XMLTV-bestand | +| `REFRESH_INTERVAL_MINUTES` | `15` | Minuten tussen twee verversingen (continu draaien) | +| `RUN_ONCE` | `0` | `1` = eenmalig genereren en stoppen | + +Een lager interval betekent vaker verversen en dus meer verzoeken naar de F1TV-API. +`15` minuten is ruim voldoende voor een normale gids; gebruik bijvoorbeeld `60` als je +minder verkeer wilt. + +## Werking + +1. De container start en genereert direct een eerste EPG. +2. Het script draait in een tijdelijke submap van het output-volume. +3. Bij succes wordt `guide.xml` atomisch naar de eindlocatie verplaatst, zodat een + IPTV-client nooit een half geschreven bestand leest. +4. Bij een fout blijft de laatst bekende `guide.xml` staan en wordt het na het volgende + interval opnieuw geprobeerd. +5. Daarna volgt elke `REFRESH_INTERVAL_MINUTES` minuten een nieuwe generatie. De container + blijft dus actief als achtergronddienst; met `restart: unless-stopped` in Compose start + hij ook na een reboot of crash weer op. + +## Kanaal-ID + +Het upstream-script hardcodeert het kanaal als: + +- **Channel ID:** `f1tv` +- **Display name:** `F1TV` + +Gebruik in je IPTV-client dus `tvg-id="f1tv"` (of een alias daarvoor) om de gids te +koppelen. Het script ondersteunt ondanks de upstream-README geen `--id`, `--name` of +`--output`; deze wrapper respecteert daarom de vaste kanaalgegevens en regelt alleen de +outputlocatie en het verversen. + +## Bouwen vanaf een specifieke upstream-versie + +Standaard wordt `main` gekloond tijdens de build. Je kunt een andere branch, tag of commit +vastzetten: + +```bash +docker build \ + --build-arg F1TV_EPG_REF= \ + -t f1tv-epg . +``` + +## Bron + +- Upstream repo: +- Gegenereerde gids van upstream: diff --git a/Dockers/f1tv-epg/docker-compose.example.yml b/Dockers/f1tv-epg/docker-compose.example.yml new file mode 100644 index 0000000..c852b3b --- /dev/null +++ b/Dockers/f1tv-epg/docker-compose.example.yml @@ -0,0 +1,11 @@ +services: + f1tv-epg: + build: . + container_name: f1tv-epg + volumes: + - ./data:/output + environment: + OUTPUT_FILE: "guide.xml" + REFRESH_INTERVAL_MINUTES: "15" + # RUN_ONCE: "1" # eenmalig genereren en stoppen + restart: unless-stopped diff --git a/Dockers/f1tv-epg/entrypoint.sh b/Dockers/f1tv-epg/entrypoint.sh new file mode 100755 index 0000000..cc88db0 --- /dev/null +++ b/Dockers/f1tv-epg/entrypoint.sh @@ -0,0 +1,61 @@ +#!/bin/sh +set -eu + +OUTPUT_DIR="${OUTPUT_DIR:-/output}" +OUTPUT_FILE="${OUTPUT_FILE:-guide.xml}" +REFRESH_INTERVAL_MINUTES="${REFRESH_INTERVAL_MINUTES:-15}" +RUN_ONCE="${RUN_ONCE:-0}" + +log() { + printf '%s %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$*" +} + +generate() { + tmp_dir="$OUTPUT_DIR/.f1tv-epg.tmp" + rm -rf "$tmp_dir" + mkdir -p "$tmp_dir" + + log "Generating F1TV EPG" + status=0 + if (cd "$tmp_dir" && python3 -u /app/f1tv_epg.py); then + if mv -f "$tmp_dir/guide.xml" "$OUTPUT_DIR/$OUTPUT_FILE"; then + log "EPG written to $OUTPUT_DIR/$OUTPUT_FILE" + else + status=$? + log "Failed to move EPG into place" >&2 + fi + else + status=$? + log "EPG generation failed; keeping existing $OUTPUT_DIR/$OUTPUT_FILE" >&2 + fi + + rm -rf "$tmp_dir" + return "$status" +} + +trap 'log "Stopping"; exit 0' INT TERM + +mkdir -p "$OUTPUT_DIR" + +if [ "$RUN_ONCE" = "1" ]; then + generate + exit $? +fi + +case "$REFRESH_INTERVAL_MINUTES" in + ''|*[!0-9]*) + log "REFRESH_INTERVAL_MINUTES must be a positive integer" >&2 + exit 1 + ;; +esac + +if [ "$REFRESH_INTERVAL_MINUTES" -le 0 ]; then + log "REFRESH_INTERVAL_MINUTES must be greater than 0" >&2 + exit 1 +fi + +while true; do + generate || true + log "Next EPG refresh in ${REFRESH_INTERVAL_MINUTES}m" + sleep $((REFRESH_INTERVAL_MINUTES * 60)) +done diff --git a/Dockers/f1tv-epg/version b/Dockers/f1tv-epg/version new file mode 100644 index 0000000..a0f9a4b --- /dev/null +++ b/Dockers/f1tv-epg/version @@ -0,0 +1 @@ +latest