feat(player): persistent auto-advance + loop playback modes
Two saved-to-account playback settings on the player's prev/next bar (any queued player — feed or playlist): Auto-advance (Off/Next/Prev/Random — what plays when a video ends) and Loop (Off / One = repeat the current video / All = wrap the list at its ends; a single-item list repeats). Stored in users.preferences (playerAutoAdvance/playerLoop), read from the cached me + written via savePrefs so they apply everywhere and survive reloads. The feed's player queue is now the live filtered feed with the watch-state filter NOT applied — marking the current video watched keeps it in the sequence (no reindex/reload mid-play), while a hidden video still drops out. Removes the old frozen-queue workaround and the boolean autoAdvance prop. i18n en/hu/de.
This commit is contained in:
parent
597cec6517
commit
d02c338465
5 changed files with 161 additions and 27 deletions
|
|
@ -306,10 +306,16 @@ export default function Feed({
|
|||
|
||||
const loaded: Video[] = (query.data?.pages ?? []).flatMap((p) => p.items);
|
||||
loadedRef.current = loaded;
|
||||
const items: Video[] = loaded
|
||||
.map((v) => (overrides[v.id] ? { ...v, status: overrides[v.id] } : v))
|
||||
.map((v) => (savedOverrides[v.id] !== undefined ? { ...v, saved: savedOverrides[v.id] } : v))
|
||||
.filter((v) => matchesView(v.status, filters.show));
|
||||
const withOverrides = (list: Video[]): Video[] =>
|
||||
list
|
||||
.map((v) => (overrides[v.id] ? { ...v, status: overrides[v.id] } : v))
|
||||
.map((v) => (savedOverrides[v.id] !== undefined ? { ...v, saved: savedOverrides[v.id] } : v));
|
||||
const items: Video[] = withOverrides(loaded).filter((v) => matchesView(v.status, filters.show));
|
||||
// The in-app player's queue (auto-advance / loop / prev-next). It's the filtered feed, but the
|
||||
// watch-state view filter is NOT applied — so marking the current video watched keeps it in the
|
||||
// sequence (no reindex/reload mid-play), matching "watched doesn't affect the list". A video that
|
||||
// goes hidden still drops out ("visible affects").
|
||||
const playerQueue: Video[] = withOverrides(loaded).filter((v) => v.status !== "hidden");
|
||||
|
||||
// --- Live YouTube search mode -------------------------------------------------------------
|
||||
// A separate data source rendered in the same cards/player. No watch-state view filter (the
|
||||
|
|
@ -317,9 +323,8 @@ export default function Feed({
|
|||
if (ytActive) {
|
||||
const ytLoaded: Video[] = (ytQuery.data?.pages ?? []).flatMap((p) => p.items);
|
||||
loadedRef.current = ytLoaded;
|
||||
const ytItems: Video[] = ytLoaded
|
||||
.map((v) => (overrides[v.id] ? { ...v, status: overrides[v.id] } : v))
|
||||
.map((v) => (savedOverrides[v.id] !== undefined ? { ...v, saved: savedOverrides[v.id] } : v));
|
||||
const ytItems: Video[] = withOverrides(ytLoaded);
|
||||
const ytPlayerQueue: Video[] = ytItems.filter((v) => v.status !== "hidden");
|
||||
const ytError =
|
||||
ytQuery.error instanceof HttpError
|
||||
? ytQuery.error.detail || t("feed.yt.error")
|
||||
|
|
@ -446,8 +451,7 @@ export default function Feed({
|
|||
<PlayerModal
|
||||
video={activeVideo.video}
|
||||
startAt={activeVideo.startAt}
|
||||
queue={ytItems}
|
||||
autoAdvance={false}
|
||||
queue={ytPlayerQueue}
|
||||
onClose={() => setActiveVideo(null)}
|
||||
onState={onState}
|
||||
onOpenChannel={onOpenChannel}
|
||||
|
|
@ -656,8 +660,7 @@ export default function Feed({
|
|||
<PlayerModal
|
||||
video={activeVideo.video}
|
||||
startAt={activeVideo.startAt}
|
||||
queue={items}
|
||||
autoAdvance={false}
|
||||
queue={playerQueue}
|
||||
onClose={() => setActiveVideo(null)}
|
||||
onState={onState}
|
||||
onOpenChannel={onOpenChannel}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue