mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-24 12:15:27 -07:00
fix(subtitles): collapse layered ASS lyrics across startup and seeks
- Reconstruct fragment-only karaoke while preserving canonical animated signs - Reprocess live subtitles after initial playback and seek updates - Add a development launcher for playable media files
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { parseSubtitleCues } from '../../core/services/subtitle-cue-parser';
|
||||
import { createSubtitleProcessingController } from '../../core/services/subtitle-processing-controller';
|
||||
import type { SubtitleData } from '../../types';
|
||||
import {
|
||||
@@ -211,6 +212,69 @@ test('primeCurrentSubtitleForAutoplay emits raw first paint on cache miss before
|
||||
]);
|
||||
});
|
||||
|
||||
test('parsed cues replace a duplicate raw autoplay subtitle that was already primed', async () => {
|
||||
const rawText = 'ジグザグな道を抜け\nジグザグな道を抜け';
|
||||
const correctedText = 'ジグザグな道を抜け';
|
||||
const mediaPath = '/media/video.mkv';
|
||||
let currentSubText = '';
|
||||
const emitted: string[] = [];
|
||||
const client = {
|
||||
connected: true,
|
||||
currentVideoPath: mediaPath,
|
||||
currentTimePos: 90,
|
||||
currentSubText: rawText,
|
||||
requestProperty: async (name: string) => {
|
||||
if (name === 'sub-text') return rawText;
|
||||
if (name === 'time-pos') return 90;
|
||||
return null;
|
||||
},
|
||||
};
|
||||
const cues = parseSubtitleCues(
|
||||
[
|
||||
'[Events]',
|
||||
'Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text',
|
||||
`Dialogue: 1,0:01:29.00,0:01:32.00,EDJP,,0,0,0,,${correctedText}`,
|
||||
`Dialogue: 0,0:01:29.00,0:01:32.00,EDJP,,0,0,0,,${correctedText}`,
|
||||
].join('\n'),
|
||||
'startup-ending.ass',
|
||||
);
|
||||
let activeCues = cues.slice(0, 0);
|
||||
const runtime = createAutoplaySubtitlePrimingRuntime({
|
||||
getCurrentMediaPath: () => mediaPath,
|
||||
getMpvClient: () => client,
|
||||
setCurrentSubText: (text) => {
|
||||
currentSubText = text;
|
||||
},
|
||||
getCurrentSubText: () => currentSubText,
|
||||
getCurrentSubtitleData: () => null,
|
||||
getActiveParsedSubtitleCues: () => activeCues,
|
||||
setActiveParsedSubtitleMediaPath: () => {},
|
||||
subtitleProcessingController: {
|
||||
consumeCachedSubtitle: () => null,
|
||||
onSubtitleChange: () => true,
|
||||
refreshCurrentSubtitle: () => true,
|
||||
notePlainSubtitleEmitted: () => {},
|
||||
},
|
||||
emitSubtitlePayload: (payload) => emitted.push(payload.text),
|
||||
getSubtitlePrefetchService: () => null,
|
||||
getLastObservedTimePos: () => 90,
|
||||
getVisibleOverlayVisible: () => true,
|
||||
emitSecondarySubtitle: () => {},
|
||||
initSubtitlePrefetch: async () => {},
|
||||
refreshSubtitlePrefetchFromActiveTrack: async () => {},
|
||||
logDebug: () => {},
|
||||
});
|
||||
|
||||
await runtime.primeCurrentSubtitleForAutoplay(mediaPath);
|
||||
assert.equal(currentSubText, rawText);
|
||||
|
||||
activeCues = cues;
|
||||
await runtime.primeAutoplaySubtitleFromParsedCues(mediaPath, cues);
|
||||
|
||||
assert.equal(currentSubText, correctedText);
|
||||
assert.deepEqual(emitted, [rawText, correctedText]);
|
||||
});
|
||||
|
||||
// Driven by the real processing controller rather than a stub: the failure this
|
||||
// covers is a disagreement between the priming path and the controller's own
|
||||
// staleness rules, which a hand-written stub cannot reproduce.
|
||||
|
||||
Reference in New Issue
Block a user