From e89a81a3f1569ca08871a23c8722f61aac130e8f Mon Sep 17 00:00:00 2001 From: Nicolas Date: Tue, 15 Sep 2026 21:32:34 +0200 Subject: [PATCH 1/2] Cast a listen party too, and fix a slow/freezing catalog Three separate reports handled together. Cast was video-only by design (docs/architecture.md flagged it as video-parties-only for v1) - asked for directly, and turned out to need almost nothing new server-side: CastTokenService and the 4 streaming routes' sessionForStream fallback were already keyed on nothing more specific than partyId. cast.ts's localDriver only needed its parameter widened from HTMLVideoElement to HTMLMediaElement - both already share the same currentTime/paused/duration/play()/pause() surface. MusicBar.ts gained the same activeDriver indirection Player.ts already has, with one real difference from the video case: a listen party's queue advances far more often than a video party changes items, so dropping the cast on every track (the video path's own choice there) would have made this worse than not having it - a track change while casting instead calls startCast() again, reusing the already-connected session (a cache-busting query param added since the content URL itself never changes between tracks - the server alone decides what's current). Falls back to local playback if a re-cast throws, same recovery instinct loadTrack's own hls.js try/catch already has. The queue popup: reported separately, a fixed 480px width and a header that scrolled away with the list - both leftover CSS from before the row shape was reworked, never revisited since. Width cap dropped; overflow/max-height moved off the outer .musicBarQueue (which wraps the header too) down onto #queueList alone. The catalog: still too slow, the front freezing while it loads. CatalogService.getLibraryItems was asking Emby for Overview on every one of up to 300 items and never using it (views/library's tiles only ever show a poster/name/year) - dropped. getArtists had no Limit at all, unlike every sibling query. Separately, tiles.ts's shared render path built one HTML string for a whole batch and inserted it via a single innerHTML write - fine for a 16-item carousel, a real hitch for a 300-tile grid. renderTilesInChunks inserts the same tileHtml output 40 at a time across requestAnimationFrame callbacks instead; wireTileButtons switched to one delegated listener so a tile from a later chunk is still clickable. Verified: full typecheck/test/build on both projects (122/122 server tests). The chunked-render mechanism was verified directly - a synthetic 300-item list against a real DOM confirms every item lands and a button in the last chunk still fires through the delegated listener. Not verified: no real Chromecast or Emby login reachable from this sandbox, so the actual on-TV re-cast round trip and the before/after catalog latency against a real large library are both unconfirmed - same standing gap this project already flags for its other casting work. Co-Authored-By: Claude Sonnet 5 --- README.md | 37 +++-- client/src/cast.ts | 33 ++-- client/src/musicBar/MusicBar.css | 32 +++- client/src/musicBar/MusicBar.html | 8 + client/src/musicBar/MusicBar.ts | 213 +++++++++++++++++++++++--- client/src/tiles.ts | 70 +++++++-- client/src/views/library/Library.ts | 4 +- docs/architecture.md | 134 +++++++++++++++- server/src/services/CatalogService.ts | 16 +- 9 files changed, 467 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index e983923..fd3f6aa 100644 --- a/README.md +++ b/README.md @@ -132,14 +132,15 @@ assumes, how a real transcode's seek handling feels once several viewers depend on the exact same one). Casting to a Chromecast (see docs/architecture.md) is the newest, -least-verified piece: the security-critical parts were checked against -the real running server directly (the party-stream/burn routes reject a -request with no auth exactly as before, and now also reject an invalid -`castToken`, both a plain 401) and the Cast SDK itself was confirmed to -load and initialize in a real browser, but there's neither a real -Chromecast nor Emby login credentials in this environment to take it -any further - the actual on-TV playback and the cast button's own -live behavior are unconfirmed. +least-verified piece, for video and music alike: the security-critical +parts were checked against the real running server directly (the +party-stream/burn routes reject a request with no auth exactly as +before, and now also reject an invalid `castToken`, both a plain 401) +and the Cast SDK itself was confirmed to load and initialize in a real +browser, but there's neither a real Chromecast nor Emby login +credentials in this environment to take it any further - the actual +on-TV playback, the cast button's own live behavior, and (for music) a +re-cast actually surviving a real track change are all unconfirmed. ## Project layout @@ -301,13 +302,21 @@ Then put it behind your existing reverse proxy like everything else - [x] Fixed catalog browsing feeling slow: image thumbnails were never cacheable (Emby's own Cache-Control/ETag were silently dropped) — see docs/architecture.md -- [x] Cast a party's video to a Chromecast (Default Media Receiver), - with a play/pause/seek remote on the sender's own screen — see - docs/architecture.md +- [x] Cast a party's video *or* listen-party music to a Chromecast + (Default Media Receiver), with a play/pause/seek remote on the + sender's own screen — music reuses the same `PlaybackDriver`/ + `CastTokenService` the video case introduced, and re-casts + in place on every track change instead of dropping the session + the way an item change does for video — see docs/architecture.md - [x] Fixed the listen-party queue's broken layout (it was reusing an - album page's row grid) and its missing album art (a track almost - never has its own image — now falls back to its album's) — see - docs/architecture.md + album page's row grid), its missing album art (a track almost + never has its own image — now falls back to its album's), and, + reported later, its fixed 480px width and a header that scrolled + away with the queue — see docs/architecture.md +- [x] Fixed a slow, freeze-prone catalog: a library grid's query fetched + an unused `Overview` field for every item, its artist list had no + cap at all, and up to 300 tiles were inserted in one synchronous + pass — see docs/architecture.md - [x] Reworked the video player's bottom bar (episode/request actions/ fullscreen, one bar instead of three floating pieces) and added a real fullscreen toggle — fullscreen now targets the whole player, diff --git a/client/src/cast.ts b/client/src/cast.ts index e5b1036..a762b4b 100644 --- a/client/src/cast.ts +++ b/client/src/cast.ts @@ -3,12 +3,13 @@ * to the Cast Application Framework SDK directly (a CDN global, loaded via * client/src/index.html's