version: "3.8" services: fade-out: build: context: . args: # Set by scripts/deploy.sh so the running image can be identified. BUILD_COMMIT: ${BUILD_COMMIT:-unknown} BUILD_TIME: ${BUILD_TIME:-unknown} BUILD_SOURCE: ${BUILD_SOURCE:-local} # Or use pre-built image: # image: ghcr.io/rancur/fade-out:latest container_name: fade-out restart: unless-stopped ports: - "8500:8000" volumes: # Host paths come from .env so this file works unmodified on any machine. # Defaults drop everything under ./media/ next to the compose file; point # them at your NAS shares (e.g. /volume1/music/mixes) by setting the # matching variables in .env. # # Audio + video watch folders are READ-WRITE so the optional "Rename # source files to match titles" setting (Settings -> Advanced, OFF by # default) can rename finished recordings in place. Change them to :ro if # you never want fade-out to touch the source files — with the setting on # and a :ro mount every rename is simply skipped and logged, and nothing # else about the pipeline changes. - ${WATCH_AUDIO_DIR:-./media/audio}:/watch/audio:rw - ${WATCH_VIDEO_DIR:-./media/video}:/watch/video:rw - ${WATCH_CUE_DIR:-./media/cue-sheets}:/watch/djctl-cue:ro # Vertical clips for the Shorts auto-uploader (READ-ONLY — the pipeline # only ever reads the source recordings) - ${WATCH_SHORTS_DIR:-./media/shorts}:/watch/shorts:ro # Output folders - ${OUTPUT_THUMBNAILS_DIR:-./media/thumbnails}:/output/thumbnails - ${OUTPUT_COVER_ART_DIR:-./media/cover-art}:/output/cover-art # Persistent data (SQLite DB, state, tokens) - ./data:/data environment: - TZ=${TZ:-UTC} - OPENAI_API_KEY=${OPENAI_API_KEY} - FAL_API_KEY=${FAL_API_KEY} - SOUNDCLOUD_CLIENT_ID=${SOUNDCLOUD_CLIENT_ID} - SOUNDCLOUD_CLIENT_SECRET=${SOUNDCLOUD_CLIENT_SECRET} - SOUNDCLOUD_ACCESS_TOKEN=${SOUNDCLOUD_ACCESS_TOKEN} - SOUNDCLOUD_REFRESH_TOKEN=${SOUNDCLOUD_REFRESH_TOKEN} - SOUNDCLOUD_EMAIL=${SOUNDCLOUD_EMAIL} - SOUNDCLOUD_PASSWORD=${SOUNDCLOUD_PASSWORD} - YOUTUBE_API_KEY=${YOUTUBE_API_KEY} - YOUTUBE_CLIENT_ID=${YOUTUBE_CLIENT_ID} - YOUTUBE_CLIENT_SECRET=${YOUTUBE_CLIENT_SECRET} - YOUTUBE_REFRESH_TOKEN=${YOUTUBE_REFRESH_TOKEN} - PUBLIC_URL=${PUBLIC_URL} - NOTIFICATION_DISCORD_WEBHOOK_URL=${NOTIFICATION_DISCORD_WEBHOOK_URL} # Read-only GitHub credential for the deployment freshness check. The # setting existed but was never passed through to the container, so on a # private repo the check could only ever answer "cannot determine". # Optional: unset, the check stays honestly unknown rather than green. - GITHUB_TOKEN=${GITHUB_TOKEN:-} # Run unprivileged if your bind mounts allow it. Left commented because the # container must be able to read the watch folders and write the output # folders, and the right UID/GID depends on your NAS share permissions. # See SECURITY.md. # user: "1000:1000" # Analysis of a long DJ set (beat/energy/track detection over a multi-hour # WAV) is the memory high-water mark. 4g was not enough: on 2026-08-21 the # container was OOM-killed at 4.19 GB mid-analysis, the boot sweep then # marked the mix failed, and the set silently never published. Keep real # headroom here — an OOM kill in the middle of the pipeline is data loss, # not a slowdown. mem_limit: 12g logging: driver: json-file options: max-size: "50m" max-file: "3"