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:
@@ -25,7 +25,7 @@ function nearbyCanonicalCues(
|
||||
currentTimeSec: number,
|
||||
): SubtitleCue[] {
|
||||
return (cues ?? []).filter((cue) => {
|
||||
if (cue.source !== 'canonical-ass') {
|
||||
if (cue.source !== 'canonical-ass' && cue.source !== 'reconstructed-ass') {
|
||||
return false;
|
||||
}
|
||||
const span = animationSpan(cue);
|
||||
@@ -40,6 +40,21 @@ function compactWhitespace(text: string): string {
|
||||
return text.replace(/\s+/gu, '');
|
||||
}
|
||||
|
||||
// ASS layers can encode the same visible spacing with ordinary, hard, or
|
||||
// ideographic spaces. Matching and emission must use the same identity or each
|
||||
// layer reappears as a copy.
|
||||
function uniqueCueTexts(cues: readonly SubtitleCue[]): string[] {
|
||||
const texts: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
for (const cue of cues) {
|
||||
const compactText = compactWhitespace(cue.text);
|
||||
if (seen.has(compactText)) continue;
|
||||
seen.add(compactText);
|
||||
texts.push(cue.text);
|
||||
}
|
||||
return texts;
|
||||
}
|
||||
|
||||
function compactLineSegments(text: string): string[] {
|
||||
return text.split('\n').map(compactWhitespace).filter(Boolean);
|
||||
}
|
||||
@@ -83,14 +98,7 @@ function resolveActiveParsedPrimarySubtitle(options: {
|
||||
return null;
|
||||
}
|
||||
|
||||
const texts: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
for (const cue of selected) {
|
||||
if (!seen.has(cue.text)) {
|
||||
seen.add(cue.text);
|
||||
texts.push(cue.text);
|
||||
}
|
||||
}
|
||||
const texts = uniqueCueTexts(selected);
|
||||
return {
|
||||
text: texts.join('\n'),
|
||||
startTime: Math.min(...selected.map((cue) => cue.startTime)),
|
||||
@@ -159,14 +167,7 @@ export function resolveCanonicalPrimarySubtitle(options: {
|
||||
return null;
|
||||
}
|
||||
|
||||
const texts: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
for (const cue of selected) {
|
||||
if (!seen.has(cue.text)) {
|
||||
seen.add(cue.text);
|
||||
texts.push(cue.text);
|
||||
}
|
||||
}
|
||||
const texts = uniqueCueTexts(selected);
|
||||
return {
|
||||
text: texts.join('\n'),
|
||||
startTime: Math.min(...selected.map((cue) => cue.startTime)),
|
||||
|
||||
Reference in New Issue
Block a user