run prettier

This commit is contained in:
2026-02-28 21:15:22 -08:00
parent e4038127cb
commit cbff3f9ad9
146 changed files with 891 additions and 584 deletions

View File

@@ -214,9 +214,13 @@ test('handleOverlayModalClosed hides modal window only after all pending modals
runtime.sendToActiveOverlayWindow('runtime-options:open', undefined, {
restoreOnModalClose: 'runtime-options',
});
runtime.sendToActiveOverlayWindow('subsync:open-manual', { sourceTracks: [] }, {
restoreOnModalClose: 'subsync',
});
runtime.sendToActiveOverlayWindow(
'subsync:open-manual',
{ sourceTracks: [] },
{
restoreOnModalClose: 'subsync',
},
);
runtime.handleOverlayModalClosed('runtime-options');
assert.equal(window.getHideCount(), 0);
@@ -267,9 +271,13 @@ test('modal runtime notifies callers when modal input state becomes active/inact
runtime.sendToActiveOverlayWindow('runtime-options:open', undefined, {
restoreOnModalClose: 'runtime-options',
});
runtime.sendToActiveOverlayWindow('subsync:open-manual', { sourceTracks: [] }, {
restoreOnModalClose: 'subsync',
});
runtime.sendToActiveOverlayWindow(
'subsync:open-manual',
{ sourceTracks: [] },
{
restoreOnModalClose: 'subsync',
},
);
assert.deepEqual(state, []);
runtime.notifyOverlayModalOpened('runtime-options');
assert.deepEqual(state, [true]);
@@ -352,9 +360,13 @@ test('handleOverlayModalClosed hides modal window for single kiku modal', () =>
setModalWindowBounds: () => {},
});
runtime.sendToActiveOverlayWindow('kiku:field-grouping-open', { test: true }, {
restoreOnModalClose: 'kiku',
});
runtime.sendToActiveOverlayWindow(
'kiku:field-grouping-open',
{ test: true },
{
restoreOnModalClose: 'kiku',
},
);
runtime.handleOverlayModalClosed('kiku');
assert.equal(window.getHideCount(), 1);

View File

@@ -3,7 +3,9 @@ import type {
createMaybeProbeAnilistDurationHandler,
} from './anilist-media-guess';
type MaybeProbeAnilistDurationMainDeps = Parameters<typeof createMaybeProbeAnilistDurationHandler>[0];
type MaybeProbeAnilistDurationMainDeps = Parameters<
typeof createMaybeProbeAnilistDurationHandler
>[0];
type EnsureAnilistMediaGuessMainDeps = Parameters<typeof createEnsureAnilistMediaGuessHandler>[0];
export function createBuildMaybeProbeAnilistDurationMainDepsHandler(
@@ -19,13 +21,17 @@ export function createBuildMaybeProbeAnilistDurationMainDepsHandler(
});
}
export function createBuildEnsureAnilistMediaGuessMainDepsHandler(deps: EnsureAnilistMediaGuessMainDeps) {
export function createBuildEnsureAnilistMediaGuessMainDepsHandler(
deps: EnsureAnilistMediaGuessMainDeps,
) {
return (): EnsureAnilistMediaGuessMainDeps => ({
getState: () => deps.getState(),
setState: (state) => deps.setState(state),
resolveMediaPathForJimaku: (currentMediaPath) => deps.resolveMediaPathForJimaku(currentMediaPath),
resolveMediaPathForJimaku: (currentMediaPath) =>
deps.resolveMediaPathForJimaku(currentMediaPath),
getCurrentMediaPath: () => deps.getCurrentMediaPath(),
getCurrentMediaTitle: () => deps.getCurrentMediaTitle(),
guessAnilistMediaInfo: (mediaPath, mediaTitle) => deps.guessAnilistMediaInfo(mediaPath, mediaTitle),
guessAnilistMediaInfo: (mediaPath, mediaTitle) =>
deps.guessAnilistMediaInfo(mediaPath, mediaTitle),
});
}

View File

@@ -6,8 +6,12 @@ import type {
createSetAnilistMediaGuessRuntimeStateHandler,
} from './anilist-media-state';
type GetCurrentAnilistMediaKeyMainDeps = Parameters<typeof createGetCurrentAnilistMediaKeyHandler>[0];
type ResetAnilistMediaTrackingMainDeps = Parameters<typeof createResetAnilistMediaTrackingHandler>[0];
type GetCurrentAnilistMediaKeyMainDeps = Parameters<
typeof createGetCurrentAnilistMediaKeyHandler
>[0];
type ResetAnilistMediaTrackingMainDeps = Parameters<
typeof createResetAnilistMediaTrackingHandler
>[0];
type GetAnilistMediaGuessRuntimeStateMainDeps = Parameters<
typeof createGetAnilistMediaGuessRuntimeStateHandler
>[0];

View File

@@ -47,7 +47,8 @@ export function createBuildMaybeRunAnilistPostWatchUpdateMainDepsHandler(
hasAttemptedUpdateKey: (key: string) => deps.hasAttemptedUpdateKey(key),
processNextAnilistRetryUpdate: () => deps.processNextAnilistRetryUpdate(),
refreshAnilistClientSecretState: () => deps.refreshAnilistClientSecretState(),
enqueueRetry: (key: string, title: string, episode: number) => deps.enqueueRetry(key, title, episode),
enqueueRetry: (key: string, title: string, episode: number) =>
deps.enqueueRetry(key, title, episode),
markRetryFailure: (key: string, message: string) => deps.markRetryFailure(key, message),
markRetrySuccess: (key: string) => deps.markRetrySuccess(key),
refreshRetryQueueState: () => deps.refreshRetryQueueState(),

View File

@@ -64,7 +64,11 @@ export function createProcessNextAnilistRetryUpdateHandler(deps: {
return { ok: false, message: 'AniList token unavailable for queued retry.' };
}
const result = await deps.updateAnilistPostWatchProgress(accessToken, queued.title, queued.episode);
const result = await deps.updateAnilistPostWatchProgress(
accessToken,
queued.title,
queued.episode,
);
if (result.status === 'updated' || result.status === 'skipped') {
deps.markSuccess(queued.key);
deps.rememberAttemptedUpdateKey(queued.key);
@@ -166,7 +170,11 @@ export function createMaybeRunAnilistPostWatchUpdateHandler(deps: {
return;
}
const result = await deps.updateAnilistPostWatchProgress(accessToken, guess.title, guess.episode);
const result = await deps.updateAnilistPostWatchProgress(
accessToken,
guess.title,
guess.episode,
);
if (result.status === 'updated') {
deps.rememberAttemptedUpdateKey(attemptKey);
deps.markRetrySuccess(attemptKey);

View File

@@ -44,7 +44,8 @@ export function createBuildHandleAnilistSetupProtocolUrlMainDepsHandler(
deps: HandleAnilistSetupProtocolUrlMainDeps,
) {
return (): HandleAnilistSetupProtocolUrlMainDeps => ({
consumeAnilistSetupTokenFromUrl: (rawUrl: string) => deps.consumeAnilistSetupTokenFromUrl(rawUrl),
consumeAnilistSetupTokenFromUrl: (rawUrl: string) =>
deps.consumeAnilistSetupTokenFromUrl(rawUrl),
logWarn: (message: string, details: unknown) => deps.logWarn(message, details),
});
}

View File

@@ -66,11 +66,7 @@ export function createRegisterSubminerProtocolClientHandler(deps: {
getArgv: () => string[];
execPath: string;
resolvePath: (value: string) => string;
setAsDefaultProtocolClient: (
scheme: string,
path?: string,
args?: string[],
) => boolean;
setAsDefaultProtocolClient: (scheme: string, path?: string, args?: string[]) => boolean;
logWarn: (message: string, details?: unknown) => void;
}) {
return (): void => {

View File

@@ -259,7 +259,8 @@ test('open anilist setup handler no-ops when existing setup window focused', ()
test('open anilist setup handler wires navigation, fallback, and lifecycle', () => {
let openHandler: ((params: { url: string }) => { action: 'deny' }) | null = null;
let willNavigateHandler: ((event: { preventDefault: () => void }, url: string) => void) | null = null;
let willNavigateHandler: ((event: { preventDefault: () => void }, url: string) => void) | null =
null;
let didNavigateHandler: ((event: unknown, url: string) => void) | null = null;
let didFinishLoadHandler: (() => void) | null = null;
let didFailLoadHandler:
@@ -276,7 +277,12 @@ test('open anilist setup handler wires navigation, fallback, and lifecycle', ()
openHandler = handler;
},
on: (
event: 'will-navigate' | 'will-redirect' | 'did-navigate' | 'did-fail-load' | 'did-finish-load',
event:
| 'will-navigate'
| 'will-redirect'
| 'did-navigate'
| 'did-fail-load'
| 'did-finish-load',
handler: (...args: any[]) => void,
) => {
if (event === 'will-navigate') willNavigateHandler = handler as never;

View File

@@ -126,7 +126,11 @@ export function createAnilistSetupDidNavigateHandler(deps: {
}
export function createAnilistSetupDidFailLoadHandler(deps: {
onLoadFailure: (details: { errorCode: number; errorDescription: string; validatedURL: string }) => void;
onLoadFailure: (details: {
errorCode: number;
errorDescription: string;
validatedURL: string;
}) => void;
}) {
return (details: { errorCode: number; errorDescription: string; validatedURL: string }): void => {
deps.onLoadFailure(details);
@@ -175,7 +179,11 @@ export function createAnilistSetupFallbackHandler(deps: {
logWarn: (message: string) => void;
}) {
return {
onLoadFailure: (details: { errorCode: number; errorDescription: string; validatedURL: string }) => {
onLoadFailure: (details: {
errorCode: number;
errorDescription: string;
validatedURL: string;
}) => {
deps.logError('AniList setup window failed to load', details);
deps.openSetupInBrowser();
if (!deps.setupWindow.isDestroyed()) {
@@ -298,12 +306,7 @@ export function createOpenAnilistSetupWindowHandler<TWindow extends AnilistSetup
});
setupWindow.webContents.on(
'did-fail-load',
(
_event: unknown,
errorCode: number,
errorDescription: string,
validatedURL: string,
) => {
(_event: unknown, errorCode: number, errorDescription: string, validatedURL: string) => {
handleDidFailLoad({
errorCode,
errorDescription,

View File

@@ -65,9 +65,7 @@ export function findAnilistSetupDeepLinkArgvUrl(argv: readonly string[]): string
return null;
}
export function consumeAnilistSetupCallbackUrl(
deps: ConsumeAnilistSetupCallbackUrlDeps,
): boolean {
export function consumeAnilistSetupCallbackUrl(deps: ConsumeAnilistSetupCallbackUrlDeps): boolean {
const token = extractAnilistAccessTokenFromUrl(deps.rawUrl);
if (!token) {
return false;

View File

@@ -12,7 +12,9 @@ type ConfigWithAnilistToken = {
};
};
export function createRefreshAnilistClientSecretStateHandler<TConfig extends ConfigWithAnilistToken>(deps: {
export function createRefreshAnilistClientSecretStateHandler<
TConfig extends ConfigWithAnilistToken,
>(deps: {
getResolvedConfig: () => TConfig;
isAnilistTrackingEnabled: (config: TConfig) => boolean;
getCachedAccessToken: () => string | null;

View File

@@ -24,7 +24,9 @@ export function createBuildUpdateLastCardFromClipboardMainDepsHandler<TAnki>(dep
});
}
export function createBuildRefreshKnownWordCacheMainDepsHandler(deps: RefreshKnownWordCacheMainDeps) {
export function createBuildRefreshKnownWordCacheMainDepsHandler(
deps: RefreshKnownWordCacheMainDeps,
) {
return (): RefreshKnownWordCacheMainDeps => ({
getAnkiIntegration: () => deps.getAnkiIntegration(),
missingIntegrationMessage: deps.missingIntegrationMessage,
@@ -42,8 +44,10 @@ export function createBuildTriggerFieldGroupingMainDepsHandler<TAnki>(deps: {
return () => ({
getAnkiIntegration: () => deps.getAnkiIntegration(),
showMpvOsd: (text: string) => deps.showMpvOsd(text),
triggerFieldGroupingCore: (options: { ankiIntegration: TAnki; showMpvOsd: (text: string) => void }) =>
deps.triggerFieldGroupingCore(options),
triggerFieldGroupingCore: (options: {
ankiIntegration: TAnki;
showMpvOsd: (text: string) => void;
}) => deps.triggerFieldGroupingCore(options),
});
}
@@ -58,8 +62,10 @@ export function createBuildMarkLastCardAsAudioCardMainDepsHandler<TAnki>(deps: {
return () => ({
getAnkiIntegration: () => deps.getAnkiIntegration(),
showMpvOsd: (text: string) => deps.showMpvOsd(text),
markLastCardAsAudioCardCore: (options: { ankiIntegration: TAnki; showMpvOsd: (text: string) => void }) =>
deps.markLastCardAsAudioCardCore(options),
markLastCardAsAudioCardCore: (options: {
ankiIntegration: TAnki;
showMpvOsd: (text: string) => void;
}) => deps.markLastCardAsAudioCardCore(options),
});
}

View File

@@ -52,8 +52,7 @@ export function createBuildOnWillQuitCleanupDepsHandler(deps: {
destroyTray: () => deps.destroyTray(),
stopConfigHotReload: () => deps.stopConfigHotReload(),
restorePreviousSecondarySubVisibility: () => deps.restorePreviousSecondarySubVisibility(),
restoreMpvSubVisibility: () =>
deps.restoreMpvSubVisibility(),
restoreMpvSubVisibility: () => deps.restoreMpvSubVisibility(),
unregisterAllGlobalShortcuts: () => deps.unregisterAllGlobalShortcuts(),
stopSubtitleWebsocket: () => deps.stopSubtitleWebsocket(),
stopTexthookerService: () => deps.stopTexthookerService(),

View File

@@ -1,8 +1,6 @@
import type { AppReadyRuntimeDepsFactoryInput } from '../app-lifecycle';
export function createBuildAppReadyRuntimeMainDepsHandler(
deps: AppReadyRuntimeDepsFactoryInput,
) {
export function createBuildAppReadyRuntimeMainDepsHandler(deps: AppReadyRuntimeDepsFactoryInput) {
return (): AppReadyRuntimeDepsFactoryInput => ({
loadSubtitlePosition: deps.loadSubtitlePosition,
resolveKeybindings: deps.resolveKeybindings,
@@ -27,8 +25,7 @@ export function createBuildAppReadyRuntimeMainDepsHandler(
prewarmSubtitleDictionaries: deps.prewarmSubtitleDictionaries,
startBackgroundWarmups: deps.startBackgroundWarmups,
texthookerOnlyMode: deps.texthookerOnlyMode,
shouldAutoInitializeOverlayRuntimeFromConfig:
deps.shouldAutoInitializeOverlayRuntimeFromConfig,
shouldAutoInitializeOverlayRuntimeFromConfig: deps.shouldAutoInitializeOverlayRuntimeFromConfig,
initializeOverlayRuntime: deps.initializeOverlayRuntime,
handleInitialArgs: deps.handleInitialArgs,
onCriticalConfigErrors: deps.onCriticalConfigErrors,

View File

@@ -70,7 +70,8 @@ test('open yomitan settings main deps map async open callbacks', async () => {
const extension = { id: 'ext' };
const deps = createBuildOpenYomitanSettingsMainDepsHandler({
ensureYomitanExtensionLoaded: async () => extension,
openYomitanSettingsWindow: ({ yomitanExt }) => calls.push(`open:${(yomitanExt as { id: string }).id}`),
openYomitanSettingsWindow: ({ yomitanExt }) =>
calls.push(`open:${(yomitanExt as { id: string }).id}`),
getExistingWindow: () => currentWindow,
setWindow: (window) => {
currentWindow = window;

View File

@@ -2,9 +2,7 @@ import { createCliCommandContext } from './cli-command-context';
import { createBuildCliCommandContextDepsHandler } from './cli-command-context-deps';
import { createBuildCliCommandContextMainDepsHandler } from './cli-command-context-main-deps';
type CliCommandContextMainDeps = Parameters<
typeof createBuildCliCommandContextMainDepsHandler
>[0];
type CliCommandContextMainDeps = Parameters<typeof createBuildCliCommandContextMainDepsHandler>[0];
export function createCliCommandContextFactory(deps: CliCommandContextMainDeps) {
const buildCliCommandContextMainDepsHandler = createBuildCliCommandContextMainDepsHandler(deps);

View File

@@ -34,11 +34,11 @@ function createDeps() {
triggerFieldGrouping: async () => {},
triggerSubsyncFromConfig: async () => {},
markLastCardAsAudioCard: async () => {},
getAnilistStatus: () => ({} as never),
getAnilistStatus: () => ({}) as never,
clearAnilistToken: () => {},
openAnilistSetup: () => {},
openJellyfinSetup: () => {},
getAnilistQueueStatus: () => ({} as never),
getAnilistQueueStatus: () => ({}) as never,
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
runJellyfinCommand: async () => {},
openYomitanSettings: () => {},

View File

@@ -15,12 +15,11 @@ export function createCliCommandRuntimeHandler<TCliContext>(deps: {
cliContext: TCliContext,
) => void;
}) {
const handleTexthookerOnlyModeTransitionHandler =
createHandleTexthookerOnlyModeTransitionHandler(
createBuildHandleTexthookerOnlyModeTransitionMainDepsHandler(
deps.handleTexthookerOnlyModeTransitionMainDeps,
)(),
);
const handleTexthookerOnlyModeTransitionHandler = createHandleTexthookerOnlyModeTransitionHandler(
createBuildHandleTexthookerOnlyModeTransitionMainDepsHandler(
deps.handleTexthookerOnlyModeTransitionMainDeps,
)(),
);
return (args: CliArgs, source: CliCommandSource = 'initial'): void => {
handleTexthookerOnlyModeTransitionHandler(args);

View File

@@ -13,9 +13,10 @@ export type AppendClipboardVideoToQueueRuntimeDeps = {
sendMpvCommand: (command: (string | number)[]) => void;
};
export function appendClipboardVideoToQueueRuntime(
deps: AppendClipboardVideoToQueueRuntimeDeps,
): { ok: boolean; message: string } {
export function appendClipboardVideoToQueueRuntime(deps: AppendClipboardVideoToQueueRuntimeDeps): {
ok: boolean;
message: string;
} {
const mpvClient = deps.getMpvClient();
if (!mpvClient || !mpvClient.connected) {
return { ok: false, message: 'MPV is not connected.' };

View File

@@ -6,7 +6,8 @@ test('composeJellyfinRemoteHandlers returns callable jellyfin remote handlers',
let lastProgressAt = 0;
const composed = composeJellyfinRemoteHandlers({
getConfiguredSession: () => null,
getClientInfo: () => ({ clientName: 'SubMiner', clientVersion: 'test', deviceId: 'dev' }) as never,
getClientInfo: () =>
({ clientName: 'SubMiner', clientVersion: 'test', deviceId: 'dev' }) as never,
getJellyfinConfig: () => ({ enabled: false }) as never,
playJellyfinItem: async () => {},
logWarn: () => {},

View File

@@ -141,7 +141,7 @@ export function composeMpvRuntimeHandlers<
if (!options.tokenizer.createMecabTokenizerAndCheckMainDeps.getMecabTokenizer()) {
await createMecabTokenizerAndCheck().catch(() => {});
}
await prewarmSubtitleDictionaries({ showLoadingOsd: true });
await prewarmSubtitleDictionaries({ showLoadingOsd: true });
})().finally(() => {
tokenizationWarmupInFlight = null;
});

View File

@@ -39,7 +39,10 @@ export function createConfigDerivedRuntime(deps: ConfigDerivedRuntimeDeps): {
deps.defaultJimakuLanguagePreference,
),
getJimakuMaxEntryResults: () =>
getJimakuMaxEntryResultsCore(() => deps.getResolvedConfig(), deps.defaultJimakuMaxEntryResults),
getJimakuMaxEntryResultsCore(
() => deps.getResolvedConfig(),
deps.defaultJimakuMaxEntryResults,
),
resolveJimakuApiKey: () => resolveJimakuApiKeyCore(() => deps.getResolvedConfig()),
jimakuFetchJson: <T>(
endpoint: string,

View File

@@ -111,7 +111,7 @@ test('config hot reload applied main deps builder maps callbacks', () => {
test('config hot reload runtime main deps builder maps runtime callbacks', () => {
const calls: string[] = [];
const deps = createBuildConfigHotReloadRuntimeMainDepsHandler({
getCurrentConfig: () => ({ id: 1 } as never as ResolvedConfig),
getCurrentConfig: () => ({ id: 1 }) as never as ResolvedConfig,
reloadConfigStrict: () =>
({
ok: true,
@@ -144,5 +144,10 @@ test('config hot reload runtime main deps builder maps runtime callbacks', () =>
deps.onRestartRequired([]);
deps.onInvalidConfig('bad');
deps.onValidationWarnings('/tmp/config.jsonc', []);
assert.deepEqual(calls, ['hot-reload', 'restart-required', 'invalid-config', 'validation-warnings']);
assert.deepEqual(calls, [
'hot-reload',
'restart-required',
'invalid-config',
'validation-warnings',
]);
});

View File

@@ -3,7 +3,12 @@ import type {
ConfigHotReloadRuntimeDeps,
} from '../../core/services/config-hot-reload';
import type { ReloadConfigStrictResult } from '../../config';
import type { ConfigHotReloadPayload, ConfigValidationWarning, ResolvedConfig, SecondarySubMode } from '../../types';
import type {
ConfigHotReloadPayload,
ConfigValidationWarning,
ResolvedConfig,
SecondarySubMode,
} from '../../types';
import type { createConfigHotReloadMessageHandler } from './config-hot-reload-handlers';
type ConfigWatchListener = (eventType: string, filename: string | null) => void;

View File

@@ -29,7 +29,8 @@ test('jlpt dictionary runtime main deps builder maps search paths and log prefix
const deps = createBuildJlptDictionaryRuntimeMainDepsHandler({
isJlptEnabled: () => true,
getDictionaryRoots: () => ['/root/a'],
getJlptDictionarySearchPaths: ({ getDictionaryRoots }) => getDictionaryRoots().map((path) => `${path}/jlpt`),
getJlptDictionarySearchPaths: ({ getDictionaryRoots }) =>
getDictionaryRoots().map((path) => `${path}/jlpt`),
setJlptLevelLookup: () => calls.push('set-lookup'),
logInfo: (message) => calls.push(`log:${message}`),
})();

View File

@@ -12,20 +12,24 @@ test('get configured shortcuts main deps map config resolver inputs', () => {
const build = createBuildGetConfiguredShortcutsMainDepsHandler({
getResolvedConfig: () => config,
defaultConfig: defaults,
resolveConfiguredShortcuts: (nextConfig, nextDefaults) => ({ nextConfig, nextDefaults }) as never,
resolveConfiguredShortcuts: (nextConfig, nextDefaults) =>
({ nextConfig, nextDefaults }) as never,
});
const deps = build();
assert.equal(deps.getResolvedConfig(), config);
assert.equal(deps.defaultConfig, defaults);
assert.deepEqual(deps.resolveConfiguredShortcuts(config, defaults), { nextConfig: config, nextDefaults: defaults });
assert.deepEqual(deps.resolveConfiguredShortcuts(config, defaults), {
nextConfig: config,
nextDefaults: defaults,
});
});
test('register global shortcuts main deps map callbacks and flags', () => {
const calls: string[] = [];
const mainWindow = { id: 'main' };
const build = createBuildRegisterGlobalShortcutsMainDepsHandler({
getConfiguredShortcuts: () => ({ copySubtitle: 's' } as never),
getConfiguredShortcuts: () => ({ copySubtitle: 's' }) as never,
registerGlobalShortcutsCore: () => calls.push('register'),
toggleVisibleOverlay: () => calls.push('toggle-visible'),
openYomitanSettings: () => calls.push('open-yomitan'),

View File

@@ -32,15 +32,17 @@ export function createGlobalShortcutsRuntimeHandlers(deps: {
const getConfiguredShortcutsMainDeps = createBuildGetConfiguredShortcutsMainDepsHandler(
deps.getConfiguredShortcutsMainDeps,
)();
const getConfiguredShortcutsHandler =
createGetConfiguredShortcutsHandler(getConfiguredShortcutsMainDeps);
const getConfiguredShortcutsHandler = createGetConfiguredShortcutsHandler(
getConfiguredShortcutsMainDeps,
);
const getConfiguredShortcuts = () => getConfiguredShortcutsHandler();
const registerGlobalShortcutsMainDeps = createBuildRegisterGlobalShortcutsMainDepsHandler(
deps.buildRegisterGlobalShortcutsMainDeps(getConfiguredShortcuts),
)();
const registerGlobalShortcutsHandler =
createRegisterGlobalShortcutsHandler(registerGlobalShortcutsMainDeps);
const registerGlobalShortcutsHandler = createRegisterGlobalShortcutsHandler(
registerGlobalShortcutsMainDeps,
);
const registerGlobalShortcuts = () => registerGlobalShortcutsHandler();
const refreshGlobalAndOverlayShortcutsMainDeps =

View File

@@ -5,10 +5,7 @@ import type { RegisterGlobalShortcutsServiceOptions } from '../../core/services/
export function createGetConfiguredShortcutsHandler(deps: {
getResolvedConfig: () => Config;
defaultConfig: Config;
resolveConfiguredShortcuts: (
config: Config,
defaultConfig: Config,
) => ConfiguredShortcuts;
resolveConfiguredShortcuts: (config: Config, defaultConfig: Config) => ConfiguredShortcuts;
}) {
return (): ConfiguredShortcuts =>
deps.resolveConfiguredShortcuts(deps.getResolvedConfig(), deps.defaultConfig);

View File

@@ -5,7 +5,7 @@ import { createBuildImmersionTrackerStartupMainDepsHandler } from './immersion-s
test('immersion tracker startup main deps builder maps callbacks', () => {
const calls: string[] = [];
const deps = createBuildImmersionTrackerStartupMainDepsHandler({
getResolvedConfig: () => ({ immersionTracking: { enabled: true } } as never),
getResolvedConfig: () => ({ immersionTracking: { enabled: true } }) as never,
getConfiguredDbPath: () => '/tmp/immersion.db',
createTrackerService: () => {
calls.push('create');
@@ -21,9 +21,12 @@ test('immersion tracker startup main deps builder maps callbacks', () => {
assert.deepEqual(deps.getResolvedConfig(), { immersionTracking: { enabled: true } });
assert.equal(deps.getConfiguredDbPath(), '/tmp/immersion.db');
assert.deepEqual(deps.createTrackerService({ dbPath: '/tmp/immersion.db', policy: {} as never }), {
id: 'tracker',
});
assert.deepEqual(
deps.createTrackerService({ dbPath: '/tmp/immersion.db', policy: {} as never }),
{
id: 'tracker',
},
);
deps.setTracker(null);
assert.equal(deps.getMpvClient()?.connected, true);
deps.seedTrackerFromCurrentMedia();

View File

@@ -24,7 +24,7 @@ test('initial args handler no-ops without initial args', () => {
test('initial args handler ensures tray in background mode', () => {
let ensuredTray = false;
const handleInitialArgs = createHandleInitialArgsHandler({
getInitialArgs: () => ({ start: true } as never),
getInitialArgs: () => ({ start: true }) as never,
isBackgroundMode: () => true,
ensureTray: () => {
ensuredTray = true;
@@ -44,7 +44,7 @@ test('initial args handler auto-connects mpv when needed', () => {
let connectCalls = 0;
let logged = false;
const handleInitialArgs = createHandleInitialArgsHandler({
getInitialArgs: () => ({ start: true } as never),
getInitialArgs: () => ({ start: true }) as never,
isBackgroundMode: () => false,
ensureTray: () => {},
isTexthookerOnlyMode: () => false,
@@ -69,7 +69,7 @@ test('initial args handler auto-connects mpv when needed', () => {
test('initial args handler forwards args to cli handler', () => {
const seenSources: string[] = [];
const handleInitialArgs = createHandleInitialArgsHandler({
getInitialArgs: () => ({ start: true } as never),
getInitialArgs: () => ({ start: true }) as never,
isBackgroundMode: () => false,
ensureTray: () => {},
isTexthookerOnlyMode: () => false,

View File

@@ -5,7 +5,7 @@ import { createInitialArgsRuntimeHandler } from './initial-args-runtime-handler'
test('initial args runtime handler composes main deps and runs initial command flow', () => {
const calls: string[] = [];
const handleInitialArgs = createInitialArgsRuntimeHandler({
getInitialArgs: () => ({ start: true } as never),
getInitialArgs: () => ({ start: true }) as never,
isBackgroundMode: () => true,
ensureTray: () => calls.push('tray'),
isTexthookerOnlyMode: () => false,
@@ -20,5 +20,10 @@ test('initial args runtime handler composes main deps and runs initial command f
handleInitialArgs();
assert.deepEqual(calls, ['tray', 'log:Auto-connecting MPV client for immersion tracking', 'connect', 'cli:initial']);
assert.deepEqual(calls, [
'tray',
'log:Auto-connecting MPV client for immersion tracking',
'connect',
'cli:initial',
]);
});

View File

@@ -1,6 +1,8 @@
import type { MpvCommandFromIpcRuntimeDeps } from '../ipc-mpv-command';
export function createBuildMpvCommandFromIpcRuntimeMainDepsHandler(deps: MpvCommandFromIpcRuntimeDeps) {
export function createBuildMpvCommandFromIpcRuntimeMainDepsHandler(
deps: MpvCommandFromIpcRuntimeDeps,
) {
return (): MpvCommandFromIpcRuntimeDeps => ({
triggerSubsyncFromConfig: () => deps.triggerSubsyncFromConfig(),
openRuntimeOptionsPalette: () => deps.openRuntimeOptionsPalette(),

View File

@@ -1,4 +1,7 @@
import { createHandleMpvCommandFromIpcHandler, createRunSubsyncManualFromIpcHandler } from './ipc-bridge-actions';
import {
createHandleMpvCommandFromIpcHandler,
createRunSubsyncManualFromIpcHandler,
} from './ipc-bridge-actions';
import {
createBuildHandleMpvCommandFromIpcMainDepsHandler,
createBuildRunSubsyncManualFromIpcMainDepsHandler,
@@ -22,10 +25,10 @@ export function createIpcRuntimeHandlers<TRequest, TResult>(deps: {
handleMpvCommandFromIpcMainDeps,
);
const runSubsyncManualFromIpcMainDeps =
createBuildRunSubsyncManualFromIpcMainDepsHandler<TRequest, TResult>(
deps.runSubsyncManualFromIpcDeps,
)();
const runSubsyncManualFromIpcMainDeps = createBuildRunSubsyncManualFromIpcMainDepsHandler<
TRequest,
TResult
>(deps.runSubsyncManualFromIpcDeps)();
const runSubsyncManualFromIpc = createRunSubsyncManualFromIpcHandler<TRequest, TResult>(
runSubsyncManualFromIpcMainDeps,
);

View File

@@ -94,7 +94,11 @@ export function createHandleJellyfinListCommands(deps: {
if (!args.jellyfinItemId) {
throw new Error('Missing --jellyfin-item-id for --jellyfin-subtitles.');
}
const tracks = await deps.listJellyfinSubtitleTracks(session, clientInfo, args.jellyfinItemId);
const tracks = await deps.listJellyfinSubtitleTracks(
session,
clientInfo,
args.jellyfinItemId,
);
if (tracks.length === 0) {
deps.logInfo('No Jellyfin subtitle tracks found for item.');
return true;

View File

@@ -1,15 +1,7 @@
import type {
createHandleJellyfinAuthCommands,
} from './jellyfin-cli-auth';
import type {
createHandleJellyfinListCommands,
} from './jellyfin-cli-list';
import type {
createHandleJellyfinPlayCommand,
} from './jellyfin-cli-play';
import type {
createHandleJellyfinRemoteAnnounceCommand,
} from './jellyfin-cli-remote-announce';
import type { createHandleJellyfinAuthCommands } from './jellyfin-cli-auth';
import type { createHandleJellyfinListCommands } from './jellyfin-cli-list';
import type { createHandleJellyfinPlayCommand } from './jellyfin-cli-play';
import type { createHandleJellyfinRemoteAnnounceCommand } from './jellyfin-cli-remote-announce';
type HandleJellyfinAuthCommandsMainDeps = Parameters<typeof createHandleJellyfinAuthCommands>[0];
type HandleJellyfinListCommandsMainDeps = Parameters<typeof createHandleJellyfinListCommands>[0];

View File

@@ -3,7 +3,9 @@ import type {
createGetResolvedJellyfinConfigHandler,
} from './jellyfin-client-info';
type GetResolvedJellyfinConfigMainDeps = Parameters<typeof createGetResolvedJellyfinConfigHandler>[0];
type GetResolvedJellyfinConfigMainDeps = Parameters<
typeof createGetResolvedJellyfinConfigHandler
>[0];
type GetJellyfinClientInfoMainDeps = Parameters<typeof createGetJellyfinClientInfoHandler>[0];
export function createBuildGetResolvedJellyfinConfigMainDepsHandler(

View File

@@ -8,7 +8,7 @@ import {
test('get resolved jellyfin config returns jellyfin section from resolved config', () => {
const jellyfin = { url: 'https://jellyfin.local' } as never;
const getConfig = createGetResolvedJellyfinConfigHandler({
getResolvedConfig: () => ({ jellyfin } as never),
getResolvedConfig: () => ({ jellyfin }) as never,
loadStoredSession: () => null,
getEnv: () => undefined,
});
@@ -68,8 +68,7 @@ test('get resolved jellyfin config uses stored user id when env token set withou
},
}) as never,
loadStoredSession: () => ({ accessToken: 'stored-token', userId: 'stored-user' }),
getEnv: (key: string) =>
key === 'SUBMINER_JELLYFIN_ACCESS_TOKEN' ? 'env-token' : undefined,
getEnv: (key: string) => (key === 'SUBMINER_JELLYFIN_ACCESS_TOKEN' ? 'env-token' : undefined),
});
assert.deepEqual(getConfig(), {
@@ -81,7 +80,7 @@ test('get resolved jellyfin config uses stored user id when env token set withou
test('jellyfin client info resolves defaults when fields are missing', () => {
const getClientInfo = createGetJellyfinClientInfoHandler({
getResolvedJellyfinConfig: () => ({ clientName: '', clientVersion: '', deviceId: '' } as never),
getResolvedJellyfinConfig: () => ({ clientName: '', clientVersion: '', deviceId: '' }) as never,
getDefaultJellyfinConfig: () =>
({
clientName: 'SubMiner',

View File

@@ -2,7 +2,9 @@ import type { createPlayJellyfinItemInMpvHandler } from './jellyfin-playback-lau
type PlayJellyfinItemInMpvMainDeps = Parameters<typeof createPlayJellyfinItemInMpvHandler>[0];
export function createBuildPlayJellyfinItemInMpvMainDepsHandler(deps: PlayJellyfinItemInMpvMainDeps) {
export function createBuildPlayJellyfinItemInMpvMainDepsHandler(
deps: PlayJellyfinItemInMpvMainDeps,
) {
return (): PlayJellyfinItemInMpvMainDeps => ({
ensureMpvConnectedForPlayback: () => deps.ensureMpvConnectedForPlayback(),
getMpvClient: () => deps.getMpvClient(),

View File

@@ -136,6 +136,8 @@ test('createHandleJellyfinRemoteGeneralCommand mutates active playback indices',
assert.equal(playback.subtitleStreamIndex, null);
assert.ok(calls.includes('progress:true'));
assert.ok(
calls.some((entry) => entry.includes('Ignoring unsupported Jellyfin GeneralCommand: UnsupportedCommand')),
calls.some((entry) =>
entry.includes('Ignoring unsupported Jellyfin GeneralCommand: UnsupportedCommand'),
),
);
});

View File

@@ -44,7 +44,9 @@ export type JellyfinRemoteProgressReporterDeps = {
logDebug: (message: string, error: unknown) => void;
};
export function createReportJellyfinRemoteProgressHandler(deps: JellyfinRemoteProgressReporterDeps) {
export function createReportJellyfinRemoteProgressHandler(
deps: JellyfinRemoteProgressReporterDeps,
) {
return async (force = false): Promise<void> => {
const playback = deps.getActivePlayback();
if (!playback) return;

View File

@@ -3,8 +3,12 @@ import type {
createStopJellyfinRemoteSessionHandler,
} from './jellyfin-remote-session-lifecycle';
type StartJellyfinRemoteSessionMainDeps = Parameters<typeof createStartJellyfinRemoteSessionHandler>[0];
type StopJellyfinRemoteSessionMainDeps = Parameters<typeof createStopJellyfinRemoteSessionHandler>[0];
type StartJellyfinRemoteSessionMainDeps = Parameters<
typeof createStartJellyfinRemoteSessionHandler
>[0];
type StopJellyfinRemoteSessionMainDeps = Parameters<
typeof createStopJellyfinRemoteSessionHandler
>[0];
export function createBuildStartJellyfinRemoteSessionMainDepsHandler(
deps: StartJellyfinRemoteSessionMainDeps,

View File

@@ -16,7 +16,11 @@ test('open jellyfin setup window main deps builder maps callbacks', async () =>
accessToken: 'token',
userId: 'uid',
}),
getJellyfinClientInfo: () => ({ clientName: 'SubMiner', clientVersion: '1.0', deviceId: 'dev' }),
getJellyfinClientInfo: () => ({
clientName: 'SubMiner',
clientVersion: '1.0',
deviceId: 'dev',
}),
saveStoredSession: () => calls.push('save'),
patchJellyfinConfig: () => calls.push('patch'),
logInfo: (message) => calls.push(`info:${message}`),
@@ -38,12 +42,15 @@ test('open jellyfin setup window main deps builder maps callbacks', async () =>
username: 'u',
password: 'p',
});
assert.deepEqual(await deps.authenticateWithPassword('s', 'u', 'p', deps.getJellyfinClientInfo()), {
serverUrl: 'http://127.0.0.1:8096',
username: 'alice',
accessToken: 'token',
userId: 'uid',
});
assert.deepEqual(
await deps.authenticateWithPassword('s', 'u', 'p', deps.getJellyfinClientInfo()),
{
serverUrl: 'http://127.0.0.1:8096',
username: 'alice',
accessToken: 'token',
userId: 'uid',
},
);
deps.saveStoredSession({ accessToken: 'token', userId: 'uid' });
deps.patchJellyfinConfig({
serverUrl: 'http://127.0.0.1:8096',
@@ -57,5 +64,13 @@ test('open jellyfin setup window main deps builder maps callbacks', async () =>
deps.clearSetupWindow();
deps.setSetupWindow({} as never);
assert.equal(deps.encodeURIComponent('a b'), 'a%20b');
assert.deepEqual(calls, ['save', 'patch', 'info:ok', 'error:bad', 'osd:toast', 'clear', 'set-window']);
assert.deepEqual(calls, [
'save',
'patch',
'info:ok',
'error:bad',
'osd:toast',
'clear',
'set-window',
]);
});

View File

@@ -50,7 +50,11 @@ test('createHandleJellyfinSetupSubmissionHandler applies successful login', asyn
accessToken: 'token',
userId: 'uid',
}),
getJellyfinClientInfo: () => ({ clientName: 'SubMiner', clientVersion: '1.0', deviceId: 'did' }),
getJellyfinClientInfo: () => ({
clientName: 'SubMiner',
clientVersion: '1.0',
deviceId: 'did',
}),
saveStoredSession: (session) => {
savedSession = session;
calls.push('save');
@@ -86,7 +90,11 @@ test('createHandleJellyfinSetupSubmissionHandler reports failure to OSD', async
authenticateWithPassword: async () => {
throw new Error('bad credentials');
},
getJellyfinClientInfo: () => ({ clientName: 'SubMiner', clientVersion: '1.0', deviceId: 'did' }),
getJellyfinClientInfo: () => ({
clientName: 'SubMiner',
clientVersion: '1.0',
deviceId: 'did',
}),
saveStoredSession: () => calls.push('save'),
patchJellyfinConfig: () => calls.push('patch'),
logInfo: () => calls.push('info'),
@@ -180,7 +188,11 @@ test('createOpenJellyfinSetupWindowHandler no-ops when existing setup window is
authenticateWithPassword: async () => {
throw new Error('should not auth');
},
getJellyfinClientInfo: () => ({ clientName: 'SubMiner', clientVersion: '1.0', deviceId: 'did' }),
getJellyfinClientInfo: () => ({
clientName: 'SubMiner',
clientVersion: '1.0',
deviceId: 'did',
}),
saveStoredSession: () => {},
patchJellyfinConfig: () => {},
logInfo: () => {},
@@ -196,14 +208,18 @@ test('createOpenJellyfinSetupWindowHandler no-ops when existing setup window is
});
test('createOpenJellyfinSetupWindowHandler wires navigation, load, and window lifecycle', async () => {
let willNavigateHandler: ((event: { preventDefault: () => void }, url: string) => void) | null = null;
let willNavigateHandler: ((event: { preventDefault: () => void }, url: string) => void) | null =
null;
let closedHandler: (() => void) | null = null;
let prevented = false;
const calls: string[] = [];
const fakeWindow = {
focus: () => {},
webContents: {
on: (event: 'will-navigate', handler: (event: { preventDefault: () => void }, url: string) => void) => {
on: (
event: 'will-navigate',
handler: (event: { preventDefault: () => void }, url: string) => void,
) => {
if (event === 'will-navigate') {
willNavigateHandler = handler;
}
@@ -233,7 +249,11 @@ test('createOpenJellyfinSetupWindowHandler wires navigation, load, and window li
accessToken: 'token',
userId: 'uid',
}),
getJellyfinClientInfo: () => ({ clientName: 'SubMiner', clientVersion: '1.0', deviceId: 'did' }),
getJellyfinClientInfo: () => ({
clientName: 'SubMiner',
clientVersion: '1.0',
deviceId: 'did',
}),
saveStoredSession: () => calls.push('save'),
patchJellyfinConfig: () => calls.push('patch'),
logInfo: () => calls.push('info'),
@@ -249,7 +269,9 @@ test('createOpenJellyfinSetupWindowHandler wires navigation, load, and window li
assert.ok(closedHandler);
assert.deepEqual(calls.slice(0, 2), ['load:data-url', 'set-window']);
const navHandler = willNavigateHandler as ((event: { preventDefault: () => void }, url: string) => void) | null;
const navHandler = willNavigateHandler as
| ((event: { preventDefault: () => void }, url: string) => void)
| null;
if (!navHandler) {
throw new Error('missing will-navigate handler');
}

View File

@@ -109,7 +109,9 @@ export function parseJellyfinSetupSubmissionUrl(rawUrl: string): {
}
export function createHandleJellyfinSetupSubmissionHandler(deps: {
parseSubmissionUrl: (rawUrl: string) => { server: string; username: string; password: string } | null;
parseSubmissionUrl: (
rawUrl: string,
) => { server: string; username: string; password: string } | null;
authenticateWithPassword: (
server: string,
username: string,
@@ -179,20 +181,22 @@ export function createHandleJellyfinSetupWindowClosedHandler(deps: {
};
}
export function createHandleJellyfinSetupWindowOpenedHandler(deps: {
setSetupWindow: () => void;
}) {
export function createHandleJellyfinSetupWindowOpenedHandler(deps: { setSetupWindow: () => void }) {
return (): void => {
deps.setSetupWindow();
};
}
export function createOpenJellyfinSetupWindowHandler<TWindow extends JellyfinSetupWindowLike>(deps: {
export function createOpenJellyfinSetupWindowHandler<
TWindow extends JellyfinSetupWindowLike,
>(deps: {
maybeFocusExistingSetupWindow: () => boolean;
createSetupWindow: () => TWindow;
getResolvedJellyfinConfig: () => { serverUrl?: string | null; username?: string | null };
buildSetupFormHtml: (defaultServer: string, defaultUser: string) => string;
parseSubmissionUrl: (rawUrl: string) => { server: string; username: string; password: string } | null;
parseSubmissionUrl: (
rawUrl: string,
) => { server: string; username: string; password: string } | null;
authenticateWithPassword: (
server: string,
username: string,
@@ -258,9 +262,7 @@ export function createOpenJellyfinSetupWindowHandler<TWindow extends JellyfinSet
},
});
});
void setupWindow.loadURL(
`data:text/html;charset=utf-8,${deps.encodeURIComponent(formHtml)}`,
);
void setupWindow.loadURL(`data:text/html;charset=utf-8,${deps.encodeURIComponent(formHtml)}`);
setupWindow.on('closed', () => {
handleWindowClosed();
});

View File

@@ -117,13 +117,7 @@ export function createPreloadJellyfinExternalSubtitlesHandler(deps: {
seenUrls.add(track.deliveryUrl);
const labelBase = (track.title || track.language || '').trim();
const label = labelBase || `Jellyfin Subtitle ${track.index}`;
deps.sendMpvCommand([
'sub-add',
track.deliveryUrl,
'cached',
label,
track.language || '',
]);
deps.sendMpvCommand(['sub-add', track.deliveryUrl, 'cached', label, track.language || '']);
}
await deps.wait(250);

View File

@@ -39,27 +39,28 @@ export function createCopyCurrentSubtitleHandler<TSubtitleTimingTracker>(deps: {
};
}
export function createHandleMineSentenceDigitHandler<TSubtitleTimingTracker, TAnkiIntegration>(
deps: {
getSubtitleTimingTracker: () => TSubtitleTimingTracker;
getAnkiIntegration: () => TAnkiIntegration;
getCurrentSecondarySubText: () => string | undefined;
showMpvOsd: (text: string) => void;
logError: (message: string, err: unknown) => void;
onCardsMined: (count: number) => void;
handleMineSentenceDigitCore: (
count: number,
options: {
subtitleTimingTracker: TSubtitleTimingTracker;
ankiIntegration: TAnkiIntegration;
getCurrentSecondarySubText: () => string | undefined;
showMpvOsd: (text: string) => void;
logError: (message: string, err: unknown) => void;
onCardsMined: (count: number) => void;
},
) => void;
},
) {
export function createHandleMineSentenceDigitHandler<
TSubtitleTimingTracker,
TAnkiIntegration,
>(deps: {
getSubtitleTimingTracker: () => TSubtitleTimingTracker;
getAnkiIntegration: () => TAnkiIntegration;
getCurrentSecondarySubText: () => string | undefined;
showMpvOsd: (text: string) => void;
logError: (message: string, err: unknown) => void;
onCardsMined: (count: number) => void;
handleMineSentenceDigitCore: (
count: number,
options: {
subtitleTimingTracker: TSubtitleTimingTracker;
ankiIntegration: TAnkiIntegration;
getCurrentSecondarySubText: () => string | undefined;
showMpvOsd: (text: string) => void;
logError: (message: string, err: unknown) => void;
onCardsMined: (count: number) => void;
},
) => void;
}) {
return (count: number): void => {
deps.handleMineSentenceDigitCore(count, {
subtitleTimingTracker: deps.getSubtitleTimingTracker(),

View File

@@ -7,7 +7,10 @@ test('mpv runtime service main deps builder maps state and callbacks', () => {
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
class FakeClient {
constructor(public socketPath: string, public options: unknown) {}
constructor(
public socketPath: string,
public options: unknown,
) {}
}
const build = createBuildMpvClientRuntimeServiceFactoryDepsHandler({

View File

@@ -22,7 +22,8 @@ export function createBuildMpvClientRuntimeServiceFactoryDepsHandler<
setOverlayVisible: (visible: boolean) => deps.setOverlayVisible(visible),
isVisibleOverlayVisible: () => deps.isVisibleOverlayVisible(),
getReconnectTimer: () => deps.getReconnectTimer(),
setReconnectTimer: (timer: ReturnType<typeof setTimeout> | null) => deps.setReconnectTimer(timer),
setReconnectTimer: (timer: ReturnType<typeof setTimeout> | null) =>
deps.setReconnectTimer(timer),
},
bindEventHandlers: (client: TClient) => deps.bindEventHandlers(client),
});

View File

@@ -15,9 +15,7 @@ export function createBuildApplyJellyfinMpvDefaultsMainDepsHandler(
});
}
export function createBuildGetDefaultSocketPathMainDepsHandler(
deps: GetDefaultSocketPathMainDeps,
) {
export function createBuildGetDefaultSocketPathMainDepsHandler(deps: GetDefaultSocketPathMainDeps) {
return (): GetDefaultSocketPathMainDeps => ({
platform: deps.platform,
});

View File

@@ -97,8 +97,7 @@ export function createBindMpvMainEventHandlersHandler(deps: {
const handleMpvMediaPathChange = createHandleMpvMediaPathChangeHandler({
updateCurrentMediaPath: (path) => deps.updateCurrentMediaPath(path),
reportJellyfinRemoteStopped: () => deps.reportJellyfinRemoteStopped(),
restoreMpvSubVisibility: () =>
deps.restoreMpvSubVisibility(),
restoreMpvSubVisibility: () => deps.restoreMpvSubVisibility(),
getCurrentAnilistMediaKey: () => deps.getCurrentAnilistMediaKey(),
resetAnilistMediaTracking: (mediaKey) => deps.resetAnilistMediaTracking(mediaKey),
maybeProbeAnilistDuration: (mediaKey) => deps.maybeProbeAnilistDuration(mediaKey),

View File

@@ -1,6 +1,8 @@
import type { createUpdateMpvSubtitleRenderMetricsHandler } from './mpv-subtitle-render-metrics';
type UpdateMpvSubtitleRenderMetricsMainDeps = Parameters<typeof createUpdateMpvSubtitleRenderMetricsHandler>[0];
type UpdateMpvSubtitleRenderMetricsMainDeps = Parameters<
typeof createUpdateMpvSubtitleRenderMetricsHandler
>[0];
export function createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler(
deps: UpdateMpvSubtitleRenderMetricsMainDeps,

View File

@@ -22,7 +22,10 @@ test('numeric shortcut runtime main deps builder maps callbacks', () => {
},
})();
assert.equal(deps.globalShortcut.register('1', () => {}), true);
assert.equal(
deps.globalShortcut.register('1', () => {}),
true,
);
deps.globalShortcut.unregister('1');
deps.showMpvOsd('x');
deps.setTimer(() => calls.push('tick'), 1000);

View File

@@ -1,6 +1,8 @@
import type { NumericShortcutRuntimeOptions } from '../../core/services/numeric-shortcut';
export function createBuildNumericShortcutRuntimeMainDepsHandler(deps: NumericShortcutRuntimeOptions) {
export function createBuildNumericShortcutRuntimeMainDepsHandler(
deps: NumericShortcutRuntimeOptions,
) {
return (): NumericShortcutRuntimeOptions => ({
globalShortcut: deps.globalShortcut,
showMpvOsd: (text: string) => deps.showMpvOsd(text),

View File

@@ -3,8 +3,12 @@ import type {
createStartNumericShortcutSessionHandler,
} from './numeric-shortcut-session-handlers';
type CancelNumericShortcutSessionMainDeps = Parameters<typeof createCancelNumericShortcutSessionHandler>[0];
type StartNumericShortcutSessionMainDeps = Parameters<typeof createStartNumericShortcutSessionHandler>[0];
type CancelNumericShortcutSessionMainDeps = Parameters<
typeof createCancelNumericShortcutSessionHandler
>[0];
type StartNumericShortcutSessionMainDeps = Parameters<
typeof createStartNumericShortcutSessionHandler
>[0];
export function createBuildCancelNumericShortcutSessionMainDepsHandler(
deps: CancelNumericShortcutSessionMainDeps,

View File

@@ -20,8 +20,9 @@ export function createNumericShortcutSessionRuntimeHandlers(deps: {
const cancelPendingMultiCopyMainDeps = createBuildCancelNumericShortcutSessionMainDepsHandler({
session: deps.multiCopySession,
})();
const cancelPendingMultiCopyHandler =
createCancelNumericShortcutSessionHandler(cancelPendingMultiCopyMainDeps);
const cancelPendingMultiCopyHandler = createCancelNumericShortcutSessionHandler(
cancelPendingMultiCopyMainDeps,
);
const startPendingMultiCopyMainDeps = createBuildStartNumericShortcutSessionMainDepsHandler({
session: deps.multiCopySession,
@@ -32,8 +33,9 @@ export function createNumericShortcutSessionRuntimeHandlers(deps: {
cancelled: 'Cancelled',
},
})();
const startPendingMultiCopyHandler =
createStartNumericShortcutSessionHandler(startPendingMultiCopyMainDeps);
const startPendingMultiCopyHandler = createStartNumericShortcutSessionHandler(
startPendingMultiCopyMainDeps,
);
const cancelPendingMineSentenceMultipleMainDeps =
createBuildCancelNumericShortcutSessionMainDepsHandler({

View File

@@ -14,9 +14,7 @@ export function createBuildOverlayContentMeasurementStoreMainDepsHandler(
});
}
export function createBuildOverlayModalRuntimeMainDepsHandler(
deps: OverlayWindowResolver,
) {
export function createBuildOverlayModalRuntimeMainDepsHandler(deps: OverlayWindowResolver) {
return (): OverlayWindowResolver => ({
getMainWindow: () => deps.getMainWindow(),
getModalWindow: () => deps.getModalWindow(),

View File

@@ -35,12 +35,15 @@ test('overlay main action main deps builders map callbacks', () => {
showMpvOsd: (text) => calls.push(`osd:${text}`),
sendMpvCommand: (command) => calls.push(`cmd:${command.join(':')}`),
})();
assert.deepEqual(append.appendClipboardVideoToQueueRuntime({
getMpvClient: () => ({ connected: true }),
readClipboardText: () => '/tmp/v.mkv',
showMpvOsd: () => {},
sendMpvCommand: () => {},
}), { ok: true, message: 'ok' });
assert.deepEqual(
append.appendClipboardVideoToQueueRuntime({
getMpvClient: () => ({ connected: true }),
readClipboardText: () => '/tmp/v.mkv',
showMpvOsd: () => {},
sendMpvCommand: () => {},
}),
{ ok: true, message: 'ok' },
);
assert.equal(append.readClipboardText(), '/tmp/v.mkv');
assert.equal(typeof append.getMpvClient(), 'object');
append.showMpvOsd('queued');

View File

@@ -8,7 +8,9 @@ import type {
type SetOverlayVisibleMainDeps = Parameters<typeof createSetOverlayVisibleHandler>[0];
type ToggleOverlayMainDeps = Parameters<typeof createToggleOverlayHandler>[0];
type HandleOverlayModalClosedMainDeps = Parameters<typeof createHandleOverlayModalClosedHandler>[0];
type AppendClipboardVideoToQueueMainDeps = Parameters<typeof createAppendClipboardVideoToQueueHandler>[0];
type AppendClipboardVideoToQueueMainDeps = Parameters<
typeof createAppendClipboardVideoToQueueHandler
>[0];
export function createBuildSetOverlayVisibleMainDepsHandler(deps: SetOverlayVisibleMainDeps) {
return (): SetOverlayVisibleMainDeps => ({
@@ -34,7 +36,8 @@ export function createBuildAppendClipboardVideoToQueueMainDepsHandler(
deps: AppendClipboardVideoToQueueMainDeps,
) {
return (): AppendClipboardVideoToQueueMainDeps => ({
appendClipboardVideoToQueueRuntime: (options) => deps.appendClipboardVideoToQueueRuntime(options),
appendClipboardVideoToQueueRuntime: (options) =>
deps.appendClipboardVideoToQueueRuntime(options),
getMpvClient: () => deps.getMpvClient(),
readClipboardText: () => deps.readClipboardText(),
showMpvOsd: (text: string) => deps.showMpvOsd(text),

View File

@@ -9,9 +9,7 @@ export function createSetOverlayVisibleHandler(deps: {
};
}
export function createToggleOverlayHandler(deps: {
toggleVisibleOverlay: () => void;
}) {
export function createToggleOverlayHandler(deps: { toggleVisibleOverlay: () => void }) {
return (): void => {
deps.toggleVisibleOverlay();
};
@@ -26,9 +24,10 @@ export function createHandleOverlayModalClosedHandler(deps: {
}
export function createAppendClipboardVideoToQueueHandler(deps: {
appendClipboardVideoToQueueRuntime: (
options: AppendClipboardVideoToQueueRuntimeDeps,
) => { ok: boolean; message: string };
appendClipboardVideoToQueueRuntime: (options: AppendClipboardVideoToQueueRuntimeDeps) => {
ok: boolean;
message: string;
};
getMpvClient: () => AppendClipboardVideoToQueueRuntimeDeps['getMpvClient'] extends () => infer T
? T
: never;

View File

@@ -25,7 +25,6 @@ function parseSubVisibility(value: unknown): boolean {
return true;
}
export function createEnsureOverlayMpvSubtitlesHiddenHandler(deps: {
getMpvClient: () => MpvVisibilityClient | null;
getSavedSubVisibility: () => boolean | null;

View File

@@ -9,7 +9,7 @@ test('overlay runtime bootstrap no-ops when already initialized', () => {
initializeOverlayRuntimeCore: () => {
coreCalls += 1;
},
buildOptions: () => ({} as never),
buildOptions: () => ({}) as never,
setOverlayRuntimeInitialized: () => {},
startBackgroundWarmups: () => {},
});

View File

@@ -32,7 +32,10 @@ test('broadcast runtime options changed main deps builder maps callbacks', () =>
broadcastToOverlayWindows: (channel) => calls.push(channel),
})();
deps.broadcastRuntimeOptionsChangedRuntime(() => [], () => {});
deps.broadcastRuntimeOptionsChangedRuntime(
() => [],
() => {},
);
deps.broadcastToOverlayWindows('runtime-options:changed');
assert.deepEqual(deps.getRuntimeOptionsState(), []);
assert.deepEqual(calls, ['broadcast-runtime', 'runtime-options:changed']);

View File

@@ -14,11 +14,15 @@ type RestorePreviousSecondarySubVisibilityMainDeps = Parameters<
type BroadcastRuntimeOptionsChangedMainDeps = Parameters<
typeof createBroadcastRuntimeOptionsChangedHandler
>[0];
type SendToActiveOverlayWindowMainDeps = Parameters<typeof createSendToActiveOverlayWindowHandler>[0];
type SendToActiveOverlayWindowMainDeps = Parameters<
typeof createSendToActiveOverlayWindowHandler
>[0];
type SetOverlayDebugVisualizationEnabledMainDeps = Parameters<
typeof createSetOverlayDebugVisualizationEnabledHandler
>[0];
type OpenRuntimeOptionsPaletteMainDeps = Parameters<typeof createOpenRuntimeOptionsPaletteHandler>[0];
type OpenRuntimeOptionsPaletteMainDeps = Parameters<
typeof createOpenRuntimeOptionsPaletteHandler
>[0];
export function createBuildGetRuntimeOptionsStateMainDepsHandler(
deps: GetRuntimeOptionsStateMainDeps,
@@ -61,11 +65,7 @@ export function createBuildSetOverlayDebugVisualizationEnabledMainDepsHandler(
deps: SetOverlayDebugVisualizationEnabledMainDeps,
) {
return (): SetOverlayDebugVisualizationEnabledMainDeps => ({
setOverlayDebugVisualizationEnabledRuntime: (
currentEnabled,
nextEnabled,
setCurrentEnabled,
) =>
setOverlayDebugVisualizationEnabledRuntime: (currentEnabled, nextEnabled, setCurrentEnabled) =>
deps.setOverlayDebugVisualizationEnabledRuntime(
currentEnabled,
nextEnabled,

View File

@@ -49,7 +49,10 @@ test('runtime options state handler returns list from manager', () => {
test('restore previous secondary subtitle visibility no-ops without connected mpv client', () => {
let restored = false;
const restore = createRestorePreviousSecondarySubVisibilityHandler({
getMpvClient: () => ({ connected: false, restorePreviousSecondarySubVisibility: () => (restored = true) }),
getMpvClient: () => ({
connected: false,
restorePreviousSecondarySubVisibility: () => (restored = true),
}),
});
restore();
assert.equal(restored, false);
@@ -58,7 +61,10 @@ test('restore previous secondary subtitle visibility no-ops without connected mp
test('restore previous secondary subtitle visibility calls runtime when connected', () => {
let restored = false;
const restore = createRestorePreviousSecondarySubVisibilityHandler({
getMpvClient: () => ({ connected: true, restorePreviousSecondarySubVisibility: () => (restored = true) }),
getMpvClient: () => ({
connected: true,
restorePreviousSecondarySubVisibility: () => (restored = true),
}),
});
restore();
assert.equal(restored, true);
@@ -82,7 +88,8 @@ test('broadcast runtime options changed passes through state getter and broadcas
requiresRestart: false,
},
],
broadcastToOverlayWindows: (channel, payload) => calls.push(`emit:${channel}:${JSON.stringify(payload)}`),
broadcastToOverlayWindows: (channel, payload) =>
calls.push(`emit:${channel}:${JSON.stringify(payload)}`),
});
broadcast();

View File

@@ -70,10 +70,8 @@ export function createSetOverlayDebugVisualizationEnabledHandler(deps: {
setCurrentEnabled: (enabled: boolean) => void;
}) {
return (enabled: boolean): void => {
deps.setOverlayDebugVisualizationEnabledRuntime(
deps.getCurrentEnabled(),
enabled,
(next) => deps.setCurrentEnabled(next),
deps.setOverlayDebugVisualizationEnabledRuntime(deps.getCurrentEnabled(), enabled, (next) =>
deps.setCurrentEnabled(next),
);
};
}

View File

@@ -6,7 +6,9 @@ import type {
} from './overlay-shortcuts-lifecycle';
type RegisterOverlayShortcutsMainDeps = Parameters<typeof createRegisterOverlayShortcutsHandler>[0];
type UnregisterOverlayShortcutsMainDeps = Parameters<typeof createUnregisterOverlayShortcutsHandler>[0];
type UnregisterOverlayShortcutsMainDeps = Parameters<
typeof createUnregisterOverlayShortcutsHandler
>[0];
type SyncOverlayShortcutsMainDeps = Parameters<typeof createSyncOverlayShortcutsHandler>[0];
type RefreshOverlayShortcutsMainDeps = Parameters<typeof createRefreshOverlayShortcutsHandler>[0];

View File

@@ -21,26 +21,30 @@ export function createOverlayShortcutsRuntimeHandlers(deps: {
const registerOverlayShortcutsMainDeps = createBuildRegisterOverlayShortcutsMainDepsHandler(
deps.overlayShortcutsRuntimeMainDeps,
)();
const registerOverlayShortcutsHandler =
createRegisterOverlayShortcutsHandler(registerOverlayShortcutsMainDeps);
const registerOverlayShortcutsHandler = createRegisterOverlayShortcutsHandler(
registerOverlayShortcutsMainDeps,
);
const unregisterOverlayShortcutsMainDeps =
createBuildUnregisterOverlayShortcutsMainDepsHandler(
deps.overlayShortcutsRuntimeMainDeps,
)();
const unregisterOverlayShortcutsHandler =
createUnregisterOverlayShortcutsHandler(unregisterOverlayShortcutsMainDeps);
const unregisterOverlayShortcutsMainDeps = createBuildUnregisterOverlayShortcutsMainDepsHandler(
deps.overlayShortcutsRuntimeMainDeps,
)();
const unregisterOverlayShortcutsHandler = createUnregisterOverlayShortcutsHandler(
unregisterOverlayShortcutsMainDeps,
);
const syncOverlayShortcutsMainDeps = createBuildSyncOverlayShortcutsMainDepsHandler(
deps.overlayShortcutsRuntimeMainDeps,
)();
const syncOverlayShortcutsHandler = createSyncOverlayShortcutsHandler(syncOverlayShortcutsMainDeps);
const syncOverlayShortcutsHandler = createSyncOverlayShortcutsHandler(
syncOverlayShortcutsMainDeps,
);
const refreshOverlayShortcutsMainDeps = createBuildRefreshOverlayShortcutsMainDepsHandler(
deps.overlayShortcutsRuntimeMainDeps,
)();
const refreshOverlayShortcutsHandler =
createRefreshOverlayShortcutsHandler(refreshOverlayShortcutsMainDeps);
const refreshOverlayShortcutsHandler = createRefreshOverlayShortcutsHandler(
refreshOverlayShortcutsMainDeps,
);
return {
registerOverlayShortcuts: () => registerOverlayShortcutsHandler(),

View File

@@ -6,7 +6,7 @@ test('overlay shortcuts runtime main deps builder maps lifecycle and action call
const calls: string[] = [];
let shortcutsRegistered = false;
const deps = createBuildOverlayShortcutsRuntimeMainDepsHandler({
getConfiguredShortcuts: () => ({ copySubtitle: 's' } as never),
getConfiguredShortcuts: () => ({ copySubtitle: 's' }) as never,
getShortcutsRegistered: () => shortcutsRegistered,
setShortcutsRegistered: (registered) => {
shortcutsRegistered = registered;

View File

@@ -11,7 +11,8 @@ export function createBuildSetVisibleOverlayVisibleMainDepsHandler(
) {
return (): SetVisibleOverlayVisibleMainDeps => ({
setVisibleOverlayVisibleCore: (options) => deps.setVisibleOverlayVisibleCore(options),
setVisibleOverlayVisibleState: (visible: boolean) => deps.setVisibleOverlayVisibleState(visible),
setVisibleOverlayVisibleState: (visible: boolean) =>
deps.setVisibleOverlayVisibleState(visible),
updateVisibleOverlayVisibility: () => deps.updateVisibleOverlayVisibility(),
onVisibleOverlayEnabled: deps.onVisibleOverlayEnabled,
});

View File

@@ -22,11 +22,7 @@ test('set visible overlay handler forwards dependencies to core', () => {
});
setVisible(true);
assert.deepEqual(calls, [
'core:true',
'state:true',
'update-visible',
]);
assert.deepEqual(calls, ['core:true', 'state:true', 'update-visible']);
assert.equal(warmupStarts, 1);
setVisible(false);

View File

@@ -14,8 +14,7 @@ export function createBuildOverlayVisibilityRuntimeMainDepsHandler(
updateVisibleOverlayBounds: (geometry: WindowGeometry) =>
deps.updateVisibleOverlayBounds(geometry),
ensureOverlayWindowLevel: (window: BrowserWindow) => deps.ensureOverlayWindowLevel(window),
syncPrimaryOverlayWindowLayer: (layer: 'visible') =>
deps.syncPrimaryOverlayWindowLayer(layer),
syncPrimaryOverlayWindowLayer: (layer: 'visible') => deps.syncPrimaryOverlayWindowLayer(layer),
enforceOverlayLayerOrder: () => deps.enforceOverlayLayerOrder(),
syncOverlayShortcuts: () => deps.syncOverlayShortcuts(),
isMacOSPlatform: () => deps.isMacOSPlatform(),

View File

@@ -34,10 +34,5 @@ test('overlay window layout main deps builders map callbacks', () => {
assert.deepEqual(order.getMainWindow(), { kind: 'main' });
order.ensureOverlayWindowLevel({});
assert.deepEqual(calls, [
'visible',
'ensure',
'order',
'order-level',
]);
assert.deepEqual(calls, ['visible', 'ensure', 'order', 'order-level']);
});

View File

@@ -4,7 +4,9 @@ import type {
createUpdateVisibleOverlayBoundsHandler,
} from './overlay-window-layout';
type UpdateVisibleOverlayBoundsMainDeps = Parameters<typeof createUpdateVisibleOverlayBoundsHandler>[0];
type UpdateVisibleOverlayBoundsMainDeps = Parameters<
typeof createUpdateVisibleOverlayBoundsHandler
>[0];
type EnsureOverlayWindowLevelMainDeps = Parameters<typeof createEnsureOverlayWindowLevelHandler>[0];
type EnforceOverlayLayerOrderMainDeps = Parameters<typeof createEnforceOverlayLayerOrderHandler>[0];

View File

@@ -41,11 +41,11 @@ test('immersion media runtime main deps builder maps callbacks', async () => {
test('anilist state runtime main deps builder maps callbacks', () => {
const calls: string[] = [];
const deps = createBuildAnilistStateRuntimeMainDepsHandler({
getClientSecretState: () => ({ status: 'resolved' } as never),
getClientSecretState: () => ({ status: 'resolved' }) as never,
setClientSecretState: () => calls.push('set-client'),
getRetryQueueState: () => ({ pending: 1 } as never),
getRetryQueueState: () => ({ pending: 1 }) as never,
setRetryQueueState: () => calls.push('set-queue'),
getUpdateQueueSnapshot: () => ({ pending: 2 } as never),
getUpdateQueueSnapshot: () => ({ pending: 2 }) as never,
clearStoredToken: () => calls.push('clear-stored'),
clearCachedAccessToken: () => calls.push('clear-cached'),
})();
@@ -62,7 +62,7 @@ test('anilist state runtime main deps builder maps callbacks', () => {
test('config derived runtime main deps builder maps callbacks', () => {
const deps = createBuildConfigDerivedRuntimeMainDepsHandler({
getResolvedConfig: () => ({ jimaku: {} } as never),
getResolvedConfig: () => ({ jimaku: {} }) as never,
getRuntimeOptionsManager: () => null,
defaultJimakuLanguagePreference: 'ja',
defaultJimakuMaxEntryResults: 20,
@@ -80,7 +80,7 @@ test('main subsync runtime main deps builder maps callbacks', () => {
const calls: string[] = [];
const deps = createBuildMainSubsyncRuntimeMainDepsHandler({
getMpvClient: () => ({ connected: true }) as never,
getResolvedConfig: () => ({ subsync: {} } as never),
getResolvedConfig: () => ({ subsync: {} }) as never,
getSubsyncInProgress: () => true,
setSubsyncInProgress: () => calls.push('set-progress'),
showMpvOsd: (text) => calls.push(`osd:${text}`),

View File

@@ -18,7 +18,8 @@ test('cycle secondary sub mode main deps builder maps state and broadcasts with
lastToggleAt = timestampMs;
calls.push(`set-ts:${timestampMs}`);
},
broadcastToOverlayWindows: (channel, nextMode) => calls.push(`broadcast:${channel}:${nextMode}`),
broadcastToOverlayWindows: (channel, nextMode) =>
calls.push(`broadcast:${channel}:${nextMode}`),
showMpvOsd: (text) => calls.push(`osd:${text}`),
})();

View File

@@ -21,9 +21,5 @@ test('secondary sub mode runtime handler composes deps for runtime call', () =>
});
handleCycleSecondarySubMode();
assert.deepEqual(calls, [
'set-mode',
'broadcast:secondary-subtitle:mode:romaji',
'osd:romaji',
]);
assert.deepEqual(calls, ['set-mode', 'broadcast:secondary-subtitle:mode:romaji', 'osd:romaji']);
});

View File

@@ -11,7 +11,8 @@ export function createCycleSecondarySubModeRuntimeHandler(deps: {
cycleSecondarySubModeMainDeps: CycleSecondarySubModeMainDeps;
cycleSecondarySubMode: (deps: CycleSecondarySubModeDeps) => void;
}) {
const buildCycleSecondarySubModeMainDepsHandler =
createBuildCycleSecondarySubModeMainDepsHandler(deps.cycleSecondarySubModeMainDeps);
const buildCycleSecondarySubModeMainDepsHandler = createBuildCycleSecondarySubModeMainDepsHandler(
deps.cycleSecondarySubModeMainDeps,
);
return () => deps.cycleSecondarySubMode(buildCycleSecondarySubModeMainDepsHandler());
}

View File

@@ -44,7 +44,9 @@ test('createReloadConfigHandler runs success flow with warnings', async () => {
assert.ok(calls.some((entry) => entry.includes('1. ankiConnect.pollingRate: must be >= 50')));
assert.ok(
calls.some((entry) =>
entry.includes('dialog:SubMiner config validation warning:SubMiner detected config validation issues.'),
entry.includes(
'dialog:SubMiner config validation warning:SubMiner detected config validation issues.',
),
),
);
assert.ok(calls.some((entry) => entry.includes('actual=10 fallback=250')));

View File

@@ -28,8 +28,9 @@ export function createStartupRuntimeHandlers<
runStartupBootstrapRuntime: (deps: TStartupBootstrapRuntimeDeps) => TStartupState;
applyStartupState: (startupState: TStartupState) => void;
}) {
const appLifecycleRuntimeRunnerMainDeps =
createBuildAppLifecycleRuntimeRunnerMainDepsHandler(deps.appLifecycleRuntimeRunnerMainDeps)();
const appLifecycleRuntimeRunnerMainDeps = createBuildAppLifecycleRuntimeRunnerMainDepsHandler(
deps.appLifecycleRuntimeRunnerMainDeps,
)();
const appLifecycleRuntimeRunner = deps.createAppLifecycleRuntimeRunner(
appLifecycleRuntimeRunnerMainDeps,
);

View File

@@ -3,7 +3,9 @@ import type {
createStartBackgroundWarmupsHandler,
} from './startup-warmups';
type LaunchBackgroundWarmupTaskMainDeps = Parameters<typeof createLaunchBackgroundWarmupTaskHandler>[0];
type LaunchBackgroundWarmupTaskMainDeps = Parameters<
typeof createLaunchBackgroundWarmupTaskHandler
>[0];
type StartBackgroundWarmupsMainDeps = Parameters<typeof createStartBackgroundWarmupsHandler>[0];
export function createBuildLaunchBackgroundWarmupTaskMainDepsHandler(
@@ -16,7 +18,9 @@ export function createBuildLaunchBackgroundWarmupTaskMainDepsHandler(
});
}
export function createBuildStartBackgroundWarmupsMainDepsHandler(deps: StartBackgroundWarmupsMainDeps) {
export function createBuildStartBackgroundWarmupsMainDepsHandler(
deps: StartBackgroundWarmupsMainDeps,
) {
return (): StartBackgroundWarmupsMainDeps => ({
getStarted: () => deps.getStarted(),
setStarted: (started: boolean) => deps.setStarted(started),

View File

@@ -1,6 +1,14 @@
import type { MpvIpcClient } from '../../core/services';
import { runSubsyncManualFromIpcRuntime, triggerSubsyncFromConfigRuntime } from '../../core/services';
import type { SubsyncResult, SubsyncManualPayload, SubsyncManualRunRequest, ResolvedConfig } from '../../types';
import {
runSubsyncManualFromIpcRuntime,
triggerSubsyncFromConfigRuntime,
} from '../../core/services';
import type {
SubsyncResult,
SubsyncManualPayload,
SubsyncManualRunRequest,
ResolvedConfig,
} from '../../types';
import { getSubsyncConfig } from '../../subsync/utils';
import { createSubsyncRuntimeServiceInputFromState } from '../subsync-runtime';

View File

@@ -8,7 +8,7 @@ import {
test('load subtitle position main deps builder maps callbacks', () => {
const calls: string[] = [];
const deps = createBuildLoadSubtitlePositionMainDepsHandler({
loadSubtitlePositionCore: () => ({ x: 1, y: 2 } as never),
loadSubtitlePositionCore: () => ({ x: 1, y: 2 }) as never,
setSubtitlePosition: () => calls.push('set'),
})();

View File

@@ -122,7 +122,10 @@ test('dictionary prewarm shows OSD spinner while loading and completion when loa
}
const tickCallback: () => void = tick;
tickCallback();
assert.deepEqual(osdMessages, ['Loading subtitle annotations |', 'Loading subtitle annotations /']);
assert.deepEqual(osdMessages, [
'Loading subtitle annotations |',
'Loading subtitle annotations /',
]);
jlptDeferred.resolve();
freqDeferred.resolve();

View File

@@ -106,7 +106,9 @@ export function createPrewarmSubtitleDictionariesMainHandler(deps: {
if (!showMpvOsd) {
return;
}
showMpvOsd(`Loading subtitle annotations ${spinnerFrames[loadingOsdFrame % spinnerFrames.length]}`);
showMpvOsd(
`Loading subtitle annotations ${spinnerFrames[loadingOsdFrame % spinnerFrames.length]}`,
);
loadingOsdFrame += 1;
}, 180);
return true;
@@ -139,7 +141,10 @@ export function createPrewarmSubtitleDictionariesMainHandler(deps: {
if (!prewarmPromise) {
prewarmPromise = (async () => {
try {
await Promise.all([deps.ensureJlptDictionaryLookup(), deps.ensureFrequencyDictionaryLookup()]);
await Promise.all([
deps.ensureJlptDictionaryLookup(),
deps.ensureFrequencyDictionaryLookup(),
]);
prewarmed = true;
} finally {
prewarmPromise = null;

View File

@@ -58,7 +58,11 @@ test('ensure tray creates new tray and binds click handler', () => {
createImageFromPath: () =>
({
isEmpty: () => false,
resize: (options: { width: number; height: number; quality?: 'best' | 'better' | 'good' }) => {
resize: (options: {
width: number;
height: number;
quality?: 'best' | 'better' | 'good';
}) => {
calls.push(`resize:${options.width}x${options.height}`);
return {
isEmpty: () => false,

View File

@@ -1,6 +1,10 @@
type TrayIconLike = {
isEmpty: () => boolean;
resize: (options: { width: number; height: number; quality?: 'best' | 'better' | 'good' }) => TrayIconLike;
resize: (options: {
width: number;
height: number;
quality?: 'best' | 'better' | 'good';
}) => TrayIconLike;
setTemplateImage: (enabled: boolean) => void;
};

View File

@@ -42,14 +42,14 @@ test('tray runtime handlers compose resolve/menu/ensure/destroy handlers', () =>
isEmpty: () => false,
resize: () => ({
isEmpty: () => false,
resize: () => ({} as never),
resize: () => ({}) as never,
setTemplateImage: () => {},
}),
setTemplateImage: () => {},
}),
createEmptyImage: () => ({
isEmpty: () => true,
resize: () => ({} as never),
resize: () => ({}) as never,
setTemplateImage: () => {},
}),
createTray: () => ({

View File

@@ -8,9 +8,7 @@ type EnsureYomitanExtensionLoadedMainDeps = Parameters<
typeof createEnsureYomitanExtensionLoadedHandler
>[0];
export function createBuildLoadYomitanExtensionMainDepsHandler(
deps: LoadYomitanExtensionMainDeps,
) {
export function createBuildLoadYomitanExtensionMainDepsHandler(deps: LoadYomitanExtensionMainDeps) {
return (): LoadYomitanExtensionMainDeps => ({
loadYomitanExtensionCore: (options) => deps.loadYomitanExtensionCore(options),
userDataPath: deps.userDataPath,

View File

@@ -1,4 +1,7 @@
import { createEnsureYomitanExtensionLoadedHandler, createLoadYomitanExtensionHandler } from './yomitan-extension-loader';
import {
createEnsureYomitanExtensionLoadedHandler,
createLoadYomitanExtensionHandler,
} from './yomitan-extension-loader';
import {
createBuildEnsureYomitanExtensionLoadedMainDepsHandler,
createBuildLoadYomitanExtensionMainDepsHandler,

View File

@@ -1,7 +1,9 @@
import { createBuildOpenYomitanSettingsMainDepsHandler } from './app-runtime-main-deps';
import { createOpenYomitanSettingsHandler } from './yomitan-settings-opener';
type OpenYomitanSettingsMainDeps = Parameters<typeof createBuildOpenYomitanSettingsMainDepsHandler>[0];
type OpenYomitanSettingsMainDeps = Parameters<
typeof createBuildOpenYomitanSettingsMainDepsHandler
>[0];
export function createYomitanSettingsRuntime(deps: OpenYomitanSettingsMainDeps) {
const openYomitanSettingsMainDeps = createBuildOpenYomitanSettingsMainDepsHandler(deps)();