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:
2026-10-07 23:16:38 +02:00
parent 2aa3ac6e85
commit 392099770a
4 changed files with 36 additions and 8 deletions
+2 -1
View File
@@ -10,6 +10,7 @@ import { DetailCustomizeMenu, Filterable, PrefToggle } from "./plexDetailUi";
import { DetailAside, DetailAsideToggles, DetailKeywords } from "./plexDetailAside";
import {
DETAIL_POSTER,
episodeLine,
tmdbBackdropUrl,
useCrossfadeBackdrop,
useDetailAside,
@@ -315,7 +316,7 @@ export default function PlexInfo({
)}
{detail.kind === "episode" && (
<p className={`text-sm ${overlay ? "text-white/70" : "text-muted"}`}>
S{detail.season_number}·E{detail.episode_number} — {detail.title}
{episodeLine(detail)}
</p>
)}
</div>
+3 -7
View File
@@ -52,6 +52,7 @@ import { Ctrl, PanelHead } from "./plexPlayerControls";
import { PlexPlayerSettings } from "./PlexPlayerSettings";
import { PlexStatsOverlay } from "./PlexStatsOverlay";
import { createFragMeter } from "../lib/plexStats";
import { episodeLine } from "../lib/plexDetail";
import { HlsEngine } from "../lib/hlsEngine";
import { createHlsPort } from "../lib/hlsPort";
import { enabled, log } from "../lib/log";
@@ -586,10 +587,7 @@ export default function PlexPlayer({ itemId, onClose, queue, fromStart = false }
useMediaSession(
videoEl,
detail && {
title:
detail.kind === "episode" && detail.season_number != null
? `S${detail.season_number}·E${detail.episode_number} — ${detail.title}`
: detail.title,
title: detail.kind === "episode" ? episodeLine(detail) : detail.title,
artist:
detail.kind === "episode" ? detail.show_title : detail.year ? String(detail.year) : null,
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}
</div>
{detail?.kind === "episode" && (
<div className="text-xs text-white/70 truncate">
S{detail.season_number}·E{detail.episode_number} — {detail.title}
</div>
<div className="text-xs text-white/70 truncate">{episodeLine(detail)}</div>
)}
</div>
{/* 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",
);
});
});
+11
View File
@@ -210,6 +210,17 @@ export function epLabel(ep?: PlexCard | null): string | undefined {
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
// 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.