mirror of
https://github.com/darkzoul5/YoutubePlaylistSync.git
synced 2026-07-03 04:23:59 +03:00
feat(backend): add Download progress; add SyncStarted, SyncFinished, SyncSummary
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from src.app.core.download.downloader import Downloader
|
||||
from src.app.core.download.queue_manager import DownloadJob
|
||||
from src.app.core.events.event_bus import EventBus
|
||||
from src.app.core.models import PlaylistItem, SyncAction, SyncActionType
|
||||
from src.app.core.sync.executor import ActionExecutor
|
||||
|
||||
|
||||
def test_executor_emits_sync_events(tmp_path):
|
||||
published: list[tuple[str, dict]] = []
|
||||
|
||||
class TestBus(EventBus):
|
||||
async def publish(self, event_name: str, payload: dict) -> None: # type: ignore[override]
|
||||
published.append((event_name, dict(payload)))
|
||||
|
||||
class StubDB:
|
||||
def update_local_filename(self, playlist_id: str, video_id: str, filename: str) -> None:
|
||||
return None
|
||||
|
||||
def mark_downloaded(self, playlist_id: str, video_id: str, downloaded: bool) -> None:
|
||||
return None
|
||||
|
||||
bus = TestBus()
|
||||
ex = ActionExecutor(StubDB(), concurrency=1, event_bus=bus) # type: ignore[arg-type]
|
||||
|
||||
item = PlaylistItem(playlist_id="p", video_id="v", title="t", playlist_index=1)
|
||||
actions = [SyncAction(SyncActionType.SKIP, item=item, to_name="0001 - t.mp4")]
|
||||
|
||||
asyncio.run(ex.execute(actions, {"url": "p", "save_path": str(tmp_path)}))
|
||||
|
||||
names = [n for n, _ in published]
|
||||
assert "SyncStarted" in names
|
||||
assert "SyncSummary" in names
|
||||
assert "SyncFinished" in names
|
||||
|
||||
summary = [p for n, p in published if n == "SyncSummary"][0]
|
||||
assert summary["playlist_id"] == "p"
|
||||
assert "duration_s" in summary
|
||||
assert isinstance(summary["counts"], dict)
|
||||
|
||||
|
||||
def test_downloader_progress_hook_calls_callback(tmp_path, monkeypatch):
|
||||
callbacks: list[dict] = []
|
||||
|
||||
class DummyYDL:
|
||||
def __init__(self, opts):
|
||||
self.opts = opts
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc, tb):
|
||||
return False
|
||||
|
||||
def download(self, urls):
|
||||
hooks = self.opts.get("progress_hooks") or []
|
||||
for h in hooks:
|
||||
h({"status": "downloading", "downloaded_bytes": 50, "total_bytes": 100, "speed": 1.0, "eta": 1, "filename": "x"})
|
||||
h({"status": "finished", "downloaded_bytes": 100, "total_bytes": 100, "speed": 1.0, "eta": 0, "filename": "x"})
|
||||
|
||||
dummy = type("yt_dlp", (), {"YoutubeDL": DummyYDL})
|
||||
monkeypatch.setitem(sys.modules, "yt_dlp", dummy)
|
||||
|
||||
ffmpeg = tmp_path / "ffmpeg"
|
||||
ffmpeg.write_text("x", encoding="utf-8")
|
||||
|
||||
job = DownloadJob(
|
||||
item=PlaylistItem(playlist_id="p", video_id="v", title="t", playlist_index=1),
|
||||
url="https://example.invalid",
|
||||
output_path=tmp_path / "out.mp4",
|
||||
ffmpeg_path=str(ffmpeg),
|
||||
)
|
||||
job.progress_callback = lambda payload: callbacks.append(dict(payload))
|
||||
|
||||
dl = Downloader()
|
||||
asyncio.run(dl._download(job)) # type: ignore[attr-defined]
|
||||
|
||||
assert callbacks
|
||||
assert any("progress" in c for c in callbacks)
|
||||
|
||||
Reference in New Issue
Block a user