feat(plex): Playlists Phase 1 — per-user ordered watch-lists (Siftlode-native)
Personal ordered lists of Plex items, kept in Siftlode's own DB (works for users without a Plex account, like watch-state) — the "your own lists" counterpart to shared collections. Plex-direction sync is a later phase (plex_rating_key reserved). Backend: migration 0048 (plex_playlists + plex_playlist_items with position), PlexPlaylist/PlexPlaylistItem models, and per-user CRUD endpoints under /api/plex/playlists (list [+?contains for the add dialog], create [seeded], detail [ordered cards], rename, delete, add/remove item, reorder). _leaf_card handles the movie/episode mix. Frontend: "Add to playlist" dialog from the movie info page (all users), a Playlists section in PlexSidebar (list + create), PlexPlaylistView (reorder up/down, remove, rename, delete, Play all), and PlexPlayer gained an optional `queue` so play-through follows the list order (prev/next + auto-advance). i18n en/hu/de. Verified end-to-end on localdev (backend CRUD + the create→add→view→play-through UI flow).
This commit is contained in:
parent
1fd3003038
commit
25197ed817
16 changed files with 796 additions and 18 deletions
|
|
@ -1109,3 +1109,33 @@ class PlexState(Base, UpdatedAtMixin):
|
|||
synced_to_plex: Mapped[bool] = mapped_column(
|
||||
Boolean, default=False, server_default="false"
|
||||
)
|
||||
|
||||
|
||||
class PlexPlaylist(Base, TimestampMixin, UpdatedAtMixin):
|
||||
"""A per-user ORDERED watch-list of Plex items — Siftlode-native (lives in our own DB, works for
|
||||
users WITHOUT a Plex account, like plex_states). Unlike collections (shared, library-level), a
|
||||
playlist is owned by one user and its items are ordered. Optional Plex-direction sync is a later
|
||||
phase (`plex_rating_key` set once pushed back to the owner's Plex account)."""
|
||||
|
||||
__tablename__ = "plex_playlists"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
||||
title: Mapped[str] = mapped_column(String(512))
|
||||
plex_rating_key: Mapped[str | None] = mapped_column(String(32))
|
||||
|
||||
|
||||
class PlexPlaylistItem(Base):
|
||||
"""One ordered entry in a playlist. `position` (0-based) orders playback."""
|
||||
|
||||
__tablename__ = "plex_playlist_items"
|
||||
__table_args__ = (UniqueConstraint("playlist_id", "item_id", name="uq_plex_playlist_item"),)
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
playlist_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("plex_playlists.id", ondelete="CASCADE"), index=True
|
||||
)
|
||||
item_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("plex_items.id", ondelete="CASCADE"), index=True
|
||||
)
|
||||
position: Mapped[int] = mapped_column(Integer, default=0, server_default="0", nullable=False)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue