fix(subtitles): improve secondary subtitle extraction and display (#215)

This commit is contained in:
sudacode authored and GitHub committed 2026-08-23 01:56:49 -07:00
1 parent 0a0aa3ec98
commit 509dc5bf7f
20 files changed
+503 -37

No files matched your search

@@ -6,6 +6,7 @@ import process from 'node:process';
import test from 'node:test';
import {
buildFfmpegSubtitleExtractionArgs,
createCachedInternalSubtitleTrackExtractor,
extractInternalSubtitleTrackToTempFile,
parseTrackId,
} from './internal-subtitle-extraction';
@@ -22,6 +23,65 @@ test('parseTrackId rejects negative track ids', () => {
assert.equal(parseTrackId(' -2 '), null);
});
test('cached internal subtitle extraction shares concurrent and repeated track requests', async () => {
let extractionCalls = 0;
let cleanupCalls = 0;
let resolveExtraction:
| ((result: { path: string; cleanup: () => Promise<void> }) => void)
| undefined;
const firstExtraction = new Promise<{ path: string; cleanup: () => Promise<void> }>((resolve) => {
resolveExtraction = resolve;
});
const extractor = createCachedInternalSubtitleTrackExtractor({
extract: async () => {
extractionCalls += 1;
if (extractionCalls === 1) {
return firstExtraction;
}
return {
path: `/tmp/subtitle-${extractionCalls}.ass`,
cleanup: async () => {
cleanupCalls += 1;
},
};
},
});
const request = () =>
extractor.extract('ffmpeg', '/Volumes/media/episode.mkv', {
'ff-index': 3,
codec: 'ass',
});
const concurrent = Array.from({ length: 6 }, request);
assert.equal(extractionCalls, 1);
if (!resolveExtraction) {
throw new Error('extraction did not start');
}
resolveExtraction({
path: '/tmp/subtitle-1.ass',
cleanup: async () => {
cleanupCalls += 1;
},
});
const results = await Promise.all(concurrent);
assert.deepEqual(
results.map((result) => result?.path),
Array.from({ length: 6 }, () => '/tmp/subtitle-1.ass'),
);
await Promise.all(results.map((result) => result?.cleanup()));
assert.equal(cleanupCalls, 0);
assert.equal((await request())?.path, '/tmp/subtitle-1.ass');
assert.equal(extractionCalls, 1);
extractor.clear();
await new Promise((resolve) => setImmediate(resolve));
assert.equal(cleanupCalls, 1);
assert.equal((await request())?.path, '/tmp/subtitle-2.ass');
assert.equal(extractionCalls, 2);
});
test('extractInternalSubtitleTrackToTempFile times out stalled ffmpeg process', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-ffmpeg-timeout-'));
const videoPath = path.join(root, 'video.mkv');