Restore overlay keybindings

This commit is contained in:
2026-02-22 21:35:47 -08:00
parent 9f619d73ef
commit 7f2d84ad42
6 changed files with 72 additions and 93 deletions

View File

@@ -128,7 +128,7 @@ src/renderer/
The main process has three layers: `main.ts` delegates to composition modules that wire together domain services. Three overlay windows (visible, invisible, secondary) run in separate Electron renderer processes, connected through `preload.ts`. External runtimes (launcher CLI and mpv plugin) operate independently and communicate via IPC socket or CLI passthrough. The main process has three layers: `main.ts` delegates to composition modules that wire together domain services. Three overlay windows (visible, invisible, secondary) run in separate Electron renderer processes, connected through `preload.ts`. External runtimes (launcher CLI and mpv plugin) operate independently and communicate via IPC socket or CLI passthrough.
```mermaid ```mermaid
flowchart TD flowchart LR
classDef entry fill:#c6a0f6,stroke:#494d64,color:#24273a,stroke-width:2px,font-weight:bold classDef entry fill:#c6a0f6,stroke:#494d64,color:#24273a,stroke-width:2px,font-weight:bold
classDef comp fill:#b7bdf8,stroke:#494d64,color:#24273a,stroke-width:1.5px classDef comp fill:#b7bdf8,stroke:#494d64,color:#24273a,stroke-width:1.5px
classDef svc fill:#8aadf4,stroke:#494d64,color:#24273a,stroke-width:1.5px classDef svc fill:#8aadf4,stroke:#494d64,color:#24273a,stroke-width:1.5px
@@ -137,94 +137,70 @@ flowchart TD
classDef ext fill:#a6da95,stroke:#494d64,color:#24273a,stroke-width:1.5px classDef ext fill:#a6da95,stroke:#494d64,color:#24273a,stroke-width:1.5px
classDef extrt fill:#eed49f,stroke:#494d64,color:#24273a,stroke-width:1.5px classDef extrt fill:#eed49f,stroke:#494d64,color:#24273a,stroke-width:1.5px
Main["main.ts — composition root"]:::entry subgraph ExtRt["External Runtimes"]
Launcher["launcher/<br/>CLI dispatch"]:::extrt
subgraph Comp["Composition — src/main/"] Plugin["subminer.lua<br/>mpv plugin"]:::extrt
direction TB
Startup["Startup & Lifecycle<br/>startup · app-lifecycle · startup-lifecycle · state"]:::comp
Wiring["Runtime Wiring<br/>ipc-runtime · cli-runtime · overlay-runtime · subsync-runtime"]:::comp
Composers["Composers<br/>mpv-runtime · anilist-tracking · jellyfin-runtime"]:::comp
end
subgraph Svc["Services — src/core/services/"]
direction TB
subgraph SvcRow1[" "]
direction LR
Mpv["MPV Stack<br/>transport · protocol<br/>properties · render-metrics"]:::svc
Overlay["Overlay Manager<br/>window · geometry<br/>visibility · bridge"]:::svc
end
subgraph SvcRow2[" "]
direction LR
Mining["Mining & Subtitles<br/>mining · field-grouping<br/>subtitle-ws · tokenizer"]:::svc
Integrations["Integrations<br/>jimaku · subsync · texthooker<br/>yomitan · discord-presence"]:::svc
end
subgraph SvcRow3[" "]
direction LR
Tracking["Tracking<br/>anilist · jellyfin-remote<br/>immersion-tracker"]:::svc
Config["Config & Runtime<br/>config-hot-reload<br/>runtime-options"]:::svc
end
end
Bridge(["preload.ts — Electron IPC bridge"]):::bridge
subgraph Rend["Renderer — src/renderer/"]
direction TB
subgraph Windows["Three overlay windows"]
direction LR
Visible["Visible<br/>interactive Yomitan lookups"]:::rend
Invisible["Invisible<br/>mpv-matched positioning"]:::rend
Secondary["Secondary<br/>secondary subtitle bar"]:::rend
end
UI["subtitle-render · positioning · handlers · modals"]:::rend
end end
subgraph Ext["External Systems"] subgraph Ext["External Systems"]
direction LR
mpvExt["mpv player"]:::ext mpvExt["mpv player"]:::ext
AnkiExt["AnkiConnect"]:::ext AnkiExt["AnkiConnect"]:::ext
JimakuExt["Jimaku API"]:::ext JimakuExt["Jimaku API"]:::ext
TrackerExt["Window Tracker<br/>Hyprland · Sway · X11 · macOS"]:::ext TrackerExt["Window Tracker<br/>Hyprland · Sway<br/>X11 · macOS"]:::ext
AnilistExt["AniList API"]:::ext AnilistExt["AniList API"]:::ext
JellyfinExt["Jellyfin"]:::ext JellyfinExt["Jellyfin"]:::ext
DiscordExt["Discord RPC"]:::ext DiscordExt["Discord RPC"]:::ext
end end
subgraph ExtRt["External Runtimes"] Main["main.ts<br/>composition root"]:::entry
direction LR
Launcher["launcher/<br/>CLI command dispatch"]:::extrt subgraph Comp["Composition — src/main/"]
Plugin["subminer.lua<br/>mpv plugin"]:::extrt Startup["Startup & Lifecycle<br/>startup · app-lifecycle<br/>startup-lifecycle · state"]:::comp
Wiring["Runtime Wiring<br/>ipc-runtime · cli-runtime<br/>overlay-runtime"]:::comp
Composers["Composers<br/>mpv · anilist<br/>jellyfin"]:::comp
end end
Main -->|"delegates"| Comp subgraph Svc["Services — src/core/services/"]
Startup -->|"initializes"| Svc Mpv["MPV Stack<br/>transport · protocol<br/>properties · metrics"]:::svc
Wiring -->|"dispatches to"| Svc Overlay["Overlay Manager<br/>window · geometry<br/>visibility · bridge"]:::svc
Composers -->|"wires"| Svc Mining["Mining & Subtitles<br/>mining · field-grouping<br/>subtitle-ws · tokenizer"]:::svc
Integrations["Integrations<br/>jimaku · subsync<br/>texthooker · yomitan"]:::svc
Tracking["Tracking<br/>anilist · jellyfin<br/>immersion · discord"]:::svc
Config["Config & Runtime<br/>hot-reload<br/>runtime-options"]:::svc
end
Overlay <-->Bridge Bridge(["preload.ts<br/>Electron IPC"]):::bridge
Mining <--> Bridge
Bridge <--> Visible
Bridge <--> Invisible
Bridge <--> Secondary
Windows --> UI
Mpv <-->|"JSON IPC socket"| mpvExt subgraph Rend["Renderer — src/renderer/"]
Mining -->|"HTTP"| AnkiExt Visible["Visible window<br/>Yomitan lookups"]:::rend
Integrations -->|"HTTP"| JimakuExt Invisible["Invisible window<br/>mpv positioning"]:::rend
Overlay -->|"platform API"| TrackerExt Secondary["Secondary window<br/>subtitle bar"]:::rend
Tracking -->|"HTTP"| AnilistExt UI["subtitle-render<br/>positioning<br/>handlers · modals"]:::rend
Tracking -->|"HTTP"| JellyfinExt end
Integrations -->|"RPC"| DiscordExt
Launcher -->|"CLI passthrough"| Main Launcher -->|"CLI"| Main
Plugin -->|"IPC socket"| mpvExt Plugin -->|"IPC"| mpvExt
Main --> Comp
Comp --> Svc
mpvExt <-->|"JSON socket"| Mpv
AnkiExt <-->|"HTTP"| Mining
JimakuExt <-->|"HTTP"| Integrations
TrackerExt <-->|"platform"| Overlay
AnilistExt <-->|"HTTP"| Tracking
JellyfinExt <-->|"HTTP"| Tracking
DiscordExt <-->|"RPC"| Integrations
Overlay & Mining --> Bridge
Bridge --> Visible
Bridge --> Invisible
Bridge --> Secondary
Visible & Invisible & Secondary --> UI
style Comp fill:#363a4f,stroke:#494d64,color:#cad3f5 style Comp fill:#363a4f,stroke:#494d64,color:#cad3f5
style Svc fill:#363a4f,stroke:#494d64,color:#cad3f5 style Svc fill:#363a4f,stroke:#494d64,color:#cad3f5
style SvcRow1 fill:transparent,stroke:none
style SvcRow2 fill:transparent,stroke:none
style SvcRow3 fill:transparent,stroke:none
style Rend fill:#363a4f,stroke:#494d64,color:#cad3f5 style Rend fill:#363a4f,stroke:#494d64,color:#cad3f5
style Windows fill:#1e2030,stroke:#494d64,color:#cad3f5
style Ext fill:#363a4f,stroke:#494d64,color:#cad3f5 style Ext fill:#363a4f,stroke:#494d64,color:#cad3f5
style ExtRt fill:#363a4f,stroke:#494d64,color:#cad3f5 style ExtRt fill:#363a4f,stroke:#494d64,color:#cad3f5
``` ```

