fix(plex): an episode Plex has no number for is named by its title alone
The OS media title printed the missing number as "Enull", the player and info headers as a bare "E". One helper for the three lines.
This commit is contained in:
@@ -10,6 +10,7 @@ import { DetailCustomizeMenu, Filterable, PrefToggle } from "./plexDetailUi";
|
|||||||
import { DetailAside, DetailAsideToggles, DetailKeywords } from "./plexDetailAside";
|
import { DetailAside, DetailAsideToggles, DetailKeywords } from "./plexDetailAside";
|
||||||
import {
|
import {
|
||||||
DETAIL_POSTER,
|
DETAIL_POSTER,
|
||||||
|
episodeLine,
|
||||||
tmdbBackdropUrl,
|
tmdbBackdropUrl,
|
||||||
useCrossfadeBackdrop,
|
useCrossfadeBackdrop,
|
||||||
useDetailAside,
|
useDetailAside,
|
||||||
@@ -315,7 +316,7 @@ export default function PlexInfo({
|
|||||||
)}
|
)}
|
||||||
{detail.kind === "episode" && (
|
{detail.kind === "episode" && (
|
||||||
<p className={`text-sm ${overlay ? "text-white/70" : "text-muted"}`}>
|
<p className={`text-sm ${overlay ? "text-white/70" : "text-muted"}`}>
|
||||||
S{detail.season_number}·E{detail.episode_number} — {detail.title}
|
{episodeLine(detail)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import { Ctrl, PanelHead } from "./plexPlayerControls";
|
|||||||
import { PlexPlayerSettings } from "./PlexPlayerSettings";
|
import { PlexPlayerSettings } from "./PlexPlayerSettings";
|
||||||
import { PlexStatsOverlay } from "./PlexStatsOverlay";
|
import { PlexStatsOverlay } from "./PlexStatsOverlay";
|
||||||
import { createFragMeter } from "../lib/plexStats";
|
import { createFragMeter } from "../lib/plexStats";
|
||||||
|
import { episodeLine } from "../lib/plexDetail";
|
||||||
import { HlsEngine } from "../lib/hlsEngine";
|
import { HlsEngine } from "../lib/hlsEngine";
|
||||||
import { createHlsPort } from "../lib/hlsPort";
|
import { createHlsPort } from "../lib/hlsPort";
|
||||||
import { enabled, log } from "../lib/log";
|
import { enabled, log } from "../lib/log";
|
||||||
@@ -586,10 +587,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
|
|||||||
useMediaSession(
|
useMediaSession(
|
||||||
videoEl,
|
videoEl,
|
||||||
detail && {
|
detail && {
|
||||||
title:
|
title: detail.kind === "episode" ? episodeLine(detail) : detail.title,
|
||||||
detail.kind === "episode" && detail.season_number != null
|
|
||||||
? `S${detail.season_number}·E${detail.episode_number} — ${detail.title}`
|
|
||||||
: detail.title,
|
|
||||||
artist:
|
artist:
|
||||||
detail.kind === "episode" ? detail.show_title : detail.year ? String(detail.year) : null,
|
detail.kind === "episode" ? detail.show_title : detail.year ? String(detail.year) : null,
|
||||||
artwork: api.plexImageUrl(id),
|
artwork: api.plexImageUrl(id),
|
||||||
@@ -1258,9 +1256,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
|
|||||||
{detail?.kind === "episode" && detail.show_title ? detail.show_title : detail?.title}
|
{detail?.kind === "episode" && detail.show_title ? detail.show_title : detail?.title}
|
||||||
</div>
|
</div>
|
||||||
{detail?.kind === "episode" && (
|
{detail?.kind === "episode" && (
|
||||||
<div className="text-xs text-white/70 truncate">
|
<div className="text-xs text-white/70 truncate">{episodeLine(detail)}</div>
|
||||||
S{detail.season_number}·E{detail.episode_number} — {detail.title}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{/* Live wall clock — handy on a lean-back / HTPC screen (toggle + style in the Clock tab). */}
|
{/* Live wall clock — handy on a lean-back / HTPC screen (toggle + style in the Clock tab). */}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { episodeLine } from "./plexDetail";
|
||||||
|
|
||||||
|
describe("episodeLine", () => {
|
||||||
|
it("names the episode by its season and number", () => {
|
||||||
|
expect(episodeLine({ season_number: 2, episode_number: 7, title: "Pilot" })).toBe(
|
||||||
|
"S2·E7 — Pilot",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("is the title alone for an episode Plex has no number for", () => {
|
||||||
|
expect(episodeLine({ season_number: 1, episode_number: null, title: "Special" })).toBe(
|
||||||
|
"Special",
|
||||||
|
);
|
||||||
|
expect(episodeLine({ season_number: null, episode_number: 3, title: "Special" })).toBe(
|
||||||
|
"Special",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -210,6 +210,17 @@ export function epLabel(ep?: PlexCard | null): string | undefined {
|
|||||||
return ep.title;
|
return ep.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An episode's line under its show's name: "S1·E4 — Title" — or the title alone when Plex has no
|
||||||
|
* number for it (a special): a template literal printed the missing one as "Enull", JSX as "E". */
|
||||||
|
export function episodeLine(ep: {
|
||||||
|
season_number?: number | null;
|
||||||
|
episode_number?: number | null;
|
||||||
|
title: string;
|
||||||
|
}): string {
|
||||||
|
if (ep.season_number == null || ep.episode_number == null) return ep.title;
|
||||||
|
return `S${ep.season_number}·E${ep.episode_number} — ${ep.title}`;
|
||||||
|
}
|
||||||
|
|
||||||
// Plex names seasons in the library's language ("Season 1", "Specials"), so a Hungarian reader got
|
// Plex names seasons in the library's language ("Season 1", "Specials"), so a Hungarian reader got
|
||||||
// English there. A generic name is rebuilt from the number in the reader's language; a season
|
// English there. A generic name is rebuilt from the number in the reader's language; a season
|
||||||
// with a name of its own ("Book One: Water") keeps it.
|
// with a name of its own ("Book One: Water") keeps it.
|
||||||
|
|||||||
Reference in New Issue
Block a user