mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-21 05:01:26 -07:00
refactor(ipc): remove dead preload methods and the ASS line broadcast (#293)
Drop 16 overlay preload methods with no caller (onSubtitleAss, getCurrentSubtitleAss, onVisibility, getOverlayVisibility, openYomitanSettings, quitApp, toggleOverlay, getMecabStatus, setMecabEnabled, getKeybindings, saveControllerPreference, getAnkiConnectStatus, setAnkiConnectEnabled, clearAnkiConnectHistory, cycleRuntimeOption, appendClipboardVideoToQueue) along with their IPC_CHANNELS keys, handlers, validators and dep plumbing. With both ASS consumers gone, stop observing sub-text/ass in mpv and remove the subtitle-ass-change event chain and appState.currentSubAssText. The main-process functions these wrapped stay; tray, CLI, shortcuts and session actions still use them.
This commit is contained in:
1 parent
8fc20b2499
commit
7909fcd2cf
32 files changed
+8
-876
No files matched your search
@@ -0,0 +1,4 @@
|
|||||||
|
type: internal
|
||||||
|
area: overlay
|
||||||
|
|
||||||
|
- Removed 16 overlay preload/IPC methods that nothing called, plus their main-process handlers. SubMiner no longer observes mpv's `sub-text/ass` or sends every ASS line to overlay windows that never listened.
|
||||||
@@ -32,8 +32,6 @@ test('anki/jimaku IPC handlers reject malformed invoke payloads', async () => {
|
|||||||
let previewCalls = 0;
|
let previewCalls = 0;
|
||||||
registerAnkiJimakuIpcHandlers(
|
registerAnkiJimakuIpcHandlers(
|
||||||
{
|
{
|
||||||
setAnkiConnectEnabled: () => {},
|
|
||||||
clearAnkiHistory: () => {},
|
|
||||||
refreshKnownWords: async () => {},
|
refreshKnownWords: async () => {},
|
||||||
respondFieldGrouping: () => {},
|
respondFieldGrouping: () => {},
|
||||||
buildKikuMergePreview: async () => {
|
buildKikuMergePreview: async () => {
|
||||||
@@ -138,8 +136,6 @@ test('tsukihime downloads always route Japanese as primary', async () => {
|
|||||||
const secondaryLoads: string[] = [];
|
const secondaryLoads: string[] = [];
|
||||||
registerAnkiJimakuIpcHandlers(
|
registerAnkiJimakuIpcHandlers(
|
||||||
{
|
{
|
||||||
setAnkiConnectEnabled: () => {},
|
|
||||||
clearAnkiHistory: () => {},
|
|
||||||
refreshKnownWords: async () => {},
|
refreshKnownWords: async () => {},
|
||||||
respondFieldGrouping: () => {},
|
respondFieldGrouping: () => {},
|
||||||
buildKikuMergePreview: async () => ({ ok: true }),
|
buildKikuMergePreview: async () => ({ ok: true }),
|
||||||
@@ -205,13 +201,8 @@ test('tsukihime downloads always route Japanese as primary', async () => {
|
|||||||
test('anki/jimaku IPC command handlers ignore malformed payloads', () => {
|
test('anki/jimaku IPC command handlers ignore malformed payloads', () => {
|
||||||
const { registrar, onHandlers } = createFakeRegistrar();
|
const { registrar, onHandlers } = createFakeRegistrar();
|
||||||
const fieldGroupingChoices: unknown[] = [];
|
const fieldGroupingChoices: unknown[] = [];
|
||||||
const enabledStates: boolean[] = [];
|
|
||||||
registerAnkiJimakuIpcHandlers(
|
registerAnkiJimakuIpcHandlers(
|
||||||
{
|
{
|
||||||
setAnkiConnectEnabled: (enabled) => {
|
|
||||||
enabledStates.push(enabled);
|
|
||||||
},
|
|
||||||
clearAnkiHistory: () => {},
|
|
||||||
refreshKnownWords: async () => {},
|
refreshKnownWords: async () => {},
|
||||||
respondFieldGrouping: (choice) => {
|
respondFieldGrouping: (choice) => {
|
||||||
fieldGroupingChoices.push(choice);
|
fieldGroupingChoices.push(choice);
|
||||||
@@ -241,10 +232,6 @@ test('anki/jimaku IPC command handlers ignore malformed payloads', () => {
|
|||||||
registrar,
|
registrar,
|
||||||
);
|
);
|
||||||
|
|
||||||
onHandlers.get(IPC_CHANNELS.command.setAnkiConnectEnabled)!({}, 'true');
|
|
||||||
onHandlers.get(IPC_CHANNELS.command.setAnkiConnectEnabled)!({}, true);
|
|
||||||
assert.deepEqual(enabledStates, [true]);
|
|
||||||
|
|
||||||
onHandlers.get(IPC_CHANNELS.command.kikuFieldGroupingRespond)!({}, null);
|
onHandlers.get(IPC_CHANNELS.command.kikuFieldGroupingRespond)!({}, null);
|
||||||
onHandlers.get(IPC_CHANNELS.command.kikuFieldGroupingRespond)!(
|
onHandlers.get(IPC_CHANNELS.command.kikuFieldGroupingRespond)!(
|
||||||
{},
|
{},
|
||||||
|
|||||||
@@ -40,8 +40,6 @@ const { ipcMain } = electron;
|
|||||||
const logger = createLogger('main:anki-jimaku-ipc');
|
const logger = createLogger('main:anki-jimaku-ipc');
|
||||||
|
|
||||||
export interface AnkiJimakuIpcDeps {
|
export interface AnkiJimakuIpcDeps {
|
||||||
setAnkiConnectEnabled: (enabled: boolean) => void;
|
|
||||||
clearAnkiHistory: () => void;
|
|
||||||
refreshKnownWords: () => Promise<void> | void;
|
refreshKnownWords: () => Promise<void> | void;
|
||||||
respondFieldGrouping: (choice: KikuFieldGroupingChoice) => void;
|
respondFieldGrouping: (choice: KikuFieldGroupingChoice) => void;
|
||||||
buildKikuMergePreview: (request: KikuMergePreviewRequest) => Promise<KikuMergePreviewResponse>;
|
buildKikuMergePreview: (request: KikuMergePreviewRequest) => Promise<KikuMergePreviewResponse>;
|
||||||
@@ -77,15 +75,6 @@ export function registerAnkiJimakuIpcHandlers(
|
|||||||
deps: AnkiJimakuIpcDeps,
|
deps: AnkiJimakuIpcDeps,
|
||||||
ipc: IpcMainRegistrar = ipcMain,
|
ipc: IpcMainRegistrar = ipcMain,
|
||||||
): void {
|
): void {
|
||||||
ipc.on(IPC_CHANNELS.command.setAnkiConnectEnabled, (_event: unknown, enabled: unknown) => {
|
|
||||||
if (typeof enabled !== 'boolean') return;
|
|
||||||
deps.setAnkiConnectEnabled(enabled);
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.on(IPC_CHANNELS.command.clearAnkiConnectHistory, () => {
|
|
||||||
deps.clearAnkiHistory();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.on(IPC_CHANNELS.command.refreshKnownWords, async () => {
|
ipc.on(IPC_CHANNELS.command.refreshKnownWords, async () => {
|
||||||
await deps.refreshKnownWords();
|
await deps.refreshKnownWords();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ interface RuntimeHarness {
|
|||||||
state: {
|
state: {
|
||||||
ankiIntegration: unknown;
|
ankiIntegration: unknown;
|
||||||
fieldGroupingResolver: ((choice: unknown) => void) | null;
|
fieldGroupingResolver: ((choice: unknown) => void) | null;
|
||||||
patches: boolean[];
|
|
||||||
broadcasts: number;
|
|
||||||
fetchCalls: Array<{ endpoint: string; query?: Record<string, unknown> }>;
|
fetchCalls: Array<{ endpoint: string; query?: Record<string, unknown> }>;
|
||||||
tsukihimeFetchCalls: Array<{ endpoint: string; query?: Record<string, unknown> }>;
|
tsukihimeFetchCalls: Array<{ endpoint: string; query?: Record<string, unknown> }>;
|
||||||
sentCommands: Array<{ command: (string | number)[] }>;
|
sentCommands: Array<{ command: (string | number)[] }>;
|
||||||
@@ -20,8 +18,6 @@ function createHarness(): RuntimeHarness {
|
|||||||
const state = {
|
const state = {
|
||||||
ankiIntegration: null as unknown,
|
ankiIntegration: null as unknown,
|
||||||
fieldGroupingResolver: null as ((choice: unknown) => void) | null,
|
fieldGroupingResolver: null as ((choice: unknown) => void) | null,
|
||||||
patches: [] as boolean[],
|
|
||||||
broadcasts: 0,
|
|
||||||
fetchCalls: [] as Array<{
|
fetchCalls: [] as Array<{
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
query?: Record<string, unknown>;
|
query?: Record<string, unknown>;
|
||||||
@@ -34,11 +30,7 @@ function createHarness(): RuntimeHarness {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const options: AnkiJimakuIpcRuntimeOptions = {
|
const options: AnkiJimakuIpcRuntimeOptions = {
|
||||||
patchAnkiConnectEnabled: (enabled) => {
|
|
||||||
state.patches.push(enabled);
|
|
||||||
},
|
|
||||||
getResolvedConfig: () => ({ tsukihime: { maxSearchResults: 2 } }),
|
getResolvedConfig: () => ({ tsukihime: { maxSearchResults: 2 } }),
|
||||||
getRuntimeOptionsManager: () => null,
|
|
||||||
tsukihimeFetchJson: async (endpoint, query) => {
|
tsukihimeFetchJson: async (endpoint, query) => {
|
||||||
state.tsukihimeFetchCalls.push({
|
state.tsukihimeFetchCalls.push({
|
||||||
endpoint,
|
endpoint,
|
||||||
@@ -76,7 +68,6 @@ function createHarness(): RuntimeHarness {
|
|||||||
} as never,
|
} as never,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getSubtitleTimingTracker: () => null,
|
|
||||||
getMpvClient: () => ({
|
getMpvClient: () => ({
|
||||||
connected: true,
|
connected: true,
|
||||||
send: (payload) => {
|
send: (payload) => {
|
||||||
@@ -99,20 +90,6 @@ function createHarness(): RuntimeHarness {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
getAnkiIntegration: () => state.ankiIntegration as never,
|
getAnkiIntegration: () => state.ankiIntegration as never,
|
||||||
setAnkiIntegration: (integration) => {
|
|
||||||
state.ankiIntegration = integration;
|
|
||||||
},
|
|
||||||
getKnownWordCacheStatePath: () => '/tmp/subminer-known-words-cache.json',
|
|
||||||
showDesktopNotification: () => {},
|
|
||||||
createFieldGroupingCallback: () => async () => ({
|
|
||||||
keepNoteId: 1,
|
|
||||||
deleteNoteId: 2,
|
|
||||||
deleteDuplicate: false,
|
|
||||||
cancelled: false,
|
|
||||||
}),
|
|
||||||
broadcastRuntimeOptionsChanged: () => {
|
|
||||||
state.broadcasts += 1;
|
|
||||||
},
|
|
||||||
getFieldGroupingResolver: () => state.fieldGroupingResolver as never,
|
getFieldGroupingResolver: () => state.fieldGroupingResolver as never,
|
||||||
setFieldGroupingResolver: (resolver) => {
|
setFieldGroupingResolver: (resolver) => {
|
||||||
state.fieldGroupingResolver = resolver as never;
|
state.fieldGroupingResolver = resolver as never;
|
||||||
@@ -169,51 +146,21 @@ test('refreshKnownWords throws when integration is unavailable', async () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('setAnkiConnectEnabled disables active integration and broadcasts changes', () => {
|
test('respondFieldGrouping resolves and clears the pending resolver', () => {
|
||||||
const { registered, state } = createHarness();
|
const { registered, state } = createHarness();
|
||||||
let destroyed = 0;
|
|
||||||
state.ankiIntegration = {
|
|
||||||
destroy: () => {
|
|
||||||
destroyed += 1;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
registered.setAnkiConnectEnabled!(false);
|
|
||||||
|
|
||||||
assert.deepEqual(state.patches, [false]);
|
|
||||||
assert.equal(destroyed, 1);
|
|
||||||
assert.equal(state.ankiIntegration, null);
|
|
||||||
assert.equal(state.broadcasts, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('clearAnkiHistory and respondFieldGrouping execute runtime callbacks', () => {
|
|
||||||
const { registered, state, options } = createHarness();
|
|
||||||
let cleaned = 0;
|
|
||||||
let resolvedChoice: unknown = null;
|
let resolvedChoice: unknown = null;
|
||||||
state.fieldGroupingResolver = (choice) => {
|
state.fieldGroupingResolver = (choice) => {
|
||||||
resolvedChoice = choice;
|
resolvedChoice = choice;
|
||||||
};
|
};
|
||||||
|
|
||||||
const originalGetTracker = options.getSubtitleTimingTracker;
|
|
||||||
options.getSubtitleTimingTracker = () =>
|
|
||||||
({
|
|
||||||
cleanup: () => {
|
|
||||||
cleaned += 1;
|
|
||||||
},
|
|
||||||
}) as never;
|
|
||||||
|
|
||||||
const choice = {
|
const choice = {
|
||||||
keepNoteId: 10,
|
keepNoteId: 10,
|
||||||
deleteNoteId: 11,
|
deleteNoteId: 11,
|
||||||
deleteDuplicate: true,
|
deleteDuplicate: true,
|
||||||
cancelled: false,
|
cancelled: false,
|
||||||
};
|
};
|
||||||
registered.clearAnkiHistory!();
|
|
||||||
registered.respondFieldGrouping!(choice);
|
registered.respondFieldGrouping!(choice);
|
||||||
|
|
||||||
options.getSubtitleTimingTracker = originalGetTracker;
|
|
||||||
|
|
||||||
assert.equal(cleaned, 1);
|
|
||||||
assert.deepEqual(resolvedChoice, choice);
|
assert.deepEqual(resolvedChoice, choice);
|
||||||
assert.equal(state.fieldGroupingResolver, null);
|
assert.equal(state.fieldGroupingResolver, null);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { AnkiIntegration } from '../../anki-integration';
|
import type { AnkiIntegration } from '../../anki-integration';
|
||||||
import { mergeAiConfig } from '../../ai/config';
|
|
||||||
import {
|
import {
|
||||||
AiConfig,
|
|
||||||
TsukihimeApiResponse,
|
TsukihimeApiResponse,
|
||||||
TsukihimeConfig,
|
TsukihimeConfig,
|
||||||
AnkiConnectConfig,
|
|
||||||
JimakuApiResponse,
|
JimakuApiResponse,
|
||||||
JimakuEntry,
|
JimakuEntry,
|
||||||
JimakuFileEntry,
|
JimakuFileEntry,
|
||||||
JimakuLanguagePreference,
|
JimakuLanguagePreference,
|
||||||
JimakuMediaInfo,
|
JimakuMediaInfo,
|
||||||
KikuFieldGroupingChoice,
|
KikuFieldGroupingChoice,
|
||||||
KikuFieldGroupingRequestData,
|
|
||||||
OverlayNotificationPayload,
|
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import { sortJimakuFiles } from '../../jimaku/utils';
|
import { sortJimakuFiles } from '../../jimaku/utils';
|
||||||
import {
|
import {
|
||||||
@@ -35,41 +30,13 @@ interface MpvClientLike {
|
|||||||
request?: (command: unknown[]) => Promise<{ data?: unknown }>;
|
request?: (command: unknown[]) => Promise<{ data?: unknown }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RuntimeOptionsManagerLike {
|
|
||||||
getEffectiveAnkiConnectConfig: (config?: AnkiConnectConfig) => AnkiConnectConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SubtitleTimingTrackerLike {
|
|
||||||
cleanup: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AnkiJimakuIpcRuntimeOptions {
|
export interface AnkiJimakuIpcRuntimeOptions {
|
||||||
patchAnkiConnectEnabled: (enabled: boolean) => void;
|
|
||||||
getResolvedConfig: () => {
|
getResolvedConfig: () => {
|
||||||
ankiConnect?: AnkiConnectConfig;
|
|
||||||
ai?: AiConfig;
|
|
||||||
tsukihime?: TsukihimeConfig;
|
tsukihime?: TsukihimeConfig;
|
||||||
secondarySub?: { secondarySubLanguages?: string[] };
|
secondarySub?: { secondarySubLanguages?: string[] };
|
||||||
};
|
};
|
||||||
getRuntimeOptionsManager: () => RuntimeOptionsManagerLike | null;
|
|
||||||
getSubtitleTimingTracker: () => SubtitleTimingTrackerLike | null;
|
|
||||||
getMpvClient: () => MpvClientLike | null;
|
getMpvClient: () => MpvClientLike | null;
|
||||||
getAnkiIntegration: () => AnkiIntegration | null;
|
getAnkiIntegration: () => AnkiIntegration | null;
|
||||||
setAnkiIntegration: (integration: AnkiIntegration | null) => void;
|
|
||||||
getKnownWordCacheStatePath: () => string;
|
|
||||||
getCachedMediaPath?: (
|
|
||||||
currentVideoPath: string,
|
|
||||||
kind: 'audio' | 'video',
|
|
||||||
) => Promise<string | null>;
|
|
||||||
shouldRequireRemoteMediaCache?: () => boolean;
|
|
||||||
getYoutubeMediaSourceUrl?: () => Promise<string | null | undefined> | string | null | undefined;
|
|
||||||
showDesktopNotification: (title: string, options: { body?: string; icon?: string }) => void;
|
|
||||||
showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
|
|
||||||
dismissOverlayNotification?: (id: string) => void;
|
|
||||||
createFieldGroupingCallback: () => (
|
|
||||||
data: KikuFieldGroupingRequestData,
|
|
||||||
) => Promise<KikuFieldGroupingChoice>;
|
|
||||||
broadcastRuntimeOptionsChanged: () => void;
|
|
||||||
getFieldGroupingResolver: () => ((choice: KikuFieldGroupingChoice) => void) | null;
|
getFieldGroupingResolver: () => ((choice: KikuFieldGroupingChoice) => void) | null;
|
||||||
setFieldGroupingResolver: (resolver: ((choice: KikuFieldGroupingChoice) => void) | null) => void;
|
setFieldGroupingResolver: (resolver: ((choice: KikuFieldGroupingChoice) => void) | null) => void;
|
||||||
parseMediaInfo: (mediaPath: string | null) => JimakuMediaInfo;
|
parseMediaInfo: (mediaPath: string | null) => JimakuMediaInfo;
|
||||||
@@ -135,58 +102,6 @@ export function registerAnkiJimakuIpcRuntime(
|
|||||||
registerHandlers: RegisterAnkiJimakuIpcRuntimeHandler,
|
registerHandlers: RegisterAnkiJimakuIpcRuntimeHandler,
|
||||||
): void {
|
): void {
|
||||||
registerHandlers({
|
registerHandlers({
|
||||||
setAnkiConnectEnabled: (enabled) => {
|
|
||||||
options.patchAnkiConnectEnabled(enabled);
|
|
||||||
const config = options.getResolvedConfig();
|
|
||||||
const subtitleTimingTracker = options.getSubtitleTimingTracker();
|
|
||||||
const mpvClient = options.getMpvClient();
|
|
||||||
const ankiIntegration = options.getAnkiIntegration();
|
|
||||||
|
|
||||||
if (enabled && !ankiIntegration && subtitleTimingTracker && mpvClient) {
|
|
||||||
const runtimeOptionsManager = options.getRuntimeOptionsManager();
|
|
||||||
const effectiveAnkiConfig = runtimeOptionsManager
|
|
||||||
? runtimeOptionsManager.getEffectiveAnkiConnectConfig(config.ankiConnect)
|
|
||||||
: config.ankiConnect;
|
|
||||||
const integration = new AnkiIntegration(
|
|
||||||
effectiveAnkiConfig as never,
|
|
||||||
subtitleTimingTracker as never,
|
|
||||||
mpvClient as never,
|
|
||||||
(text: string) => {
|
|
||||||
if (mpvClient) {
|
|
||||||
mpvClient.send({
|
|
||||||
command: ['show-text', text, '3000'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
options.showDesktopNotification,
|
|
||||||
options.createFieldGroupingCallback(),
|
|
||||||
options.getKnownWordCacheStatePath(),
|
|
||||||
mergeAiConfig(config.ai, config.ankiConnect?.ai) as AiConfig,
|
|
||||||
undefined,
|
|
||||||
options.showOverlayNotification,
|
|
||||||
options.getCachedMediaPath,
|
|
||||||
options.shouldRequireRemoteMediaCache,
|
|
||||||
options.getYoutubeMediaSourceUrl,
|
|
||||||
options.dismissOverlayNotification,
|
|
||||||
);
|
|
||||||
integration.start();
|
|
||||||
options.setAnkiIntegration(integration);
|
|
||||||
logger.info('AnkiConnect integration enabled');
|
|
||||||
} else if (!enabled && ankiIntegration) {
|
|
||||||
ankiIntegration.destroy();
|
|
||||||
options.setAnkiIntegration(null);
|
|
||||||
logger.info('AnkiConnect integration disabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
options.broadcastRuntimeOptionsChanged();
|
|
||||||
},
|
|
||||||
clearAnkiHistory: () => {
|
|
||||||
const subtitleTimingTracker = options.getSubtitleTimingTracker();
|
|
||||||
if (subtitleTimingTracker) {
|
|
||||||
subtitleTimingTracker.cleanup();
|
|
||||||
logger.info('AnkiConnect subtitle timing history cleared');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
refreshKnownWords: async () => {
|
refreshKnownWords: async () => {
|
||||||
const integration = options.getAnkiIntegration();
|
const integration = options.getAnkiIntegration();
|
||||||
if (!integration) {
|
if (!integration) {
|
||||||
|
|||||||
@@ -114,23 +114,15 @@ function createSubtitleSidebarSnapshotFixture(): SubtitleSidebarSnapshot {
|
|||||||
function createRegisterIpcDeps(overrides: Partial<IpcServiceDeps> = {}): IpcServiceDeps {
|
function createRegisterIpcDeps(overrides: Partial<IpcServiceDeps> = {}): IpcServiceDeps {
|
||||||
return {
|
return {
|
||||||
onOverlayModalClosed: () => {},
|
onOverlayModalClosed: () => {},
|
||||||
openYomitanSettings: () => {},
|
|
||||||
quitApp: () => {},
|
|
||||||
toggleDevTools: () => {},
|
toggleDevTools: () => {},
|
||||||
getVisibleOverlayVisibility: () => false,
|
|
||||||
toggleVisibleOverlay: () => {},
|
|
||||||
tokenizeCurrentSubtitle: async () => null,
|
tokenizeCurrentSubtitle: async () => null,
|
||||||
getCurrentSubtitleRaw: () => '',
|
getCurrentSubtitleRaw: () => '',
|
||||||
getCurrentSubtitleAss: () => '',
|
|
||||||
getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(),
|
getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(),
|
||||||
getPlaybackPaused: () => false,
|
getPlaybackPaused: () => false,
|
||||||
getSubtitlePosition: () => null,
|
getSubtitlePosition: () => null,
|
||||||
getSubtitleStyle: () => null,
|
getSubtitleStyle: () => null,
|
||||||
saveSubtitlePosition: () => {},
|
saveSubtitlePosition: () => {},
|
||||||
getMecabStatus: () => ({ available: false, enabled: false, path: null }),
|
|
||||||
setMecabEnabled: () => {},
|
|
||||||
handleMpvCommand: () => {},
|
handleMpvCommand: () => {},
|
||||||
getKeybindings: () => [],
|
|
||||||
getSessionBindings: () => [],
|
getSessionBindings: () => [],
|
||||||
getConfiguredShortcuts: () => ({}),
|
getConfiguredShortcuts: () => ({}),
|
||||||
dispatchSessionAction: async () => {},
|
dispatchSessionAction: async () => {},
|
||||||
@@ -139,23 +131,19 @@ function createRegisterIpcDeps(overrides: Partial<IpcServiceDeps> = {}): IpcServ
|
|||||||
getOverlayNotificationPosition: () => 'top-right',
|
getOverlayNotificationPosition: () => 'top-right',
|
||||||
getControllerConfig: () => createControllerConfigFixture(),
|
getControllerConfig: () => createControllerConfigFixture(),
|
||||||
saveControllerConfig: async () => {},
|
saveControllerConfig: async () => {},
|
||||||
saveControllerPreference: async () => {},
|
|
||||||
getSecondarySubMode: () => 'hover',
|
getSecondarySubMode: () => 'hover',
|
||||||
getCurrentSecondarySub: () => '',
|
getCurrentSecondarySub: () => '',
|
||||||
focusMainWindow: () => {},
|
focusMainWindow: () => {},
|
||||||
activatePlaybackWindowForOverlayInteraction: () => false,
|
activatePlaybackWindowForOverlayInteraction: () => false,
|
||||||
runSubsyncManual: async () => ({ ok: true, message: 'ok' }),
|
runSubsyncManual: async () => ({ ok: true, message: 'ok' }),
|
||||||
getAnkiConnectStatus: () => false,
|
|
||||||
getRuntimeOptions: () => [],
|
getRuntimeOptions: () => [],
|
||||||
setRuntimeOption: () => ({ ok: true }),
|
setRuntimeOption: () => ({ ok: true }),
|
||||||
cycleRuntimeOption: () => ({ ok: true }),
|
|
||||||
reportOverlayContentBounds: () => {},
|
reportOverlayContentBounds: () => {},
|
||||||
getAnilistStatus: () => ({}),
|
getAnilistStatus: () => ({}),
|
||||||
clearAnilistToken: () => {},
|
clearAnilistToken: () => {},
|
||||||
openAnilistSetup: () => {},
|
openAnilistSetup: () => {},
|
||||||
getAnilistQueueStatus: () => ({}),
|
getAnilistQueueStatus: () => ({}),
|
||||||
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
|
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
|
||||||
appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }),
|
|
||||||
getPlaylistBrowserSnapshot: async () => ({
|
getPlaylistBrowserSnapshot: async () => ({
|
||||||
directoryPath: null,
|
directoryPath: null,
|
||||||
directoryAvailable: false,
|
directoryAvailable: false,
|
||||||
@@ -312,26 +300,17 @@ test('registerIpcHandlers skips AniList update when manual mark watched has no a
|
|||||||
test('registerIpcHandlers rejects malformed runtime-option payloads', async () => {
|
test('registerIpcHandlers rejects malformed runtime-option payloads', async () => {
|
||||||
const { registrar, handlers } = createFakeIpcRegistrar();
|
const { registrar, handlers } = createFakeIpcRegistrar();
|
||||||
const calls: Array<{ id: string; value: unknown }> = [];
|
const calls: Array<{ id: string; value: unknown }> = [];
|
||||||
const cycles: Array<{ id: string; direction: 1 | -1 }> = [];
|
|
||||||
registerIpcHandlers(
|
registerIpcHandlers(
|
||||||
{
|
{
|
||||||
onOverlayModalClosed: () => {},
|
onOverlayModalClosed: () => {},
|
||||||
openYomitanSettings: () => {},
|
|
||||||
quitApp: () => {},
|
|
||||||
toggleDevTools: () => {},
|
toggleDevTools: () => {},
|
||||||
getVisibleOverlayVisibility: () => false,
|
|
||||||
toggleVisibleOverlay: () => {},
|
|
||||||
tokenizeCurrentSubtitle: async () => null,
|
tokenizeCurrentSubtitle: async () => null,
|
||||||
getCurrentSubtitleRaw: () => '',
|
getCurrentSubtitleRaw: () => '',
|
||||||
getCurrentSubtitleAss: () => '',
|
|
||||||
getPlaybackPaused: () => null,
|
getPlaybackPaused: () => null,
|
||||||
getSubtitlePosition: () => null,
|
getSubtitlePosition: () => null,
|
||||||
getSubtitleStyle: () => null,
|
getSubtitleStyle: () => null,
|
||||||
saveSubtitlePosition: () => {},
|
saveSubtitlePosition: () => {},
|
||||||
getMecabStatus: () => ({ available: false, enabled: false, path: null }),
|
|
||||||
setMecabEnabled: () => {},
|
|
||||||
handleMpvCommand: () => {},
|
handleMpvCommand: () => {},
|
||||||
getKeybindings: () => [],
|
|
||||||
getSessionBindings: () => [],
|
getSessionBindings: () => [],
|
||||||
getConfiguredShortcuts: () => ({}),
|
getConfiguredShortcuts: () => ({}),
|
||||||
dispatchSessionAction: async () => {},
|
dispatchSessionAction: async () => {},
|
||||||
@@ -340,21 +319,15 @@ test('registerIpcHandlers rejects malformed runtime-option payloads', async () =
|
|||||||
getOverlayNotificationPosition: () => 'top-right',
|
getOverlayNotificationPosition: () => 'top-right',
|
||||||
getControllerConfig: () => createControllerConfigFixture(),
|
getControllerConfig: () => createControllerConfigFixture(),
|
||||||
saveControllerConfig: () => {},
|
saveControllerConfig: () => {},
|
||||||
saveControllerPreference: () => {},
|
|
||||||
getSecondarySubMode: () => 'hover',
|
getSecondarySubMode: () => 'hover',
|
||||||
getCurrentSecondarySub: () => '',
|
getCurrentSecondarySub: () => '',
|
||||||
focusMainWindow: () => {},
|
focusMainWindow: () => {},
|
||||||
runSubsyncManual: async () => ({ ok: true, message: 'ok' }),
|
runSubsyncManual: async () => ({ ok: true, message: 'ok' }),
|
||||||
getAnkiConnectStatus: () => false,
|
|
||||||
getRuntimeOptions: () => [],
|
getRuntimeOptions: () => [],
|
||||||
setRuntimeOption: (id, value) => {
|
setRuntimeOption: (id, value) => {
|
||||||
calls.push({ id, value });
|
calls.push({ id, value });
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
},
|
},
|
||||||
cycleRuntimeOption: (id, direction) => {
|
|
||||||
cycles.push({ id, direction });
|
|
||||||
return { ok: true };
|
|
||||||
},
|
|
||||||
getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(),
|
getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(),
|
||||||
reportOverlayContentBounds: () => {},
|
reportOverlayContentBounds: () => {},
|
||||||
getAnilistStatus: () => ({}),
|
getAnilistStatus: () => ({}),
|
||||||
@@ -362,7 +335,6 @@ test('registerIpcHandlers rejects malformed runtime-option payloads', async () =
|
|||||||
openAnilistSetup: () => {},
|
openAnilistSetup: () => {},
|
||||||
getAnilistQueueStatus: () => ({}),
|
getAnilistQueueStatus: () => ({}),
|
||||||
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
|
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
|
||||||
appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }),
|
|
||||||
getPlaylistBrowserSnapshot: async () => ({
|
getPlaylistBrowserSnapshot: async () => ({
|
||||||
directoryPath: null,
|
directoryPath: null,
|
||||||
directoryAvailable: false,
|
directoryAvailable: false,
|
||||||
@@ -399,16 +371,6 @@ test('registerIpcHandlers rejects malformed runtime-option payloads', async () =
|
|||||||
{ id: 'subtitle.annotation.jlpt', value: false },
|
{ id: 'subtitle.annotation.jlpt', value: false },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const cycleHandler = handlers.handle.get(IPC_CHANNELS.request.cycleRuntimeOption);
|
|
||||||
assert.ok(cycleHandler);
|
|
||||||
const invalidDirection = await cycleHandler!({}, 'anki.kikuFieldGrouping', 2);
|
|
||||||
assert.deepEqual(invalidDirection, {
|
|
||||||
ok: false,
|
|
||||||
error: 'Invalid runtime option cycle direction',
|
|
||||||
});
|
|
||||||
await cycleHandler!({}, 'anki.kikuFieldGrouping', -1);
|
|
||||||
assert.deepEqual(cycles, [{ id: 'anki.kikuFieldGrouping', direction: -1 }]);
|
|
||||||
|
|
||||||
const getPlaybackPausedHandler = handlers.handle.get(IPC_CHANNELS.request.getPlaybackPaused);
|
const getPlaybackPausedHandler = handlers.handle.get(IPC_CHANNELS.request.getPlaybackPaused);
|
||||||
assert.ok(getPlaybackPausedHandler);
|
assert.ok(getPlaybackPausedHandler);
|
||||||
assert.equal(getPlaybackPausedHandler!({}), null);
|
assert.equal(getPlaybackPausedHandler!({}), null);
|
||||||
@@ -609,7 +571,6 @@ test('registerIpcHandlers records yomitan lookup when subtitle context recording
|
|||||||
test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => {
|
test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => {
|
||||||
const { registrar, handlers } = createFakeIpcRegistrar();
|
const { registrar, handlers } = createFakeIpcRegistrar();
|
||||||
const saves: unknown[] = [];
|
const saves: unknown[] = [];
|
||||||
const controllerSaves: unknown[] = [];
|
|
||||||
const closedModals: unknown[] = [];
|
const closedModals: unknown[] = [];
|
||||||
const openedModals: unknown[] = [];
|
const openedModals: unknown[] = [];
|
||||||
registerIpcHandlers(
|
registerIpcHandlers(
|
||||||
@@ -620,14 +581,9 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => {
|
|||||||
onOverlayModalOpened: (modal) => {
|
onOverlayModalOpened: (modal) => {
|
||||||
openedModals.push(modal);
|
openedModals.push(modal);
|
||||||
},
|
},
|
||||||
openYomitanSettings: () => {},
|
|
||||||
quitApp: () => {},
|
|
||||||
toggleDevTools: () => {},
|
toggleDevTools: () => {},
|
||||||
getVisibleOverlayVisibility: () => false,
|
|
||||||
toggleVisibleOverlay: () => {},
|
|
||||||
tokenizeCurrentSubtitle: async () => null,
|
tokenizeCurrentSubtitle: async () => null,
|
||||||
getCurrentSubtitleRaw: () => '',
|
getCurrentSubtitleRaw: () => '',
|
||||||
getCurrentSubtitleAss: () => '',
|
|
||||||
getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(),
|
getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(),
|
||||||
getPlaybackPaused: () => false,
|
getPlaybackPaused: () => false,
|
||||||
getSubtitlePosition: () => null,
|
getSubtitlePosition: () => null,
|
||||||
@@ -635,10 +591,7 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => {
|
|||||||
saveSubtitlePosition: (position) => {
|
saveSubtitlePosition: (position) => {
|
||||||
saves.push(position);
|
saves.push(position);
|
||||||
},
|
},
|
||||||
getMecabStatus: () => ({ available: false, enabled: false, path: null }),
|
|
||||||
setMecabEnabled: () => {},
|
|
||||||
handleMpvCommand: () => {},
|
handleMpvCommand: () => {},
|
||||||
getKeybindings: () => [],
|
|
||||||
getSessionBindings: () => [],
|
getSessionBindings: () => [],
|
||||||
getConfiguredShortcuts: () => ({}),
|
getConfiguredShortcuts: () => ({}),
|
||||||
dispatchSessionAction: async () => {},
|
dispatchSessionAction: async () => {},
|
||||||
@@ -647,24 +600,18 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => {
|
|||||||
getOverlayNotificationPosition: () => 'top-right',
|
getOverlayNotificationPosition: () => 'top-right',
|
||||||
getControllerConfig: () => createControllerConfigFixture(),
|
getControllerConfig: () => createControllerConfigFixture(),
|
||||||
saveControllerConfig: () => {},
|
saveControllerConfig: () => {},
|
||||||
saveControllerPreference: (update) => {
|
|
||||||
controllerSaves.push(update);
|
|
||||||
},
|
|
||||||
getSecondarySubMode: () => 'hover',
|
getSecondarySubMode: () => 'hover',
|
||||||
getCurrentSecondarySub: () => '',
|
getCurrentSecondarySub: () => '',
|
||||||
focusMainWindow: () => {},
|
focusMainWindow: () => {},
|
||||||
runSubsyncManual: async () => ({ ok: true, message: 'ok' }),
|
runSubsyncManual: async () => ({ ok: true, message: 'ok' }),
|
||||||
getAnkiConnectStatus: () => false,
|
|
||||||
getRuntimeOptions: () => [],
|
getRuntimeOptions: () => [],
|
||||||
setRuntimeOption: () => ({ ok: true }),
|
setRuntimeOption: () => ({ ok: true }),
|
||||||
cycleRuntimeOption: () => ({ ok: true }),
|
|
||||||
reportOverlayContentBounds: () => {},
|
reportOverlayContentBounds: () => {},
|
||||||
getAnilistStatus: () => ({}),
|
getAnilistStatus: () => ({}),
|
||||||
clearAnilistToken: () => {},
|
clearAnilistToken: () => {},
|
||||||
openAnilistSetup: () => {},
|
openAnilistSetup: () => {},
|
||||||
getAnilistQueueStatus: () => ({}),
|
getAnilistQueueStatus: () => ({}),
|
||||||
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
|
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
|
||||||
appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }),
|
|
||||||
getPlaylistBrowserSnapshot: async () => ({
|
getPlaylistBrowserSnapshot: async () => ({
|
||||||
directoryPath: null,
|
directoryPath: null,
|
||||||
directoryAvailable: false,
|
directoryAvailable: false,
|
||||||
@@ -698,96 +645,6 @@ test('registerIpcHandlers ignores malformed fire-and-forget payloads', () => {
|
|||||||
assert.deepEqual(openedModals, ['subsync', 'runtime-options']);
|
assert.deepEqual(openedModals, ['subsync', 'runtime-options']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('registerIpcHandlers awaits saveControllerPreference through request-response IPC', async () => {
|
|
||||||
const { registrar, handlers } = createFakeIpcRegistrar();
|
|
||||||
const controllerSaves: unknown[] = [];
|
|
||||||
registerIpcHandlers(
|
|
||||||
{
|
|
||||||
onOverlayModalClosed: () => {},
|
|
||||||
openYomitanSettings: () => {},
|
|
||||||
quitApp: () => {},
|
|
||||||
toggleDevTools: () => {},
|
|
||||||
getVisibleOverlayVisibility: () => false,
|
|
||||||
toggleVisibleOverlay: () => {},
|
|
||||||
tokenizeCurrentSubtitle: async () => null,
|
|
||||||
getCurrentSubtitleRaw: () => '',
|
|
||||||
getCurrentSubtitleAss: () => '',
|
|
||||||
getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(),
|
|
||||||
getPlaybackPaused: () => false,
|
|
||||||
getSubtitlePosition: () => null,
|
|
||||||
getSubtitleStyle: () => null,
|
|
||||||
saveSubtitlePosition: () => {},
|
|
||||||
getMecabStatus: () => ({ available: false, enabled: false, path: null }),
|
|
||||||
setMecabEnabled: () => {},
|
|
||||||
handleMpvCommand: () => {},
|
|
||||||
getKeybindings: () => [],
|
|
||||||
getSessionBindings: () => [],
|
|
||||||
getConfiguredShortcuts: () => ({}),
|
|
||||||
dispatchSessionAction: async () => {},
|
|
||||||
getStatsToggleKey: () => 'Backquote',
|
|
||||||
getMarkWatchedKey: () => 'KeyW',
|
|
||||||
getOverlayNotificationPosition: () => 'top-right',
|
|
||||||
getControllerConfig: () => createControllerConfigFixture(),
|
|
||||||
saveControllerConfig: async () => {},
|
|
||||||
saveControllerPreference: async (update) => {
|
|
||||||
await Promise.resolve();
|
|
||||||
controllerSaves.push(update);
|
|
||||||
},
|
|
||||||
getSecondarySubMode: () => 'hover',
|
|
||||||
getCurrentSecondarySub: () => '',
|
|
||||||
focusMainWindow: () => {},
|
|
||||||
runSubsyncManual: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
getAnkiConnectStatus: () => false,
|
|
||||||
getRuntimeOptions: () => [],
|
|
||||||
setRuntimeOption: () => ({ ok: true }),
|
|
||||||
cycleRuntimeOption: () => ({ ok: true }),
|
|
||||||
reportOverlayContentBounds: () => {},
|
|
||||||
getAnilistStatus: () => ({}),
|
|
||||||
clearAnilistToken: () => {},
|
|
||||||
openAnilistSetup: () => {},
|
|
||||||
getAnilistQueueStatus: () => ({}),
|
|
||||||
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }),
|
|
||||||
getPlaylistBrowserSnapshot: async () => ({
|
|
||||||
directoryPath: null,
|
|
||||||
directoryAvailable: false,
|
|
||||||
directoryStatus: '',
|
|
||||||
directoryItems: [],
|
|
||||||
playlistItems: [],
|
|
||||||
playingIndex: null,
|
|
||||||
currentFilePath: null,
|
|
||||||
}),
|
|
||||||
appendPlaylistBrowserFile: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
playPlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
removePlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
movePlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
onYoutubePickerResolve: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
},
|
|
||||||
registrar,
|
|
||||||
);
|
|
||||||
|
|
||||||
const saveHandler = handlers.handle.get(IPC_CHANNELS.command.saveControllerPreference);
|
|
||||||
assert.ok(saveHandler);
|
|
||||||
|
|
||||||
await assert.rejects(async () => {
|
|
||||||
await saveHandler!({}, { preferredGamepadId: 12 });
|
|
||||||
}, /Invalid controller preference payload/);
|
|
||||||
await saveHandler!(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
preferredGamepadId: 'pad-1',
|
|
||||||
preferredGamepadLabel: 'Pad 1',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.deepEqual(controllerSaves, [
|
|
||||||
{
|
|
||||||
preferredGamepadId: 'pad-1',
|
|
||||||
preferredGamepadLabel: 'Pad 1',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('registerIpcHandlers accepts per-controller profile config updates', async () => {
|
test('registerIpcHandlers accepts per-controller profile config updates', async () => {
|
||||||
const { registrar, handlers } = createFakeIpcRegistrar();
|
const { registrar, handlers } = createFakeIpcRegistrar();
|
||||||
const controllerSaves: unknown[] = [];
|
const controllerSaves: unknown[] = [];
|
||||||
@@ -975,76 +832,6 @@ test('registerIpcHandlers forwards valid overlay notification actions', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('registerIpcHandlers rejects malformed controller preference payloads', async () => {
|
|
||||||
const { registrar, handlers } = createFakeIpcRegistrar();
|
|
||||||
registerIpcHandlers(
|
|
||||||
{
|
|
||||||
onOverlayModalClosed: () => {},
|
|
||||||
openYomitanSettings: () => {},
|
|
||||||
quitApp: () => {},
|
|
||||||
toggleDevTools: () => {},
|
|
||||||
getVisibleOverlayVisibility: () => false,
|
|
||||||
toggleVisibleOverlay: () => {},
|
|
||||||
tokenizeCurrentSubtitle: async () => null,
|
|
||||||
getCurrentSubtitleRaw: () => '',
|
|
||||||
getCurrentSubtitleAss: () => '',
|
|
||||||
getSubtitleSidebarSnapshot: async () => createSubtitleSidebarSnapshotFixture(),
|
|
||||||
getPlaybackPaused: () => false,
|
|
||||||
getSubtitlePosition: () => null,
|
|
||||||
getSubtitleStyle: () => null,
|
|
||||||
saveSubtitlePosition: () => {},
|
|
||||||
getMecabStatus: () => ({ available: false, enabled: false, path: null }),
|
|
||||||
setMecabEnabled: () => {},
|
|
||||||
handleMpvCommand: () => {},
|
|
||||||
getKeybindings: () => [],
|
|
||||||
getSessionBindings: () => [],
|
|
||||||
getConfiguredShortcuts: () => ({}),
|
|
||||||
dispatchSessionAction: async () => {},
|
|
||||||
getStatsToggleKey: () => 'Backquote',
|
|
||||||
getMarkWatchedKey: () => 'KeyW',
|
|
||||||
getOverlayNotificationPosition: () => 'top-right',
|
|
||||||
getControllerConfig: () => createControllerConfigFixture(),
|
|
||||||
saveControllerConfig: async () => {},
|
|
||||||
saveControllerPreference: async () => {},
|
|
||||||
getSecondarySubMode: () => 'hover',
|
|
||||||
getCurrentSecondarySub: () => '',
|
|
||||||
focusMainWindow: () => {},
|
|
||||||
runSubsyncManual: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
getAnkiConnectStatus: () => false,
|
|
||||||
getRuntimeOptions: () => [],
|
|
||||||
setRuntimeOption: () => ({ ok: true }),
|
|
||||||
cycleRuntimeOption: () => ({ ok: true }),
|
|
||||||
reportOverlayContentBounds: () => {},
|
|
||||||
getAnilistStatus: () => ({}),
|
|
||||||
clearAnilistToken: () => {},
|
|
||||||
openAnilistSetup: () => {},
|
|
||||||
getAnilistQueueStatus: () => ({}),
|
|
||||||
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }),
|
|
||||||
getPlaylistBrowserSnapshot: async () => ({
|
|
||||||
directoryPath: null,
|
|
||||||
directoryAvailable: false,
|
|
||||||
directoryStatus: '',
|
|
||||||
directoryItems: [],
|
|
||||||
playlistItems: [],
|
|
||||||
playingIndex: null,
|
|
||||||
currentFilePath: null,
|
|
||||||
}),
|
|
||||||
appendPlaylistBrowserFile: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
playPlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
removePlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
movePlaylistBrowserIndex: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
onYoutubePickerResolve: async () => ({ ok: true, message: 'ok' }),
|
|
||||||
},
|
|
||||||
registrar,
|
|
||||||
);
|
|
||||||
|
|
||||||
const saveHandler = handlers.handle.get(IPC_CHANNELS.command.saveControllerPreference);
|
|
||||||
await assert.rejects(async () => {
|
|
||||||
await saveHandler!({}, { preferredGamepadId: 12 });
|
|
||||||
}, /Invalid controller preference payload/);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('registerIpcHandlers exposes character dictionary selection handlers', async () => {
|
test('registerIpcHandlers exposes character dictionary selection handlers', async () => {
|
||||||
const { registrar, handlers } = createFakeIpcRegistrar();
|
const { registrar, handlers } = createFakeIpcRegistrar();
|
||||||
const calls: number[] = [];
|
const calls: number[] = [];
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import type {
|
|||||||
ControllerConfigUpdate,
|
ControllerConfigUpdate,
|
||||||
PlaylistBrowserMutationResult,
|
PlaylistBrowserMutationResult,
|
||||||
PlaylistBrowserSnapshot,
|
PlaylistBrowserSnapshot,
|
||||||
ControllerPreferenceUpdate,
|
|
||||||
ResolvedControllerConfig,
|
ResolvedControllerConfig,
|
||||||
RuntimeOptionId,
|
RuntimeOptionId,
|
||||||
RuntimeOptionValue,
|
RuntimeOptionValue,
|
||||||
@@ -34,10 +33,8 @@ import { IPC_CHANNELS, type OverlayHostedModal } from '../../shared/ipc/contract
|
|||||||
import {
|
import {
|
||||||
parseMpvCommand,
|
parseMpvCommand,
|
||||||
parseControllerConfigUpdate,
|
parseControllerConfigUpdate,
|
||||||
parseControllerPreferenceUpdate,
|
|
||||||
parseOptionalForwardingOptions,
|
parseOptionalForwardingOptions,
|
||||||
parseOverlayHostedModal,
|
parseOverlayHostedModal,
|
||||||
parseRuntimeOptionDirection,
|
|
||||||
parseRuntimeOptionId,
|
parseRuntimeOptionId,
|
||||||
parseRuntimeOptionValue,
|
parseRuntimeOptionValue,
|
||||||
parseSessionActionDispatchRequest,
|
parseSessionActionDispatchRequest,
|
||||||
@@ -71,14 +68,9 @@ export interface IpcServiceDeps {
|
|||||||
actionId: string,
|
actionId: string,
|
||||||
noteId?: number,
|
noteId?: number,
|
||||||
) => void | Promise<void>;
|
) => void | Promise<void>;
|
||||||
openYomitanSettings: () => void;
|
|
||||||
quitApp: () => void;
|
|
||||||
toggleDevTools: () => void;
|
toggleDevTools: () => void;
|
||||||
getVisibleOverlayVisibility: () => boolean;
|
|
||||||
toggleVisibleOverlay: () => void;
|
|
||||||
tokenizeCurrentSubtitle: () => Promise<unknown>;
|
tokenizeCurrentSubtitle: () => Promise<unknown>;
|
||||||
getCurrentSubtitleRaw: () => string;
|
getCurrentSubtitleRaw: () => string;
|
||||||
getCurrentSubtitleAss: () => string;
|
|
||||||
getSubtitleSidebarSnapshot?: () => Promise<SubtitleSidebarSnapshot>;
|
getSubtitleSidebarSnapshot?: () => Promise<SubtitleSidebarSnapshot>;
|
||||||
getSubtitleSidebarPlaybackState?: () => SubtitleSidebarPlaybackState;
|
getSubtitleSidebarPlaybackState?: () => SubtitleSidebarPlaybackState;
|
||||||
getSubtitleSidebarOpen?: () => boolean;
|
getSubtitleSidebarOpen?: () => boolean;
|
||||||
@@ -86,14 +78,7 @@ export interface IpcServiceDeps {
|
|||||||
getSubtitlePosition: () => unknown;
|
getSubtitlePosition: () => unknown;
|
||||||
getSubtitleStyle: () => unknown;
|
getSubtitleStyle: () => unknown;
|
||||||
saveSubtitlePosition: (position: SubtitlePosition) => void;
|
saveSubtitlePosition: (position: SubtitlePosition) => void;
|
||||||
getMecabStatus: () => {
|
|
||||||
available: boolean;
|
|
||||||
enabled: boolean;
|
|
||||||
path: string | null;
|
|
||||||
};
|
|
||||||
setMecabEnabled: (enabled: boolean) => void;
|
|
||||||
handleMpvCommand: (command: Array<string | number>) => void;
|
handleMpvCommand: (command: Array<string | number>) => void;
|
||||||
getKeybindings: () => unknown;
|
|
||||||
getMpvInputBindings?: () => Promise<MpvInputBindingsSnapshot>;
|
getMpvInputBindings?: () => Promise<MpvInputBindingsSnapshot>;
|
||||||
getSessionBindings?: () => CompiledSessionBinding[] | Promise<CompiledSessionBinding[]>;
|
getSessionBindings?: () => CompiledSessionBinding[] | Promise<CompiledSessionBinding[]>;
|
||||||
getConfiguredShortcuts: () => unknown;
|
getConfiguredShortcuts: () => unknown;
|
||||||
@@ -103,7 +88,6 @@ export interface IpcServiceDeps {
|
|||||||
getOverlayNotificationPosition: () => string;
|
getOverlayNotificationPosition: () => string;
|
||||||
getControllerConfig: () => ResolvedControllerConfig;
|
getControllerConfig: () => ResolvedControllerConfig;
|
||||||
saveControllerConfig: (update: ControllerConfigUpdate) => void | Promise<void>;
|
saveControllerConfig: (update: ControllerConfigUpdate) => void | Promise<void>;
|
||||||
saveControllerPreference: (update: ControllerPreferenceUpdate) => void | Promise<void>;
|
|
||||||
getSecondarySubMode: () => unknown;
|
getSecondarySubMode: () => unknown;
|
||||||
getCurrentSecondarySub: () => string;
|
getCurrentSecondarySub: () => string;
|
||||||
focusMainWindow: () => void;
|
focusMainWindow: () => void;
|
||||||
@@ -125,10 +109,8 @@ export interface IpcServiceDeps {
|
|||||||
resolveMediaTimingReview?: (
|
resolveMediaTimingReview?: (
|
||||||
request: MediaTimingReviewResolveRequest,
|
request: MediaTimingReviewResolveRequest,
|
||||||
) => MediaTimingReviewActionResult | Promise<MediaTimingReviewActionResult>;
|
) => MediaTimingReviewActionResult | Promise<MediaTimingReviewActionResult>;
|
||||||
getAnkiConnectStatus: () => boolean;
|
|
||||||
getRuntimeOptions: () => unknown;
|
getRuntimeOptions: () => unknown;
|
||||||
setRuntimeOption: (id: RuntimeOptionId, value: RuntimeOptionValue) => unknown;
|
setRuntimeOption: (id: RuntimeOptionId, value: RuntimeOptionValue) => unknown;
|
||||||
cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => unknown;
|
|
||||||
reportOverlayContentBounds: (
|
reportOverlayContentBounds: (
|
||||||
payload: unknown,
|
payload: unknown,
|
||||||
senderWindow: ElectronBrowserWindow | null,
|
senderWindow: ElectronBrowserWindow | null,
|
||||||
@@ -149,7 +131,6 @@ export interface IpcServiceDeps {
|
|||||||
getCharacterDictionaryManagerSnapshot?: () => Promise<unknown>;
|
getCharacterDictionaryManagerSnapshot?: () => Promise<unknown>;
|
||||||
removeCharacterDictionaryManagedEntry?: (mediaId: number) => Promise<unknown>;
|
removeCharacterDictionaryManagedEntry?: (mediaId: number) => Promise<unknown>;
|
||||||
moveCharacterDictionaryManagedEntry?: (mediaId: number, direction: 1 | -1) => Promise<unknown>;
|
moveCharacterDictionaryManagedEntry?: (mediaId: number, direction: 1 | -1) => Promise<unknown>;
|
||||||
appendClipboardVideoToQueue: () => { ok: boolean; message: string };
|
|
||||||
getChangelogSnapshot?: (options?: { refresh?: boolean }) => Promise<ChangelogSnapshot>;
|
getChangelogSnapshot?: (options?: { refresh?: boolean }) => Promise<ChangelogSnapshot>;
|
||||||
getPlaylistBrowserSnapshot: () => Promise<PlaylistBrowserSnapshot>;
|
getPlaylistBrowserSnapshot: () => Promise<PlaylistBrowserSnapshot>;
|
||||||
appendPlaylistBrowserFile: (filePath: string) => Promise<PlaylistBrowserMutationResult>;
|
appendPlaylistBrowserFile: (filePath: string) => Promise<PlaylistBrowserMutationResult>;
|
||||||
@@ -174,15 +155,6 @@ interface WindowLike {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MecabTokenizerLike {
|
|
||||||
getStatus: () => {
|
|
||||||
available: boolean;
|
|
||||||
enabled: boolean;
|
|
||||||
path: string | null;
|
|
||||||
};
|
|
||||||
setEnabled: (enabled: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MpvClientLike {
|
interface MpvClientLike {
|
||||||
currentSecondarySubText?: string;
|
currentSecondarySubText?: string;
|
||||||
}
|
}
|
||||||
@@ -342,7 +314,6 @@ function parseMediaTimingReviewResolveRequest(
|
|||||||
|
|
||||||
export interface IpcDepsRuntimeOptions {
|
export interface IpcDepsRuntimeOptions {
|
||||||
getMainWindow: () => WindowLike | null;
|
getMainWindow: () => WindowLike | null;
|
||||||
getVisibleOverlayVisibility: () => boolean;
|
|
||||||
onOverlayModalClosed: (
|
onOverlayModalClosed: (
|
||||||
modal: OverlayHostedModal,
|
modal: OverlayHostedModal,
|
||||||
senderWindow: ElectronBrowserWindow | null,
|
senderWindow: ElectronBrowserWindow | null,
|
||||||
@@ -364,12 +335,8 @@ export interface IpcDepsRuntimeOptions {
|
|||||||
actionId: string,
|
actionId: string,
|
||||||
noteId?: number,
|
noteId?: number,
|
||||||
) => void | Promise<void>;
|
) => void | Promise<void>;
|
||||||
openYomitanSettings: () => void;
|
|
||||||
quitApp: () => void;
|
|
||||||
toggleVisibleOverlay: () => void;
|
|
||||||
tokenizeCurrentSubtitle: () => Promise<unknown>;
|
tokenizeCurrentSubtitle: () => Promise<unknown>;
|
||||||
getCurrentSubtitleRaw: () => string;
|
getCurrentSubtitleRaw: () => string;
|
||||||
getCurrentSubtitleAss: () => string;
|
|
||||||
getSubtitleSidebarSnapshot?: () => Promise<SubtitleSidebarSnapshot>;
|
getSubtitleSidebarSnapshot?: () => Promise<SubtitleSidebarSnapshot>;
|
||||||
getSubtitleSidebarPlaybackState?: () => SubtitleSidebarPlaybackState;
|
getSubtitleSidebarPlaybackState?: () => SubtitleSidebarPlaybackState;
|
||||||
getSubtitleSidebarOpen?: () => boolean;
|
getSubtitleSidebarOpen?: () => boolean;
|
||||||
@@ -377,9 +344,7 @@ export interface IpcDepsRuntimeOptions {
|
|||||||
getSubtitlePosition: () => unknown;
|
getSubtitlePosition: () => unknown;
|
||||||
getSubtitleStyle: () => unknown;
|
getSubtitleStyle: () => unknown;
|
||||||
saveSubtitlePosition: (position: SubtitlePosition) => void;
|
saveSubtitlePosition: (position: SubtitlePosition) => void;
|
||||||
getMecabTokenizer: () => MecabTokenizerLike | null;
|
|
||||||
handleMpvCommand: (command: Array<string | number>) => void;
|
handleMpvCommand: (command: Array<string | number>) => void;
|
||||||
getKeybindings: () => unknown;
|
|
||||||
getMpvInputBindings?: () => Promise<MpvInputBindingsSnapshot>;
|
getMpvInputBindings?: () => Promise<MpvInputBindingsSnapshot>;
|
||||||
getSessionBindings?: () => CompiledSessionBinding[] | Promise<CompiledSessionBinding[]>;
|
getSessionBindings?: () => CompiledSessionBinding[] | Promise<CompiledSessionBinding[]>;
|
||||||
getConfiguredShortcuts: () => unknown;
|
getConfiguredShortcuts: () => unknown;
|
||||||
@@ -389,7 +354,6 @@ export interface IpcDepsRuntimeOptions {
|
|||||||
getOverlayNotificationPosition: () => string;
|
getOverlayNotificationPosition: () => string;
|
||||||
getControllerConfig: () => ResolvedControllerConfig;
|
getControllerConfig: () => ResolvedControllerConfig;
|
||||||
saveControllerConfig: (update: ControllerConfigUpdate) => void | Promise<void>;
|
saveControllerConfig: (update: ControllerConfigUpdate) => void | Promise<void>;
|
||||||
saveControllerPreference: (update: ControllerPreferenceUpdate) => void | Promise<void>;
|
|
||||||
getSecondarySubMode: () => unknown;
|
getSecondarySubMode: () => unknown;
|
||||||
getMpvClient: () => MpvClientLike | null;
|
getMpvClient: () => MpvClientLike | null;
|
||||||
focusMainWindow: () => void;
|
focusMainWindow: () => void;
|
||||||
@@ -403,10 +367,8 @@ export interface IpcDepsRuntimeOptions {
|
|||||||
getMediaTimingReviewWaveform?: IpcServiceDeps['getMediaTimingReviewWaveform'];
|
getMediaTimingReviewWaveform?: IpcServiceDeps['getMediaTimingReviewWaveform'];
|
||||||
stopMediaTimingReviewPreview?: IpcServiceDeps['stopMediaTimingReviewPreview'];
|
stopMediaTimingReviewPreview?: IpcServiceDeps['stopMediaTimingReviewPreview'];
|
||||||
resolveMediaTimingReview?: IpcServiceDeps['resolveMediaTimingReview'];
|
resolveMediaTimingReview?: IpcServiceDeps['resolveMediaTimingReview'];
|
||||||
getAnkiConnectStatus: () => boolean;
|
|
||||||
getRuntimeOptions: () => unknown;
|
getRuntimeOptions: () => unknown;
|
||||||
setRuntimeOption: (id: RuntimeOptionId, value: RuntimeOptionValue) => unknown;
|
setRuntimeOption: (id: RuntimeOptionId, value: RuntimeOptionValue) => unknown;
|
||||||
cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => unknown;
|
|
||||||
reportOverlayContentBounds: (payload: unknown) => void;
|
reportOverlayContentBounds: (payload: unknown) => void;
|
||||||
getAnilistStatus: () => unknown;
|
getAnilistStatus: () => unknown;
|
||||||
clearAnilistToken: () => void;
|
clearAnilistToken: () => void;
|
||||||
@@ -424,7 +386,6 @@ export interface IpcDepsRuntimeOptions {
|
|||||||
getCharacterDictionaryManagerSnapshot?: () => Promise<unknown>;
|
getCharacterDictionaryManagerSnapshot?: () => Promise<unknown>;
|
||||||
removeCharacterDictionaryManagedEntry?: (mediaId: number) => Promise<unknown>;
|
removeCharacterDictionaryManagedEntry?: (mediaId: number) => Promise<unknown>;
|
||||||
moveCharacterDictionaryManagedEntry?: (mediaId: number, direction: 1 | -1) => Promise<unknown>;
|
moveCharacterDictionaryManagedEntry?: (mediaId: number, direction: 1 | -1) => Promise<unknown>;
|
||||||
appendClipboardVideoToQueue: () => { ok: boolean; message: string };
|
|
||||||
getChangelogSnapshot?: (options?: { refresh?: boolean }) => Promise<ChangelogSnapshot>;
|
getChangelogSnapshot?: (options?: { refresh?: boolean }) => Promise<ChangelogSnapshot>;
|
||||||
getPlaylistBrowserSnapshot: () => Promise<PlaylistBrowserSnapshot>;
|
getPlaylistBrowserSnapshot: () => Promise<PlaylistBrowserSnapshot>;
|
||||||
appendPlaylistBrowserFile: (filePath: string) => Promise<PlaylistBrowserMutationResult>;
|
appendPlaylistBrowserFile: (filePath: string) => Promise<PlaylistBrowserMutationResult>;
|
||||||
@@ -444,19 +405,14 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService
|
|||||||
onOverlayMouseInteractionChanged: options.onOverlayMouseInteractionChanged,
|
onOverlayMouseInteractionChanged: options.onOverlayMouseInteractionChanged,
|
||||||
onOverlayInteractiveHint: options.onOverlayInteractiveHint,
|
onOverlayInteractiveHint: options.onOverlayInteractiveHint,
|
||||||
handleOverlayNotificationAction: options.handleOverlayNotificationAction,
|
handleOverlayNotificationAction: options.handleOverlayNotificationAction,
|
||||||
openYomitanSettings: options.openYomitanSettings,
|
|
||||||
recordSubtitleMiningContext: options.recordSubtitleMiningContext,
|
recordSubtitleMiningContext: options.recordSubtitleMiningContext,
|
||||||
quitApp: options.quitApp,
|
|
||||||
toggleDevTools: () => {
|
toggleDevTools: () => {
|
||||||
const mainWindow = options.getMainWindow();
|
const mainWindow = options.getMainWindow();
|
||||||
if (!mainWindow || mainWindow.isDestroyed()) return;
|
if (!mainWindow || mainWindow.isDestroyed()) return;
|
||||||
mainWindow.webContents.toggleDevTools();
|
mainWindow.webContents.toggleDevTools();
|
||||||
},
|
},
|
||||||
getVisibleOverlayVisibility: options.getVisibleOverlayVisibility,
|
|
||||||
toggleVisibleOverlay: options.toggleVisibleOverlay,
|
|
||||||
tokenizeCurrentSubtitle: options.tokenizeCurrentSubtitle,
|
tokenizeCurrentSubtitle: options.tokenizeCurrentSubtitle,
|
||||||
getCurrentSubtitleRaw: options.getCurrentSubtitleRaw,
|
getCurrentSubtitleRaw: options.getCurrentSubtitleRaw,
|
||||||
getCurrentSubtitleAss: options.getCurrentSubtitleAss,
|
|
||||||
getSubtitleSidebarSnapshot: options.getSubtitleSidebarSnapshot,
|
getSubtitleSidebarSnapshot: options.getSubtitleSidebarSnapshot,
|
||||||
getSubtitleSidebarPlaybackState: options.getSubtitleSidebarPlaybackState,
|
getSubtitleSidebarPlaybackState: options.getSubtitleSidebarPlaybackState,
|
||||||
getSubtitleSidebarOpen: options.getSubtitleSidebarOpen ?? (() => false),
|
getSubtitleSidebarOpen: options.getSubtitleSidebarOpen ?? (() => false),
|
||||||
@@ -464,19 +420,7 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService
|
|||||||
getSubtitlePosition: options.getSubtitlePosition,
|
getSubtitlePosition: options.getSubtitlePosition,
|
||||||
getSubtitleStyle: options.getSubtitleStyle,
|
getSubtitleStyle: options.getSubtitleStyle,
|
||||||
saveSubtitlePosition: options.saveSubtitlePosition,
|
saveSubtitlePosition: options.saveSubtitlePosition,
|
||||||
getMecabStatus: () => {
|
|
||||||
const mecabTokenizer = options.getMecabTokenizer();
|
|
||||||
return mecabTokenizer
|
|
||||||
? mecabTokenizer.getStatus()
|
|
||||||
: { available: false, enabled: false, path: null };
|
|
||||||
},
|
|
||||||
setMecabEnabled: (enabled) => {
|
|
||||||
const mecabTokenizer = options.getMecabTokenizer();
|
|
||||||
if (!mecabTokenizer) return;
|
|
||||||
mecabTokenizer.setEnabled(enabled);
|
|
||||||
},
|
|
||||||
handleMpvCommand: options.handleMpvCommand,
|
handleMpvCommand: options.handleMpvCommand,
|
||||||
getKeybindings: options.getKeybindings,
|
|
||||||
getMpvInputBindings: options.getMpvInputBindings,
|
getMpvInputBindings: options.getMpvInputBindings,
|
||||||
getSessionBindings: options.getSessionBindings ?? (() => []),
|
getSessionBindings: options.getSessionBindings ?? (() => []),
|
||||||
getConfiguredShortcuts: options.getConfiguredShortcuts,
|
getConfiguredShortcuts: options.getConfiguredShortcuts,
|
||||||
@@ -486,7 +430,6 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService
|
|||||||
getOverlayNotificationPosition: options.getOverlayNotificationPosition,
|
getOverlayNotificationPosition: options.getOverlayNotificationPosition,
|
||||||
getControllerConfig: options.getControllerConfig,
|
getControllerConfig: options.getControllerConfig,
|
||||||
saveControllerConfig: options.saveControllerConfig,
|
saveControllerConfig: options.saveControllerConfig,
|
||||||
saveControllerPreference: options.saveControllerPreference,
|
|
||||||
getSecondarySubMode: options.getSecondarySubMode,
|
getSecondarySubMode: options.getSecondarySubMode,
|
||||||
getCurrentSecondarySub: () => options.getMpvClient()?.currentSecondarySubText || '',
|
getCurrentSecondarySub: () => options.getMpvClient()?.currentSecondarySubText || '',
|
||||||
focusMainWindow: () => {
|
focusMainWindow: () => {
|
||||||
@@ -503,10 +446,8 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService
|
|||||||
getMediaTimingReviewWaveform: options.getMediaTimingReviewWaveform,
|
getMediaTimingReviewWaveform: options.getMediaTimingReviewWaveform,
|
||||||
stopMediaTimingReviewPreview: options.stopMediaTimingReviewPreview,
|
stopMediaTimingReviewPreview: options.stopMediaTimingReviewPreview,
|
||||||
resolveMediaTimingReview: options.resolveMediaTimingReview,
|
resolveMediaTimingReview: options.resolveMediaTimingReview,
|
||||||
getAnkiConnectStatus: options.getAnkiConnectStatus,
|
|
||||||
getRuntimeOptions: options.getRuntimeOptions,
|
getRuntimeOptions: options.getRuntimeOptions,
|
||||||
setRuntimeOption: options.setRuntimeOption,
|
setRuntimeOption: options.setRuntimeOption,
|
||||||
cycleRuntimeOption: options.cycleRuntimeOption,
|
|
||||||
reportOverlayContentBounds: (payload, senderWindow) => {
|
reportOverlayContentBounds: (payload, senderWindow) => {
|
||||||
const mainWindow = options.getMainWindow();
|
const mainWindow = options.getMainWindow();
|
||||||
if (!mainWindow || mainWindow.isDestroyed()) return;
|
if (!mainWindow || mainWindow.isDestroyed()) return;
|
||||||
@@ -553,7 +494,6 @@ export function createIpcDepsRuntime(options: IpcDepsRuntimeOptions): IpcService
|
|||||||
message: 'Character dictionary manager unavailable.',
|
message: 'Character dictionary manager unavailable.',
|
||||||
entries: [],
|
entries: [],
|
||||||
})),
|
})),
|
||||||
appendClipboardVideoToQueue: options.appendClipboardVideoToQueue,
|
|
||||||
getChangelogSnapshot: options.getChangelogSnapshot,
|
getChangelogSnapshot: options.getChangelogSnapshot,
|
||||||
getPlaylistBrowserSnapshot: options.getPlaylistBrowserSnapshot,
|
getPlaylistBrowserSnapshot: options.getPlaylistBrowserSnapshot,
|
||||||
appendPlaylistBrowserFile: options.appendPlaylistBrowserFile,
|
appendPlaylistBrowserFile: options.appendPlaylistBrowserFile,
|
||||||
@@ -680,10 +620,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
ipc.on(IPC_CHANNELS.command.openYomitanSettings, () => {
|
|
||||||
deps.openYomitanSettings();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.on(IPC_CHANNELS.command.recordYomitanLookup, (_event: unknown, payload: unknown) => {
|
ipc.on(IPC_CHANNELS.command.recordYomitanLookup, (_event: unknown, payload: unknown) => {
|
||||||
try {
|
try {
|
||||||
deps.recordSubtitleMiningContext?.(parseSubtitleMiningContext(payload));
|
deps.recordSubtitleMiningContext?.(parseSubtitleMiningContext(payload));
|
||||||
@@ -711,22 +647,10 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
|
|||||||
return marked;
|
return marked;
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.on(IPC_CHANNELS.command.quitApp, () => {
|
|
||||||
deps.quitApp();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.on(IPC_CHANNELS.command.toggleDevTools, () => {
|
ipc.on(IPC_CHANNELS.command.toggleDevTools, () => {
|
||||||
deps.toggleDevTools();
|
deps.toggleDevTools();
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.on(IPC_CHANNELS.command.toggleOverlay, () => {
|
|
||||||
deps.toggleVisibleOverlay();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.getVisibleOverlayVisibility, () => {
|
|
||||||
return deps.getVisibleOverlayVisibility();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.getCurrentSubtitle, async () => {
|
ipc.handle(IPC_CHANNELS.request.getCurrentSubtitle, async () => {
|
||||||
return await deps.tokenizeCurrentSubtitle();
|
return await deps.tokenizeCurrentSubtitle();
|
||||||
});
|
});
|
||||||
@@ -735,10 +659,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
|
|||||||
return deps.getCurrentSubtitleRaw();
|
return deps.getCurrentSubtitleRaw();
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.getCurrentSubtitleAss, () => {
|
|
||||||
return deps.getCurrentSubtitleAss();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.getSubtitleSidebarSnapshot, async () => {
|
ipc.handle(IPC_CHANNELS.request.getSubtitleSidebarSnapshot, async () => {
|
||||||
if (!deps.getSubtitleSidebarSnapshot) {
|
if (!deps.getSubtitleSidebarSnapshot) {
|
||||||
throw new Error('Subtitle sidebar snapshot is unavailable.');
|
throw new Error('Subtitle sidebar snapshot is unavailable.');
|
||||||
@@ -775,17 +695,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
|
|||||||
deps.saveSubtitlePosition(parsedPosition);
|
deps.saveSubtitlePosition(parsedPosition);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.handle(
|
|
||||||
IPC_CHANNELS.command.saveControllerPreference,
|
|
||||||
async (_event: unknown, update: unknown) => {
|
|
||||||
const parsedUpdate = parseControllerPreferenceUpdate(update);
|
|
||||||
if (!parsedUpdate) {
|
|
||||||
throw new Error('Invalid controller preference payload');
|
|
||||||
}
|
|
||||||
await deps.saveControllerPreference(parsedUpdate);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
ipc.handle(
|
ipc.handle(
|
||||||
IPC_CHANNELS.command.saveControllerConfig,
|
IPC_CHANNELS.command.saveControllerConfig,
|
||||||
async (_event: unknown, update: unknown) => {
|
async (_event: unknown, update: unknown) => {
|
||||||
@@ -797,15 +706,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.getMecabStatus, () => {
|
|
||||||
return deps.getMecabStatus();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.on(IPC_CHANNELS.command.setMecabEnabled, (_event: unknown, enabled: unknown) => {
|
|
||||||
if (typeof enabled !== 'boolean') return;
|
|
||||||
deps.setMecabEnabled(enabled);
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.on(IPC_CHANNELS.command.mpvCommand, (_event: unknown, command: unknown) => {
|
ipc.on(IPC_CHANNELS.command.mpvCommand, (_event: unknown, command: unknown) => {
|
||||||
const parsedCommand = parseMpvCommand(command);
|
const parsedCommand = parseMpvCommand(command);
|
||||||
if (!parsedCommand) return;
|
if (!parsedCommand) return;
|
||||||
@@ -823,10 +723,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.getKeybindings, () => {
|
|
||||||
return deps.getKeybindings();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.getMpvInputBindings, () => {
|
ipc.handle(IPC_CHANNELS.request.getMpvInputBindings, () => {
|
||||||
return deps.getMpvInputBindings?.() ?? { keys: [], blockedKeys: [] };
|
return deps.getMpvInputBindings?.() ?? { keys: [], blockedKeys: [] };
|
||||||
});
|
});
|
||||||
@@ -879,10 +775,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
|
|||||||
return await deps.runSubsyncManual(parsedRequest);
|
return await deps.runSubsyncManual(parsedRequest);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.getAnkiConnectStatus, () => {
|
|
||||||
return deps.getAnkiConnectStatus();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.getRuntimeOptions, () => {
|
ipc.handle(IPC_CHANNELS.request.getRuntimeOptions, () => {
|
||||||
return deps.getRuntimeOptions();
|
return deps.getRuntimeOptions();
|
||||||
});
|
});
|
||||||
@@ -899,18 +791,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
|
|||||||
return deps.setRuntimeOption(parsedId, parsedValue);
|
return deps.setRuntimeOption(parsedId, parsedValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.cycleRuntimeOption, (_event, id: unknown, direction: unknown) => {
|
|
||||||
const parsedId = parseRuntimeOptionId(id);
|
|
||||||
if (!parsedId) {
|
|
||||||
return { ok: false, error: 'Invalid runtime option id' };
|
|
||||||
}
|
|
||||||
const parsedDirection = parseRuntimeOptionDirection(direction);
|
|
||||||
if (!parsedDirection) {
|
|
||||||
return { ok: false, error: 'Invalid runtime option cycle direction' };
|
|
||||||
}
|
|
||||||
return deps.cycleRuntimeOption(parsedId, parsedDirection);
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.on(IPC_CHANNELS.command.reportOverlayContentBounds, (event: unknown, payload: unknown) => {
|
ipc.on(IPC_CHANNELS.command.reportOverlayContentBounds, (event: unknown, payload: unknown) => {
|
||||||
const senderWindow =
|
const senderWindow =
|
||||||
electron.BrowserWindow?.fromWebContents((event as IpcMainEvent).sender) ?? null;
|
electron.BrowserWindow?.fromWebContents((event as IpcMainEvent).sender) ?? null;
|
||||||
@@ -1020,10 +900,6 @@ export function registerIpcHandlers(deps: IpcServiceDeps, ipc: IpcMainRegistrar
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.appendClipboardVideoToQueue, () => {
|
|
||||||
return deps.appendClipboardVideoToQueue();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipc.handle(IPC_CHANNELS.request.getChangelogSnapshot, async (_event, payload: unknown) => {
|
ipc.handle(IPC_CHANNELS.request.getChangelogSnapshot, async (_event, payload: unknown) => {
|
||||||
const refresh =
|
const refresh =
|
||||||
typeof payload === 'object' && payload !== null && 'refresh' in payload
|
typeof payload === 'object' && payload !== null && 'refresh' in payload
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import {
|
|||||||
MPV_REQUEST_ID_SUB_SHADOW_OFFSET,
|
MPV_REQUEST_ID_SUB_SHADOW_OFFSET,
|
||||||
MPV_REQUEST_ID_SUB_SPACING,
|
MPV_REQUEST_ID_SUB_SPACING,
|
||||||
MPV_REQUEST_ID_SUBTEXT,
|
MPV_REQUEST_ID_SUBTEXT,
|
||||||
MPV_REQUEST_ID_SUBTEXT_ASS,
|
|
||||||
MPV_REQUEST_ID_SUB_USE_MARGINS,
|
MPV_REQUEST_ID_SUB_USE_MARGINS,
|
||||||
MPV_REQUEST_ID_PAUSE,
|
MPV_REQUEST_ID_PAUSE,
|
||||||
} from './mpv-protocol';
|
} from './mpv-protocol';
|
||||||
@@ -54,7 +53,6 @@ const MPV_SUBTITLE_PROPERTY_OBSERVATIONS: string[] = [
|
|||||||
'sub-scale-by-window',
|
'sub-scale-by-window',
|
||||||
'osd-height',
|
'osd-height',
|
||||||
'osd-dimensions',
|
'osd-dimensions',
|
||||||
'sub-text/ass',
|
|
||||||
'sub-border-size',
|
'sub-border-size',
|
||||||
'sub-shadow-offset',
|
'sub-shadow-offset',
|
||||||
'sub-ass-override',
|
'sub-ass-override',
|
||||||
@@ -76,10 +74,6 @@ const MPV_INITIAL_PROPERTY_REQUESTS: Array<MpvProtocolCommand> = [
|
|||||||
command: ['get_property', 'sub-text'],
|
command: ['get_property', 'sub-text'],
|
||||||
request_id: MPV_REQUEST_ID_SUBTEXT,
|
request_id: MPV_REQUEST_ID_SUBTEXT,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
command: ['get_property', 'sub-text/ass'],
|
|
||||||
request_id: MPV_REQUEST_ID_SUBTEXT_ASS,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
command: ['get_property', 'path'],
|
command: ['get_property', 'path'],
|
||||||
request_id: MPV_REQUEST_ID_PATH,
|
request_id: MPV_REQUEST_ID_PATH,
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ function createDeps(overrides: Partial<MpvProtocolHandleMessageDeps> = {}): {
|
|||||||
getSubtitleMetrics: () => metrics,
|
getSubtitleMetrics: () => metrics,
|
||||||
isVisibleOverlayVisible: () => false,
|
isVisibleOverlayVisible: () => false,
|
||||||
emitSubtitleChange: (payload) => state.events.push(payload),
|
emitSubtitleChange: (payload) => state.events.push(payload),
|
||||||
emitSubtitleAssChange: (payload) => state.events.push(payload),
|
|
||||||
emitSubtitleTiming: (payload) => state.events.push(payload),
|
emitSubtitleTiming: (payload) => state.events.push(payload),
|
||||||
emitSecondarySubtitleChange: (payload) => state.events.push(payload),
|
emitSecondarySubtitleChange: (payload) => state.events.push(payload),
|
||||||
emitSubtitleTrackChange: (payload) => state.events.push(payload),
|
emitSubtitleTrackChange: (payload) => state.events.push(payload),
|
||||||
@@ -132,28 +131,6 @@ test('dispatchMpvProtocolMessage emits subtitle text on property change', async
|
|||||||
assert.deepEqual(state.events, [{ text: '字幕', isOverlayVisible: false }]);
|
assert.deepEqual(state.events, [{ text: '字幕', isOverlayVisible: false }]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('dispatchMpvProtocolMessage emits ASS subtitle text from the current mpv property', async () => {
|
|
||||||
const { deps, state } = createDeps();
|
|
||||||
|
|
||||||
await dispatchMpvProtocolMessage(
|
|
||||||
{ event: 'property-change', name: 'sub-text/ass', data: '{\\b1}字幕' },
|
|
||||||
deps,
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.deepEqual(state.events, [{ text: '{\\b1}字幕' }]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('dispatchMpvProtocolMessage emits ASS subtitle text from the legacy mpv property', async () => {
|
|
||||||
const { deps, state } = createDeps();
|
|
||||||
|
|
||||||
await dispatchMpvProtocolMessage(
|
|
||||||
{ event: 'property-change', name: 'sub-text-ass', data: '{\\b1}字幕' },
|
|
||||||
deps,
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.deepEqual(state.events, [{ text: '{\\b1}字幕' }]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('dispatchMpvProtocolMessage emits subtitle track changes', async () => {
|
test('dispatchMpvProtocolMessage emits subtitle track changes', async () => {
|
||||||
const { deps, state } = createDeps({
|
const { deps, state } = createDeps({
|
||||||
emitSubtitleTrackChange: (payload) => state.events.push(payload),
|
emitSubtitleTrackChange: (payload) => state.events.push(payload),
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ export const MPV_REQUEST_ID_SUB_FONT = 111;
|
|||||||
export const MPV_REQUEST_ID_SUB_SCALE_BY_WINDOW = 112;
|
export const MPV_REQUEST_ID_SUB_SCALE_BY_WINDOW = 112;
|
||||||
export const MPV_REQUEST_ID_OSD_HEIGHT = 113;
|
export const MPV_REQUEST_ID_OSD_HEIGHT = 113;
|
||||||
export const MPV_REQUEST_ID_OSD_DIMENSIONS = 114;
|
export const MPV_REQUEST_ID_OSD_DIMENSIONS = 114;
|
||||||
export const MPV_REQUEST_ID_SUBTEXT_ASS = 115;
|
|
||||||
export const MPV_REQUEST_ID_SUB_SPACING = 116;
|
export const MPV_REQUEST_ID_SUB_SPACING = 116;
|
||||||
export const MPV_REQUEST_ID_SUB_BOLD = 117;
|
export const MPV_REQUEST_ID_SUB_BOLD = 117;
|
||||||
export const MPV_REQUEST_ID_SUB_ITALIC = 118;
|
export const MPV_REQUEST_ID_SUB_ITALIC = 118;
|
||||||
@@ -52,7 +51,6 @@ export interface MpvProtocolHandleMessageDeps {
|
|||||||
getSubtitleMetrics: () => MpvSubtitleRenderMetrics;
|
getSubtitleMetrics: () => MpvSubtitleRenderMetrics;
|
||||||
isVisibleOverlayVisible: () => boolean;
|
isVisibleOverlayVisible: () => boolean;
|
||||||
emitSubtitleChange: (payload: { text: string; isOverlayVisible: boolean }) => void;
|
emitSubtitleChange: (payload: { text: string; isOverlayVisible: boolean }) => void;
|
||||||
emitSubtitleAssChange: (payload: { text: string }) => void;
|
|
||||||
emitSubtitleTiming: (payload: { text: string; start: number; end: number }) => void;
|
emitSubtitleTiming: (payload: { text: string; start: number; end: number }) => void;
|
||||||
emitSecondarySubtitleChange: (payload: { text: string }) => void;
|
emitSecondarySubtitleChange: (payload: { text: string }) => void;
|
||||||
emitSubtitleTrackChange: (payload: { sid: number | null }) => void;
|
emitSubtitleTrackChange: (payload: { sid: number | null }) => void;
|
||||||
@@ -253,8 +251,6 @@ export async function dispatchMpvProtocolMessage(
|
|||||||
isOverlayVisible: overlayVisible,
|
isOverlayVisible: overlayVisible,
|
||||||
});
|
});
|
||||||
deps.setCurrentSubText(nextSubText);
|
deps.setCurrentSubText(nextSubText);
|
||||||
} else if (msg.name === 'sub-text/ass' || msg.name === 'sub-text-ass') {
|
|
||||||
deps.emitSubtitleAssChange({ text: (msg.data as string) || '' });
|
|
||||||
} else if (msg.name === 'sub-start') {
|
} else if (msg.name === 'sub-start') {
|
||||||
deps.setCurrentSubStart((msg.data as number) || 0);
|
deps.setCurrentSubStart((msg.data as number) || 0);
|
||||||
deps.emitSubtitleTiming({
|
deps.emitSubtitleTiming({
|
||||||
@@ -468,8 +464,6 @@ export async function dispatchMpvProtocolMessage(
|
|||||||
text: nextSubText,
|
text: nextSubText,
|
||||||
isOverlayVisible: deps.isVisibleOverlayVisible(),
|
isOverlayVisible: deps.isVisibleOverlayVisible(),
|
||||||
});
|
});
|
||||||
} else if (msg.request_id === MPV_REQUEST_ID_SUBTEXT_ASS) {
|
|
||||||
deps.emitSubtitleAssChange({ text: (msg.data as string) || '' });
|
|
||||||
} else if (msg.request_id === MPV_REQUEST_ID_PATH) {
|
} else if (msg.request_id === MPV_REQUEST_ID_PATH) {
|
||||||
deps.emitMediaPathChange({ path: (msg.data as string) || '' });
|
deps.emitMediaPathChange({ path: (msg.data as string) || '' });
|
||||||
} else if (msg.request_id === MPV_REQUEST_ID_MEDIA_TITLE) {
|
} else if (msg.request_id === MPV_REQUEST_ID_MEDIA_TITLE) {
|
||||||
|
|||||||
@@ -444,17 +444,6 @@ test('MpvIpcClient reconnect replays property subscriptions and initial state re
|
|||||||
(command as { command: unknown[] }).command[1] === 1 &&
|
(command as { command: unknown[] }).command[1] === 1 &&
|
||||||
(command as { command: unknown[] }).command[2] === 'sub-text',
|
(command as { command: unknown[] }).command[2] === 'sub-text',
|
||||||
);
|
);
|
||||||
const hasAssSubtitleSubscription = commands.some(
|
|
||||||
(command) =>
|
|
||||||
Array.isArray((command as { command: unknown[] }).command) &&
|
|
||||||
(command as { command: unknown[] }).command[0] === 'observe_property' &&
|
|
||||||
(command as { command: unknown[] }).command[2] === 'sub-text/ass',
|
|
||||||
);
|
|
||||||
const hasDeprecatedAssSubtitleProperty = commands.some(
|
|
||||||
(command) =>
|
|
||||||
Array.isArray((command as { command: unknown[] }).command) &&
|
|
||||||
(command as { command: unknown[] }).command.includes('sub-text-ass'),
|
|
||||||
);
|
|
||||||
const hasPathRequest = commands.some(
|
const hasPathRequest = commands.some(
|
||||||
(command) =>
|
(command) =>
|
||||||
Array.isArray((command as { command: unknown[] }).command) &&
|
Array.isArray((command as { command: unknown[] }).command) &&
|
||||||
@@ -464,8 +453,6 @@ test('MpvIpcClient reconnect replays property subscriptions and initial state re
|
|||||||
|
|
||||||
assert.equal(hasSecondaryVisibilityReset, true);
|
assert.equal(hasSecondaryVisibilityReset, true);
|
||||||
assert.equal(hasTrackSubscription, true);
|
assert.equal(hasTrackSubscription, true);
|
||||||
assert.equal(hasAssSubtitleSubscription, true);
|
|
||||||
assert.equal(hasDeprecatedAssSubtitleProperty, false);
|
|
||||||
assert.equal(hasPathRequest, true);
|
assert.equal(hasPathRequest, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,6 @@ export interface MpvIpcClientDeps extends MpvIpcClientProtocolDeps {}
|
|||||||
export interface MpvIpcClientEventMap {
|
export interface MpvIpcClientEventMap {
|
||||||
'connection-change': { connected: boolean };
|
'connection-change': { connected: boolean };
|
||||||
'subtitle-change': { text: string; isOverlayVisible: boolean };
|
'subtitle-change': { text: string; isOverlayVisible: boolean };
|
||||||
'subtitle-ass-change': { text: string };
|
|
||||||
'subtitle-timing': { text: string; start: number; end: number };
|
'subtitle-timing': { text: string; start: number; end: number };
|
||||||
'time-pos-change': { time: number };
|
'time-pos-change': { time: number };
|
||||||
'duration-change': { duration: number };
|
'duration-change': { duration: number };
|
||||||
@@ -417,9 +416,6 @@ export class MpvIpcClient implements MpvClient {
|
|||||||
emitSubtitleChange: (payload) => {
|
emitSubtitleChange: (payload) => {
|
||||||
this.emit('subtitle-change', payload);
|
this.emit('subtitle-change', payload);
|
||||||
},
|
},
|
||||||
emitSubtitleAssChange: (payload) => {
|
|
||||||
this.emit('subtitle-ass-change', payload);
|
|
||||||
},
|
|
||||||
emitSubtitleTiming: (payload) => {
|
emitSubtitleTiming: (payload) => {
|
||||||
this.emit('subtitle-timing', payload);
|
this.emit('subtitle-timing', payload);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import test from 'node:test';
|
|||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import {
|
import {
|
||||||
applyRuntimeOptionResultRuntime,
|
applyRuntimeOptionResultRuntime,
|
||||||
cycleRuntimeOptionFromIpcRuntime,
|
|
||||||
setRuntimeOptionFromIpcRuntime,
|
setRuntimeOptionFromIpcRuntime,
|
||||||
} from './runtime-options-ipc';
|
} from './runtime-options-ipc';
|
||||||
|
|
||||||
@@ -25,21 +24,3 @@ test('setRuntimeOptionFromIpcRuntime returns unavailable when manager missing',
|
|||||||
assert.equal(result.error, 'Runtime options manager unavailable');
|
assert.equal(result.error, 'Runtime options manager unavailable');
|
||||||
assert.deepEqual(osd, []);
|
assert.deepEqual(osd, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cycleRuntimeOptionFromIpcRuntime reports errors once', () => {
|
|
||||||
const osd: string[] = [];
|
|
||||||
const result = cycleRuntimeOptionFromIpcRuntime(
|
|
||||||
{
|
|
||||||
setOptionValue: () => ({ ok: true }),
|
|
||||||
cycleOption: () => ({ ok: false, error: 'bad option' }),
|
|
||||||
},
|
|
||||||
'anki.kikuFieldGrouping',
|
|
||||||
1,
|
|
||||||
(text) => {
|
|
||||||
osd.push(text);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
assert.equal(result.ok, false);
|
|
||||||
assert.equal(result.error, 'bad option');
|
|
||||||
assert.deepEqual(osd, ['bad option']);
|
|
||||||
});
|
|
||||||
@@ -34,19 +34,3 @@ export function setRuntimeOptionFromIpcRuntime(
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cycleRuntimeOptionFromIpcRuntime(
|
|
||||||
manager: RuntimeOptionsManagerLike | null,
|
|
||||||
id: RuntimeOptionId,
|
|
||||||
direction: 1 | -1,
|
|
||||||
showMpvOsd: (text: string) => void,
|
|
||||||
): RuntimeOptionApplyResult {
|
|
||||||
if (!manager) {
|
|
||||||
return { ok: false, error: 'Runtime options manager unavailable' };
|
|
||||||
}
|
|
||||||
const result = applyRuntimeOptionResultRuntime(manager.cycleOption(id, direction), showMpvOsd);
|
|
||||||
if (!result.ok && result.error) {
|
|
||||||
showMpvOsd(result.error);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
-50
@@ -4767,7 +4767,6 @@ const {
|
|||||||
autoplaySubtitlePrimingRuntime.resetAutoplaySubtitlePrime();
|
autoplaySubtitlePrimingRuntime.resetAutoplaySubtitlePrime();
|
||||||
lastObservedTimePos = 0;
|
lastObservedTimePos = 0;
|
||||||
appState.currentSubText = '';
|
appState.currentSubText = '';
|
||||||
appState.currentSubAssText = '';
|
|
||||||
appState.currentSubtitleData = null;
|
appState.currentSubtitleData = null;
|
||||||
if (!preserveParsedSubtitleCues) {
|
if (!preserveParsedSubtitleCues) {
|
||||||
appState.activeParsedSubtitleCues = [];
|
appState.activeParsedSubtitleCues = [];
|
||||||
@@ -5723,7 +5722,6 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
|
|||||||
stopMediaTimingReviewPreview: (reviewId) => mediaTimingReviewRuntime.stopPreview(reviewId),
|
stopMediaTimingReviewPreview: (reviewId) => mediaTimingReviewRuntime.stopPreview(reviewId),
|
||||||
resolveMediaTimingReview: (request) => mediaTimingReviewRuntime.resolveReview(request),
|
resolveMediaTimingReview: (request) => mediaTimingReviewRuntime.resolveReview(request),
|
||||||
getMainWindow: () => overlayManager.getMainWindow(),
|
getMainWindow: () => overlayManager.getMainWindow(),
|
||||||
getVisibleOverlayVisibility: () => overlayManager.getVisibleOverlayVisible(),
|
|
||||||
focusMainWindow: () => {
|
focusMainWindow: () => {
|
||||||
const mainWindow = overlayManager.getMainWindow();
|
const mainWindow = overlayManager.getMainWindow();
|
||||||
if (!mainWindow || mainWindow.isDestroyed()) return;
|
if (!mainWindow || mainWindow.isDestroyed()) return;
|
||||||
@@ -5837,14 +5835,11 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onYoutubePickerResolve: (request) => youtubeFlowRuntime.resolveActivePicker(request),
|
onYoutubePickerResolve: (request) => youtubeFlowRuntime.resolveActivePicker(request),
|
||||||
openYomitanSettings: () => openYomitanSettings(),
|
|
||||||
// Overlay lookups carry no cue context of their own; fall back to snapshotting the
|
// Overlay lookups carry no cue context of their own; fall back to snapshotting the
|
||||||
// live mpv sub timings at lookup time so media generation clips the mined line even
|
// live mpv sub timings at lookup time so media generation clips the mined line even
|
||||||
// when extraction finishes long after playback has moved on.
|
// when extraction finishes long after playback has moved on.
|
||||||
recordSubtitleMiningContext: (context) =>
|
recordSubtitleMiningContext: (context) =>
|
||||||
recordSubtitleMiningContext(context ?? captureCurrentPrimarySubtitleMiningContext()),
|
recordSubtitleMiningContext(context ?? captureCurrentPrimarySubtitleMiningContext()),
|
||||||
quitApp: () => requestAppQuit(),
|
|
||||||
toggleVisibleOverlay: () => toggleVisibleOverlay(),
|
|
||||||
tokenizeCurrentSubtitle: async () => {
|
tokenizeCurrentSubtitle: async () => {
|
||||||
const tokenizeSubtitleForCurrent = tokenizeSubtitleDeferred;
|
const tokenizeSubtitleForCurrent = tokenizeSubtitleDeferred;
|
||||||
return resolveCurrentSubtitleForRenderer({
|
return resolveCurrentSubtitleForRenderer({
|
||||||
@@ -5862,7 +5857,6 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
getCurrentSubtitleRaw: () => appState.currentSubText,
|
getCurrentSubtitleRaw: () => appState.currentSubText,
|
||||||
getCurrentSubtitleAss: () => appState.currentSubAssText,
|
|
||||||
getSubtitleSidebarOpen: () => subtitleSidebarRequestedOpen,
|
getSubtitleSidebarOpen: () => subtitleSidebarRequestedOpen,
|
||||||
getSubtitleSidebarPlaybackState: () => getSubtitleSidebarPlaybackState(),
|
getSubtitleSidebarPlaybackState: () => getSubtitleSidebarPlaybackState(),
|
||||||
// Full snapshot: resolves the active source over mpv IPC and re-parses it when it changed.
|
// Full snapshot: resolves the active source over mpv IPC and re-parses it when it changed.
|
||||||
@@ -5942,8 +5936,6 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
|
|||||||
return resolveSubtitleStyleForRenderer(resolvedConfig);
|
return resolveSubtitleStyleForRenderer(resolvedConfig);
|
||||||
},
|
},
|
||||||
saveSubtitlePosition: (position) => saveSubtitlePosition(position),
|
saveSubtitlePosition: (position) => saveSubtitlePosition(position),
|
||||||
getMecabTokenizer: () => appState.mecabTokenizer,
|
|
||||||
getKeybindings: () => appState.keybindings,
|
|
||||||
getMpvInputBindings: async () => {
|
getMpvInputBindings: async () => {
|
||||||
await refreshMpvSessionBindings();
|
await refreshMpvSessionBindings();
|
||||||
return readMpvInputBindings({
|
return readMpvInputBindings({
|
||||||
@@ -5973,17 +5965,8 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
|
|||||||
controller: applyControllerConfigUpdate(currentRawConfig.controller, update),
|
controller: applyControllerConfigUpdate(currentRawConfig.controller, update),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
saveControllerPreference: ({ preferredGamepadId, preferredGamepadLabel }) => {
|
|
||||||
configService.patchRawConfig({
|
|
||||||
controller: {
|
|
||||||
preferredGamepadId,
|
|
||||||
preferredGamepadLabel,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getSecondarySubMode: () => appState.secondarySubMode,
|
getSecondarySubMode: () => appState.secondarySubMode,
|
||||||
getMpvClient: () => appState.mpvClient,
|
getMpvClient: () => appState.mpvClient,
|
||||||
getAnkiConnectStatus: () => appState.ankiIntegration !== null,
|
|
||||||
getRuntimeOptions: () => getRuntimeOptionsStateHandler(),
|
getRuntimeOptions: () => getRuntimeOptionsStateHandler(),
|
||||||
reportOverlayContentBounds: (payload: unknown) => {
|
reportOverlayContentBounds: (payload: unknown) => {
|
||||||
if (overlayContentMeasurementStore.report(payload)) {
|
if (overlayContentMeasurementStore.report(payload)) {
|
||||||
@@ -6071,47 +6054,14 @@ const { registerIpcRuntimeHandlers } = composeIpcRuntimeHandlers({
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
appendClipboardVideoToQueue: () => appendClipboardVideoToQueueHandler(),
|
|
||||||
getChangelogSnapshot: (options) => getChangelogSnapshot(options),
|
getChangelogSnapshot: (options) => getChangelogSnapshot(options),
|
||||||
...playlistBrowserMainDeps,
|
...playlistBrowserMainDeps,
|
||||||
getImmersionTracker: () => appState.immersionTracker,
|
getImmersionTracker: () => appState.immersionTracker,
|
||||||
},
|
},
|
||||||
ankiJimakuDeps: createAnkiJimakuIpcRuntimeServiceDeps({
|
ankiJimakuDeps: createAnkiJimakuIpcRuntimeServiceDeps({
|
||||||
patchAnkiConnectEnabled: (enabled: boolean) => {
|
|
||||||
configService.patchRawConfig({ ankiConnect: { enabled } });
|
|
||||||
},
|
|
||||||
getResolvedConfig: () => configService.getConfig(),
|
getResolvedConfig: () => configService.getConfig(),
|
||||||
getRuntimeOptionsManager: () => appState.runtimeOptionsManager,
|
|
||||||
getSubtitleTimingTracker: () => appState.subtitleTimingTracker,
|
|
||||||
getMpvClient: () => appState.mpvClient,
|
getMpvClient: () => appState.mpvClient,
|
||||||
getAnkiIntegration: () => appState.ankiIntegration,
|
getAnkiIntegration: () => appState.ankiIntegration,
|
||||||
setAnkiIntegration: (integration: AnkiIntegration | null) => {
|
|
||||||
appState.ankiIntegration = integration;
|
|
||||||
appState.ankiIntegration?.setRecordCardsMinedCallback(recordTrackedCardsMined);
|
|
||||||
appState.ankiIntegration?.setKnownWordCacheUpdatedCallback(
|
|
||||||
refreshCurrentSubtitleAnnotations,
|
|
||||||
);
|
|
||||||
appState.ankiIntegration?.setSubtitleMiningContextConsumer(
|
|
||||||
consumePendingSubtitleMiningContext,
|
|
||||||
);
|
|
||||||
appState.ankiIntegration?.setMediaTimingReviewCallback(
|
|
||||||
mediaTimingReviewRuntime.requestReview,
|
|
||||||
);
|
|
||||||
appState.ankiIntegration?.setSentenceFuriganaGenerator(generateMiningSentenceFurigana);
|
|
||||||
},
|
|
||||||
getKnownWordCacheStatePath: () => path.join(USER_DATA_PATH, 'known-words-cache.json'),
|
|
||||||
getCachedMediaPath: (currentVideoPath, kind) =>
|
|
||||||
getCachedYoutubeMediaPathForCurrentPlayback(currentVideoPath, kind),
|
|
||||||
shouldRequireRemoteMediaCache: () => shouldRequireYoutubeMediaCacheForCurrentPlayback(),
|
|
||||||
getYoutubeMediaSourceUrl: () => getCurrentYoutubeMediaCacheSourceUrl(),
|
|
||||||
showDesktopNotification,
|
|
||||||
showOverlayNotification: (payload) =>
|
|
||||||
overlayNotificationsRuntime.showOverlayNotification(payload),
|
|
||||||
dismissOverlayNotification: (id) =>
|
|
||||||
overlayNotificationsRuntime.dismissOverlayNotification(id),
|
|
||||||
createFieldGroupingCallback: () => createFieldGroupingCallback(),
|
|
||||||
broadcastRuntimeOptionsChanged: () =>
|
|
||||||
overlayVisibilityComposer.broadcastRuntimeOptionsChanged(),
|
|
||||||
getFieldGroupingResolver: () => getFieldGroupingResolverHandler(),
|
getFieldGroupingResolver: () => getFieldGroupingResolverHandler(),
|
||||||
setFieldGroupingResolver: (resolver: ((choice: KikuFieldGroupingChoice) => void) | null) =>
|
setFieldGroupingResolver: (resolver: ((choice: KikuFieldGroupingChoice) => void) | null) =>
|
||||||
setFieldGroupingResolverHandler(resolver),
|
setFieldGroupingResolverHandler(resolver),
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
import { RuntimeOptionId, RuntimeOptionValue, SubsyncManualPayload } from '../types';
|
import { RuntimeOptionId, RuntimeOptionValue, SubsyncManualPayload } from '../types';
|
||||||
import type { OverlayNotificationPayload } from '../types/notification';
|
|
||||||
import { SubsyncResolvedConfig } from '../subsync/utils';
|
import { SubsyncResolvedConfig } from '../subsync/utils';
|
||||||
import type { SubsyncRuntimeDeps } from '../core/services/subsync-runner';
|
import type { SubsyncRuntimeDeps } from '../core/services/subsync-runner';
|
||||||
import type { IpcDepsRuntimeOptions } from '../core/services/ipc';
|
import type { IpcDepsRuntimeOptions } from '../core/services/ipc';
|
||||||
import type { AnkiJimakuIpcRuntimeOptions } from '../core/services/anki-jimaku';
|
import type { AnkiJimakuIpcRuntimeOptions } from '../core/services/anki-jimaku';
|
||||||
import type { CliCommandDepsRuntimeOptions } from '../core/services/cli-command';
|
import type { CliCommandDepsRuntimeOptions } from '../core/services/cli-command';
|
||||||
import type { HandleMpvCommandFromIpcOptions } from '../core/services/ipc-command';
|
import type { HandleMpvCommandFromIpcOptions } from '../core/services/ipc-command';
|
||||||
import {
|
import { setRuntimeOptionFromIpcRuntime } from '../core/services/runtime-options-ipc';
|
||||||
cycleRuntimeOptionFromIpcRuntime,
|
|
||||||
setRuntimeOptionFromIpcRuntime,
|
|
||||||
} from '../core/services/runtime-options-ipc';
|
|
||||||
import { RuntimeOptionsManager } from '../runtime-options';
|
import { RuntimeOptionsManager } from '../runtime-options';
|
||||||
|
|
||||||
export interface RuntimeOptionsIpcDepsParams {
|
export interface RuntimeOptionsIpcDepsParams {
|
||||||
@@ -28,17 +24,12 @@ export interface SubsyncRuntimeDepsParams {
|
|||||||
|
|
||||||
export function createRuntimeOptionsIpcDeps(params: RuntimeOptionsIpcDepsParams): {
|
export function createRuntimeOptionsIpcDeps(params: RuntimeOptionsIpcDepsParams): {
|
||||||
setRuntimeOption: (id: RuntimeOptionId, value: RuntimeOptionValue) => unknown;
|
setRuntimeOption: (id: RuntimeOptionId, value: RuntimeOptionValue) => unknown;
|
||||||
cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => unknown;
|
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
setRuntimeOption: (id, value) =>
|
setRuntimeOption: (id, value) =>
|
||||||
setRuntimeOptionFromIpcRuntime(params.getRuntimeOptionsManager(), id, value, (text) =>
|
setRuntimeOptionFromIpcRuntime(params.getRuntimeOptionsManager(), id, value, (text) =>
|
||||||
params.showMpvOsd(text),
|
params.showMpvOsd(text),
|
||||||
),
|
),
|
||||||
cycleRuntimeOption: (id, direction) =>
|
|
||||||
cycleRuntimeOptionFromIpcRuntime(params.getRuntimeOptionsManager(), id, direction, (text) =>
|
|
||||||
params.showMpvOsd(text),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +46,6 @@ export function createSubsyncRuntimeDeps(params: SubsyncRuntimeDepsParams): Subs
|
|||||||
|
|
||||||
export interface MainIpcRuntimeServiceDepsParams {
|
export interface MainIpcRuntimeServiceDepsParams {
|
||||||
getMainWindow: IpcDepsRuntimeOptions['getMainWindow'];
|
getMainWindow: IpcDepsRuntimeOptions['getMainWindow'];
|
||||||
getVisibleOverlayVisibility: IpcDepsRuntimeOptions['getVisibleOverlayVisibility'];
|
|
||||||
onOverlayModalClosed: IpcDepsRuntimeOptions['onOverlayModalClosed'];
|
onOverlayModalClosed: IpcDepsRuntimeOptions['onOverlayModalClosed'];
|
||||||
onOverlayModalOpened?: IpcDepsRuntimeOptions['onOverlayModalOpened'];
|
onOverlayModalOpened?: IpcDepsRuntimeOptions['onOverlayModalOpened'];
|
||||||
onOverlayMouseInteractionChanged?: IpcDepsRuntimeOptions['onOverlayMouseInteractionChanged'];
|
onOverlayMouseInteractionChanged?: IpcDepsRuntimeOptions['onOverlayMouseInteractionChanged'];
|
||||||
@@ -67,12 +57,8 @@ export interface MainIpcRuntimeServiceDepsParams {
|
|||||||
getMediaTimingReviewWaveform?: IpcDepsRuntimeOptions['getMediaTimingReviewWaveform'];
|
getMediaTimingReviewWaveform?: IpcDepsRuntimeOptions['getMediaTimingReviewWaveform'];
|
||||||
stopMediaTimingReviewPreview?: IpcDepsRuntimeOptions['stopMediaTimingReviewPreview'];
|
stopMediaTimingReviewPreview?: IpcDepsRuntimeOptions['stopMediaTimingReviewPreview'];
|
||||||
resolveMediaTimingReview?: IpcDepsRuntimeOptions['resolveMediaTimingReview'];
|
resolveMediaTimingReview?: IpcDepsRuntimeOptions['resolveMediaTimingReview'];
|
||||||
openYomitanSettings: IpcDepsRuntimeOptions['openYomitanSettings'];
|
|
||||||
quitApp: IpcDepsRuntimeOptions['quitApp'];
|
|
||||||
toggleVisibleOverlay: IpcDepsRuntimeOptions['toggleVisibleOverlay'];
|
|
||||||
tokenizeCurrentSubtitle: IpcDepsRuntimeOptions['tokenizeCurrentSubtitle'];
|
tokenizeCurrentSubtitle: IpcDepsRuntimeOptions['tokenizeCurrentSubtitle'];
|
||||||
getCurrentSubtitleRaw: IpcDepsRuntimeOptions['getCurrentSubtitleRaw'];
|
getCurrentSubtitleRaw: IpcDepsRuntimeOptions['getCurrentSubtitleRaw'];
|
||||||
getCurrentSubtitleAss: IpcDepsRuntimeOptions['getCurrentSubtitleAss'];
|
|
||||||
getSubtitleSidebarSnapshot?: IpcDepsRuntimeOptions['getSubtitleSidebarSnapshot'];
|
getSubtitleSidebarSnapshot?: IpcDepsRuntimeOptions['getSubtitleSidebarSnapshot'];
|
||||||
getSubtitleSidebarPlaybackState?: IpcDepsRuntimeOptions['getSubtitleSidebarPlaybackState'];
|
getSubtitleSidebarPlaybackState?: IpcDepsRuntimeOptions['getSubtitleSidebarPlaybackState'];
|
||||||
getSubtitleSidebarOpen?: IpcDepsRuntimeOptions['getSubtitleSidebarOpen'];
|
getSubtitleSidebarOpen?: IpcDepsRuntimeOptions['getSubtitleSidebarOpen'];
|
||||||
@@ -82,9 +68,7 @@ export interface MainIpcRuntimeServiceDepsParams {
|
|||||||
getSubtitlePosition: IpcDepsRuntimeOptions['getSubtitlePosition'];
|
getSubtitlePosition: IpcDepsRuntimeOptions['getSubtitlePosition'];
|
||||||
getSubtitleStyle: IpcDepsRuntimeOptions['getSubtitleStyle'];
|
getSubtitleStyle: IpcDepsRuntimeOptions['getSubtitleStyle'];
|
||||||
saveSubtitlePosition: IpcDepsRuntimeOptions['saveSubtitlePosition'];
|
saveSubtitlePosition: IpcDepsRuntimeOptions['saveSubtitlePosition'];
|
||||||
getMecabTokenizer: IpcDepsRuntimeOptions['getMecabTokenizer'];
|
|
||||||
handleMpvCommand: IpcDepsRuntimeOptions['handleMpvCommand'];
|
handleMpvCommand: IpcDepsRuntimeOptions['handleMpvCommand'];
|
||||||
getKeybindings: IpcDepsRuntimeOptions['getKeybindings'];
|
|
||||||
getMpvInputBindings?: IpcDepsRuntimeOptions['getMpvInputBindings'];
|
getMpvInputBindings?: IpcDepsRuntimeOptions['getMpvInputBindings'];
|
||||||
getSessionBindings: IpcDepsRuntimeOptions['getSessionBindings'];
|
getSessionBindings: IpcDepsRuntimeOptions['getSessionBindings'];
|
||||||
getConfiguredShortcuts: IpcDepsRuntimeOptions['getConfiguredShortcuts'];
|
getConfiguredShortcuts: IpcDepsRuntimeOptions['getConfiguredShortcuts'];
|
||||||
@@ -94,14 +78,11 @@ export interface MainIpcRuntimeServiceDepsParams {
|
|||||||
getOverlayNotificationPosition: IpcDepsRuntimeOptions['getOverlayNotificationPosition'];
|
getOverlayNotificationPosition: IpcDepsRuntimeOptions['getOverlayNotificationPosition'];
|
||||||
getControllerConfig: IpcDepsRuntimeOptions['getControllerConfig'];
|
getControllerConfig: IpcDepsRuntimeOptions['getControllerConfig'];
|
||||||
saveControllerConfig: IpcDepsRuntimeOptions['saveControllerConfig'];
|
saveControllerConfig: IpcDepsRuntimeOptions['saveControllerConfig'];
|
||||||
saveControllerPreference: IpcDepsRuntimeOptions['saveControllerPreference'];
|
|
||||||
getSecondarySubMode: IpcDepsRuntimeOptions['getSecondarySubMode'];
|
getSecondarySubMode: IpcDepsRuntimeOptions['getSecondarySubMode'];
|
||||||
getMpvClient: IpcDepsRuntimeOptions['getMpvClient'];
|
getMpvClient: IpcDepsRuntimeOptions['getMpvClient'];
|
||||||
runSubsyncManual: IpcDepsRuntimeOptions['runSubsyncManual'];
|
runSubsyncManual: IpcDepsRuntimeOptions['runSubsyncManual'];
|
||||||
getAnkiConnectStatus: IpcDepsRuntimeOptions['getAnkiConnectStatus'];
|
|
||||||
getRuntimeOptions: IpcDepsRuntimeOptions['getRuntimeOptions'];
|
getRuntimeOptions: IpcDepsRuntimeOptions['getRuntimeOptions'];
|
||||||
setRuntimeOption: IpcDepsRuntimeOptions['setRuntimeOption'];
|
setRuntimeOption: IpcDepsRuntimeOptions['setRuntimeOption'];
|
||||||
cycleRuntimeOption: IpcDepsRuntimeOptions['cycleRuntimeOption'];
|
|
||||||
reportOverlayContentBounds: IpcDepsRuntimeOptions['reportOverlayContentBounds'];
|
reportOverlayContentBounds: IpcDepsRuntimeOptions['reportOverlayContentBounds'];
|
||||||
getAnilistStatus: IpcDepsRuntimeOptions['getAnilistStatus'];
|
getAnilistStatus: IpcDepsRuntimeOptions['getAnilistStatus'];
|
||||||
clearAnilistToken: IpcDepsRuntimeOptions['clearAnilistToken'];
|
clearAnilistToken: IpcDepsRuntimeOptions['clearAnilistToken'];
|
||||||
@@ -115,7 +96,6 @@ export interface MainIpcRuntimeServiceDepsParams {
|
|||||||
getCharacterDictionaryManagerSnapshot?: IpcDepsRuntimeOptions['getCharacterDictionaryManagerSnapshot'];
|
getCharacterDictionaryManagerSnapshot?: IpcDepsRuntimeOptions['getCharacterDictionaryManagerSnapshot'];
|
||||||
removeCharacterDictionaryManagedEntry?: IpcDepsRuntimeOptions['removeCharacterDictionaryManagedEntry'];
|
removeCharacterDictionaryManagedEntry?: IpcDepsRuntimeOptions['removeCharacterDictionaryManagedEntry'];
|
||||||
moveCharacterDictionaryManagedEntry?: IpcDepsRuntimeOptions['moveCharacterDictionaryManagedEntry'];
|
moveCharacterDictionaryManagedEntry?: IpcDepsRuntimeOptions['moveCharacterDictionaryManagedEntry'];
|
||||||
appendClipboardVideoToQueue: IpcDepsRuntimeOptions['appendClipboardVideoToQueue'];
|
|
||||||
getChangelogSnapshot?: IpcDepsRuntimeOptions['getChangelogSnapshot'];
|
getChangelogSnapshot?: IpcDepsRuntimeOptions['getChangelogSnapshot'];
|
||||||
getPlaylistBrowserSnapshot: IpcDepsRuntimeOptions['getPlaylistBrowserSnapshot'];
|
getPlaylistBrowserSnapshot: IpcDepsRuntimeOptions['getPlaylistBrowserSnapshot'];
|
||||||
appendPlaylistBrowserFile: IpcDepsRuntimeOptions['appendPlaylistBrowserFile'];
|
appendPlaylistBrowserFile: IpcDepsRuntimeOptions['appendPlaylistBrowserFile'];
|
||||||
@@ -126,22 +106,9 @@ export interface MainIpcRuntimeServiceDepsParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface AnkiJimakuIpcRuntimeServiceDepsParams {
|
export interface AnkiJimakuIpcRuntimeServiceDepsParams {
|
||||||
patchAnkiConnectEnabled: AnkiJimakuIpcRuntimeOptions['patchAnkiConnectEnabled'];
|
|
||||||
getResolvedConfig: AnkiJimakuIpcRuntimeOptions['getResolvedConfig'];
|
getResolvedConfig: AnkiJimakuIpcRuntimeOptions['getResolvedConfig'];
|
||||||
getRuntimeOptionsManager: AnkiJimakuIpcRuntimeOptions['getRuntimeOptionsManager'];
|
|
||||||
getSubtitleTimingTracker: AnkiJimakuIpcRuntimeOptions['getSubtitleTimingTracker'];
|
|
||||||
getMpvClient: AnkiJimakuIpcRuntimeOptions['getMpvClient'];
|
getMpvClient: AnkiJimakuIpcRuntimeOptions['getMpvClient'];
|
||||||
getAnkiIntegration: AnkiJimakuIpcRuntimeOptions['getAnkiIntegration'];
|
getAnkiIntegration: AnkiJimakuIpcRuntimeOptions['getAnkiIntegration'];
|
||||||
setAnkiIntegration: AnkiJimakuIpcRuntimeOptions['setAnkiIntegration'];
|
|
||||||
getKnownWordCacheStatePath: AnkiJimakuIpcRuntimeOptions['getKnownWordCacheStatePath'];
|
|
||||||
getCachedMediaPath?: AnkiJimakuIpcRuntimeOptions['getCachedMediaPath'];
|
|
||||||
shouldRequireRemoteMediaCache?: AnkiJimakuIpcRuntimeOptions['shouldRequireRemoteMediaCache'];
|
|
||||||
getYoutubeMediaSourceUrl?: AnkiJimakuIpcRuntimeOptions['getYoutubeMediaSourceUrl'];
|
|
||||||
showDesktopNotification: AnkiJimakuIpcRuntimeOptions['showDesktopNotification'];
|
|
||||||
showOverlayNotification?: (payload: OverlayNotificationPayload) => void;
|
|
||||||
dismissOverlayNotification?: (id: string) => void;
|
|
||||||
createFieldGroupingCallback: AnkiJimakuIpcRuntimeOptions['createFieldGroupingCallback'];
|
|
||||||
broadcastRuntimeOptionsChanged: AnkiJimakuIpcRuntimeOptions['broadcastRuntimeOptionsChanged'];
|
|
||||||
getFieldGroupingResolver: AnkiJimakuIpcRuntimeOptions['getFieldGroupingResolver'];
|
getFieldGroupingResolver: AnkiJimakuIpcRuntimeOptions['getFieldGroupingResolver'];
|
||||||
setFieldGroupingResolver: AnkiJimakuIpcRuntimeOptions['setFieldGroupingResolver'];
|
setFieldGroupingResolver: AnkiJimakuIpcRuntimeOptions['setFieldGroupingResolver'];
|
||||||
parseMediaInfo: AnkiJimakuIpcRuntimeOptions['parseMediaInfo'];
|
parseMediaInfo: AnkiJimakuIpcRuntimeOptions['parseMediaInfo'];
|
||||||
@@ -258,7 +225,6 @@ export function createMainIpcRuntimeServiceDeps(
|
|||||||
): IpcDepsRuntimeOptions {
|
): IpcDepsRuntimeOptions {
|
||||||
return {
|
return {
|
||||||
getMainWindow: params.getMainWindow,
|
getMainWindow: params.getMainWindow,
|
||||||
getVisibleOverlayVisibility: params.getVisibleOverlayVisibility,
|
|
||||||
onOverlayModalClosed: params.onOverlayModalClosed,
|
onOverlayModalClosed: params.onOverlayModalClosed,
|
||||||
onOverlayModalOpened: params.onOverlayModalOpened,
|
onOverlayModalOpened: params.onOverlayModalOpened,
|
||||||
onOverlayMouseInteractionChanged: params.onOverlayMouseInteractionChanged,
|
onOverlayMouseInteractionChanged: params.onOverlayMouseInteractionChanged,
|
||||||
@@ -270,12 +236,8 @@ export function createMainIpcRuntimeServiceDeps(
|
|||||||
getMediaTimingReviewWaveform: params.getMediaTimingReviewWaveform,
|
getMediaTimingReviewWaveform: params.getMediaTimingReviewWaveform,
|
||||||
stopMediaTimingReviewPreview: params.stopMediaTimingReviewPreview,
|
stopMediaTimingReviewPreview: params.stopMediaTimingReviewPreview,
|
||||||
resolveMediaTimingReview: params.resolveMediaTimingReview,
|
resolveMediaTimingReview: params.resolveMediaTimingReview,
|
||||||
openYomitanSettings: params.openYomitanSettings,
|
|
||||||
quitApp: params.quitApp,
|
|
||||||
toggleVisibleOverlay: params.toggleVisibleOverlay,
|
|
||||||
tokenizeCurrentSubtitle: params.tokenizeCurrentSubtitle,
|
tokenizeCurrentSubtitle: params.tokenizeCurrentSubtitle,
|
||||||
getCurrentSubtitleRaw: params.getCurrentSubtitleRaw,
|
getCurrentSubtitleRaw: params.getCurrentSubtitleRaw,
|
||||||
getCurrentSubtitleAss: params.getCurrentSubtitleAss,
|
|
||||||
getSubtitleSidebarSnapshot: params.getSubtitleSidebarSnapshot,
|
getSubtitleSidebarSnapshot: params.getSubtitleSidebarSnapshot,
|
||||||
getSubtitleSidebarPlaybackState: params.getSubtitleSidebarPlaybackState,
|
getSubtitleSidebarPlaybackState: params.getSubtitleSidebarPlaybackState,
|
||||||
getSubtitleSidebarOpen: params.getSubtitleSidebarOpen,
|
getSubtitleSidebarOpen: params.getSubtitleSidebarOpen,
|
||||||
@@ -283,9 +245,7 @@ export function createMainIpcRuntimeServiceDeps(
|
|||||||
getSubtitlePosition: params.getSubtitlePosition,
|
getSubtitlePosition: params.getSubtitlePosition,
|
||||||
getSubtitleStyle: params.getSubtitleStyle,
|
getSubtitleStyle: params.getSubtitleStyle,
|
||||||
saveSubtitlePosition: params.saveSubtitlePosition,
|
saveSubtitlePosition: params.saveSubtitlePosition,
|
||||||
getMecabTokenizer: params.getMecabTokenizer,
|
|
||||||
handleMpvCommand: params.handleMpvCommand,
|
handleMpvCommand: params.handleMpvCommand,
|
||||||
getKeybindings: params.getKeybindings,
|
|
||||||
getMpvInputBindings: params.getMpvInputBindings,
|
getMpvInputBindings: params.getMpvInputBindings,
|
||||||
getSessionBindings: params.getSessionBindings,
|
getSessionBindings: params.getSessionBindings,
|
||||||
getConfiguredShortcuts: params.getConfiguredShortcuts,
|
getConfiguredShortcuts: params.getConfiguredShortcuts,
|
||||||
@@ -295,16 +255,13 @@ export function createMainIpcRuntimeServiceDeps(
|
|||||||
getOverlayNotificationPosition: params.getOverlayNotificationPosition,
|
getOverlayNotificationPosition: params.getOverlayNotificationPosition,
|
||||||
getControllerConfig: params.getControllerConfig,
|
getControllerConfig: params.getControllerConfig,
|
||||||
saveControllerConfig: params.saveControllerConfig,
|
saveControllerConfig: params.saveControllerConfig,
|
||||||
saveControllerPreference: params.saveControllerPreference,
|
|
||||||
focusMainWindow: params.focusMainWindow ?? (() => {}),
|
focusMainWindow: params.focusMainWindow ?? (() => {}),
|
||||||
activatePlaybackWindowForOverlayInteraction: params.activatePlaybackWindowForOverlayInteraction,
|
activatePlaybackWindowForOverlayInteraction: params.activatePlaybackWindowForOverlayInteraction,
|
||||||
getSecondarySubMode: params.getSecondarySubMode,
|
getSecondarySubMode: params.getSecondarySubMode,
|
||||||
getMpvClient: params.getMpvClient,
|
getMpvClient: params.getMpvClient,
|
||||||
runSubsyncManual: params.runSubsyncManual,
|
runSubsyncManual: params.runSubsyncManual,
|
||||||
getAnkiConnectStatus: params.getAnkiConnectStatus,
|
|
||||||
getRuntimeOptions: params.getRuntimeOptions,
|
getRuntimeOptions: params.getRuntimeOptions,
|
||||||
setRuntimeOption: params.setRuntimeOption,
|
setRuntimeOption: params.setRuntimeOption,
|
||||||
cycleRuntimeOption: params.cycleRuntimeOption,
|
|
||||||
reportOverlayContentBounds: params.reportOverlayContentBounds,
|
reportOverlayContentBounds: params.reportOverlayContentBounds,
|
||||||
getAnilistStatus: params.getAnilistStatus,
|
getAnilistStatus: params.getAnilistStatus,
|
||||||
clearAnilistToken: params.clearAnilistToken,
|
clearAnilistToken: params.clearAnilistToken,
|
||||||
@@ -318,7 +275,6 @@ export function createMainIpcRuntimeServiceDeps(
|
|||||||
getCharacterDictionaryManagerSnapshot: params.getCharacterDictionaryManagerSnapshot,
|
getCharacterDictionaryManagerSnapshot: params.getCharacterDictionaryManagerSnapshot,
|
||||||
removeCharacterDictionaryManagedEntry: params.removeCharacterDictionaryManagedEntry,
|
removeCharacterDictionaryManagedEntry: params.removeCharacterDictionaryManagedEntry,
|
||||||
moveCharacterDictionaryManagedEntry: params.moveCharacterDictionaryManagedEntry,
|
moveCharacterDictionaryManagedEntry: params.moveCharacterDictionaryManagedEntry,
|
||||||
appendClipboardVideoToQueue: params.appendClipboardVideoToQueue,
|
|
||||||
getChangelogSnapshot: params.getChangelogSnapshot,
|
getChangelogSnapshot: params.getChangelogSnapshot,
|
||||||
getPlaylistBrowserSnapshot: params.getPlaylistBrowserSnapshot,
|
getPlaylistBrowserSnapshot: params.getPlaylistBrowserSnapshot,
|
||||||
appendPlaylistBrowserFile: params.appendPlaylistBrowserFile,
|
appendPlaylistBrowserFile: params.appendPlaylistBrowserFile,
|
||||||
@@ -333,26 +289,9 @@ export function createAnkiJimakuIpcRuntimeServiceDeps(
|
|||||||
params: AnkiJimakuIpcRuntimeServiceDepsParams,
|
params: AnkiJimakuIpcRuntimeServiceDepsParams,
|
||||||
): AnkiJimakuIpcRuntimeOptions {
|
): AnkiJimakuIpcRuntimeOptions {
|
||||||
return {
|
return {
|
||||||
patchAnkiConnectEnabled: params.patchAnkiConnectEnabled,
|
|
||||||
getResolvedConfig: params.getResolvedConfig,
|
getResolvedConfig: params.getResolvedConfig,
|
||||||
getRuntimeOptionsManager: params.getRuntimeOptionsManager,
|
|
||||||
getSubtitleTimingTracker: params.getSubtitleTimingTracker,
|
|
||||||
getMpvClient: params.getMpvClient,
|
getMpvClient: params.getMpvClient,
|
||||||
getAnkiIntegration: params.getAnkiIntegration,
|
getAnkiIntegration: params.getAnkiIntegration,
|
||||||
setAnkiIntegration: params.setAnkiIntegration,
|
|
||||||
getKnownWordCacheStatePath: params.getKnownWordCacheStatePath,
|
|
||||||
...(params.getCachedMediaPath ? { getCachedMediaPath: params.getCachedMediaPath } : {}),
|
|
||||||
...(params.shouldRequireRemoteMediaCache
|
|
||||||
? { shouldRequireRemoteMediaCache: params.shouldRequireRemoteMediaCache }
|
|
||||||
: {}),
|
|
||||||
...(params.getYoutubeMediaSourceUrl
|
|
||||||
? { getYoutubeMediaSourceUrl: params.getYoutubeMediaSourceUrl }
|
|
||||||
: {}),
|
|
||||||
showDesktopNotification: params.showDesktopNotification,
|
|
||||||
showOverlayNotification: params.showOverlayNotification,
|
|
||||||
dismissOverlayNotification: params.dismissOverlayNotification,
|
|
||||||
createFieldGroupingCallback: params.createFieldGroupingCallback,
|
|
||||||
broadcastRuntimeOptionsChanged: params.broadcastRuntimeOptionsChanged,
|
|
||||||
getFieldGroupingResolver: params.getFieldGroupingResolver,
|
getFieldGroupingResolver: params.getFieldGroupingResolver,
|
||||||
setFieldGroupingResolver: params.setFieldGroupingResolver,
|
setFieldGroupingResolver: params.setFieldGroupingResolver,
|
||||||
parseMediaInfo: params.parseMediaInfo,
|
parseMediaInfo: params.parseMediaInfo,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
|
|
||||||
export interface RegisterIpcRuntimeServicesParams {
|
export interface RegisterIpcRuntimeServicesParams {
|
||||||
runtimeOptions: RuntimeOptionsIpcDepsParams;
|
runtimeOptions: RuntimeOptionsIpcDepsParams;
|
||||||
mainDeps: Omit<MainIpcRuntimeServiceDepsParams, 'setRuntimeOption' | 'cycleRuntimeOption'>;
|
mainDeps: Omit<MainIpcRuntimeServiceDepsParams, 'setRuntimeOption'>;
|
||||||
ankiJimakuDeps: AnkiJimakuIpcRuntimeServiceDepsParams;
|
ankiJimakuDeps: AnkiJimakuIpcRuntimeServiceDepsParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +40,6 @@ export function registerIpcRuntimeServices(params: RegisterIpcRuntimeServicesPar
|
|||||||
registerMainIpcRuntimeServices({
|
registerMainIpcRuntimeServices({
|
||||||
...params.mainDeps,
|
...params.mainDeps,
|
||||||
setRuntimeOption: runtimeOptionsIpcDeps.setRuntimeOption,
|
setRuntimeOption: runtimeOptionsIpcDeps.setRuntimeOption,
|
||||||
cycleRuntimeOption: runtimeOptionsIpcDeps.cycleRuntimeOption,
|
|
||||||
});
|
});
|
||||||
registerAnkiJimakuIpcRuntimeServices(params.ankiJimakuDeps);
|
registerAnkiJimakuIpcRuntimeServices(params.ankiJimakuDeps);
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,6 @@ test('media path changes clear rendered subtitle state without clearing same-you
|
|||||||
|
|
||||||
assert.ok(actionBlock);
|
assert.ok(actionBlock);
|
||||||
assert.match(actionBlock, /appState\.currentSubText = '';/);
|
assert.match(actionBlock, /appState\.currentSubText = '';/);
|
||||||
assert.match(actionBlock, /appState\.currentSubAssText = '';/);
|
|
||||||
assert.match(actionBlock, /appState\.currentSubtitleData = null;/);
|
assert.match(actionBlock, /appState\.currentSubtitleData = null;/);
|
||||||
assert.match(actionBlock, /isSameYoutubeMediaPath\(/);
|
assert.match(actionBlock, /isSameYoutubeMediaPath\(/);
|
||||||
assert.match(actionBlock, /if \(!preserveParsedSubtitleCues\)/);
|
assert.match(actionBlock, /if \(!preserveParsedSubtitleCues\)/);
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ function createDefaultMpvFixture() {
|
|||||||
immersionTracker: null,
|
immersionTracker: null,
|
||||||
subtitleTimingTracker: null,
|
subtitleTimingTracker: null,
|
||||||
currentSubText: '',
|
currentSubText: '',
|
||||||
currentSubAssText: '',
|
|
||||||
playbackPaused: null,
|
playbackPaused: null,
|
||||||
previousSecondarySubVisibility: null,
|
previousSecondarySubVisibility: null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
type MpvBindingEventName =
|
type MpvBindingEventName =
|
||||||
| 'connection-change'
|
| 'connection-change'
|
||||||
| 'subtitle-change'
|
| 'subtitle-change'
|
||||||
| 'subtitle-ass-change'
|
|
||||||
| 'secondary-subtitle-change'
|
| 'secondary-subtitle-change'
|
||||||
| 'subtitle-track-change'
|
| 'subtitle-track-change'
|
||||||
| 'secondary-subtitle-track-change'
|
| 'secondary-subtitle-track-change'
|
||||||
@@ -89,7 +88,6 @@ export function createHandleMpvSubtitleTimingHandler(deps: {
|
|||||||
export function createBindMpvClientEventHandlers(deps: {
|
export function createBindMpvClientEventHandlers(deps: {
|
||||||
onConnectionChange: (payload: { connected: boolean }) => void;
|
onConnectionChange: (payload: { connected: boolean }) => void;
|
||||||
onSubtitleChange: (payload: { text: string }) => void;
|
onSubtitleChange: (payload: { text: string }) => void;
|
||||||
onSubtitleAssChange: (payload: { text: string }) => void;
|
|
||||||
onSecondarySubtitleChange: (payload: { text: string }) => void;
|
onSecondarySubtitleChange: (payload: { text: string }) => void;
|
||||||
onSubtitleTrackChange: (payload: { sid: number | null }) => void;
|
onSubtitleTrackChange: (payload: { sid: number | null }) => void;
|
||||||
onSecondarySubtitleTrackChange: (payload: { sid: number | null }) => void;
|
onSecondarySubtitleTrackChange: (payload: { sid: number | null }) => void;
|
||||||
@@ -108,7 +106,6 @@ export function createBindMpvClientEventHandlers(deps: {
|
|||||||
return (mpvClient: MpvEventClient): void => {
|
return (mpvClient: MpvEventClient): void => {
|
||||||
mpvClient.on('connection-change', deps.onConnectionChange);
|
mpvClient.on('connection-change', deps.onConnectionChange);
|
||||||
mpvClient.on('subtitle-change', deps.onSubtitleChange);
|
mpvClient.on('subtitle-change', deps.onSubtitleChange);
|
||||||
mpvClient.on('subtitle-ass-change', deps.onSubtitleAssChange);
|
|
||||||
mpvClient.on('secondary-subtitle-change', deps.onSecondarySubtitleChange);
|
mpvClient.on('secondary-subtitle-change', deps.onSecondarySubtitleChange);
|
||||||
mpvClient.on('subtitle-track-change', deps.onSubtitleTrackChange);
|
mpvClient.on('subtitle-track-change', deps.onSubtitleTrackChange);
|
||||||
mpvClient.on('secondary-subtitle-track-change', deps.onSecondarySubtitleTrackChange);
|
mpvClient.on('secondary-subtitle-track-change', deps.onSecondarySubtitleTrackChange);
|
||||||
|
|||||||
@@ -49,16 +49,6 @@ export function createHandleMpvSubtitleChangeHandler(deps: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createHandleMpvSubtitleAssChangeHandler(deps: {
|
|
||||||
setCurrentSubAssText: (text: string) => void;
|
|
||||||
broadcastSubtitleAss: (text: string) => void;
|
|
||||||
}) {
|
|
||||||
return ({ text }: { text: string }): void => {
|
|
||||||
deps.setCurrentSubAssText(text);
|
|
||||||
deps.broadcastSubtitleAss(text);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createHandleMpvSecondarySubtitleChangeHandler(deps: {
|
export function createHandleMpvSecondarySubtitleChangeHandler(deps: {
|
||||||
broadcastSecondarySubtitle: (text: string) => void;
|
broadcastSecondarySubtitle: (text: string) => void;
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ function createDeps(overrides: Partial<Deps> = {}): Deps {
|
|||||||
onSubtitleChange: () => {},
|
onSubtitleChange: () => {},
|
||||||
refreshDiscordPresence: () => {},
|
refreshDiscordPresence: () => {},
|
||||||
|
|
||||||
setCurrentSubAssText: () => {},
|
|
||||||
broadcastSubtitleAss: () => {},
|
|
||||||
broadcastSecondarySubtitle: () => {},
|
broadcastSecondarySubtitle: () => {},
|
||||||
|
|
||||||
updateCurrentMediaPath: () => {},
|
updateCurrentMediaPath: () => {},
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
createHandleMpvPauseChangeHandler,
|
createHandleMpvPauseChangeHandler,
|
||||||
createHandleMpvSecondarySubtitleChangeHandler,
|
createHandleMpvSecondarySubtitleChangeHandler,
|
||||||
createHandleMpvSecondarySubtitleVisibilityHandler,
|
createHandleMpvSecondarySubtitleVisibilityHandler,
|
||||||
createHandleMpvSubtitleAssChangeHandler,
|
|
||||||
createHandleMpvSubtitleChangeHandler,
|
createHandleMpvSubtitleChangeHandler,
|
||||||
createHandleMpvSubtitleMetricsChangeHandler,
|
createHandleMpvSubtitleMetricsChangeHandler,
|
||||||
createHandleMpvTimePosChangeHandler,
|
createHandleMpvTimePosChangeHandler,
|
||||||
@@ -52,8 +51,6 @@ export function createBindMpvMainEventHandlersHandler(deps: {
|
|||||||
logSubtitleProcessingDebug?: (message: string) => void;
|
logSubtitleProcessingDebug?: (message: string) => void;
|
||||||
refreshDiscordPresence: () => void;
|
refreshDiscordPresence: () => void;
|
||||||
|
|
||||||
setCurrentSubAssText: (text: string) => void;
|
|
||||||
broadcastSubtitleAss: (text: string) => void;
|
|
||||||
broadcastSecondarySubtitle: (text: string) => void;
|
broadcastSecondarySubtitle: (text: string) => void;
|
||||||
onSubtitleTrackChange?: (sid: number | null) => void;
|
onSubtitleTrackChange?: (sid: number | null) => void;
|
||||||
onSecondarySubtitleTrackChange?: (sid: number | null) => void;
|
onSecondarySubtitleTrackChange?: (sid: number | null) => void;
|
||||||
@@ -135,10 +132,6 @@ export function createBindMpvMainEventHandlersHandler(deps: {
|
|||||||
: undefined,
|
: undefined,
|
||||||
refreshDiscordPresence: () => deps.refreshDiscordPresence(),
|
refreshDiscordPresence: () => deps.refreshDiscordPresence(),
|
||||||
});
|
});
|
||||||
const handleMpvSubtitleAssChange = createHandleMpvSubtitleAssChangeHandler({
|
|
||||||
setCurrentSubAssText: (text) => deps.setCurrentSubAssText(text),
|
|
||||||
broadcastSubtitleAss: (text) => deps.broadcastSubtitleAss(text),
|
|
||||||
});
|
|
||||||
const handleMpvSecondarySubtitleChange = createHandleMpvSecondarySubtitleChangeHandler({
|
const handleMpvSecondarySubtitleChange = createHandleMpvSecondarySubtitleChangeHandler({
|
||||||
broadcastSecondarySubtitle: (text) => deps.broadcastSecondarySubtitle(text),
|
broadcastSecondarySubtitle: (text) => deps.broadcastSecondarySubtitle(text),
|
||||||
});
|
});
|
||||||
@@ -200,7 +193,6 @@ export function createBindMpvMainEventHandlersHandler(deps: {
|
|||||||
createBindMpvClientEventHandlers({
|
createBindMpvClientEventHandlers({
|
||||||
onConnectionChange: handleMpvConnectionChangeWithSidebarReset,
|
onConnectionChange: handleMpvConnectionChangeWithSidebarReset,
|
||||||
onSubtitleChange: handleMpvSubtitleChange,
|
onSubtitleChange: handleMpvSubtitleChange,
|
||||||
onSubtitleAssChange: handleMpvSubtitleAssChange,
|
|
||||||
onSecondarySubtitleChange: handleMpvSecondarySubtitleChange,
|
onSecondarySubtitleChange: handleMpvSecondarySubtitleChange,
|
||||||
onSubtitleTrackChange: ({ sid }) => deps.onSubtitleTrackChange?.(sid),
|
onSubtitleTrackChange: ({ sid }) => deps.onSubtitleTrackChange?.(sid),
|
||||||
onSecondarySubtitleTrackChange: ({ sid }) => deps.onSecondarySubtitleTrackChange?.(sid),
|
onSecondarySubtitleTrackChange: ({ sid }) => deps.onSecondarySubtitleTrackChange?.(sid),
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ function buildMainDeps(
|
|||||||
immersionTracker: null,
|
immersionTracker: null,
|
||||||
subtitleTimingTracker: null,
|
subtitleTimingTracker: null,
|
||||||
currentSubText: '',
|
currentSubText: '',
|
||||||
currentSubAssText: '',
|
|
||||||
playbackPaused: null,
|
playbackPaused: null,
|
||||||
previousSecondarySubVisibility: false,
|
previousSecondarySubVisibility: false,
|
||||||
...appStateOverrides,
|
...appStateOverrides,
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ export function createBuildBindMpvMainEventHandlersMainDepsHandler(deps: {
|
|||||||
activeParsedSubtitleSource?: string | null;
|
activeParsedSubtitleSource?: string | null;
|
||||||
currentMediaPath?: string | null;
|
currentMediaPath?: string | null;
|
||||||
currentSubText: string;
|
currentSubText: string;
|
||||||
currentSubAssText: string;
|
|
||||||
currentSubtitleData?: SubtitleData | null;
|
currentSubtitleData?: SubtitleData | null;
|
||||||
playbackPaused: boolean | null;
|
playbackPaused: boolean | null;
|
||||||
previousSecondarySubVisibility: boolean | null;
|
previousSecondarySubVisibility: boolean | null;
|
||||||
@@ -300,11 +299,6 @@ export function createBuildBindMpvMainEventHandlersMainDepsHandler(deps: {
|
|||||||
? (trackList: unknown[] | null) => deps.onSubtitleTrackListChange!(trackList)
|
? (trackList: unknown[] | null) => deps.onSubtitleTrackListChange!(trackList)
|
||||||
: undefined,
|
: undefined,
|
||||||
refreshDiscordPresence: () => deps.refreshDiscordPresence(),
|
refreshDiscordPresence: () => deps.refreshDiscordPresence(),
|
||||||
setCurrentSubAssText: (text: string) => {
|
|
||||||
deps.appState.currentSubAssText = text;
|
|
||||||
},
|
|
||||||
broadcastSubtitleAss: (text: string) =>
|
|
||||||
deps.broadcastToOverlayWindows('subtitle-ass:set', text),
|
|
||||||
broadcastSecondarySubtitle: (text: string) => {
|
broadcastSecondarySubtitle: (text: string) => {
|
||||||
if (deps.onSecondarySubtitleChange) {
|
if (deps.onSecondarySubtitleChange) {
|
||||||
deps.onSecondarySubtitleChange(text);
|
deps.onSecondarySubtitleChange(text);
|
||||||
|
|||||||
@@ -160,7 +160,6 @@ export interface AppState {
|
|||||||
discordPresenceService: ReturnType<typeof createDiscordPresenceService> | null;
|
discordPresenceService: ReturnType<typeof createDiscordPresenceService> | null;
|
||||||
reconnectTimer: ReturnType<typeof setTimeout> | null;
|
reconnectTimer: ReturnType<typeof setTimeout> | null;
|
||||||
currentSubText: string;
|
currentSubText: string;
|
||||||
currentSubAssText: string;
|
|
||||||
currentSubtitleData: SubtitleData | null;
|
currentSubtitleData: SubtitleData | null;
|
||||||
activeParsedSubtitleCues: SubtitleCue[];
|
activeParsedSubtitleCues: SubtitleCue[];
|
||||||
activeParsedSubtitleSource: string | null;
|
activeParsedSubtitleSource: string | null;
|
||||||
@@ -247,7 +246,6 @@ export function createAppState(values: AppStateInitialValues): AppState {
|
|||||||
discordPresenceService: null,
|
discordPresenceService: null,
|
||||||
reconnectTimer: null,
|
reconnectTimer: null,
|
||||||
currentSubText: '',
|
currentSubText: '',
|
||||||
currentSubAssText: '',
|
|
||||||
currentSubtitleData: null,
|
currentSubtitleData: null,
|
||||||
activeParsedSubtitleCues: [],
|
activeParsedSubtitleCues: [],
|
||||||
activeParsedSubtitleSource: null,
|
activeParsedSubtitleSource: null,
|
||||||
|
|||||||
@@ -399,29 +399,6 @@ export class MecabTokenizer {
|
|||||||
path: this.mecabPath,
|
path: this.mecabPath,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
setEnabled(enabled: boolean): void {
|
|
||||||
this.enabled = enabled;
|
|
||||||
if (!enabled) {
|
|
||||||
const pending: MecabQueuedRequest[] = [];
|
|
||||||
if (this.activeRequest) {
|
|
||||||
pending.push({
|
|
||||||
text: this.activeRequest.text,
|
|
||||||
retryCount: MecabTokenizer.MAX_RETRY_COUNT,
|
|
||||||
resolve: this.activeRequest.resolve,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (this.requestQueue.length > 0) {
|
|
||||||
pending.push(...this.requestQueue);
|
|
||||||
}
|
|
||||||
this.activeRequest = null;
|
|
||||||
this.requestQueue = [];
|
|
||||||
for (const request of pending) {
|
|
||||||
request.resolve(null);
|
|
||||||
}
|
|
||||||
this.stopPersistentProcess();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { mapMecabPos1ToPartOfSpeech as mapPartOfSpeech };
|
export { mapMecabPos1ToPartOfSpeech as mapPartOfSpeech };
|
||||||
@@ -22,8 +22,6 @@ import { createIpcListenerFactories } from './preload-ipc-listeners';
|
|||||||
import type {
|
import type {
|
||||||
SubtitleData,
|
SubtitleData,
|
||||||
SubtitlePosition,
|
SubtitlePosition,
|
||||||
MecabStatus,
|
|
||||||
Keybinding,
|
|
||||||
ElectronAPI,
|
ElectronAPI,
|
||||||
SecondarySubMode,
|
SecondarySubMode,
|
||||||
SubtitleStyleConfig,
|
SubtitleStyleConfig,
|
||||||
@@ -45,7 +43,6 @@ import type {
|
|||||||
SubsyncManualPayload,
|
SubsyncManualPayload,
|
||||||
SubsyncManualRunRequest,
|
SubsyncManualRunRequest,
|
||||||
SubsyncResult,
|
SubsyncResult,
|
||||||
ClipboardAppendResult,
|
|
||||||
PlaylistBrowserMutationResult,
|
PlaylistBrowserMutationResult,
|
||||||
PlaylistBrowserSnapshot,
|
PlaylistBrowserSnapshot,
|
||||||
KikuFieldGroupingRequestData,
|
KikuFieldGroupingRequestData,
|
||||||
@@ -60,7 +57,6 @@ import type {
|
|||||||
ShortcutsConfig,
|
ShortcutsConfig,
|
||||||
ConfigHotReloadPayload,
|
ConfigHotReloadPayload,
|
||||||
ControllerConfigUpdate,
|
ControllerConfigUpdate,
|
||||||
ControllerPreferenceUpdate,
|
|
||||||
ResolvedControllerConfig,
|
ResolvedControllerConfig,
|
||||||
SessionHelpOpenPayload,
|
SessionHelpOpenPayload,
|
||||||
SessionNumericSelectionStartPayload,
|
SessionNumericSelectionStartPayload,
|
||||||
@@ -176,10 +172,6 @@ const onOverlayNotificationEvent =
|
|||||||
const onNotificationHistoryToggleEvent = createQueuedIpcListener(
|
const onNotificationHistoryToggleEvent = createQueuedIpcListener(
|
||||||
IPC_CHANNELS.event.notificationHistoryToggle,
|
IPC_CHANNELS.event.notificationHistoryToggle,
|
||||||
);
|
);
|
||||||
const onSubtitleVisibilityEvent = createLatestValueIpcListenerWithPayload<boolean>(
|
|
||||||
IPC_CHANNELS.event.subtitleVisibility,
|
|
||||||
(payload) => payload === true,
|
|
||||||
);
|
|
||||||
const onSubtitlePositionSetEvent = createLatestValueIpcListenerWithPayload<SubtitlePosition | null>(
|
const onSubtitlePositionSetEvent = createLatestValueIpcListenerWithPayload<SubtitlePosition | null>(
|
||||||
IPC_CHANNELS.event.subtitlePositionSet,
|
IPC_CHANNELS.event.subtitlePositionSet,
|
||||||
(payload) => payload as SubtitlePosition | null,
|
(payload) => payload as SubtitlePosition | null,
|
||||||
@@ -236,22 +228,14 @@ const electronAPI: ElectronAPI = {
|
|||||||
},
|
},
|
||||||
onNotificationHistoryToggle: onNotificationHistoryToggleEvent,
|
onNotificationHistoryToggle: onNotificationHistoryToggleEvent,
|
||||||
|
|
||||||
onVisibility: (callback: (visible: boolean) => void) => {
|
|
||||||
onSubtitleVisibilityEvent(callback);
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubtitlePosition: (callback: (position: SubtitlePosition | null) => void) => {
|
onSubtitlePosition: (callback: (position: SubtitlePosition | null) => void) => {
|
||||||
onSubtitlePositionSetEvent(callback);
|
onSubtitlePositionSetEvent(callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
getOverlayVisibility: (): Promise<boolean> =>
|
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getVisibleOverlayVisibility),
|
|
||||||
getCurrentSubtitle: (): Promise<SubtitleData> =>
|
getCurrentSubtitle: (): Promise<SubtitleData> =>
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getCurrentSubtitle),
|
ipcRenderer.invoke(IPC_CHANNELS.request.getCurrentSubtitle),
|
||||||
getCurrentSubtitleRaw: (): Promise<string> =>
|
getCurrentSubtitleRaw: (): Promise<string> =>
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getCurrentSubtitleRaw),
|
ipcRenderer.invoke(IPC_CHANNELS.request.getCurrentSubtitleRaw),
|
||||||
getCurrentSubtitleAss: (): Promise<string> =>
|
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getCurrentSubtitleAss),
|
|
||||||
getSubtitleSidebarOpen: (): Promise<boolean> =>
|
getSubtitleSidebarOpen: (): Promise<boolean> =>
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getSubtitleSidebarOpen),
|
ipcRenderer.invoke(IPC_CHANNELS.request.getSubtitleSidebarOpen),
|
||||||
getSubtitleSidebarSnapshot: () =>
|
getSubtitleSidebarSnapshot: () =>
|
||||||
@@ -264,14 +248,6 @@ const electronAPI: ElectronAPI = {
|
|||||||
},
|
},
|
||||||
getPlaybackPaused: (): Promise<boolean | null> =>
|
getPlaybackPaused: (): Promise<boolean | null> =>
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getPlaybackPaused),
|
ipcRenderer.invoke(IPC_CHANNELS.request.getPlaybackPaused),
|
||||||
onSubtitleAss: (callback: (assText: string) => void) => {
|
|
||||||
ipcRenderer.on(
|
|
||||||
IPC_CHANNELS.event.subtitleAssSet,
|
|
||||||
(_event: IpcRendererEvent, assText: string) => {
|
|
||||||
callback(assText);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
setIgnoreMouseEvents: (ignore: boolean, options?: { forward?: boolean }) => {
|
setIgnoreMouseEvents: (ignore: boolean, options?: { forward?: boolean }) => {
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.setIgnoreMouseEvents, ignore, options);
|
ipcRenderer.send(IPC_CHANNELS.command.setIgnoreMouseEvents, ignore, options);
|
||||||
@@ -281,10 +257,6 @@ const electronAPI: ElectronAPI = {
|
|||||||
ipcRenderer.send(IPC_CHANNELS.command.reportOverlayInteractive, interactive);
|
ipcRenderer.send(IPC_CHANNELS.command.reportOverlayInteractive, interactive);
|
||||||
},
|
},
|
||||||
|
|
||||||
openYomitanSettings: () => {
|
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.openYomitanSettings);
|
|
||||||
},
|
|
||||||
|
|
||||||
recordYomitanLookup: (context?: SubtitleMiningContext | null) => {
|
recordYomitanLookup: (context?: SubtitleMiningContext | null) => {
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.recordYomitanLookup, context ?? null);
|
ipcRenderer.send(IPC_CHANNELS.command.recordYomitanLookup, context ?? null);
|
||||||
},
|
},
|
||||||
@@ -295,18 +267,10 @@ const electronAPI: ElectronAPI = {
|
|||||||
ipcRenderer.send(IPC_CHANNELS.command.saveSubtitlePosition, position);
|
ipcRenderer.send(IPC_CHANNELS.command.saveSubtitlePosition, position);
|
||||||
},
|
},
|
||||||
|
|
||||||
getMecabStatus: (): Promise<MecabStatus> =>
|
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getMecabStatus),
|
|
||||||
setMecabEnabled: (enabled: boolean) => {
|
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.setMecabEnabled, enabled);
|
|
||||||
},
|
|
||||||
|
|
||||||
sendMpvCommand: (command: (string | number)[]) => {
|
sendMpvCommand: (command: (string | number)[]) => {
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.mpvCommand, command);
|
ipcRenderer.send(IPC_CHANNELS.command.mpvCommand, command);
|
||||||
},
|
},
|
||||||
|
|
||||||
getKeybindings: (): Promise<Keybinding[]> =>
|
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getKeybindings),
|
|
||||||
getMpvInputBindings: () => ipcRenderer.invoke(IPC_CHANNELS.request.getMpvInputBindings),
|
getMpvInputBindings: () => ipcRenderer.invoke(IPC_CHANNELS.request.getMpvInputBindings),
|
||||||
getSessionBindings: () => ipcRenderer.invoke(IPC_CHANNELS.request.getSessionBindings),
|
getSessionBindings: () => ipcRenderer.invoke(IPC_CHANNELS.request.getSessionBindings),
|
||||||
getConfiguredShortcuts: (): Promise<Required<ShortcutsConfig>> =>
|
getConfiguredShortcuts: (): Promise<Required<ShortcutsConfig>> =>
|
||||||
@@ -325,8 +289,6 @@ const electronAPI: ElectronAPI = {
|
|||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getControllerConfig),
|
ipcRenderer.invoke(IPC_CHANNELS.request.getControllerConfig),
|
||||||
saveControllerConfig: (update: ControllerConfigUpdate): Promise<void> =>
|
saveControllerConfig: (update: ControllerConfigUpdate): Promise<void> =>
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.command.saveControllerConfig, update),
|
ipcRenderer.invoke(IPC_CHANNELS.command.saveControllerConfig, update),
|
||||||
saveControllerPreference: (update: ControllerPreferenceUpdate): Promise<void> =>
|
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.command.saveControllerPreference, update),
|
|
||||||
|
|
||||||
getJimakuMediaInfo: (): Promise<JimakuMediaInfo> =>
|
getJimakuMediaInfo: (): Promise<JimakuMediaInfo> =>
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.jimakuGetMediaInfo),
|
ipcRenderer.invoke(IPC_CHANNELS.request.jimakuGetMediaInfo),
|
||||||
@@ -350,31 +312,14 @@ const electronAPI: ElectronAPI = {
|
|||||||
tsukihimeGetSecondaryLanguages: (): Promise<string[]> =>
|
tsukihimeGetSecondaryLanguages: (): Promise<string[]> =>
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.tsukihimeGetSecondaryLanguages),
|
ipcRenderer.invoke(IPC_CHANNELS.request.tsukihimeGetSecondaryLanguages),
|
||||||
|
|
||||||
quitApp: () => {
|
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.quitApp);
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleDevTools: () => {
|
toggleDevTools: () => {
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.toggleDevTools);
|
ipcRenderer.send(IPC_CHANNELS.command.toggleDevTools);
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleOverlay: () => {
|
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.toggleOverlay);
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleStatsOverlay: () => {
|
toggleStatsOverlay: () => {
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.toggleStatsOverlay);
|
ipcRenderer.send(IPC_CHANNELS.command.toggleStatsOverlay);
|
||||||
},
|
},
|
||||||
|
|
||||||
getAnkiConnectStatus: (): Promise<boolean> =>
|
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getAnkiConnectStatus),
|
|
||||||
setAnkiConnectEnabled: (enabled: boolean) => {
|
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.setAnkiConnectEnabled, enabled);
|
|
||||||
},
|
|
||||||
clearAnkiConnectHistory: () => {
|
|
||||||
ipcRenderer.send(IPC_CHANNELS.command.clearAnkiConnectHistory);
|
|
||||||
},
|
|
||||||
|
|
||||||
onSecondarySub: (callback: (text: string) => void) => {
|
onSecondarySub: (callback: (text: string) => void) => {
|
||||||
onSecondarySubtitleSetEvent(callback);
|
onSecondarySubtitleSetEvent(callback);
|
||||||
},
|
},
|
||||||
@@ -419,8 +364,6 @@ const electronAPI: ElectronAPI = {
|
|||||||
value: RuntimeOptionValue,
|
value: RuntimeOptionValue,
|
||||||
): Promise<RuntimeOptionApplyResult> =>
|
): Promise<RuntimeOptionApplyResult> =>
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.setRuntimeOption, id, value),
|
ipcRenderer.invoke(IPC_CHANNELS.request.setRuntimeOption, id, value),
|
||||||
cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1): Promise<RuntimeOptionApplyResult> =>
|
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.cycleRuntimeOption, id, direction),
|
|
||||||
onRuntimeOptionsChanged: (callback: (options: RuntimeOptionState[]) => void) => {
|
onRuntimeOptionsChanged: (callback: (options: RuntimeOptionState[]) => void) => {
|
||||||
ipcRenderer.on(
|
ipcRenderer.on(
|
||||||
IPC_CHANNELS.event.runtimeOptionsChanged,
|
IPC_CHANNELS.event.runtimeOptionsChanged,
|
||||||
@@ -485,8 +428,6 @@ const electronAPI: ElectronAPI = {
|
|||||||
onSessionNumericSelectionStart: onSessionNumericSelectionStartEvent,
|
onSessionNumericSelectionStart: onSessionNumericSelectionStartEvent,
|
||||||
onKeyboardModeToggleRequested: onKeyboardModeToggleRequestedEvent,
|
onKeyboardModeToggleRequested: onKeyboardModeToggleRequestedEvent,
|
||||||
onLookupWindowToggleRequested: onLookupWindowToggleRequestedEvent,
|
onLookupWindowToggleRequested: onLookupWindowToggleRequestedEvent,
|
||||||
appendClipboardVideoToQueue: (): Promise<ClipboardAppendResult> =>
|
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.appendClipboardVideoToQueue),
|
|
||||||
getPlaylistBrowserSnapshot: (): Promise<PlaylistBrowserSnapshot> =>
|
getPlaylistBrowserSnapshot: (): Promise<PlaylistBrowserSnapshot> =>
|
||||||
ipcRenderer.invoke(IPC_CHANNELS.request.getPlaylistBrowserSnapshot),
|
ipcRenderer.invoke(IPC_CHANNELS.request.getPlaylistBrowserSnapshot),
|
||||||
appendPlaylistBrowserFile: (pathValue: string): Promise<PlaylistBrowserMutationResult> =>
|
appendPlaylistBrowserFile: (pathValue: string): Promise<PlaylistBrowserMutationResult> =>
|
||||||
|
|||||||
@@ -242,7 +242,6 @@ function installKeyboardTestGlobals() {
|
|||||||
windowFocusCalls += 1;
|
windowFocusCalls += 1;
|
||||||
},
|
},
|
||||||
electronAPI: {
|
electronAPI: {
|
||||||
getKeybindings: async () => [],
|
|
||||||
getMpvInputBindings: () => getMpvInputBindings(),
|
getMpvInputBindings: () => getMpvInputBindings(),
|
||||||
getSessionBindings: () => getSessionBindingsImpl(),
|
getSessionBindings: () => getSessionBindingsImpl(),
|
||||||
getConfiguredShortcuts: async () => configuredShortcuts,
|
getConfiguredShortcuts: async () => configuredShortcuts,
|
||||||
|
|||||||
@@ -25,22 +25,15 @@ export const IPC_CHANNELS = {
|
|||||||
command: {
|
command: {
|
||||||
setIgnoreMouseEvents: 'set-ignore-mouse-events',
|
setIgnoreMouseEvents: 'set-ignore-mouse-events',
|
||||||
overlayModalClosed: 'overlay:modal-closed',
|
overlayModalClosed: 'overlay:modal-closed',
|
||||||
openYomitanSettings: 'open-yomitan-settings',
|
|
||||||
recordYomitanLookup: 'record-yomitan-lookup',
|
recordYomitanLookup: 'record-yomitan-lookup',
|
||||||
quitApp: 'quit-app',
|
|
||||||
youtubePickerResolve: 'youtube:picker-resolve',
|
youtubePickerResolve: 'youtube:picker-resolve',
|
||||||
toggleDevTools: 'toggle-dev-tools',
|
toggleDevTools: 'toggle-dev-tools',
|
||||||
toggleOverlay: 'toggle-overlay',
|
|
||||||
saveSubtitlePosition: 'save-subtitle-position',
|
saveSubtitlePosition: 'save-subtitle-position',
|
||||||
statsNativeConfirmDialog: 'stats:native-confirm-dialog',
|
statsNativeConfirmDialog: 'stats:native-confirm-dialog',
|
||||||
statsNativeDialogOpened: 'stats:native-dialog-opened',
|
statsNativeDialogOpened: 'stats:native-dialog-opened',
|
||||||
statsNativeDialogClosed: 'stats:native-dialog-closed',
|
statsNativeDialogClosed: 'stats:native-dialog-closed',
|
||||||
saveControllerConfig: 'save-controller-config',
|
saveControllerConfig: 'save-controller-config',
|
||||||
saveControllerPreference: 'save-controller-preference',
|
|
||||||
setMecabEnabled: 'set-mecab-enabled',
|
|
||||||
mpvCommand: 'mpv-command',
|
mpvCommand: 'mpv-command',
|
||||||
setAnkiConnectEnabled: 'set-anki-connect-enabled',
|
|
||||||
clearAnkiConnectHistory: 'clear-anki-connect-history',
|
|
||||||
refreshKnownWords: 'anki:refresh-known-words',
|
refreshKnownWords: 'anki:refresh-known-words',
|
||||||
kikuFieldGroupingRespond: 'kiku:field-grouping-respond',
|
kikuFieldGroupingRespond: 'kiku:field-grouping-respond',
|
||||||
reportOverlayContentBounds: 'overlay-content-bounds:report',
|
reportOverlayContentBounds: 'overlay-content-bounds:report',
|
||||||
@@ -63,18 +56,14 @@ export const IPC_CHANNELS = {
|
|||||||
downloadSubtitleGenerationVadModel: 'subtitle-generation:download-vad',
|
downloadSubtitleGenerationVadModel: 'subtitle-generation:download-vad',
|
||||||
setSubtitleGenerationVadEnabled: 'subtitle-generation:set-vad-enabled',
|
setSubtitleGenerationVadEnabled: 'subtitle-generation:set-vad-enabled',
|
||||||
cancelSubtitleGeneration: 'subtitle-generation:cancel',
|
cancelSubtitleGeneration: 'subtitle-generation:cancel',
|
||||||
getVisibleOverlayVisibility: 'get-visible-overlay-visibility',
|
|
||||||
getCurrentSubtitle: 'get-current-subtitle',
|
getCurrentSubtitle: 'get-current-subtitle',
|
||||||
getCurrentSubtitleRaw: 'get-current-subtitle-raw',
|
getCurrentSubtitleRaw: 'get-current-subtitle-raw',
|
||||||
getCurrentSubtitleAss: 'get-current-subtitle-ass',
|
|
||||||
getSubtitleSidebarSnapshot: 'get-subtitle-sidebar-snapshot',
|
getSubtitleSidebarSnapshot: 'get-subtitle-sidebar-snapshot',
|
||||||
getSubtitleSidebarPlaybackState: 'get-subtitle-sidebar-playback-state',
|
getSubtitleSidebarPlaybackState: 'get-subtitle-sidebar-playback-state',
|
||||||
getSubtitleSidebarOpen: 'get-subtitle-sidebar-open',
|
getSubtitleSidebarOpen: 'get-subtitle-sidebar-open',
|
||||||
getPlaybackPaused: 'get-playback-paused',
|
getPlaybackPaused: 'get-playback-paused',
|
||||||
getSubtitlePosition: 'get-subtitle-position',
|
getSubtitlePosition: 'get-subtitle-position',
|
||||||
getSubtitleStyle: 'get-subtitle-style',
|
getSubtitleStyle: 'get-subtitle-style',
|
||||||
getMecabStatus: 'get-mecab-status',
|
|
||||||
getKeybindings: 'get-keybindings',
|
|
||||||
getMpvInputBindings: 'get-mpv-input-bindings',
|
getMpvInputBindings: 'get-mpv-input-bindings',
|
||||||
getSessionBindings: 'get-session-bindings',
|
getSessionBindings: 'get-session-bindings',
|
||||||
getConfigShortcuts: 'get-config-shortcuts',
|
getConfigShortcuts: 'get-config-shortcuts',
|
||||||
@@ -88,10 +77,8 @@ export const IPC_CHANNELS = {
|
|||||||
focusMainWindow: 'focus-main-window',
|
focusMainWindow: 'focus-main-window',
|
||||||
activatePlaybackWindowForOverlayInteraction: 'overlay:activate-playback-window',
|
activatePlaybackWindowForOverlayInteraction: 'overlay:activate-playback-window',
|
||||||
runSubsyncManual: 'subsync:run-manual',
|
runSubsyncManual: 'subsync:run-manual',
|
||||||
getAnkiConnectStatus: 'get-anki-connect-status',
|
|
||||||
getRuntimeOptions: 'runtime-options:get',
|
getRuntimeOptions: 'runtime-options:get',
|
||||||
setRuntimeOption: 'runtime-options:set',
|
setRuntimeOption: 'runtime-options:set',
|
||||||
cycleRuntimeOption: 'runtime-options:cycle',
|
|
||||||
getAnilistStatus: 'anilist:get-status',
|
getAnilistStatus: 'anilist:get-status',
|
||||||
clearAnilistToken: 'anilist:clear-token',
|
clearAnilistToken: 'anilist:clear-token',
|
||||||
openAnilistSetup: 'anilist:open-setup',
|
openAnilistSetup: 'anilist:open-setup',
|
||||||
@@ -103,7 +90,6 @@ export const IPC_CHANNELS = {
|
|||||||
getCharacterDictionaryManagerSnapshot: 'character-dictionary:get-manager-snapshot',
|
getCharacterDictionaryManagerSnapshot: 'character-dictionary:get-manager-snapshot',
|
||||||
removeCharacterDictionaryManagedEntry: 'character-dictionary:remove-managed-entry',
|
removeCharacterDictionaryManagedEntry: 'character-dictionary:remove-managed-entry',
|
||||||
moveCharacterDictionaryManagedEntry: 'character-dictionary:move-managed-entry',
|
moveCharacterDictionaryManagedEntry: 'character-dictionary:move-managed-entry',
|
||||||
appendClipboardVideoToQueue: 'clipboard:append-video-to-queue',
|
|
||||||
getPlaylistBrowserSnapshot: 'playlist-browser:get-snapshot',
|
getPlaylistBrowserSnapshot: 'playlist-browser:get-snapshot',
|
||||||
appendPlaylistBrowserFile: 'playlist-browser:append-file',
|
appendPlaylistBrowserFile: 'playlist-browser:append-file',
|
||||||
playPlaylistBrowserIndex: 'playlist-browser:play-index',
|
playPlaylistBrowserIndex: 'playlist-browser:play-index',
|
||||||
@@ -153,9 +139,7 @@ export const IPC_CHANNELS = {
|
|||||||
subtitleGenerationProgress: 'subtitle-generation:progress',
|
subtitleGenerationProgress: 'subtitle-generation:progress',
|
||||||
subtitleSet: 'subtitle:set',
|
subtitleSet: 'subtitle:set',
|
||||||
overlayPointerRecoveryRequest: 'overlay:pointer-recovery-request',
|
overlayPointerRecoveryRequest: 'overlay:pointer-recovery-request',
|
||||||
subtitleVisibility: 'mpv:subVisibility',
|
|
||||||
subtitlePositionSet: 'subtitle-position:set',
|
subtitlePositionSet: 'subtitle-position:set',
|
||||||
subtitleAssSet: 'subtitle-ass:set',
|
|
||||||
secondarySubtitleSet: 'secondary-subtitle:set',
|
secondarySubtitleSet: 'secondary-subtitle:set',
|
||||||
secondarySubtitleMode: 'secondary-subtitle:mode',
|
secondarySubtitleMode: 'secondary-subtitle:mode',
|
||||||
subsyncOpenManual: 'subsync:open-manual',
|
subsyncOpenManual: 'subsync:open-manual',
|
||||||
@@ -197,11 +181,6 @@ export type RuntimeOptionsSetRequest = {
|
|||||||
value: RuntimeOptionValue;
|
value: RuntimeOptionValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RuntimeOptionsCycleRequest = {
|
|
||||||
id: RuntimeOptionId;
|
|
||||||
direction: 1 | -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type OverlayContentBoundsReportRequest = {
|
export type OverlayContentBoundsReportRequest = {
|
||||||
measurement: OverlayContentMeasurement;
|
measurement: OverlayContentMeasurement;
|
||||||
};
|
};
|
||||||
@@ -10,7 +10,6 @@ import type {
|
|||||||
} from '../../types/integrations';
|
} from '../../types/integrations';
|
||||||
import type {
|
import type {
|
||||||
ControllerConfigUpdate,
|
ControllerConfigUpdate,
|
||||||
ControllerPreferenceUpdate,
|
|
||||||
SessionActionDispatchRequest,
|
SessionActionDispatchRequest,
|
||||||
SubsyncManualRunRequest,
|
SubsyncManualRunRequest,
|
||||||
} from '../../types/runtime';
|
} from '../../types/runtime';
|
||||||
@@ -131,16 +130,6 @@ export function parseSubtitlePosition(value: unknown): SubtitlePosition | null {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseControllerPreferenceUpdate(value: unknown): ControllerPreferenceUpdate | null {
|
|
||||||
if (!isObject(value)) return null;
|
|
||||||
if (typeof value.preferredGamepadId !== 'string') return null;
|
|
||||||
if (typeof value.preferredGamepadLabel !== 'string') return null;
|
|
||||||
return {
|
|
||||||
preferredGamepadId: value.preferredGamepadId,
|
|
||||||
preferredGamepadLabel: value.preferredGamepadLabel,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseDiscreteBinding(value: unknown) {
|
function parseDiscreteBinding(value: unknown) {
|
||||||
if (!isObject(value) || typeof value.kind !== 'string') return null;
|
if (!isObject(value) || typeof value.kind !== 'string') return null;
|
||||||
if (value.kind === 'none') {
|
if (value.kind === 'none') {
|
||||||
@@ -328,10 +317,6 @@ export function parseRuntimeOptionId(value: unknown): RuntimeOptionId | null {
|
|||||||
return RUNTIME_OPTION_IDS.includes(value as RuntimeOptionId) ? (value as RuntimeOptionId) : null;
|
return RUNTIME_OPTION_IDS.includes(value as RuntimeOptionId) ? (value as RuntimeOptionId) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseRuntimeOptionDirection(value: unknown): 1 | -1 | null {
|
|
||||||
return value === 1 || value === -1 ? value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseRuntimeOptionValue(value: unknown): RuntimeOptionValue | null {
|
export function parseRuntimeOptionValue(value: unknown): RuntimeOptionValue | null {
|
||||||
return typeof value === 'boolean' || typeof value === 'string'
|
return typeof value === 'boolean' || typeof value === 'string'
|
||||||
? (value as RuntimeOptionValue)
|
? (value as RuntimeOptionValue)
|
||||||
|
|||||||
@@ -297,11 +297,6 @@ export interface ControllerConfig {
|
|||||||
profiles?: Record<string, ControllerProfileConfig>;
|
profiles?: Record<string, ControllerProfileConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ControllerPreferenceUpdate {
|
|
||||||
preferredGamepadId: string;
|
|
||||||
preferredGamepadLabel: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ControllerConfigUpdate = ControllerConfig;
|
export type ControllerConfigUpdate = ControllerConfig;
|
||||||
|
|
||||||
export interface ControllerDeviceInfo {
|
export interface ControllerDeviceInfo {
|
||||||
@@ -470,28 +465,20 @@ export interface ElectronAPI {
|
|||||||
options?: Pick<OverlayNotificationAction, 'noteId'>,
|
options?: Pick<OverlayNotificationAction, 'noteId'>,
|
||||||
) => void;
|
) => void;
|
||||||
onNotificationHistoryToggle: (callback: () => void) => void;
|
onNotificationHistoryToggle: (callback: () => void) => void;
|
||||||
onVisibility: (callback: (visible: boolean) => void) => void;
|
|
||||||
onSubtitlePosition: (callback: (position: SubtitlePosition | null) => void) => void;
|
onSubtitlePosition: (callback: (position: SubtitlePosition | null) => void) => void;
|
||||||
getOverlayVisibility: () => Promise<boolean>;
|
|
||||||
getCurrentSubtitle: () => Promise<SubtitleData>;
|
getCurrentSubtitle: () => Promise<SubtitleData>;
|
||||||
getCurrentSubtitleRaw: () => Promise<string>;
|
getCurrentSubtitleRaw: () => Promise<string>;
|
||||||
getCurrentSubtitleAss: () => Promise<string>;
|
|
||||||
getSubtitleSidebarSnapshot: () => Promise<SubtitleSidebarSnapshot>;
|
getSubtitleSidebarSnapshot: () => Promise<SubtitleSidebarSnapshot>;
|
||||||
getSubtitleSidebarPlaybackState: () => Promise<SubtitleSidebarPlaybackState>;
|
getSubtitleSidebarPlaybackState: () => Promise<SubtitleSidebarPlaybackState>;
|
||||||
copySubtitleSidebarSelection: (text: string) => Promise<void>;
|
copySubtitleSidebarSelection: (text: string) => Promise<void>;
|
||||||
getSubtitleSidebarOpen: () => Promise<boolean>;
|
getSubtitleSidebarOpen: () => Promise<boolean>;
|
||||||
getPlaybackPaused: () => Promise<boolean | null>;
|
getPlaybackPaused: () => Promise<boolean | null>;
|
||||||
onSubtitleAss: (callback: (assText: string) => void) => void;
|
|
||||||
setIgnoreMouseEvents: (ignore: boolean, options?: { forward?: boolean }) => void;
|
setIgnoreMouseEvents: (ignore: boolean, options?: { forward?: boolean }) => void;
|
||||||
reportOverlayInteractive: (interactive: boolean) => void;
|
reportOverlayInteractive: (interactive: boolean) => void;
|
||||||
openYomitanSettings: () => void;
|
|
||||||
recordYomitanLookup: (context?: SubtitleMiningContext | null) => void;
|
recordYomitanLookup: (context?: SubtitleMiningContext | null) => void;
|
||||||
getSubtitlePosition: () => Promise<SubtitlePosition | null>;
|
getSubtitlePosition: () => Promise<SubtitlePosition | null>;
|
||||||
saveSubtitlePosition: (position: SubtitlePosition) => void;
|
saveSubtitlePosition: (position: SubtitlePosition) => void;
|
||||||
getMecabStatus: () => Promise<MecabStatus>;
|
|
||||||
setMecabEnabled: (enabled: boolean) => void;
|
|
||||||
sendMpvCommand: (command: (string | number)[]) => void;
|
sendMpvCommand: (command: (string | number)[]) => void;
|
||||||
getKeybindings: () => Promise<Keybinding[]>;
|
|
||||||
getMpvInputBindings: () => Promise<MpvInputBindingsSnapshot>;
|
getMpvInputBindings: () => Promise<MpvInputBindingsSnapshot>;
|
||||||
getSessionBindings: () => Promise<CompiledSessionBinding[]>;
|
getSessionBindings: () => Promise<CompiledSessionBinding[]>;
|
||||||
getConfiguredShortcuts: () => Promise<Required<ShortcutsConfig>>;
|
getConfiguredShortcuts: () => Promise<Required<ShortcutsConfig>>;
|
||||||
@@ -505,7 +492,6 @@ export interface ElectronAPI {
|
|||||||
markActiveVideoWatched: () => Promise<boolean>;
|
markActiveVideoWatched: () => Promise<boolean>;
|
||||||
getControllerConfig: () => Promise<ResolvedControllerConfig>;
|
getControllerConfig: () => Promise<ResolvedControllerConfig>;
|
||||||
saveControllerConfig: (update: ControllerConfigUpdate) => Promise<void>;
|
saveControllerConfig: (update: ControllerConfigUpdate) => Promise<void>;
|
||||||
saveControllerPreference: (update: ControllerPreferenceUpdate) => Promise<void>;
|
|
||||||
getJimakuMediaInfo: () => Promise<JimakuMediaInfo>;
|
getJimakuMediaInfo: () => Promise<JimakuMediaInfo>;
|
||||||
jimakuSearchEntries: (query: JimakuSearchQuery) => Promise<JimakuApiResponse<JimakuEntry[]>>;
|
jimakuSearchEntries: (query: JimakuSearchQuery) => Promise<JimakuApiResponse<JimakuEntry[]>>;
|
||||||
jimakuListFiles: (query: JimakuFilesQuery) => Promise<JimakuApiResponse<JimakuFileEntry[]>>;
|
jimakuListFiles: (query: JimakuFilesQuery) => Promise<JimakuApiResponse<JimakuFileEntry[]>>;
|
||||||
@@ -518,13 +504,8 @@ export interface ElectronAPI {
|
|||||||
) => Promise<TsukihimeApiResponse<TsukihimeSubtitleFile[]>>;
|
) => Promise<TsukihimeApiResponse<TsukihimeSubtitleFile[]>>;
|
||||||
tsukihimeDownloadFile: (query: TsukihimeDownloadQuery) => Promise<TsukihimeDownloadResult>;
|
tsukihimeDownloadFile: (query: TsukihimeDownloadQuery) => Promise<TsukihimeDownloadResult>;
|
||||||
tsukihimeGetSecondaryLanguages: () => Promise<string[]>;
|
tsukihimeGetSecondaryLanguages: () => Promise<string[]>;
|
||||||
quitApp: () => void;
|
|
||||||
toggleDevTools: () => void;
|
toggleDevTools: () => void;
|
||||||
toggleOverlay: () => void;
|
|
||||||
toggleStatsOverlay: () => void;
|
toggleStatsOverlay: () => void;
|
||||||
getAnkiConnectStatus: () => Promise<boolean>;
|
|
||||||
setAnkiConnectEnabled: (enabled: boolean) => void;
|
|
||||||
clearAnkiConnectHistory: () => void;
|
|
||||||
onSecondarySub: (callback: (text: string) => void) => void;
|
onSecondarySub: (callback: (text: string) => void) => void;
|
||||||
onSecondarySubMode: (callback: (mode: SecondarySubMode) => void) => void;
|
onSecondarySubMode: (callback: (mode: SecondarySubMode) => void) => void;
|
||||||
getSecondarySubMode: () => Promise<SecondarySubMode>;
|
getSecondarySubMode: () => Promise<SecondarySubMode>;
|
||||||
@@ -550,7 +531,6 @@ export interface ElectronAPI {
|
|||||||
id: RuntimeOptionId,
|
id: RuntimeOptionId,
|
||||||
value: RuntimeOptionValue,
|
value: RuntimeOptionValue,
|
||||||
) => Promise<RuntimeOptionApplyResult>;
|
) => Promise<RuntimeOptionApplyResult>;
|
||||||
cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => Promise<RuntimeOptionApplyResult>;
|
|
||||||
onRuntimeOptionsChanged: (callback: (options: RuntimeOptionState[]) => void) => void;
|
onRuntimeOptionsChanged: (callback: (options: RuntimeOptionState[]) => void) => void;
|
||||||
onOpenRuntimeOptions: (callback: () => void) => void;
|
onOpenRuntimeOptions: (callback: () => void) => void;
|
||||||
onOpenSessionHelp: (callback: (payload: SessionHelpOpenPayload) => void) => void;
|
onOpenSessionHelp: (callback: (payload: SessionHelpOpenPayload) => void) => void;
|
||||||
@@ -589,7 +569,6 @@ export interface ElectronAPI {
|
|||||||
) => void;
|
) => void;
|
||||||
onKeyboardModeToggleRequested: (callback: () => void) => void;
|
onKeyboardModeToggleRequested: (callback: () => void) => void;
|
||||||
onLookupWindowToggleRequested: (callback: () => void) => void;
|
onLookupWindowToggleRequested: (callback: () => void) => void;
|
||||||
appendClipboardVideoToQueue: () => Promise<ClipboardAppendResult>;
|
|
||||||
getPlaylistBrowserSnapshot: () => Promise<PlaylistBrowserSnapshot>;
|
getPlaylistBrowserSnapshot: () => Promise<PlaylistBrowserSnapshot>;
|
||||||
appendPlaylistBrowserFile: (path: string) => Promise<PlaylistBrowserMutationResult>;
|
appendPlaylistBrowserFile: (path: string) => Promise<PlaylistBrowserMutationResult>;
|
||||||
playPlaylistBrowserIndex: (index: number) => Promise<PlaylistBrowserMutationResult>;
|
playPlaylistBrowserIndex: (index: number) => Promise<PlaylistBrowserMutationResult>;
|
||||||
|
|||||||
Reference in new issue
Block a user