BIN
flow-diagram-fullview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
flow-review-full.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

View File

@@ -1595,10 +1595,7 @@ local function start_overlay_from_script_message(...)
end end
local function stop_overlay() local function stop_overlay()
if not is_subminer_app_running() then if not ensure_binary_available() then
return
end
if not state.binary_available then
subminer_log("error", "binary", "SubMiner binary not found") subminer_log("error", "binary", "SubMiner binary not found")
show_osd("Error: binary not found") show_osd("Error: binary not found")
return return
@@ -1626,10 +1623,7 @@ local function stop_overlay()
end end
local function toggle_overlay() local function toggle_overlay()
if not is_subminer_app_running() then if not ensure_binary_available() then
return
end
if not state.binary_available then
subminer_log("error", "binary", "SubMiner binary not found") subminer_log("error", "binary", "SubMiner binary not found")
show_osd("Error: binary not found") show_osd("Error: binary not found")
return return
@@ -1653,10 +1647,7 @@ local function toggle_overlay()
end end
local function toggle_invisible_overlay() local function toggle_invisible_overlay()
if not is_subminer_app_running() then if not ensure_binary_available() then
return
end
if not state.binary_available then
subminer_log("error", "binary", "SubMiner binary not found") subminer_log("error", "binary", "SubMiner binary not found")
show_osd("Error: binary not found") show_osd("Error: binary not found")
return return
@@ -1684,10 +1675,7 @@ local function toggle_invisible_overlay()
end end
local function show_invisible_overlay() local function show_invisible_overlay()
if not is_subminer_app_running() then if not ensure_binary_available() then
return
end
if not state.binary_available then
subminer_log("error", "binary", "SubMiner binary not found") subminer_log("error", "binary", "SubMiner binary not found")
show_osd("Error: binary not found") show_osd("Error: binary not found")
return return
@@ -1715,10 +1703,7 @@ local function show_invisible_overlay()
end end
local function hide_invisible_overlay() local function hide_invisible_overlay()
if not is_subminer_app_running() then if not ensure_binary_available() then
return
end
if not state.binary_available then
subminer_log("error", "binary", "SubMiner binary not found") subminer_log("error", "binary", "SubMiner binary not found")
show_osd("Error: binary not found") show_osd("Error: binary not found")
return return
@@ -1811,10 +1796,7 @@ local function show_menu()
end end
restart_overlay = function() restart_overlay = function()
if not is_subminer_app_running() then if not ensure_binary_available() then
return
end
if not state.binary_available then
subminer_log("error", "binary", "SubMiner binary not found") subminer_log("error", "binary", "SubMiner binary not found")
show_osd("Error: binary not found") show_osd("Error: binary not found")
return return

