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.
This commit is contained in:
parent
380ad39ad4
commit
55833d8f72
7 changed files with 120 additions and 4 deletions
|
|
@ -305,6 +305,39 @@ def push_playlist(db: Session, user: User, pl: Playlist) -> dict:
|
|||
}
|
||||
|
||||
|
||||
def repull_playlist(db: Session, user: User, pl: Playlist) -> dict:
|
||||
"""Force-refresh ONE YouTube-linked playlist from YouTube, discarding local edits and
|
||||
clearing dirty. This is the per-playlist 'reset to YouTube' — unlike the bulk read-sync
|
||||
it deliberately does NOT skip a dirty playlist (overwriting local changes is the point).
|
||||
Works for both mirrors (source='youtube') and exported local playlists (yt_playlist_id)."""
|
||||
if not pl.yt_playlist_id:
|
||||
raise YouTubeError("Playlist is not linked to YouTube")
|
||||
with YouTubeClient(db, user) as yt:
|
||||
snippet = yt.get_playlist_snippet(pl.yt_playlist_id)
|
||||
if snippet is None:
|
||||
raise YouTubeError("Playlist no longer exists on YouTube")
|
||||
ids = list(yt.iter_my_playlist_video_ids(pl.yt_playlist_id))
|
||||
_ensure_videos(db, yt, ids)
|
||||
present = (
|
||||
set(db.execute(select(Video.id).where(Video.id.in_(ids))).scalars().all())
|
||||
if ids
|
||||
else set()
|
||||
)
|
||||
ordered: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for v in ids:
|
||||
if v in present and v not in seen:
|
||||
seen.add(v)
|
||||
ordered.append(v)
|
||||
pl.name = snippet.get("title") or pl.name
|
||||
db.execute(delete(PlaylistItem).where(PlaylistItem.playlist_id == pl.id))
|
||||
for pos, vid in enumerate(ordered):
|
||||
db.add(PlaylistItem(playlist_id=pl.id, video_id=vid, position=pos))
|
||||
pl.dirty = False
|
||||
db.commit()
|
||||
return {"items": len(ordered)}
|
||||
|
||||
|
||||
def sync_all_playlists(db: Session) -> dict:
|
||||
"""Scheduler entry point: mirror playlists for every user with a read scope + token."""
|
||||
users = (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue