Fix startup TDZ and suppress subtitles during settings modals

This commit is contained in:
2026-02-10 01:58:44 -08:00
parent d6df86c6bb
commit a1ec32a6ba
3 changed files with 137 additions and 145 deletions

View File

@@ -47,7 +47,7 @@ import * as fs from "fs";
import * as crypto from "crypto"; import * as crypto from "crypto";
import { MecabTokenizer } from "./mecab-tokenizer"; import { MecabTokenizer } from "./mecab-tokenizer";
import { BaseWindowTracker } from "./window-trackers"; import { BaseWindowTracker } from "./window-trackers";
import { import type {
JimakuApiResponse, JimakuApiResponse,
JimakuDownloadResult, JimakuDownloadResult,
JimakuMediaInfo, JimakuMediaInfo,
@@ -78,169 +78,126 @@ import {
getSubsyncConfig, getSubsyncConfig,
} from "./subsync/utils"; } from "./subsync/utils";
import { import {
CliArgs,
CliCommandSource,
hasExplicitCommand, hasExplicitCommand,
parseArgs, parseArgs,
shouldStartApp, shouldStartApp,
} from "./cli/args"; } from "./cli/args";
import type { CliArgs, CliCommandSource } from "./cli/args";
import { printHelp } from "./cli/help"; import { printHelp } from "./cli/help";
import { generateDefaultConfigFile } from "./core/utils/config-gen";
import { import {
asBoolean,
asFiniteNumber,
asString,
enforceUnsupportedWaylandMode, enforceUnsupportedWaylandMode,
forceX11Backend, forceX11Backend,
} from "./core/utils/electron-backend"; generateDefaultConfigFile,
import { asBoolean, asFiniteNumber, asString } from "./core/utils/coerce"; resolveConfiguredShortcuts,
import { resolveKeybindings } from "./core/utils/keybindings"; resolveKeybindings,
import { resolveConfiguredShortcuts } from "./core/utils/shortcut-config"; showDesktopNotification,
import { TexthookerService } from "./core/services/texthooker-service"; } from "./core/utils";
import { import {
hasMpvWebsocketPlugin,
SubtitleWebSocketService,
} from "./core/services/subtitle-ws-service";
import { registerGlobalShortcutsService } from "./core/services/shortcut-service";
import { registerIpcHandlersService } from "./core/services/ipc-service";
import {
isGlobalShortcutRegisteredSafe,
shortcutMatchesInputForLocalFallback,
} from "./core/services/shortcut-fallback-service";
import {
registerOverlayShortcutsService,
} from "./core/services/overlay-shortcut-service";
import { createOverlayShortcutRuntimeHandlers } from "./core/services/overlay-shortcut-runtime-service";
import { handleCliCommandService } from "./core/services/cli-command-service";
import { cycleSecondarySubModeService } from "./core/services/secondary-subtitle-service";
import {
refreshOverlayShortcutsRuntimeService,
syncOverlayShortcutsRuntimeService,
unregisterOverlayShortcutsRuntimeService,
} from "./core/services/overlay-shortcut-lifecycle-service";
import {
copyCurrentSubtitleService,
handleMineSentenceDigitService,
handleMultiCopyDigitService,
markLastCardAsAudioCardService,
mineSentenceCardService,
triggerFieldGroupingService,
updateLastCardFromClipboardService,
} from "./core/services/mining-runtime-service";
import { startAppLifecycleService } from "./core/services/app-lifecycle-service";
import {
playNextSubtitleRuntimeService,
replayCurrentSubtitleRuntimeService,
sendMpvCommandRuntimeService,
setMpvSubVisibilityRuntimeService,
showMpvOsdRuntimeService,
} from "./core/services/mpv-runtime-service";
import {
getInitialInvisibleOverlayVisibilityService,
isAutoUpdateEnabledRuntimeService,
shouldAutoInitializeOverlayRuntimeFromConfigService,
shouldBindVisibleOverlayToMpvSubVisibilityService,
} from "./core/services/runtime-config-service";
import { showDesktopNotification } from "./core/utils/notification";
import { openYomitanSettingsWindow } from "./core/services/yomitan-settings-service";
import { tokenizeSubtitleService } from "./core/services/tokenizer-service";
import { loadYomitanExtensionService } from "./core/services/yomitan-extension-loader-service";
import {
getJimakuLanguagePreferenceService,
getJimakuMaxEntryResultsService,
jimakuFetchJsonService,
resolveJimakuApiKeyService,
} from "./core/services/jimaku-runtime-service";
import {
loadSubtitlePositionService,
saveSubtitlePositionService,
updateCurrentMediaPathService,
} from "./core/services/subtitle-position-service";
import {
createOverlayWindowService,
enforceOverlayLayerOrderService,
ensureOverlayWindowLevelService,
updateOverlayBoundsService,
} from "./core/services/overlay-window-service";
import { initializeOverlayRuntimeService } from "./core/services/overlay-runtime-init-service";
import {
syncInvisibleOverlayMousePassthroughService,
} from "./core/services/overlay-visibility-runtime-service";
import {
setInvisibleOverlayVisibleRuntimeFacadeService,
setVisibleOverlayVisibleRuntimeFacadeService,
toggleInvisibleOverlayRuntimeFacadeService,
toggleVisibleOverlayRuntimeFacadeService,
} from "./core/services/overlay-visibility-facade-service";
import {
MpvIpcClient,
MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY, MPV_REQUEST_ID_SECONDARY_SUB_VISIBILITY,
} from "./core/services/mpv-service"; MpvIpcClient,
import { applyMpvSubtitleRenderMetricsPatchService } from "./core/services/mpv-render-metrics-service"; SubtitleWebSocketService,
import { TexthookerService,
handleMpvCommandFromIpcService, applyMpvSubtitleRenderMetricsPatchService,
} from "./core/services/ipc-command-service";
import {
handleOverlayModalClosedService,
} from "./core/services/overlay-modal-restore-service";
import {
broadcastRuntimeOptionsChangedRuntimeService, broadcastRuntimeOptionsChangedRuntimeService,
broadcastToOverlayWindowsRuntimeService, broadcastToOverlayWindowsRuntimeService,
getOverlayWindowsRuntimeService, copyCurrentSubtitleService,
setOverlayDebugVisualizationEnabledRuntimeService, createAnkiJimakuIpcDepsRuntimeService,
} from "./core/services/overlay-broadcast-runtime-service"; createAppLifecycleDepsRuntimeService,
import { createMpvIpcClientDepsRuntimeService } from "./core/services/mpv-client-deps-runtime-service"; createAppLoggingRuntimeService,
import { createAppLifecycleDepsRuntimeService } from "./core/services/app-lifecycle-deps-runtime-service"; createCliCommandDepsRuntimeService,
import { createCliCommandDepsRuntimeService } from "./core/services/cli-command-deps-runtime-service";
import { createIpcDepsRuntimeService } from "./core/services/ipc-deps-runtime-service";
import { createAnkiJimakuIpcDepsRuntimeService } from "./core/services/anki-jimaku-ipc-deps-runtime-service";
import { createFieldGroupingOverlayRuntimeService } from "./core/services/field-grouping-overlay-runtime-service";
import { createSubsyncRuntimeDepsService } from "./core/services/subsync-deps-runtime-service";
import { createNumericShortcutRuntimeService } from "./core/services/numeric-shortcut-runtime-service";
import { createOverlayVisibilityFacadeDepsRuntimeService } from "./core/services/overlay-visibility-facade-deps-runtime-service";
import { createMpvCommandIpcDepsRuntimeService } from "./core/services/mpv-command-ipc-deps-runtime-service";
import { createRuntimeOptionsIpcDepsRuntimeService } from "./core/services/runtime-options-ipc-deps-runtime-service";
import { createTokenizerDepsRuntimeService } from "./core/services/tokenizer-deps-runtime-service";
import {
createInitializeOverlayRuntimeDepsService,
createInvisibleOverlayVisibilityDepsRuntimeService,
createOverlayWindowRuntimeDepsService,
createVisibleOverlayVisibilityDepsRuntimeService,
} from "./core/services/overlay-runtime-deps-service";
import {
createOverlayShortcutLifecycleDepsRuntimeService,
createOverlayShortcutRuntimeDepsService,
} from "./core/services/overlay-shortcut-runtime-deps-service";
import {
createCopyCurrentSubtitleDepsRuntimeService, createCopyCurrentSubtitleDepsRuntimeService,
createFieldGroupingOverlayRuntimeService,
createGlobalShortcutRegistrationDepsRuntimeService,
createHandleMineSentenceDigitDepsRuntimeService, createHandleMineSentenceDigitDepsRuntimeService,
createHandleMultiCopyDigitDepsRuntimeService, createHandleMultiCopyDigitDepsRuntimeService,
createInitializeOverlayRuntimeDepsService,
createInvisibleOverlayVisibilityDepsRuntimeService,
createIpcDepsRuntimeService,
createMarkLastCardAsAudioCardDepsRuntimeService, createMarkLastCardAsAudioCardDepsRuntimeService,
createMecabTokenizerAndCheckRuntimeService,
createMineSentenceCardDepsRuntimeService, createMineSentenceCardDepsRuntimeService,
createMpvCommandIpcDepsRuntimeService,
createMpvIpcClientDepsRuntimeService,
createNumericShortcutRuntimeService,
createOverlayShortcutLifecycleDepsRuntimeService,
createOverlayShortcutRuntimeDepsService,
createOverlayShortcutRuntimeHandlers,
createOverlayVisibilityFacadeDepsRuntimeService,
createOverlayWindowRuntimeDepsService,
createOverlayWindowService,
createRuntimeOptionsIpcDepsRuntimeService,
createRuntimeOptionsManagerRuntimeService,
createSecondarySubtitleCycleDepsRuntimeService,
createStartupLifecycleHooksRuntimeService,
createSubsyncRuntimeDepsService,
createSubtitleTimingTrackerRuntimeService,
createTokenizerDepsRuntimeService,
createTriggerFieldGroupingDepsRuntimeService, createTriggerFieldGroupingDepsRuntimeService,
createUpdateLastCardFromClipboardDepsRuntimeService, createUpdateLastCardFromClipboardDepsRuntimeService,
} from "./core/services/mining-runtime-deps-service"; createVisibleOverlayVisibilityDepsRuntimeService,
import {
createGlobalShortcutRegistrationDepsRuntimeService,
createSecondarySubtitleCycleDepsRuntimeService,
createYomitanSettingsWindowDepsRuntimeService, createYomitanSettingsWindowDepsRuntimeService,
cycleSecondarySubModeService,
enforceOverlayLayerOrderService,
ensureOverlayWindowLevelService,
getInitialInvisibleOverlayVisibilityService,
getJimakuLanguagePreferenceService,
getJimakuMaxEntryResultsService,
getOverlayWindowsRuntimeService,
handleCliCommandService,
handleMineSentenceDigitService,
handleMpvCommandFromIpcService,
handleMultiCopyDigitService,
handleOverlayModalClosedService,
hasMpvWebsocketPlugin,
initializeOverlayRuntimeService,
isAutoUpdateEnabledRuntimeService,
isGlobalShortcutRegisteredSafe,
jimakuFetchJsonService,
loadSubtitlePositionService,
loadYomitanExtensionService,
markLastCardAsAudioCardService,
mineSentenceCardService,
openYomitanSettingsWindow,
playNextSubtitleRuntimeService,
refreshOverlayShortcutsRuntimeService,
registerAnkiJimakuIpcRuntimeService,
registerGlobalShortcutsService,
registerIpcHandlersService,
registerOverlayShortcutsService,
replayCurrentSubtitleRuntimeService,
resolveJimakuApiKeyService,
runGenerateConfigFlowRuntimeService,
runOverlayShortcutLocalFallbackRuntimeService, runOverlayShortcutLocalFallbackRuntimeService,
} from "./core/services/shortcut-ui-runtime-deps-service"; runStartupBootstrapRuntimeService,
import { createStartupLifecycleHooksRuntimeService } from "./core/services/startup-lifecycle-hooks-runtime-service";
import { createRuntimeOptionsManagerRuntimeService } from "./core/services/runtime-options-manager-runtime-service";
import { createAppLoggingRuntimeService } from "./core/services/app-logging-runtime-service";
import {
createMecabTokenizerAndCheckRuntimeService,
createSubtitleTimingTrackerRuntimeService,
} from "./core/services/startup-resource-runtime-service";
import { runGenerateConfigFlowRuntimeService } from "./core/services/config-generation-runtime-service";
import { runStartupBootstrapRuntimeService } from "./core/services/startup-bootstrap-runtime-service";
import {
runSubsyncManualFromIpcRuntimeService, runSubsyncManualFromIpcRuntimeService,
saveSubtitlePositionService,
sendMpvCommandRuntimeService,
setInvisibleOverlayVisibleRuntimeFacadeService,
setMpvSubVisibilityRuntimeService,
setOverlayDebugVisualizationEnabledRuntimeService,
setVisibleOverlayVisibleRuntimeFacadeService,
shouldAutoInitializeOverlayRuntimeFromConfigService,
shouldBindVisibleOverlayToMpvSubVisibilityService,
shortcutMatchesInputForLocalFallback,
showMpvOsdRuntimeService,
startAppLifecycleService,
syncInvisibleOverlayMousePassthroughService,
syncOverlayShortcutsRuntimeService,
tokenizeSubtitleService,
toggleInvisibleOverlayRuntimeFacadeService,
toggleVisibleOverlayRuntimeFacadeService,
triggerFieldGroupingService,
triggerSubsyncFromConfigRuntimeService, triggerSubsyncFromConfigRuntimeService,
} from "./core/services/subsync-runtime-service"; unregisterOverlayShortcutsRuntimeService,
import { updateCurrentMediaPathService,
updateInvisibleOverlayVisibilityService, updateInvisibleOverlayVisibilityService,
updateLastCardFromClipboardService,
updateOverlayBoundsService,
updateVisibleOverlayVisibilityService, updateVisibleOverlayVisibilityService,
} from "./core/services/overlay-visibility-service"; } from "./core/services";
import { registerAnkiJimakuIpcRuntimeService } from "./core/services/anki-jimaku-runtime-service";
import { import {
ConfigService, ConfigService,
DEFAULT_CONFIG, DEFAULT_CONFIG,
@@ -474,6 +431,12 @@ function updateCurrentMediaPath(mediaPath: unknown): void {
} }
let subsyncInProgress = false; let subsyncInProgress = false;
let initialArgs: CliArgs;
let mpvSocketPath = getDefaultSocketPath();
let texthookerPort = DEFAULT_TEXTHOOKER_PORT;
let backendOverride: string | null = null;
let autoStartOverlay = false;
let texthookerOnlyMode = false;
const startupState = runStartupBootstrapRuntimeService({ const startupState = runStartupBootstrapRuntimeService({
argv: process.argv, argv: process.argv,
@@ -684,12 +647,12 @@ const startupState = runStartupBootstrapRuntimeService({
}, },
}); });
const initialArgs = startupState.initialArgs; initialArgs = startupState.initialArgs;
let mpvSocketPath = startupState.mpvSocketPath; mpvSocketPath = startupState.mpvSocketPath;
let texthookerPort = startupState.texthookerPort; texthookerPort = startupState.texthookerPort;
const backendOverride = startupState.backendOverride; backendOverride = startupState.backendOverride;
const autoStartOverlay = startupState.autoStartOverlay; autoStartOverlay = startupState.autoStartOverlay;
const texthookerOnlyMode = startupState.texthookerOnlyMode; texthookerOnlyMode = startupState.texthookerOnlyMode;
function handleCliCommand( function handleCliCommand(
args: CliArgs, args: CliArgs,

View File

@@ -405,6 +405,18 @@ let mpvSubtitleRenderMetrics: MpvSubtitleRenderMetrics = {
}; };
let currentSubtitleAss = ""; let currentSubtitleAss = "";
function isAnySettingsModalOpen(): boolean {
return runtimeOptionsModalOpen || subsyncModalOpen || kikuModalOpen;
}
function syncSettingsModalSubtitleSuppression(): void {
const suppressSubtitles = isAnySettingsModalOpen();
document.body.classList.toggle("settings-modal-open", suppressSubtitles);
if (suppressSubtitles) {
isOverSubtitle = false;
}
}
function normalizeSubtitle(text: string, trim = true): string { function normalizeSubtitle(text: string, trim = true): string {
if (!text) return ""; if (!text) return "";
@@ -1140,6 +1152,7 @@ function updateRuntimeOptions(options: RuntimeOptionState[]): void {
function closeRuntimeOptionsModal(): void { function closeRuntimeOptionsModal(): void {
if (!runtimeOptionsModalOpen) return; if (!runtimeOptionsModalOpen) return;
runtimeOptionsModalOpen = false; runtimeOptionsModalOpen = false;
syncSettingsModalSubtitleSuppression();
runtimeOptionsModal.classList.add("hidden"); runtimeOptionsModal.classList.add("hidden");
runtimeOptionsModal.setAttribute("aria-hidden", "true"); runtimeOptionsModal.setAttribute("aria-hidden", "true");
window.electronAPI.notifyOverlayModalClosed("runtime-options"); window.electronAPI.notifyOverlayModalClosed("runtime-options");
@@ -1159,6 +1172,7 @@ async function openRuntimeOptionsModal(): Promise<void> {
const options = await window.electronAPI.getRuntimeOptions(); const options = await window.electronAPI.getRuntimeOptions();
updateRuntimeOptions(options); updateRuntimeOptions(options);
runtimeOptionsModalOpen = true; runtimeOptionsModalOpen = true;
syncSettingsModalSubtitleSuppression();
overlay.classList.add("interactive"); overlay.classList.add("interactive");
runtimeOptionsModal.classList.remove("hidden"); runtimeOptionsModal.classList.remove("hidden");
runtimeOptionsModal.setAttribute("aria-hidden", "false"); runtimeOptionsModal.setAttribute("aria-hidden", "false");
@@ -1296,6 +1310,7 @@ function renderSubsyncSourceTracks(): void {
function closeSubsyncModal(): void { function closeSubsyncModal(): void {
if (!subsyncModalOpen) return; if (!subsyncModalOpen) return;
subsyncModalOpen = false; subsyncModalOpen = false;
syncSettingsModalSubtitleSuppression();
subsyncModal.classList.add("hidden"); subsyncModal.classList.add("hidden");
subsyncModal.setAttribute("aria-hidden", "true"); subsyncModal.setAttribute("aria-hidden", "true");
window.electronAPI.notifyOverlayModalClosed("subsync"); window.electronAPI.notifyOverlayModalClosed("subsync");
@@ -1326,6 +1341,7 @@ function openSubsyncModal(payload: SubsyncManualPayload): void {
false, false,
); );
subsyncModalOpen = true; subsyncModalOpen = true;
syncSettingsModalSubtitleSuppression();
overlay.classList.add("interactive"); overlay.classList.add("interactive");
subsyncModal.classList.remove("hidden"); subsyncModal.classList.remove("hidden");
subsyncModal.setAttribute("aria-hidden", "false"); subsyncModal.setAttribute("aria-hidden", "false");
@@ -1454,6 +1470,7 @@ function openKikuFieldGroupingModal(data: {
updateKikuCardSelection(); updateKikuCardSelection();
syncSettingsModalSubtitleSuppression();
overlay.classList.add("interactive"); overlay.classList.add("interactive");
kikuModal.classList.remove("hidden"); kikuModal.classList.remove("hidden");
kikuModal.setAttribute("aria-hidden", "false"); kikuModal.setAttribute("aria-hidden", "false");
@@ -1462,6 +1479,7 @@ function openKikuFieldGroupingModal(data: {
function closeKikuFieldGroupingModal(): void { function closeKikuFieldGroupingModal(): void {
if (!kikuModalOpen) return; if (!kikuModalOpen) return;
kikuModalOpen = false; kikuModalOpen = false;
syncSettingsModalSubtitleSuppression();
kikuModal.classList.add("hidden"); kikuModal.classList.add("hidden");
kikuModal.setAttribute("aria-hidden", "true"); kikuModal.setAttribute("aria-hidden", "true");
setKikuPreviewError(null); setKikuPreviewError(null);
@@ -2395,6 +2413,7 @@ async function init(): Promise<void> {
openRuntimeOptionsModal().catch(() => { openRuntimeOptionsModal().catch(() => {
setRuntimeOptionsStatus("Failed to load runtime options", true); setRuntimeOptionsStatus("Failed to load runtime options", true);
window.electronAPI.notifyOverlayModalClosed("runtime-options"); window.electronAPI.notifyOverlayModalClosed("runtime-options");
syncSettingsModalSubtitleSuppression();
}); });
}); });
window.electronAPI.onOpenJimaku(() => { window.electronAPI.onOpenJimaku(() => {

View File

@@ -259,6 +259,11 @@ body {
display: none; display: none;
} }
body.settings-modal-open #subtitleContainer {
display: none !important;
pointer-events: none !important;
}
#subtitleRoot .c { #subtitleRoot .c {
display: inline; display: inline;
position: relative; position: relative;
@@ -378,6 +383,11 @@ body.layer-invisible.debug-invisible-visualization #subtitleRoot .c {
display: none; display: none;
} }
body.settings-modal-open #secondarySubContainer {
display: none !important;
pointer-events: none !important;
}
.secondary-sub-hidden { .secondary-sub-hidden {
display: none !important; display: none !important;
} }