feat(external): mega.nz via megatools in the runtime image (Phase 4c)
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 17s
CI / backend-lint-and-test (push) Successful in 33s
CI / integration (push) Successful in 3m17s

Use `megatools dl` (Debian-native apt package) for mega.nz public links rather
than MEGAcmd — no external MEGA apt repo/key to add, one apt line. Adds
`megatools` to the runtime Dockerfile; the fetcher's mega backend now shells
`megatools dl --path <dir> <url>` (key in the #fragment is preserved by the
extractor). gdown (gdrive) is already a pip dep in the runtime image.

NOTE: build.yml builds the image on main/tags only (not dev), so this Dockerfile
change is verified on the next dev→main merge, not by this dev push. The fetcher
code path is unit-tested via the mocked _run_mega_get seam.

With this, all 5 hosts download end-to-end once a celery download-worker runs.
Refs FC #830 (Phase 4c).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-14 15:41:18 -04:00
parent 82b26b8aaa
commit bd2807cdd1
3 changed files with 13 additions and 9 deletions
+4 -1
View File
@@ -18,13 +18,16 @@ ENV PYTHONUNBUFFERED=1 \
# System deps: ffmpeg (transcode + thumbnails, FC-2), unar (archives, FC-2), # System deps: ffmpeg (transcode + thumbnails, FC-2), unar (archives, FC-2),
# libpq for psycopg, postgresql-client + zstd for FC-5 backup/restore # libpq for psycopg, postgresql-client + zstd for FC-5 backup/restore
# (pg_dump + tar --zstd), image libs. # (pg_dump + tar --zstd), image libs, megatools (mega.nz public-link downloads
# for off-platform file-host links, #830 — `megatools dl`; Debian-native, no
# external MEGA apt repo needed).
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
ffmpeg \ ffmpeg \
unar \ unar \
libpq5 \ libpq5 \
postgresql-client \ postgresql-client \
zstd \ zstd \
megatools \
libjpeg62-turbo \ libjpeg62-turbo \
libwebp7 \ libwebp7 \
libpng16-16 \ libpng16-16 \
+8 -7
View File
@@ -16,8 +16,8 @@ Backends:
- pixeldrain : GET the /api/file/{id} endpoint. - pixeldrain : GET the /api/file/{id} endpoint.
- mediafire : scrape the download page for the direct link + stream GET. - mediafire : scrape the download page for the direct link + stream GET.
- gdrive : gdown (handles the confirm-token + virus-scan interstitial). - gdrive : gdown (handles the confirm-token + virus-scan interstitial).
- mega : MEGAcmd `mega-get` subprocess (public link incl. #key); needs - mega : `megatools dl` subprocess (public link incl. #key); needs the
the binary in the runtime image. `megatools` binary in the runtime image (Debian apt package).
Public links work credential-free (rule 26); per-host creds are a later Settings Public links work credential-free (rule 26); per-host creds are a later Settings
concern. Plain-HTTP homelab — no secure-context API. The HTTP / gdown / concern. Plain-HTTP homelab — no secure-context API. The HTTP / gdown /
@@ -89,16 +89,17 @@ def _gdown_download(url: str, out_dir: str) -> str | None:
def _run_mega_get(url: str, out_dir: str, *, timeout: float) -> None: def _run_mega_get(url: str, out_dir: str, *, timeout: float) -> None:
"""Download a mega.nz public link (key in the #fragment) into out_dir via """Download a mega.nz public link (key in the #fragment) into out_dir via
MEGAcmd's `mega-get`. Raises ExternalFetchError on non-zero exit.""" `megatools dl` (the Debian `megatools` package). Raises ExternalFetchError
# Fixed argv (not shell): only `url` is external input, and it's a positional on non-zero exit."""
# arg to mega-get, so there's no shell-injection surface. # Fixed argv (not shell): only `url` is external input, passed positionally,
# so there's no shell-injection surface.
proc = subprocess.run( proc = subprocess.run(
["mega-get", url, out_dir], ["megatools", "dl", "--path", out_dir, url],
capture_output=True, text=True, timeout=timeout, check=False, capture_output=True, text=True, timeout=timeout, check=False,
) )
if proc.returncode != 0: if proc.returncode != 0:
raise ExternalFetchError( raise ExternalFetchError(
f"mega-get exit {proc.returncode}: {(proc.stderr or '').strip()[:300]}" f"megatools dl exit {proc.returncode}: {(proc.stderr or '').strip()[:300]}"
) )
+1 -1
View File
@@ -41,5 +41,5 @@ py7zr>=1,<2
# Google Drive fetcher for off-platform file-host links (external downloads, # Google Drive fetcher for off-platform file-host links (external downloads,
# #830). Handles Drive's confirm-token + virus-scan interstitial. mega.nz uses # #830). Handles Drive's confirm-token + virus-scan interstitial. mega.nz uses
# the MEGAcmd `mega-get` binary instead (added to the runtime image, not pip). # the `megatools` binary instead (Debian apt pkg in the runtime image, not pip).
gdown>=5,<6 gdown>=5,<6