commit b5a1b354a74db59e78ff596343ff157c303933cf
parent cd1c5dbea3a0baa6c23f762bad774bdbc17ee207
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Thu, 1 Oct 2026 22:10:35 -0400
common: the hook's media-side temp is scratch and a dead process's is swept (re-review R2)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
4 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/common/lib/mediaTier-server.test.ts b/common/lib/mediaTier-server.test.ts
@@ -325,3 +325,16 @@ test("removeMediaFile derefs a link into ANOTHER id's media dir (a renamed video
await assert.rejects(lstat(path.join(f.videoDir, "audio.m4a")));
await rm(f.root, { recursive: true, force: true });
});
+
+test("a dead process's half-placed bytes in media/<id>/ are swept with the video dir", async () => {
+ const f = await fixture();
+ const tierDir = path.join(channelMediaLink(f.paths, f.slug), "vid1");
+ await mkdir(tierDir, { recursive: true });
+ await writeFile(path.join(tierDir, ".audio.mp3.tiering-999999"), "HALF");
+ await tierVideoDir(f.videoDir);
+ assert.deepEqual(
+ (await readdir(tierDir)).filter((n) => n.includes("tiering")),
+ [],
+ );
+ await rm(f.root, { recursive: true, force: true });
+});
diff --git a/common/lib/mediaTier-server.ts b/common/lib/mediaTier-server.ts
@@ -288,6 +288,17 @@ export async function tierVideoDir(
if (!isTierable(name)) continue;
counts[await tierMediaFile(videoDir, name, opts)] += 1;
}
+ // The media side's strays: bytes a dead process was placing
+ // (`.<name>.tiering-<pid>` in `media/<id>/`). Only while the tier answers.
+ const destDir = mediaDirOfVideoDir(videoDir);
+ if (await mediaTierReady(path.dirname(destDir))) {
+ for (const name of await readdir(destDir).catch(() => [] as string[])) {
+ const stray = /^\..+\.tiering-(\d+)$/.exec(name);
+ if (stray && !processAlive(Number(stray[1]))) {
+ await rm(path.join(destDir, name), { force: true }).catch(() => {});
+ }
+ }
+ }
return counts;
}
diff --git a/common/lib/mediaTier.test.ts b/common/lib/mediaTier.test.ts
@@ -44,6 +44,7 @@ const TABLE: ReadonlyArray<[string, "media" | "text" | "scratch", boolean]> = [
["audio.m4a.ytdl", "scratch", false],
[".audio.mp3.parakeet", "scratch", false],
[".audio.mp3.tierlink-4242", "scratch", false],
+ [".audio.mp3.tiering-4242", "scratch", false],
// The hot text.
["transcript.json", "text", false],
["transcript.en.vtt", "text", false],
diff --git a/common/lib/mediaTier.ts b/common/lib/mediaTier.ts
@@ -59,8 +59,10 @@ const SCRATCH_PATTERNS: ReadonlyArray<RegExp> = [
// yt-dlp's resume-state file beside one (`audio.m4a.ytdl`).
/\.part$/,
/\.ytdl$/,
- // The media-tier hook's own temp link (`lib/mediaTier-server.ts`).
+ // The media-tier hook's own temps (`lib/mediaTier-server.ts`): the link
+ // beside the name, and the bytes being placed in `media/<id>/`.
/\.tierlink-\d+$/,
+ /\.tiering-\d+$/,
];
export function isScratchEntry(name: string): boolean {