mirror of
https://github.com/darkzoul5/YoutubePlaylistSync.git
synced 2026-07-03 04:23:59 +03:00
feat: add “fail fast” dependency check
This commit is contained in:
+5
-1
@@ -88,7 +88,11 @@ def main(argv: list[str] | None = None) -> int:
|
||||
summary = ", ".join(f"{k}:{v}" for k, v in sorted(counts.items()))
|
||||
print(f"Playlist {pid}: {len(actions)} actions → {summary}")
|
||||
if args.apply and actions:
|
||||
asyncio.run(executor.execute(actions, pl))
|
||||
try:
|
||||
asyncio.run(executor.execute(actions, pl))
|
||||
except DependencyError as e:
|
||||
print(f"ERROR: {e}")
|
||||
return 2
|
||||
db.set_playlist_last_sync(pid)
|
||||
print(f"Applied actions for {pid}.")
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from ..sync.reorder import safe_multi_rename
|
||||
from ..database.db import Database
|
||||
from ..utils.yt import extract_playlist_id
|
||||
from ..events.event_bus import EventBus
|
||||
from ..utils.deps import ensure_ffmpeg_available, ensure_yt_dlp_available
|
||||
|
||||
|
||||
class ActionExecutor:
|
||||
@@ -21,6 +22,8 @@ class ActionExecutor:
|
||||
self.bus = event_bus
|
||||
|
||||
async def execute(self, actions: Iterable[SyncAction], playlist_cfg: dict) -> None:
|
||||
self._preflight_dependencies(actions, playlist_cfg)
|
||||
|
||||
save_path = Path(playlist_cfg.get("save_path", "./downloads")).resolve()
|
||||
mode = playlist_cfg.get("download_mode", "audio")
|
||||
|
||||
@@ -39,6 +42,23 @@ class ActionExecutor:
|
||||
# Finally, perform downloads concurrently
|
||||
await self._apply_downloads(actions, mode, audio_root, video_root, playlist_cfg)
|
||||
|
||||
def _preflight_dependencies(self, actions: Iterable[SyncAction], playlist_cfg: dict) -> None:
|
||||
"""
|
||||
Fail fast on core runtime dependencies before doing any filesystem work.
|
||||
|
||||
This keeps errors consistent regardless of entrypoint (CLI, bootstrap, tests, etc.).
|
||||
"""
|
||||
needs_download = any(a.type == SyncActionType.DOWNLOAD for a in actions)
|
||||
if not needs_download:
|
||||
return
|
||||
|
||||
# yt-dlp is required for any download job (Python API usage)
|
||||
ensure_yt_dlp_available()
|
||||
|
||||
# ffmpeg/ffprobe are required for merges and audio extraction; check once up-front
|
||||
ffmpeg_hint = playlist_cfg.get("ffmpeg_path", "ffmpeg")
|
||||
ensure_ffmpeg_available(str(ffmpeg_hint) if ffmpeg_hint is not None else None)
|
||||
|
||||
async def _apply_renames(self, actions: Iterable[SyncAction], audio_root: Path, video_root: Path, playlist_cfg: dict) -> None:
|
||||
playlist_id = extract_playlist_id(playlist_cfg.get("url", "")) or playlist_cfg.get("url", "")
|
||||
audio_renames = []
|
||||
|
||||
+5
-1
@@ -37,7 +37,11 @@ def bootstrap(db_path: Path | None = None) -> None:
|
||||
print(f"Plan → {summary}")
|
||||
# Execute
|
||||
import asyncio
|
||||
asyncio.run(executor.execute(actions, pl))
|
||||
try:
|
||||
asyncio.run(executor.execute(actions, pl))
|
||||
except DependencyError as e:
|
||||
print(f"ERROR: {e}")
|
||||
continue
|
||||
# Post summary (no DB readback yet)
|
||||
pid = extract_playlist_id(pl.get('url', '')) or pl.get('url', '')
|
||||
db.set_playlist_last_sync(pid)
|
||||
|
||||
Reference in New Issue
Block a user