fix(chapters): address review findings + trickplay polish

Copilot + CodeRabbit review findings:
- React.memo ChapterTicks and ChapterList (project guideline: hot-path
  components must use React.memo to cut redraw work during control
  updates).
- chapterNameAt now sorts the chapter array once instead of twice per
  call. The previous version went through currentChapterIndex
  (chapterStartsMs + sort) then sortedChapters (sort again). Runs on
  every playback tick, so the duplicate work added up.
- Import getUserLibraryApi from the public barrel
  (@jellyfin/sdk/lib/utils/api) instead of the deep internal path
  (@jellyfin/sdk/lib/utils/api/user-library-api) to match the rest of
  the codebase and avoid coupling to SDK file layout.

TrickplayBubble polish:
- Sit just above the slider (bottom: 0) so the bubble no longer overlaps
  the progress bar.
- Move the chapter-name + timestamp overlay to the bottom-left of the
  preview frame, smaller font, in front of the surrounding overlays
  (zIndex + elevation).

BottomControls cleanup:
- Drop dev-only "pick one to test" comment in favour of a one-line note
  on TICK_HEIGHT.
- Inline scrubMs into its useMemo callback so the scrub-chapter-name
  lookup only recomputes while a slide is active.
This commit is contained in:
Gauvain
2026-05-27 20:08:21 +02:00
parent 558fb41833
commit e3f4eea132
6 changed files with 21 additions and 10 deletions

View File

@@ -70,9 +70,16 @@ export const chapterNameAt = (
positionMs: number,
chapters: ChapterInfo[] | null | undefined,
): string | null => {
const idx = currentChapterIndex(positionMs, chapters);
if (idx < 0) return null;
// Sort once, derive both the active index and the entry from the same array
// — `chapterNameAt` runs on every playback tick, so paying for one `sort()`
// instead of two is worth the duplication of the index loop here.
const sorted = sortedChapters(chapters);
let idx = -1;
for (let i = 0; i < sorted.length; i++) {
if (positionMs >= sorted[i].positionMs) idx = i;
else break;
}
if (idx < 0) return null;
const name = sorted[idx]?.chapter.Name;
return name && name.length > 0 ? name : null;
};