# Pin the UI builder to the build host platform: its output is just static # files, so there is no need to run node under QEMU when cross-building. FROM --platform=$BUILDPLATFORM node:lts-alpine AS builder WORKDIR /metube COPY ui ./ RUN npm ci && \ node_modules/.bin/ng build --configuration production FROM python:3.13-slim WORKDIR /app # Heavy system dependencies in their own layer, independent of app/dep files, # so it stays cached unless this block itself changes. # apt caches are BuildKit cache mounts: even when this layer is invalidated, # package downloads are reused instead of hitting deb.debian.org again. RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ apt-get update && \ apt-get install -y --no-install-recommends ffmpeg aria2 curl tini gosu ca-certificates unzip \ chromium libnss3 libfreetype6 libharfbuzz0b fonts-freefont-ttf && \ ln -s /usr/sbin/gosu /usr/local/bin/su-exec && \ curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh && \ pip install --no-cache-dir uv && \ mkdir /.cache && chmod 777 /.cache # Python dependencies: only invalidated when pyproject.toml/uv.lock change. # The uv cache mount makes re-resolving after a lockfile change much faster. COPY pyproject.toml uv.lock ./ RUN --mount=type=cache,target=/root/.cache/uv \ UV_PROJECT_ENVIRONMENT=/usr/local uv sync --frozen --no-dev --compile-bytecode --extra headless # Use sed to strip carriage-return characters from the entrypoint script (in case building on Windows) COPY docker-entrypoint.sh ./ RUN sed -i 's/\r$//g' docker-entrypoint.sh && chmod +x docker-entrypoint.sh COPY app ./app COPY --from=builder /metube/dist/metube ./ui/dist/metube ENV UID=0 ENV GID=0 ENV UMASK=022 # Playwright settings for system Chromium ENV PLAYWRIGHT_BROWSERS_PATH=0 ENV PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium ENV DOWNLOAD_DIR /downloads ENV STATE_DIR /downloads/.metube ENV TEMP_DIR /downloads VOLUME /downloads EXPOSE 8081 # Add build-time argument for version ARG VERSION=dev ENV METUBE_VERSION=$VERSION ENTRYPOINT ["tini", "-g", "--", "./docker-entrypoint.sh"]