Commit graph

6 commits

Author SHA1 Message Date
npeter83
993e6ba7d5 fix(playlists): dirty lagged one edit (flush before fingerprinting)
The session has autoflush off, so recompute_dirty's query read the last-committed
state, not the current request's pending item/order edits — so the first reorder
after a sync compared against itself and missed dirty, and only the next edit showed
it. Flush pending changes before computing the current fingerprint. Verified: a swap
now flips dirty immediately, and reverting to the original clears it.
2026-06-16 00:11:58 +02:00
npeter83
6330ac3184 feat(playlists): derive dirty from a synced-state fingerprint
Store a SHA-256 of each playlist's name + ordered video ids as last synced from /
pushed to YouTube (migration 0013, backfilled for already-clean linked playlists).
'dirty' is now recomputed on every edit by comparing the current fingerprint to that
baseline instead of being stickily set true. So manually restoring the original order
(or undo back to it) clears dirty on its own — the Reset to YouTube button disappears
and no YouTube read is needed. Baseline is set on read-sync, repull (reset), and a
clean push; a missing baseline counts as dirty (unknown YT state). Verified the
migration's fingerprint matches the app's runtime fingerprint exactly.
2026-06-15 23:00:56 +02:00
npeter83
55833d8f72 feat(playlists): reset a playlist to its YouTube state (discard local edits)
The in-session undo/redo is lost when switching playlists, leaving no way to undo
local edits to a YouTube-linked list afterwards. Add a per-playlist 'Reset to YouTube'
action (shown when a linked playlist is dirty) that force-repulls that single playlist
from YouTube, replacing its items/order/name and clearing dirty — even though the bulk
read-sync skips dirty playlists. Backend: repull_playlist() + POST /api/playlists/
{id}/revert-youtube (read-scope gated). Confirm dialog (destructive). Trilingual.
2026-06-15 22:28:16 +02:00
npeter83
9acea11010 feat(playlists): make YouTube-mirrored playlists editable + syncable
Mirrors (source='youtube') were read-only; per the original two-way design they can
now be edited locally (add/remove/reorder/rename) and pushed back. The read-sync
skips a dirty mirror so it won't clobber unpushed edits; a successful push clears
dirty and lets the mirror refresh. _mark_dirty now covers any YouTube-linked list
(exported local or mirror), and rename marks dirty too. push/delete no longer reject
mirrors. Push reconciles the title as well (cheap playlists.list compare, then
playlists.update only if changed) so a local rename doesn't revert on the next pull.
Frontend: editable = not-built-in (was also excluding mirrors); rows/reorder enabled
for all owned lists; AddToPlaylist popover lists mirrors too (with a YT marker); the
origin chip now reads 'edits sync back'. Trilingual.
2026-06-15 21:40:13 +02:00
npeter83
b150337c87 feat(playlists): push local playlists to YouTube (export + diff sync)
Local 'user' playlists (not Watch later, not YouTube mirrors) can now be pushed
to YouTube: create a new playlist on first push, else reconcile membership + order
so YouTube matches local (local wins). plan_push computes a dry-run estimate
(inserts/deletes/reorders + quota units + divergence) read from the live YouTube
state; push refuses if the estimate exceeds the remaining daily quota so a big
playlist can't strand half-pushed. Reorder uses an insertion-sort move count that
matches what executes. Edits to a linked playlist set dirty; a successful push
clears it. DELETE accepts on_youtube to also delete the playlist on YouTube. The
read-sync now skips YouTube playlists already owned by a local export, avoiding
duplicate read-only mirrors.
2026-06-15 21:23:02 +02:00
npeter83
a661d079ee feat(playlists): YouTube playlist read-sync (backend)
Mirror each user's own YouTube playlists into local source='youtube' playlists,
one-way (YT -> local). New client methods iter_my_playlists / iter_my_playlist_video_ids
(OAuth, so private playlists work); sync/playlists.py reconciles the mirror (matching YT
order) and ingests any playlist videos not in the shared catalog yet (with stub channels).
POST /api/playlists/sync-youtube for manual sync (read-scope gated, per-user quota) plus a
scheduler job (playlist_sync_minutes, default 6h) that syncs all read-scope users. YouTube's
Watch Later / History are not API-accessible and are never synced.
2026-06-15 19:37:03 +02:00