The code cited its plan instead of saying why: `E28 review J4`, `(R6 S3b)`, `S1 justified…`,
`deep-review round 5`. That plan lives in the private ops repo, so for every reader of this one the
citation was noise, and a sentence whose subject was the plan step ("round 2 showed…") hid its
lesson behind an id. Each one is gone and the "why" kept: a bare citation is deleted, a sentence
carrying a lesson is reworded around it ("a later attempt showed…").
Measured (`scripts/audit_metrics.py`, product code): 652 lines in 270 files carried an epic code by
the definition the next commit holds (507 / 241 by the old, two-digit-only one) -> 0. Across all
code, tests, scripts and configs: ~1100 epic-code lines plus ~320 sprint/round ids.
Behaviour unchanged, checked mechanically: every changed .py file has the same AST once docstrings
are blanked; css/sh/toml/yml/json files are identical once comments are stripped; the only
non-comment changes in TS/JS are test titles, one description string in a contract table, and five
ESLint messages, whose text is all the gates snapshot diff holds. Not touched: Markdown (docs and
the changelog keep their history), Alembic migrations, TV episode notation (`S2 · E5`), DESIGN.md
ids (`C1`, `B4`, `S3h`), tracker ids (`SEC-16`, `DX-17`).
One stale claim fixed on the way: test_hls_reaper's docstring said the player checkpoints "every
10 s whether or not it is playing", which plex/stream.py calls wrong; it now says what the code does.
90 lines
3.7 KiB
TypeScript
90 lines
3.7 KiB
TypeScript
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: "discover" }
|
|
| { kind: "grid" }
|
|
| { kind: "playlists" } // browse-all-playlists surface (header pill "Playlist" mode)
|
|
| { kind: "collections" } // browse-all-collections surface (header pill "Collection" mode)
|
|
| { kind: "show"; id: string }
|
|
| { kind: "season"; showId: string; seasonId: string }
|
|
// `fromStart`: the card's Restart (C5) — the first item plays from 0, not its resume point.
|
|
| { kind: "player"; id: string; queue?: string[]; fromStart?: boolean }
|
|
| { kind: "info"; id: string }
|
|
| { kind: "person"; name: string }
|
|
| { kind: "playlist"; id: number }
|
|
| { kind: "collection"; id: string }; // the Collection info page (id = collection rating_key)
|
|
|
|
// Mirror the Plex sub-view to ?v=<kind>:<args> so a show / season / movie-info / person / playlist page
|
|
// — and the flat browse grid — are bookmarkable. Discover is the ROOT landing, so it (and the
|
|
// ephemeral player) is not mirrored (encode → null); the grid gets `?v=browse` so "Browse all" is a
|
|
// distinct, shareable URL. The person name is the whole tail after the first ":", so a name containing
|
|
// ":" round-trips.
|
|
export const PLEX_SUB_URL: SubviewUrl<Sub> = {
|
|
key: "v",
|
|
encode: (v) => {
|
|
switch (v.kind) {
|
|
case "grid":
|
|
return "browse";
|
|
case "playlists":
|
|
return "playlists";
|
|
case "collections":
|
|
return "collections";
|
|
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}`;
|
|
case "collection":
|
|
return `collection:${v.id}`;
|
|
default:
|
|
return null; // discover (root) + the ephemeral player are not URL-mirrored
|
|
}
|
|
},
|
|
// `fromStart` is the Restart CLICK, not a property of the entry: kept in history.state it restarted
|
|
// the item from 0 again on every reload or Forward onto the player, and the progress checkpoint
|
|
// then overwrote the resume point it had skipped.
|
|
entry: (v) => (v.kind === "player" && v.fromStart ? { ...v, fromStart: undefined } : v),
|
|
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 "browse":
|
|
return { kind: "grid" };
|
|
case "playlists":
|
|
return { kind: "playlists" };
|
|
case "collections":
|
|
return { kind: "collections" };
|
|
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:<arg> 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 "collection":
|
|
return arg ? { kind: "collection", id: arg } : null;
|
|
case "season": {
|
|
const [showId, seasonId] = arg.split(":");
|
|
return showId && seasonId ? { kind: "season", showId, seasonId } : null;
|
|
}
|
|
default:
|
|
return null;
|
|
}
|
|
},
|
|
};
|