Compact HE-AAC audio saves: server lane with fdkaac, shrink saved songs from Saved videos

This commit is contained in:
Jonathan Sykes
2026-10-18 17:28:47 +08:00
parent eef9fbf05f
commit b48d36b3dd
12 changed files with 342 additions and 22 deletions

View File

@@ -435,6 +435,39 @@ describe('media cache jobs', () => {
expect(await again.filePath('stilAAAAAA1', after.gen, 'jpg')).toBeTruthy();
}, 90000);
// Stand-in for fdkaac (not installed on dev machines): same CLI shape, reads
// WAV on stdin, writes a low-bitrate AAC .m4a to -o.
function fakeFdkaac() {
const p = join(root, 'fake-fdkaac.sh');
writeFileSync(p, '#!/bin/sh\nwhile [ "$1" != "-o" ]; do shift; done\nout="$2"\nexec ffmpeg -v error -nostdin -y -f wav -i - -c:a aac -b:a 24k -f mp4 "$out"\n');
spawnSync('chmod', ['+x', p]);
return p;
}
test('compact audio lane: HE-AAC copy is made once, gated, and kept with the copy', async () => {
await clearDb();
const { cache } = makeCache({ fixture: 'still40.mp4', duration: 40, fdkaac: fakeFdkaac() });
await cache.init();
expect((await cache.compactAudio('compAAAAAA1')).status).toBe('none');
await cache.ensureCached('compAAAAAA1', { priority: HIGH });
expect(await until(async () => ((await dbmod.getMedia('compAAAAAA1')).he_size || 0) > 0, 20000)).toBe(true);
const he = await cache.compactAudio('compAAAAAA1');
expect(he.status).toBe('ready');
const lc = await cache.filePath('compAAAAAA1', he.gen, 'm4a');
expect(he.size).toBeLessThan(readFileSync(lc).length * 0.85);
expect(he.sha256).toBe(await sha256File(he.path));
expect(await cache.filePath('compAAAAAA1', he.gen, 'he.m4a')).toBe(he.path);
}, 60000);
test('compact audio is off (never blocks saves) when fdkaac is missing', async () => {
await clearDb();
const { cache } = makeCache({ fdkaac: join(root, 'no-such-fdkaac') });
await cache.init();
await cache.ensureCached('nofdAAAAAA1', { priority: HIGH });
expect(await until(async () => (await cache.compactAudio('nofdAAAAAA1')).status === 'off', 15000)).toBe(true);
expect((await cache.stats()).compactAudio).toBe('fdkaac missing');
}, 30000);
test('a moving copy already done by the HEVC lane is not re-encoded for rev 3', async () => {
await clearDb();
const seed = makeCache({ fixture: 'fat64.mp4', duration: 64,