mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-01 05:40:50 -07:00
perf(subtitle-prefetch): sweep overlap spans instead of rescanning cues
- Track active cues with a single sorted start/end sweep across boundaries - Join simultaneous cues in cue-list order to match mpv - Skip empty or inverted cues - Add test for multi-cue overlap spans with unsorted cue input
This commit is contained in:
@@ -22,3 +22,17 @@ test('back-to-back cues yield no overlap lines', () => {
|
|||||||
|
|
||||||
assert.deepEqual(buildOverlapPrefetchCues(cues), []);
|
assert.deepEqual(buildOverlapPrefetchCues(cues), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('each overlap span joins only the cues active across it, in cue-list order', () => {
|
||||||
|
const cues: SubtitleCue[] = [
|
||||||
|
{ startTime: 3, endTime: 8, text: 'C' },
|
||||||
|
{ startTime: 0, endTime: 6, text: 'A' },
|
||||||
|
{ startTime: 2, endTime: 4, text: 'B' },
|
||||||
|
];
|
||||||
|
|
||||||
|
assert.deepEqual(buildOverlapPrefetchCues(cues), [
|
||||||
|
{ startTime: 2, endTime: 3, text: 'A\n\nB' },
|
||||||
|
{ startTime: 3, endTime: 4, text: 'C\n\nA\n\nB' },
|
||||||
|
{ startTime: 4, endTime: 6, text: 'C\n\nA' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|||||||
@@ -13,20 +13,43 @@ export function buildOverlapPrefetchCues(cues: readonly SubtitleCue[]): Subtitle
|
|||||||
const boundaries = [...new Set(cues.flatMap((cue) => [cue.startTime, cue.endTime]))].sort(
|
const boundaries = [...new Set(cues.flatMap((cue) => [cue.startTime, cue.endTime]))].sort(
|
||||||
(a, b) => a - b,
|
(a, b) => a - b,
|
||||||
);
|
);
|
||||||
|
const indices = cues.map((_, index) => index);
|
||||||
|
const byStart = [...indices].sort((a, b) => cues[a]!.startTime - cues[b]!.startTime);
|
||||||
|
const byEnd = [...indices].sort((a, b) => cues[a]!.endTime - cues[b]!.endTime);
|
||||||
const singleTexts = new Set(cues.map((cue) => cue.text));
|
const singleTexts = new Set(cues.map((cue) => cue.text));
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
const overlapCues: SubtitleCue[] = [];
|
const overlapCues: SubtitleCue[] = [];
|
||||||
|
|
||||||
|
// Sweep the boundaries once, keeping the cues active over [startTime, endTime). Every
|
||||||
|
// cue edge is a boundary, so a cue is active for a whole interval or not at all.
|
||||||
|
const active = new Set<number>();
|
||||||
|
let nextStart = 0;
|
||||||
|
let nextEnd = 0;
|
||||||
for (let i = 0; i + 1 < boundaries.length; i += 1) {
|
for (let i = 0; i + 1 < boundaries.length; i += 1) {
|
||||||
const startTime = boundaries[i]!;
|
const startTime = boundaries[i]!;
|
||||||
const endTime = boundaries[i + 1]!;
|
const endTime = boundaries[i + 1]!;
|
||||||
const midpoint = (startTime + endTime) / 2;
|
for (; nextEnd < byEnd.length && cues[byEnd[nextEnd]!]!.endTime <= startTime; nextEnd += 1) {
|
||||||
const active = cues.filter((cue) => cue.startTime <= midpoint && cue.endTime > midpoint);
|
active.delete(byEnd[nextEnd]!);
|
||||||
if (active.length < 2) continue;
|
}
|
||||||
|
for (
|
||||||
|
;
|
||||||
|
nextStart < byStart.length && cues[byStart[nextStart]!]!.startTime <= startTime;
|
||||||
|
nextStart += 1
|
||||||
|
) {
|
||||||
|
const index = byStart[nextStart]!;
|
||||||
|
// Empty or inverted cues are never on screen.
|
||||||
|
if (cues[index]!.endTime > startTime) active.add(index);
|
||||||
|
}
|
||||||
|
if (active.size < 2) continue;
|
||||||
|
|
||||||
|
// mpv joins simultaneous cues in cue-list order.
|
||||||
|
const liveText = [...active]
|
||||||
|
.sort((a, b) => a - b)
|
||||||
|
.map((index) => cues[index]!.text)
|
||||||
|
.join('\n');
|
||||||
const text = resolvePrimarySubtitleText({
|
const text = resolvePrimarySubtitleText({
|
||||||
liveText: active.map((cue) => cue.text).join('\n'),
|
liveText,
|
||||||
currentTimeSec: midpoint,
|
currentTimeSec: (startTime + endTime) / 2,
|
||||||
cues,
|
cues,
|
||||||
});
|
});
|
||||||
if (!text.trim() || singleTexts.has(text) || seen.has(text)) continue;
|
if (!text.trim() || singleTexts.has(text) || seen.has(text)) continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user