Archilyzer · Source

archilyzer

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

commit e81e8c9630feaa732e86d4e3e9a7cfeef20747c6
parent 2fec224848f03a2d8347aa1b5abc92c38a080a91
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Wed,  7 Oct 2026 20:22:25 -0400

fetch-window: a video's own URL picks its platform args, not its channel's

community-notes has no url or platform and holds Rumble videos, so its
windows were fetched without --impersonate and Rumble's Cloudflare
refused the embed JSON (403) — then the next, impersonated request too.
configForVideoUrl lets the URL's platform choose the args and the pace.

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

Diffstat:
Mcommon/ytdlp/channelArgs.test.ts | 18++++++++++++++++++
Mcommon/ytdlp/channelArgs.ts | 12++++++++++++
Mcommon/ytdlp/fetchWindowManaged.ts | 6++++--
3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/common/ytdlp/channelArgs.test.ts b/common/ytdlp/channelArgs.test.ts @@ -3,6 +3,7 @@ import assert from "node:assert/strict"; import { channelExtraArgs, channelPaceSeconds, + configForVideoUrl, pacedPlatformArgs, platformArgs, platformArgsForUrl, @@ -198,3 +199,20 @@ test("one-off imports have their own floor: Odysee's 60 s, BitChute's batch floo assert.equal(platformImportMinGapSeconds(p), 0, String(p)); } }); + +test("a video's own URL picks the platform args when the channel names none or another", () => { + const notes = cfg({ handling: "transcribe" } as Partial<ChannelConfig>); + assert.deepEqual(channelExtraArgs(notes), []); + assert.deepEqual( + channelExtraArgs(configForVideoUrl(notes, "https://rumble.com/v7em13s-x.html")), + RUMBLE, + ); + const yt = cfg({ url: "https://www.youtube.com/@x", ytdlpExtraArgs: ["--limit-rate", "1M"] }); + assert.deepEqual( + channelExtraArgs(configForVideoUrl(yt, "https://rumble.com/v7em13s-x.html")), + [...RUMBLE, "--limit-rate", "1M"], + "the channel's own args still apply", + ); + assert.equal(configForVideoUrl(yt, "https://www.youtube.com/watch?v=abc"), yt); + assert.equal(configForVideoUrl(yt, "https://example.com/v.mp4"), yt); +}); diff --git a/common/ytdlp/channelArgs.ts b/common/ytdlp/channelArgs.ts @@ -53,6 +53,18 @@ export function channelPlatform( return config.platform ?? detectPlatform(config.url); } +// The config to build a VIDEO's argv from: the channel's, with the platform +// taken from the video's own URL when that names a different one. A channel +// may hold another platform's videos — community-notes has no url or platform +// of its own and holds Rumble videos — and a Rumble request without Rumble's +// args (`--impersonate`) is refused at Cloudflare. The request goes where the +// URL points, so the URL's platform decides the args and the pace. +export function configForVideoUrl(config: ChannelConfig, videoUrl: string): ChannelConfig { + const platform = detectPlatform(videoUrl); + if (!platform || platform === channelPlatform(config)) return config; + return { ...config, platform, url: videoUrl }; +} + // The key the pacing state is kept under — the same one the rate-limit // cooldown uses (`detectPlatform(url) ?? "unknown"`, autoRunner/runYtdlp), so a // 429 recorded by any path paces every path. diff --git a/common/ytdlp/fetchWindowManaged.ts b/common/ytdlp/fetchWindowManaged.ts @@ -41,7 +41,7 @@ import { writeClipProvenance, type ClipWindow, } from "../lib/clipWindow-server"; -import { channelExtraArgs } from "./channelArgs"; +import { channelExtraArgs, configForVideoUrl } from "./channelArgs"; import { runOneYtdlp } from "./runOneYtdlp"; import { FULL_LOG_PROGRESS_ARGS } from "./downloadOneManaged"; import { clipFormatSelector } from "./downloadFormat"; @@ -210,7 +210,9 @@ export async function fetchWindowManaged( "--merge-output-format", "mp4", ...FULL_LOG_PROGRESS_ARGS, - ...channelExtraArgs(opts.channelConfig, cookies), + // The video's URL picks the platform args: a channel may hold another + // platform's videos (configForVideoUrl). + ...channelExtraArgs(configForVideoUrl(opts.channelConfig, opts.videoUrl), cookies), // THE NEGATIONS COME AFTER THE CHANNEL'S OWN ARGS, AND -o AFTER THOSE. // // `ytdlpExtraArgs` is free text an operator typed into a form; it is