Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit 743deb3cabab054800cbe60ed24fa09c79275f51
parent 0e84914b7fd62b967973d8b315704ffba3d483ee
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Wed,  7 Oct 2026 17:56:36 -0400

fetch-windows: a window's own URL picks its queue, not its channel's

A channel whose URL is no platform's (community-notes) holding Rumble videos
grouped them on platform:unknown, so a second Rumble job would run beside the
first, each pacing only itself. Seen on the jeralyzer-private dry run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Diffstat:
Meditor/app/api/ops/fetch-windows/route.test.ts | 10++++++++--
Meditor/app/channels/[slug]/videos/fetchWindowsAction.ts | 16+++++++++-------
2 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/editor/app/api/ops/fetch-windows/route.test.ts b/editor/app/api/ops/fetch-windows/route.test.ts @@ -19,7 +19,7 @@ process.env.SETTINGS_FILE = path.join(ROOT, "settings.json"); const { POST } = await import("./route"); test.after(() => rm(ROOT, { recursive: true, force: true })); -// Two channels on two platforms, one video each, the YouTube one with a window +// Channels on two platforms, one video each, the YouTube one with a window // already on disk. const CH = path.join(ROOT, "channels"); async function channel(slug: string, url: string, id: string, webpage: string) { @@ -35,6 +35,8 @@ async function channel(slug: string, url: string, id: string, webpage: string) { } await channel("yt-chan", "https://www.youtube.com/@yt", "vid1", "https://www.youtube.com/watch?v=vid1"); await channel("rb-chan", "https://rumble.com/c/rb", "rb1", "https://rumble.com/rb1-x.html"); +// A channel whose own URL is no platform's, holding a Rumble video. +await channel("mix-chan", "https://example.test/mix", "rb2", "https://rumble.com/rb2-y.html"); await mkdir(path.join(CH, "yt-chan", "data", "vid1", "clips"), { recursive: true }); await writeFile(path.join(CH, "yt-chan", "data", "vid1", "clips", "0.00-60.00.mp4"), "mp4"); @@ -103,6 +105,7 @@ test("a dry run answers the cache, groups by platform queue, and names what it c item({ from: 100, to: 110 }), item({ from: 100, to: 110 }), // a duplicate collapses item({ slug: "rb-chan", id: "rb1", from: 5, to: 15 }), + item({ slug: "mix-chan", id: "rb2", from: 5, to: 15 }), item({ slug: "no-such", id: "x", from: 5, to: 15 }), ], }); @@ -119,8 +122,11 @@ test("a dry run answers the cache, groups by platform queue, and names what it c assert.deepEqual(j.cached.map((c) => c.from), [10]); assert.deepEqual( j.groups.map((g) => [g.platform, g.items.length]).sort(), - [["rumble", 1], ["youtube", 1]], + [["rumble", 2], ["youtube", 1]], ); + // The window's own URL picks the queue: the mix channel's Rumble video joins + // the Rumble job rather than starting a second one beside it. + assert.deepEqual(j.groups.map((g) => g.queueKey).sort(), ["platform:rumble", "platform:youtube"]); const yt = j.groups.find((g) => g.platform === "youtube")!; assert.equal(yt.items[0].webpageUrl, "https://www.youtube.com/watch?v=vid1"); assert.equal(j.unresolved.length, 1); diff --git a/editor/app/channels/[slug]/videos/fetchWindowsAction.ts b/editor/app/channels/[slug]/videos/fetchWindowsAction.ts @@ -5,11 +5,8 @@ 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 { detectPlatform } from "yt-dlp-transcript-common/lib/platform"; -import { - downloadQueueKey, - resolveQueueKey, -} from "yt-dlp-transcript-common/lib/queueKeys"; +import { resolveQueueKey } from "yt-dlp-transcript-common/lib/queueKeys"; +import { detectPlatform, queueKeyForUrl } from "yt-dlp-transcript-common/lib/platform"; import { MAX_CLIP_WINDOW_SECONDS, isFetchMaxHeight, @@ -48,7 +45,8 @@ import { safeRevalidate } from "../../../lib/safeRevalidate"; // The batch form of fetchWindowAction (videos/[id]/videoActions.ts), with the // same rules at the door: a window of at most MAX_CLIP_WINDOW_SECONDS, a height // cap in range, a channel that exists, a URL that resolves. What it adds is the -// fan-out: the list is grouped by `downloadQueueKey` and each group starts its +// fan-out: the list is grouped by the queue of each window's own URL +// (`queueKeyForUrl`) and each group starts its // own job on that queue, so YouTube and Rumble run side by side, each behind // its own platform's other downloads — persistVideosAction's shape. // @@ -164,7 +162,11 @@ async function planFetchWindows( }); continue; } - const queueKey = resolveQueueKey(downloadQueueKey(config), queueOverride); + // THE WINDOW'S OWN URL decides the queue, not the channel's: a channel + // whose URL is no platform's (a curated mix) can hold Rumble videos, and + // its queue would put a second Rumble job beside the first, each pacing + // only itself. + const queueKey = resolveQueueKey(queueKeyForUrl(url), queueOverride); const platform = detectPlatform(url) ?? "unknown"; // One job per queue. Two platforms sharing a queue (an override) share a // job too; the controller keys the cooldown per item, so each is honoured.