diff --git a/Dockerfile b/Dockerfile index cc32eb1..d26f31e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,35 +1,35 @@ +# syntax=docker/dockerfile:1 FROM python:3.12-slim-bookworm -# Install system dependencies (ffmpeg required by yt-dlp for audio extraction) -RUN apt-get update && apt-get install -y --no-install-recommends \ - ffmpeg \ - curl \ - gosu \ - && rm -rf /var/lib/apt/lists/* +ARG TARGETARCH -# Install yt-dlp (standalone binary, always up-to-date) -RUN curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp \ - -o /usr/local/bin/yt-dlp && \ - chmod +x /usr/local/bin/yt-dlp +# ffmpeg + ffprobe as static binaries (yt-dlp needs both for audio extraction). +# The Debian package pulls in ~400 MB of X11/desktop dependencies that dpkg then +# unpacks file by file — on an SD card that alone dominates the build time. +COPY --from=mwader/static-ffmpeg:7.1 /ffmpeg /ffprobe /usr/local/bin/ + +# gosu drops privileges in the entrypoint; the binary avoids an apt transaction +ADD --chmod=755 https://github.com/tianon/gosu/releases/download/1.17/gosu-${TARGETARCH} /usr/local/bin/gosu WORKDIR /app COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install --prefer-binary -r requirements.txt +# Placed after pip: the "latest" URL changes with every yt-dlp release and would +# otherwise invalidate the dependency layer on each build +ADD --chmod=755 https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp /usr/local/bin/yt-dlp + +COPY --chmod=755 entrypoint.sh /entrypoint.sh COPY . . -RUN mkdir -p /app/tmp /app/data - ENV APP_HOST=0.0.0.0 ENV APP_PORT=8000 ENV TMP_DIR=/app/tmp EXPOSE 8000 -COPY entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh - ENTRYPOINT ["/entrypoint.sh"] # Single worker to stay within Pi 3's memory budget CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"] diff --git a/requirements.txt b/requirements.txt index 809e62b..b140493 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,15 @@ -fastapi>=0.115 -uvicorn>=0.30 -pydantic>=2.9 -pydantic-settings>=2.5 -httpx>=0.27 -python-multipart>=0.0.18 -recipe-scrapers>=15.0 -beautifulsoup4>=4.12 -lxml>=5.2 -openai>=1.50 -python-dotenv>=1.0 -aiofiles>=23.0 +# Pinned to the versions verified on the Pi. Bump deliberately, not implicitly: +# an unpinned rebuild months later resolves different versions than the running +# container and breaks in ways the diff cannot explain. +fastapi==0.139.2 +uvicorn==0.51.0 +pydantic==2.13.4 +pydantic-settings==2.14.2 +httpx==0.28.1 +python-multipart==0.0.32 +recipe-scrapers==15.11.0 +beautifulsoup4==4.15.0 +lxml==6.1.1 +openai==2.46.0 +python-dotenv==1.2.2 +aiofiles==25.1.0