commit ddfa7debb0622f066cdcc5c93ea5a6463a325132
parent 7818ca35a03d72fc0d0f81a749c8083510d22dfb
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Sun, 20 Sep 2026 00:48:31 -0400
fix: the matched-titles list came back empty because the limit was a client reference
`MATCHED_PREVIEW_LIMIT` was exported from PlaylistStage.tsx, which is
`"use client"`. A value imported from a client module into a Server Component
is replaced by a client REFERENCE, not the value — so `matched.slice(0, limit)`
became `slice(0, NaN)` and the list rendered empty beside a count that
correctly said 2. Types were fine (erased); the constant is what forced the
move to a plain module.
Caught by the e2e, which is the point of asserting the rendered list rather
than the number next to it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
3 files changed, 36 insertions(+), 25 deletions(-)
diff --git a/editor/app/channels/[slug]/components/stages/PlaylistStage.tsx b/editor/app/channels/[slug]/components/stages/PlaylistStage.tsx
@@ -11,29 +11,7 @@ import {
syncAction,
} from "../../pipelineActions";
import type { MetadataScanRun } from "yt-dlp-transcript-common/controller/metadataScanStore";
-
-// How many matched titles the stage lists. An eyeball check that the regex
-// caught what the operator meant, not an inventory — the full answer is the
-// channel's download list.
-export const MATCHED_PREVIEW_LIMIT = 50;
-
-export type MetadataScanMatch = {
- id: string;
- uploadDate: string;
- title: string;
-};
-
-export type MetadataScanView = {
- listed: number;
- scanned: number;
- errors: number;
- unscanned: number;
- lastRun: MetadataScanRun | null;
- filterConfigured: boolean;
- filteredOut: number;
- matchedTotal: number;
- matched: MetadataScanMatch[];
-};
+import type { MetadataScanView } from "../../lib/metadataScanView";
type Props = {
slug: string;
diff --git a/editor/app/channels/[slug]/lib/metadataScanView.ts b/editor/app/channels/[slug]/lib/metadataScanView.ts
@@ -0,0 +1,33 @@
+// The Playlist stage's metadata-scan view model.
+//
+// DELIBERATELY NOT IN PlaylistStage.tsx. That file is `"use client"`, and a
+// value imported from a client module into a Server Component is replaced by a
+// client REFERENCE — not the value. `MATCHED_PREVIEW_LIMIT` exported from there
+// reached the server as an object, `slice(0, <object>)` became `slice(0, NaN)`,
+// and the matched-titles list rendered empty while the count beside it said 2.
+// Types alone would have been safe (they are erased); the constant is what
+// forced this module to exist.
+import type { MetadataScanRun } from "yt-dlp-transcript-common/controller/metadataScanStore";
+
+// How many matched titles the stage lists. An eyeball check that the regex
+// caught what the operator meant, not an inventory — the full answer is the
+// channel's download list.
+export const MATCHED_PREVIEW_LIMIT = 50;
+
+export type MetadataScanMatch = {
+ id: string;
+ uploadDate: string;
+ title: string;
+};
+
+export type MetadataScanView = {
+ listed: number;
+ scanned: number;
+ errors: number;
+ unscanned: number;
+ lastRun: MetadataScanRun | null;
+ filterConfigured: boolean;
+ filteredOut: number;
+ matchedTotal: number;
+ matched: MetadataScanMatch[];
+};
diff --git a/editor/app/channels/[slug]/page.tsx b/editor/app/channels/[slug]/page.tsx
@@ -68,11 +68,11 @@ import { liveJobRows } from "../../jobs/active/buildActiveJobs";
import { CleanupStage } from "./components/stages/CleanupStage";
import { DiagnosticsStage } from "./components/stages/DiagnosticsStage";
import { DownloadStage } from "./components/stages/DownloadStage";
+import { PlaylistStage } from "./components/stages/PlaylistStage";
import {
- PlaylistStage,
MATCHED_PREVIEW_LIMIT,
type MetadataScanMatch,
-} from "./components/stages/PlaylistStage";
+} from "./lib/metadataScanView";
import { loadMetadataScan } from "yt-dlp-transcript-common/controller/metadataScanStore";
import {
compileDownloadFilter,