feat(web): #415 stage 3 (web) — rotation-aware system playlist play
Web half of Stage 3. System-playlist tile play now:
- calls the new GET /api/playlists/system/{variant}/shuffle endpoint
(rotation-aware order from the server) instead of getPlaylist;
plays the returned order AS-IS — no client Fisher-Yates, since
the server already ordered it. Supersedes #413's client shuffle
for system playlists specifically; user playlists keep getPlaylist
+ stored order.
- tags the queue with the system variant. The player store carries
_queueSource; the events dispatcher includes `source` on
play_started so the server advances that playlist's rotation.
User playlists are unchanged (getPlaylist, plain playQueue, no
source). Tests updated: For-You play hits systemShuffle (not
getPlaylist/refresh) and passes source:for_you; user play uses
getPlaylist + plain playQueue with no source.
Flutter half is blocked — the Flutter client has no play-event
reporting at all (no /api/events POST, no scrobble), so there's no
play_started to attach `source` to. Surfacing that as a separate
decision rather than silently scope-exploding #415.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,18 @@ export async function getPlaylist(id: string): Promise<PlaylistDetail> {
|
||||
return api.get<PlaylistDetail>(`/api/playlists/${encodeURIComponent(id)}`);
|
||||
}
|
||||
|
||||
// #415 stage 2/3: rotation-aware play order for a system playlist.
|
||||
// Same shape as getPlaylist but tracks are server-ordered (unplayed
|
||||
// this rotation first, then heard; resets when exhausted). The model
|
||||
// variant uses underscores; the route segment is hyphenated.
|
||||
// Intentionally uncached — it varies per play, unlike getPlaylist.
|
||||
export async function systemShuffle(variant: string): Promise<PlaylistDetail> {
|
||||
const seg = variant === 'for_you' ? 'for-you' : variant;
|
||||
return api.get<PlaylistDetail>(
|
||||
`/api/playlists/system/${encodeURIComponent(seg)}/shuffle`,
|
||||
);
|
||||
}
|
||||
|
||||
export type CreatePlaylistInput = {
|
||||
name: string;
|
||||
description?: string;
|
||||
|
||||
Reference in New Issue
Block a user