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.
8.8 KiB
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/currentItemstale-flash race fixed vialoadingEpisodeId.- App-wide Jellyfin remote control: a
PlaybackControllercontract (utils/playback/playbackController.ts); a pure WS-message mapper (utils/playback/remoteCommands.ts, unit-tested);hooks/useRemoteControl.tsdispatches to whichever player (cast / native video / music) is registered.WebSocketProvideradvertises 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:
- Trickplay preview window is truncated at the right screen edge / does not track the cursor.
- The progress-bar touch zone overlaps the 4-button episode row.
- The purple time label should sit directly above the progress cursor.
- Trickplay on the mini-player progress bar.
- A stop button on the mini-player.
These now live in clean post-C files (
CastPlayerProgressBar,CastingMiniPlayer).
- Repo hygiene — add
* text=auto eol=lfto.gitattributes(fixes the ~124 CRLF errors inbun run check); de-duplicateBitRateSheet.tsxvsBitrateSelector.tsx; remove the unusedliveProgressexport fromuseCastPlayerProgress.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
PlaybackControllerregistry 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:
getStreamUrlstill takesMediaSources[0]internally — fine becausegetPlaybackInfois called withmediaSourceId.
- D: the
8. How to resume
- 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 isdocs/chromecast-test-matrix.md. - Push. When satisfied, push
refactor-chromecastto update draft PR #1402 (46 commits unpushed). Decide first what to do with the two uncommitted files (see §9). - 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-Bytrailer. - GPG: committing requires a warm
gpg-agentcache;~/.gnupg/gpg-agent.confwas 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.