docs(casting): add chromecast refactor handoff & resume document

Captures the full state of the A/B/C/D sub-projects and the #1367 prep:
commit ranges, verification status, pending queue, key decisions, and
how to resume the work in a later session.
This commit is contained in:
Uruk
2026-05-22 02:32:36 +02:00
parent 8b94f491e4
commit 788a3b7cfd

View File

@@ -0,0 +1,175 @@
# Chromecast Refactor — Handoff & Resume Document
**Branch:** `refactor-chromecast` · **PR:** #1402 (draft) · **Last updated:** 2026-05-22
This document captures the full state of the Chromecast refactor so the work can be
resumed in a later session. Specs and plans for each sub-project live in
`docs/superpowers/specs/` and `docs/superpowers/plans/`.
---
## 1. Summary
The Chromecast casting code (PR #1402) was refactored in four sub-projects plus one
prep task. All four are **implemented, type-checked, and unit-tested**; the branch is
86 commits ahead of `develop`, **46 commits unpushed** to `origin/refactor-chromecast`.
| Sub-project | What | Status |
|---|---|---|
| **A** — Device profiles | Per-device capability detection, profile builder, unified `loadCastMedia`, crash fixes (status 2100, 5.1, bitrate) | ✅ done, **verified on hardware** |
| **Prep #1367** — Segment-skip | Backport segment-skip fixes to PR #1367, remove 177 dead lines | ✅ done, **pushed to #1367** |
| **B** — Track switching | `CastSelection` source-of-truth via customData, audio/subtitle/quality/version switching, multi-version | ✅ done, **verified on hardware** |
| **C** — Player split | `casting-player.tsx` 1428→574 lines: 6 components + 4 hooks | ✅ done, **needs manual re-test** |
| **D** — Session & remote control | Correct PlayMethod, conditional episode buttons, `loadEpisode` race fix, app-wide Jellyfin remote control | ✅ done, **needs manual test** |
Verification gate for the whole branch: `bun run typecheck` ✅, `bun test utils/`
(32 tests). Note: project-wide `bun run check` shows ~124 pre-existing CRLF errors —
a Windows `core.autocrlf` artifact, unrelated to this work (see §6).
---
## 2. Sub-project A — Device profiles & capability detection
**Spec:** `specs/2026-05-21-chromecast-profiles-design.md` · **Plan:**
`plans/2026-05-21-chromecast-profiles.md` · **Commits:** `bcfa8c6d`..`73214f5d`
Replaced the two static device profiles with `detectCapabilities()` +
`buildChromecastProfile()` (`utils/casting/capabilities.ts`, `buildProfile.ts`), a
unified `loadCastMedia()` (`utils/casting/castLoad.ts`) with downgrade-on-failure,
and `chromecastProfile` / `chromecastMaxBitrate` settings replacing
`enableH265ForChromecast`. Fixed the audio-index, media-source, and PlaySessionId
load-path bugs.
**Verified:** all 7 test-matrix files cast successfully on the Chromecast HD,
including a 50 Mb/s HEVC-10bit movie that previously crashed with status 2100.
---
## 3. Prep — Segment-skip reconciliation (PR #1367)
The chromecast branch and PR #1367 (`autoskip`) both carried segment-skip; #1367 was
behind. The chromecast branch's fixes were backported to the `autoskip` branch
(`useSegmentSkipper` auto-skip-by-identity, `Controls` stale-closure fix, `segments`
cleanup) and the two dead hooks `useIntroSkipper`/`useCreditSkipper` (177 lines) were
removed. **Commit `0990e479` is pushed to `origin/autoskip` — PR #1367 is updated.**
The `page.tsx` plugin-lock lines were not backported (depend on a newer
`PlatformDropdown` not on #1367's base — will arrive when #1367 rebases on develop).
---
## 4. Sub-project B — Track switching & multi-version
**Spec:** `specs/2026-05-21-chromecast-track-switching-design.md` · **Plan:**
`plans/2026-05-21-chromecast-track-switching.md` · **Commits:** `3d65c3bb`..`23b4f20d`
`CastSelection` (`utils/casting/selection.ts`) is the single source of truth, carried
in cast `customData` and read back by `hooks/useCastSelection.ts` with an optimistic
pending overlay. Audio / subtitle / quality / version switching all reflect reality.
The shared `BITRATES` ladder (`components/BitrateSelector.tsx`) was expanded; the cast
quality menu filters it by device capability and media bitrate.
**Verified:** audio (Bleach JP↔FR), SubRip subtitles, and bitrate switching all work
on hardware — which also confirms the `customData` round-trip.
---
## 5. Sub-project C — `casting-player.tsx` split
**Spec:** `specs/2026-05-22-chromecast-player-split-design.md` · **Plan:**
`plans/2026-05-22-chromecast-player-split.md` · **Commits:** `02df2477`..`1ea7f0f4`
Decomposed the 1428-line god-component into a 574-line orchestrator + 6
presentational components (`components/casting/player/`) + 4 hooks
(`useCastPlayerItem`, `useCastEpisodes`, `useCastDismissGesture`,
`useCastPlayerProgress`). Purely structural — zero behaviour change.
**Needs manual re-test:** the cast player has no unit tests; re-test cast + episode
playback, track switching, scrub/trickplay, dismiss — behaviour must match pre-split.
---
## 6. Sub-project D — Session reporting & remote control
**Spec:** `specs/2026-05-22-chromecast-session-remote-control-design.md` · **Plan:**
`plans/2026-05-22-chromecast-session-remote-control.md` · **Commits:**
`288b390e`..`8b94f491`
- Cast sessions now report the real `PlayMethod` (`Transcode`/`DirectPlay`).
- Episode Previous/Next buttons render only when an adjacent episode exists.
- `loadEpisode`/`currentItem` stale-flash race fixed via `loadingEpisodeId`.
- **App-wide Jellyfin remote control:** a `PlaybackController` contract
(`utils/playback/playbackController.ts`); a pure WS-message mapper
(`utils/playback/remoteCommands.ts`, unit-tested); `hooks/useRemoteControl.ts`
dispatches to whichever player (cast / native video / music) is registered.
`WebSocketProvider` advertises the commands and routes the messages.
**Needs manual test:** from the Jellyfin dashboard's active-session panel — pause /
stop / seek / next / volume / "send message" against the cast and the native player.
---
## 7. Pending work (queue)
- **UX player sub-project** (not started) — 5 items the user reported:
1. Trickplay preview window is truncated at the right screen edge / does not track
the cursor.
2. The progress-bar touch zone overlaps the 4-button episode row.
3. The purple time label should sit directly above the progress cursor.
4. Trickplay on the mini-player progress bar.
5. A stop button on the mini-player.
These now live in clean post-C files (`CastPlayerProgressBar`, `CastingMiniPlayer`).
- **Repo hygiene** — add `* text=auto eol=lf` to `.gitattributes` (fixes the ~124
CRLF errors in `bun run check`); de-duplicate `BitRateSheet.tsx` vs
`BitrateSelector.tsx`; remove the unused `liveProgress` export from
`useCastPlayerProgress.ts`.
- **Custom Cast receiver** (deferred from sub-project A) — PR #1521 builds a custom
CAF receiver. Decided to defer; revisit as its own sub-project. It would own
subtitle rendering/styling (ASS, custom style — issues #1452, #1543) and cleaner
session integrity. Sender-side work so far does not block it.
- **Open review notes** (low severity, not fixed):
- D: the `PlaybackController` registry is last-write-wins; the spec's "cast
precedence" is not actually enforced (acceptable — one player at a time).
- D: remote next/previous works for cast but is a no-op for the native video
player (its episode navigation lives in `Controls`, not the screen).
- A: `getStreamUrl` still takes `MediaSources[0]` internally — fine because
`getPlaybackInfo` is called with `mediaSourceId`.
---
## 8. How to resume
1. **Test the branch.** Build from `refactor-chromecast` (`bun run android`). Run the
sub-project C manual re-test and the sub-project D dashboard remote-control test.
Sub-project A's matrix is `docs/chromecast-test-matrix.md`.
2. **Push.** When satisfied, push `refactor-chromecast` to update draft PR #1402
(46 commits unpushed). Decide first what to do with the two uncommitted files
(see §9).
3. **Continue.** Pick the next sub-project from §7 — likely the UX player sub-project.
Each sub-project follows the brainstorm → spec → plan → subagent-execution cycle;
specs/plans go in `docs/superpowers/`.
---
## 9. Working-tree / repo notes
- **Uncommitted, intentionally left for the user to decide:**
- `docs/chromecast-test-matrix.md` — modified to list the user's actual library
titles (anime/movies). If PR #1402 should not expose the personal library, revert
this file to its generic committed form before pushing.
- `scripts/find-test-media.ts` — untracked helper that queries Jellyfin and buckets
the library against the test matrix. Commit it if useful, or leave it local.
- **Commits:** this project does **not** use a `Co-Authored-By` trailer.
- **GPG:** committing requires a warm `gpg-agent` cache; `~/.gnupg/gpg-agent.conf`
was set to an 8h TTL.
---
## 10. Key decisions
- **#1367 is the source of truth for segment-skip** — backport flows chromecast →
#1367, never the reverse.
- **Custom receiver deferred** — the crash fixes (A) were decoupled from it; it is a
future sub-project, not a blocker.
- **Long-term goal:** support AirPlay and other cast protocols — the casting layer is
kept protocol-agnostic (`CastProtocol`). The user has an iOS phone and an
AirPlay-capable Samsung screen for testing.