3.3 KiB
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:
- Fetch playlist metadata
- Create/update queue items for all playlist videos
- Download available queued items
- On normal temporary errors: retry later
- On YouTube rate-limit / bot check: pause the whole sync
- On unavailable/private/deleted videos: mark as permanent failure
- 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.