diff --git a/src/core/services/mpv-protocol.test.ts b/src/core/services/mpv-protocol.test.ts index 9878e383..80838333 100644 --- a/src/core/services/mpv-protocol.test.ts +++ b/src/core/services/mpv-protocol.test.ts @@ -181,6 +181,18 @@ test('dispatchMpvProtocolMessage emits subtitle track changes', async () => { ]); }); +test('dispatchMpvProtocolMessage rejects decimal subtitle track IDs', async () => { + const { deps, state } = createDeps(); + + await dispatchMpvProtocolMessage({ event: 'property-change', name: 'sid', data: '4.5' }, deps); + await dispatchMpvProtocolMessage( + { event: 'property-change', name: 'secondary-sid', data: '4.5' }, + deps, + ); + + assert.deepEqual(state.events, [{ sid: null }, { sid: null }]); +}); + test('dispatchMpvProtocolMessage enforces sub-visibility hidden when overlay suppression is enabled', async () => { const { deps, state } = createDeps({ isVisibleOverlayVisible: () => true, diff --git a/src/core/services/mpv-protocol.ts b/src/core/services/mpv-protocol.ts index 9077913b..c892a577 100644 --- a/src/core/services/mpv-protocol.ts +++ b/src/core/services/mpv-protocol.ts @@ -283,7 +283,7 @@ export async function dispatchMpvProtocolMessage( : typeof msg.data === 'string' ? Number(msg.data) : null; - deps.emitSubtitleTrackChange({ sid: sid !== null && Number.isFinite(sid) ? sid : null }); + deps.emitSubtitleTrackChange({ sid: sid !== null && Number.isInteger(sid) ? sid : null }); } else if (msg.name === 'secondary-sid') { const sid = typeof msg.data === 'number' @@ -292,7 +292,7 @@ export async function dispatchMpvProtocolMessage( ? Number(msg.data) : null; deps.emitSecondarySubtitleTrackChange({ - sid: sid !== null && Number.isFinite(sid) ? sid : null, + sid: sid !== null && Number.isInteger(sid) ? sid : null, }); } else if (msg.name === 'secondary-sub-delay') { const delay = diff --git a/src/renderer/subtitle-render.test.ts b/src/renderer/subtitle-render.test.ts index 8d60a21a..4f6e978a 100644 --- a/src/renderer/subtitle-render.test.ts +++ b/src/renderer/subtitle-render.test.ts @@ -1434,10 +1434,10 @@ test('prepareSecondarySubtitleLines collapses karaoke syllable spam into one ded assert.deepEqual(prepareSecondarySubtitleLines(karaoke), ['ya This no ma ups']); }); -test('prepareSecondarySubtitleLines collapses a short stack of repeated ASS layers', () => { - const layeredSign = ['Your', 'Your', 'Your', 'Your', 'mosaic'].join('\\N'); +test('prepareSecondarySubtitleLines preserves repeated short dialogue without layer metadata', () => { + const dialogue = ['Wait', 'Wait', 'Wait']; - assert.deepEqual(prepareSecondarySubtitleLines(layeredSign), ['Your mosaic']); + assert.deepEqual(prepareSecondarySubtitleLines(dialogue.join('\\N')), dialogue); }); test('prepareSecondarySubtitleLines preserves short simultaneous dialogue without repeats', () => { diff --git a/src/renderer/subtitle-render.ts b/src/renderer/subtitle-render.ts index 95d70d2f..8b63c004 100644 --- a/src/renderer/subtitle-render.ts +++ b/src/renderer/subtitle-render.ts @@ -657,24 +657,12 @@ function renderPlainTextPreserveLineBreaks(root: ParentNode, text: string): void // hover-pause band into a full-screen trap. const KARAOKE_MIN_LINE_COUNT = 8; const KARAOKE_MAX_MEDIAN_LINE_LENGTH = 4; -const LAYERED_REPEAT_MIN_LINE_COUNT = 4; -const LAYERED_REPEAT_MIN_COUNT = 3; function isKaraokeLikeLineSet(lines: string[]): boolean { + if (lines.length < KARAOKE_MIN_LINE_COUNT) return false; const lengths = lines.map((line) => line.length).sort((a, b) => a - b); const median = lengths[Math.floor(lengths.length / 2)] ?? 0; - if (median > KARAOKE_MAX_MEDIAN_LINE_LENGTH) return false; - - if (lines.length >= KARAOKE_MIN_LINE_COUNT) return true; - if (lines.length < LAYERED_REPEAT_MIN_LINE_COUNT) return false; - - const repeatCounts = new Map(); - for (const line of lines) { - const count = (repeatCounts.get(line) ?? 0) + 1; - if (count >= LAYERED_REPEAT_MIN_COUNT) return true; - repeatCounts.set(line, count); - } - return false; + return median <= KARAOKE_MAX_MEDIAN_LINE_LENGTH; } export function prepareSecondarySubtitleLines(text: string): string[] {