commit fc175654d01b10966ba45fa5933e39f5b6c3b742
parent 7f91177c75088089fdf8556b05ca9af26d5a5c89
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Sat, 10 Oct 2026 00:42:46 -0400
channels: release 21 D2 — a clip window of a saved video is cut from its container, not fetched
fetchWindowAction asks the saved-video store after the clip-window cache and
the in-flight jobs, before the network: a container that covers the window is
cut locally (evidenceClip-server's evidenceCutArgs) into data/<id>/clips/ with
the fetched sidecar shape plus `source: "saved-video"`, and answered
`cached: true`. No pointer, or a container that ends before the window, goes
to the network as before; a pointer whose container cannot be read (missing,
an unmounted or unanswering store drive, a store mid-move, unreadable by
ffprobe) is refused with the media guard's (or the store guard's) sentence.
The fetch-windows batch puts covered windows in their own group, platform
`saved-video` on `clips:saved-video` (no platform's hold, cooldown or gap);
the controller cuts them with no request and no pause, and fails an
unreadable one as `unreachable`. The video page marks a cut window. The MCP
plan says a locally held video is cut without a fetch.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
12 files changed, 982 insertions(+), 4 deletions(-)
diff --git a/common/controller/fetchWindows.test.ts b/common/controller/fetchWindows.test.ts
@@ -274,3 +274,79 @@ test("a second run on the same platform waits out the gap the first one set", as
await go(await corpus(), [item("v3", "/ok"), item("v4", "/ok")], second);
assert.deepEqual(second.rec.sleeps, [1000, 1000], "the first fetch waits for the earlier run's gap");
});
+
+// THE SAVED CONTAINER (release 21 D2): a window it holds is cut, not fetched;
+// a pointer it cannot be read for fails the item, never a fetch in its place;
+// a container that ends too early is fetched as before.
+test("saved containers: a covered window is cut with no request and no pause; unreadable fails; not-covering is fetched", async () => {
+ const paths = await corpus();
+ const cuts: { id: string; from: number; to: number; clipId?: string }[] = [];
+ const h = harness({
+ savedWindowSource: async ({ videoDir }) => {
+ const id = path.basename(videoDir);
+ if (id === "held") {
+ return {
+ kind: "covers",
+ pointer: { storedAt: "", dir: "/store", file: "source-media.mp4", bytes: 1 },
+ container: "/store/source-media.mp4",
+ durationSec: 600,
+ probe: { durationSec: 600, width: 160, height: 90, hasVideo: true, hasAudio: true },
+ };
+ }
+ if (id === "unplugged") {
+ return { kind: "unreadable", error: `Channel "c": media is not reachable — its saved video is not there` };
+ }
+ if (id === "short") return { kind: "not-covering", container: "/store/x.mp4", durationSec: 5 };
+ return { kind: "none" };
+ },
+ cutSavedWindow: async ({ videoDir, from, to, provenance }) => {
+ cuts.push({ id: path.basename(videoDir), from, to, clipId: provenance.clipId });
+ return { file: "x.mp4", path: "/x.mp4", from, to, bytes: 1, provenance: { requestedBy: "test", source: "saved-video" } };
+ },
+ });
+ const before = await spawns();
+ const r = await go(
+ paths,
+ [
+ { ...item("held", "/a"), clipId: "r#1" },
+ item("unplugged", "/b"),
+ item("short", "/c"),
+ { ...item("held", "/d", 30, 40), clipId: "r#2" },
+ ],
+ h,
+ );
+ assert.deepEqual(cuts, [
+ { id: "held", from: 10, to: 20, clipId: "r#1" },
+ { id: "held", from: 30, to: 40, clipId: "r#2" },
+ ]);
+ assert.deepEqual(r.cut.map((i) => i.id), ["held", "held"]);
+ assert.equal(r.failed.length, 1);
+ assert.equal(r.failed[0].class, "unreachable");
+ assert.equal(r.failed[0].item.id, "unplugged");
+ assert.match(r.failed[0].message, /media is not reachable/);
+ assert.deepEqual(r.fetched.map((i) => i.id), ["short"]);
+ assert.equal((await spawns()) - before, 1, "only the not-covering window touched the network");
+ assert.deepEqual(h.rec.sleeps, [], "a cut owes no pause, and one fetch owes none either");
+ assert.deepEqual(h.rec.progress.at(-1), { metric: "clips", initial: 0, target: 4, current: 4 });
+});
+
+test("saved containers: a cut that fails is a cut-failed item and the run carries on", async () => {
+ const h = harness({
+ savedWindowSource: async () => ({
+ kind: "covers",
+ pointer: { storedAt: "", dir: "/store", file: "source-media.mp4", bytes: 1 },
+ container: "/store/source-media.mp4",
+ durationSec: 600,
+ probe: { durationSec: 600, width: 160, height: 90, hasVideo: true, hasAudio: true },
+ }),
+ cutSavedWindow: async ({ from }) => {
+ if (from === 10) throw new Error("ffmpeg failed cutting 10.00–20.00");
+ return { file: "x.mp4", path: "/x.mp4", from, to: from + 10, bytes: 1, provenance: null };
+ },
+ });
+ const r = await go(await corpus(), [item("v1", "/a"), item("v2", "/b", 30, 40)], h);
+ assert.equal(r.failed.length, 1);
+ assert.equal(r.failed[0].class, "cut-failed");
+ assert.deepEqual(r.cut.map((i) => i.id), ["v2"]);
+ assert.equal(r.stopped, undefined);
+});
diff --git a/common/controller/fetchWindows.ts b/common/controller/fetchWindows.ts
@@ -8,6 +8,10 @@ import { resolveCookiePolicy } from "../lib/cookiePolicy";
import { assertChannelTextReadable } from "../lib/channelMedia";
import { detectPlatform } from "../lib/platform";
import { findContainingClipWindow } from "../lib/clipWindow-server";
+import {
+ cutSavedVideoWindow,
+ savedWindowSource,
+} from "../lib/savedVideoWindow-server";
import type { JobProgress } from "../jobs/registry";
import { downloadGapMs } from "../jobs/platformBackoff";
import { notePlatformGap, platformGapRemainingMs } from "../jobs/platformGap";
@@ -49,6 +53,10 @@ import { findVideoSourceUrl } from "./undownloadedVideos";
// - A CACHED WINDOW costs nothing: no request, no pause. The cache is asked
// here first (the same containing-window rule fetchWindowManaged applies),
// so a re-run of a half-done list walks straight to what is missing.
+// - A WINDOW HELD BY A SAVED CONTAINER (release 21 D2) is CUT from it, with
+// no request and no pause either (lib/savedVideoWindow-server.ts). A
+// pointer whose container cannot be read fails the item as `unreachable`
+// — never a fetch in its place; one that ends too early is fetched.
// - BETWEEN TWO NETWORK FETCHES the batch downloads' own gap
// (downloadGapMs), with a floor of CLIP_WINDOW_MIN_GAP_SECONDS — jittered
// up to half again, so a platform is never asked on a fixed beat.
@@ -107,8 +115,11 @@ export type FetchWindowsFailureClass =
| DownloadFailureClass
// No channel config for the slug.
| "unknown-channel"
- // The channel's text (and so its clips/) is not readable.
+ // The channel's text (and so its clips/) is not readable, or the video's
+ // saved container is not.
| "unreachable"
+ // ffmpeg could not cut the window out of a covering saved container.
+ | "cut-failed"
// No page URL to fetch from.
| "no-url";
@@ -129,6 +140,8 @@ export type FetchWindowsStop =
export type FetchWindowsResult = {
fetched: FetchWindowsItem[];
cached: FetchWindowsItem[];
+ // Cut from the video's saved container, not fetched (release 21 D2).
+ cut: FetchWindowsItem[];
failed: FetchWindowsFailure[];
// Due a fetch but not attempted because the run stopped first.
notAttempted: FetchWindowsItem[];
@@ -146,6 +159,9 @@ export type FetchWindowsProvenance = {
// is.
export type FetchWindowsDeps = {
fetchWindow: (opts: FetchWindowOpts) => Promise<FetchWindowResult>;
+ // The saved-container tier (lib/savedVideoWindow-server.ts).
+ savedWindowSource: typeof savedWindowSource;
+ cutSavedWindow: typeof cutSavedVideoWindow;
sleep: (ms: number, signal?: AbortSignal) => Promise<void>;
getSettings: () => SiteSettings;
readChannelConfig: (paths: Paths, slug: string) => Promise<ChannelConfig | null>;
@@ -188,6 +204,8 @@ function abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {
const DEFAULT_DEPS: FetchWindowsDeps = {
fetchWindow: fetchWindowManaged,
+ savedWindowSource,
+ cutSavedWindow: cutSavedVideoWindow,
sleep: abortableSleep,
getSettings,
readChannelConfig,
@@ -262,6 +280,7 @@ export async function fetchWindows({
const result: FetchWindowsResult = {
fetched: [],
cached: [],
+ cut: [],
failed: [],
notAttempted: [],
};
@@ -351,6 +370,49 @@ export async function fetchWindows({
continue;
}
+ // THEN THE SAVED CONTAINER: cut, no request, no pause, not a network
+ // attempt.
+ const saved = await deps.savedWindowSource({
+ paths,
+ slug: item.slug,
+ videoDir,
+ from: item.from,
+ to: item.to,
+ });
+ if (saved.kind === "unreadable") {
+ fail(item, "unreachable", saved.error);
+ done += 1;
+ progress();
+ continue;
+ }
+ if (saved.kind === "covers") {
+ try {
+ const cut = await deps.cutSavedWindow({
+ paths,
+ videoDir,
+ source: saved,
+ from: item.from,
+ to: item.to,
+ provenance: {
+ requestedBy: provenance.requestedBy,
+ manifest: provenance.manifest,
+ clipId: item.clipId,
+ reason: item.reason,
+ pad: item.pad,
+ requestedAt,
+ },
+ signal: fetchSignal,
+ });
+ result.cut.push(item);
+ log(` ✂ ${label}: cut from the saved video into clips/${cut.file}`);
+ } catch (e) {
+ fail(item, "cut-failed", (e as Error).message);
+ }
+ done += 1;
+ progress();
+ continue;
+ }
+
const url =
item.webpageUrl?.trim() ||
(await deps.findVideoSourceUrl(paths, item.slug, item.id, config));
@@ -490,7 +552,9 @@ export async function fetchWindows({
}
log(
- `Fetch windows: ${result.fetched.length} fetched, ${result.cached.length} cached, ` +
+ `Fetch windows: ${result.fetched.length} fetched, ` +
+ (result.cut.length ? `${result.cut.length} cut from saved videos, ` : "") +
+ `${result.cached.length} cached, ` +
`${result.failed.length} failed` +
(result.notAttempted.length
? `, ${result.notAttempted.length} not attempted (stopped: ${result.stopped})`
diff --git a/common/lib/clipWindow.ts b/common/lib/clipWindow.ts
@@ -152,8 +152,15 @@ export type ClipProvenance = {
// The argv the fetch actually ran, minus the binary. For the case where a
// window looks wrong and the question is which format selector produced it.
ytdlp?: { args: string[] };
+ // WHERE THE BYTES CAME FROM, when it was not the network: "saved-video" for
+ // a window cut from the video's saved container (release 21 D2,
+ // lib/savedVideoWindow-server.ts). Absent on every fetched window.
+ source?: ClipWindowSource;
};
+export const CLIP_WINDOW_SOURCES = ["saved-video"] as const;
+export type ClipWindowSource = (typeof CLIP_WINDOW_SOURCES)[number];
+
const str = (v: unknown): string | undefined =>
typeof v === "string" && v !== "" ? v : undefined;
const num = (v: unknown): number | undefined =>
@@ -188,6 +195,9 @@ export function parseClipProvenance(raw: unknown): ClipProvenance | null {
);
out.ytdlp = { args };
}
+ if ((CLIP_WINDOW_SOURCES as readonly unknown[]).includes(r.source)) {
+ out.source = r.source as ClipWindowSource;
+ }
return out;
}
diff --git a/common/lib/queueKeys.ts b/common/lib/queueKeys.ts
@@ -110,3 +110,11 @@ export function resolveQueueKey(
): string {
return override === undefined ? defaultKey : override.trim();
}
+
+// WINDOWS CUT FROM SAVED CONTAINERS (release 21 D2) run on a queue of their own:
+// no platform is asked, so none of a platform's queues — or its hold, cooldown
+// and gap — applies, and a batch of local cuts never waits behind a network
+// window. The pseudo-platform a batch's group of them carries is
+// SAVED_VIDEO_CLIP_PLATFORM.
+export const SAVED_VIDEO_CLIP_QUEUE = "clips:saved-video";
+export const SAVED_VIDEO_CLIP_PLATFORM = "saved-video";
diff --git a/common/lib/savedVideoWindow-server.test.ts b/common/lib/savedVideoWindow-server.test.ts
@@ -0,0 +1,206 @@
+// A clip window cut from a saved container (release 21 D2): which pointer
+// answers which way, and the cut itself.
+//
+// Real ffmpeg over tiny lavfi containers (160×90, a few seconds), so a run
+// costs a second or two.
+//
+// Run with: pnpm --filter yt-dlp-transcript-common exec tsx --test lib/savedVideoWindow-server.test.ts
+
+import { after, before, test } from "node:test";
+import assert from "node:assert/strict";
+import { execFileSync } from "node:child_process";
+import { copyFile, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
+import { tmpdir } from "node:os";
+import path from "node:path";
+import { cutSavedVideoWindow, savedWindowSource } from "./savedVideoWindow-server";
+import { findContainingClipWindow } from "./clipWindow-server";
+import { probeMedia } from "./evidenceClip-server";
+import { SAVED_VIDEOS_MARKER_FILENAME } from "./savedVideoStore";
+
+const SLUG = "demo-channel";
+const ID = "abc123";
+
+let ROOT = "";
+// 8 s of 160×90 picture with sound, and 8 s of sound alone.
+let PICTURE = "";
+let SOUND = "";
+
+function ff(args: string[]): void {
+ execFileSync("ffmpeg", ["-nostdin", "-v", "error", "-y", ...args]);
+}
+
+before(async () => {
+ ROOT = await mkdtemp(path.join(tmpdir(), "saved-window-"));
+ const fx = path.join(ROOT, "fixtures");
+ await mkdir(fx, { recursive: true });
+ PICTURE = path.join(fx, "picture.mp4");
+ SOUND = path.join(fx, "sound.m4a");
+ ff([
+ "-f", "lavfi", "-i", "testsrc=size=160x90:rate=10:duration=8",
+ "-f", "lavfi", "-i", "sine=frequency=440:duration=8",
+ "-c:v", "libx264", "-preset", "ultrafast", "-pix_fmt", "yuv420p", "-c:a", "aac", "-shortest", PICTURE,
+ ]);
+ ff(["-f", "lavfi", "-i", "sine=frequency=220:duration=8", "-c:a", "aac", SOUND]);
+});
+
+after(() => rm(ROOT, { recursive: true, force: true }));
+
+let n = 0;
+// A fresh corpus per test: `<root>/<n>/transcripts/channels/<slug>/data/<id>/`
+// and its saved-video store `<root>/<n>/transcripts/saved-videos/<slug>/<id>/`,
+// holding `container` (when given) under the pointer's name.
+async function corpus(container?: string, opts: { pointer?: boolean } = {}) {
+ const root = path.join(ROOT, String(++n));
+ const transcriptsDir = path.join(root, "transcripts");
+ const savedVideosDir = path.join(transcriptsDir, "saved-videos");
+ const videoDir = path.join(transcriptsDir, "channels", SLUG, "data", ID);
+ const storeDir = path.join(savedVideosDir, SLUG, ID);
+ await mkdir(videoDir, { recursive: true });
+ await mkdir(storeDir, { recursive: true });
+ const file = `source-media${container ? path.extname(container) : ".mp4"}`;
+ if (container) await copyFile(container, path.join(storeDir, file));
+ if (opts.pointer !== false) {
+ await writeFile(
+ path.join(videoDir, "saved-video.json"),
+ JSON.stringify({
+ storedAt: "2026-10-10T00:00:00.000Z",
+ dir: storeDir,
+ file,
+ bytes: 1,
+ keepReason: "pin",
+ origin: {
+ requestedBy: "attach-media",
+ kind: "local-archive",
+ archive: "/archive/example.zip",
+ entry: "Example (abc123)/example.mp4",
+ },
+ }),
+ );
+ }
+ const paths = { transcriptsDir, savedVideosDir, ffmpegBin: "ffmpeg", ffprobeBin: "ffprobe" };
+ return { paths, videoDir, storeDir, transcriptsDir };
+}
+
+test("no pointer: none — the caller goes to the network", async () => {
+ const c = await corpus(undefined, { pointer: false });
+ const r = await savedWindowSource({ paths: c.paths, slug: SLUG, videoDir: c.videoDir, from: 1, to: 3 });
+ assert.deepEqual(r, { kind: "none" });
+});
+
+test("a container that ends before the window: not-covering", async () => {
+ const c = await corpus(PICTURE);
+ const r = await savedWindowSource({ paths: c.paths, slug: SLUG, videoDir: c.videoDir, from: 5, to: 12 });
+ assert.equal(r.kind, "not-covering");
+ assert.ok(r.kind === "not-covering" && Math.abs(r.durationSec - 8) < 0.2);
+});
+
+test("a pointer whose container is missing: unreadable, in the media guard's words", async () => {
+ const c = await corpus(undefined);
+ const r = await savedWindowSource({ paths: c.paths, slug: SLUG, videoDir: c.videoDir, from: 1, to: 3 });
+ assert.equal(r.kind, "unreadable");
+ assert.match(
+ (r as { error: string }).error,
+ /^Channel "demo-channel": media is not reachable — its saved video .*source-media\.mp4 is not there \(drive not mounted\?\)$/,
+ );
+});
+
+test("a pointer whose store is unmounted (its directory gone): unreadable", async () => {
+ const c = await corpus(PICTURE);
+ await rm(c.storeDir, { recursive: true, force: true });
+ const r = await savedWindowSource({ paths: c.paths, slug: SLUG, videoDir: c.videoDir, from: 1, to: 3 });
+ assert.equal(r.kind, "unreadable");
+ assert.match((r as { error: string }).error, /media is not reachable/);
+});
+
+test("a missing container while the store is being moved: the store guard's sentence", async () => {
+ const c = await corpus(undefined);
+ await writeFile(
+ path.join(c.transcriptsDir, SAVED_VIDEOS_MARKER_FILENAME),
+ JSON.stringify({ target: "/mnt/elsewhere/saved-videos", direction: "out", startedAt: "", phase: "swap" }),
+ );
+ const r = await savedWindowSource({ paths: c.paths, slug: SLUG, videoDir: c.videoDir, from: 1, to: 3 });
+ assert.equal(r.kind, "unreadable");
+ assert.match((r as { error: string }).error, /^The saved-video store is being moved \(out to \/mnt\/elsewhere\/saved-videos, phase "swap"\)/);
+});
+
+test("a container ffprobe cannot read: unreadable, never a guess", async () => {
+ const c = await corpus(undefined);
+ await writeFile(path.join(c.storeDir, "source-media.mp4"), "not a container");
+ const r = await savedWindowSource({ paths: c.paths, slug: SLUG, videoDir: c.videoDir, from: 1, to: 3 });
+ assert.equal(r.kind, "unreadable");
+ assert.match((r as { error: string }).error, /could not be read by ffprobe/);
+});
+
+test("a covering container is cut into clips/ with a saved-video sidecar, and the cache then answers it", async () => {
+ const c = await corpus(PICTURE);
+ const src = await savedWindowSource({ paths: c.paths, slug: SLUG, videoDir: c.videoDir, from: 2, to: 5 });
+ assert.equal(src.kind, "covers");
+ if (src.kind !== "covers") return;
+ const logs: string[] = [];
+ const w = await cutSavedVideoWindow({
+ paths: c.paths,
+ videoDir: c.videoDir,
+ source: src,
+ from: 2,
+ to: 5,
+ provenance: { requestedBy: "test", manifest: "m", clipId: "c1", pad: 1, requestedAt: "2026-10-10T01:00:00.000Z" },
+ onLog: (l) => logs.push(l),
+ });
+ assert.equal(w.file, "2.00-5.00.mp4");
+ assert.equal(path.dirname(w.path), path.join(c.videoDir, "clips"));
+ // Only the window and its sidecar: no temp file left behind.
+ assert.deepEqual((await readdir(path.join(c.videoDir, "clips"))).sort(), ["2.00-5.00.json", "2.00-5.00.mp4"]);
+ const probe = await probeMedia(w.path);
+ assert.ok(probe?.hasVideo && probe.hasAudio);
+ assert.ok(Math.abs((probe?.durationSec ?? 0) - 3) < 0.25, `duration ${probe?.durationSec}`);
+ const sidecar = JSON.parse(await readFile(path.join(c.videoDir, "clips", "2.00-5.00.json"), "utf8"));
+ assert.equal(sidecar.source, "saved-video");
+ assert.equal(sidecar.requestedBy, "test");
+ assert.equal(sidecar.manifest, "m");
+ assert.equal(sidecar.clipId, "c1");
+ assert.equal(sidecar.pad, 1);
+ assert.equal(sidecar.bytes, w.bytes);
+ assert.equal(sidecar.ytdlp, undefined, "nothing was fetched");
+ assert.match(logs.join(""), /Cut 2\.00–5\.00 from the saved video source-media\.mp4/);
+ // The fetched-window cache reads it back like any window.
+ const hit = await findContainingClipWindow(c.videoDir, 2.5, 4.5);
+ assert.equal(hit?.file, "2.00-5.00.mp4");
+ assert.equal(hit?.provenance?.source, "saved-video");
+});
+
+test("a container with no picture is cut as sound", async () => {
+ const c = await corpus(SOUND);
+ const src = await savedWindowSource({ paths: c.paths, slug: SLUG, videoDir: c.videoDir, from: 1, to: 4 });
+ assert.equal(src.kind, "covers");
+ if (src.kind !== "covers") return;
+ const w = await cutSavedVideoWindow({
+ paths: c.paths,
+ videoDir: c.videoDir,
+ source: src,
+ from: 1,
+ to: 4,
+ provenance: { requestedBy: "test" },
+ });
+ const probe = await probeMedia(w.path);
+ assert.equal(probe?.hasVideo, false);
+ assert.equal(probe?.hasAudio, true);
+});
+
+test("an ffmpeg that fails leaves no window behind", async () => {
+ const c = await corpus(PICTURE);
+ const src = await savedWindowSource({ paths: c.paths, slug: SLUG, videoDir: c.videoDir, from: 1, to: 2 });
+ assert.equal(src.kind, "covers");
+ if (src.kind !== "covers") return;
+ await assert.rejects(
+ cutSavedVideoWindow({
+ paths: { ...c.paths, ffmpegBin: "false" },
+ videoDir: c.videoDir,
+ source: src,
+ from: 1,
+ to: 2,
+ provenance: { requestedBy: "test" },
+ }),
+ /ffmpeg failed cutting 1\.00–2\.00 from the saved video source-media\.mp4/,
+ );
+ assert.deepEqual(await readdir(path.join(c.videoDir, "clips")), []);
+});
diff --git a/common/lib/savedVideoWindow-server.ts b/common/lib/savedVideoWindow-server.ts
@@ -0,0 +1,208 @@
+// A CLIP WINDOW CUT FROM A SAVED CONTAINER, not fetched (release 21 D2).
+//
+// A video whose whole source is in the saved-video store (a persist, a
+// `full: true` fetch, or a container attached from a local archive — release 21
+// D1's `origin.kind: "local-archive"`) holds every second a window could ask
+// for. Fetching those seconds again spends the source's patience for bytes
+// already on a disk here — and for a deleted channel there is no source to ask:
+// the fetch fails every time. So the window paths (the single
+// `fetchWindowAction` and the `fetch-windows` batch) ask here after the
+// clip-window cache and BEFORE the network.
+//
+// THE THREE ANSWERS, and what each caller does with them (ruled 2026-10-10):
+// none no pointer: the network path, exactly as before.
+// unreadable a pointer whose container cannot be read — the store's drive
+// is not mounted or not answering, the file is missing, ffprobe
+// cannot open it. REFUSED with the sentence below, never a
+// silent fall-through to the network: the operator who can plug
+// the drive in is the one who needs to hear it.
+// not-covering a pointer whose container ends before the window does: the
+// network path.
+// covers cut it here.
+//
+// THE CUT IS evidenceClip-server's (`evidenceCutArgs`): seeked on the input
+// and re-encoded, so the window's first frame is the asked-for second; H.264 +
+// AAC in an mp4, fitted inside 1280×720 — the container a fetched window is
+// pinned to (lib/clipWindow.ts), at most the default clip height. A container
+// with no picture is cut as sound (still an `.mp4` name, the window's one
+// extension). The window lands in `data/<id>/clips/<from>-<to>.mp4` with a
+// provenance sidecar of the fetched shape plus `source: "saved-video"`, so
+// every reader of the cache (the video page, the build, umtool) sees it as a
+// window like any other.
+//
+// SERVER-ONLY (node:fs, ffmpeg).
+
+import { mkdir, rename, rm, stat } from "node:fs/promises";
+import path from "node:path";
+import { execa } from "execa";
+import {
+ WIN_EPS,
+ clipWindowFile,
+ type ClipProvenance,
+} from "./clipWindow";
+import {
+ clipWindowPath,
+ writeClipProvenance,
+ type ClipWindow,
+} from "./clipWindow-server";
+import { evidenceCutArgs, probeMedia, type MediaProbe } from "./evidenceClip-server";
+import { tmpPathFor } from "./jsonFile-server";
+import { savedVideoPath, type SavedVideoPointer } from "./savedVideo";
+import { loadSavedVideo } from "./savedVideo-server";
+import { readSavedVideosMarker, SavedVideosStoreInTransitionError } from "./savedVideoStore";
+import { isDriveNotAnswering, onDrive } from "./storageHealth";
+import type { Paths } from "./paths";
+
+// A window cut from a container is seconds of re-encoding; a whole container
+// on a platter seeks once. Generous, so only a wedged ffmpeg reaches it —
+// evidenceClip-server's limit for the same work.
+const CUT_TIMEOUT_MS = 10 * 60_000;
+
+export type SavedWindowSource =
+ | { kind: "none" }
+ | { kind: "unreadable"; error: string }
+ | { kind: "not-covering"; container: string; durationSec: number }
+ | {
+ kind: "covers";
+ pointer: SavedVideoPointer;
+ container: string;
+ durationSec: number;
+ probe: MediaProbe;
+ };
+
+// The media guard's sentence (lib/channelMedia.ts, ChannelMediaUnreachableError)
+// with the saved container as its detail, so a refusal here reads like every
+// other unreachable-media refusal the operator has seen.
+function unreachable(slug: string, detail: string): SavedWindowSource {
+ return { kind: "unreadable", error: `Channel "${slug}": media is not reachable — ${detail}` };
+}
+
+// Does this video's saved container hold [from, to]? Reads the pointer, stats
+// the container through the drive watchdog (an unanswering drive is refused in
+// seconds, not waited on), and probes it once for its duration and streams.
+export async function savedWindowSource(opts: {
+ paths: Pick<Paths, "transcriptsDir" | "savedVideosDir" | "ffprobeBin">;
+ slug: string;
+ videoDir: string;
+ from: number;
+ to: number;
+}): Promise<SavedWindowSource> {
+ const pointer = await loadSavedVideo(opts.videoDir);
+ if (!pointer) return { kind: "none" };
+ const container = savedVideoPath(pointer);
+ let isFile = false;
+ try {
+ isFile = await onDrive(pointer.dir, () =>
+ stat(container).then(
+ (s) => s.isFile(),
+ () => false,
+ ),
+ );
+ } catch (err) {
+ if (isDriveNotAnswering(err)) {
+ return unreachable(opts.slug, `its saved video ${container}: ${(err as Error).message}`);
+ }
+ throw err;
+ }
+ if (!isFile) {
+ // The store mid-move is the one case with a sentence of its own: the
+ // store guard's (assertSavedVideosStoreWritable), which names the move.
+ const marker = await readSavedVideosMarker(opts.paths);
+ if (marker) {
+ return { kind: "unreadable", error: new SavedVideosStoreInTransitionError(marker).message };
+ }
+ return unreachable(
+ opts.slug,
+ `its saved video ${container} is not there (drive not mounted?)`,
+ );
+ }
+ const probe = await probeMedia(container, opts.paths.ffprobeBin);
+ if (!probe || probe.durationSec === null || (!probe.hasVideo && !probe.hasAudio)) {
+ return unreachable(opts.slug, `its saved video ${container} could not be read by ffprobe`);
+ }
+ const durationSec = probe.durationSec;
+ if (opts.from < 0 || opts.to > durationSec + WIN_EPS) {
+ return { kind: "not-covering", container, durationSec };
+ }
+ return { kind: "covers", pointer, container, durationSec, probe };
+}
+
+export type SavedWindowProvenance = {
+ requestedBy: string;
+ manifest?: string;
+ clipId?: string;
+ reason?: string;
+ pad?: number;
+ requestedAt?: string;
+};
+
+export class SavedWindowCutError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "SavedWindowCutError";
+ }
+}
+
+// Cut [from, to] out of a covering container into the video's clips/, with its
+// sidecar. Written to a temp name first (which no window parser accepts) and
+// renamed, so a reader never sees half a window.
+export async function cutSavedVideoWindow(opts: {
+ paths: Pick<Paths, "ffmpegBin" | "ffprobeBin">;
+ videoDir: string;
+ source: Extract<SavedWindowSource, { kind: "covers" }>;
+ from: number;
+ to: number;
+ provenance: SavedWindowProvenance;
+ onLog?: (line: string) => void;
+ signal?: AbortSignal;
+}): Promise<ClipWindow> {
+ const { from, to, source } = opts;
+ const dest = clipWindowPath(opts.videoDir, from, to);
+ await mkdir(path.dirname(dest), { recursive: true });
+ const tmp = tmpPathFor(dest);
+ const kind = source.probe.hasVideo ? "video" : "audio";
+ try {
+ const r = await execa(opts.paths.ffmpegBin, evidenceCutArgs(source.container, from, to, kind, tmp), {
+ reject: false,
+ timeout: CUT_TIMEOUT_MS,
+ ...(opts.signal ? { cancelSignal: opts.signal } : {}),
+ });
+ if (r.exitCode !== 0) {
+ const err = String(r.stderr ?? "").trim().split("\n").slice(-3).join(" | ");
+ throw new SavedWindowCutError(
+ `ffmpeg failed cutting ${from.toFixed(2)}–${to.toFixed(2)} from the saved video ` +
+ `${source.pointer.file}${err ? `: ${err}` : ` (exit ${r.exitCode ?? "?"})`}`,
+ );
+ }
+ const bytes = (await stat(tmp)).size;
+ await rename(tmp, dest);
+ const now = new Date().toISOString();
+ const provenance: ClipProvenance = {
+ requestedBy: opts.provenance.requestedBy,
+ ...(opts.provenance.manifest ? { manifest: opts.provenance.manifest } : {}),
+ ...(opts.provenance.clipId ? { clipId: opts.provenance.clipId } : {}),
+ ...(opts.provenance.reason ? { reason: opts.provenance.reason } : {}),
+ requestedAt: opts.provenance.requestedAt ?? now,
+ ...(typeof opts.provenance.pad === "number" ? { pad: opts.provenance.pad } : {}),
+ bytes,
+ // When the window landed — for a cut, when it was cut.
+ fetchedAt: now,
+ source: "saved-video",
+ };
+ await writeClipProvenance(opts.videoDir, from, to, provenance);
+ opts.onLog?.(
+ `Cut ${from.toFixed(2)}–${to.toFixed(2)} from the saved video ${source.pointer.file} into ` +
+ `clips/${clipWindowFile(from, to)} (${bytes} bytes); nothing fetched.\n`,
+ );
+ return {
+ file: clipWindowFile(from, to),
+ path: dest,
+ from,
+ to,
+ bytes,
+ provenance,
+ };
+ } finally {
+ await rm(tmp, { force: true }).catch(() => {});
+ }
+}
diff --git a/editor/app/api/media/fetch-window/route.saved.test.ts b/editor/app/api/media/fetch-window/route.saved.test.ts
@@ -0,0 +1,151 @@
+import test from "node:test";
+import assert from "node:assert/strict";
+import { execFileSync } from "node:child_process";
+import { mkdir, mkdtemp, readdir, readFile, rm, writeFile } from "node:fs/promises";
+import os from "node:os";
+import path from "node:path";
+
+// Run with:
+// pnpm -C editor exec tsx --test "app/api/media/fetch-window/route.saved.test.ts"
+//
+// A window of a video whose source is in the saved-video store (release 21
+// D2): cut on the spot and answered `cached: true`, with no job and no
+// network; a container that does not reach the window goes to the network
+// path exactly as before; a pointer whose container is missing is refused.
+//
+// THE NETWORK PATH IS SEEN BY ITS DOOR: YouTube is put in a rate-limit
+// cooldown before the first request, so a request that reaches the network
+// path answers 409 with the cooldown's sentence — before any job is queued,
+// and never a real fetch. Real ffmpeg over an 8 s 160×90 lavfi container.
+
+const ROOT = await mkdtemp(path.join(os.tmpdir(), "fetch-window-saved-"));
+const SLUG = "demo-channel";
+// Set before the route (and getPaths, which caches) is first imported.
+process.env.WORKER_TOKEN = "test-token";
+process.env.TRANSCRIPTS_DIR = ROOT;
+process.env.SETTINGS_FILE = path.join(ROOT, "settings.json");
+delete process.env.FFPROBE_BIN;
+delete process.env.FFMPEG_BIN;
+
+await mkdir(path.join(ROOT, "channels", SLUG), { recursive: true });
+await writeFile(
+ path.join(ROOT, "channels", SLUG, "config.json"),
+ JSON.stringify({ name: "Demo", handling: "youtube", url: "https://www.youtube.com/@demo" }),
+);
+
+// `held1` has its container in the store; `gone1` has a pointer to a file that
+// is not there (the store's drive unplugged).
+async function pointTo(id: string, withFile: boolean): Promise<string> {
+ const videoDir = path.join(ROOT, "channels", SLUG, "data", id);
+ const store = path.join(ROOT, "saved-videos", SLUG, id);
+ await mkdir(videoDir, { recursive: true });
+ await mkdir(store, { recursive: true });
+ if (withFile) {
+ execFileSync("ffmpeg", [
+ "-nostdin", "-v", "error", "-y",
+ "-f", "lavfi", "-i", "testsrc=size=160x90:rate=10:duration=8",
+ "-f", "lavfi", "-i", "sine=frequency=440:duration=8",
+ "-c:v", "libx264", "-preset", "ultrafast", "-pix_fmt", "yuv420p", "-c:a", "aac", "-shortest",
+ path.join(store, "source-media.mp4"),
+ ]);
+ }
+ await writeFile(
+ path.join(videoDir, "saved-video.json"),
+ JSON.stringify({
+ storedAt: "2026-10-10T00:00:00.000Z",
+ dir: store,
+ file: "source-media.mp4",
+ bytes: 1,
+ keepReason: "pin",
+ origin: { requestedBy: "attach-media", kind: "local-archive", archive: "/archive/example.zip", entry: "e.mp4" },
+ }),
+ );
+ return videoDir;
+}
+const HELD = await pointTo("held1", true);
+const GONE = await pointTo("gone1", false);
+
+const { POST } = await import("./route");
+const { getRegistry } = await import("yt-dlp-transcript-common/jobs/registry");
+const { recordDownloadBackoff } = await import("yt-dlp-transcript-common/jobs/downloadBackoff");
+const { getPaths } = await import("yt-dlp-transcript-common/lib/paths");
+await recordDownloadBackoff("youtube", getPaths());
+const NETWORK_DOOR = /youtube is in a rate-limit cooldown/;
+test.after(() => rm(ROOT, { recursive: true, force: true }));
+
+function post(body: Record<string, unknown>): Promise<Response> {
+ return POST(
+ new Request("http://localhost/api/media/fetch-window", {
+ method: "POST",
+ headers: { authorization: "Bearer test-token", "content-type": "application/json" },
+ body: JSON.stringify(body),
+ }),
+ );
+}
+
+const base = { channelSlug: SLUG, requestedBy: "test", manifest: "m", clipId: "c1", pad: 1 };
+const jobsNow = () => getRegistry().list().length;
+
+test("a window the saved container holds is cut and answered cached, with no job", async () => {
+ const jobs = jobsNow();
+ const res = await post({ ...base, videoId: "held1", from: 2, to: 5 });
+ assert.equal(res.status, 200);
+ const body = (await res.json()) as {
+ cached: boolean;
+ file: string;
+ from: number;
+ to: number;
+ bytes: number;
+ height?: number;
+ provenance: Record<string, unknown>;
+ };
+ assert.equal(body.cached, true);
+ assert.equal(body.from, 2);
+ assert.equal(body.to, 5);
+ assert.equal(body.file, path.join(HELD, "clips", "2.00-5.00.mp4"));
+ assert.ok(body.bytes > 0);
+ assert.equal(body.height, 90);
+ assert.equal(body.provenance.source, "saved-video");
+ assert.equal(body.provenance.requestedBy, "test");
+ assert.equal(body.provenance.clipId, "c1");
+ assert.equal(jobsNow(), jobs, "no job was queued");
+ const sidecar = JSON.parse(await readFile(path.join(HELD, "clips", "2.00-5.00.json"), "utf8"));
+ assert.equal(sidecar.source, "saved-video");
+
+ // Asked again (or for seconds inside it), the clip cache answers it.
+ const again = await post({ ...base, videoId: "held1", from: 2.5, to: 4.5 });
+ assert.equal(again.status, 200);
+ const b2 = (await again.json()) as { file: string; provenance: Record<string, unknown> };
+ assert.equal(b2.file, body.file);
+ assert.equal(b2.provenance.source, "saved-video");
+ assert.deepEqual((await readdir(path.join(HELD, "clips"))).sort(), ["2.00-5.00.json", "2.00-5.00.mp4"]);
+});
+
+test("a window past the container's end goes to the network path, as before", async () => {
+ const res = await post({ ...base, videoId: "held1", from: 6, to: 12 });
+ assert.equal(res.status, 409);
+ const body = (await res.json()) as { error: string };
+ assert.match(body.error, NETWORK_DOOR);
+ assert.ok(
+ !(await readdir(path.join(HELD, "clips"))).some((f) => f.startsWith("6.00-")),
+ "nothing was cut",
+ );
+});
+
+test("a pointer whose container is missing is refused with the media guard's sentence, never fetched", async () => {
+ const res = await post({ ...base, videoId: "gone1", from: 2, to: 5 });
+ assert.equal(res.status, 503);
+ const body = (await res.json()) as { error: string };
+ assert.match(
+ body.error,
+ /^Channel "demo-channel": media is not reachable — its saved video .*source-media\.mp4 is not there \(drive not mounted\?\)$/,
+ );
+ assert.deepEqual(await readdir(GONE), ["saved-video.json"]);
+});
+
+test("a video with no pointer goes to the network path, as before", async () => {
+ await mkdir(path.join(ROOT, "channels", SLUG, "data", "plain1"), { recursive: true });
+ const res = await post({ ...base, videoId: "plain1", from: 2, to: 5 });
+ assert.equal(res.status, 409);
+ assert.match(((await res.json()) as { error: string }).error, NETWORK_DOOR);
+});
diff --git a/editor/app/channels/[slug]/videos/[id]/components/cards/FetchedWindows.tsx b/editor/app/channels/[slug]/videos/[id]/components/cards/FetchedWindows.tsx
@@ -46,6 +46,7 @@ export function FetchedWindows({ windows }: { windows: FetchedWindow[] }) {
requested by {p.requestedBy}
{what ? ` for ${what}` : ""}
{p.reason ? ` · \u201c${p.reason}\u201d` : ""}
+ {p.source === "saved-video" ? " · cut from the saved video" : ""}
{p.fetchedAt
? ` · ${new Date(p.fetchedAt).toLocaleString()}`
: ""}
diff --git a/editor/app/channels/[slug]/videos/[id]/videoActions.ts b/editor/app/channels/[slug]/videos/[id]/videoActions.ts
@@ -43,6 +43,7 @@ import {
} from "yt-dlp-transcript-common/controller/keepVideosMatching";
import {
ChannelMediaUnreachableError,
+ assertChannelTextReadable,
channelTextStall,
inspectChannelMedia,
} from "yt-dlp-transcript-common/lib/channelMedia";
@@ -78,6 +79,10 @@ import {
findContainingClipWindow,
} from "yt-dlp-transcript-common/lib/clipWindow-server";
import {
+ cutSavedVideoWindow,
+ savedWindowSource,
+} from "yt-dlp-transcript-common/lib/savedVideoWindow-server";
+import {
fetchWindowManaged,
type FetchWindowProvenance,
} from "yt-dlp-transcript-common/ytdlp/fetchWindowManaged";
@@ -1133,6 +1138,57 @@ export async function fetchWindowAction(req: {
}
}
+ // ...THEN THE SAVED CONTAINER (release 21 D2), before any network: a video
+ // whose whole source is in the saved-video store is CUT here, not fetched,
+ // and the answer is a cached window like the one above
+ // (lib/savedVideoWindow-server.ts). No
+ // pointer, or a container that ends before the window, goes on to the
+ // network as before; a pointer whose container cannot be read is REFUSED —
+ // falling through would spend the source's patience (or, for a deleted
+ // channel, fail) on seconds that are on a drive somebody can plug in.
+ const saved = await savedWindowSource({ paths, slug, videoDir, from, to });
+ if (saved.kind === "unreadable") {
+ return { ok: false, status: 503, error: saved.error };
+ }
+ if (saved.kind === "covers") {
+ // The window lands in data/<id>/clips/, the channel's TEXT tier: the guard a
+ // fetch-window job's `needsText` would have asked, asked here because no
+ // job runs.
+ try {
+ await assertChannelTextReadable(paths, slug);
+ } catch (e) {
+ return { ok: false, status: 503, error: (e as Error).message };
+ }
+ let cut;
+ try {
+ cut = await cutSavedVideoWindow({
+ paths,
+ videoDir,
+ source: saved,
+ from,
+ to,
+ provenance: req.provenance,
+ });
+ } catch (e) {
+ return { ok: false, status: 500, error: (e as Error).message };
+ }
+ const height = await probeVideoHeight({
+ ffprobeBin: paths.ffprobeBin,
+ file: cut.path,
+ });
+ safeRevalidate([`/channels/${slug}/videos/${videoId}`]);
+ return {
+ ok: true,
+ cached: true,
+ file: cut.path,
+ from: cut.from,
+ to: cut.to,
+ bytes: cut.bytes,
+ provenance: cut.provenance,
+ ...(height !== null ? { height } : {}),
+ };
+ }
+
const url =
req.webpageUrl?.trim() ||
(await findVideoSourceUrl(paths, slug, videoId, r.config));
diff --git a/editor/app/channels/[slug]/videos/fetchWindowsAction.test.ts b/editor/app/channels/[slug]/videos/fetchWindowsAction.test.ts
@@ -0,0 +1,155 @@
+import test from "node:test";
+import assert from "node:assert/strict";
+import { execFileSync } from "node:child_process";
+import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
+import os from "node:os";
+import path from "node:path";
+
+// Run with:
+// pnpm -C editor exec tsx --test "app/channels/*/videos/fetchWindowsAction.test.ts"
+// (a wildcard: node's --test reads `[slug]` as a glob class)
+//
+// The batch fetch over videos whose source is in the saved-video store
+// (release 21 D2): a window a container holds joins the `saved-video` group on
+// `clips:saved-video` — no platform's queue, hold or cooldown — and its job
+// cuts it; a pointer whose container is missing is unresolved with the media
+// guard's sentence; a window past the container's end joins its platform's
+// group as before. YouTube is in a cooldown throughout, so its group is
+// refused at the door and nothing here ever reaches the network.
+
+const ROOT = await mkdtemp(path.join(os.tmpdir(), "fetch-windows-saved-"));
+const SLUG = "demo-channel";
+process.env.TRANSCRIPTS_DIR = ROOT;
+process.env.SETTINGS_FILE = path.join(ROOT, "settings.json");
+delete process.env.FFPROBE_BIN;
+delete process.env.FFMPEG_BIN;
+
+// The temp corpus sits on whatever disk os.tmpdir() is; the floor is not what
+// is under test.
+await writeFile(process.env.SETTINGS_FILE, JSON.stringify({ minFreeDiskGB: 0 }));
+await mkdir(path.join(ROOT, "channels", SLUG), { recursive: true });
+await writeFile(
+ path.join(ROOT, "channels", SLUG, "config.json"),
+ JSON.stringify({ name: "Demo", handling: "youtube", url: "https://www.youtube.com/@demo" }),
+);
+
+async function pointTo(id: string, withFile: boolean): Promise<string> {
+ const videoDir = path.join(ROOT, "channels", SLUG, "data", id);
+ const store = path.join(ROOT, "saved-videos", SLUG, id);
+ await mkdir(videoDir, { recursive: true });
+ await mkdir(store, { recursive: true });
+ await writeFile(
+ path.join(videoDir, "metadata.info.json"),
+ JSON.stringify({ id, webpage_url: `https://www.youtube.com/watch?v=${id}` }),
+ );
+ if (withFile) {
+ execFileSync("ffmpeg", [
+ "-nostdin", "-v", "error", "-y",
+ "-f", "lavfi", "-i", "testsrc=size=160x90:rate=10:duration=8",
+ "-f", "lavfi", "-i", "sine=frequency=440:duration=8",
+ "-c:v", "libx264", "-preset", "ultrafast", "-pix_fmt", "yuv420p", "-c:a", "aac", "-shortest",
+ path.join(store, "source-media.mp4"),
+ ]);
+ }
+ await writeFile(
+ path.join(videoDir, "saved-video.json"),
+ JSON.stringify({ storedAt: "", dir: store, file: "source-media.mp4", bytes: 1, keepReason: "pin" }),
+ );
+ return videoDir;
+}
+const HELD = await pointTo("held1", true);
+await pointTo("gone1", false);
+
+const { fetchWindowsAction } = await import("./fetchWindowsAction");
+const { getRegistry } = await import("yt-dlp-transcript-common/jobs/registry");
+const { recordDownloadBackoff } = await import("yt-dlp-transcript-common/jobs/downloadBackoff");
+const { getPaths } = await import("yt-dlp-transcript-common/lib/paths");
+await recordDownloadBackoff("youtube", getPaths());
+test.after(() => rm(ROOT, { recursive: true, force: true }));
+
+const items = [
+ { slug: SLUG, id: "held1", from: 1, to: 3, clipId: "r#1" },
+ { slug: SLUG, id: "held1", from: 6, to: 12, clipId: "r#2" }, // past the container's end
+ { slug: SLUG, id: "gone1", from: 1, to: 3, clipId: "r#3" },
+];
+
+test("a dry run groups held windows on clips:saved-video, refuses the unreadable, and sends the rest to their platform", async () => {
+ const r = await fetchWindowsAction({ items, requestedBy: "test", dryRun: true });
+ assert.ok(r.ok);
+ if (!r.ok) return;
+ assert.deepEqual(
+ r.groups.map((g) => [g.platform, g.queueKey, g.items.map((i) => i.clipId)]).sort(),
+ [
+ ["saved-video", "clips:saved-video", ["r#1"]],
+ ["youtube", "clips:youtube", ["r#2"]],
+ ],
+ );
+ assert.equal(r.unresolved.length, 1);
+ assert.equal(r.unresolved[0].item.id, "gone1");
+ assert.match(r.unresolved[0].error, /^Channel "demo-channel": media is not reachable — its saved video .* is not there/);
+});
+
+test("a real run cuts the held window in a saved-video job while the cooling platform is refused", async () => {
+ const r = await fetchWindowsAction({ items, requestedBy: "test", manifest: "m" });
+ assert.ok(r.ok, JSON.stringify(r));
+ if (!r.ok) return;
+ assert.deepEqual(
+ r.jobs.map((j) => [j.platform, j.queueKey, j.items]),
+ [["saved-video", "clips:saved-video", 1]],
+ );
+ assert.deepEqual(r.refused.map((x) => x.platform), ["youtube"]);
+ const jobId = r.jobs[0].jobId;
+ const reg = getRegistry();
+ for (let i = 0; i < 200; i++) {
+ const s = reg.get(jobId)?.status;
+ if (s !== "queued" && s !== "running") break;
+ await new Promise((res) => setTimeout(res, 50));
+ }
+ assert.equal(reg.get(jobId)?.status, "done", `job ${jobId}: ${reg.get(jobId)?.status}`);
+ assert.deepEqual((await readdir(path.join(HELD, "clips"))).sort(), ["1.00-3.00.json", "1.00-3.00.mp4"]);
+ const sidecar = JSON.parse(await readFile(path.join(HELD, "clips", "1.00-3.00.json"), "utf8"));
+ assert.equal(sidecar.source, "saved-video");
+ assert.equal(sidecar.manifest, "m");
+ assert.equal(sidecar.clipId, "r#1");
+
+ // Sent again, the cut window is cached and joins no job.
+ const again = await fetchWindowsAction({ items: [items[0]], requestedBy: "test", dryRun: true });
+ assert.ok(again.ok);
+ if (!again.ok) return;
+ assert.deepEqual(again.cached.map((i) => i.clipId), ["r#1"]);
+ assert.deepEqual(again.groups, []);
+});
+
+test("a held window a queued saved-video job will already cut is answered in inFlight (A5's dedupe)", async () => {
+ const reg = getRegistry();
+ const make = (id: string, params: Record<string, unknown>) => {
+ const record = {
+ id,
+ kind: "fetch-windows",
+ queueKey: "clips:saved-video",
+ channelSlug: SLUG,
+ status: "queued" as const,
+ queuedAt: Date.now(),
+ logPath: "/dev/null",
+ spec: { kind: "fetch-windows", slug: SLUG, params },
+ };
+ reg.register(record);
+ reg.enqueue(record, { start: () => {}, onCancel: () => {} });
+ };
+ make("HOLDER", { items: [{ slug: SLUG, id: "other", from: 0, to: 1 }] });
+ make("CUT4", { items: [{ slug: SLUG, id: "held1", from: 4, to: 7 }] });
+ try {
+ const r = await fetchWindowsAction({
+ items: [{ slug: SLUG, id: "held1", from: 4.5, to: 6.5 }],
+ requestedBy: "test",
+ dryRun: true,
+ });
+ assert.ok(r.ok);
+ if (!r.ok) return;
+ assert.deepEqual(r.inFlight.map((f) => f.jobId), ["CUT4"]);
+ assert.deepEqual(r.groups, []);
+ } finally {
+ reg.cancel("CUT4");
+ reg.forceRelease("HOLDER");
+ }
+});
diff --git a/editor/app/channels/[slug]/videos/fetchWindowsAction.ts b/editor/app/channels/[slug]/videos/fetchWindowsAction.ts
@@ -5,7 +5,12 @@ import { getPaths } from "yt-dlp-transcript-common/lib/paths";
import { getSettings } from "yt-dlp-transcript-common/lib/settings";
import { diskGate } from "yt-dlp-transcript-common/lib/diskSpace";
import { formatBytes } from "yt-dlp-transcript-common/lib/format";
-import { clipWindowQueueKey, resolveQueueKey } from "yt-dlp-transcript-common/lib/queueKeys";
+import {
+ SAVED_VIDEO_CLIP_PLATFORM,
+ SAVED_VIDEO_CLIP_QUEUE,
+ clipWindowQueueKey,
+ resolveQueueKey,
+} from "yt-dlp-transcript-common/lib/queueKeys";
import { getRegistry } from "yt-dlp-transcript-common/jobs/registry";
import { windowInFlight } from "yt-dlp-transcript-common/jobs/windowJobs";
import { detectPlatform, queueKeyForUrl } from "yt-dlp-transcript-common/lib/platform";
@@ -14,6 +19,7 @@ import {
isFetchMaxHeight,
} from "yt-dlp-transcript-common/lib/clipWindow";
import { findContainingClipWindow } from "yt-dlp-transcript-common/lib/clipWindow-server";
+import { savedWindowSource } from "yt-dlp-transcript-common/lib/savedVideoWindow-server";
import type { ChannelConfig } from "yt-dlp-transcript-common/lib/channelConfig";
import {
isValidChannelSlug,
@@ -59,6 +65,14 @@ import { safeRevalidate } from "../../../lib/safeRevalidate";
// queued or running job will already write (`inFlight`, with that job's id —
// jobs/windowJobs.ts): the same manifest sent twice queues nothing twice.
//
+// A WINDOW A SAVED CONTAINER HOLDS (release 21 D2) joins no platform's job: it
+// goes to one group of its own, platform `saved-video` on the
+// `clips:saved-video` queue, whose job CUTS each window from the container
+// (controller/fetchWindows.ts) — no request, no pause, no hold or cooldown to
+// pass. A pointer whose container cannot be read is `unresolved` with the
+// media guard's sentence, never sent to the network; one whose container ends
+// before the window is fetched as before.
+//
// Like the single fetch, NOT GATED BY THE DOWNLOAD PAUSE: an operator (or a
// tool they are driving) asked for these seconds by hand.
@@ -80,6 +94,8 @@ export type FetchWindowsUnresolved = { item: FetchWindowsItem; error: string };
export type FetchWindowsGroup = {
// The cooldown key (`detectPlatform(url)`), and the queue the job runs on.
+ // `saved-video` (SAVED_VIDEO_CLIP_PLATFORM) for the windows cut from saved
+ // containers, on SAVED_VIDEO_CLIP_QUEUE.
platform: string;
queueKey: string;
items: FetchWindowsItem[];
@@ -174,6 +190,30 @@ async function planFetchWindows(
inFlight.push({ item, jobId: running.jobId });
continue;
}
+ // The saved container: a window it holds is cut, on a queue no platform
+ // shares; one it cannot be read for is refused here, not fetched.
+ const saved = await savedWindowSource({
+ paths,
+ slug: item.slug,
+ videoDir,
+ from: item.from,
+ to: item.to,
+ });
+ if (saved.kind === "unreadable") {
+ unresolved.push({ item, error: saved.error });
+ continue;
+ }
+ if (saved.kind === "covers") {
+ const queueKey = resolveQueueKey(SAVED_VIDEO_CLIP_QUEUE, queueOverride);
+ const group = groups.get(queueKey) ?? {
+ platform: SAVED_VIDEO_CLIP_PLATFORM,
+ queueKey,
+ items: [],
+ };
+ group.items.push(item);
+ groups.set(queueKey, group);
+ continue;
+ }
const url =
item.webpageUrl?.trim() ||
(await findVideoSourceUrl(paths, item.slug, item.id, config));
@@ -204,6 +244,8 @@ async function planFetchWindows(
// The door each group passes before its job is queued: the platform's hold,
// then its cooldown — fetchWindowAction's checks and sentences.
async function groupRefusal(platform: string): Promise<string | null> {
+ // Cuts from saved containers ask no platform.
+ if (platform === SAVED_VIDEO_CLIP_PLATFORM) return null;
const paths = getPaths();
const held = await heldPlatformRefusal(platform, "This batch", paths);
if (held) return held;
diff --git a/mcp/src/instructions.ts b/mcp/src/instructions.ts
@@ -155,7 +155,8 @@ function clipStep(ctx: PlanContext): string {
`NEVER run yt-dlp yourself, in any form. If the tool reports no editor is ` +
`configured, say so and stop — the README's yt-dlp command is the ` +
`operator's fallback, not yours. If it returns queued, call it again with ` +
- `the job it names.`
+ `the job it names. A video the archive holds locally is cut from its ` +
+ `saved copy without a fetch (cached at once).`
);
}