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.
This commit is contained in:
parent
49d226126c
commit
9acea11010
8 changed files with 58 additions and 26 deletions
|
|
@ -24,9 +24,10 @@ def _own_playlist(db: Session, user: User, playlist_id: int) -> Playlist:
|
|||
|
||||
|
||||
def _mark_dirty(pl: Playlist) -> None:
|
||||
"""Flag a YouTube-linked local playlist as having unpushed local edits, so the UI can
|
||||
offer a 'Sync to YouTube'. No-op for un-linked or mirrored playlists."""
|
||||
if pl.source == "local" and pl.yt_playlist_id:
|
||||
"""Flag a YouTube-linked playlist as having unpushed local edits, so the UI can offer
|
||||
a 'Sync to YouTube' and the read-sync won't clobber them. Covers both exported local
|
||||
playlists and edited YouTube mirrors; no-op for un-linked lists and Watch later."""
|
||||
if pl.kind != "watch_later" and pl.yt_playlist_id:
|
||||
pl.dirty = True
|
||||
|
||||
|
||||
|
|
@ -222,10 +223,6 @@ def _pushable(db: Session, user: User, playlist_id: int) -> Playlist:
|
|||
raise HTTPException(
|
||||
status_code=400, detail="The Watch later list can't be sent to YouTube."
|
||||
)
|
||||
if pl.source == "youtube":
|
||||
raise HTTPException(
|
||||
status_code=400, detail="This playlist already mirrors a YouTube playlist."
|
||||
)
|
||||
return pl
|
||||
|
||||
|
||||
|
|
@ -335,7 +332,9 @@ def rename_playlist(
|
|||
name = (payload.get("name") or "").strip()
|
||||
if not name:
|
||||
raise HTTPException(status_code=400, detail="name cannot be empty")
|
||||
pl.name = name
|
||||
if name != pl.name:
|
||||
pl.name = name
|
||||
_mark_dirty(pl)
|
||||
db.commit()
|
||||
count = db.scalar(
|
||||
select(func.count()).where(PlaylistItem.playlist_id == pl.id)
|
||||
|
|
@ -354,11 +353,6 @@ def delete_playlist(
|
|||
if pl.kind == "watch_later":
|
||||
raise HTTPException(status_code=400, detail="The Watch later list can't be deleted.")
|
||||
if on_youtube:
|
||||
if pl.source == "youtube":
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="This is a mirror of a YouTube playlist; manage it on YouTube.",
|
||||
)
|
||||
if not pl.yt_playlist_id:
|
||||
raise HTTPException(status_code=400, detail="This playlist isn't on YouTube.")
|
||||
if not has_write_scope(user):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue