mirror of
https://github.com/darkzoul5/YoutubePlaylistSync.git
synced 2026-09-18 20:43:54 +03:00
feat: add GUI mvp
This commit is contained in:
+3
-17
@@ -3,8 +3,6 @@
|
||||
## Python-first Desktop Architecture
|
||||
|
||||
- **Primary GUI framework**: `PySide6` (Qt for Python).
|
||||
- **Communication Layer**: A local `FastAPI` backend to separate core logic from the UI.
|
||||
- **IPC Mechanism**: The GUI spawns the FastAPI server on a random high port (binding to `127.0.0.1` ONLY) and communicates via REST/WebSockets.
|
||||
|
||||
## Core Features to Implement
|
||||
|
||||
@@ -12,27 +10,15 @@
|
||||
2. **Interactive Configuration**: Wizard-style setup for new playlists (URL detection, folder picker).
|
||||
3. **Queue Manager**: Visual progress bars for active downloads, showing speed, ETA, and current video title.
|
||||
4. **Log Viewer**: Real-time streaming of yt-dlp logs for troubleshooting.
|
||||
5. **Settings Panel**: Global settings for binary paths (ffmpeg, aria2c), max parallel jobs, and Docker detection toggle.
|
||||
5. **Settings Panel**: Global settings for binary paths (ffmpeg), max parallel jobs, and Docker detection toggle.
|
||||
|
||||
## Phase 1 Roadmap: "The Bridge"
|
||||
|
||||
- [ ] **Refactor `src/manager.py`**: Convert CLI-first execution to async-compatible methods for FastAPI consumption.
|
||||
- [ ] **FastAPI Integration**: Create endpoints for `/playlists`, `/status`, and `/download/start`.
|
||||
- [ ] **PySide6 Skeleton**: Basic window with `QWebEngine` (if hybrid) or native `QWidget` dashboard.
|
||||
- [ ] **Packaging**: `pyinstaller` configuration to bundle both backend and frontend into a single `.exe`.
|
||||
|
||||
## Packaging & Distribution (brief)
|
||||
|
||||
- Bundle the backend and GUI into one distributable. The GUI should spawn the local API process (background subprocess) on startup.
|
||||
- Bundle the backend and GUI into one distributable.
|
||||
- Windows: use `pyinstaller` or `briefcase` to create an executable/installer. Consider creating an MSI or Inno Setup installer for a polished UX.
|
||||
- Linux: provide AppImage, Snap, or distribution-specific packages (deb/rpm) — AppImage is a good starting point for single-file distribution.
|
||||
- Security: bind the local API to `localhost` only, use a short-lived token or IPC for authentication between GUI and backend, and avoid exposing unnecessary ports.
|
||||
|
||||
## Roadmap (GUI → Web → Mobile)
|
||||
|
||||
1. Desktop prototype: `FastAPI` backend + `PySide6` GUI (thin client) with basic playlist add/update/download controls and status streaming.
|
||||
2. Packaging: create Windows exe/installer and Linux AppImage for the prototype.
|
||||
3. Web frontend: build a web SPA that consumes the same backend API (hosted or local) — this reuses business logic with minimal change.
|
||||
4. Android: either a native app or cross-platform UI (Flutter/React Native) that calls the backend API; alternatively host the backend and make a thin mobile client.
|
||||
|
||||
If you want, I can now: scaffold a minimal `FastAPI` backend and `PySide6` desktop starter in this repo, or produce concise packaging steps for Windows and Linux. Which do you prefer?
|
||||
- Linux: provide AppImage, Snap, or distribution-specific packages (deb/rpm) — AppImage is a good starting point for single-file distribution.
|
||||
@@ -0,0 +1,121 @@
|
||||
You need to separate playlist sync state from download attempts.
|
||||
|
||||
The goal should not be “all 400 downloaded in one run”. It should be:
|
||||
|
||||
All downloadable items eventually reach a final state. Temporary failures are retried later. Permanent failures are recorded clearly.
|
||||
|
||||
Use statuses like:
|
||||
|
||||
queued
|
||||
downloading
|
||||
completed
|
||||
|
||||
temporary_failed
|
||||
rate_limited
|
||||
verification_required
|
||||
|
||||
unavailable
|
||||
private
|
||||
geo_blocked
|
||||
copyright_blocked
|
||||
age_restricted
|
||||
unsupported
|
||||
failed_permanent
|
||||
|
||||
skipped_by_user
|
||||
removed_from_playlist
|
||||
|
||||
Main logic:
|
||||
|
||||
1. Fetch playlist metadata
|
||||
2. Create/update queue items for all playlist videos
|
||||
3. Download available queued items
|
||||
4. On normal temporary errors: retry later
|
||||
5. On YouTube rate-limit / bot check: pause the whole sync
|
||||
6. On unavailable/private/deleted videos: mark as permanent failure
|
||||
7. On next sync: retry only retryable items
|
||||
|
||||
Important: do not delete queue records just because download failed. Keep them as sync records.
|
||||
|
||||
For each video, store:
|
||||
|
||||
video_id
|
||||
playlist_id
|
||||
playlist_position
|
||||
wanted_format: audio | video
|
||||
status
|
||||
failure_type
|
||||
failure_message
|
||||
attempt_count
|
||||
last_attempt_at
|
||||
next_retry_at
|
||||
is_retryable
|
||||
local_file_path
|
||||
|
||||
Retry behavior:
|
||||
|
||||
temporary_failed -> retry with backoff
|
||||
rate_limited -> pause playlist/app queue, retry much later
|
||||
verification_required -> pause until user action
|
||||
unavailable/private/deleted -> do not retry often
|
||||
geo/age restricted -> do not retry unless settings/auth changed
|
||||
|
||||
Example backoff:
|
||||
|
||||
attempt 1: retry after 10 minutes
|
||||
attempt 2: retry after 1 hour
|
||||
attempt 3: retry after 6 hours
|
||||
attempt 4: retry after 24 hours
|
||||
attempt 5+: retry manually or during next scheduled sync
|
||||
|
||||
For the user, show a sync summary:
|
||||
|
||||
Playlist sync partially completed
|
||||
|
||||
Downloaded: 200
|
||||
Queued: 0
|
||||
Retry later: 80
|
||||
Needs attention: 1
|
||||
Unavailable: 119
|
||||
|
||||
The playlist is still tracked. Retryable items will be attempted again in the next sync.
|
||||
|
||||
Best behavior for the 400-item example:
|
||||
|
||||
200 downloaded
|
||||
50 unavailable/private/deleted -> mark permanent
|
||||
149 temporary/rate-limited -> retry later
|
||||
1 bot/verification error -> pause sync and ask user
|
||||
|
||||
Do not cancel the whole sync as “failed”. Mark it as:
|
||||
|
||||
completed_with_issues
|
||||
paused_needs_attention
|
||||
partially_synced
|
||||
|
||||
In UI terms, the playlist should have a health/status:
|
||||
|
||||
Synced
|
||||
Syncing
|
||||
Partially synced
|
||||
Paused - needs attention
|
||||
Error
|
||||
|
||||
The most important rule:
|
||||
|
||||
Never lose the reason why an item did not download.
|
||||
|
||||
That lets your app eventually download everything possible without repeatedly hammering YouTube or confusing the user.
|
||||
|
||||
|
||||
## What to change to match the plan
|
||||
|
||||
Fix the destructive UPSERT behavior in src/app/core/database/db.py / SyncService.sync_from_config() so scans update metadata (title/index/last_seen) but do not overwrite existing downloaded/local_filename (and later: status/failure fields).
|
||||
|
||||
Introduce a persistent table (or extend playlist_items) with:
|
||||
status, failure_type, failure_message, attempt_count, last_attempt_at, next_retry_at, is_retryable, wanted_format, local_file_path.
|
||||
|
||||
Update ActionExecutor / worker layer to write transitions into DB (queued → downloading → completed / temporary_failed / rate_limited / verification_required / failed_permanent).
|
||||
|
||||
Change “next sync” selection to only pick queued or retryable && next_retry_at <= now, not everything each time.
|
||||
Add summary/health states (partially_synced, paused_needs_attention, etc.) based on counts.
|
||||
Reference in New Issue
Block a user