import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; function readMainSource(): string { return fs.readFileSync(path.join(process.cwd(), 'src/main.ts'), 'utf8'); } test('manual watched session action starts immersion tracker before marking watched', () => { const source = readMainSource(); const actionBlock = source.match( /markActiveVideoWatched:\s*async\s*\(\)\s*=>\s*\{(?[\s\S]*?)\}\s*,/, )?.groups?.body; assert.ok(actionBlock); assert.match(actionBlock, /ensureImmersionTrackerStarted\(\);/); assert.ok( actionBlock.indexOf('ensureImmersionTrackerStarted();') < actionBlock.indexOf('markActiveVideoWatched()'), ); }); test('media path changes clear rendered subtitle state without clearing same-youtube parsed cues', () => { const source = readMainSource(); const actionBlock = source.match( /updateCurrentMediaPath:\s*\(path\)\s*=>\s*\{(?[\s\S]*?)autoplayReadyGate\.invalidatePendingAutoplayReadyFallbacks\(\);/, )?.groups?.body; assert.ok(actionBlock); assert.match(actionBlock, /appState\.currentSubText = '';/); assert.match(actionBlock, /appState\.currentSubAssText = '';/); assert.match(actionBlock, /appState\.currentSubtitleData = null;/); assert.match(actionBlock, /isSameYoutubeMediaPath\(/); assert.match(actionBlock, /if \(!preserveParsedSubtitleCues\)/); assert.match(actionBlock, /appState\.activeParsedSubtitleCues = \[\];/); assert.match(actionBlock, /appState\.activeParsedSubtitleSource = null;/); assert.match(actionBlock, /appState\.activeParsedSubtitleMediaPath = null;/); assert.match(actionBlock, /lastObservedTimePos = 0;/); assert.match(actionBlock, /broadcastToOverlayWindows\('subtitle:set',/); assert.match(actionBlock, /subtitleWsService\.broadcast\(/); assert.match(actionBlock, /annotationSubtitleWsService\.broadcast\(/); assert.ok( actionBlock.indexOf('appState.currentSubtitleData = null;') < actionBlock.indexOf("broadcastToOverlayWindows('subtitle:set'"), ); }); test('same media path updates do not reset autoplay ready fallback state', () => { const source = readMainSource(); const actionBlock = source.match( /updateCurrentMediaPath:\s*\(path\)\s*=>\s*\{(?[\s\S]*?)\n restoreMpvSubVisibility:/, )?.groups?.body; assert.ok(actionBlock); assert.match( actionBlock, /annotationSubtitleWsService\.broadcast\(resetSubtitlePayload, frequencyOptions\);\s+autoplayReadyGate\.invalidatePendingAutoplayReadyFallbacks\(\);\s+\}\s+currentMediaTokenizationGate\.updateCurrentMediaPath\(path\);/, ); }); test('manual visible overlay toggles only release current-media autoplay when hiding', () => { const source = readMainSource(); const actionBlock = source.match( /function toggleVisibleOverlay\(\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(actionBlock); assert.match( actionBlock, /if \(!nextVisible\) \{\s+autoplayReadyGate\.markCurrentMediaAutoplayReady\(\);\s+cancelPendingLinuxMpvFullscreenOverlayRefreshBurst\(\);/, ); }); test('all visible overlay hide paths clear stale overlay input state', () => { const source = readMainSource(); const setVisibleBlock = source.match( /function setVisibleOverlayVisible\(visible: boolean\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; const toggleBlock = source.match( /function toggleVisibleOverlay\(\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; const setOverlayBlock = source.match( /function setOverlayVisible\(visible: boolean\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(setVisibleBlock); assert.ok(toggleBlock); assert.ok(setOverlayBlock); assert.match( setVisibleBlock, /if \(!visible\) \{\s+autoplayReadyGate\.markCurrentMediaAutoplayReady\(\);\s+cancelPendingLinuxMpvFullscreenOverlayRefreshBurst\(\);\s+resetVisibleOverlayInputState\(\);/, ); assert.match( toggleBlock, /if \(!nextVisible\) \{\s+autoplayReadyGate\.markCurrentMediaAutoplayReady\(\);\s+cancelPendingLinuxMpvFullscreenOverlayRefreshBurst\(\);\s+resetVisibleOverlayInputState\(\);/, ); assert.match( setOverlayBlock, /if \(!visible\) \{\s+resetVisibleOverlayInputState\(\);\s+autoplayReadyGate\.markCurrentMediaAutoplayReady\(\);\s+cancelPendingLinuxMpvFullscreenOverlayRefreshBurst\(\);/, ); }); test('subtitle sidebar media path tag is assigned after prefetch succeeds', () => { const source = readMainSource(); const actionBlock = source.match( /async function refreshSubtitleSidebarFromSource\([\s\S]*?\): Promise \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(actionBlock); assert.match( actionBlock, /const nextMediaPath = mediaPath\?\.trim\(\) \|\| getCurrentAutoplayMediaPath\(\);/, ); assert.ok( actionBlock.indexOf('subtitlePrefetchInitController.initSubtitlePrefetch') < actionBlock.indexOf('appState.activeParsedSubtitleMediaPath = nextMediaPath;'), ); }); test('update overlay notification action triggers install flow', () => { const source = readMainSource(); assert.match(source, /handleOverlayNotificationAction:\s*\(notificationId,\s*actionId\)\s*=>/); assert.match(source, /notificationId === UPDATE_AVAILABLE_NOTIFICATION_ID/); assert.match(source, /actionId === INSTALL_UPDATE_ACTION_ID/); assert.match(source, /installWhenAvailable:\s*true/); }); test('subtitle change re-prioritizes prefetch around live playback before tokenizing current line', () => { const source = readMainSource(); const actionBlock = source.match( /onSubtitleChange:\s*\(text\)\s*=>\s*\{(?[\s\S]*?)\n \},\n refreshDiscordPresence:/, )?.groups?.body; assert.ok(actionBlock); assert.match(actionBlock, /subtitlePrefetchService\?\.pause\(\);/); assert.match(actionBlock, /subtitlePrefetchService\?\.onSeek\(lastObservedTimePos\);/); assert.match(actionBlock, /subtitleProcessingController\.onSubtitleChange\(text\);/); assert.ok( actionBlock.indexOf('subtitlePrefetchService?.pause();') < actionBlock.indexOf('subtitlePrefetchService?.onSeek(lastObservedTimePos);'), ); assert.ok( actionBlock.indexOf('subtitlePrefetchService?.onSeek(lastObservedTimePos);') < actionBlock.indexOf('subtitleProcessingController.onSubtitleChange(text);'), ); }); test('autoplay subtitle prime emits cached annotations and avoids raw fallback overlay flashes', () => { const source = readMainSource(); const actionBlock = source.match( /function emitAutoplayPrimedSubtitle\([\s\S]*?\): boolean \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(actionBlock); assert.match( actionBlock, /const cachedPayload = subtitleProcessingController\.consumeCachedSubtitle\(text\);/, ); assert.match(actionBlock, /if \(cachedPayload\) \{/); assert.match(actionBlock, /emitSubtitlePayload\(cachedPayload\);/); assert.doesNotMatch(actionBlock, /withCurrentSubtitleTiming\(\{ text, tokens: null \}\)/); assert.doesNotMatch(actionBlock, /broadcastToOverlayWindows\('subtitle:set', rawPayload\)/); assert.match(actionBlock, /subtitleProcessingController\.onSubtitleChange\(text\);/); assert.ok( actionBlock.indexOf('consumeCachedSubtitle(text)') < actionBlock.indexOf('subtitleProcessingController.onSubtitleChange(text);'), ); }); test('startup autoplay release is tied to tokenization and visible overlay measurement readiness', () => { const source = readMainSource(); const gateBlock = source.match( /const autoplayReadyGate = createAutoplayReadyGate\(\{(?[\s\S]*?)\n\}\);/, )?.groups?.body; const measurementBlock = source.match( /reportOverlayContentBounds:\s*\(payload: unknown\)\s*=>\s*\{(?[\s\S]*?)\n \},/, )?.groups?.body; assert.ok(gateBlock); assert.match(gateBlock, /isSignalTargetReady:\s*\(signal\) =>/); assert.match(gateBlock, /isTokenizationWarmupReady\(\)/); assert.match(gateBlock, /isVisibleOverlayAutoplayTargetReady\(/); assert.match(gateBlock, /getLatestVisibleMeasurement:/); assert.ok(measurementBlock); assert.match(measurementBlock, /overlayContentMeasurementStore\.report\(payload\)/); assert.match(measurementBlock, /autoplayReadyGate\.flushPendingAutoplayReadySignal\(\)/); }); test('accepted visible overlay measurement immediately refreshes Linux pointer interaction', () => { const source = readMainSource(); const measurementBlock = source.match( /reportOverlayContentBounds:\s*\(payload: unknown\)\s*=>\s*\{(?[\s\S]*?)\n \},/, )?.groups?.body; assert.ok(measurementBlock); assert.match(measurementBlock, /overlayContentMeasurementStore\.report\(payload\)/); assert.match(measurementBlock, /tickLinuxOverlayPointerInteractionNow\(\)/); assert.ok( measurementBlock.indexOf('overlayContentMeasurementStore.report(payload)') < measurementBlock.indexOf('tickLinuxOverlayPointerInteractionNow();'), ); }); test('subtitle sidebar open state is restored for replacement visible overlay windows', () => { const source = readMainSource(); const openedBlock = source.match( /onOverlayModalOpened:\s*\(modal,\s*senderWindow\)\s*=>\s*\{(?[\s\S]*?)\n \},/, )?.groups?.body; const closedBlock = source.match( /onOverlayModalClosed:\s*\(modal,\s*senderWindow\)\s*=>\s*\{(?[\s\S]*?)\n \},/, )?.groups?.body; const depsBlock = source.match(/getSubtitleSidebarOpen:\s*\(\)\s*=>\s*(?[^\n,]+)/)?.groups ?.body; assert.ok(openedBlock); assert.ok(closedBlock); assert.ok(depsBlock); assert.match(openedBlock, /if \(modal === 'subtitle-sidebar'/); assert.match(openedBlock, /subtitleSidebarRequestedOpen = true;/); assert.match(closedBlock, /if \(modal === 'subtitle-sidebar'/); assert.match(closedBlock, /subtitleSidebarRequestedOpen = false;/); assert.match(depsBlock, /subtitleSidebarRequestedOpen/); }); test('warm tokenization release can signal readiness before the first subtitle appears', () => { const source = readMainSource(); const warmReleaseBlock = source.match( /signalAutoplayReadyFromWarmTokenization = createAutoplayTokenizationWarmRelease\(\{(?[\s\S]*?)\n\}\);/, )?.groups?.body; const signalBlock = source.match( /function signalCurrentSubtitleAutoplayReady\(\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; const currentPayloadBlock = source.match( /function getCurrentAutoplaySubtitlePayload\(\): SubtitleData \| null \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(warmReleaseBlock); assert.match( warmReleaseBlock, /signalAutoplayReady: \(\) => signalCurrentSubtitleAutoplayReady\(\)/, ); assert.ok(signalBlock); assert.match(signalBlock, /const payload = getCurrentAutoplaySubtitlePayload\(\);/); assert.match(signalBlock, /if \(payload\) \{/); assert.match(signalBlock, /if \(!appState\.currentSubText\.trim\(\)\) \{/); assert.match(signalBlock, /text: '__warm__'/); assert.ok(currentPayloadBlock); assert.match(currentPayloadBlock, /appState\.currentSubtitleData/); assert.match(currentPayloadBlock, /payload\.text !== appState\.currentSubText/); }); test('stats server Yomitan note creation honors configured Anki server override policy', () => { const source = readMainSource(); const startStatsServerBlock = source.match( /statsServer = startStatsServer\(\{(?[\s\S]*?)\n \}\);/, )?.groups?.body; const addYomitanNoteBlock = startStatsServerBlock?.match( /addYomitanNote:\s*async\s*\(word: string\)\s*=>\s*\{(?[\s\S]*?)\n \},/, )?.groups?.body; assert.ok(addYomitanNoteBlock); assert.match(addYomitanNoteBlock, /const ankiConnectConfig = getResolvedConfig\(\)\.ankiConnect;/); assert.match(addYomitanNoteBlock, /shouldForceOverrideYomitanAnkiServer\(ankiConnectConfig\)/); assert.doesNotMatch(addYomitanNoteBlock, /forceOverride:\s*true/); }); test('Linux visible overlay recreation clears stale input state before creating replacement window', () => { const source = readMainSource(); const actionBlock = source.match( /function createLinuxVisibleOverlayWindowForCurrentMode\([\s\S]*?\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; const resetBlock = source.match( /function resetVisibleOverlayInputState\(\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(actionBlock); assert.ok(resetBlock); assert.match(actionBlock, /resetVisibleOverlayInputState\(\);/); assert.match(resetBlock, /overlayContentMeasurementStore\.clear\('visible'\);/); assert.ok( actionBlock.indexOf('resetVisibleOverlayInputState();') < actionBlock.indexOf('createMainWindow();'), ); }); test('Linux visible overlay recreation avoids display fallback before tracked geometry exists', () => { const source = readMainSource(); const actionBlock = source.match( /function createLinuxVisibleOverlayWindowForCurrentMode\([\s\S]*?\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(actionBlock); assert.match(actionBlock, /const trackedGeometry = getCurrentTrackedOverlayGeometry\(\);/); assert.match(actionBlock, /if \(trackedGeometry\) \{/); assert.match(actionBlock, /overlayManager\.setOverlayWindowBounds\(trackedGeometry\);/); assert.doesNotMatch(actionBlock, /setOverlayWindowBounds\(getCurrentOverlayGeometry\(\)\)/); }); test('known-word updates invalidate prefetched tokenizations before refreshing current subtitle', () => { const source = readMainSource(); const actionBlock = source.match( /const refreshCurrentSubtitleAfterKnownWordUpdate = \(\): void => \{(?[\s\S]*?)\n\};/, )?.groups?.body; assert.ok(actionBlock); assert.match(actionBlock, /subtitleProcessingController\.invalidateTokenizationCache\(\);/); assert.match(actionBlock, /subtitlePrefetchService\?\.onSeek\(lastObservedTimePos\);/); assert.match( actionBlock, /subtitleProcessingController\.refreshCurrentSubtitle\(appState\.currentSubText\);/, ); assert.ok( actionBlock.indexOf('subtitleProcessingController.invalidateTokenizationCache();') < actionBlock.indexOf( 'subtitleProcessingController.refreshCurrentSubtitle(appState.currentSubText);', ), ); }); test('manual visible overlay changes notify mpv plugin visibility state', () => { const source = readMainSource(); const setBlock = source.match( /function setVisibleOverlayVisible\(visible: boolean\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; const toggleBlock = source.match( /function toggleVisibleOverlay\(\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(setBlock); assert.ok(toggleBlock); assert.match(setBlock, /notifyMpvPluginVisibleOverlayVisibility\(visible\);/); assert.match(toggleBlock, /const nextVisible = !overlayManager\.getVisibleOverlayVisible\(\);/); assert.match(toggleBlock, /notifyMpvPluginVisibleOverlayVisibility\(nextVisible\);/); }); test('manual visible overlay show primes current subtitle from mpv before relying on live events', () => { const source = readMainSource(); const setBlock = source.match( /function setVisibleOverlayVisible\(visible: boolean\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; const toggleBlock = source.match( /function toggleVisibleOverlay\(\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(setBlock); assert.ok(toggleBlock); assert.match( setBlock, /if \(visible\) \{\s+restoreVisibleOverlayWindowShapeForShow\(\);\s+void ensureOverlayMpvSubtitlesHidden\(\);\s+void primeCurrentSubtitleForVisibleOverlay\(\);/, ); assert.match( toggleBlock, /else \{\s+restoreVisibleOverlayWindowShapeForShow\(\);\s+void ensureOverlayMpvSubtitlesHidden\(\);\s+void primeCurrentSubtitleForVisibleOverlay\(\);/, ); }); test('Linux visible overlay show/reset does not leave an empty X11 window shape', () => { const source = readMainSource(); const resetBlock = source.match( /function resetVisibleOverlayInputState\(\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; const setBlock = source.match( /function setVisibleOverlayVisible\(visible: boolean\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(resetBlock); assert.ok(setBlock); assert.match(resetBlock, /restoreLinuxOverlayWindowShape\(mainWindow\);/); assert.doesNotMatch(source, /setShape\?\.\(\[\]\)|setShape\(\[\]\)/); assert.match( setBlock, /if \(visible\) \{\s+restoreVisibleOverlayWindowShapeForShow\(\);\s+void ensureOverlayMpvSubtitlesHidden\(\);/, ); }); test('Linux visible overlay bounds refresh restores X11 shape after applying mpv geometry', () => { const source = readMainSource(); const afterBoundsBlock = source.match( /afterSetOverlayWindowBounds:\s*\(\) => \{(?[\s\S]*?)\n \},/, )?.groups?.body; assert.ok(afterBoundsBlock); assert.match(afterBoundsBlock, /restoreLinuxOverlayWindowShape\(mainWindow\);/); assert.ok( afterBoundsBlock.indexOf('restoreLinuxOverlayWindowShape(mainWindow);') < afterBoundsBlock.indexOf('ensureOverlayWindowLevel(mainWindow);'), ); }); test('main process uses one shared mpv plugin runtime config helper', () => { const source = readMainSource(); assert.match(source, /function getMpvPluginRuntimeConfig\(\)/); assert.equal((source.match(/socketPath: appState\.mpvSocketPath/g) ?? []).length, 1); assert.equal( (source.match(/binaryPath: getResolvedConfig\(\)\.mpv\.subminerBinaryPath/g) ?? []).length, 0, ); }); test('subtitle sidebar snapshot prefers cached YouTube parsed cues before active-source parsing', () => { const source = readMainSource(); const snapshotBlock = source.match( /getSubtitleSidebarSnapshot:\s*async\s*\(\)\s*=>\s*\{(?[\s\S]*?const resolvedSource = await resolveActiveSubtitleSidebarSourceHandler)/, )?.groups?.body; assert.ok(snapshotBlock); assert.match(snapshotBlock, /shouldUseCachedYoutubeParsedCues\(/); assert.match(snapshotBlock, /cachedMediaPath:\s*appState\.activeParsedSubtitleMediaPath/); assert.match(snapshotBlock, /cachedCueCount:\s*appState\.activeParsedSubtitleCues\.length/); assert.ok( snapshotBlock.indexOf('shouldUseCachedYoutubeParsedCues(') < snapshotBlock.indexOf('resolveActiveSubtitleSidebarSourceHandler'), ); });