fix(plex): a collection sibling is a full Plex card, and the player's info overlay plays it

- PlexInfo's collection strip gives each card the related strip's action set: the "…" menu (with
  Restart for a touch reader), the watched toggle and the playlist add.
- `onPlayItem` is required, so no variant draws a Play that does nothing; the player's info overlay
  plays the sibling in the running player (`go(id, _, fromZero)` for its Restart).
This commit is contained in:
2026-09-27 14:44:38 +02:00
parent efa4aeeeda
commit 70f98b352f
4 changed files with 180 additions and 20 deletions
+18 -3
View File
@@ -623,6 +623,9 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
// to that item (Back within 3 s of the next) resumes it like any other. A flag, not a consumed
// prop: StrictMode replays this effect, and a consumed one resumed on the replay.
const movedOnRef = useRef(false);
// An item `go` was asked to play from its start (a collection sibling's Restart in the info
// overlay); the opening item's own `fromStart` is the prop above.
const startAtZeroRef = useRef<string | null>(null);
useEffect(() => {
if (!detail || detail.id !== id || startedForRef.current === id) return;
startedForRef.current = id;
@@ -637,7 +640,9 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
setAudioOrd(aOrd);
setSubOrd(subOrdForLang(detail.subtitle_streams ?? [], subLang));
const resume =
detail.status !== "watched" && !(fromStart && !movedOnRef.current)
detail.status !== "watched" &&
!(fromStart && !movedOnRef.current) &&
startAtZeroRef.current !== id
? detail.position_seconds || 0
: 0;
void loadSession(resume);
@@ -818,8 +823,9 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
);
const go = useCallback(
(otherId: string | null | undefined, watchedWrite?: Promise<unknown>) => {
(otherId: string | null | undefined, watchedWrite?: Promise<unknown>, fromZero = false) => {
if (otherId) {
startAtZeroRef.current = fromZero ? otherId : null;
// A played-through item settles as watched, with no checkpoint at the credits (see
// usePlexProgress's `finish`) — said BEFORE the pause below, whose own checkpoint on the
// 'pause' event can land before the player has re-rendered for the next item. The write is
@@ -1840,7 +1846,16 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
onClick={(e) => e.stopPropagation()}
>
<Suspense fallback={null}>
<PlexInfo detail={detail} variant="overlay" onClose={() => setInfoOpen(false)} />
<PlexInfo
detail={detail}
variant="overlay"
onClose={() => setInfoOpen(false)}
// A collection sibling plays right here (E28 review D1), as Next would.
onPlayItem={(other, fromZero) => {
setInfoOpen(false);
go(other, undefined, fromZero);
}}
/>
</Suspense>
</div>
</div>