Refetch missing media from catalog source

This commit is contained in:
Jonathan Sykes
2026-10-14 01:26:25 +08:00
parent 593ecaecd9
commit ca10fe6486
6 changed files with 46 additions and 12 deletions

View File

@@ -2,7 +2,7 @@
// Uses real ffmpeg fixtures and the real db.js against a throwaway DB file.
import { describe, test, expect, beforeAll, afterAll } from 'bun:test';
import { spawnSync } from 'node:child_process';
import { mkdtempSync, rmSync, copyFileSync, writeFileSync, readFileSync, existsSync, readdirSync } from 'node:fs';
import { mkdtempSync, rmSync, copyFileSync, writeFileSync, readFileSync, existsSync, readdirSync, unlinkSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
@@ -93,6 +93,7 @@ let dirN = 0;
function makeCache({ fixture = 'good.mp4', duration = 10, ...opts } = {}) {
const dir = join(root, 'media' + dirN++);
const calls = [];
const sources = [];
const db = {
getMedia: dbmod.getMedia, upsertMedia: dbmod.upsertMedia, deleteMedia: dbmod.deleteMedia,
listMedia: dbmod.listMedia, listMediaLru: dbmod.listMediaLru, touchMedia: dbmod.touchMedia,
@@ -102,13 +103,13 @@ function makeCache({ fixture = 'good.mp4', duration = 10, ...opts } = {}) {
const cache = createMediaCache({
dir, db, log: silentLog,
getInfo: async (id) => ({ id, title: 'T ' + id, channel: 'C', duration }),
download: async (id, out) => { calls.push(id); await sleep(30); copyFileSync(fx(state.fixture), out); return out; },
download: async (id, out, sourceUrl) => { calls.push(id); sources.push({ id, sourceUrl }); await sleep(30); copyFileSync(fx(state.fixture), out); return out; },
transcode: { enabled: false },
freeBytes: () => 100 * 1024 ** 3,
backfillDelayMs: -1,
...opts,
});
return { cache, dir, calls, state };
return { cache, dir, calls, sources, state };
}
async function clearDb() {
for (const r of await dbmod.listMedia()) await dbmod.deleteMedia(r.video_id);
@@ -233,6 +234,19 @@ describe('media cache jobs', () => {
expect(calls.length).toBe(2);
});
test('missing cached files are re-fetched from the stored source URL', async () => {
await clearDb();
const id = 'srcAAAAAA01';
const sourceUrl = `https://www.youtube.com/watch?v=${id}`;
const { cache, dir, calls, sources } = makeCache({ getSourceUrl: async () => sourceUrl });
await cache.init();
const first = await cache.ensureCached(id, { priority: HIGH });
unlinkSync(join(dir, `${id}.${first.gen}.mp4`));
await cache.ensureCached(id, { priority: HIGH });
expect(calls).toHaveLength(2);
expect(sources.every(call => call.id === id && call.sourceUrl === sourceUrl)).toBe(true);
});
test('auto jobs respect the auto length limit; explicit saves do not', async () => {
await clearDb();
const { cache } = makeCache({ duration: 7200, autoMaxSeconds: 3600 });