feat(downloader): tier-limited classification, config defaults, yt-dlp support

- Classify Patreon "Not allowed to view post" warnings as TIER_LIMITED so
  subscription-gated runs are distinguished from genuine failures, and persist
  error_type/message on completed runs so the distinction survives to the UI.
- Fold PLATFORM_DEFAULTS into _get_default_config so gallery-dl.conf is a
  complete, editable document; _build_config_for_source now preserves the
  user's conf and only re-seeds missing platform sections.
- Add Reset-to-Defaults action in Settings (vs. Revert Changes which just
  reloads disk); show info banner when no gallery-dl.conf exists yet.
- Fix Discord embeds option: must be "all" string, not bool (gallery-dl
  iterates the value).
- Install yt-dlp + ffmpeg in Docker images so Patreon/Mux HLS video posts
  download instead of logging "Cannot import yt-dlp" and skipping.
- Recognize yt-dlp import failures as per-item errors so they don't mask
  TIER_LIMITED/NO_NEW_CONTENT classification.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 19:32:44 -04:00
parent f747750f97
commit 86bf43c80a
10 changed files with 435 additions and 48 deletions
@@ -22,6 +22,7 @@ def test_run_stats_all_zeros_on_empty_output():
"skipped_count": 0,
"per_item_failures": 0,
"warning_count": 0,
"tier_gated_count": 0,
}
@@ -79,3 +80,18 @@ def test_run_stats_exit_code_passed_through():
assert service._compute_run_stats(0, "", "")["exit_code"] == 0
assert service._compute_run_stats(4, "", "")["exit_code"] == 4
assert service._compute_run_stats(-9, "", "")["exit_code"] == -9
def test_run_stats_tier_gated_count_from_patreon_warnings():
"""'Not allowed to view post N' warnings tallied separately from generic warnings."""
service = _make_service()
stderr = (
"[patreon][warning] Not allowed to view post 100\n"
"[patreon][warning] Not allowed to view post 101\n"
"[patreon][warning] Not allowed to view post 102\n"
"[downloader.http][warning] '404 OK' for 'https://example.com/x'\n"
)
stats = service._compute_run_stats(4, "", stderr)
assert stats["tier_gated_count"] == 3
# Still tallied in warning_count — tier_gated is a subset, not separate
assert stats["warning_count"] == 4