Download Dockerfile from Reooiq/Hode: direct link, hf CLI and curl.
- Browser
- Download file 3.98 kB
-
https://huggingface.co/spaces/Reooiq/Hode/resolve/main/Dockerfile
- Command line
-
hf download hf://spaces/Reooiq/Hode/Dockerfile
-
curl -L -o Dockerfile https://huggingface.co/spaces/Reooiq/Hode/resolve/main/Dockerfile
3.98 kB
| FROM python:3.11-slim-trixie | |
| RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg mkvtoolnix ca-certificates tzdata && rm -rf /var/lib/apt/lists/* | |
| RUN ffmpeg -hide_banner -h protocol=rtmps 2>&1 | grep -q rtmp_enhanced_codecs | |
| WORKDIR /app | |
| COPY requirements.txt . | |
| RUN pip install --no-cache-dir -r requirements.txt | |
| COPY app.py relay.py youtube_api.py youtube_manager.py flv_bridge.py tiktok_auth.py index.html ./ | |
| # --- YouTube ingestion ------------------------------------------------------- | |
| # copy = forward the source untouched (original quality, no extra CPU). DEFAULT. | |
| # The YouTube stream is created with cdn.resolution='variable' and | |
| # cdn.frameRate='variable', which per the Live Streaming API means | |
| # "YouTube should automatically detect the resolution of your streamed | |
| # video". So a mid-stream resolution change does NOT require a new | |
| # session, and YOUTUBE_FORMAT_GUARD=off keeps the RTMPS session alive | |
| # across it. Restarting the session was itself a visible gap and, when | |
| # the phone flipped resolution repeatedly, a reconnect storm. | |
| # fixed1080 = constant 1080x1920 canvas, re-encodes to H.264. Zero gaps but costs | |
| # CPU: measured 2.26x real time on 2 vCPU (~44% for one stream). | |
| # fixed720 = constant 720x1280 canvas, 3.72x real time (~27%). Lighter. | |
| # Both canvas modes stay available from Settings if YouTube's own healthStatus ever | |
| # reports videoResolutionUnsupported; they are opt-in because of the CPU cost. | |
| # | |
| # YOUTUBE_FORMAT_GUARD=on -> tear the session down on a resolution change (old | |
| # behaviour: 1-3 s gap, but YouTube re-declares the new size explicitly). | |
| # YOUTUBE_FLAP_LIMIT: if resolution flips this many times in 10 minutes, copy mode | |
| # falls back to YOUTUBE_FLAP_FALLBACK_MODE for the rest of the event. Dormant | |
| # while the guard is off, kept as a safety net. | |
| # | |
| # YOUTUBE_FIFO_TIMESHIFT: the push goes through FFmpeg's fifo pseudo-muxer, which | |
| # reconnects on its own when YouTube drops the connection instead of killing the | |
| # whole process (that is why the recording kept running while the broadcast died). | |
| # timeshift additionally delays the YouTube feed behind the live TikTok source and | |
| # keeps that many seconds buffered, so a source hiccup is covered instead of | |
| # starving YouTube's ingest, and packets survive a reconnect instead of being | |
| # dropped. Cost is latency only, no CPU. https://ffmpeg.org/ffmpeg-formats.html#fifo | |
| # NOTE: fifo's queue_size defaults to 60 packets, under one second of stream, so | |
| # timeshift requires it to be raised or the queue overflows and the stream is | |
| # destroyed instead of delayed. relay.py sizes it automatically (ts*250+500). | |
| # YOUTUBE_HEALTH_INTERVAL: seconds between reads of YouTube's own | |
| # healthStatus/configurationIssues while live. This is what reports videoIngestion | |
| # Starved (viewers buffer), gopSizeLong, openGop, videoResolutionUnsupported and | |
| # videoCodec, i.e. the ground truth instead of a guess. | |
| ENV YOUTUBE_SEND_MODE=copy \ | |
| YOUTUBE_FORMAT_GUARD=off \ | |
| YOUTUBE_FLAP_LIMIT=4 \ | |
| YOUTUBE_FLAP_FALLBACK_MODE=fixed720 \ | |
| YOUTUBE_X264_PRESET=veryfast \ | |
| YOUTUBE_CRF=22 \ | |
| YOUTUBE_RECOVERY_WAIT=1 \ | |
| YOUTUBE_FIFO_TIMESHIFT=10 \ | |
| YOUTUBE_HEALTH_INTERVAL=180 | |
| # --- TikTok session token (age-restricted 18+ rooms) ------------------------- | |
| # Set TIKTOK_SESSIONID in Settings > Variables and secrets, or paste it into the | |
| # UI panel (no Factory reboot needed). Sessions are short-lived (~6 h per | |
| # sid_guard), so the UI panel is the practical way to refresh. | |
| # Per account: TIKTOK_SESSIONID_<USER> (upper-case, non A-Z0-9 -> _) | |
| # Compact map: TIKTOK_TOKENS=user1=token1;user2=token2 | |
| ENV TIKTOK_TT_TARGET_IDC=useast1a | |
| ENV PORT=7860 PYTHONUNBUFFERED=1 YOUTUBE_VIDEO_MODE=original PASSWORD=admin | |
| EXPOSE 7860 | |
| CMD ["sh", "-c", "exec uvicorn app:app --host 0.0.0.0 --port ${PORT:-7860} --timeout-graceful-shutdown 65"] | |