Still-picture songs save and play as audio plus one picture

This commit is contained in:
Jonathan Sykes
2026-10-17 07:00:22 +08:00
parent 2e6c79e360
commit eef9fbf05f
10 changed files with 262 additions and 24 deletions

View File

@@ -404,7 +404,7 @@ describe('media cache jobs', () => {
test('still-picture lane: one looped frame in H.264, far smaller, still verifies', async () => {
await clearDb();
const lines = [];
const { cache } = makeCache({ fixture: 'still40.mp4', duration: 40, log: { info: (m) => lines.push(m), warn: (m) => lines.push(m) },
const { cache, dir } = makeCache({ fixture: 'still40.mp4', duration: 40, log: { info: (m) => lines.push(m), warn: (m) => lines.push(m) },
transcode: { enabled: true, codec: 'hevc', crf: 28, preset: 'ultrafast', threads: 2 } });
await cache.init();
const first = await cache.ensureCached('stilAAAAAA1', { priority: HIGH });
@@ -415,6 +415,24 @@ describe('media cache jobs', () => {
expect(after.size).toBeLessThan(first.size * 0.6);
expect(lines.some((l) => /\(still\)/.test(l))).toBe(true);
expect(await cache.verify('stilAAAAAA1')).toBe(true);
// Devices can save audio + picture: the flag, the picture and the m4a hash.
expect(after.still).toBe(1);
const art = await cache.filePath('stilAAAAAA1', after.gen, 'jpg');
expect(art).toBeTruthy();
expect(after.audio_sha256).toBe(await sha256File(await cache.filePath('stilAAAAAA1', after.gen, 'm4a')));
// An already-looped copy (1 fps, one keyframe) is recognised as still after
// a deploy that predates the flag.
await dbmod.upsertMedia('stilAAAAAA1', { still: null, audio_sha256: null });
unlinkSync(art);
const again = createMediaCache({
dir, db: { getMedia: dbmod.getMedia, upsertMedia: dbmod.upsertMedia, deleteMedia: dbmod.deleteMedia,
listMedia: dbmod.listMedia, listMediaLru: dbmod.listMediaLru, touchMedia: dbmod.touchMedia, mediaStats: dbmod.mediaStats },
log: silentLog, getInfo: async () => ({ duration: 40 }), download: async () => { throw new Error('no download expected'); },
transcode: { enabled: false }, freeBytes: () => 100 * 1024 ** 3,
});
await again.init();
expect(await until(async () => (await dbmod.getMedia('stilAAAAAA1')).still === 1, 20000)).toBe(true);
expect(await again.filePath('stilAAAAAA1', after.gen, 'jpg')).toBeTruthy();
}, 90000);
test('a moving copy already done by the HEVC lane is not re-encoded for rev 3', async () => {
@@ -437,6 +455,7 @@ describe('media cache jobs', () => {
await again.init();
expect(await until(async () => (await dbmod.getMedia('rev2AAAAAA1')).optimized === OPT_REV, 30000)).toBe(true);
expect((await dbmod.getMedia('rev2AAAAAA1')).gen).toBe(before.gen);
expect((await dbmod.getMedia('rev2AAAAAA1')).still).toBe(0);
}, 120000);
test('copies evaluated by an older lane revision are re-queued at boot', async () => {