The Plex player names the playlist it plays through (v=player:<id>:playlist:<pid>), so a bookmark
rebuilds the queue from the playlist's own order while the item is still in it.
Found in the browser and fixed:
- after a reload the shell's player opened a second one over Home and the feed: it read the catalog
row the page had fetched (a disabled query still reads the shared cache); it now waits for ready.
- every reload under an open overlay left a dead history step: the first overlay to open takes over
the entry the document was loaded on.
- the feed's address was implicit, the same as the start-page landing, so a reloaded or bookmarked
feed opened as Home: the feed now names itself (page=feed) like every page.
- a linked file or video that is gone was said, but stayed in the address and was said again on
every reload: its keys are taken off.
The overlay address is written in one place (the entry is named once it is current), and the player
keys only the codec reads are no longer exported.
The player names what it plays in its own history entry (watch, wrel, wtab): a reload or a
bookmark reopens it on the page that hosts it, with that page's list as the queue, or alone
from the catalog (GET /api/videos/{id}/row); a page that hosts none gets the shell's. Back
lands on the page's address without it (useBackToClose's url; ui/Modal passes it on). The
Files viewer and player do the same (fview, fplay). The Plex and channel-manager views are
always written in full, as their fallback is remembered state.
Adds a movie-scoped "Playback" filter to the Plex feed so a user can isolate items by how
they play — the groundwork for collecting HW-transcodable (or no-transcode) versions.
Four classes derived from the stored `playable` + a new `transcode_hw` facet:
- Direct Play (direct), Direct Stream (remux)
- Transcode · HW — playable=transcode AND the iGPU can hardware-transcode it
- Transcode · SW — playable=transcode, software libx264 only
The HW/SW split is precise, not codec-only: a 10-bit/HDR HEVC is HW-decodable yet breaks the
VAAPI nv12 pipeline (the same case plex/stream special-cases), so it must count as SW.
Backend:
- New PlexItem columns (migration 0077): transcode_hw, video_bit_depth, media_probed_at.
Migration backfills transcode_hw codec-only so the filter works immediately.
- `plex.sync.transcode_hw_capable` is the single classifier; the HW-decodable codec set moves
to sync as `HW_DECODABLE_CODECS` and plex.stream imports it, so the catalog facet and the
runtime encoder choice can't disagree by codec.
- Bit-depth backfill (`_probe_media_batch`, wired into sync): probes only HW-decodable transcode
items' video Stream for bit-depth + HDR and refines a 10-bit/HDR HEVC to software. Bounded
per run, watermarked by media_probed_at. A codec change resets the watermark (stale probe).
- Filter + self-excluded facet on a shared `playback_class_expr` CASE (movie-leg only — a show
is an aggregate with no single class). transcode_hw threaded onto the feed/detail/card JSON.
Frontend:
- Multi-select "Playback" Combobox in the sidebar (movie scope, facet-empty drop-out), active
chips, 4-way corner-dot badge (green/blue/amber/red) + tooltip, and an info-page playback chip
with a codec · bit-depth subtitle. New `bg-info` (blue) token, i18n HU/EN parity.
- Fix a regression where the card's playback dot lost its hover tooltip: the full-card reveal
overlay swallowed the cursor; the dot now sits above it (z-20).
Gate: backend full lane + frontend typecheck/lint/knip/prettier/vitest all green. Browser-UAT'd
on localdev (filter narrows to the SW set, facet counts, badge colour + tooltip, info chip).
Mirror the Plex-browse content state into the address bar so a browse view is
bookmarkable/shareable, the Plex analogue of the feed's urlState. Keys are
NAMESPACED (pscope/psort/pshow/pf) rather than reusing the feed's bare
scope/sort/show: FeedFiltersProvider actively strips its own KEYS from the URL
whenever off the feed page, so a shared key would be deleted out from under the
Plex page. The namespaced keys are Plex-unique (like ?v=/?pl), so no other
provider ever reads or clears them.
- New lib/plexUrlState.ts: plexParamUpdates / plexParamsToState / hasPlexParams.
The pf filter blob reuses the SAME appendPlexFilters wire serializer (new
public plexFiltersToParams + inverse parsePlexFilters, kept next to each other
so a new wire key can't be added on one side only).
- PlexProvider: URL-seed wins over localStorage at mount; the account-pin
rehydrate persists the seed instead of clobbering it (mirrors feed's
initialHadUrlFilters); useUrlMirror mirrors/clears the 4 keys, gated on
page===plex. q/field stay out of the shareable contract.
- NavigationProvider: a page switch now also nulls the 4 plex keys.
Tests: 8 new round-trip cases in plexUrlState.dom.test.ts (FE vitest 483→491).