View File

@@ -2926,11 +2926,30 @@ function handleMineSentenceDigit(count: number): void {
handleMineSentenceDigitHandler(count); handleMineSentenceDigitHandler(count);
} }
function ensureOverlayWindowsReadyForVisibilityActions(): void {
if (!appState.overlayRuntimeInitialized) {
initializeOverlayRuntime();
return;
}
const mainWindow = overlayManager.getMainWindow();
if (!mainWindow || mainWindow.isDestroyed()) {
createMainWindow();
}
const invisibleWindow = overlayManager.getInvisibleWindow();
if (!invisibleWindow || invisibleWindow.isDestroyed()) {
createInvisibleWindow();
}
}
function setVisibleOverlayVisible(visible: boolean): void { function setVisibleOverlayVisible(visible: boolean): void {
ensureOverlayWindowsReadyForVisibilityActions();
setVisibleOverlayVisibleHandler(visible); setVisibleOverlayVisibleHandler(visible);
} }
function setInvisibleOverlayVisible(visible: boolean): void { function setInvisibleOverlayVisible(visible: boolean): void {
ensureOverlayWindowsReadyForVisibilityActions();
setInvisibleOverlayVisibleHandler(visible); setInvisibleOverlayVisibleHandler(visible);
if (visible) { if (visible) {
subtitleProcessingController.refreshCurrentSubtitle(appState.currentSubText); subtitleProcessingController.refreshCurrentSubtitle(appState.currentSubText);
@@ -2938,9 +2957,11 @@ function setInvisibleOverlayVisible(visible: boolean): void {
} }
function toggleVisibleOverlay(): void { function toggleVisibleOverlay(): void {
ensureOverlayWindowsReadyForVisibilityActions();
toggleVisibleOverlayHandler(); toggleVisibleOverlayHandler();
} }
function toggleInvisibleOverlay(): void { function toggleInvisibleOverlay(): void {
ensureOverlayWindowsReadyForVisibilityActions();
toggleInvisibleOverlayHandler(); toggleInvisibleOverlayHandler();
} }
function setOverlayVisible(visible: boolean): void { function setOverlayVisible(visible: boolean): void {