import type { SubviewUrl } from "../lib/history"; import { parsePositiveIntId } from "../lib/parseId"; // The Plex module's sub-view union and its address-bar mirror, extracted from PlexBrowse so the // encode/decode round-trip (and its guards) can be unit-tested without pulling the whole component // (and its lazy hls.js player) into the test graph. export type Sub = | { kind: "grid" } | { kind: "show"; id: string } | { kind: "season"; showId: string; seasonId: string } | { kind: "player"; id: string; queue?: string[] } | { kind: "info"; id: string } | { kind: "person"; name: string } | { kind: "playlist"; id: number }; // Mirror the Plex sub-view to ?v=: so a show / season / movie-info / person / playlist page // is bookmarkable. Grid (root) and the ephemeral player are not mirrored (encode → null). The person // name is the whole tail after the first ":", so a name containing ":" round-trips. export const PLEX_SUB_URL: SubviewUrl = { key: "v", encode: (v) => { switch (v.kind) { case "show": return `show:${v.id}`; case "season": return `season:${v.showId}:${v.seasonId}`; case "info": return `info:${v.id}`; case "person": return `person:${v.name}`; case "playlist": return `playlist:${v.id}`; default: return null; // grid + the ephemeral player are not URL-mirrored } }, decode: (raw) => { const i = raw.indexOf(":"); const kind = i === -1 ? raw : raw.slice(0, i); const arg = i === -1 ? "" : raw.slice(i + 1); switch (kind) { case "show": return arg ? { kind: "show", id: arg } : null; case "info": return arg ? { kind: "info", id: arg } : null; case "person": return arg ? { kind: "person", name: arg } : null; case "playlist": { // Positive-integer id only — a fractional/zero/negative ?v=playlist: would open a // sub-view for a non-existent id (shares parsePositiveIntId with readSelectedId's ?pl guard). const id = parsePositiveIntId(arg); return id != null ? { kind: "playlist", id } : null; } case "season": { const [showId, seasonId] = arg.split(":"); return showId && seasonId ? { kind: "season", showId, seasonId } : null; } default: return null; } }, };