diff --git a/Dockerfile b/Dockerfile index b062486..c9bef05 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,4 +10,8 @@ COPY backend/requirements.txt . RUN pip install -r requirements.txt RUN rm requirements.txt +COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +RUN chmod a+rx /usr/local/bin/docker-entrypoint.sh + +ENTRYPOINT ["docker-entrypoint.sh"] CMD ["python", "backend/main.py"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index a130140..0de5e22 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,7 +3,7 @@ services: hottub-webclient: image: hottub-webclient:latest container_name: hottub-webclient - entrypoint: python3 + entrypoint: ["/app/docker-entrypoint.sh", "python3"] command: ["backend/main.py"] volumes: - /path/to/hottub-webclient:/app diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..40a69c8 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,68 @@ +#!/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