Archilyzer · Source

archilyzer

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

commit 427b6f218041766fab69589d9d906f5b22c93ef8
parent b3b47e28964866e4e3189b8354a997740a7cd9a1
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Tue,  6 Oct 2026 09:07:41 -0400

wayback refresh: a lane pick whose outcome sidecar is newer has finished

A transcription or download pick is released once the record's transcribe-outcome.json /
download-outcome.json was written at or after the pick, so a finished pick does not hold
its record for the whole six-hour window.

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

Diffstat:
Mcommon/controller/waybackRefresh.test.ts | 10+++++++++-
Mcommon/controller/waybackRefresh.ts | 22++++++++++++++++++----
2 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/common/controller/waybackRefresh.test.ts b/common/controller/waybackRefresh.test.ts @@ -181,10 +181,18 @@ test("a record a live job names is held; a dead writer's job is not", async () = await writeFile( paths.autoQueueStateFile, JSON.stringify({ - transcription: { picks: [{ at, leafId: "x", videoId: `${JW_B}-12345678.mp4`, channelSlug: SLUG }] }, + transcription: { + picks: [ + { at, leafId: "x", videoId: `${JW_B}-12345678.mp4`, channelSlug: SLUG }, + // Finished: its outcome sidecar is newer than the pick (below). + { at: at - 1000, leafId: "x", videoId: "watch", channelSlug: SLUG }, + ], + }, + // Too old to be in flight. download: { picks: [{ at: at - 7 * 3600 * 1000, leafId: "x", videoId: "watch", channelSlug: SLUG }] }, }), ); + await writeFile(path.join(dataDir, "watch", "transcribe-outcome.json"), "{}"); const r = await refreshWaybackRecords({ slug: SLUG, paths, titles, now: () => new Date(at + 60_000) }); assert.equal(r.records.find((x) => x.from === `${JW_B}-12345678.mp4`)!.rename, "held"); const a = r.records.find((x) => x.from === `${JW_A}-12345678.mp4`)!; diff --git a/common/controller/waybackRefresh.ts b/common/controller/waybackRefresh.ts @@ -24,7 +24,7 @@ // No network. import path from "node:path"; -import { readdir, readFile } from "node:fs/promises"; +import { readdir, readFile, stat } from "node:fs/promises"; import { getPaths, type Paths } from "../lib/paths"; import { readJsonFile } from "../lib/jsonFile-server"; import { assertChannelTextReadable, readRelocationMarker } from "../lib/channelMedia"; @@ -129,11 +129,20 @@ async function liveJobs( const read = await readJsonFile(paths.autoQueueStateFile); const state = read.ok && read.value && typeof read.value === "object" ? (read.value as Record<string, unknown>) : {}; const since = now - LANE_PICK_HOLD_MS; - for (const kind of Object.values(state)) { - const picks = (kind as { picks?: unknown } | null)?.picks; + for (const [kind, kindState] of Object.entries(state)) { + const picks = (kindState as { picks?: unknown } | null)?.picks; if (!Array.isArray(picks)) continue; for (const pick of picks.slice(0, LANE_PICKS_HELD) as Partial<AutoQueuePick>[]) { - if (pick?.channelSlug === slug && typeof pick.videoId === "string" && (pick.at ?? 0) >= since) ids.add(pick.videoId); + if (pick?.channelSlug !== slug || typeof pick.videoId !== "string") continue; + const at = pick.at ?? 0; + if (at < since) continue; + // A pick whose outcome sidecar was written since is finished. + const outcome = LANE_OUTCOME[kind]; + if (outcome) { + const done = await stat(path.join(paths.channelsDir, slug, "data", pick.videoId, outcome)).catch(() => null); + if (done && done.mtimeMs >= at) continue; + } + ids.add(pick.videoId); } } } @@ -143,6 +152,11 @@ async function liveJobs( // How many of a lane's newest picks may still be in flight, and for how long. const LANE_PICKS_HELD = 4; const LANE_PICK_HOLD_MS = 6 * 60 * 60 * 1000; +// The sidecar a lane's run writes when it ends, by lane kind. +const LANE_OUTCOME: Record<string, string> = { + transcription: "transcribe-outcome.json", + download: "download-outcome.json", +}; // A title that is not one: absent, or the file's own name (what yt-dlp's // generic extractor titles a raw file with).