feat(player): the YouTube player and the file viewer are named in the address

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.
This commit is contained in:
2026-10-27 05:29:49 +01:00
parent d4f24de4ba
commit fa893c73a3
45 changed files with 1005 additions and 89 deletions
+18 -7
View File
@@ -48,15 +48,26 @@ const BASE: PlexUrlState = {
};
describe("plexParamUpdates", () => {
it("emits nothing for the all-default state", () => {
it("writes the default view in full: this account remembers one a link must not inherit", () => {
expect(plexParamUpdates(BASE)).toEqual({
pscope: null,
psort: null,
pshow: null,
pf: null,
pscope: "both",
psort: "title:asc",
pshow: "all",
pf: "",
});
});
it("a link to the default view opens it over another remembered one", () => {
const params = applyUpdates(plexParamUpdates(BASE));
const back = plexParamsToState(params, {
scope: "movie",
sort: { key: "year", dir: "desc" },
show: "watched",
filters: RICH_FILTERS,
});
expect(back).toEqual(BASE);
});
it("clears every key when passed null (off-plex page)", () => {
expect(plexParamUpdates(null)).toEqual({
pscope: null,
@@ -66,7 +77,7 @@ describe("plexParamUpdates", () => {
});
});
it("emits only non-default keys", () => {
it("writes the view picked", () => {
const u = plexParamUpdates({
scope: "movie",
sort: { key: "year", dir: "desc" },
@@ -76,7 +87,7 @@ describe("plexParamUpdates", () => {
expect(u.pscope).toBe("movie");
expect(u.psort).toBe("year:desc");
expect(u.pshow).toBe("in_progress");
expect(u.pf).toBeNull();
expect(u.pf).toBe("");
});
});