Hash every validated server copy and register it as verified content

This commit is contained in:
Claude
2026-09-30 07:18:52 +00:00
parent b19193841c
commit ea56d286b3
10 changed files with 245 additions and 7 deletions

View File

@@ -10,6 +10,8 @@ const root = mkdtempSync(join(tmpdir(), 'ytp-media-test-'));
process.env.DB_PATH = join(root, 'test.db');
const dbmod = await import('./db.js');
const { createMediaCache, validateMedia, MediaSkip, HIGH, LOW, OPT_REV } = await import('./media-cache.js');
const { initP2pSchema } = await import('./p2p-db.js');
const { sha256File } = await import('./hash.js');
const fx = (name) => join(root, name);
const ff = (...args) => {
@@ -26,6 +28,7 @@ async function until(fn, ms = 20000) {
beforeAll(async () => {
await dbmod.initDb();
await initP2pSchema(); // adds media_cache.sha256
// 10 s 640x360 H.264 + AAC — the shape of a good cached copy.
ff('-f', 'lavfi', '-i', 'testsrc=size=640x360:rate=30:duration=10', '-f', 'lavfi', '-i', 'sine=frequency=440:duration=10',
'-c:v', 'libx264', '-preset', 'ultrafast', '-pix_fmt', 'yuv420p', '-c:a', 'aac', '-shortest', fx('good.mp4'));
@@ -102,6 +105,7 @@ function makeCache({ fixture = 'good.mp4', duration = 10, ...opts } = {}) {
download: async (id, out) => { calls.push(id); 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 };
@@ -110,6 +114,35 @@ async function clearDb() {
for (const r of await dbmod.listMedia()) await dbmod.deleteMedia(r.video_id);
}
describe('content hashes (P2P cids)', () => {
test('a promoted copy stores the sha256 of its mp4 and reports it once', async () => {
await clearDb();
const seen = [];
const { cache, dir } = makeCache({ onReady: (i) => { seen.push(i); } });
await cache.init();
const row = await cache.ensureCached('hashAAAAAA1', { priority: HIGH });
const want = await sha256File(join(dir, `hashAAAAAA1.${row.gen}.mp4`));
expect((await dbmod.getMedia('hashAAAAAA1')).sha256).toBe(want);
expect(await until(() => seen.length === 1)).toBe(true);
expect(seen[0]).toMatchObject({ id: 'hashAAAAAA1', gen: row.gen, sha256: want, vcodec: 'h264' });
expect(seen[0].meta.title).toBe('T hashAAAAAA1');
});
test('backfill hashes ready copies that have no sha256 yet', async () => {
await clearDb();
const seen = [];
const { cache } = makeCache({ onReady: (i) => { seen.push(i); } });
await cache.init();
await cache.ensureCached('hashAAAAAA2', { priority: HIGH });
await dbmod.upsertMedia('hashAAAAAA2', { sha256: null });
seen.length = 0;
expect(await cache.backfillHashes()).toBe(1);
expect((await dbmod.getMedia('hashAAAAAA2')).sha256).toMatch(/^[0-9a-f]{64}$/);
expect(await until(() => seen.length === 1)).toBe(true);
expect(await cache.backfillHashes()).toBe(0); // nothing left
});
});
describe('media cache jobs', () => {
test('fetches once, dedupes concurrent requests, then serves from disk', async () => {
await clearDb();