#!/bin/sh # Supervise the app and keep yt-dlp fresh. # # yt-dlp breaks frequently against site changes, so we check PyPI once a day # for a newer release. The app imports yt_dlp at startup, so a new version # only takes effect on (re)start -- we therefore restart the app *only* when # an update was actually installed. If the app exits on its own, we propagate # its exit status so Docker's restart policy can handle it. set -e CHECK_INTERVAL=86400 # check for a new yt-dlp once per day POLL=60 # how often to check on the app # Upgrade yt-dlp only if PyPI has a newer version. # Returns 0 if an update was installed, 1 otherwise (incl. errors / up to date). check_and_update() { current=$(python -c "import yt_dlp; print(yt_dlp.version.__version__)" 2>/dev/null) || return 1 latest=$(python -c "import json,urllib.request; print(json.load(urllib.request.urlopen('https://pypi.org/pypi/yt-dlp/json', timeout=30))['info']['version'])" 2>/dev/null) || { echo "Could not reach PyPI to check for yt-dlp updates; will retry." return 1 } if [ "$current" = "$latest" ]; then echo "yt-dlp is up to date ($current)." return 1 fi echo "New yt-dlp available: $current -> $latest. Updating..." if pip install --upgrade --quiet --root-user-action=ignore yt-dlp; then return 0 fi echo "yt-dlp update failed; continuing with the installed version." return 1 } # Forward termination to the app so the container stops cleanly. trap 'kill "$APP_PID" 2>/dev/null; exit 0' TERM INT while true; do # Make sure we launch with the latest available yt-dlp. check_and_update || true "$@" & APP_PID=$! # Periodically check for updates; restart the app only when one is applied. while true; do waited=0 while [ "$waited" -lt "$CHECK_INTERVAL" ] && kill -0 "$APP_PID" 2>/dev/null; do sleep "$POLL" waited=$((waited + POLL)) done if ! kill -0 "$APP_PID" 2>/dev/null; then wait "$APP_PID" status=$? echo "App exited with status $status" exit "$status" fi if check_and_update; then echo "Restarting app to apply yt-dlp update..." kill "$APP_PID" 2>/dev/null || true wait "$APP_PID" 2>/dev/null || true break # outer loop relaunches the app fi done done