86bf43c80a
- 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>
98 lines
3.4 KiB
Python
98 lines
3.4 KiB
Python
"""Unit tests for GalleryDLService._compute_run_stats.
|
|
|
|
Covers the structured counts the Downloads modal surfaces in its header row:
|
|
exit code, downloaded count, skipped count, per-item failures, warning count.
|
|
"""
|
|
from unittest.mock import patch
|
|
|
|
from app.services.gallery_dl import GalleryDLService
|
|
|
|
|
|
def _make_service():
|
|
with patch.object(GalleryDLService, "_load_base_config", return_value={}):
|
|
return GalleryDLService(rate_limit=1.0)
|
|
|
|
|
|
def test_run_stats_all_zeros_on_empty_output():
|
|
service = _make_service()
|
|
stats = service._compute_run_stats(0, "", "")
|
|
assert stats == {
|
|
"exit_code": 0,
|
|
"downloaded_count": 0,
|
|
"skipped_count": 0,
|
|
"per_item_failures": 0,
|
|
"warning_count": 0,
|
|
"tier_gated_count": 0,
|
|
}
|
|
|
|
|
|
def test_run_stats_counts_downloads_from_stdout_paths():
|
|
service = _make_service()
|
|
stdout = (
|
|
"/data/downloads/Foo/bar/1.jpg\n"
|
|
"/data/downloads/Foo/bar/2.jpg\n"
|
|
"[some log line that should not count]\n"
|
|
)
|
|
stats = service._compute_run_stats(0, stdout, "")
|
|
assert stats["downloaded_count"] == 2
|
|
|
|
|
|
def test_run_stats_skips_from_both_streams():
|
|
"""stdout '#' lines AND stderr 'skipping ' lines both count."""
|
|
service = _make_service()
|
|
stdout = (
|
|
"# /data/downloads/Foo/already_archived_1.jpg\n"
|
|
"# /data/downloads/Foo/already_archived_2.jpg\n"
|
|
)
|
|
stderr = (
|
|
"[patreon][debug] skipping https://example.com/a.jpg (abc image_large)\n"
|
|
"[patreon][debug] skipping https://example.com/b.jpg (def image_large)\n"
|
|
"[patreon][debug] skipping https://example.com/c.jpg (ghi image_large)\n"
|
|
)
|
|
stats = service._compute_run_stats(0, stdout, stderr)
|
|
assert stats["skipped_count"] == 5
|
|
|
|
|
|
def test_run_stats_per_item_failures_counted():
|
|
service = _make_service()
|
|
stderr = (
|
|
"[download][error] Failed to download 02_46004845.part\n"
|
|
"[download][error] Failed to download 03_46004845.part\n"
|
|
"[patreon][debug] something unrelated\n"
|
|
)
|
|
stats = service._compute_run_stats(1, "", stderr)
|
|
assert stats["per_item_failures"] == 2
|
|
|
|
|
|
def test_run_stats_warnings_counted():
|
|
service = _make_service()
|
|
stderr = (
|
|
"[downloader.http][warning] '404 OK' for 'https://example.com/x'\n"
|
|
"[patreon][warning] something else\n"
|
|
"[patreon][error] not a warning\n"
|
|
)
|
|
stats = service._compute_run_stats(1, "", stderr)
|
|
assert stats["warning_count"] == 2
|
|
|
|
|
|
def test_run_stats_exit_code_passed_through():
|
|
service = _make_service()
|
|
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
|