mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-11-10 04:46:07 -08:00
refactor(main): drop pass-through main-deps builders (#306)
* refactor(main): drop mining/anki main-deps builders * refactor(anilist): drop main-deps builders * refactor(jellyfin): drop main-deps builders * refactor(overlay): drop overlay and shortcut main-deps builders * refactor(main): drop ipc, tray, and osd main-deps builders * refactor(startup): drop startup main-deps builders * test(scripts): ignore stray local requests in AUR download test Also apply prettier to launcher/mpv.test.ts so format:check:src passes. * fix(shortcuts): forward overlay numeric selection hooks through the composer composeShortcutRuntimes only passed the digit callbacks, so the visible-overlay selection added in #78 never ran from the multi-copy/mine-sentence shortcuts. * fix(stats): skip mpv auto-connect when stats starts the immersion tracker The immersion-startup main-deps builder never forwarded shouldAutoConnectMpv, so background stats and stats CLI startup always connected to mpv. Drop the builder and pass the deps straight to the handler. * build(deps): bump follow-redirects override to 1.16.2 Resolves GHSA-mrwp-f3q8-3g9p (high), which fails the quality-gate bun audit --audit-level high step. * test(subtitles): cover the null-tokenization settle path in prefetch test The mock ignored the value the test resolved, so the null case never ran. * test(e2e): surface mpv crashes and install current mpv on macOS CI The harness IPC client never handled socket close, so a crashed mpv left commands pending until the 120s test timeout with an empty mpv.log. Reject pending commands on close, write mpv's own log via --log-file, and refresh Homebrew on macOS CI so the installed mpv build no longer depends on the runner image. * test(e2e): render mpv through cocoa-cb OpenGL on macOS mpv 0.41.0_12 with libplacebo 7.387.0 segfaults in gpu-next's MoltenVK path on GitHub's paravirtual macOS GPU on the first frame, so the E2E session never started. * test(e2e): name mpv-stdio.log in the mpv close diagnostic
This commit is contained in:
1 parent
0129e03c0f
commit
2a0e931325
84 files changed
+719
-2754
No files matched your search
@@ -56,7 +56,12 @@ jobs:
|
||||
|
||||
- name: Install mpv and ffmpeg (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install mpv ffmpeg
|
||||
run: |
|
||||
# Runner images bake in different Homebrew metadata, so without an update the
|
||||
# installed mpv build depends on which image the job lands on.
|
||||
brew update
|
||||
brew install mpv ffmpeg
|
||||
mpv --version
|
||||
|
||||
- name: Install mpv and ffmpeg (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"brace-expansion": "5.0.11",
|
||||
"electron-builder-squirrel-windows": "26.16.1",
|
||||
"fast-uri": "3.1.7",
|
||||
"follow-redirects": "1.16.1",
|
||||
"follow-redirects": "1.16.2",
|
||||
"form-data": "4.0.6",
|
||||
"ip-address": "10.2.0",
|
||||
"js-yaml": "4.3.2",
|
||||
@@ -351,7 +351,7 @@
|
||||
|
||||
"filelist": ["filelist@1.0.6", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA=="],
|
||||
|
||||
"follow-redirects": ["follow-redirects@1.16.1", "", { "peerDependencies": { "debug": "*" }, "optionalPeers": ["debug"] }, "sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg=="],
|
||||
"follow-redirects": ["follow-redirects@1.16.2", "", {}, "sha512-/kVP2U8z596Ia0gwFrwyIeo74ta5aVmSeU1FfAUMAmcEP5EP7zydmag3SLiN64NaRKef3lxsq7i/g7ltJQDGow=="],
|
||||
|
||||
"form-data": ["form-data@4.0.6", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.4", "mime-types": "^2.1.35" } }, "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ=="],
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ Renderer, launcher, plugin, and stats each keep their own local layering and sho
|
||||
## Rules
|
||||
|
||||
- Keep `src/main.ts` thin; wire, do not implement.
|
||||
- Pass deps straight to a handler factory (`createXHandler({...})`). Do not add
|
||||
`*-main-deps.ts` builders that only re-wrap deps; existing ones are being removed.
|
||||
- Prefer injecting dependencies from `src/main/` instead of reaching outward from core services.
|
||||
- Keep side effects explicit and close to composition boundaries.
|
||||
- Put reusable business logic in focused services, not in top-level lifecycle files.
|
||||
|
||||
@@ -125,7 +125,8 @@ whenever the behavior does not depend on a specific compositor.
|
||||
- Scenarios live in `e2e/*.e2e.test.ts` and share one session per file through
|
||||
`startE2eSession()`. Pass `config` to override settings for a scenario file.
|
||||
- On a failed startup the temp dir is kept and its path is in the error. Set
|
||||
`SUBMINER_E2E_KEEP=1` to keep it after any run (`app-stdio.log`, `app.log`, `mpv.log`).
|
||||
`SUBMINER_E2E_KEEP=1` to keep it after any run (`app-stdio.log`, `app.log`, `mpv.log`,
|
||||
`mpv-stdio.log`).
|
||||
|
||||
For exploratory checks, keep one session up and poke at it:
|
||||
|
||||
|
||||
+39
-4
@@ -15,25 +15,38 @@ export type MpvClient = {
|
||||
|
||||
type MpvReply = { request_id?: number; error?: string; data?: unknown };
|
||||
|
||||
function videoOutputArgs(display: E2eDisplay): string[] {
|
||||
// Xvfb has no GPU; the software X11 output always works there.
|
||||
if (display.kind === 'xvfb') return ['--vo=x11'];
|
||||
// gpu-next's Vulkan path (libplacebo over MoltenVK) segfaults on the first frame
|
||||
// on GitHub's paravirtual macOS GPU with libplacebo 7.387. `--vo=libmpv` is mpv's
|
||||
// cocoa-cb OpenGL output, which avoids it and still opens the window the overlay tracks.
|
||||
if (process.platform === 'darwin') return ['--vo=libmpv'];
|
||||
return [];
|
||||
}
|
||||
|
||||
export async function startMpv(options: {
|
||||
socketPath: string;
|
||||
mediaPath: string;
|
||||
subtitlePath: string;
|
||||
/** mpv's own verbose log (`--log-file`); `--no-terminal` silences its console output. */
|
||||
logPath: string;
|
||||
/** Process stdout/stderr, which still catches crash output from mpv's libraries. */
|
||||
stdioLogPath: string;
|
||||
display: E2eDisplay;
|
||||
}): Promise<ChildProcess> {
|
||||
const log = fs.openSync(options.logPath, 'w');
|
||||
const log = fs.openSync(options.stdioLogPath, 'w');
|
||||
const child = spawn(
|
||||
'mpv',
|
||||
[
|
||||
'--no-config',
|
||||
'--no-terminal',
|
||||
`--log-file=${options.logPath}`,
|
||||
'--pause',
|
||||
'--keep-open=yes',
|
||||
'--ao=null',
|
||||
`--geometry=${E2E_SCREEN.width}x${E2E_SCREEN.height}+0+0`,
|
||||
// Xvfb has no GPU; the software X11 output always works there.
|
||||
...(options.display.kind === 'xvfb' ? ['--vo=x11'] : []),
|
||||
...videoOutputArgs(options.display),
|
||||
`--input-ipc-server=${options.socketPath}`,
|
||||
`--sub-file=${options.subtitlePath}`,
|
||||
options.mediaPath,
|
||||
@@ -58,13 +71,31 @@ function tryConnect(socketPath: string): Promise<net.Socket | null> {
|
||||
});
|
||||
}
|
||||
|
||||
export async function connectMpv(socketPath: string): Promise<MpvClient> {
|
||||
/**
|
||||
* Connects to mpv's JSON IPC socket. Once the socket closes (mpv exited or
|
||||
* crashed), pending and later commands reject instead of hanging until the test
|
||||
* timeout; `describeClose` adds context such as mpv's exit status.
|
||||
*/
|
||||
export async function connectMpv(
|
||||
socketPath: string,
|
||||
describeClose: () => string = () => 'mpv IPC connection closed',
|
||||
): Promise<MpvClient> {
|
||||
const socket = await waitUntil(() => tryConnect(socketPath), {
|
||||
description: `mpv IPC socket ${socketPath}`,
|
||||
});
|
||||
const pending = new Map<number, (reply: MpvReply) => void>();
|
||||
let nextRequestId = 1;
|
||||
let buffer = '';
|
||||
let closedError: Error | null = null;
|
||||
|
||||
const failPending = () => {
|
||||
closedError ??= new Error(describeClose());
|
||||
for (const settle of pending.values()) settle({ error: closedError.message });
|
||||
pending.clear();
|
||||
};
|
||||
socket.on('close', failPending);
|
||||
// 'close' always follows 'error'; listening here keeps the error from being thrown.
|
||||
socket.on('error', () => {});
|
||||
|
||||
socket.setEncoding('utf8');
|
||||
socket.on('data', (chunk: string) => {
|
||||
@@ -83,6 +114,10 @@ export async function connectMpv(socketPath: string): Promise<MpvClient> {
|
||||
return {
|
||||
command: (...args) =>
|
||||
new Promise((resolve, reject) => {
|
||||
if (closedError) {
|
||||
reject(new Error(`mpv ${JSON.stringify(args)} failed: ${closedError.message}`));
|
||||
return;
|
||||
}
|
||||
const requestId = nextRequestId++;
|
||||
pending.set(requestId, (reply) => {
|
||||
if (reply.error === 'success') resolve(reply.data);
|
||||
|
||||
+12
-2
@@ -265,15 +265,25 @@ export async function startE2eSession(options: E2eSessionOptions = {}): Promise<
|
||||
settings.close();
|
||||
await stopProcess(seeder.child);
|
||||
|
||||
const mpvLogPath = path.join(root, 'mpv.log');
|
||||
const mpvStdioLogPath = path.join(root, 'mpv-stdio.log');
|
||||
const mpvProcess = await startMpv({
|
||||
socketPath: mpvSocketPath,
|
||||
mediaPath,
|
||||
subtitlePath,
|
||||
logPath: path.join(root, 'mpv.log'),
|
||||
logPath: mpvLogPath,
|
||||
stdioLogPath: mpvStdioLogPath,
|
||||
display,
|
||||
});
|
||||
teardown.push(() => stopProcess(mpvProcess));
|
||||
const mpv = await connectMpv(mpvSocketPath);
|
||||
const mpv = await connectMpv(mpvSocketPath, () => {
|
||||
const { exitCode, signalCode } = mpvProcess;
|
||||
const status =
|
||||
exitCode === null && signalCode === null
|
||||
? 'mpv IPC connection closed'
|
||||
: `mpv exited (code ${String(exitCode)}, signal ${String(signalCode)})`;
|
||||
return `${status}; see ${mpvLogPath} and ${mpvStdioLogPath}`;
|
||||
});
|
||||
teardown.push(mpv.close);
|
||||
|
||||
const app = await launchApp(['--start']);
|
||||
|
||||
+22
-25
@@ -172,33 +172,30 @@ test('runAppCommandCaptureOutput strips ELECTRON_RUN_AS_NODE from app child env'
|
||||
});
|
||||
});
|
||||
|
||||
test(
|
||||
'runAppCommandCaptureOutput transports Linux AppImage args through environment',
|
||||
async () => {
|
||||
// Bun's node:test shim ignores the `skip` option, so gate the platform here.
|
||||
if (process.platform !== 'linux') return;
|
||||
await withTempCase(({ dir }) => {
|
||||
const appPath = writeFakeApp(
|
||||
dir,
|
||||
[
|
||||
'printf "args:%s\\n" "$*"',
|
||||
'printf "argc:%s\\n" "$SUBMINER_APP_ARGC"',
|
||||
'printf "arg0:%s\\n" "$SUBMINER_APP_ARG_0"',
|
||||
'printf "arg1:%s\\n" "$SUBMINER_APP_ARG_1"',
|
||||
],
|
||||
'SubMiner.AppImage',
|
||||
);
|
||||
test('runAppCommandCaptureOutput transports Linux AppImage args through environment', async () => {
|
||||
// Bun's node:test shim ignores the `skip` option, so gate the platform here.
|
||||
if (process.platform !== 'linux') return;
|
||||
await withTempCase(({ dir }) => {
|
||||
const appPath = writeFakeApp(
|
||||
dir,
|
||||
[
|
||||
'printf "args:%s\\n" "$*"',
|
||||
'printf "argc:%s\\n" "$SUBMINER_APP_ARGC"',
|
||||
'printf "arg0:%s\\n" "$SUBMINER_APP_ARG_0"',
|
||||
'printf "arg1:%s\\n" "$SUBMINER_APP_ARG_1"',
|
||||
],
|
||||
'SubMiner.AppImage',
|
||||
);
|
||||
|
||||
const result = runAppCommandCaptureOutput(appPath, ['--app-ping', '--socket']);
|
||||
const result = runAppCommandCaptureOutput(appPath, ['--app-ping', '--socket']);
|
||||
|
||||
assert.equal(result.status, 0);
|
||||
assert.match(result.stdout, /^args:\n/m);
|
||||
assert.match(result.stdout, /^argc:2\n/m);
|
||||
assert.match(result.stdout, /^arg0:--app-ping\n/m);
|
||||
assert.match(result.stdout, /^arg1:--socket\n/m);
|
||||
});
|
||||
},
|
||||
);
|
||||
assert.equal(result.status, 0);
|
||||
assert.match(result.stdout, /^args:\n/m);
|
||||
assert.match(result.stdout, /^argc:2\n/m);
|
||||
assert.match(result.stdout, /^arg0:--app-ping\n/m);
|
||||
assert.match(result.stdout, /^arg1:--socket\n/m);
|
||||
});
|
||||
});
|
||||
|
||||
test('runAppCommandCaptureOutput runs Linux AppImage sync in Node-only mode', async () => {
|
||||
await withTempCase(({ dir }) => {
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@
|
||||
"brace-expansion": "5.0.11",
|
||||
"electron-builder-squirrel-windows": "26.16.1",
|
||||
"fast-uri": "3.1.7",
|
||||
"follow-redirects": "1.16.1",
|
||||
"follow-redirects": "1.16.2",
|
||||
"form-data": "4.0.6",
|
||||
"ip-address": "10.2.0",
|
||||
"js-yaml": "4.3.2",
|
||||
|
||||
@@ -29,6 +29,10 @@ test.each([false, true])(
|
||||
port: 0,
|
||||
fetch(request) {
|
||||
const pathname = new URL(request.url).pathname;
|
||||
// Ignore stray local probes of the ephemeral port; only count the script's downloads.
|
||||
if (!pathname.startsWith('/ksyasuda/SubMiner/releases/download/')) {
|
||||
return new Response('not found', { status: 404 });
|
||||
}
|
||||
requests.push(pathname);
|
||||
if (unavailable || requests.length === 1) return new Response('try again', { status: 503 });
|
||||
const name = pathname.split('/').at(-1);
|
||||
|
||||
+234
-370
@@ -155,7 +155,6 @@ import {
|
||||
buildAnilistSetupUrl,
|
||||
consumeAnilistSetupCallbackUrl,
|
||||
createAnilistStateRuntime,
|
||||
createBuildOpenAnilistSetupWindowMainDepsHandler,
|
||||
createMaybeFocusExistingAnilistSetupWindowHandler,
|
||||
createOpenAnilistSetupWindowHandler,
|
||||
findAnilistSetupDeepLinkArgvUrl,
|
||||
@@ -168,8 +167,6 @@ import { DEFAULT_MIN_WATCH_RATIO } from './shared/watch-threshold';
|
||||
import { shouldShowTexthookerTrayEntry } from './main/runtime/tray-main-actions';
|
||||
import {
|
||||
createApplyJellyfinMpvDefaultsHandler,
|
||||
createBuildApplyJellyfinMpvDefaultsMainDepsHandler,
|
||||
createBuildGetDefaultSocketPathMainDepsHandler,
|
||||
createGetDefaultSocketPathHandler,
|
||||
buildJellyfinSetupFormHtml,
|
||||
parseJellyfinSetupSubmissionUrl,
|
||||
@@ -184,22 +181,7 @@ import {
|
||||
createBuildConfigHotReloadRuntimeMainDepsHandler,
|
||||
createBuildWatchConfigPathMainDepsHandler,
|
||||
createWatchConfigPathHandler,
|
||||
createBuildOverlayContentMeasurementStoreMainDepsHandler,
|
||||
createBuildOverlayModalRuntimeMainDepsHandler,
|
||||
createBuildAppendClipboardVideoToQueueMainDepsHandler,
|
||||
createBuildHandleOverlayModalClosedMainDepsHandler,
|
||||
createBuildLoadSubtitlePositionMainDepsHandler,
|
||||
createBuildSaveSubtitlePositionMainDepsHandler,
|
||||
createBuildFieldGroupingOverlayMainDepsHandler,
|
||||
createBuildGetFieldGroupingResolverMainDepsHandler,
|
||||
createBuildSetFieldGroupingResolverMainDepsHandler,
|
||||
createBuildOverlayVisibilityRuntimeMainDepsHandler,
|
||||
createBuildBroadcastRuntimeOptionsChangedMainDepsHandler,
|
||||
createBuildGetRuntimeOptionsStateMainDepsHandler,
|
||||
createBuildOpenRuntimeOptionsPaletteMainDepsHandler,
|
||||
createBuildRestorePreviousSecondarySubVisibilityMainDepsHandler,
|
||||
createBuildSendToActiveOverlayWindowMainDepsHandler,
|
||||
createBuildSetOverlayDebugVisualizationEnabledMainDepsHandler,
|
||||
createTrayRuntimeHandlers,
|
||||
createOverlayVisibilityRuntime,
|
||||
createGetRuntimeOptionsStateHandler,
|
||||
@@ -219,12 +201,6 @@ import {
|
||||
resolveSubtitleStyleForRenderer,
|
||||
} from './main/runtime/domains/overlay';
|
||||
import {
|
||||
createBuildAnilistStateRuntimeMainDepsHandler,
|
||||
createBuildConfigDerivedRuntimeMainDepsHandler,
|
||||
createBuildImmersionMediaRuntimeMainDepsHandler,
|
||||
createBuildMainSubsyncRuntimeMainDepsHandler,
|
||||
createBuildSubtitleProcessingControllerMainDepsHandler,
|
||||
createBuildMediaRuntimeMainDepsHandler,
|
||||
createBuildDictionaryRootsMainHandler,
|
||||
createBuildFrequencyDictionaryRootsMainHandler,
|
||||
createBuildFrequencyDictionaryRuntimeMainDepsHandler,
|
||||
@@ -244,14 +220,6 @@ import {
|
||||
resolvePrimarySubtitle,
|
||||
} from './main/runtime/primary-subtitle-text';
|
||||
import {
|
||||
createBuildCopyCurrentSubtitleMainDepsHandler,
|
||||
createBuildHandleMineSentenceDigitMainDepsHandler,
|
||||
createBuildHandleMultiCopyDigitMainDepsHandler,
|
||||
createBuildMarkLastCardAsAudioCardMainDepsHandler,
|
||||
createBuildMineSentenceCardMainDepsHandler,
|
||||
createBuildRefreshKnownWordCacheMainDepsHandler,
|
||||
createBuildTriggerFieldGroupingMainDepsHandler,
|
||||
createBuildUpdateLastCardFromClipboardMainDepsHandler,
|
||||
createMarkLastCardAsAudioCardHandler,
|
||||
createMineSentenceCardHandler,
|
||||
createRefreshKnownWordCacheHandler,
|
||||
@@ -291,7 +259,6 @@ import {
|
||||
createOverlayContentMeasurementStore,
|
||||
createOverlayManager,
|
||||
createOverlayWindow as createOverlayWindowCore,
|
||||
createSubtitleProcessingController,
|
||||
createTokenizerDepsRuntime,
|
||||
cycleSecondarySubMode as cycleSecondarySubModeCore,
|
||||
deleteYomitanDictionaryByTitle,
|
||||
@@ -428,8 +395,10 @@ import {
|
||||
shouldQuitOnWindowAllClosedForTrayState,
|
||||
} from './main/runtime/startup-tray-policy';
|
||||
import { createLogExportTrayRuntime } from './main/runtime/log-export-tray';
|
||||
import { createImmersionTrackerStartupHandler } from './main/runtime/immersion-startup';
|
||||
import { createBuildImmersionTrackerStartupMainDepsHandler } from './main/runtime/immersion-startup-main-deps';
|
||||
import {
|
||||
createImmersionTrackerStartupHandler,
|
||||
type ImmersionTrackerStartupDeps,
|
||||
} from './main/runtime/immersion-startup';
|
||||
import {
|
||||
createRunStatsCliCommandHandler,
|
||||
writeStatsCliCommandResponse,
|
||||
@@ -529,6 +498,7 @@ import {
|
||||
getJlptDictionarySearchPaths,
|
||||
} from './main/jlpt-runtime';
|
||||
import { createMediaRuntimeService } from './main/media-runtime';
|
||||
import { createPrefetchAwareSubtitleProcessingController } from './main/runtime/subtitle-processing-runtime';
|
||||
import { createOverlayVisibilityRuntimeService } from './main/overlay-visibility-runtime';
|
||||
import { createDiscordPresenceRuntime } from './main/runtime/discord-presence-runtime';
|
||||
import { createCharacterDictionaryRuntimeService } from './main/character-dictionary-runtime';
|
||||
@@ -707,15 +677,10 @@ let backgroundWarmupsStarted = false;
|
||||
let yomitanLoadInFlight: Promise<Extension | null> | null = null;
|
||||
let notifyAnilistTokenStoreWarning: (message: string) => void = () => {};
|
||||
|
||||
const buildApplyJellyfinMpvDefaultsMainDepsHandler =
|
||||
createBuildApplyJellyfinMpvDefaultsMainDepsHandler({
|
||||
sendMpvCommandRuntime: (client, command) => sendMpvCommandRuntime(client, command),
|
||||
jellyfinLangPref: JELLYFIN_LANG_PREF,
|
||||
});
|
||||
const applyJellyfinMpvDefaultsMainDeps = buildApplyJellyfinMpvDefaultsMainDepsHandler();
|
||||
const applyJellyfinMpvDefaultsHandler = createApplyJellyfinMpvDefaultsHandler(
|
||||
applyJellyfinMpvDefaultsMainDeps,
|
||||
);
|
||||
const applyJellyfinMpvDefaultsHandler = createApplyJellyfinMpvDefaultsHandler({
|
||||
sendMpvCommandRuntime: (client, command) => sendMpvCommandRuntime(client, command),
|
||||
jellyfinLangPref: JELLYFIN_LANG_PREF,
|
||||
});
|
||||
|
||||
const isDev = process.argv.includes('--dev') || process.argv.includes('--debug');
|
||||
const texthookerService = new Texthooker(() => {
|
||||
@@ -758,11 +723,9 @@ const texthookerService = new Texthooker(() => {
|
||||
});
|
||||
let syncOverlayShortcutsForModal: (isActive: boolean) => void = () => {};
|
||||
let syncOverlayVisibilityForModal: () => void = () => {};
|
||||
const buildGetDefaultSocketPathMainDepsHandler = createBuildGetDefaultSocketPathMainDepsHandler({
|
||||
const getDefaultSocketPathHandler = createGetDefaultSocketPathHandler({
|
||||
platform: process.platform,
|
||||
});
|
||||
const getDefaultSocketPathMainDeps = buildGetDefaultSocketPathMainDepsHandler();
|
||||
const getDefaultSocketPathHandler = createGetDefaultSocketPathHandler(getDefaultSocketPathMainDeps);
|
||||
|
||||
type BootServices = MainBootServicesResult<
|
||||
ConfigService,
|
||||
@@ -852,45 +815,46 @@ const bootServices = createMainBootServices({
|
||||
}),
|
||||
createOverlayModalInputState,
|
||||
createOverlayContentMeasurementStore: ({ logger }) => {
|
||||
const buildHandler = createBuildOverlayContentMeasurementStoreMainDepsHandler({
|
||||
return createOverlayContentMeasurementStore({
|
||||
now: () => Date.now(),
|
||||
warn: (message: string) => logger.warn(message),
|
||||
});
|
||||
return createOverlayContentMeasurementStore(buildHandler());
|
||||
},
|
||||
getSyncOverlayShortcutsForModal: () => syncOverlayShortcutsForModal,
|
||||
getSyncOverlayVisibilityForModal: () => syncOverlayVisibilityForModal,
|
||||
createOverlayModalRuntime: ({ overlayManager, overlayModalInputState }) => {
|
||||
const buildHandler = createBuildOverlayModalRuntimeMainDepsHandler({
|
||||
getMainWindow: () => overlayManager.getMainWindow(),
|
||||
getModalWindow: () => overlayManager.getModalWindow(),
|
||||
createModalWindow: () => createModalWindow(),
|
||||
getModalGeometry: () => overlayGeometryRuntime.getCurrentOverlayGeometry(),
|
||||
setModalWindowBounds: (geometry) => overlayManager.setModalWindowBounds(geometry),
|
||||
});
|
||||
return createOverlayModalRuntimeService(buildHandler(), {
|
||||
onModalStateChange: (isActive: boolean) =>
|
||||
overlayModalInputState.handleModalInputStateChange(isActive),
|
||||
// On macOS, after the last modal closes the post-close visibility sync hides the overlay
|
||||
// when neither it nor mpv is focused, and keyboard focus is left in limbo (mpv keys like
|
||||
// shift-to-unpause stop working). Programmatically focusing mpv from our background helper
|
||||
// is refused by macOS (most visibly in native fullscreen), so instead resign SubMiner's
|
||||
// active status — exactly what a manual click does — handing focus back to the previously
|
||||
// active app (mpv). The overlay is already hidden at this point, so app.hide() hides nothing
|
||||
// visible; once mpv is focused the tracker re-shows the overlay above it.
|
||||
onFinalModalClosed: () => {
|
||||
void restoreMacOSMpvFocusAfterModalClose({
|
||||
platform: process.platform,
|
||||
focusMpv: async () => {
|
||||
app.hide();
|
||||
},
|
||||
getWindowTracker: () => appState.windowTracker,
|
||||
updateVisibleOverlayVisibility: () =>
|
||||
overlayVisibilityRuntime.updateVisibleOverlayVisibility(),
|
||||
warn: (message, details) => logger.warn(message, details),
|
||||
});
|
||||
return createOverlayModalRuntimeService(
|
||||
{
|
||||
getMainWindow: () => overlayManager.getMainWindow(),
|
||||
getModalWindow: () => overlayManager.getModalWindow(),
|
||||
createModalWindow: () => createModalWindow(),
|
||||
getModalGeometry: () => overlayGeometryRuntime.getCurrentOverlayGeometry(),
|
||||
setModalWindowBounds: (geometry) => overlayManager.setModalWindowBounds(geometry),
|
||||
},
|
||||
});
|
||||
{
|
||||
onModalStateChange: (isActive: boolean) =>
|
||||
overlayModalInputState.handleModalInputStateChange(isActive),
|
||||
// On macOS, after the last modal closes the post-close visibility sync hides the overlay
|
||||
// when neither it nor mpv is focused, and keyboard focus is left in limbo (mpv keys like
|
||||
// shift-to-unpause stop working). Programmatically focusing mpv from our background helper
|
||||
// is refused by macOS (most visibly in native fullscreen), so instead resign SubMiner's
|
||||
// active status — exactly what a manual click does — handing focus back to the previously
|
||||
// active app (mpv). The overlay is already hidden at this point, so app.hide() hides nothing
|
||||
// visible; once mpv is focused the tracker re-shows the overlay above it.
|
||||
onFinalModalClosed: () => {
|
||||
void restoreMacOSMpvFocusAfterModalClose({
|
||||
platform: process.platform,
|
||||
focusMpv: async () => {
|
||||
app.hide();
|
||||
},
|
||||
getWindowTracker: () => appState.windowTracker,
|
||||
updateVisibleOverlayVisibility: () =>
|
||||
overlayVisibilityRuntime.updateVisibleOverlayVisibility(),
|
||||
warn: (message, details) => logger.warn(message, details),
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
createAppState,
|
||||
}) as BootServices;
|
||||
@@ -1717,7 +1681,7 @@ function syncOverlayMpvSubtitleSuppression(): void {
|
||||
restoreOverlayMpvSubtitles();
|
||||
}
|
||||
|
||||
const buildImmersionMediaRuntimeMainDepsHandler = createBuildImmersionMediaRuntimeMainDepsHandler({
|
||||
const immersionMediaRuntime = createImmersionMediaRuntime({
|
||||
getResolvedConfig: () => configService.getConfig(),
|
||||
defaultImmersionDbPath: DEFAULT_IMMERSION_DB_PATH,
|
||||
getTracker: () => appState.immersionTracker,
|
||||
@@ -1727,7 +1691,23 @@ const buildImmersionMediaRuntimeMainDepsHandler = createBuildImmersionMediaRunti
|
||||
logDebug: (message) => logger.debug(message),
|
||||
logInfo: (message) => logger.info(message),
|
||||
});
|
||||
const buildAnilistStateRuntimeMainDepsHandler = createBuildAnilistStateRuntimeMainDepsHandler({
|
||||
const anilistRateLimiter = createAnilistRateLimiter();
|
||||
const statsCoverArtFetcher = createCoverArtFetcher(
|
||||
anilistRateLimiter,
|
||||
createLogger('main:stats-cover-art'),
|
||||
{
|
||||
liveAction: createLiveActionMetadataResolver(
|
||||
createTmdbClient({
|
||||
resolveApiKey: createTmdbApiKeyResolver(
|
||||
() => configService.getConfig().tmdb,
|
||||
() => bundledTmdbApiKey,
|
||||
),
|
||||
}),
|
||||
createLogger('main:tmdb'),
|
||||
),
|
||||
},
|
||||
);
|
||||
const anilistStateRuntime = createAnilistStateRuntime({
|
||||
getClientSecretState: () => appState.anilistClientSecretState,
|
||||
setClientSecretState: (next) => {
|
||||
appState.anilistClientSecretState = transitionAnilistClientSecretState(
|
||||
@@ -1748,14 +1728,14 @@ const buildAnilistStateRuntimeMainDepsHandler = createBuildAnilistStateRuntimeMa
|
||||
anilistCachedAccessToken = null;
|
||||
},
|
||||
});
|
||||
const buildConfigDerivedRuntimeMainDepsHandler = createBuildConfigDerivedRuntimeMainDepsHandler({
|
||||
const configDerivedRuntime = createConfigDerivedRuntime({
|
||||
getResolvedConfig: () => configService.getConfig(),
|
||||
getRuntimeOptionsManager: () => appState.runtimeOptionsManager,
|
||||
defaultJimakuLanguagePreference: DEFAULT_CONFIG.jimaku.languagePreference,
|
||||
defaultJimakuMaxEntryResults: DEFAULT_CONFIG.jimaku.maxEntryResults,
|
||||
defaultJimakuApiBaseUrl: DEFAULT_CONFIG.jimaku.apiBaseUrl,
|
||||
});
|
||||
const buildMainSubsyncRuntimeMainDepsHandler = createBuildMainSubsyncRuntimeMainDepsHandler({
|
||||
const subsyncRuntime = createMainSubsyncRuntime({
|
||||
getMpvClient: () => appState.mpvClient,
|
||||
getResolvedConfig: () => configService.getConfig(),
|
||||
getSubsyncInProgress: () => appState.subsyncInProgress,
|
||||
@@ -1771,28 +1751,6 @@ const buildMainSubsyncRuntimeMainDepsHandler = createBuildMainSubsyncRuntimeMain
|
||||
);
|
||||
},
|
||||
});
|
||||
const immersionMediaRuntime = createImmersionMediaRuntime(
|
||||
buildImmersionMediaRuntimeMainDepsHandler(),
|
||||
);
|
||||
const anilistRateLimiter = createAnilistRateLimiter();
|
||||
const statsCoverArtFetcher = createCoverArtFetcher(
|
||||
anilistRateLimiter,
|
||||
createLogger('main:stats-cover-art'),
|
||||
{
|
||||
liveAction: createLiveActionMetadataResolver(
|
||||
createTmdbClient({
|
||||
resolveApiKey: createTmdbApiKeyResolver(
|
||||
() => configService.getConfig().tmdb,
|
||||
() => bundledTmdbApiKey,
|
||||
),
|
||||
}),
|
||||
createLogger('main:tmdb'),
|
||||
),
|
||||
},
|
||||
);
|
||||
const anilistStateRuntime = createAnilistStateRuntime(buildAnilistStateRuntimeMainDepsHandler());
|
||||
const configDerivedRuntime = createConfigDerivedRuntime(buildConfigDerivedRuntimeMainDepsHandler());
|
||||
const subsyncRuntime = createMainSubsyncRuntime(buildMainSubsyncRuntimeMainDepsHandler());
|
||||
const currentMediaTokenizationGate = createCurrentMediaTokenizationGate();
|
||||
const startupOsdSequencer = createStartupOsdSequencer({
|
||||
getNotificationType: () => overlayNotificationsRuntime.getConfiguredStatusNotificationType(),
|
||||
@@ -2061,30 +2019,18 @@ function signalCurrentSubtitleAutoplayReady(): void {
|
||||
);
|
||||
}
|
||||
}
|
||||
const buildSubtitleProcessingControllerMainDepsHandler =
|
||||
createBuildSubtitleProcessingControllerMainDepsHandler({
|
||||
tokenizeSubtitle: async (text: string) =>
|
||||
tokenizeSubtitleDeferred ? await tokenizeSubtitleDeferred(text) : { text, tokens: null },
|
||||
// Controller emits never release the prefetch pause: the first emit for an
|
||||
// uncached line is the provisional plain payload, sent before tokenization
|
||||
// starts, so resuming on it would put prefetch back in contention with the
|
||||
// on-screen line for the single parser window.
|
||||
emitSubtitle: (payload) => emitSubtitlePayload(payload, { resumePrefetch: false }),
|
||||
// The pause is released once the controller has no work left, which covers
|
||||
// the runs that end without an emit (suppressed duplicate, failed
|
||||
// tokenization) as well as the ones that deliver a payload.
|
||||
onProcessingSettled: () => {
|
||||
subtitlePrefetchService?.resume();
|
||||
},
|
||||
logDebug: (message) => {
|
||||
logger.debug(`[subtitle-processing] ${message}`);
|
||||
},
|
||||
now: () => Date.now(),
|
||||
});
|
||||
const subtitleProcessingControllerMainDeps = buildSubtitleProcessingControllerMainDepsHandler();
|
||||
const subtitleProcessingController = createSubtitleProcessingController(
|
||||
subtitleProcessingControllerMainDeps,
|
||||
);
|
||||
const subtitleProcessingController = createPrefetchAwareSubtitleProcessingController({
|
||||
tokenizeSubtitle: async (text: string) =>
|
||||
tokenizeSubtitleDeferred ? await tokenizeSubtitleDeferred(text) : { text, tokens: null },
|
||||
emitSubtitlePayload: (payload, options) => emitSubtitlePayload(payload, options),
|
||||
resumePrefetch: () => {
|
||||
subtitlePrefetchService?.resume();
|
||||
},
|
||||
logDebug: (message) => {
|
||||
logger.debug(`[subtitle-processing] ${message}`);
|
||||
},
|
||||
now: () => Date.now(),
|
||||
});
|
||||
|
||||
let subtitlePrefetchService: SubtitlePrefetchService | null = null;
|
||||
let lastObservedTimePos = 0;
|
||||
@@ -2645,79 +2591,68 @@ const frequencyDictionaryRuntime = createFrequencyDictionaryRuntimeService(
|
||||
})(),
|
||||
);
|
||||
|
||||
const buildGetFieldGroupingResolverMainDepsHandler =
|
||||
createBuildGetFieldGroupingResolverMainDepsHandler({
|
||||
getResolver: () => appState.fieldGroupingResolver,
|
||||
});
|
||||
const getFieldGroupingResolverMainDeps = buildGetFieldGroupingResolverMainDepsHandler();
|
||||
const getFieldGroupingResolverHandler = createGetFieldGroupingResolverHandler(
|
||||
getFieldGroupingResolverMainDeps,
|
||||
);
|
||||
const getFieldGroupingResolverHandler = createGetFieldGroupingResolverHandler({
|
||||
getResolver: () => appState.fieldGroupingResolver,
|
||||
});
|
||||
|
||||
const buildSetFieldGroupingResolverMainDepsHandler =
|
||||
createBuildSetFieldGroupingResolverMainDepsHandler({
|
||||
setResolver: (resolver) => {
|
||||
appState.fieldGroupingResolver = resolver;
|
||||
},
|
||||
nextSequence: () => {
|
||||
appState.fieldGroupingResolverSequence += 1;
|
||||
return appState.fieldGroupingResolverSequence;
|
||||
},
|
||||
getSequence: () => appState.fieldGroupingResolverSequence,
|
||||
});
|
||||
const setFieldGroupingResolverMainDeps = buildSetFieldGroupingResolverMainDepsHandler();
|
||||
const setFieldGroupingResolverHandler = createSetFieldGroupingResolverHandler(
|
||||
setFieldGroupingResolverMainDeps,
|
||||
);
|
||||
const setFieldGroupingResolverHandler = createSetFieldGroupingResolverHandler({
|
||||
setResolver: (resolver) => {
|
||||
appState.fieldGroupingResolver = resolver;
|
||||
},
|
||||
nextSequence: () => {
|
||||
appState.fieldGroupingResolverSequence += 1;
|
||||
return appState.fieldGroupingResolverSequence;
|
||||
},
|
||||
getSequence: () => appState.fieldGroupingResolverSequence,
|
||||
});
|
||||
|
||||
const fieldGroupingOverlayRuntime = createFieldGroupingOverlayRuntime<OverlayHostedModal>(
|
||||
createBuildFieldGroupingOverlayMainDepsHandler<OverlayHostedModal>({
|
||||
getMainWindow: () => overlayManager.getMainWindow(),
|
||||
getVisibleOverlayVisible: () => overlayManager.getVisibleOverlayVisible(),
|
||||
setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible),
|
||||
getResolver: () => getFieldGroupingResolverHandler(),
|
||||
setResolver: (resolver) => setFieldGroupingResolverHandler(resolver),
|
||||
getRestoreVisibleOverlayOnModalClose: () =>
|
||||
overlayModalRuntime.getRestoreVisibleOverlayOnModalClose(),
|
||||
waitForModalOpen: (modal, timeoutMs) => overlayModalRuntime.waitForModalOpen(modal, timeoutMs),
|
||||
handleOverlayModalClosed: (modal) => overlayModalRuntime.handleOverlayModalClosed(modal),
|
||||
logWarn: (message) => logger.warn(message),
|
||||
ensureOverlayStartupPrereqs: () => ensureOverlayStartupPrereqs(),
|
||||
ensureOverlayWindowsReadyForVisibilityActions: () =>
|
||||
ensureOverlayWindowsReadyForVisibilityActions(),
|
||||
sendToActiveOverlayWindow: (channel, payload, runtimeOptions) =>
|
||||
overlayModalRuntime.sendToActiveOverlayWindow(channel, payload, runtimeOptions),
|
||||
})(),
|
||||
);
|
||||
const fieldGroupingOverlayRuntime = createFieldGroupingOverlayRuntime<OverlayHostedModal>({
|
||||
getMainWindow: () => overlayManager.getMainWindow(),
|
||||
getVisibleOverlayVisible: () => overlayManager.getVisibleOverlayVisible(),
|
||||
setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible),
|
||||
getResolver: () => getFieldGroupingResolverHandler(),
|
||||
setResolver: (resolver) => setFieldGroupingResolverHandler(resolver),
|
||||
getRestoreVisibleOverlayOnModalClose: () =>
|
||||
overlayModalRuntime.getRestoreVisibleOverlayOnModalClose(),
|
||||
// These are optional on the runtime options, so a missing forward compiles silently, but
|
||||
// dropping them leaves the field grouping modal with no modal-open ack/retry, no teardown on
|
||||
// failure, and no warn logging.
|
||||
waitForModalOpen: (modal, timeoutMs) => overlayModalRuntime.waitForModalOpen(modal, timeoutMs),
|
||||
handleOverlayModalClosed: (modal) => overlayModalRuntime.handleOverlayModalClosed(modal),
|
||||
logWarn: (message) => logger.warn(message),
|
||||
ensureOverlayStartupPrereqs: () => ensureOverlayStartupPrereqs(),
|
||||
ensureOverlayWindowsReadyForVisibilityActions: () =>
|
||||
ensureOverlayWindowsReadyForVisibilityActions(),
|
||||
sendToVisibleOverlay: (channel, payload, runtimeOptions) =>
|
||||
overlayModalRuntime.sendToActiveOverlayWindow(channel, payload, runtimeOptions),
|
||||
});
|
||||
const createFieldGroupingCallback = fieldGroupingOverlayRuntime.createFieldGroupingCallback;
|
||||
|
||||
const SUBTITLE_POSITIONS_DIR = path.join(CONFIG_DIR, 'subtitle-positions');
|
||||
|
||||
const mediaRuntime = createMediaRuntimeService(
|
||||
createBuildMediaRuntimeMainDepsHandler({
|
||||
isRemoteMediaPath: (mediaPath) => isRemoteMediaPath(mediaPath),
|
||||
loadSubtitlePosition: () => loadSubtitlePosition(),
|
||||
getCurrentMediaPath: () => appState.currentMediaPath,
|
||||
getPendingSubtitlePosition: () => appState.pendingSubtitlePosition,
|
||||
getSubtitlePositionsDir: () => SUBTITLE_POSITIONS_DIR,
|
||||
setCurrentMediaPath: (nextPath: string | null) => {
|
||||
appState.currentMediaPath = nextPath;
|
||||
},
|
||||
clearPendingSubtitlePosition: () => {
|
||||
appState.pendingSubtitlePosition = null;
|
||||
},
|
||||
setSubtitlePosition: (position: SubtitlePosition | null) => {
|
||||
appState.subtitlePosition = position;
|
||||
},
|
||||
broadcastToOverlayWindows: (channel, payload) => {
|
||||
overlayManager.broadcastToOverlayWindows(channel, payload);
|
||||
},
|
||||
getCurrentMediaTitle: () => appState.currentMediaTitle,
|
||||
setCurrentMediaTitle: (title) => {
|
||||
appState.currentMediaTitle = title;
|
||||
},
|
||||
})(),
|
||||
);
|
||||
const mediaRuntime = createMediaRuntimeService({
|
||||
isRemoteMediaPath: (mediaPath) => isRemoteMediaPath(mediaPath),
|
||||
loadSubtitlePosition: () => loadSubtitlePosition(),
|
||||
getCurrentMediaPath: () => appState.currentMediaPath,
|
||||
getPendingSubtitlePosition: () => appState.pendingSubtitlePosition,
|
||||
getSubtitlePositionsDir: () => SUBTITLE_POSITIONS_DIR,
|
||||
setCurrentMediaPath: (nextPath: string | null) => {
|
||||
appState.currentMediaPath = nextPath;
|
||||
},
|
||||
clearPendingSubtitlePosition: () => {
|
||||
appState.pendingSubtitlePosition = null;
|
||||
},
|
||||
setSubtitlePosition: (position: SubtitlePosition | null) => {
|
||||
appState.subtitlePosition = position;
|
||||
},
|
||||
broadcastSubtitlePosition: (position) => {
|
||||
overlayManager.broadcastToOverlayWindows('subtitle-position:set', position);
|
||||
},
|
||||
getCurrentMediaTitle: () => appState.currentMediaTitle,
|
||||
setCurrentMediaTitle: (title) => {
|
||||
appState.currentMediaTitle = title;
|
||||
},
|
||||
});
|
||||
|
||||
const characterDictionaryRuntime = createCharacterDictionaryRuntimeService({
|
||||
userDataPath: USER_DATA_PATH,
|
||||
@@ -2993,20 +2928,10 @@ const visibleOverlayInteractionRuntime = createVisibleOverlayInteractionRuntime(
|
||||
getOverlayForegroundSeparateWindows: () => getOverlayForegroundSeparateWindows(),
|
||||
});
|
||||
|
||||
const buildGetRuntimeOptionsStateMainDepsHandler = createBuildGetRuntimeOptionsStateMainDepsHandler(
|
||||
{
|
||||
getRuntimeOptionsManager: () => appState.runtimeOptionsManager,
|
||||
},
|
||||
);
|
||||
const getRuntimeOptionsStateMainDeps = buildGetRuntimeOptionsStateMainDepsHandler();
|
||||
const getRuntimeOptionsStateHandler = createGetRuntimeOptionsStateHandler(
|
||||
getRuntimeOptionsStateMainDeps,
|
||||
);
|
||||
const getRuntimeOptionsStateHandler = createGetRuntimeOptionsStateHandler({
|
||||
getRuntimeOptionsManager: () => appState.runtimeOptionsManager,
|
||||
});
|
||||
|
||||
const buildRestorePreviousSecondarySubVisibilityMainDepsHandler =
|
||||
createBuildRestorePreviousSecondarySubVisibilityMainDepsHandler({
|
||||
getMpvClient: () => appState.mpvClient,
|
||||
});
|
||||
syncOverlayVisibilityForModal = () => {
|
||||
overlayVisibilityRuntime.updateVisibleOverlayVisibility();
|
||||
};
|
||||
@@ -3031,42 +2956,31 @@ const {
|
||||
maybeStartOverlayLoadingOsd,
|
||||
} = overlayNotificationsRuntime;
|
||||
|
||||
const buildBroadcastRuntimeOptionsChangedMainDepsHandler =
|
||||
createBuildBroadcastRuntimeOptionsChangedMainDepsHandler({
|
||||
const overlayVisibilityComposer = composeOverlayVisibilityRuntime({
|
||||
overlayVisibilityRuntime,
|
||||
restorePreviousSecondarySubVisibilityMainDeps: {
|
||||
getMpvClient: () => appState.mpvClient,
|
||||
},
|
||||
broadcastRuntimeOptionsChangedMainDeps: {
|
||||
broadcastRuntimeOptionsChangedRuntime,
|
||||
getRuntimeOptionsState: () => getRuntimeOptionsStateHandler(),
|
||||
broadcastToOverlayWindows: (channel, ...args) =>
|
||||
overlayManager.broadcastToOverlayWindows(channel, ...args),
|
||||
});
|
||||
|
||||
const buildSendToActiveOverlayWindowMainDepsHandler =
|
||||
createBuildSendToActiveOverlayWindowMainDepsHandler({
|
||||
},
|
||||
sendToActiveOverlayWindowMainDeps: {
|
||||
sendToActiveOverlayWindowRuntime: (channel, payload, runtimeOptions) =>
|
||||
overlayModalRuntime.sendToActiveOverlayWindow(channel, payload, runtimeOptions),
|
||||
});
|
||||
|
||||
const buildSetOverlayDebugVisualizationEnabledMainDepsHandler =
|
||||
createBuildSetOverlayDebugVisualizationEnabledMainDepsHandler({
|
||||
},
|
||||
setOverlayDebugVisualizationEnabledMainDeps: {
|
||||
setOverlayDebugVisualizationEnabledRuntime,
|
||||
getCurrentEnabled: () => appState.overlayDebugVisualizationEnabled,
|
||||
setCurrentEnabled: (next) => {
|
||||
appState.overlayDebugVisualizationEnabled = next;
|
||||
},
|
||||
});
|
||||
|
||||
const buildOpenRuntimeOptionsPaletteMainDepsHandler =
|
||||
createBuildOpenRuntimeOptionsPaletteMainDepsHandler({
|
||||
},
|
||||
openRuntimeOptionsPaletteMainDeps: {
|
||||
openRuntimeOptionsPaletteRuntime: () => overlayModalRuntime.openRuntimeOptionsPalette(),
|
||||
});
|
||||
const overlayVisibilityComposer = composeOverlayVisibilityRuntime({
|
||||
overlayVisibilityRuntime,
|
||||
restorePreviousSecondarySubVisibilityMainDeps:
|
||||
buildRestorePreviousSecondarySubVisibilityMainDepsHandler(),
|
||||
broadcastRuntimeOptionsChangedMainDeps: buildBroadcastRuntimeOptionsChangedMainDepsHandler(),
|
||||
sendToActiveOverlayWindowMainDeps: buildSendToActiveOverlayWindowMainDepsHandler(),
|
||||
setOverlayDebugVisualizationEnabledMainDeps:
|
||||
buildSetOverlayDebugVisualizationEnabledMainDepsHandler(),
|
||||
openRuntimeOptionsPaletteMainDeps: buildOpenRuntimeOptionsPaletteMainDepsHandler(),
|
||||
},
|
||||
});
|
||||
|
||||
function createOverlayHostedModalOpenDeps(): {
|
||||
@@ -3881,56 +3795,50 @@ const {
|
||||
const maybeFocusExistingAnilistSetupWindow = createMaybeFocusExistingAnilistSetupWindowHandler({
|
||||
getSetupWindow: () => appState.anilistSetupWindow,
|
||||
});
|
||||
const buildOpenAnilistSetupWindowMainDepsHandler = createBuildOpenAnilistSetupWindowMainDepsHandler(
|
||||
{
|
||||
maybeFocusExistingSetupWindow: maybeFocusExistingAnilistSetupWindow,
|
||||
createSetupWindow: createCreateAnilistSetupWindowHandler({
|
||||
createBrowserWindow: (options) => new BrowserWindow(options),
|
||||
const openAnilistSetupWindowHandler = createOpenAnilistSetupWindowHandler({
|
||||
maybeFocusExistingSetupWindow: maybeFocusExistingAnilistSetupWindow,
|
||||
createSetupWindow: createCreateAnilistSetupWindowHandler({
|
||||
createBrowserWindow: (options) => new BrowserWindow(options),
|
||||
}),
|
||||
buildAuthorizeUrl: () =>
|
||||
buildAnilistSetupUrl({
|
||||
authorizeUrl: ANILIST_SETUP_CLIENT_ID_URL,
|
||||
clientId: ANILIST_DEFAULT_CLIENT_ID,
|
||||
responseType: ANILIST_SETUP_RESPONSE_TYPE,
|
||||
}),
|
||||
buildAuthorizeUrl: () =>
|
||||
buildAnilistSetupUrl({
|
||||
authorizeUrl: ANILIST_SETUP_CLIENT_ID_URL,
|
||||
clientId: ANILIST_DEFAULT_CLIENT_ID,
|
||||
responseType: ANILIST_SETUP_RESPONSE_TYPE,
|
||||
}),
|
||||
consumeCallbackUrl: (rawUrl) => consumeAnilistSetupTokenFromUrl(rawUrl),
|
||||
openSetupInBrowser: (authorizeUrl) =>
|
||||
openAnilistSetupInBrowser({
|
||||
authorizeUrl,
|
||||
openExternal: (url) => shell.openExternal(url),
|
||||
logError: (message, error) => logger.error(message, error),
|
||||
}),
|
||||
loadManualTokenEntry: (setupWindow, authorizeUrl) =>
|
||||
loadAnilistManualTokenEntry({
|
||||
setupWindow: setupWindow as BrowserWindow,
|
||||
authorizeUrl,
|
||||
developerSettingsUrl: ANILIST_DEVELOPER_SETTINGS_URL,
|
||||
logWarn: (message, data) => logger.warn(message, data),
|
||||
}),
|
||||
redirectUri: ANILIST_REDIRECT_URI,
|
||||
developerSettingsUrl: ANILIST_DEVELOPER_SETTINGS_URL,
|
||||
isAllowedExternalUrl: (url) => isAllowedAnilistExternalUrl(url),
|
||||
isAllowedNavigationUrl: (url) => isAllowedAnilistSetupNavigationUrl(url),
|
||||
logWarn: (message, details) => logger.warn(message, details),
|
||||
logError: (message, details) => logger.error(message, details),
|
||||
clearSetupWindow: () => {
|
||||
appState.anilistSetupWindow = null;
|
||||
},
|
||||
setSetupPageOpened: (opened) => {
|
||||
appState.anilistSetupPageOpened = opened;
|
||||
},
|
||||
setSetupWindow: (setupWindow) => {
|
||||
appState.anilistSetupWindow = setupWindow as BrowserWindow;
|
||||
},
|
||||
openExternal: (url) => {
|
||||
void shell.openExternal(url);
|
||||
},
|
||||
consumeCallbackUrl: (rawUrl) => consumeAnilistSetupTokenFromUrl(rawUrl),
|
||||
openSetupInBrowser: (authorizeUrl) =>
|
||||
openAnilistSetupInBrowser({
|
||||
authorizeUrl,
|
||||
openExternal: (url) => shell.openExternal(url),
|
||||
logError: (message, error) => logger.error(message, error),
|
||||
}),
|
||||
loadManualTokenEntry: (setupWindow, authorizeUrl) =>
|
||||
loadAnilistManualTokenEntry({
|
||||
setupWindow: setupWindow as BrowserWindow,
|
||||
authorizeUrl,
|
||||
developerSettingsUrl: ANILIST_DEVELOPER_SETTINGS_URL,
|
||||
logWarn: (message, data) => logger.warn(message, data),
|
||||
}),
|
||||
redirectUri: ANILIST_REDIRECT_URI,
|
||||
developerSettingsUrl: ANILIST_DEVELOPER_SETTINGS_URL,
|
||||
isAllowedExternalUrl: (url) => isAllowedAnilistExternalUrl(url),
|
||||
isAllowedNavigationUrl: (url) => isAllowedAnilistSetupNavigationUrl(url),
|
||||
logWarn: (message, details) => logger.warn(message, details),
|
||||
logError: (message, details) => logger.error(message, details),
|
||||
clearSetupWindow: () => {
|
||||
appState.anilistSetupWindow = null;
|
||||
},
|
||||
);
|
||||
|
||||
const openAnilistSetupWindowHandler = createOpenAnilistSetupWindowHandler(
|
||||
buildOpenAnilistSetupWindowMainDepsHandler(),
|
||||
);
|
||||
setSetupPageOpened: (opened) => {
|
||||
appState.anilistSetupPageOpened = opened;
|
||||
},
|
||||
setSetupWindow: (setupWindow) => {
|
||||
appState.anilistSetupWindow = setupWindow as BrowserWindow;
|
||||
},
|
||||
openExternal: (url) => {
|
||||
void shell.openExternal(url);
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
refreshAnilistClientSecretState,
|
||||
@@ -4191,7 +4099,7 @@ const rememberAnilistAttemptedUpdate = (key: string): void => {
|
||||
);
|
||||
};
|
||||
|
||||
const buildLoadSubtitlePositionMainDepsHandler = createBuildLoadSubtitlePositionMainDepsHandler({
|
||||
const loadSubtitlePosition = createLoadSubtitlePositionHandler({
|
||||
loadSubtitlePositionCore: () =>
|
||||
loadSubtitlePositionCore({
|
||||
currentMediaPath: appState.currentMediaPath,
|
||||
@@ -4202,10 +4110,8 @@ const buildLoadSubtitlePositionMainDepsHandler = createBuildLoadSubtitlePosition
|
||||
appState.subtitlePosition = position;
|
||||
},
|
||||
});
|
||||
const loadSubtitlePositionMainDeps = buildLoadSubtitlePositionMainDepsHandler();
|
||||
const loadSubtitlePosition = createLoadSubtitlePositionHandler(loadSubtitlePositionMainDeps);
|
||||
|
||||
const buildSaveSubtitlePositionMainDepsHandler = createBuildSaveSubtitlePositionMainDepsHandler({
|
||||
const saveSubtitlePosition = createSaveSubtitlePositionHandler({
|
||||
saveSubtitlePositionCore: (position) => {
|
||||
saveSubtitlePositionCore({
|
||||
position,
|
||||
@@ -4223,8 +4129,6 @@ const buildSaveSubtitlePositionMainDepsHandler = createBuildSaveSubtitlePosition
|
||||
appState.subtitlePosition = position;
|
||||
},
|
||||
});
|
||||
const saveSubtitlePositionMainDeps = buildSaveSubtitlePositionMainDepsHandler();
|
||||
const saveSubtitlePosition = createSaveSubtitlePositionHandler(saveSubtitlePositionMainDeps);
|
||||
|
||||
registerSubminerProtocolClient();
|
||||
let flushPendingMpvLogWrites = (): void => {};
|
||||
@@ -4377,9 +4281,7 @@ const resolveLegacyVocabularyPos = async (row: {
|
||||
return null;
|
||||
};
|
||||
|
||||
const immersionTrackerStartupMainDeps: Parameters<
|
||||
typeof createBuildImmersionTrackerStartupMainDepsHandler
|
||||
>[0] = {
|
||||
const immersionTrackerStartupMainDeps: ImmersionTrackerStartupDeps = {
|
||||
getResolvedConfig: () => configService.getConfig(),
|
||||
getConfiguredDbPath: () => immersionMediaRuntime.getConfiguredDbPath(),
|
||||
createTrackerService: (params) =>
|
||||
@@ -4437,7 +4339,7 @@ const immersionTrackerStartupMainDeps: Parameters<
|
||||
logWarn: (message, details) => logger.warn(message, details),
|
||||
};
|
||||
const createImmersionTrackerStartup = createImmersionTrackerStartupHandler(
|
||||
createBuildImmersionTrackerStartupMainDepsHandler(immersionTrackerStartupMainDeps)(),
|
||||
immersionTrackerStartupMainDeps,
|
||||
);
|
||||
const recordSubtitleMiningContext = (context: SubtitleMiningContext | null): void => {
|
||||
pendingSubtitleMiningContext = context;
|
||||
@@ -5538,8 +5440,8 @@ const {
|
||||
buildRegisterGlobalShortcutsMainDeps: (getConfiguredShortcutsHandler) => ({
|
||||
getConfiguredShortcuts: () => getConfiguredShortcutsHandler(),
|
||||
registerGlobalShortcutsCore,
|
||||
toggleVisibleOverlay: () => toggleVisibleOverlay(),
|
||||
openYomitanSettings: () => openDictionarySettings(),
|
||||
onToggleVisibleOverlay: () => toggleVisibleOverlay(),
|
||||
onOpenYomitanSettings: () => openDictionarySettings(),
|
||||
isDev,
|
||||
getMainWindow: () => overlayManager.getMainWindow(),
|
||||
}),
|
||||
@@ -5668,8 +5570,8 @@ const cycleSecondarySubMode = createCycleSecondarySubModeRuntimeHandler({
|
||||
setLastSecondarySubToggleAtMs: (timestampMs: number) => {
|
||||
appState.lastSecondarySubToggleAtMs = timestampMs;
|
||||
},
|
||||
broadcastToOverlayWindows: (channel, mode) => {
|
||||
overlayManager.broadcastToOverlayWindows(channel, mode);
|
||||
broadcastSecondarySubMode: (mode) => {
|
||||
overlayManager.broadcastToOverlayWindows('secondary-subtitle:mode', mode);
|
||||
},
|
||||
showMpvOsd: (text: string) => showConfiguredPlaybackFeedback(text),
|
||||
},
|
||||
@@ -5680,90 +5582,62 @@ function setSecondarySubMode(mode: SecondarySubMode): void {
|
||||
appState.secondarySubMode = mode;
|
||||
}
|
||||
|
||||
const buildUpdateLastCardFromClipboardMainDepsHandler =
|
||||
createBuildUpdateLastCardFromClipboardMainDepsHandler({
|
||||
getAnkiIntegration: () => appState.ankiIntegration,
|
||||
readClipboardText: () => clipboard.readText(),
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
updateLastCardFromClipboardCore,
|
||||
});
|
||||
const updateLastCardFromClipboardMainDeps = buildUpdateLastCardFromClipboardMainDepsHandler();
|
||||
const updateLastCardFromClipboardHandler = createUpdateLastCardFromClipboardHandler(
|
||||
updateLastCardFromClipboardMainDeps,
|
||||
);
|
||||
const updateLastCardFromClipboardHandler = createUpdateLastCardFromClipboardHandler({
|
||||
getAnkiIntegration: () => appState.ankiIntegration,
|
||||
readClipboardText: () => clipboard.readText(),
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
updateLastCardFromClipboardCore,
|
||||
});
|
||||
|
||||
const buildRefreshKnownWordCacheMainDepsHandler = createBuildRefreshKnownWordCacheMainDepsHandler({
|
||||
const refreshKnownWordCacheHandler = createRefreshKnownWordCacheHandler({
|
||||
getAnkiIntegration: () => appState.ankiIntegration,
|
||||
missingIntegrationMessage: 'AnkiConnect integration not enabled',
|
||||
});
|
||||
const refreshKnownWordCacheMainDeps = buildRefreshKnownWordCacheMainDepsHandler();
|
||||
const refreshKnownWordCacheHandler = createRefreshKnownWordCacheHandler(
|
||||
refreshKnownWordCacheMainDeps,
|
||||
);
|
||||
|
||||
const buildTriggerFieldGroupingMainDepsHandler = createBuildTriggerFieldGroupingMainDepsHandler({
|
||||
const triggerFieldGroupingHandler = createTriggerFieldGroupingHandler({
|
||||
getAnkiIntegration: () => appState.ankiIntegration,
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
triggerFieldGroupingCore,
|
||||
});
|
||||
const triggerFieldGroupingMainDeps = buildTriggerFieldGroupingMainDepsHandler();
|
||||
const triggerFieldGroupingHandler = createTriggerFieldGroupingHandler(triggerFieldGroupingMainDeps);
|
||||
|
||||
const buildMarkLastCardAsAudioCardMainDepsHandler =
|
||||
createBuildMarkLastCardAsAudioCardMainDepsHandler({
|
||||
getAnkiIntegration: () => appState.ankiIntegration,
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
markLastCardAsAudioCardCore,
|
||||
});
|
||||
const markLastCardAsAudioCardMainDeps = buildMarkLastCardAsAudioCardMainDepsHandler();
|
||||
const markLastCardAsAudioCardHandler = createMarkLastCardAsAudioCardHandler(
|
||||
markLastCardAsAudioCardMainDeps,
|
||||
);
|
||||
const markLastCardAsAudioCardHandler = createMarkLastCardAsAudioCardHandler({
|
||||
getAnkiIntegration: () => appState.ankiIntegration,
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
markLastCardAsAudioCardCore,
|
||||
});
|
||||
|
||||
const buildMineSentenceCardMainDepsHandler = createBuildMineSentenceCardMainDepsHandler({
|
||||
const mineSentenceCardHandler = createMineSentenceCardHandler({
|
||||
getAnkiIntegration: () => appState.ankiIntegration,
|
||||
getMpvClient: () => appState.mpvClient,
|
||||
getPrimarySubtitle: () => captureCurrentPrimarySubtitleMiningContext(),
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
mineSentenceCardCore,
|
||||
});
|
||||
const mineSentenceCardHandler = createMineSentenceCardHandler(
|
||||
buildMineSentenceCardMainDepsHandler(),
|
||||
);
|
||||
|
||||
const buildHandleMultiCopyDigitMainDepsHandler = createBuildHandleMultiCopyDigitMainDepsHandler({
|
||||
const handleMultiCopyDigitHandler = createHandleMultiCopyDigitHandler({
|
||||
getSubtitleTimingTracker: () => appState.subtitleTimingTracker,
|
||||
writeClipboardText: (text) => clipboard.writeText(text),
|
||||
showMpvOsd: (text) => showConfiguredPlaybackFeedback(text),
|
||||
handleMultiCopyDigitCore,
|
||||
});
|
||||
const handleMultiCopyDigitMainDeps = buildHandleMultiCopyDigitMainDepsHandler();
|
||||
const handleMultiCopyDigitHandler = createHandleMultiCopyDigitHandler(handleMultiCopyDigitMainDeps);
|
||||
|
||||
const buildCopyCurrentSubtitleMainDepsHandler = createBuildCopyCurrentSubtitleMainDepsHandler({
|
||||
const copyCurrentSubtitleHandler = createCopyCurrentSubtitleHandler({
|
||||
getSubtitleTimingTracker: () => appState.subtitleTimingTracker,
|
||||
writeClipboardText: (text) => clipboard.writeText(text),
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
copyCurrentSubtitleCore,
|
||||
});
|
||||
const copyCurrentSubtitleMainDeps = buildCopyCurrentSubtitleMainDepsHandler();
|
||||
const copyCurrentSubtitleHandler = createCopyCurrentSubtitleHandler(copyCurrentSubtitleMainDeps);
|
||||
|
||||
const buildHandleMineSentenceDigitMainDepsHandler =
|
||||
createBuildHandleMineSentenceDigitMainDepsHandler({
|
||||
getSubtitleTimingTracker: () => appState.subtitleTimingTracker,
|
||||
getAnkiIntegration: () => appState.ankiIntegration,
|
||||
getCurrentSecondarySubText: () => appState.mpvClient?.currentSecondarySubText || undefined,
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
logError: (message, err) => {
|
||||
logger.error(message, err);
|
||||
},
|
||||
handleMineSentenceDigitCore,
|
||||
});
|
||||
const handleMineSentenceDigitMainDeps = buildHandleMineSentenceDigitMainDepsHandler();
|
||||
const handleMineSentenceDigitHandler = createHandleMineSentenceDigitHandler(
|
||||
handleMineSentenceDigitMainDeps,
|
||||
);
|
||||
const handleMineSentenceDigitHandler = createHandleMineSentenceDigitHandler({
|
||||
getSubtitleTimingTracker: () => appState.subtitleTimingTracker,
|
||||
getAnkiIntegration: () => appState.ankiIntegration,
|
||||
getCurrentSecondarySubText: () => appState.mpvClient?.currentSecondarySubText || undefined,
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
logError: (message, err) => {
|
||||
logger.error(message, err);
|
||||
},
|
||||
handleMineSentenceDigitCore,
|
||||
});
|
||||
const {
|
||||
setVisibleOverlayVisible: setVisibleOverlayVisibleHandler,
|
||||
toggleVisibleOverlay: toggleVisibleOverlayHandler,
|
||||
@@ -5779,29 +5653,19 @@ const {
|
||||
getVisibleOverlayVisible: () => overlayManager.getVisibleOverlayVisible(),
|
||||
});
|
||||
|
||||
const buildHandleOverlayModalClosedMainDepsHandler =
|
||||
createBuildHandleOverlayModalClosedMainDepsHandler({
|
||||
handleOverlayModalClosedRuntime: (modal) => overlayModalRuntime.handleOverlayModalClosed(modal),
|
||||
});
|
||||
const handleOverlayModalClosedMainDeps = buildHandleOverlayModalClosedMainDepsHandler();
|
||||
const handleOverlayModalClosedHandler = createHandleOverlayModalClosedHandler(
|
||||
handleOverlayModalClosedMainDeps,
|
||||
);
|
||||
const handleOverlayModalClosedHandler = createHandleOverlayModalClosedHandler({
|
||||
handleOverlayModalClosedRuntime: (modal) => overlayModalRuntime.handleOverlayModalClosed(modal),
|
||||
});
|
||||
|
||||
const buildAppendClipboardVideoToQueueMainDepsHandler =
|
||||
createBuildAppendClipboardVideoToQueueMainDepsHandler({
|
||||
appendClipboardVideoToQueueRuntime,
|
||||
getMpvClient: () => appState.mpvClient,
|
||||
readClipboardText: () => clipboard.readText(),
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
sendMpvCommand: (command) => {
|
||||
sendMpvCommandRuntime(appState.mpvClient, command);
|
||||
},
|
||||
});
|
||||
const appendClipboardVideoToQueueMainDeps = buildAppendClipboardVideoToQueueMainDepsHandler();
|
||||
const appendClipboardVideoToQueueHandler = createAppendClipboardVideoToQueueHandler(
|
||||
appendClipboardVideoToQueueMainDeps,
|
||||
);
|
||||
const appendClipboardVideoToQueueHandler = createAppendClipboardVideoToQueueHandler({
|
||||
appendClipboardVideoToQueueRuntime,
|
||||
getMpvClient: () => appState.mpvClient,
|
||||
readClipboardText: () => clipboard.readText(),
|
||||
showMpvOsd: (text) => overlayNotificationsRuntime.showConfiguredStatusNotification(text),
|
||||
sendMpvCommand: (command) => {
|
||||
sendMpvCommandRuntime(appState.mpvClient, command);
|
||||
},
|
||||
});
|
||||
|
||||
async function dispatchSessionAction(request: SessionActionDispatchRequest): Promise<void> {
|
||||
await dispatchSessionActionCore(request, {
|
||||
|
||||
@@ -425,25 +425,6 @@ test('subtitle annotation updates invalidate prefetched tokenizations before ref
|
||||
);
|
||||
});
|
||||
|
||||
test('subtitle processing controller resumes prefetch on settle, not on its emits', () => {
|
||||
const source = readMainSource();
|
||||
const depsBlock = source.match(
|
||||
/createBuildSubtitleProcessingControllerMainDepsHandler\(\{(?<body>[\s\S]*?)\n \}\);/,
|
||||
)?.groups?.body;
|
||||
|
||||
assert.ok(depsBlock);
|
||||
// A controller emit can be the provisional plain payload sent before the
|
||||
// scan runs, so it must not release the prefetch pause.
|
||||
assert.match(
|
||||
depsBlock,
|
||||
/emitSubtitle: \(payload\) => emitSubtitlePayload\(payload, \{ resumePrefetch: false \}\),/,
|
||||
);
|
||||
assert.match(
|
||||
depsBlock,
|
||||
/onProcessingSettled: \(\) => \{\s+subtitlePrefetchService\?\.resume\(\);/,
|
||||
);
|
||||
});
|
||||
|
||||
test('annotation upgrades skip the duplicate basic websocket event', () => {
|
||||
const source = readMainSource();
|
||||
const emitBlock = source.match(
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import type {
|
||||
createEnsureAnilistMediaGuessHandler,
|
||||
createMaybeProbeAnilistDurationHandler,
|
||||
} from './anilist-media-guess';
|
||||
|
||||
type MaybeProbeAnilistDurationMainDeps = Parameters<
|
||||
typeof createMaybeProbeAnilistDurationHandler
|
||||
>[0];
|
||||
type EnsureAnilistMediaGuessMainDeps = Parameters<typeof createEnsureAnilistMediaGuessHandler>[0];
|
||||
|
||||
export function createBuildMaybeProbeAnilistDurationMainDepsHandler(
|
||||
deps: MaybeProbeAnilistDurationMainDeps,
|
||||
) {
|
||||
return (): MaybeProbeAnilistDurationMainDeps => ({
|
||||
getState: () => deps.getState(),
|
||||
setState: (state) => deps.setState(state),
|
||||
durationRetryIntervalMs: deps.durationRetryIntervalMs,
|
||||
now: () => deps.now(),
|
||||
requestMpvDuration: () => deps.requestMpvDuration(),
|
||||
logWarn: (message: string, error: unknown) => deps.logWarn(message, error),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildEnsureAnilistMediaGuessMainDepsHandler(
|
||||
deps: EnsureAnilistMediaGuessMainDeps,
|
||||
) {
|
||||
return (): EnsureAnilistMediaGuessMainDeps => ({
|
||||
getState: () => deps.getState(),
|
||||
setState: (state) => deps.setState(state),
|
||||
resolveMediaPathForJimaku: (currentMediaPath) =>
|
||||
deps.resolveMediaPathForJimaku(currentMediaPath),
|
||||
getCurrentMediaPath: () => deps.getCurrentMediaPath(),
|
||||
getCurrentMediaTitle: () => deps.getCurrentMediaTitle(),
|
||||
guessAnilistMediaInfo: (mediaPath, mediaTitle) =>
|
||||
deps.guessAnilistMediaInfo(mediaPath, mediaTitle),
|
||||
});
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
import type {
|
||||
createGetAnilistMediaGuessRuntimeStateHandler,
|
||||
createGetCurrentAnilistMediaKeyHandler,
|
||||
createRecordAnilistMediaDurationHandler,
|
||||
createResetAnilistMediaGuessStateHandler,
|
||||
createResetAnilistMediaTrackingHandler,
|
||||
createSetAnilistMediaGuessRuntimeStateHandler,
|
||||
} from './anilist-media-state';
|
||||
|
||||
type GetCurrentAnilistMediaKeyMainDeps = Parameters<
|
||||
typeof createGetCurrentAnilistMediaKeyHandler
|
||||
>[0];
|
||||
type ResetAnilistMediaTrackingMainDeps = Parameters<
|
||||
typeof createResetAnilistMediaTrackingHandler
|
||||
>[0];
|
||||
type GetAnilistMediaGuessRuntimeStateMainDeps = Parameters<
|
||||
typeof createGetAnilistMediaGuessRuntimeStateHandler
|
||||
>[0];
|
||||
type SetAnilistMediaGuessRuntimeStateMainDeps = Parameters<
|
||||
typeof createSetAnilistMediaGuessRuntimeStateHandler
|
||||
>[0];
|
||||
type RecordAnilistMediaDurationMainDeps = Parameters<
|
||||
typeof createRecordAnilistMediaDurationHandler
|
||||
>[0];
|
||||
type ResetAnilistMediaGuessStateMainDeps = Parameters<
|
||||
typeof createResetAnilistMediaGuessStateHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildGetCurrentAnilistMediaKeyMainDepsHandler(
|
||||
deps: GetCurrentAnilistMediaKeyMainDeps,
|
||||
) {
|
||||
return (): GetCurrentAnilistMediaKeyMainDeps => ({
|
||||
getCurrentMediaPath: () => deps.getCurrentMediaPath(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildResetAnilistMediaTrackingMainDepsHandler(
|
||||
deps: ResetAnilistMediaTrackingMainDeps,
|
||||
) {
|
||||
return (): ResetAnilistMediaTrackingMainDeps => ({
|
||||
setMediaKey: (value) => deps.setMediaKey(value),
|
||||
setMediaDurationSec: (value) => deps.setMediaDurationSec(value),
|
||||
setMediaGuess: (value) => deps.setMediaGuess(value),
|
||||
setMediaGuessPromise: (value) => deps.setMediaGuessPromise(value),
|
||||
setLastDurationProbeAtMs: (value: number) => deps.setLastDurationProbeAtMs(value),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildGetAnilistMediaGuessRuntimeStateMainDepsHandler(
|
||||
deps: GetAnilistMediaGuessRuntimeStateMainDeps,
|
||||
) {
|
||||
return (): GetAnilistMediaGuessRuntimeStateMainDeps => ({
|
||||
getMediaKey: () => deps.getMediaKey(),
|
||||
getMediaDurationSec: () => deps.getMediaDurationSec(),
|
||||
getMediaGuess: () => deps.getMediaGuess(),
|
||||
getMediaGuessPromise: () => deps.getMediaGuessPromise(),
|
||||
getLastDurationProbeAtMs: () => deps.getLastDurationProbeAtMs(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildSetAnilistMediaGuessRuntimeStateMainDepsHandler(
|
||||
deps: SetAnilistMediaGuessRuntimeStateMainDeps,
|
||||
) {
|
||||
return (): SetAnilistMediaGuessRuntimeStateMainDeps => ({
|
||||
setMediaKey: (value) => deps.setMediaKey(value),
|
||||
setMediaDurationSec: (value) => deps.setMediaDurationSec(value),
|
||||
setMediaGuess: (value) => deps.setMediaGuess(value),
|
||||
setMediaGuessPromise: (value) => deps.setMediaGuessPromise(value),
|
||||
setLastDurationProbeAtMs: (value: number) => deps.setLastDurationProbeAtMs(value),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildRecordAnilistMediaDurationMainDepsHandler(
|
||||
deps: RecordAnilistMediaDurationMainDeps,
|
||||
) {
|
||||
return (): RecordAnilistMediaDurationMainDeps => ({
|
||||
getCurrentMediaKey: () => deps.getCurrentMediaKey(),
|
||||
getState: () => deps.getState(),
|
||||
setState: (state) => deps.setState(state),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildResetAnilistMediaGuessStateMainDepsHandler(
|
||||
deps: ResetAnilistMediaGuessStateMainDeps,
|
||||
) {
|
||||
return (): ResetAnilistMediaGuessStateMainDeps => ({
|
||||
setMediaGuess: (value) => deps.setMediaGuess(value),
|
||||
setMediaGuessPromise: (value) => deps.setMediaGuessPromise(value),
|
||||
});
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
import type {
|
||||
createMaybeRunAnilistPostWatchUpdateHandler,
|
||||
createProcessNextAnilistRetryUpdateHandler,
|
||||
} from './anilist-post-watch';
|
||||
|
||||
type ProcessNextAnilistRetryUpdateMainDeps = Parameters<
|
||||
typeof createProcessNextAnilistRetryUpdateHandler
|
||||
>[0];
|
||||
type MaybeRunAnilistPostWatchUpdateMainDeps = Parameters<
|
||||
typeof createMaybeRunAnilistPostWatchUpdateHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildProcessNextAnilistRetryUpdateMainDepsHandler(
|
||||
deps: ProcessNextAnilistRetryUpdateMainDeps,
|
||||
) {
|
||||
return (): ProcessNextAnilistRetryUpdateMainDeps => ({
|
||||
nextReady: () => deps.nextReady(),
|
||||
refreshRetryQueueState: () => deps.refreshRetryQueueState(),
|
||||
setLastAttemptAt: (value: number) => deps.setLastAttemptAt(value),
|
||||
setLastError: (value: string | null) => deps.setLastError(value),
|
||||
refreshAnilistClientSecretState: () => deps.refreshAnilistClientSecretState(),
|
||||
updateAnilistPostWatchProgress: (
|
||||
accessToken: string,
|
||||
title: string,
|
||||
episode: number,
|
||||
season?: number | null,
|
||||
mediaId?: number | null,
|
||||
) => deps.updateAnilistPostWatchProgress(accessToken, title, episode, season, mediaId),
|
||||
markSuccess: (key: string) => deps.markSuccess(key),
|
||||
rememberAttemptedUpdateKey: (key: string) => deps.rememberAttemptedUpdateKey(key),
|
||||
markFailure: (key: string, message: string) => deps.markFailure(key, message),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
now: () => deps.now(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildMaybeRunAnilistPostWatchUpdateMainDepsHandler(
|
||||
deps: MaybeRunAnilistPostWatchUpdateMainDeps,
|
||||
) {
|
||||
return (): MaybeRunAnilistPostWatchUpdateMainDeps => ({
|
||||
getInFlight: () => deps.getInFlight(),
|
||||
setInFlight: (value: boolean) => deps.setInFlight(value),
|
||||
getResolvedConfig: () => deps.getResolvedConfig(),
|
||||
isAnilistTrackingEnabled: (config) => deps.isAnilistTrackingEnabled(config),
|
||||
getCurrentMediaKey: () => deps.getCurrentMediaKey(),
|
||||
hasMpvClient: () => deps.hasMpvClient(),
|
||||
getTrackedMediaKey: () => deps.getTrackedMediaKey(),
|
||||
resetTrackedMedia: (mediaKey) => deps.resetTrackedMedia(mediaKey),
|
||||
getWatchedSeconds: () => deps.getWatchedSeconds(),
|
||||
maybeProbeAnilistDuration: (mediaKey: string, options) =>
|
||||
deps.maybeProbeAnilistDuration(mediaKey, options),
|
||||
ensureAnilistMediaGuess: (mediaKey: string) => deps.ensureAnilistMediaGuess(mediaKey),
|
||||
hasAttemptedUpdateKey: (key: string) => deps.hasAttemptedUpdateKey(key),
|
||||
processNextAnilistRetryUpdate: () => deps.processNextAnilistRetryUpdate(),
|
||||
refreshAnilistClientSecretState: () => deps.refreshAnilistClientSecretState(),
|
||||
enqueueRetry: (
|
||||
key: string,
|
||||
title: string,
|
||||
episode: number,
|
||||
season?: number | null,
|
||||
mediaId?: number | null,
|
||||
) => deps.enqueueRetry(key, title, episode, season, mediaId),
|
||||
getCurrentMediaTitle: deps.getCurrentMediaTitle
|
||||
? () => deps.getCurrentMediaTitle!()
|
||||
: undefined,
|
||||
resolvePinnedAnilistMediaId: deps.resolvePinnedAnilistMediaId
|
||||
? (input) => deps.resolvePinnedAnilistMediaId!(input)
|
||||
: undefined,
|
||||
markRetryFailure: (key: string, message: string) => deps.markRetryFailure(key, message),
|
||||
markRetrySuccess: (key: string) => deps.markRetrySuccess(key),
|
||||
refreshRetryQueueState: () => deps.refreshRetryQueueState(),
|
||||
updateAnilistPostWatchProgress: (
|
||||
accessToken: string,
|
||||
title: string,
|
||||
episode: number,
|
||||
season?: number | null,
|
||||
mediaId?: number | null,
|
||||
) => deps.updateAnilistPostWatchProgress(accessToken, title, episode, season, mediaId),
|
||||
rememberAttemptedUpdateKey: (key: string) => deps.rememberAttemptedUpdateKey(key),
|
||||
showMpvOsd: (message: string) => deps.showMpvOsd(message),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
logWarn: (message: string) => deps.logWarn(message),
|
||||
minWatchSeconds: deps.minWatchSeconds,
|
||||
minWatchRatio: deps.minWatchRatio,
|
||||
});
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import type {
|
||||
createConsumeAnilistSetupTokenFromUrlHandler,
|
||||
createHandleAnilistSetupProtocolUrlHandler,
|
||||
createNotifyAnilistSetupHandler,
|
||||
createRegisterSubminerProtocolClientHandler,
|
||||
} from './anilist-setup-protocol';
|
||||
|
||||
type NotifyAnilistSetupMainDeps = Parameters<typeof createNotifyAnilistSetupHandler>[0];
|
||||
type ConsumeAnilistSetupTokenMainDeps = Parameters<
|
||||
typeof createConsumeAnilistSetupTokenFromUrlHandler
|
||||
>[0];
|
||||
type HandleAnilistSetupProtocolUrlMainDeps = Parameters<
|
||||
typeof createHandleAnilistSetupProtocolUrlHandler
|
||||
>[0];
|
||||
type RegisterSubminerProtocolClientMainDeps = Parameters<
|
||||
typeof createRegisterSubminerProtocolClientHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildNotifyAnilistSetupMainDepsHandler(deps: NotifyAnilistSetupMainDeps) {
|
||||
return (): NotifyAnilistSetupMainDeps => ({
|
||||
getNotificationType: deps.getNotificationType ? () => deps.getNotificationType?.() : undefined,
|
||||
hasMpvClient: () => deps.hasMpvClient(),
|
||||
showMpvOsd: (message: string) => deps.showMpvOsd(message),
|
||||
showOverlayNotification: deps.showOverlayNotification
|
||||
? (payload) => deps.showOverlayNotification?.(payload)
|
||||
: undefined,
|
||||
showDesktopNotification: (title: string, options: { body: string }) =>
|
||||
deps.showDesktopNotification(title, options),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildConsumeAnilistSetupTokenFromUrlMainDepsHandler(
|
||||
deps: ConsumeAnilistSetupTokenMainDeps,
|
||||
) {
|
||||
return (): ConsumeAnilistSetupTokenMainDeps => ({
|
||||
consumeAnilistSetupCallbackUrl: (input) => deps.consumeAnilistSetupCallbackUrl(input),
|
||||
saveToken: (token: string) => deps.saveToken(token),
|
||||
setCachedToken: (token: string) => deps.setCachedToken(token),
|
||||
setResolvedState: (resolvedAt: number) => deps.setResolvedState(resolvedAt),
|
||||
setSetupPageOpened: (opened: boolean) => deps.setSetupPageOpened(opened),
|
||||
onSuccess: () => deps.onSuccess(),
|
||||
closeWindow: () => deps.closeWindow(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildHandleAnilistSetupProtocolUrlMainDepsHandler(
|
||||
deps: HandleAnilistSetupProtocolUrlMainDeps,
|
||||
) {
|
||||
return (): HandleAnilistSetupProtocolUrlMainDeps => ({
|
||||
consumeAnilistSetupTokenFromUrl: (rawUrl: string) =>
|
||||
deps.consumeAnilistSetupTokenFromUrl(rawUrl),
|
||||
logWarn: (message: string, details: unknown) => deps.logWarn(message, details),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildRegisterSubminerProtocolClientMainDepsHandler(
|
||||
deps: RegisterSubminerProtocolClientMainDeps,
|
||||
) {
|
||||
return (): RegisterSubminerProtocolClientMainDeps => ({
|
||||
isDefaultApp: () => deps.isDefaultApp(),
|
||||
getArgv: () => deps.getArgv(),
|
||||
execPath: deps.execPath,
|
||||
resolvePath: (value: string) => deps.resolvePath(value),
|
||||
setAsDefaultProtocolClient: (scheme: string, path?: string, args?: string[]) =>
|
||||
deps.setAsDefaultProtocolClient(scheme, path, args),
|
||||
logDebug: (message: string, details?: unknown) => deps.logDebug(message, details),
|
||||
});
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import type { createOpenAnilistSetupWindowHandler } from './anilist-setup-window';
|
||||
|
||||
type OpenAnilistSetupWindowMainDeps = Parameters<typeof createOpenAnilistSetupWindowHandler>[0];
|
||||
|
||||
export function createBuildOpenAnilistSetupWindowMainDepsHandler(
|
||||
deps: OpenAnilistSetupWindowMainDeps,
|
||||
) {
|
||||
return (): OpenAnilistSetupWindowMainDeps => ({
|
||||
maybeFocusExistingSetupWindow: () => deps.maybeFocusExistingSetupWindow(),
|
||||
createSetupWindow: () => deps.createSetupWindow(),
|
||||
buildAuthorizeUrl: () => deps.buildAuthorizeUrl(),
|
||||
consumeCallbackUrl: (rawUrl: string) => deps.consumeCallbackUrl(rawUrl),
|
||||
openSetupInBrowser: (authorizeUrl: string) => deps.openSetupInBrowser(authorizeUrl),
|
||||
loadManualTokenEntry: (setupWindow, authorizeUrl: string) =>
|
||||
deps.loadManualTokenEntry(setupWindow, authorizeUrl),
|
||||
redirectUri: deps.redirectUri,
|
||||
developerSettingsUrl: deps.developerSettingsUrl,
|
||||
isAllowedExternalUrl: (url: string) => deps.isAllowedExternalUrl(url),
|
||||
isAllowedNavigationUrl: (url: string) => deps.isAllowedNavigationUrl(url),
|
||||
logWarn: (message: string, details?: unknown) => deps.logWarn(message, details),
|
||||
logError: (message: string, details: unknown) => deps.logError(message, details),
|
||||
clearSetupWindow: () => deps.clearSetupWindow(),
|
||||
setSetupPageOpened: (opened: boolean) => deps.setSetupPageOpened(opened),
|
||||
setSetupWindow: (setupWindow) => deps.setSetupWindow(setupWindow),
|
||||
openExternal: (url: string) => deps.openExternal(url),
|
||||
});
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import type { createRefreshAnilistClientSecretStateHandler } from './anilist-token-refresh';
|
||||
|
||||
type RefreshAnilistClientSecretStateMainDeps = Parameters<
|
||||
typeof createRefreshAnilistClientSecretStateHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildRefreshAnilistClientSecretStateMainDepsHandler(
|
||||
deps: RefreshAnilistClientSecretStateMainDeps,
|
||||
) {
|
||||
return (): RefreshAnilistClientSecretStateMainDeps => ({
|
||||
getResolvedConfig: () => deps.getResolvedConfig(),
|
||||
isAnilistTrackingEnabled: (config) => deps.isAnilistTrackingEnabled(config),
|
||||
getCachedAccessToken: () => deps.getCachedAccessToken(),
|
||||
setCachedAccessToken: (token) => deps.setCachedAccessToken(token),
|
||||
saveStoredToken: (token: string) => deps.saveStoredToken(token),
|
||||
loadStoredToken: () => deps.loadStoredToken(),
|
||||
setClientSecretState: (state) => deps.setClientSecretState(state),
|
||||
getAnilistSetupPageOpened: () => deps.getAnilistSetupPageOpened(),
|
||||
setAnilistSetupPageOpened: (opened: boolean) => deps.setAnilistSetupPageOpened(opened),
|
||||
openAnilistSetupWindow: () => deps.openAnilistSetupWindow(),
|
||||
now: () => deps.now(),
|
||||
});
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
import type { createRefreshKnownWordCacheHandler, PrimarySubtitle } from './anki-actions';
|
||||
|
||||
type RefreshKnownWordCacheMainDeps = Parameters<typeof createRefreshKnownWordCacheHandler>[0];
|
||||
|
||||
export function createBuildUpdateLastCardFromClipboardMainDepsHandler<TAnki>(deps: {
|
||||
getAnkiIntegration: () => TAnki;
|
||||
readClipboardText: () => string;
|
||||
showMpvOsd: (text: string) => void;
|
||||
updateLastCardFromClipboardCore: (options: {
|
||||
ankiIntegration: TAnki;
|
||||
readClipboardText: () => string;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) => Promise<void>;
|
||||
}) {
|
||||
return () => ({
|
||||
getAnkiIntegration: () => deps.getAnkiIntegration(),
|
||||
readClipboardText: () => deps.readClipboardText(),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
updateLastCardFromClipboardCore: (options: {
|
||||
ankiIntegration: TAnki;
|
||||
readClipboardText: () => string;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) => deps.updateLastCardFromClipboardCore(options),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildRefreshKnownWordCacheMainDepsHandler(
|
||||
deps: RefreshKnownWordCacheMainDeps,
|
||||
) {
|
||||
return (): RefreshKnownWordCacheMainDeps => ({
|
||||
getAnkiIntegration: () => deps.getAnkiIntegration(),
|
||||
missingIntegrationMessage: deps.missingIntegrationMessage,
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildTriggerFieldGroupingMainDepsHandler<TAnki>(deps: {
|
||||
getAnkiIntegration: () => TAnki;
|
||||
showMpvOsd: (text: string) => void;
|
||||
triggerFieldGroupingCore: (options: {
|
||||
ankiIntegration: TAnki;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) => Promise<void>;
|
||||
}) {
|
||||
return () => ({
|
||||
getAnkiIntegration: () => deps.getAnkiIntegration(),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
triggerFieldGroupingCore: (options: {
|
||||
ankiIntegration: TAnki;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) => deps.triggerFieldGroupingCore(options),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildMarkLastCardAsAudioCardMainDepsHandler<TAnki>(deps: {
|
||||
getAnkiIntegration: () => TAnki;
|
||||
showMpvOsd: (text: string) => void;
|
||||
markLastCardAsAudioCardCore: (options: {
|
||||
ankiIntegration: TAnki;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) => Promise<void>;
|
||||
}) {
|
||||
return () => ({
|
||||
getAnkiIntegration: () => deps.getAnkiIntegration(),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
markLastCardAsAudioCardCore: (options: {
|
||||
ankiIntegration: TAnki;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) => deps.markLastCardAsAudioCardCore(options),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildMineSentenceCardMainDepsHandler<TAnki, TMpv>(deps: {
|
||||
getAnkiIntegration: () => TAnki;
|
||||
getMpvClient: () => TMpv;
|
||||
getPrimarySubtitle?: () => PrimarySubtitle | null;
|
||||
showMpvOsd: (text: string) => void;
|
||||
mineSentenceCardCore: (options: {
|
||||
ankiIntegration: TAnki;
|
||||
mpvClient: TMpv;
|
||||
primarySubtitle?: PrimarySubtitle;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) => Promise<boolean>;
|
||||
}) {
|
||||
return () => ({
|
||||
getAnkiIntegration: () => deps.getAnkiIntegration(),
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
...(deps.getPrimarySubtitle
|
||||
? { getPrimarySubtitle: () => deps.getPrimarySubtitle?.() ?? null }
|
||||
: {}),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
mineSentenceCardCore: (options: {
|
||||
ankiIntegration: TAnki;
|
||||
mpvClient: TMpv;
|
||||
primarySubtitle?: PrimarySubtitle;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) => deps.mineSentenceCardCore(options),
|
||||
});
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import type { AppReadyRuntimeDepsFactoryInput } from '../app-lifecycle';
|
||||
|
||||
export function createBuildAppReadyRuntimeMainDepsHandler(deps: AppReadyRuntimeDepsFactoryInput) {
|
||||
return (): AppReadyRuntimeDepsFactoryInput => ({
|
||||
ensureDefaultConfigBootstrap: deps.ensureDefaultConfigBootstrap,
|
||||
loadSubtitlePosition: deps.loadSubtitlePosition,
|
||||
resolveKeybindings: deps.resolveKeybindings,
|
||||
createMpvClient: deps.createMpvClient,
|
||||
reloadConfig: deps.reloadConfig,
|
||||
getResolvedConfig: deps.getResolvedConfig,
|
||||
getConfigWarnings: deps.getConfigWarnings,
|
||||
logConfigWarning: deps.logConfigWarning,
|
||||
initRuntimeOptionsManager: deps.initRuntimeOptionsManager,
|
||||
setSecondarySubMode: deps.setSecondarySubMode,
|
||||
defaultSecondarySubMode: deps.defaultSecondarySubMode,
|
||||
defaultWebsocketPort: deps.defaultWebsocketPort,
|
||||
defaultAnnotationWebsocketPort: deps.defaultAnnotationWebsocketPort,
|
||||
defaultTexthookerPort: deps.defaultTexthookerPort,
|
||||
hasMpvWebsocketPlugin: deps.hasMpvWebsocketPlugin,
|
||||
startSubtitleWebsocket: deps.startSubtitleWebsocket,
|
||||
startAnnotationWebsocket: deps.startAnnotationWebsocket,
|
||||
startTexthooker: deps.startTexthooker,
|
||||
log: deps.log,
|
||||
setLogLevel: deps.setLogLevel,
|
||||
setLogRotation: deps.setLogRotation,
|
||||
setLogFileToggles: deps.setLogFileToggles,
|
||||
createMecabTokenizerAndCheck: deps.createMecabTokenizerAndCheck,
|
||||
createSubtitleTimingTracker: deps.createSubtitleTimingTracker,
|
||||
createImmersionTracker: deps.createImmersionTracker,
|
||||
startJellyfinRemoteSession: deps.startJellyfinRemoteSession,
|
||||
loadYomitanExtension: deps.loadYomitanExtension,
|
||||
ensureYomitanExtensionLoaded: deps.ensureYomitanExtensionLoaded,
|
||||
handleFirstRunSetup: deps.handleFirstRunSetup,
|
||||
prewarmSubtitleDictionaries: deps.prewarmSubtitleDictionaries,
|
||||
startBackgroundWarmups: deps.startBackgroundWarmups,
|
||||
texthookerOnlyMode: deps.texthookerOnlyMode,
|
||||
shouldAutoInitializeOverlayRuntimeFromConfig: deps.shouldAutoInitializeOverlayRuntimeFromConfig,
|
||||
setVisibleOverlayVisible: deps.setVisibleOverlayVisible,
|
||||
initializeOverlayRuntime: deps.initializeOverlayRuntime,
|
||||
runHeadlessInitialCommand: deps.runHeadlessInitialCommand,
|
||||
handleInitialArgs: deps.handleInitialArgs,
|
||||
onCriticalConfigErrors: deps.onCriticalConfigErrors,
|
||||
logDebug: deps.logDebug,
|
||||
now: deps.now,
|
||||
shouldRunHeadlessInitialCommand: deps.shouldRunHeadlessInitialCommand,
|
||||
shouldUseMinimalStartup: deps.shouldUseMinimalStartup,
|
||||
shouldSkipHeavyStartup: deps.shouldSkipHeavyStartup,
|
||||
shouldHandleInitialArgsBeforeDeferredOverlayWarmup:
|
||||
deps.shouldHandleInitialArgsBeforeDeferredOverlayWarmup,
|
||||
});
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import type { CliArgs } from '../../cli/args';
|
||||
|
||||
export function createBuildHandleTexthookerOnlyModeTransitionMainDepsHandler(deps: {
|
||||
isTexthookerOnlyMode: () => boolean;
|
||||
setTexthookerOnlyMode: (enabled: boolean) => void;
|
||||
commandNeedsOverlayStartupPrereqs: (args: CliArgs) => boolean;
|
||||
ensureOverlayStartupPrereqs: () => void;
|
||||
startBackgroundWarmups: () => void;
|
||||
logInfo: (message: string) => void;
|
||||
}) {
|
||||
return () => ({
|
||||
isTexthookerOnlyMode: () => deps.isTexthookerOnlyMode(),
|
||||
setTexthookerOnlyMode: (enabled: boolean) => deps.setTexthookerOnlyMode(enabled),
|
||||
commandNeedsOverlayStartupPrereqs: (args: CliArgs) =>
|
||||
deps.commandNeedsOverlayStartupPrereqs(args),
|
||||
ensureOverlayStartupPrereqs: () => deps.ensureOverlayStartupPrereqs(),
|
||||
startBackgroundWarmups: () => deps.startBackgroundWarmups(),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
});
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { CliArgs, CliCommandSource } from '../../cli/args';
|
||||
import { createHandleTexthookerOnlyModeTransitionHandler } from './cli-command-prechecks';
|
||||
import { createBuildHandleTexthookerOnlyModeTransitionMainDepsHandler } from './cli-command-prechecks-main-deps';
|
||||
|
||||
type HandleTexthookerOnlyModeTransitionMainDeps = Parameters<
|
||||
typeof createBuildHandleTexthookerOnlyModeTransitionMainDepsHandler
|
||||
typeof createHandleTexthookerOnlyModeTransitionHandler
|
||||
>[0];
|
||||
|
||||
export function createCliCommandRuntimeHandler<TCliContext>(deps: {
|
||||
@@ -17,9 +16,7 @@ export function createCliCommandRuntimeHandler<TCliContext>(deps: {
|
||||
) => void;
|
||||
}) {
|
||||
const handleTexthookerOnlyModeTransitionHandler = createHandleTexthookerOnlyModeTransitionHandler(
|
||||
createBuildHandleTexthookerOnlyModeTransitionMainDepsHandler(
|
||||
deps.handleTexthookerOnlyModeTransitionMainDeps,
|
||||
)(),
|
||||
deps.handleTexthookerOnlyModeTransitionMainDeps,
|
||||
);
|
||||
|
||||
return (args: CliArgs, source: CliCommandSource = 'initial'): void => {
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
createBuildConsumeAnilistSetupTokenFromUrlMainDepsHandler,
|
||||
createBuildHandleAnilistSetupProtocolUrlMainDepsHandler,
|
||||
createBuildNotifyAnilistSetupMainDepsHandler,
|
||||
createBuildRegisterSubminerProtocolClientMainDepsHandler,
|
||||
createConsumeAnilistSetupTokenFromUrlHandler,
|
||||
createHandleAnilistSetupProtocolUrlHandler,
|
||||
createNotifyAnilistSetupHandler,
|
||||
@@ -16,12 +12,10 @@ type HandleProtocolHandler = ReturnType<typeof createHandleAnilistSetupProtocolU
|
||||
type RegisterClientHandler = ReturnType<typeof createRegisterSubminerProtocolClientHandler>;
|
||||
|
||||
export type AnilistSetupComposerOptions = ComposerInputs<{
|
||||
notifyDeps: Parameters<typeof createBuildNotifyAnilistSetupMainDepsHandler>[0];
|
||||
consumeTokenDeps: Parameters<typeof createBuildConsumeAnilistSetupTokenFromUrlMainDepsHandler>[0];
|
||||
handleProtocolDeps: Parameters<typeof createBuildHandleAnilistSetupProtocolUrlMainDepsHandler>[0];
|
||||
registerProtocolClientDeps: Parameters<
|
||||
typeof createBuildRegisterSubminerProtocolClientMainDepsHandler
|
||||
>[0];
|
||||
notifyDeps: Parameters<typeof createNotifyAnilistSetupHandler>[0];
|
||||
consumeTokenDeps: Parameters<typeof createConsumeAnilistSetupTokenFromUrlHandler>[0];
|
||||
handleProtocolDeps: Parameters<typeof createHandleAnilistSetupProtocolUrlHandler>[0];
|
||||
registerProtocolClientDeps: Parameters<typeof createRegisterSubminerProtocolClientHandler>[0];
|
||||
}>;
|
||||
|
||||
export type AnilistSetupComposerResult = ComposerOutputs<{
|
||||
@@ -34,17 +28,15 @@ export type AnilistSetupComposerResult = ComposerOutputs<{
|
||||
export function composeAnilistSetupHandlers(
|
||||
options: AnilistSetupComposerOptions,
|
||||
): AnilistSetupComposerResult {
|
||||
const notifyAnilistSetup = createNotifyAnilistSetupHandler(
|
||||
createBuildNotifyAnilistSetupMainDepsHandler(options.notifyDeps)(),
|
||||
);
|
||||
const notifyAnilistSetup = createNotifyAnilistSetupHandler(options.notifyDeps);
|
||||
const consumeAnilistSetupTokenFromUrl = createConsumeAnilistSetupTokenFromUrlHandler(
|
||||
createBuildConsumeAnilistSetupTokenFromUrlMainDepsHandler(options.consumeTokenDeps)(),
|
||||
options.consumeTokenDeps,
|
||||
);
|
||||
const handleAnilistSetupProtocolUrl = createHandleAnilistSetupProtocolUrlHandler(
|
||||
createBuildHandleAnilistSetupProtocolUrlMainDepsHandler(options.handleProtocolDeps)(),
|
||||
options.handleProtocolDeps,
|
||||
);
|
||||
const registerSubminerProtocolClient = createRegisterSubminerProtocolClientHandler(
|
||||
createBuildRegisterSubminerProtocolClientMainDepsHandler(options.registerProtocolClientDeps)(),
|
||||
options.registerProtocolClientDeps,
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,15 +1,4 @@
|
||||
import {
|
||||
createBuildEnsureAnilistMediaGuessMainDepsHandler,
|
||||
createBuildGetAnilistMediaGuessRuntimeStateMainDepsHandler,
|
||||
createBuildGetCurrentAnilistMediaKeyMainDepsHandler,
|
||||
createBuildMaybeProbeAnilistDurationMainDepsHandler,
|
||||
createBuildMaybeRunAnilistPostWatchUpdateMainDepsHandler,
|
||||
createBuildProcessNextAnilistRetryUpdateMainDepsHandler,
|
||||
createBuildRecordAnilistMediaDurationMainDepsHandler,
|
||||
createBuildRefreshAnilistClientSecretStateMainDepsHandler,
|
||||
createBuildResetAnilistMediaGuessStateMainDepsHandler,
|
||||
createBuildResetAnilistMediaTrackingMainDepsHandler,
|
||||
createBuildSetAnilistMediaGuessRuntimeStateMainDepsHandler,
|
||||
createEnsureAnilistMediaGuessHandler,
|
||||
createGetAnilistMediaGuessRuntimeStateHandler,
|
||||
createGetCurrentAnilistMediaKeyHandler,
|
||||
@@ -25,36 +14,22 @@ import {
|
||||
import type { ComposerInputs, ComposerOutputs } from './contracts';
|
||||
|
||||
export type AnilistTrackingComposerOptions = ComposerInputs<{
|
||||
refreshClientSecretMainDeps: Parameters<
|
||||
typeof createBuildRefreshAnilistClientSecretStateMainDepsHandler
|
||||
>[0];
|
||||
getCurrentMediaKeyMainDeps: Parameters<
|
||||
typeof createBuildGetCurrentAnilistMediaKeyMainDepsHandler
|
||||
>[0];
|
||||
resetMediaTrackingMainDeps: Parameters<
|
||||
typeof createBuildResetAnilistMediaTrackingMainDepsHandler
|
||||
>[0];
|
||||
refreshClientSecretMainDeps: Parameters<typeof createRefreshAnilistClientSecretStateHandler>[0];
|
||||
getCurrentMediaKeyMainDeps: Parameters<typeof createGetCurrentAnilistMediaKeyHandler>[0];
|
||||
resetMediaTrackingMainDeps: Parameters<typeof createResetAnilistMediaTrackingHandler>[0];
|
||||
getMediaGuessRuntimeStateMainDeps: Parameters<
|
||||
typeof createBuildGetAnilistMediaGuessRuntimeStateMainDepsHandler
|
||||
typeof createGetAnilistMediaGuessRuntimeStateHandler
|
||||
>[0];
|
||||
setMediaGuessRuntimeStateMainDeps: Parameters<
|
||||
typeof createBuildSetAnilistMediaGuessRuntimeStateMainDepsHandler
|
||||
>[0];
|
||||
recordMediaDurationMainDeps: Parameters<
|
||||
typeof createBuildRecordAnilistMediaDurationMainDepsHandler
|
||||
>[0];
|
||||
resetMediaGuessStateMainDeps: Parameters<
|
||||
typeof createBuildResetAnilistMediaGuessStateMainDepsHandler
|
||||
>[0];
|
||||
maybeProbeDurationMainDeps: Parameters<
|
||||
typeof createBuildMaybeProbeAnilistDurationMainDepsHandler
|
||||
>[0];
|
||||
ensureMediaGuessMainDeps: Parameters<typeof createBuildEnsureAnilistMediaGuessMainDepsHandler>[0];
|
||||
processNextRetryUpdateMainDeps: Parameters<
|
||||
typeof createBuildProcessNextAnilistRetryUpdateMainDepsHandler
|
||||
typeof createSetAnilistMediaGuessRuntimeStateHandler
|
||||
>[0];
|
||||
recordMediaDurationMainDeps: Parameters<typeof createRecordAnilistMediaDurationHandler>[0];
|
||||
resetMediaGuessStateMainDeps: Parameters<typeof createResetAnilistMediaGuessStateHandler>[0];
|
||||
maybeProbeDurationMainDeps: Parameters<typeof createMaybeProbeAnilistDurationHandler>[0];
|
||||
ensureMediaGuessMainDeps: Parameters<typeof createEnsureAnilistMediaGuessHandler>[0];
|
||||
processNextRetryUpdateMainDeps: Parameters<typeof createProcessNextAnilistRetryUpdateHandler>[0];
|
||||
maybeRunPostWatchUpdateMainDeps: Parameters<
|
||||
typeof createBuildMaybeRunAnilistPostWatchUpdateMainDepsHandler
|
||||
typeof createMaybeRunAnilistPostWatchUpdateHandler
|
||||
>[0];
|
||||
}>;
|
||||
|
||||
@@ -80,47 +55,37 @@ export function composeAnilistTrackingHandlers(
|
||||
options: AnilistTrackingComposerOptions,
|
||||
): AnilistTrackingComposerResult {
|
||||
const refreshAnilistClientSecretState = createRefreshAnilistClientSecretStateHandler(
|
||||
createBuildRefreshAnilistClientSecretStateMainDepsHandler(
|
||||
options.refreshClientSecretMainDeps,
|
||||
)(),
|
||||
options.refreshClientSecretMainDeps,
|
||||
);
|
||||
const getCurrentAnilistMediaKey = createGetCurrentAnilistMediaKeyHandler(
|
||||
createBuildGetCurrentAnilistMediaKeyMainDepsHandler(options.getCurrentMediaKeyMainDeps)(),
|
||||
options.getCurrentMediaKeyMainDeps,
|
||||
);
|
||||
const resetAnilistMediaTracking = createResetAnilistMediaTrackingHandler(
|
||||
createBuildResetAnilistMediaTrackingMainDepsHandler(options.resetMediaTrackingMainDeps)(),
|
||||
options.resetMediaTrackingMainDeps,
|
||||
);
|
||||
const getAnilistMediaGuessRuntimeState = createGetAnilistMediaGuessRuntimeStateHandler(
|
||||
createBuildGetAnilistMediaGuessRuntimeStateMainDepsHandler(
|
||||
options.getMediaGuessRuntimeStateMainDeps,
|
||||
)(),
|
||||
options.getMediaGuessRuntimeStateMainDeps,
|
||||
);
|
||||
const setAnilistMediaGuessRuntimeState = createSetAnilistMediaGuessRuntimeStateHandler(
|
||||
createBuildSetAnilistMediaGuessRuntimeStateMainDepsHandler(
|
||||
options.setMediaGuessRuntimeStateMainDeps,
|
||||
)(),
|
||||
options.setMediaGuessRuntimeStateMainDeps,
|
||||
);
|
||||
const recordAnilistMediaDuration = createRecordAnilistMediaDurationHandler(
|
||||
createBuildRecordAnilistMediaDurationMainDepsHandler(options.recordMediaDurationMainDeps)(),
|
||||
options.recordMediaDurationMainDeps,
|
||||
);
|
||||
const resetAnilistMediaGuessState = createResetAnilistMediaGuessStateHandler(
|
||||
createBuildResetAnilistMediaGuessStateMainDepsHandler(options.resetMediaGuessStateMainDeps)(),
|
||||
options.resetMediaGuessStateMainDeps,
|
||||
);
|
||||
const maybeProbeAnilistDuration = createMaybeProbeAnilistDurationHandler(
|
||||
createBuildMaybeProbeAnilistDurationMainDepsHandler(options.maybeProbeDurationMainDeps)(),
|
||||
options.maybeProbeDurationMainDeps,
|
||||
);
|
||||
const ensureAnilistMediaGuess = createEnsureAnilistMediaGuessHandler(
|
||||
createBuildEnsureAnilistMediaGuessMainDepsHandler(options.ensureMediaGuessMainDeps)(),
|
||||
options.ensureMediaGuessMainDeps,
|
||||
);
|
||||
const processNextAnilistRetryUpdate = createProcessNextAnilistRetryUpdateHandler(
|
||||
createBuildProcessNextAnilistRetryUpdateMainDepsHandler(
|
||||
options.processNextRetryUpdateMainDeps,
|
||||
)(),
|
||||
options.processNextRetryUpdateMainDeps,
|
||||
);
|
||||
const maybeRunAnilistPostWatchUpdate = createMaybeRunAnilistPostWatchUpdateHandler(
|
||||
createBuildMaybeRunAnilistPostWatchUpdateMainDepsHandler(
|
||||
options.maybeRunPostWatchUpdateMainDeps,
|
||||
)(),
|
||||
options.maybeRunPostWatchUpdateMainDeps,
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
import { createAppReadyRuntimeRunner } from '../../app-lifecycle';
|
||||
import { createBuildAppReadyRuntimeMainDepsHandler } from '../app-ready-main-deps';
|
||||
import {
|
||||
createBuildCriticalConfigErrorMainDepsHandler,
|
||||
createBuildReloadConfigMainDepsHandler,
|
||||
} from '../startup-config-main-deps';
|
||||
createAppReadyRuntimeRunner,
|
||||
type AppReadyRuntimeDepsFactoryInput,
|
||||
} from '../../app-lifecycle';
|
||||
import { createCriticalConfigErrorHandler, createReloadConfigHandler } from '../startup-config';
|
||||
import { createBuildImmersionTrackerStartupMainDepsHandler } from '../immersion-startup-main-deps';
|
||||
import { createImmersionTrackerStartupHandler } from '../immersion-startup';
|
||||
import type { ComposerInputs, ComposerOutputs } from './contracts';
|
||||
|
||||
type ReloadConfigMainDeps = Parameters<typeof createBuildReloadConfigMainDepsHandler>[0];
|
||||
type CriticalConfigErrorMainDeps = Parameters<
|
||||
typeof createBuildCriticalConfigErrorMainDepsHandler
|
||||
>[0];
|
||||
type AppReadyRuntimeMainDeps = Parameters<typeof createBuildAppReadyRuntimeMainDepsHandler>[0];
|
||||
type ReloadConfigMainDeps = Parameters<typeof createReloadConfigHandler>[0];
|
||||
type CriticalConfigErrorMainDeps = Parameters<typeof createCriticalConfigErrorHandler>[0];
|
||||
|
||||
export type AppReadyComposerOptions = ComposerInputs<{
|
||||
reloadConfigMainDeps: ReloadConfigMainDeps;
|
||||
criticalConfigErrorMainDeps: CriticalConfigErrorMainDeps;
|
||||
appReadyRuntimeMainDeps: Omit<AppReadyRuntimeMainDeps, 'reloadConfig' | 'onCriticalConfigErrors'>;
|
||||
immersionTrackerStartupMainDeps: Parameters<
|
||||
typeof createBuildImmersionTrackerStartupMainDepsHandler
|
||||
>[0];
|
||||
appReadyRuntimeMainDeps: Omit<
|
||||
AppReadyRuntimeDepsFactoryInput,
|
||||
'reloadConfig' | 'onCriticalConfigErrors'
|
||||
>;
|
||||
immersionTrackerStartupMainDeps: Parameters<typeof createImmersionTrackerStartupHandler>[0];
|
||||
}>;
|
||||
|
||||
export type AppReadyComposerResult = ComposerOutputs<{
|
||||
@@ -31,27 +26,17 @@ export type AppReadyComposerResult = ComposerOutputs<{
|
||||
}>;
|
||||
|
||||
export function composeAppReadyRuntime(options: AppReadyComposerOptions): AppReadyComposerResult {
|
||||
const reloadConfig = createReloadConfigHandler(
|
||||
createBuildReloadConfigMainDepsHandler(options.reloadConfigMainDeps)(),
|
||||
);
|
||||
const criticalConfigError = createCriticalConfigErrorHandler(
|
||||
createBuildCriticalConfigErrorMainDepsHandler(options.criticalConfigErrorMainDeps)(),
|
||||
);
|
||||
const reloadConfig = createReloadConfigHandler(options.reloadConfigMainDeps);
|
||||
const criticalConfigError = createCriticalConfigErrorHandler(options.criticalConfigErrorMainDeps);
|
||||
|
||||
const appReadyRuntimeRunner = createAppReadyRuntimeRunner(
|
||||
createBuildAppReadyRuntimeMainDepsHandler({
|
||||
...options.appReadyRuntimeMainDeps,
|
||||
reloadConfig,
|
||||
createImmersionTracker:
|
||||
options.appReadyRuntimeMainDeps.createImmersionTracker ??
|
||||
createImmersionTrackerStartupHandler(
|
||||
createBuildImmersionTrackerStartupMainDepsHandler(
|
||||
options.immersionTrackerStartupMainDeps,
|
||||
)(),
|
||||
),
|
||||
onCriticalConfigErrors: criticalConfigError,
|
||||
})(),
|
||||
);
|
||||
const appReadyRuntimeRunner = createAppReadyRuntimeRunner({
|
||||
...options.appReadyRuntimeMainDeps,
|
||||
reloadConfig,
|
||||
createImmersionTracker:
|
||||
options.appReadyRuntimeMainDeps.createImmersionTracker ??
|
||||
createImmersionTrackerStartupHandler(options.immersionTrackerStartupMainDeps),
|
||||
onCriticalConfigErrors: criticalConfigError,
|
||||
});
|
||||
|
||||
return {
|
||||
reloadConfig,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import type { RegisterIpcRuntimeServicesParams } from '../../ipc-runtime';
|
||||
import type { MpvCommandFromIpcRuntimeDeps } from '../../ipc-mpv-command';
|
||||
import type { SubsyncManualRunRequest, SubsyncResult } from '../../../types';
|
||||
import {
|
||||
createBuildMpvCommandFromIpcRuntimeMainDepsHandler,
|
||||
createIpcRuntimeHandlers,
|
||||
} from '../domains/ipc';
|
||||
import { createIpcRuntimeHandlers } from '../domains/ipc';
|
||||
import type { ComposerInputs, ComposerOutputs } from './contracts';
|
||||
|
||||
type MpvCommand = (string | number)[];
|
||||
@@ -17,7 +15,7 @@ type IpcRuntimeDeps = Parameters<
|
||||
>[0];
|
||||
|
||||
export type IpcRuntimeComposerOptions = ComposerInputs<{
|
||||
mpvCommandMainDeps: Parameters<typeof createBuildMpvCommandFromIpcRuntimeMainDepsHandler>[0];
|
||||
mpvCommandMainDeps: MpvCommandFromIpcRuntimeDeps;
|
||||
handleMpvCommandFromIpcRuntime: IpcRuntimeDeps['handleMpvCommandFromIpcDeps']['handleMpvCommandFromIpcRuntime'];
|
||||
runSubsyncManualFromIpc: RunSubsyncManual;
|
||||
registration: {
|
||||
@@ -37,16 +35,13 @@ export type IpcRuntimeComposerResult = ComposerOutputs<{
|
||||
export function composeIpcRuntimeHandlers(
|
||||
options: IpcRuntimeComposerOptions,
|
||||
): IpcRuntimeComposerResult {
|
||||
const mpvCommandFromIpcRuntimeMainDeps = createBuildMpvCommandFromIpcRuntimeMainDepsHandler(
|
||||
options.mpvCommandMainDeps,
|
||||
)();
|
||||
const { handleMpvCommandFromIpc, runSubsyncManualFromIpc } = createIpcRuntimeHandlers<
|
||||
SubsyncManualRunRequest,
|
||||
SubsyncResult
|
||||
>({
|
||||
handleMpvCommandFromIpcDeps: {
|
||||
handleMpvCommandFromIpcRuntime: options.handleMpvCommandFromIpcRuntime,
|
||||
buildMpvCommandDeps: () => mpvCommandFromIpcRuntimeMainDeps,
|
||||
buildMpvCommandDeps: () => options.mpvCommandMainDeps,
|
||||
},
|
||||
runSubsyncManualFromIpcDeps: {
|
||||
runManualFromIpc: (request) => options.runSubsyncManualFromIpc(request),
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
import {
|
||||
buildJellyfinSetupFormHtml,
|
||||
createEnsureMpvConnectedForJellyfinPlaybackHandler,
|
||||
createBuildEnsureMpvConnectedForJellyfinPlaybackMainDepsHandler,
|
||||
createBuildGetJellyfinClientInfoMainDepsHandler,
|
||||
createBuildGetResolvedJellyfinConfigMainDepsHandler,
|
||||
createBuildHandleJellyfinAuthCommandsMainDepsHandler,
|
||||
createBuildHandleJellyfinListCommandsMainDepsHandler,
|
||||
createBuildHandleJellyfinPlayCommandMainDepsHandler,
|
||||
createBuildHandleJellyfinRemoteAnnounceCommandMainDepsHandler,
|
||||
createBuildLaunchMpvIdleForJellyfinPlaybackMainDepsHandler,
|
||||
createBuildOpenJellyfinSetupWindowMainDepsHandler,
|
||||
createBuildPlayJellyfinItemInMpvMainDepsHandler,
|
||||
createBuildPreloadJellyfinExternalSubtitlesMainDepsHandler,
|
||||
createBuildRunJellyfinCommandMainDepsHandler,
|
||||
createBuildStartJellyfinRemoteSessionMainDepsHandler,
|
||||
createBuildStopJellyfinRemoteSessionMainDepsHandler,
|
||||
createBuildWaitForMpvConnectedMainDepsHandler,
|
||||
createGetJellyfinClientInfoHandler,
|
||||
createGetResolvedJellyfinConfigHandler,
|
||||
createHandleJellyfinAuthCommands,
|
||||
@@ -40,23 +28,13 @@ import {
|
||||
import type { ComposerInputs, ComposerOutputs } from './contracts';
|
||||
|
||||
type EnsureMpvConnectedMainDeps = Parameters<
|
||||
typeof createBuildEnsureMpvConnectedForJellyfinPlaybackMainDepsHandler
|
||||
>[0];
|
||||
type PlayJellyfinItemMainDeps = Parameters<
|
||||
typeof createBuildPlayJellyfinItemInMpvMainDepsHandler
|
||||
>[0];
|
||||
type HandlePlayCommandMainDeps = Parameters<
|
||||
typeof createBuildHandleJellyfinPlayCommandMainDepsHandler
|
||||
>[0];
|
||||
type HandleRemoteAnnounceMainDeps = Parameters<
|
||||
typeof createBuildHandleJellyfinRemoteAnnounceCommandMainDepsHandler
|
||||
>[0];
|
||||
type StartRemoteSessionMainDeps = Parameters<
|
||||
typeof createBuildStartJellyfinRemoteSessionMainDepsHandler
|
||||
>[0];
|
||||
type RunJellyfinCommandMainDeps = Parameters<
|
||||
typeof createBuildRunJellyfinCommandMainDepsHandler
|
||||
typeof createEnsureMpvConnectedForJellyfinPlaybackHandler
|
||||
>[0];
|
||||
type PlayJellyfinItemMainDeps = Parameters<typeof createPlayJellyfinItemInMpvHandler>[0];
|
||||
type HandlePlayCommandMainDeps = Parameters<typeof createHandleJellyfinPlayCommand>[0];
|
||||
type HandleRemoteAnnounceMainDeps = Parameters<typeof createHandleJellyfinRemoteAnnounceCommand>[0];
|
||||
type StartRemoteSessionMainDeps = Parameters<typeof createStartJellyfinRemoteSessionHandler>[0];
|
||||
type RunJellyfinCommandMainDeps = Parameters<typeof createRunJellyfinCommandHandler>[0];
|
||||
type OpenJellyfinSetupWindowMainDeps = Parameters<
|
||||
typeof createBuildOpenJellyfinSetupWindowMainDepsHandler
|
||||
>[0];
|
||||
@@ -68,16 +46,16 @@ export type JellyfinRuntimeComposerOptions = ComposerInputs<{
|
||||
getJellyfinClientInfoMainDeps: Parameters<
|
||||
typeof createBuildGetJellyfinClientInfoMainDepsHandler
|
||||
>[0];
|
||||
waitForMpvConnectedMainDeps: Parameters<typeof createBuildWaitForMpvConnectedMainDepsHandler>[0];
|
||||
waitForMpvConnectedMainDeps: Parameters<typeof createWaitForMpvConnectedHandler>[0];
|
||||
launchMpvIdleForJellyfinPlaybackMainDeps: Parameters<
|
||||
typeof createBuildLaunchMpvIdleForJellyfinPlaybackMainDepsHandler
|
||||
typeof createLaunchMpvIdleForJellyfinPlaybackHandler
|
||||
>[0];
|
||||
ensureMpvConnectedForJellyfinPlaybackMainDeps: Omit<
|
||||
EnsureMpvConnectedMainDeps,
|
||||
'waitForMpvConnected' | 'launchMpvIdleForJellyfinPlayback'
|
||||
>;
|
||||
preloadJellyfinExternalSubtitlesMainDeps: Parameters<
|
||||
typeof createBuildPreloadJellyfinExternalSubtitlesMainDepsHandler
|
||||
typeof createPreloadJellyfinExternalSubtitlesHandler
|
||||
>[0];
|
||||
playJellyfinItemInMpvMainDeps: Omit<
|
||||
PlayJellyfinItemMainDeps,
|
||||
@@ -87,12 +65,8 @@ export type JellyfinRuntimeComposerOptions = ComposerInputs<{
|
||||
JellyfinRemoteComposerOptions,
|
||||
'getClientInfo' | 'getJellyfinConfig' | 'playJellyfinItem'
|
||||
>;
|
||||
handleJellyfinAuthCommandsMainDeps: Parameters<
|
||||
typeof createBuildHandleJellyfinAuthCommandsMainDepsHandler
|
||||
>[0];
|
||||
handleJellyfinListCommandsMainDeps: Parameters<
|
||||
typeof createBuildHandleJellyfinListCommandsMainDepsHandler
|
||||
>[0];
|
||||
handleJellyfinAuthCommandsMainDeps: Parameters<typeof createHandleJellyfinAuthCommands>[0];
|
||||
handleJellyfinListCommandsMainDeps: Parameters<typeof createHandleJellyfinListCommands>[0];
|
||||
handleJellyfinPlayCommandMainDeps: Omit<HandlePlayCommandMainDeps, 'playJellyfinItemInMpv'>;
|
||||
handleJellyfinRemoteAnnounceCommandMainDeps: Omit<
|
||||
HandleRemoteAnnounceMainDeps,
|
||||
@@ -106,9 +80,7 @@ export type JellyfinRuntimeComposerOptions = ComposerInputs<{
|
||||
| 'handlePlaystate'
|
||||
| 'handleGeneralCommand'
|
||||
>;
|
||||
stopJellyfinRemoteSessionMainDeps: Parameters<
|
||||
typeof createBuildStopJellyfinRemoteSessionMainDepsHandler
|
||||
>[0];
|
||||
stopJellyfinRemoteSessionMainDeps: Parameters<typeof createStopJellyfinRemoteSessionHandler>[0];
|
||||
runJellyfinCommandMainDeps: Omit<
|
||||
RunJellyfinCommandMainDeps,
|
||||
| 'getJellyfinConfig'
|
||||
@@ -177,36 +149,26 @@ export function composeJellyfinRuntimeHandlers(
|
||||
createBuildGetJellyfinClientInfoMainDepsHandler(options.getJellyfinClientInfoMainDeps)(),
|
||||
);
|
||||
|
||||
const waitForMpvConnected = createWaitForMpvConnectedHandler(
|
||||
createBuildWaitForMpvConnectedMainDepsHandler(options.waitForMpvConnectedMainDeps)(),
|
||||
);
|
||||
const waitForMpvConnected = createWaitForMpvConnectedHandler(options.waitForMpvConnectedMainDeps);
|
||||
const launchMpvIdleForJellyfinPlayback = createLaunchMpvIdleForJellyfinPlaybackHandler(
|
||||
createBuildLaunchMpvIdleForJellyfinPlaybackMainDepsHandler(
|
||||
options.launchMpvIdleForJellyfinPlaybackMainDeps,
|
||||
)(),
|
||||
);
|
||||
const ensureMpvConnectedForJellyfinPlayback = createEnsureMpvConnectedForJellyfinPlaybackHandler(
|
||||
createBuildEnsureMpvConnectedForJellyfinPlaybackMainDepsHandler({
|
||||
...options.ensureMpvConnectedForJellyfinPlaybackMainDeps,
|
||||
waitForMpvConnected: (timeoutMs) => waitForMpvConnected(timeoutMs),
|
||||
launchMpvIdleForJellyfinPlayback: () => launchMpvIdleForJellyfinPlayback(),
|
||||
})(),
|
||||
options.launchMpvIdleForJellyfinPlaybackMainDeps,
|
||||
);
|
||||
const ensureMpvConnectedForJellyfinPlayback = createEnsureMpvConnectedForJellyfinPlaybackHandler({
|
||||
...options.ensureMpvConnectedForJellyfinPlaybackMainDeps,
|
||||
waitForMpvConnected: (timeoutMs) => waitForMpvConnected(timeoutMs),
|
||||
launchMpvIdleForJellyfinPlayback: () => launchMpvIdleForJellyfinPlayback(),
|
||||
});
|
||||
|
||||
const preloadJellyfinExternalSubtitles = createPreloadJellyfinExternalSubtitlesHandler(
|
||||
createBuildPreloadJellyfinExternalSubtitlesMainDepsHandler(
|
||||
options.preloadJellyfinExternalSubtitlesMainDeps,
|
||||
)(),
|
||||
);
|
||||
const playJellyfinItemInMpv = createPlayJellyfinItemInMpvHandler(
|
||||
createBuildPlayJellyfinItemInMpvMainDepsHandler({
|
||||
...options.playJellyfinItemInMpvMainDeps,
|
||||
ensureMpvConnectedForPlayback: () => ensureMpvConnectedForJellyfinPlayback(),
|
||||
preloadExternalSubtitles: (params) => {
|
||||
void preloadJellyfinExternalSubtitles(params);
|
||||
},
|
||||
})(),
|
||||
options.preloadJellyfinExternalSubtitlesMainDeps,
|
||||
);
|
||||
const playJellyfinItemInMpv = createPlayJellyfinItemInMpvHandler({
|
||||
...options.playJellyfinItemInMpvMainDeps,
|
||||
ensureMpvConnectedForPlayback: () => ensureMpvConnectedForJellyfinPlayback(),
|
||||
preloadExternalSubtitles: (params) => {
|
||||
void preloadJellyfinExternalSubtitles(params);
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
reportJellyfinRemoteProgress,
|
||||
@@ -223,59 +185,45 @@ export function composeJellyfinRuntimeHandlers(
|
||||
});
|
||||
|
||||
const handleJellyfinAuthCommands = createHandleJellyfinAuthCommands(
|
||||
createBuildHandleJellyfinAuthCommandsMainDepsHandler(
|
||||
options.handleJellyfinAuthCommandsMainDeps,
|
||||
)(),
|
||||
options.handleJellyfinAuthCommandsMainDeps,
|
||||
);
|
||||
const handleJellyfinListCommands = createHandleJellyfinListCommands(
|
||||
createBuildHandleJellyfinListCommandsMainDepsHandler(
|
||||
options.handleJellyfinListCommandsMainDeps,
|
||||
)(),
|
||||
);
|
||||
const handleJellyfinPlayCommand = createHandleJellyfinPlayCommand(
|
||||
createBuildHandleJellyfinPlayCommandMainDepsHandler({
|
||||
...options.handleJellyfinPlayCommandMainDeps,
|
||||
playJellyfinItemInMpv: (params) =>
|
||||
playJellyfinItemInMpv(params as Parameters<typeof playJellyfinItemInMpv>[0]),
|
||||
})(),
|
||||
options.handleJellyfinListCommandsMainDeps,
|
||||
);
|
||||
const handleJellyfinPlayCommand = createHandleJellyfinPlayCommand({
|
||||
...options.handleJellyfinPlayCommandMainDeps,
|
||||
playJellyfinItemInMpv: (params) =>
|
||||
playJellyfinItemInMpv(params as Parameters<typeof playJellyfinItemInMpv>[0]),
|
||||
});
|
||||
|
||||
let startJellyfinRemoteSession!: ReturnType<typeof createStartJellyfinRemoteSessionHandler>;
|
||||
const handleJellyfinRemoteAnnounceCommand = createHandleJellyfinRemoteAnnounceCommand(
|
||||
createBuildHandleJellyfinRemoteAnnounceCommandMainDepsHandler({
|
||||
...options.handleJellyfinRemoteAnnounceCommandMainDeps,
|
||||
startJellyfinRemoteSession: (startOptions) => startJellyfinRemoteSession(startOptions),
|
||||
})(),
|
||||
);
|
||||
const handleJellyfinRemoteAnnounceCommand = createHandleJellyfinRemoteAnnounceCommand({
|
||||
...options.handleJellyfinRemoteAnnounceCommandMainDeps,
|
||||
startJellyfinRemoteSession: (startOptions) => startJellyfinRemoteSession(startOptions),
|
||||
});
|
||||
|
||||
startJellyfinRemoteSession = createStartJellyfinRemoteSessionHandler(
|
||||
createBuildStartJellyfinRemoteSessionMainDepsHandler({
|
||||
...options.startJellyfinRemoteSessionMainDeps,
|
||||
getJellyfinConfig: () => getResolvedJellyfinConfig(),
|
||||
getClientInfo: () => getJellyfinClientInfo(),
|
||||
handlePlay: (payload) => handleJellyfinRemotePlay(payload),
|
||||
handlePlaystate: (payload) => handleJellyfinRemotePlaystate(payload),
|
||||
handleGeneralCommand: (payload) => handleJellyfinRemoteGeneralCommand(payload),
|
||||
})(),
|
||||
);
|
||||
startJellyfinRemoteSession = createStartJellyfinRemoteSessionHandler({
|
||||
...options.startJellyfinRemoteSessionMainDeps,
|
||||
getJellyfinConfig: () => getResolvedJellyfinConfig(),
|
||||
getClientInfo: () => getJellyfinClientInfo(),
|
||||
handlePlay: (payload) => handleJellyfinRemotePlay(payload),
|
||||
handlePlaystate: (payload) => handleJellyfinRemotePlaystate(payload),
|
||||
handleGeneralCommand: (payload) => handleJellyfinRemoteGeneralCommand(payload),
|
||||
});
|
||||
|
||||
const stopJellyfinRemoteSession = createStopJellyfinRemoteSessionHandler(
|
||||
createBuildStopJellyfinRemoteSessionMainDepsHandler(
|
||||
options.stopJellyfinRemoteSessionMainDeps,
|
||||
)(),
|
||||
options.stopJellyfinRemoteSessionMainDeps,
|
||||
);
|
||||
|
||||
const runJellyfinCommand = createRunJellyfinCommandHandler(
|
||||
createBuildRunJellyfinCommandMainDepsHandler({
|
||||
...options.runJellyfinCommandMainDeps,
|
||||
getJellyfinConfig: () => getResolvedJellyfinConfig(),
|
||||
getJellyfinClientInfo: (jellyfinConfig) => getJellyfinClientInfo(jellyfinConfig),
|
||||
handleAuthCommands: (params) => handleJellyfinAuthCommands(params),
|
||||
handleRemoteAnnounceCommand: (args) => handleJellyfinRemoteAnnounceCommand(args),
|
||||
handleListCommands: (params) => handleJellyfinListCommands(params),
|
||||
handlePlayCommand: (params) => handleJellyfinPlayCommand(params),
|
||||
})(),
|
||||
);
|
||||
const runJellyfinCommand = createRunJellyfinCommandHandler({
|
||||
...options.runJellyfinCommandMainDeps,
|
||||
getJellyfinConfig: () => getResolvedJellyfinConfig(),
|
||||
getJellyfinClientInfo: (jellyfinConfig) => getJellyfinClientInfo(jellyfinConfig),
|
||||
handleAuthCommands: (params) => handleJellyfinAuthCommands(params),
|
||||
handleRemoteAnnounceCommand: (args) => handleJellyfinRemoteAnnounceCommand(args),
|
||||
handleListCommands: (params) => handleJellyfinListCommands(params),
|
||||
handlePlayCommand: (params) => handleJellyfinPlayCommand(params),
|
||||
});
|
||||
|
||||
const maybeFocusExistingJellyfinSetupWindow = createMaybeFocusExistingJellyfinSetupWindowHandler(
|
||||
options.maybeFocusExistingJellyfinSetupWindowMainDeps,
|
||||
|
||||
@@ -4,17 +4,12 @@ import { createBuildMpvClientRuntimeServiceFactoryDepsHandler } from '../mpv-cli
|
||||
import { createMpvClientRuntimeServiceFactory } from '../mpv-client-runtime-service';
|
||||
import type { MpvClientRuntimeServiceOptions } from '../mpv-client-runtime-service';
|
||||
import type { Config } from '../../../types';
|
||||
import { createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler } from '../mpv-subtitle-render-metrics-main-deps';
|
||||
import { createUpdateMpvSubtitleRenderMetricsHandler } from '../mpv-subtitle-render-metrics';
|
||||
import {
|
||||
createBuildTokenizerDepsMainHandler,
|
||||
createCreateMecabTokenizerAndCheckMainHandler,
|
||||
createPrewarmSubtitleDictionariesMainHandler,
|
||||
} from '../subtitle-tokenization-main-deps';
|
||||
import {
|
||||
createBuildLaunchBackgroundWarmupTaskMainDepsHandler,
|
||||
createBuildStartBackgroundWarmupsMainDepsHandler,
|
||||
} from '../startup-warmups-main-deps';
|
||||
import {
|
||||
createLaunchBackgroundWarmupTaskHandler as createLaunchBackgroundWarmupTaskFromStartup,
|
||||
createStartBackgroundWarmupsHandler as createStartBackgroundWarmupsFromStartup,
|
||||
@@ -38,7 +33,7 @@ type MpvClientRuntimeServiceFactoryMainDeps<TMpvClient extends RuntimeMpvClient>
|
||||
'bindEventHandlers'
|
||||
>;
|
||||
type UpdateMpvSubtitleRenderMetricsMainDeps = Parameters<
|
||||
typeof createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler
|
||||
typeof createUpdateMpvSubtitleRenderMetricsHandler
|
||||
>[0];
|
||||
type BuildTokenizerDepsMainDeps = Parameters<typeof createBuildTokenizerDepsMainHandler>[0];
|
||||
type TokenizerMainDeps = BuiltMainDeps<typeof createBuildTokenizerDepsMainHandler>;
|
||||
@@ -49,10 +44,10 @@ type PrewarmSubtitleDictionariesMainDeps = Parameters<
|
||||
typeof createPrewarmSubtitleDictionariesMainHandler
|
||||
>[0];
|
||||
type LaunchBackgroundWarmupTaskMainDeps = Parameters<
|
||||
typeof createBuildLaunchBackgroundWarmupTaskMainDepsHandler
|
||||
typeof createLaunchBackgroundWarmupTaskFromStartup
|
||||
>[0];
|
||||
type StartBackgroundWarmupsMainDeps = Omit<
|
||||
Parameters<typeof createBuildStartBackgroundWarmupsMainDepsHandler>[0],
|
||||
Parameters<typeof createStartBackgroundWarmupsFromStartup>[0],
|
||||
'launchTask' | 'createMecabTokenizerAndCheck' | 'prewarmSubtitleDictionaries'
|
||||
>;
|
||||
|
||||
@@ -120,9 +115,7 @@ export function composeMpvRuntimeHandlers<
|
||||
createMpvClientRuntimeServiceFactory(buildMpvClientRuntimeServiceFactoryMainDepsHandler())();
|
||||
|
||||
const updateMpvSubtitleRenderMetrics = createUpdateMpvSubtitleRenderMetricsHandler(
|
||||
createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler(
|
||||
options.updateMpvSubtitleRenderMetricsMainDeps,
|
||||
)(),
|
||||
options.updateMpvSubtitleRenderMetricsMainDeps,
|
||||
);
|
||||
|
||||
const buildTokenizerDepsHandler = createBuildTokenizerDepsMainHandler(
|
||||
@@ -257,48 +250,44 @@ export function composeMpvRuntimeHandlers<
|
||||
};
|
||||
|
||||
const launchBackgroundWarmupTask = createLaunchBackgroundWarmupTaskFromStartup(
|
||||
createBuildLaunchBackgroundWarmupTaskMainDepsHandler(
|
||||
options.warmups.launchBackgroundWarmupTaskMainDeps,
|
||||
)(),
|
||||
);
|
||||
const startBackgroundWarmups = createStartBackgroundWarmupsFromStartup(
|
||||
createBuildStartBackgroundWarmupsMainDepsHandler({
|
||||
...options.warmups.startBackgroundWarmupsMainDeps,
|
||||
launchTask: (label, task) => launchBackgroundWarmupTask(label, task),
|
||||
createMecabTokenizerAndCheck: () => createMecabTokenizerAndCheck(),
|
||||
prewarmSubtitleDictionaries: () => prewarmSubtitleDictionaries(),
|
||||
onYomitanExtensionWarmupScheduled: (promise) => {
|
||||
if (tokenizationPrerequisiteWarmupCompleted) {
|
||||
return;
|
||||
}
|
||||
const finalizedPromise = promise
|
||||
.then(() => {
|
||||
markTokenizationPrerequisiteWarmupCompleted();
|
||||
})
|
||||
.finally(() => {
|
||||
if (tokenizationPrerequisiteWarmupInFlight === finalizedPromise) {
|
||||
tokenizationPrerequisiteWarmupInFlight = null;
|
||||
}
|
||||
});
|
||||
tokenizationPrerequisiteWarmupInFlight = finalizedPromise;
|
||||
},
|
||||
onTokenizationWarmupScheduled: (promise) => {
|
||||
if (tokenizationWarmupCompleted || !backgroundWarmupCoversOnDemandTokenization()) {
|
||||
return;
|
||||
}
|
||||
const finalizedPromise = promise
|
||||
.then(() => {
|
||||
markTokenizationWarmupCompleted();
|
||||
})
|
||||
.finally(() => {
|
||||
if (tokenizationWarmupInFlight === finalizedPromise) {
|
||||
tokenizationWarmupInFlight = null;
|
||||
}
|
||||
});
|
||||
tokenizationWarmupInFlight = finalizedPromise;
|
||||
},
|
||||
})(),
|
||||
options.warmups.launchBackgroundWarmupTaskMainDeps,
|
||||
);
|
||||
const startBackgroundWarmups = createStartBackgroundWarmupsFromStartup({
|
||||
...options.warmups.startBackgroundWarmupsMainDeps,
|
||||
launchTask: (label, task) => launchBackgroundWarmupTask(label, task),
|
||||
createMecabTokenizerAndCheck: () => createMecabTokenizerAndCheck(),
|
||||
prewarmSubtitleDictionaries: () => prewarmSubtitleDictionaries(),
|
||||
onYomitanExtensionWarmupScheduled: (promise) => {
|
||||
if (tokenizationPrerequisiteWarmupCompleted) {
|
||||
return;
|
||||
}
|
||||
const finalizedPromise = promise
|
||||
.then(() => {
|
||||
markTokenizationPrerequisiteWarmupCompleted();
|
||||
})
|
||||
.finally(() => {
|
||||
if (tokenizationPrerequisiteWarmupInFlight === finalizedPromise) {
|
||||
tokenizationPrerequisiteWarmupInFlight = null;
|
||||
}
|
||||
});
|
||||
tokenizationPrerequisiteWarmupInFlight = finalizedPromise;
|
||||
},
|
||||
onTokenizationWarmupScheduled: (promise) => {
|
||||
if (tokenizationWarmupCompleted || !backgroundWarmupCoversOnDemandTokenization()) {
|
||||
return;
|
||||
}
|
||||
const finalizedPromise = promise
|
||||
.then(() => {
|
||||
markTokenizationWarmupCompleted();
|
||||
})
|
||||
.finally(() => {
|
||||
if (tokenizationWarmupInFlight === finalizedPromise) {
|
||||
tokenizationWarmupInFlight = null;
|
||||
}
|
||||
});
|
||||
tokenizationWarmupInFlight = finalizedPromise;
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
bindMpvClientEventHandlers: (client) => bindMpvClientEventHandlers(client),
|
||||
|
||||
@@ -5,29 +5,22 @@ import {
|
||||
createSendToActiveOverlayWindowHandler,
|
||||
createSetOverlayDebugVisualizationEnabledHandler,
|
||||
} from '../overlay-runtime-main-actions';
|
||||
import {
|
||||
createBuildBroadcastRuntimeOptionsChangedMainDepsHandler,
|
||||
createBuildOpenRuntimeOptionsPaletteMainDepsHandler,
|
||||
createBuildRestorePreviousSecondarySubVisibilityMainDepsHandler,
|
||||
createBuildSendToActiveOverlayWindowMainDepsHandler,
|
||||
createBuildSetOverlayDebugVisualizationEnabledMainDepsHandler,
|
||||
} from '../overlay-runtime-main-actions-main-deps';
|
||||
import type { ComposerInputs, ComposerOutputs } from './contracts';
|
||||
|
||||
type RestorePreviousSecondarySubVisibilityMainDeps = Parameters<
|
||||
typeof createBuildRestorePreviousSecondarySubVisibilityMainDepsHandler
|
||||
typeof createRestorePreviousSecondarySubVisibilityHandler
|
||||
>[0];
|
||||
type BroadcastRuntimeOptionsChangedMainDeps = Parameters<
|
||||
typeof createBuildBroadcastRuntimeOptionsChangedMainDepsHandler
|
||||
typeof createBroadcastRuntimeOptionsChangedHandler
|
||||
>[0];
|
||||
type SendToActiveOverlayWindowMainDeps = Parameters<
|
||||
typeof createBuildSendToActiveOverlayWindowMainDepsHandler
|
||||
typeof createSendToActiveOverlayWindowHandler
|
||||
>[0];
|
||||
type SetOverlayDebugVisualizationEnabledMainDeps = Parameters<
|
||||
typeof createBuildSetOverlayDebugVisualizationEnabledMainDepsHandler
|
||||
typeof createSetOverlayDebugVisualizationEnabledHandler
|
||||
>[0];
|
||||
type OpenRuntimeOptionsPaletteMainDeps = Parameters<
|
||||
typeof createBuildOpenRuntimeOptionsPaletteMainDepsHandler
|
||||
typeof createOpenRuntimeOptionsPaletteHandler
|
||||
>[0];
|
||||
|
||||
export type OverlayVisibilityRuntimeComposerOptions = ComposerInputs<{
|
||||
@@ -61,29 +54,19 @@ export function composeOverlayVisibilityRuntime(
|
||||
updateVisibleOverlayVisibility: () =>
|
||||
options.overlayVisibilityRuntime.updateVisibleOverlayVisibility(),
|
||||
restorePreviousSecondarySubVisibility: createRestorePreviousSecondarySubVisibilityHandler(
|
||||
createBuildRestorePreviousSecondarySubVisibilityMainDepsHandler(
|
||||
options.restorePreviousSecondarySubVisibilityMainDeps,
|
||||
)(),
|
||||
options.restorePreviousSecondarySubVisibilityMainDeps,
|
||||
),
|
||||
broadcastRuntimeOptionsChanged: createBroadcastRuntimeOptionsChangedHandler(
|
||||
createBuildBroadcastRuntimeOptionsChangedMainDepsHandler(
|
||||
options.broadcastRuntimeOptionsChangedMainDeps,
|
||||
)(),
|
||||
options.broadcastRuntimeOptionsChangedMainDeps,
|
||||
),
|
||||
sendToActiveOverlayWindow: createSendToActiveOverlayWindowHandler(
|
||||
createBuildSendToActiveOverlayWindowMainDepsHandler(
|
||||
options.sendToActiveOverlayWindowMainDeps,
|
||||
)(),
|
||||
options.sendToActiveOverlayWindowMainDeps,
|
||||
),
|
||||
setOverlayDebugVisualizationEnabled: createSetOverlayDebugVisualizationEnabledHandler(
|
||||
createBuildSetOverlayDebugVisualizationEnabledMainDepsHandler(
|
||||
options.setOverlayDebugVisualizationEnabledMainDeps,
|
||||
)(),
|
||||
options.setOverlayDebugVisualizationEnabledMainDeps,
|
||||
),
|
||||
openRuntimeOptionsPalette: createOpenRuntimeOptionsPaletteHandler(
|
||||
createBuildOpenRuntimeOptionsPaletteMainDepsHandler(
|
||||
options.openRuntimeOptionsPaletteMainDeps,
|
||||
)(),
|
||||
options.openRuntimeOptionsPaletteMainDeps,
|
||||
),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
composeShortcutRuntimes,
|
||||
type ShortcutsRuntimeComposerOptions,
|
||||
} from './shortcuts-runtime-composer';
|
||||
|
||||
type GlobalShortcutsOptions = ShortcutsRuntimeComposerOptions['globalShortcuts'];
|
||||
|
||||
function createComposerOptions(tryBeginOverlaySelection: (timeoutMs: number) => boolean) {
|
||||
const registeredAccelerators: string[] = [];
|
||||
const options: ShortcutsRuntimeComposerOptions = {
|
||||
// Global and overlay shortcut handlers are only constructed here, never invoked.
|
||||
globalShortcuts: {
|
||||
getConfiguredShortcutsMainDeps:
|
||||
{} as GlobalShortcutsOptions['getConfiguredShortcutsMainDeps'],
|
||||
buildRegisterGlobalShortcutsMainDeps: () =>
|
||||
({}) as ReturnType<GlobalShortcutsOptions['buildRegisterGlobalShortcutsMainDeps']>,
|
||||
buildRefreshGlobalAndOverlayShortcutsMainDeps: () =>
|
||||
({}) as ReturnType<GlobalShortcutsOptions['buildRefreshGlobalAndOverlayShortcutsMainDeps']>,
|
||||
},
|
||||
overlayShortcutsRuntimeMainDeps:
|
||||
{} as ShortcutsRuntimeComposerOptions['overlayShortcutsRuntimeMainDeps'],
|
||||
numericShortcutRuntimeMainDeps: {
|
||||
globalShortcut: {
|
||||
register: (accelerator) => {
|
||||
registeredAccelerators.push(accelerator);
|
||||
return true;
|
||||
},
|
||||
unregister: () => {},
|
||||
},
|
||||
showMpvOsd: () => {},
|
||||
setTimer: () => setTimeout(() => {}, 0),
|
||||
clearTimer: (timer) => clearTimeout(timer),
|
||||
},
|
||||
numericSessions: {
|
||||
onMultiCopyDigit: () => {},
|
||||
onMineSentenceDigit: () => {},
|
||||
tryBeginMultiCopyOverlaySelection: tryBeginOverlaySelection,
|
||||
tryBeginMineSentenceOverlaySelection: tryBeginOverlaySelection,
|
||||
},
|
||||
};
|
||||
return { options, registeredAccelerators };
|
||||
}
|
||||
|
||||
test('numeric sessions delegate to the visible overlay when it accepts the selection', () => {
|
||||
const timeouts: number[] = [];
|
||||
const { options, registeredAccelerators } = createComposerOptions((timeoutMs) => {
|
||||
timeouts.push(timeoutMs);
|
||||
return true;
|
||||
});
|
||||
const runtimes = composeShortcutRuntimes(options);
|
||||
|
||||
runtimes.startPendingMultiCopy(3000);
|
||||
runtimes.startPendingMineSentenceMultiple(4000);
|
||||
|
||||
assert.deepEqual(timeouts, [3000, 4000]);
|
||||
assert.deepEqual(registeredAccelerators, []);
|
||||
});
|
||||
|
||||
test('numeric sessions fall back to global digit shortcuts when the overlay declines', () => {
|
||||
const { options, registeredAccelerators } = createComposerOptions(() => false);
|
||||
const runtimes = composeShortcutRuntimes(options);
|
||||
|
||||
runtimes.startPendingMultiCopy(3000);
|
||||
|
||||
assert.ok(registeredAccelerators.length > 0);
|
||||
runtimes.cancelPendingMultiCopy();
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
import { createNumericShortcutRuntime } from '../../../core/services/numeric-shortcut';
|
||||
import {
|
||||
createBuildNumericShortcutRuntimeMainDepsHandler,
|
||||
createGlobalShortcutsRuntimeHandlers,
|
||||
createNumericShortcutSessionRuntimeHandlers,
|
||||
createOverlayShortcutsRuntimeHandlers,
|
||||
@@ -8,9 +7,7 @@ import {
|
||||
import type { ComposerInputs, ComposerOutputs } from './contracts';
|
||||
|
||||
type GlobalShortcutsOptions = Parameters<typeof createGlobalShortcutsRuntimeHandlers>[0];
|
||||
type NumericShortcutRuntimeMainDeps = Parameters<
|
||||
typeof createBuildNumericShortcutRuntimeMainDepsHandler
|
||||
>[0];
|
||||
type NumericShortcutRuntimeMainDeps = Parameters<typeof createNumericShortcutRuntime>[0];
|
||||
type NumericSessionOptions = Omit<
|
||||
Parameters<typeof createNumericShortcutSessionRuntimeHandlers>[0],
|
||||
'multiCopySession' | 'mineSentenceSession'
|
||||
@@ -37,15 +34,13 @@ export function composeShortcutRuntimes(
|
||||
): ShortcutsRuntimeComposerResult {
|
||||
const globalShortcuts = createGlobalShortcutsRuntimeHandlers(options.globalShortcuts);
|
||||
|
||||
const numericShortcutRuntimeMainDeps = createBuildNumericShortcutRuntimeMainDepsHandler(
|
||||
const numericShortcutRuntime = createNumericShortcutRuntime(
|
||||
options.numericShortcutRuntimeMainDeps,
|
||||
)();
|
||||
const numericShortcutRuntime = createNumericShortcutRuntime(numericShortcutRuntimeMainDeps);
|
||||
);
|
||||
const numericSessions = createNumericShortcutSessionRuntimeHandlers({
|
||||
...options.numericSessions,
|
||||
multiCopySession: numericShortcutRuntime.createSession(),
|
||||
mineSentenceSession: numericShortcutRuntime.createSession(),
|
||||
onMultiCopyDigit: options.numericSessions.onMultiCopyDigit,
|
||||
onMineSentenceDigit: options.numericSessions.onMineSentenceDigit,
|
||||
});
|
||||
|
||||
const overlayShortcuts = createOverlayShortcutsRuntimeHandlers({
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
export * from '../anilist-media-guess';
|
||||
export * from '../anilist-media-guess-main-deps';
|
||||
export * from '../anilist-media-state';
|
||||
export * from '../anilist-media-state-main-deps';
|
||||
export * from '../anilist-post-watch';
|
||||
export * from '../anilist-post-watch-main-deps';
|
||||
export * from '../anilist-setup';
|
||||
export * from '../anilist-setup-protocol';
|
||||
export * from '../anilist-setup-protocol-main-deps';
|
||||
export * from '../anilist-setup-window';
|
||||
export * from '../anilist-setup-window-main-deps';
|
||||
export * from '../anilist-state';
|
||||
export * from '../anilist-token-refresh';
|
||||
export * from '../anilist-token-refresh-main-deps';
|
||||
export * from '../protocol-url-handlers';
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from '../cli-command-context-factory';
|
||||
export * from '../cli-command-runtime-handler';
|
||||
export * from '../initial-args-runtime-handler';
|
||||
export * from '../ipc-mpv-command-main-deps';
|
||||
export * from '../ipc-runtime-handlers';
|
||||
@@ -1,25 +1,18 @@
|
||||
export * from '../jellyfin-cli-auth';
|
||||
export * from '../jellyfin-cli-list';
|
||||
export * from '../jellyfin-cli-main-deps';
|
||||
export * from '../jellyfin-cli-play';
|
||||
export * from '../jellyfin-cli-remote-announce';
|
||||
export * from '../jellyfin-client-info';
|
||||
export * from '../jellyfin-client-info-main-deps';
|
||||
export * from '../jellyfin-command-dispatch';
|
||||
export * from '../jellyfin-command-dispatch-main-deps';
|
||||
export * from '../jellyfin-device-identity';
|
||||
export * from '../jellyfin-playback-launch';
|
||||
export * from '../jellyfin-playback-launch-main-deps';
|
||||
export * from '../jellyfin-remote-commands';
|
||||
export * from '../jellyfin-remote-connection';
|
||||
export * from '../jellyfin-remote-connection-main-deps';
|
||||
export * from '../jellyfin-remote-main-deps';
|
||||
export * from '../jellyfin-remote-playback';
|
||||
export * from '../jellyfin-remote-session-lifecycle';
|
||||
export * from '../jellyfin-remote-session-main-deps';
|
||||
export * from '../jellyfin-setup-window';
|
||||
export * from '../jellyfin-setup-window-main-deps';
|
||||
export * from '../jellyfin-subtitle-preload';
|
||||
export * from '../jellyfin-subtitle-preload-main-deps';
|
||||
export * from '../mpv-jellyfin-defaults';
|
||||
export * from '../mpv-jellyfin-defaults-main-deps';
|
||||
@@ -1,4 +1,2 @@
|
||||
export * from '../anki-actions';
|
||||
export * from '../anki-actions-main-deps';
|
||||
export * from '../mining-actions';
|
||||
export * from '../mining-actions-main-deps';
|
||||
@@ -4,6 +4,5 @@ export * from '../mpv-main-event-bindings';
|
||||
export * from '../mpv-main-event-main-deps';
|
||||
export * from '../mpv-osd-runtime-handlers';
|
||||
export * from '../mpv-subtitle-render-metrics';
|
||||
export * from '../mpv-subtitle-render-metrics-main-deps';
|
||||
export * from '../secondary-sub-mode-runtime-handler';
|
||||
export * from '../subtitle-tokenization-main-deps';
|
||||
@@ -1,21 +1,15 @@
|
||||
export * from '../config-hot-reload-handlers';
|
||||
export * from '../config-hot-reload-main-deps';
|
||||
export * from '../field-grouping-overlay-main-deps';
|
||||
export * from '../field-grouping-resolver';
|
||||
export * from '../field-grouping-resolver-main-deps';
|
||||
export * from '../overlay-bootstrap-main-deps';
|
||||
export * from '../overlay-main-actions';
|
||||
export * from '../overlay-main-actions-main-deps';
|
||||
export * from '../overlay-runtime-bootstrap-handlers';
|
||||
export * from '../overlay-runtime-main-actions';
|
||||
export * from '../overlay-runtime-main-actions-main-deps';
|
||||
export * from '../overlay-visibility-runtime';
|
||||
export * from '../overlay-visibility-runtime-main-deps';
|
||||
export * from '../overlay-window-layout';
|
||||
export * from '../overlay-window-layout-main-deps';
|
||||
export * from '../overlay-window-runtime-handlers';
|
||||
export * from '../subtitle-position';
|
||||
export * from '../subtitle-position-main-deps';
|
||||
export * from '../tray-runtime';
|
||||
export * from '../tray-runtime-handlers';
|
||||
export * from '../yomitan-extension-runtime';
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from '../global-shortcuts-runtime-handlers';
|
||||
export * from '../numeric-shortcut-runtime-main-deps';
|
||||
export * from '../numeric-shortcut-session-runtime-handlers';
|
||||
export * from '../overlay-shortcuts-runtime-handlers';
|
||||
export * from '../overlay-shortcuts-runtime-main-deps';
|
||||
@@ -1,19 +1,12 @@
|
||||
export * from '../app-lifecycle-actions';
|
||||
export * from '../app-lifecycle-main-activate';
|
||||
export * from '../app-lifecycle-main-cleanup';
|
||||
export * from '../app-ready-main-deps';
|
||||
export * from '../clipboard-queue';
|
||||
export * from '../config-derived';
|
||||
export * from '../dictionary-runtime-main-deps';
|
||||
export * from '../immersion-media';
|
||||
export * from '../immersion-startup';
|
||||
export * from '../immersion-startup-main-deps';
|
||||
export * from '../media-runtime-main-deps';
|
||||
export * from '../runtime-bootstrap-main-deps';
|
||||
export * from '../startup-config';
|
||||
export * from '../startup-config-main-deps';
|
||||
export * from '../startup-runtime-handlers';
|
||||
export * from '../startup-warmups';
|
||||
export * from '../startup-warmups-main-deps';
|
||||
export * from '../subtitle-processing-main-deps';
|
||||
export * from '../subsync-runtime';
|
||||
@@ -1,46 +0,0 @@
|
||||
import type { FieldGroupingOverlayRuntimeOptions } from '../../core/services/field-grouping-overlay';
|
||||
|
||||
type FieldGroupingOverlayMainDeps<TModal extends string> = Omit<
|
||||
FieldGroupingOverlayRuntimeOptions<TModal>,
|
||||
'sendToVisibleOverlay'
|
||||
> & {
|
||||
sendToActiveOverlayWindow: (
|
||||
channel: string,
|
||||
payload?: unknown,
|
||||
runtimeOptions?: { restoreOnModalClose?: TModal; preferModalWindow?: boolean },
|
||||
) => boolean;
|
||||
};
|
||||
|
||||
type BuiltFieldGroupingOverlayMainDeps<TModal extends string> =
|
||||
FieldGroupingOverlayRuntimeOptions<TModal> & {
|
||||
sendToVisibleOverlay: NonNullable<
|
||||
FieldGroupingOverlayRuntimeOptions<TModal>['sendToVisibleOverlay']
|
||||
>;
|
||||
};
|
||||
|
||||
export function createBuildFieldGroupingOverlayMainDepsHandler<TModal extends string>(
|
||||
deps: FieldGroupingOverlayMainDeps<TModal>,
|
||||
) {
|
||||
return (): BuiltFieldGroupingOverlayMainDeps<TModal> => ({
|
||||
getMainWindow: () => deps.getMainWindow(),
|
||||
getVisibleOverlayVisible: () => deps.getVisibleOverlayVisible(),
|
||||
setVisibleOverlayVisible: (visible: boolean) => deps.setVisibleOverlayVisible(visible),
|
||||
getResolver: () => deps.getResolver(),
|
||||
setResolver: (resolver) => deps.setResolver(resolver),
|
||||
getRestoreVisibleOverlayOnModalClose: () => deps.getRestoreVisibleOverlayOnModalClose(),
|
||||
// These are optional on the runtime options, so a missing forward compiles silently — but
|
||||
// dropping them left the field grouping modal with no modal-open ack/retry, no teardown on
|
||||
// failure, and no warn logging, which is why the earlier recovery fixes never took effect.
|
||||
waitForModalOpen: deps.waitForModalOpen,
|
||||
handleOverlayModalClosed: deps.handleOverlayModalClosed,
|
||||
logWarn: deps.logWarn,
|
||||
ensureOverlayStartupPrereqs: deps.ensureOverlayStartupPrereqs,
|
||||
ensureOverlayWindowsReadyForVisibilityActions:
|
||||
deps.ensureOverlayWindowsReadyForVisibilityActions,
|
||||
sendToVisibleOverlay: (
|
||||
channel: string,
|
||||
payload?: unknown,
|
||||
runtimeOptions?: { restoreOnModalClose?: TModal; preferModalWindow?: boolean },
|
||||
) => deps.sendToActiveOverlayWindow(channel, payload, runtimeOptions),
|
||||
});
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import type {
|
||||
createGetFieldGroupingResolverHandler,
|
||||
createSetFieldGroupingResolverHandler,
|
||||
} from './field-grouping-resolver';
|
||||
|
||||
type GetFieldGroupingResolverMainDeps = Parameters<typeof createGetFieldGroupingResolverHandler>[0];
|
||||
type SetFieldGroupingResolverMainDeps = Parameters<typeof createSetFieldGroupingResolverHandler>[0];
|
||||
|
||||
export function createBuildGetFieldGroupingResolverMainDepsHandler(
|
||||
deps: GetFieldGroupingResolverMainDeps,
|
||||
) {
|
||||
return (): GetFieldGroupingResolverMainDeps => ({
|
||||
getResolver: () => deps.getResolver(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildSetFieldGroupingResolverMainDepsHandler(
|
||||
deps: SetFieldGroupingResolverMainDeps,
|
||||
) {
|
||||
return (): SetFieldGroupingResolverMainDeps => ({
|
||||
setResolver: (resolver) => deps.setResolver(resolver),
|
||||
nextSequence: () => deps.nextSequence(),
|
||||
getSequence: () => deps.getSequence(),
|
||||
});
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import type { Config } from '../../types';
|
||||
import type { ConfiguredShortcuts } from '../../core/utils/shortcut-config';
|
||||
import type { RegisterGlobalShortcutsServiceOptions } from '../../core/services/shortcut';
|
||||
|
||||
export function createBuildGetConfiguredShortcutsMainDepsHandler(deps: {
|
||||
getResolvedConfig: () => Config;
|
||||
defaultConfig: Config;
|
||||
resolveConfiguredShortcuts: (config: Config, defaultConfig: Config) => ConfiguredShortcuts;
|
||||
}) {
|
||||
return () => ({
|
||||
getResolvedConfig: () => deps.getResolvedConfig(),
|
||||
defaultConfig: deps.defaultConfig,
|
||||
resolveConfiguredShortcuts: (config: Config, defaultConfig: Config) =>
|
||||
deps.resolveConfiguredShortcuts(config, defaultConfig),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildRegisterGlobalShortcutsMainDepsHandler(deps: {
|
||||
getConfiguredShortcuts: () => RegisterGlobalShortcutsServiceOptions['shortcuts'];
|
||||
registerGlobalShortcutsCore: (options: RegisterGlobalShortcutsServiceOptions) => void;
|
||||
toggleVisibleOverlay: () => void;
|
||||
openYomitanSettings: () => void;
|
||||
isDev: boolean;
|
||||
getMainWindow: RegisterGlobalShortcutsServiceOptions['getMainWindow'];
|
||||
}) {
|
||||
return () => ({
|
||||
getConfiguredShortcuts: () => deps.getConfiguredShortcuts(),
|
||||
registerGlobalShortcutsCore: (options: RegisterGlobalShortcutsServiceOptions) =>
|
||||
deps.registerGlobalShortcutsCore(options),
|
||||
onToggleVisibleOverlay: () => deps.toggleVisibleOverlay(),
|
||||
onOpenYomitanSettings: () => deps.openYomitanSettings(),
|
||||
isDev: deps.isDev,
|
||||
getMainWindow: deps.getMainWindow,
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler(deps: {
|
||||
unregisterAllGlobalShortcuts: () => void;
|
||||
registerGlobalShortcuts: () => void;
|
||||
syncOverlayShortcuts: () => void;
|
||||
}) {
|
||||
return () => ({
|
||||
unregisterAllGlobalShortcuts: () => deps.unregisterAllGlobalShortcuts(),
|
||||
registerGlobalShortcuts: () => deps.registerGlobalShortcuts(),
|
||||
syncOverlayShortcuts: () => deps.syncOverlayShortcuts(),
|
||||
});
|
||||
}
|
||||
@@ -4,20 +4,11 @@ import {
|
||||
createRefreshGlobalAndOverlayShortcutsHandler,
|
||||
createRegisterGlobalShortcutsHandler,
|
||||
} from './global-shortcuts';
|
||||
import {
|
||||
createBuildGetConfiguredShortcutsMainDepsHandler,
|
||||
createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler,
|
||||
createBuildRegisterGlobalShortcutsMainDepsHandler,
|
||||
} from './global-shortcuts-main-deps';
|
||||
|
||||
type GetConfiguredShortcutsMainDeps = Parameters<
|
||||
typeof createBuildGetConfiguredShortcutsMainDepsHandler
|
||||
>[0];
|
||||
type RegisterGlobalShortcutsMainDeps = Parameters<
|
||||
typeof createBuildRegisterGlobalShortcutsMainDepsHandler
|
||||
>[0];
|
||||
type GetConfiguredShortcutsMainDeps = Parameters<typeof createGetConfiguredShortcutsHandler>[0];
|
||||
type RegisterGlobalShortcutsMainDeps = Parameters<typeof createRegisterGlobalShortcutsHandler>[0];
|
||||
type RefreshGlobalAndOverlayShortcutsMainDeps = Parameters<
|
||||
typeof createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler
|
||||
typeof createRefreshGlobalAndOverlayShortcutsHandler
|
||||
>[0];
|
||||
|
||||
export function createGlobalShortcutsRuntimeHandlers(deps: {
|
||||
@@ -29,28 +20,18 @@ export function createGlobalShortcutsRuntimeHandlers(deps: {
|
||||
registerGlobalShortcuts: () => void,
|
||||
) => RefreshGlobalAndOverlayShortcutsMainDeps;
|
||||
}) {
|
||||
const getConfiguredShortcutsMainDeps = createBuildGetConfiguredShortcutsMainDepsHandler(
|
||||
deps.getConfiguredShortcutsMainDeps,
|
||||
)();
|
||||
const getConfiguredShortcutsHandler = createGetConfiguredShortcutsHandler(
|
||||
getConfiguredShortcutsMainDeps,
|
||||
deps.getConfiguredShortcutsMainDeps,
|
||||
);
|
||||
const getConfiguredShortcuts = () => getConfiguredShortcutsHandler();
|
||||
|
||||
const registerGlobalShortcutsMainDeps = createBuildRegisterGlobalShortcutsMainDepsHandler(
|
||||
deps.buildRegisterGlobalShortcutsMainDeps(getConfiguredShortcuts),
|
||||
)();
|
||||
const registerGlobalShortcutsHandler = createRegisterGlobalShortcutsHandler(
|
||||
registerGlobalShortcutsMainDeps,
|
||||
deps.buildRegisterGlobalShortcutsMainDeps(getConfiguredShortcuts),
|
||||
);
|
||||
const registerGlobalShortcuts = () => registerGlobalShortcutsHandler();
|
||||
|
||||
const refreshGlobalAndOverlayShortcutsMainDeps =
|
||||
createBuildRefreshGlobalAndOverlayShortcutsMainDepsHandler(
|
||||
deps.buildRefreshGlobalAndOverlayShortcutsMainDeps(registerGlobalShortcuts),
|
||||
)();
|
||||
const refreshGlobalAndOverlayShortcutsHandler = createRefreshGlobalAndOverlayShortcutsHandler(
|
||||
refreshGlobalAndOverlayShortcutsMainDeps,
|
||||
deps.buildRefreshGlobalAndOverlayShortcutsMainDeps(registerGlobalShortcuts),
|
||||
);
|
||||
const refreshGlobalAndOverlayShortcuts = () => refreshGlobalAndOverlayShortcutsHandler();
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import type {
|
||||
ImmersionTrackerStartupDeps,
|
||||
createImmersionTrackerStartupHandler,
|
||||
} from './immersion-startup';
|
||||
|
||||
type ImmersionTrackerStartupMainDeps = Parameters<typeof createImmersionTrackerStartupHandler>[0];
|
||||
|
||||
export function createBuildImmersionTrackerStartupMainDepsHandler(
|
||||
deps: ImmersionTrackerStartupMainDeps,
|
||||
) {
|
||||
return (): ImmersionTrackerStartupDeps => ({
|
||||
getResolvedConfig: () => deps.getResolvedConfig(),
|
||||
getConfiguredDbPath: () => deps.getConfiguredDbPath(),
|
||||
createTrackerService: (params) => deps.createTrackerService(params),
|
||||
setTracker: (tracker) => deps.setTracker(tracker),
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
seedTrackerFromCurrentMedia: () => deps.seedTrackerFromCurrentMedia(),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
logDebug: (message: string) => deps.logDebug(message),
|
||||
logWarn: (message: string, details: unknown) => deps.logWarn(message, details),
|
||||
});
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import type { CliArgs } from '../../cli/args';
|
||||
|
||||
export function createBuildHandleInitialArgsMainDepsHandler(deps: {
|
||||
getInitialArgs: () => CliArgs | null;
|
||||
isBackgroundMode: () => boolean;
|
||||
shouldEnsureTrayOnStartup: () => boolean;
|
||||
shouldRunHeadlessInitialCommand: (args: CliArgs) => boolean;
|
||||
ensureTray: () => void;
|
||||
isTexthookerOnlyMode: () => boolean;
|
||||
hasImmersionTracker: () => boolean;
|
||||
getMpvClient: () => { connected: boolean; connect: () => void } | null;
|
||||
commandNeedsOverlayStartupPrereqs: (args: CliArgs) => boolean;
|
||||
commandNeedsOverlayRuntime: (args: CliArgs) => boolean;
|
||||
ensureOverlayStartupPrereqs: () => void;
|
||||
isOverlayRuntimeInitialized: () => boolean;
|
||||
initializeOverlayRuntime: () => void;
|
||||
logInfo: (message: string) => void;
|
||||
handleCliCommand: (args: CliArgs, source: 'initial') => void;
|
||||
}) {
|
||||
return () => ({
|
||||
getInitialArgs: () => deps.getInitialArgs(),
|
||||
isBackgroundMode: () => deps.isBackgroundMode(),
|
||||
shouldEnsureTrayOnStartup: () => deps.shouldEnsureTrayOnStartup(),
|
||||
shouldRunHeadlessInitialCommand: (args: CliArgs) => deps.shouldRunHeadlessInitialCommand(args),
|
||||
ensureTray: () => deps.ensureTray(),
|
||||
isTexthookerOnlyMode: () => deps.isTexthookerOnlyMode(),
|
||||
hasImmersionTracker: () => deps.hasImmersionTracker(),
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
commandNeedsOverlayStartupPrereqs: (args: CliArgs) =>
|
||||
deps.commandNeedsOverlayStartupPrereqs(args),
|
||||
commandNeedsOverlayRuntime: (args: CliArgs) => deps.commandNeedsOverlayRuntime(args),
|
||||
ensureOverlayStartupPrereqs: () => deps.ensureOverlayStartupPrereqs(),
|
||||
isOverlayRuntimeInitialized: () => deps.isOverlayRuntimeInitialized(),
|
||||
initializeOverlayRuntime: () => deps.initializeOverlayRuntime(),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
handleCliCommand: (args: CliArgs, source: 'initial') => deps.handleCliCommand(args, source),
|
||||
});
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
import { createHandleInitialArgsHandler } from './initial-args-handler';
|
||||
import { createBuildHandleInitialArgsMainDepsHandler } from './initial-args-main-deps';
|
||||
|
||||
type InitialArgsMainDeps = Parameters<typeof createBuildHandleInitialArgsMainDepsHandler>[0];
|
||||
type InitialArgsMainDeps = Parameters<typeof createHandleInitialArgsHandler>[0];
|
||||
|
||||
export function createInitialArgsRuntimeHandler(deps: InitialArgsMainDeps) {
|
||||
const buildHandleInitialArgsMainDepsHandler = createBuildHandleInitialArgsMainDepsHandler(deps);
|
||||
const handleInitialArgsMainDeps = buildHandleInitialArgsMainDepsHandler();
|
||||
return createHandleInitialArgsHandler(handleInitialArgsMainDeps);
|
||||
return createHandleInitialArgsHandler(deps);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import type { createHandleMpvCommandFromIpcHandler } from './ipc-bridge-actions';
|
||||
|
||||
type HandleMpvCommandFromIpcMainDeps = Parameters<typeof createHandleMpvCommandFromIpcHandler>[0];
|
||||
|
||||
export function createBuildHandleMpvCommandFromIpcMainDepsHandler(
|
||||
deps: HandleMpvCommandFromIpcMainDeps,
|
||||
) {
|
||||
return (): HandleMpvCommandFromIpcMainDeps => ({
|
||||
handleMpvCommandFromIpcRuntime: (command, options) =>
|
||||
deps.handleMpvCommandFromIpcRuntime(command, options),
|
||||
buildMpvCommandDeps: () => deps.buildMpvCommandDeps(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildRunSubsyncManualFromIpcMainDepsHandler<TRequest, TResult>(deps: {
|
||||
runManualFromIpc: (request: TRequest) => Promise<TResult>;
|
||||
}) {
|
||||
return () => ({
|
||||
runManualFromIpc: (request: TRequest) => deps.runManualFromIpc(request),
|
||||
});
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import type { MpvCommandFromIpcRuntimeDeps } from '../ipc-mpv-command';
|
||||
|
||||
export function createBuildMpvCommandFromIpcRuntimeMainDepsHandler(
|
||||
deps: MpvCommandFromIpcRuntimeDeps,
|
||||
) {
|
||||
return (): MpvCommandFromIpcRuntimeDeps => {
|
||||
const showPlaybackFeedback = deps.showPlaybackFeedback;
|
||||
const showRawMpvOsd = deps.showRawMpvOsd;
|
||||
return {
|
||||
triggerSubsyncFromConfig: () => deps.triggerSubsyncFromConfig(),
|
||||
openRuntimeOptionsPalette: () => deps.openRuntimeOptionsPalette(),
|
||||
openJimaku: () => deps.openJimaku(),
|
||||
openTsukihime: () => deps.openTsukihime(),
|
||||
openYoutubeTrackPicker: () => deps.openYoutubeTrackPicker(),
|
||||
openPlaylistBrowser: () => deps.openPlaylistBrowser(),
|
||||
cycleRuntimeOption: (id, direction) => deps.cycleRuntimeOption(id, direction),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
...(showRawMpvOsd ? { showRawMpvOsd: (text: string) => showRawMpvOsd(text) } : {}),
|
||||
...(showPlaybackFeedback
|
||||
? { showPlaybackFeedback: (text: string) => showPlaybackFeedback(text) }
|
||||
: {}),
|
||||
replayCurrentSubtitle: () => deps.replayCurrentSubtitle(),
|
||||
playNextSubtitle: () => deps.playNextSubtitle(),
|
||||
sendMpvCommand: (command: (string | number)[]) => deps.sendMpvCommand(command),
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
isMpvConnected: () => deps.isMpvConnected(),
|
||||
hasRuntimeOptionsManager: () => deps.hasRuntimeOptionsManager(),
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -2,35 +2,18 @@ import {
|
||||
createHandleMpvCommandFromIpcHandler,
|
||||
createRunSubsyncManualFromIpcHandler,
|
||||
} from './ipc-bridge-actions';
|
||||
import {
|
||||
createBuildHandleMpvCommandFromIpcMainDepsHandler,
|
||||
createBuildRunSubsyncManualFromIpcMainDepsHandler,
|
||||
} from './ipc-bridge-actions-main-deps';
|
||||
|
||||
type HandleMpvCommandFromIpcMainDeps = Parameters<
|
||||
typeof createBuildHandleMpvCommandFromIpcMainDepsHandler
|
||||
>[0];
|
||||
type RunSubsyncManualFromIpcMainDeps<TRequest, TResult> = Parameters<
|
||||
typeof createBuildRunSubsyncManualFromIpcMainDepsHandler<TRequest, TResult>
|
||||
>[0];
|
||||
|
||||
export function createIpcRuntimeHandlers<TRequest, TResult>(deps: {
|
||||
handleMpvCommandFromIpcDeps: HandleMpvCommandFromIpcMainDeps;
|
||||
runSubsyncManualFromIpcDeps: RunSubsyncManualFromIpcMainDeps<TRequest, TResult>;
|
||||
handleMpvCommandFromIpcDeps: Parameters<typeof createHandleMpvCommandFromIpcHandler>[0];
|
||||
runSubsyncManualFromIpcDeps: Parameters<
|
||||
typeof createRunSubsyncManualFromIpcHandler<TRequest, TResult>
|
||||
>[0];
|
||||
}) {
|
||||
const handleMpvCommandFromIpcMainDeps = createBuildHandleMpvCommandFromIpcMainDepsHandler(
|
||||
deps.handleMpvCommandFromIpcDeps,
|
||||
)();
|
||||
const handleMpvCommandFromIpc = createHandleMpvCommandFromIpcHandler(
|
||||
handleMpvCommandFromIpcMainDeps,
|
||||
deps.handleMpvCommandFromIpcDeps,
|
||||
);
|
||||
|
||||
const runSubsyncManualFromIpcMainDeps = createBuildRunSubsyncManualFromIpcMainDepsHandler<
|
||||
TRequest,
|
||||
TResult
|
||||
>(deps.runSubsyncManualFromIpcDeps)();
|
||||
const runSubsyncManualFromIpc = createRunSubsyncManualFromIpcHandler<TRequest, TResult>(
|
||||
runSubsyncManualFromIpcMainDeps,
|
||||
deps.runSubsyncManualFromIpcDeps,
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
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];
|
||||
type HandleJellyfinPlayCommandMainDeps = Parameters<typeof createHandleJellyfinPlayCommand>[0];
|
||||
type HandleJellyfinRemoteAnnounceCommandMainDeps = Parameters<
|
||||
typeof createHandleJellyfinRemoteAnnounceCommand
|
||||
>[0];
|
||||
|
||||
export function createBuildHandleJellyfinAuthCommandsMainDepsHandler(
|
||||
deps: HandleJellyfinAuthCommandsMainDeps,
|
||||
) {
|
||||
return (): HandleJellyfinAuthCommandsMainDeps => ({
|
||||
patchRawConfig: (patch) => deps.patchRawConfig(patch),
|
||||
authenticateWithPassword: (serverUrl, username, password, clientInfo) =>
|
||||
deps.authenticateWithPassword(serverUrl, username, password, clientInfo),
|
||||
saveStoredSession: (session) => deps.saveStoredSession(session),
|
||||
clearStoredSession: () => deps.clearStoredSession(),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildHandleJellyfinListCommandsMainDepsHandler(
|
||||
deps: HandleJellyfinListCommandsMainDeps,
|
||||
) {
|
||||
return (): HandleJellyfinListCommandsMainDeps => ({
|
||||
listJellyfinLibraries: (session, clientInfo) => deps.listJellyfinLibraries(session, clientInfo),
|
||||
listJellyfinItems: (session, clientInfo, params) =>
|
||||
deps.listJellyfinItems(session, clientInfo, params),
|
||||
listJellyfinSubtitleTracks: (session, clientInfo, itemId) =>
|
||||
deps.listJellyfinSubtitleTracks(session, clientInfo, itemId),
|
||||
writeJellyfinResponse: (responsePath, response) =>
|
||||
deps.writeJellyfinResponse(responsePath, response),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildHandleJellyfinPlayCommandMainDepsHandler(
|
||||
deps: HandleJellyfinPlayCommandMainDeps,
|
||||
) {
|
||||
return (): HandleJellyfinPlayCommandMainDeps => ({
|
||||
playJellyfinItemInMpv: (params) => deps.playJellyfinItemInMpv(params),
|
||||
logWarn: (message: string) => deps.logWarn(message),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildHandleJellyfinRemoteAnnounceCommandMainDepsHandler(
|
||||
deps: HandleJellyfinRemoteAnnounceCommandMainDeps,
|
||||
) {
|
||||
return (): HandleJellyfinRemoteAnnounceCommandMainDeps => ({
|
||||
startJellyfinRemoteSession: (options) => deps.startJellyfinRemoteSession(options),
|
||||
getRemoteSession: () => deps.getRemoteSession(),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
logWarn: (message: string) => deps.logWarn(message),
|
||||
});
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
import type { CliArgs } from '../../cli/args';
|
||||
import type { JellyfinCliResponse } from '../../shared/jellyfin-cli-response';
|
||||
|
||||
type JellyfinConfigBase = {
|
||||
serverUrl?: string;
|
||||
accessToken?: string;
|
||||
userId?: string;
|
||||
username?: string;
|
||||
};
|
||||
|
||||
type JellyfinSession = {
|
||||
serverUrl: string;
|
||||
accessToken: string;
|
||||
userId: string;
|
||||
username: string;
|
||||
};
|
||||
|
||||
export type RunJellyfinCommandMainDeps<TClientInfo, TConfig extends JellyfinConfigBase> = {
|
||||
getJellyfinConfig: () => TConfig;
|
||||
defaultServerUrl: string;
|
||||
getJellyfinClientInfo: (config: TConfig) => TClientInfo;
|
||||
handleAuthCommands: (params: {
|
||||
args: CliArgs;
|
||||
jellyfinConfig: TConfig;
|
||||
serverUrl: string;
|
||||
clientInfo: TClientInfo;
|
||||
}) => Promise<boolean>;
|
||||
handleRemoteAnnounceCommand: (args: CliArgs) => Promise<boolean>;
|
||||
handleListCommands: (params: {
|
||||
args: CliArgs;
|
||||
session: JellyfinSession;
|
||||
clientInfo: TClientInfo;
|
||||
jellyfinConfig: TConfig;
|
||||
}) => Promise<boolean>;
|
||||
handlePlayCommand: (params: {
|
||||
args: CliArgs;
|
||||
session: JellyfinSession;
|
||||
clientInfo: TClientInfo;
|
||||
jellyfinConfig: TConfig;
|
||||
}) => Promise<boolean>;
|
||||
writeJellyfinResponse: (responsePath: string, response: JellyfinCliResponse) => void;
|
||||
};
|
||||
|
||||
export function createBuildRunJellyfinCommandMainDepsHandler<
|
||||
TClientInfo,
|
||||
TConfig extends JellyfinConfigBase,
|
||||
>(deps: RunJellyfinCommandMainDeps<TClientInfo, TConfig>) {
|
||||
return (): RunJellyfinCommandMainDeps<TClientInfo, TConfig> => ({
|
||||
getJellyfinConfig: () => deps.getJellyfinConfig(),
|
||||
defaultServerUrl: deps.defaultServerUrl,
|
||||
getJellyfinClientInfo: (config: TConfig) => deps.getJellyfinClientInfo(config),
|
||||
handleAuthCommands: (params) => deps.handleAuthCommands(params),
|
||||
handleRemoteAnnounceCommand: (args: CliArgs) => deps.handleRemoteAnnounceCommand(args),
|
||||
handleListCommands: (params) => deps.handleListCommands(params),
|
||||
handlePlayCommand: (params) => deps.handlePlayCommand(params),
|
||||
writeJellyfinResponse: (responsePath, response) =>
|
||||
deps.writeJellyfinResponse(responsePath, response),
|
||||
});
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import type { createPlayJellyfinItemInMpvHandler } from './jellyfin-playback-launch';
|
||||
|
||||
type PlayJellyfinItemInMpvMainDeps = Parameters<typeof createPlayJellyfinItemInMpvHandler>[0];
|
||||
|
||||
export function createBuildPlayJellyfinItemInMpvMainDepsHandler(
|
||||
deps: PlayJellyfinItemInMpvMainDeps,
|
||||
) {
|
||||
return (): PlayJellyfinItemInMpvMainDeps => ({
|
||||
ensureMpvConnectedForPlayback: () => deps.ensureMpvConnectedForPlayback(),
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
resolvePlaybackPlan: (params) => deps.resolvePlaybackPlan(params),
|
||||
applyJellyfinMpvDefaults: (mpvClient) => deps.applyJellyfinMpvDefaults(mpvClient),
|
||||
showVisibleOverlay: () => deps.showVisibleOverlay(),
|
||||
sendMpvCommand: (command: Array<string | number>) => deps.sendMpvCommand(command),
|
||||
armQuitOnDisconnect: () => deps.armQuitOnDisconnect(),
|
||||
schedule: (callback: () => void, delayMs: number) => deps.schedule(callback, delayMs),
|
||||
convertTicksToSeconds: (ticks: number) => deps.convertTicksToSeconds(ticks),
|
||||
preloadExternalSubtitles: (params) => deps.preloadExternalSubtitles(params),
|
||||
setActivePlayback: (state) => deps.setActivePlayback(state),
|
||||
setLastProgressAtMs: (value: number) => deps.setLastProgressAtMs(value),
|
||||
createPlaybackReporter: (params) => deps.createPlaybackReporter(params),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
recordJellyfinPlaybackMetadata: deps.recordJellyfinPlaybackMetadata
|
||||
? (metadata) => deps.recordJellyfinPlaybackMetadata!(metadata)
|
||||
: undefined,
|
||||
updateCurrentMediaTitle: deps.updateCurrentMediaTitle
|
||||
? (title) => deps.updateCurrentMediaTitle!(title)
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import type {
|
||||
EnsureMpvConnectedDeps,
|
||||
LaunchMpvForJellyfinDeps,
|
||||
WaitForMpvConnectedDeps,
|
||||
} from './jellyfin-remote-connection';
|
||||
|
||||
export function createBuildWaitForMpvConnectedMainDepsHandler(deps: WaitForMpvConnectedDeps) {
|
||||
return (): WaitForMpvConnectedDeps => ({
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
now: () => deps.now(),
|
||||
sleep: (delayMs: number) => deps.sleep(delayMs),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildLaunchMpvIdleForJellyfinPlaybackMainDepsHandler(
|
||||
deps: LaunchMpvForJellyfinDeps,
|
||||
) {
|
||||
return (): LaunchMpvForJellyfinDeps => ({
|
||||
getMpvExecutablePath: () => deps.getMpvExecutablePath(),
|
||||
getSocketPath: () => deps.getSocketPath(),
|
||||
getLaunchMode: () => deps.getLaunchMode(),
|
||||
platform: deps.platform,
|
||||
execPath: deps.execPath,
|
||||
getRuntimePluginEntrypoint: deps.getRuntimePluginEntrypoint,
|
||||
getInstalledPluginDetection: deps.getInstalledPluginDetection,
|
||||
getPluginRuntimeConfig: deps.getPluginRuntimeConfig,
|
||||
getDefaultMpvLogPath: () => deps.getDefaultMpvLogPath(),
|
||||
defaultMpvArgs: deps.defaultMpvArgs,
|
||||
removeSocketPath: (socketPath: string) => deps.removeSocketPath(socketPath),
|
||||
spawnMpv: (executablePath, args) => deps.spawnMpv(executablePath, args),
|
||||
logWarn: (message: string, error: unknown) => deps.logWarn(message, error),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildEnsureMpvConnectedForJellyfinPlaybackMainDepsHandler(
|
||||
deps: EnsureMpvConnectedDeps,
|
||||
) {
|
||||
return (): EnsureMpvConnectedDeps => ({
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
setMpvClient: (client) => deps.setMpvClient(client),
|
||||
createMpvClient: () => deps.createMpvClient(),
|
||||
waitForMpvConnected: (timeoutMs: number) => deps.waitForMpvConnected(timeoutMs),
|
||||
launchMpvIdleForJellyfinPlayback: () => deps.launchMpvIdleForJellyfinPlayback(),
|
||||
getAutoLaunchInFlight: () => deps.getAutoLaunchInFlight(),
|
||||
setAutoLaunchInFlight: (promise) => deps.setAutoLaunchInFlight(promise),
|
||||
connectTimeoutMs: deps.connectTimeoutMs,
|
||||
autoLaunchTimeoutMs: deps.autoLaunchTimeoutMs,
|
||||
});
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import type {
|
||||
createStartJellyfinRemoteSessionHandler,
|
||||
createStopJellyfinRemoteSessionHandler,
|
||||
} from './jellyfin-remote-session-lifecycle';
|
||||
|
||||
type StartJellyfinRemoteSessionMainDeps = Parameters<
|
||||
typeof createStartJellyfinRemoteSessionHandler
|
||||
>[0];
|
||||
type StopJellyfinRemoteSessionMainDeps = Parameters<
|
||||
typeof createStopJellyfinRemoteSessionHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildStartJellyfinRemoteSessionMainDepsHandler(
|
||||
deps: StartJellyfinRemoteSessionMainDeps,
|
||||
) {
|
||||
return (): StartJellyfinRemoteSessionMainDeps => ({
|
||||
getJellyfinConfig: () => deps.getJellyfinConfig(),
|
||||
getCurrentSession: () => deps.getCurrentSession(),
|
||||
setCurrentSession: (session) => deps.setCurrentSession(session),
|
||||
createRemoteSessionService: (options) => deps.createRemoteSessionService(options),
|
||||
getClientInfo: () => deps.getClientInfo(),
|
||||
getHostName: () => deps.getHostName(),
|
||||
defaultDeviceId: deps.defaultDeviceId,
|
||||
defaultClientName: deps.defaultClientName,
|
||||
defaultClientVersion: deps.defaultClientVersion,
|
||||
handlePlay: (payload) => deps.handlePlay(payload),
|
||||
handlePlaystate: (payload) => deps.handlePlaystate(payload),
|
||||
handleGeneralCommand: (payload) => deps.handleGeneralCommand(payload),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
logWarn: (message: string, details?: unknown) => deps.logWarn(message, details),
|
||||
onSessionStateChanged: deps.onSessionStateChanged,
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildStopJellyfinRemoteSessionMainDepsHandler(
|
||||
deps: StopJellyfinRemoteSessionMainDeps,
|
||||
) {
|
||||
return (): StopJellyfinRemoteSessionMainDeps => ({
|
||||
getCurrentSession: () => deps.getCurrentSession(),
|
||||
setCurrentSession: (session) => deps.setCurrentSession(session),
|
||||
clearActivePlayback: () => deps.clearActivePlayback(),
|
||||
onSessionStateChanged: deps.onSessionStateChanged,
|
||||
});
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import type { createPreloadJellyfinExternalSubtitlesHandler } from './jellyfin-subtitle-preload';
|
||||
|
||||
type PreloadJellyfinExternalSubtitlesMainDeps = Parameters<
|
||||
typeof createPreloadJellyfinExternalSubtitlesHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildPreloadJellyfinExternalSubtitlesMainDepsHandler(
|
||||
deps: PreloadJellyfinExternalSubtitlesMainDeps,
|
||||
) {
|
||||
return (): PreloadJellyfinExternalSubtitlesMainDeps => ({
|
||||
listJellyfinSubtitleTracks: (session, clientInfo, itemId) =>
|
||||
deps.listJellyfinSubtitleTracks(session, clientInfo, itemId),
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
sendMpvCommand: (command) => deps.sendMpvCommand(command),
|
||||
wait: (ms: number) => deps.wait(ms),
|
||||
cacheSubtitleTrack: (track) => deps.cacheSubtitleTrack(track),
|
||||
cleanupCachedSubtitles: (dirs) => deps.cleanupCachedSubtitles(dirs),
|
||||
initSubtitlePrefetch: deps.initSubtitlePrefetch
|
||||
? (sourcePath) => deps.initSubtitlePrefetch!(sourcePath)
|
||||
: undefined,
|
||||
logDebug: (message: string, error: unknown) => deps.logDebug(message, error),
|
||||
});
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import type { SubtitlePosition } from '../../types';
|
||||
|
||||
export function createBuildMediaRuntimeMainDepsHandler(deps: {
|
||||
isRemoteMediaPath: (mediaPath: string) => boolean;
|
||||
loadSubtitlePosition: () => SubtitlePosition | null;
|
||||
getCurrentMediaPath: () => string | null;
|
||||
getPendingSubtitlePosition: () => SubtitlePosition | null;
|
||||
getSubtitlePositionsDir: () => string;
|
||||
setCurrentMediaPath: (mediaPath: string | null) => void;
|
||||
clearPendingSubtitlePosition: () => void;
|
||||
setSubtitlePosition: (position: SubtitlePosition | null) => void;
|
||||
broadcastToOverlayWindows: (channel: string, payload: unknown) => void;
|
||||
getCurrentMediaTitle: () => string | null;
|
||||
setCurrentMediaTitle: (title: string | null) => void;
|
||||
}) {
|
||||
return () => ({
|
||||
isRemoteMediaPath: (mediaPath: string) => deps.isRemoteMediaPath(mediaPath),
|
||||
loadSubtitlePosition: () => deps.loadSubtitlePosition(),
|
||||
getCurrentMediaPath: () => deps.getCurrentMediaPath(),
|
||||
getPendingSubtitlePosition: () => deps.getPendingSubtitlePosition(),
|
||||
getSubtitlePositionsDir: () => deps.getSubtitlePositionsDir(),
|
||||
setCurrentMediaPath: (nextPath: string | null) => deps.setCurrentMediaPath(nextPath),
|
||||
clearPendingSubtitlePosition: () => deps.clearPendingSubtitlePosition(),
|
||||
setSubtitlePosition: (position: SubtitlePosition | null) => deps.setSubtitlePosition(position),
|
||||
broadcastSubtitlePosition: (position: SubtitlePosition | null) =>
|
||||
deps.broadcastToOverlayWindows('subtitle-position:set', position),
|
||||
getCurrentMediaTitle: () => deps.getCurrentMediaTitle(),
|
||||
setCurrentMediaTitle: (title: string | null) => deps.setCurrentMediaTitle(title),
|
||||
});
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
export function createBuildHandleMultiCopyDigitMainDepsHandler<TSubtitleTimingTracker>(deps: {
|
||||
getSubtitleTimingTracker: () => TSubtitleTimingTracker;
|
||||
writeClipboardText: (text: string) => void;
|
||||
showMpvOsd: (text: string) => void;
|
||||
handleMultiCopyDigitCore: (
|
||||
count: number,
|
||||
options: {
|
||||
subtitleTimingTracker: TSubtitleTimingTracker;
|
||||
writeClipboardText: (text: string) => void;
|
||||
showMpvOsd: (text: string) => void;
|
||||
},
|
||||
) => void;
|
||||
}) {
|
||||
return () => ({
|
||||
getSubtitleTimingTracker: () => deps.getSubtitleTimingTracker(),
|
||||
writeClipboardText: (text: string) => deps.writeClipboardText(text),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
handleMultiCopyDigitCore: (
|
||||
count: number,
|
||||
options: {
|
||||
subtitleTimingTracker: TSubtitleTimingTracker;
|
||||
writeClipboardText: (text: string) => void;
|
||||
showMpvOsd: (text: string) => void;
|
||||
},
|
||||
) => deps.handleMultiCopyDigitCore(count, options),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildCopyCurrentSubtitleMainDepsHandler<TSubtitleTimingTracker>(deps: {
|
||||
getSubtitleTimingTracker: () => TSubtitleTimingTracker;
|
||||
writeClipboardText: (text: string) => void;
|
||||
showMpvOsd: (text: string) => void;
|
||||
copyCurrentSubtitleCore: (options: {
|
||||
subtitleTimingTracker: TSubtitleTimingTracker;
|
||||
writeClipboardText: (text: string) => void;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) => void;
|
||||
}) {
|
||||
return () => ({
|
||||
getSubtitleTimingTracker: () => deps.getSubtitleTimingTracker(),
|
||||
writeClipboardText: (text: string) => deps.writeClipboardText(text),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
copyCurrentSubtitleCore: (options: {
|
||||
subtitleTimingTracker: TSubtitleTimingTracker;
|
||||
writeClipboardText: (text: string) => void;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) => deps.copyCurrentSubtitleCore(options),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildHandleMineSentenceDigitMainDepsHandler<
|
||||
TSubtitleTimingTracker,
|
||||
TAnkiIntegration,
|
||||
>(deps: {
|
||||
getSubtitleTimingTracker: () => TSubtitleTimingTracker;
|
||||
getAnkiIntegration: () => TAnkiIntegration;
|
||||
getCurrentSecondarySubText: () => string | undefined;
|
||||
showMpvOsd: (text: string) => void;
|
||||
logError: (message: string, err: unknown) => void;
|
||||
handleMineSentenceDigitCore: (
|
||||
count: number,
|
||||
options: {
|
||||
subtitleTimingTracker: TSubtitleTimingTracker;
|
||||
ankiIntegration: TAnkiIntegration;
|
||||
getCurrentSecondarySubText: () => string | undefined;
|
||||
showMpvOsd: (text: string) => void;
|
||||
logError: (message: string, err: unknown) => void;
|
||||
},
|
||||
) => void;
|
||||
}) {
|
||||
return () => ({
|
||||
getSubtitleTimingTracker: () => deps.getSubtitleTimingTracker(),
|
||||
getAnkiIntegration: () => deps.getAnkiIntegration(),
|
||||
getCurrentSecondarySubText: () => deps.getCurrentSecondarySubText(),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
logError: (message: string, err: unknown) => deps.logError(message, err),
|
||||
handleMineSentenceDigitCore: (
|
||||
count: number,
|
||||
options: {
|
||||
subtitleTimingTracker: TSubtitleTimingTracker;
|
||||
ankiIntegration: TAnkiIntegration;
|
||||
getCurrentSecondarySubText: () => string | undefined;
|
||||
showMpvOsd: (text: string) => void;
|
||||
logError: (message: string, err: unknown) => void;
|
||||
},
|
||||
) => deps.handleMineSentenceDigitCore(count, options),
|
||||
});
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import type {
|
||||
createApplyJellyfinMpvDefaultsHandler,
|
||||
createGetDefaultSocketPathHandler,
|
||||
} from './mpv-jellyfin-defaults';
|
||||
|
||||
type ApplyJellyfinMpvDefaultsMainDeps = Parameters<typeof createApplyJellyfinMpvDefaultsHandler>[0];
|
||||
type GetDefaultSocketPathMainDeps = Parameters<typeof createGetDefaultSocketPathHandler>[0];
|
||||
|
||||
export function createBuildApplyJellyfinMpvDefaultsMainDepsHandler(
|
||||
deps: ApplyJellyfinMpvDefaultsMainDeps,
|
||||
) {
|
||||
return (): ApplyJellyfinMpvDefaultsMainDeps => ({
|
||||
sendMpvCommandRuntime: (client, command) => deps.sendMpvCommandRuntime(client, command),
|
||||
jellyfinLangPref: deps.jellyfinLangPref,
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildGetDefaultSocketPathMainDepsHandler(deps: GetDefaultSocketPathMainDeps) {
|
||||
return (): GetDefaultSocketPathMainDeps => ({
|
||||
platform: deps.platform,
|
||||
});
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import type { createAppendToMpvLogHandler, createShowMpvOsdHandler } from './mpv-osd-log';
|
||||
|
||||
type AppendToMpvLogMainDeps = Parameters<typeof createAppendToMpvLogHandler>[0];
|
||||
type ShowMpvOsdMainDeps = Parameters<typeof createShowMpvOsdHandler>[0];
|
||||
|
||||
export function createBuildAppendToMpvLogMainDepsHandler(deps: AppendToMpvLogMainDeps) {
|
||||
return (): AppendToMpvLogMainDeps => ({
|
||||
getLogPath: () => deps.getLogPath(),
|
||||
dirname: (targetPath: string) => deps.dirname(targetPath),
|
||||
mkdir: (targetPath: string, options: { recursive: boolean }) => deps.mkdir(targetPath, options),
|
||||
appendFile: (targetPath: string, data: string, options: { encoding: 'utf8' }) =>
|
||||
deps.appendFile(targetPath, data, options),
|
||||
now: () => deps.now(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildShowMpvOsdMainDepsHandler(deps: ShowMpvOsdMainDeps) {
|
||||
return (): ShowMpvOsdMainDeps => ({
|
||||
appendToMpvLog: (message: string) => deps.appendToMpvLog(message),
|
||||
showMpvOsdRuntime: (mpvClient, text, fallbackLog) =>
|
||||
deps.showMpvOsdRuntime(mpvClient, text, fallbackLog),
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
logInfo: (line: string) => deps.logInfo(line),
|
||||
});
|
||||
}
|
||||
@@ -1,27 +1,17 @@
|
||||
import { createAppendToMpvLogHandler, createShowMpvOsdHandler } from './mpv-osd-log';
|
||||
import {
|
||||
createBuildAppendToMpvLogMainDepsHandler,
|
||||
createBuildShowMpvOsdMainDepsHandler,
|
||||
} from './mpv-osd-log-main-deps';
|
||||
|
||||
type AppendToMpvLogMainDeps = Parameters<typeof createBuildAppendToMpvLogMainDepsHandler>[0];
|
||||
type ShowMpvOsdMainDeps = Parameters<typeof createBuildShowMpvOsdMainDepsHandler>[0];
|
||||
type AppendToMpvLogMainDeps = Parameters<typeof createAppendToMpvLogHandler>[0];
|
||||
type ShowMpvOsdMainDeps = Parameters<typeof createShowMpvOsdHandler>[0];
|
||||
|
||||
export function createMpvOsdRuntimeHandlers(deps: {
|
||||
appendToMpvLogMainDeps: AppendToMpvLogMainDeps;
|
||||
buildShowMpvOsdMainDeps: (appendToMpvLog: (message: string) => void) => ShowMpvOsdMainDeps;
|
||||
}) {
|
||||
const appendToMpvLogMainDeps = createBuildAppendToMpvLogMainDepsHandler(
|
||||
deps.appendToMpvLogMainDeps,
|
||||
)();
|
||||
const appendToMpvLogRuntime = createAppendToMpvLogHandler(appendToMpvLogMainDeps);
|
||||
const appendToMpvLogRuntime = createAppendToMpvLogHandler(deps.appendToMpvLogMainDeps);
|
||||
const appendToMpvLog = (message: string) => appendToMpvLogRuntime.appendToMpvLog(message);
|
||||
const flushMpvLog = async () => appendToMpvLogRuntime.flushMpvLog();
|
||||
|
||||
const showMpvOsdMainDeps = createBuildShowMpvOsdMainDepsHandler(
|
||||
deps.buildShowMpvOsdMainDeps(appendToMpvLog),
|
||||
)();
|
||||
const showMpvOsdHandler = createShowMpvOsdHandler(showMpvOsdMainDeps);
|
||||
const showMpvOsdHandler = createShowMpvOsdHandler(deps.buildShowMpvOsdMainDeps(appendToMpvLog));
|
||||
const showMpvOsd = (text: string) => showMpvOsdHandler(text);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import type { createUpdateMpvSubtitleRenderMetricsHandler } from './mpv-subtitle-render-metrics';
|
||||
|
||||
type UpdateMpvSubtitleRenderMetricsMainDeps = Parameters<
|
||||
typeof createUpdateMpvSubtitleRenderMetricsHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildUpdateMpvSubtitleRenderMetricsMainDepsHandler(
|
||||
deps: UpdateMpvSubtitleRenderMetricsMainDeps,
|
||||
) {
|
||||
return (): UpdateMpvSubtitleRenderMetricsMainDeps => ({
|
||||
getCurrentMetrics: () => deps.getCurrentMetrics(),
|
||||
setCurrentMetrics: (metrics) => deps.setCurrentMetrics(metrics),
|
||||
applyPatch: (current, patch) => deps.applyPatch(current, patch),
|
||||
broadcastMetrics: (metrics) => deps.broadcastMetrics(metrics),
|
||||
});
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import type { NumericShortcutRuntimeOptions } from '../../core/services/numeric-shortcut';
|
||||
|
||||
export function createBuildNumericShortcutRuntimeMainDepsHandler(
|
||||
deps: NumericShortcutRuntimeOptions,
|
||||
) {
|
||||
return (): NumericShortcutRuntimeOptions => ({
|
||||
globalShortcut: deps.globalShortcut,
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
setTimer: (handler: () => void, timeoutMs: number) => deps.setTimer(handler, timeoutMs),
|
||||
clearTimer: (timer: ReturnType<typeof setTimeout>) => deps.clearTimer(timer),
|
||||
});
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import type {
|
||||
createCancelNumericShortcutSessionHandler,
|
||||
createStartNumericShortcutSessionHandler,
|
||||
} from './numeric-shortcut-session-handlers';
|
||||
|
||||
type CancelNumericShortcutSessionMainDeps = Parameters<
|
||||
typeof createCancelNumericShortcutSessionHandler
|
||||
>[0];
|
||||
type StartNumericShortcutSessionMainDeps = Parameters<
|
||||
typeof createStartNumericShortcutSessionHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildCancelNumericShortcutSessionMainDepsHandler(
|
||||
deps: CancelNumericShortcutSessionMainDeps,
|
||||
) {
|
||||
return (): CancelNumericShortcutSessionMainDeps => ({
|
||||
session: deps.session,
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildStartNumericShortcutSessionMainDepsHandler(
|
||||
deps: StartNumericShortcutSessionMainDeps,
|
||||
) {
|
||||
return (): StartNumericShortcutSessionMainDeps => ({
|
||||
session: deps.session,
|
||||
onDigit: (digit: number) => deps.onDigit(digit),
|
||||
messages: deps.messages,
|
||||
});
|
||||
}
|
||||
@@ -2,13 +2,9 @@ import {
|
||||
createCancelNumericShortcutSessionHandler,
|
||||
createStartNumericShortcutSessionHandler,
|
||||
} from './numeric-shortcut-session-handlers';
|
||||
import {
|
||||
createBuildCancelNumericShortcutSessionMainDepsHandler,
|
||||
createBuildStartNumericShortcutSessionMainDepsHandler,
|
||||
} from './numeric-shortcut-session-main-deps';
|
||||
|
||||
type CancelNumericShortcutSessionMainDeps = Parameters<
|
||||
typeof createBuildCancelNumericShortcutSessionMainDepsHandler
|
||||
typeof createCancelNumericShortcutSessionHandler
|
||||
>[0];
|
||||
|
||||
export function createNumericShortcutSessionRuntimeHandlers(deps: {
|
||||
@@ -19,14 +15,11 @@ export function createNumericShortcutSessionRuntimeHandlers(deps: {
|
||||
tryBeginMultiCopyOverlaySelection?: (timeoutMs: number) => boolean;
|
||||
tryBeginMineSentenceOverlaySelection?: (timeoutMs: number) => boolean;
|
||||
}) {
|
||||
const cancelPendingMultiCopyMainDeps = createBuildCancelNumericShortcutSessionMainDepsHandler({
|
||||
const cancelPendingMultiCopyHandler = createCancelNumericShortcutSessionHandler({
|
||||
session: deps.multiCopySession,
|
||||
})();
|
||||
const cancelPendingMultiCopyHandler = createCancelNumericShortcutSessionHandler(
|
||||
cancelPendingMultiCopyMainDeps,
|
||||
);
|
||||
});
|
||||
|
||||
const startPendingMultiCopyMainDeps = createBuildStartNumericShortcutSessionMainDepsHandler({
|
||||
const startPendingMultiCopyHandler = createStartNumericShortcutSessionHandler({
|
||||
session: deps.multiCopySession,
|
||||
onDigit: deps.onMultiCopyDigit,
|
||||
messages: {
|
||||
@@ -34,32 +27,21 @@ export function createNumericShortcutSessionRuntimeHandlers(deps: {
|
||||
timeout: 'Copy timeout',
|
||||
cancelled: 'Cancelled',
|
||||
},
|
||||
})();
|
||||
const startPendingMultiCopyHandler = createStartNumericShortcutSessionHandler(
|
||||
startPendingMultiCopyMainDeps,
|
||||
);
|
||||
});
|
||||
|
||||
const cancelPendingMineSentenceMultipleMainDeps =
|
||||
createBuildCancelNumericShortcutSessionMainDepsHandler({
|
||||
session: deps.mineSentenceSession,
|
||||
})();
|
||||
const cancelPendingMineSentenceMultipleHandler = createCancelNumericShortcutSessionHandler(
|
||||
cancelPendingMineSentenceMultipleMainDeps,
|
||||
);
|
||||
const cancelPendingMineSentenceMultipleHandler = createCancelNumericShortcutSessionHandler({
|
||||
session: deps.mineSentenceSession,
|
||||
});
|
||||
|
||||
const startPendingMineSentenceMultipleMainDeps =
|
||||
createBuildStartNumericShortcutSessionMainDepsHandler({
|
||||
session: deps.mineSentenceSession,
|
||||
onDigit: deps.onMineSentenceDigit,
|
||||
messages: {
|
||||
prompt: 'Mine how many lines? Press 1-9 (Esc to cancel)',
|
||||
timeout: 'Mine sentence timeout',
|
||||
cancelled: 'Cancelled',
|
||||
},
|
||||
})();
|
||||
const startPendingMineSentenceMultipleHandler = createStartNumericShortcutSessionHandler(
|
||||
startPendingMineSentenceMultipleMainDeps,
|
||||
);
|
||||
const startPendingMineSentenceMultipleHandler = createStartNumericShortcutSessionHandler({
|
||||
session: deps.mineSentenceSession,
|
||||
onDigit: deps.onMineSentenceDigit,
|
||||
messages: {
|
||||
prompt: 'Mine how many lines? Press 1-9 (Esc to cancel)',
|
||||
timeout: 'Mine sentence timeout',
|
||||
cancelled: 'Cancelled',
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
cancelPendingMultiCopy: () => cancelPendingMultiCopyHandler(),
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import type { OverlayWindowResolver } from '../overlay-runtime';
|
||||
|
||||
type OverlayContentMeasurementStoreMainDeps = {
|
||||
now: () => number;
|
||||
warn: (message: string) => void;
|
||||
};
|
||||
|
||||
export function createBuildOverlayContentMeasurementStoreMainDepsHandler(
|
||||
deps: OverlayContentMeasurementStoreMainDeps,
|
||||
) {
|
||||
return (): OverlayContentMeasurementStoreMainDeps => ({
|
||||
now: () => deps.now(),
|
||||
warn: (message: string) => deps.warn(message),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildOverlayModalRuntimeMainDepsHandler(deps: OverlayWindowResolver) {
|
||||
return (): OverlayWindowResolver => ({
|
||||
getMainWindow: () => deps.getMainWindow(),
|
||||
getModalWindow: () => deps.getModalWindow(),
|
||||
createModalWindow: () => deps.createModalWindow(),
|
||||
getModalGeometry: () => deps.getModalGeometry(),
|
||||
setModalWindowBounds: (geometry) => deps.setModalWindowBounds(geometry),
|
||||
});
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import type {
|
||||
createAppendClipboardVideoToQueueHandler,
|
||||
createHandleOverlayModalClosedHandler,
|
||||
createSetOverlayVisibleHandler,
|
||||
createToggleOverlayHandler,
|
||||
} from './overlay-main-actions';
|
||||
|
||||
type SetOverlayVisibleMainDeps = Parameters<typeof createSetOverlayVisibleHandler>[0];
|
||||
type ToggleOverlayMainDeps = Parameters<typeof createToggleOverlayHandler>[0];
|
||||
type HandleOverlayModalClosedMainDeps = Parameters<typeof createHandleOverlayModalClosedHandler>[0];
|
||||
type AppendClipboardVideoToQueueMainDeps = Parameters<
|
||||
typeof createAppendClipboardVideoToQueueHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildSetOverlayVisibleMainDepsHandler(deps: SetOverlayVisibleMainDeps) {
|
||||
return (): SetOverlayVisibleMainDeps => ({
|
||||
setVisibleOverlayVisible: (visible: boolean) => deps.setVisibleOverlayVisible(visible),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildToggleOverlayMainDepsHandler(deps: ToggleOverlayMainDeps) {
|
||||
return (): ToggleOverlayMainDeps => ({
|
||||
toggleVisibleOverlay: () => deps.toggleVisibleOverlay(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildHandleOverlayModalClosedMainDepsHandler(
|
||||
deps: HandleOverlayModalClosedMainDeps,
|
||||
) {
|
||||
return (): HandleOverlayModalClosedMainDeps => ({
|
||||
handleOverlayModalClosedRuntime: (modal) => deps.handleOverlayModalClosedRuntime(modal),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildAppendClipboardVideoToQueueMainDepsHandler(
|
||||
deps: AppendClipboardVideoToQueueMainDeps,
|
||||
) {
|
||||
return (): AppendClipboardVideoToQueueMainDeps => ({
|
||||
appendClipboardVideoToQueueRuntime: (options) =>
|
||||
deps.appendClipboardVideoToQueueRuntime(options),
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
readClipboardText: () => deps.readClipboardText(),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
sendMpvCommand: (command: (string | number)[]) => deps.sendMpvCommand(command),
|
||||
});
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
import {
|
||||
createBroadcastRuntimeOptionsChangedHandler,
|
||||
createGetRuntimeOptionsStateHandler,
|
||||
createOpenRuntimeOptionsPaletteHandler,
|
||||
createRestorePreviousSecondarySubVisibilityHandler,
|
||||
createSendToActiveOverlayWindowHandler,
|
||||
createSetOverlayDebugVisualizationEnabledHandler,
|
||||
} from './overlay-runtime-main-actions';
|
||||
|
||||
type GetRuntimeOptionsStateMainDeps = Parameters<typeof createGetRuntimeOptionsStateHandler>[0];
|
||||
type RestorePreviousSecondarySubVisibilityMainDeps = Parameters<
|
||||
typeof createRestorePreviousSecondarySubVisibilityHandler
|
||||
>[0];
|
||||
type BroadcastRuntimeOptionsChangedMainDeps = Parameters<
|
||||
typeof createBroadcastRuntimeOptionsChangedHandler
|
||||
>[0];
|
||||
type SendToActiveOverlayWindowMainDeps = Parameters<
|
||||
typeof createSendToActiveOverlayWindowHandler
|
||||
>[0];
|
||||
type SetOverlayDebugVisualizationEnabledMainDeps = Parameters<
|
||||
typeof createSetOverlayDebugVisualizationEnabledHandler
|
||||
>[0];
|
||||
type OpenRuntimeOptionsPaletteMainDeps = Parameters<
|
||||
typeof createOpenRuntimeOptionsPaletteHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildGetRuntimeOptionsStateMainDepsHandler(
|
||||
deps: GetRuntimeOptionsStateMainDeps,
|
||||
) {
|
||||
return (): GetRuntimeOptionsStateMainDeps => ({
|
||||
getRuntimeOptionsManager: () => deps.getRuntimeOptionsManager(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildRestorePreviousSecondarySubVisibilityMainDepsHandler(
|
||||
deps: RestorePreviousSecondarySubVisibilityMainDeps,
|
||||
) {
|
||||
return (): RestorePreviousSecondarySubVisibilityMainDeps => ({
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildBroadcastRuntimeOptionsChangedMainDepsHandler(
|
||||
deps: BroadcastRuntimeOptionsChangedMainDeps,
|
||||
) {
|
||||
return (): BroadcastRuntimeOptionsChangedMainDeps => ({
|
||||
broadcastRuntimeOptionsChangedRuntime: (getRuntimeOptionsState, broadcastToOverlayWindows) =>
|
||||
deps.broadcastRuntimeOptionsChangedRuntime(getRuntimeOptionsState, broadcastToOverlayWindows),
|
||||
getRuntimeOptionsState: () => deps.getRuntimeOptionsState(),
|
||||
broadcastToOverlayWindows: (channel: string, ...args: unknown[]) =>
|
||||
deps.broadcastToOverlayWindows(channel, ...args),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildSendToActiveOverlayWindowMainDepsHandler(
|
||||
deps: SendToActiveOverlayWindowMainDeps,
|
||||
) {
|
||||
return (): SendToActiveOverlayWindowMainDeps => ({
|
||||
sendToActiveOverlayWindowRuntime: (channel, payload, runtimeOptions) =>
|
||||
deps.sendToActiveOverlayWindowRuntime(channel, payload, runtimeOptions),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildSetOverlayDebugVisualizationEnabledMainDepsHandler(
|
||||
deps: SetOverlayDebugVisualizationEnabledMainDeps,
|
||||
) {
|
||||
return (): SetOverlayDebugVisualizationEnabledMainDeps => ({
|
||||
setOverlayDebugVisualizationEnabledRuntime: (currentEnabled, nextEnabled, setCurrentEnabled) =>
|
||||
deps.setOverlayDebugVisualizationEnabledRuntime(
|
||||
currentEnabled,
|
||||
nextEnabled,
|
||||
setCurrentEnabled,
|
||||
),
|
||||
getCurrentEnabled: () => deps.getCurrentEnabled(),
|
||||
setCurrentEnabled: (enabled: boolean) => deps.setCurrentEnabled(enabled),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildOpenRuntimeOptionsPaletteMainDepsHandler(
|
||||
deps: OpenRuntimeOptionsPaletteMainDeps,
|
||||
) {
|
||||
return (): OpenRuntimeOptionsPaletteMainDeps => ({
|
||||
openRuntimeOptionsPaletteRuntime: () => deps.openRuntimeOptionsPaletteRuntime(),
|
||||
});
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import type {
|
||||
createRefreshOverlayShortcutsHandler,
|
||||
createRegisterOverlayShortcutsHandler,
|
||||
createSyncOverlayShortcutsHandler,
|
||||
createUnregisterOverlayShortcutsHandler,
|
||||
} from './overlay-shortcuts-lifecycle';
|
||||
|
||||
type RegisterOverlayShortcutsMainDeps = Parameters<typeof createRegisterOverlayShortcutsHandler>[0];
|
||||
type UnregisterOverlayShortcutsMainDeps = Parameters<
|
||||
typeof createUnregisterOverlayShortcutsHandler
|
||||
>[0];
|
||||
type SyncOverlayShortcutsMainDeps = Parameters<typeof createSyncOverlayShortcutsHandler>[0];
|
||||
type RefreshOverlayShortcutsMainDeps = Parameters<typeof createRefreshOverlayShortcutsHandler>[0];
|
||||
|
||||
export function createBuildRegisterOverlayShortcutsMainDepsHandler(
|
||||
deps: RegisterOverlayShortcutsMainDeps,
|
||||
) {
|
||||
return (): RegisterOverlayShortcutsMainDeps => ({
|
||||
overlayShortcutsRuntime: deps.overlayShortcutsRuntime,
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildUnregisterOverlayShortcutsMainDepsHandler(
|
||||
deps: UnregisterOverlayShortcutsMainDeps,
|
||||
) {
|
||||
return (): UnregisterOverlayShortcutsMainDeps => ({
|
||||
overlayShortcutsRuntime: deps.overlayShortcutsRuntime,
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildSyncOverlayShortcutsMainDepsHandler(deps: SyncOverlayShortcutsMainDeps) {
|
||||
return (): SyncOverlayShortcutsMainDeps => ({
|
||||
overlayShortcutsRuntime: deps.overlayShortcutsRuntime,
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildRefreshOverlayShortcutsMainDepsHandler(
|
||||
deps: RefreshOverlayShortcutsMainDeps,
|
||||
) {
|
||||
return (): RefreshOverlayShortcutsMainDeps => ({
|
||||
overlayShortcutsRuntime: deps.overlayShortcutsRuntime,
|
||||
});
|
||||
}
|
||||
@@ -4,46 +4,26 @@ import {
|
||||
createSyncOverlayShortcutsHandler,
|
||||
createUnregisterOverlayShortcutsHandler,
|
||||
} from './overlay-shortcuts-lifecycle';
|
||||
import {
|
||||
createBuildRefreshOverlayShortcutsMainDepsHandler,
|
||||
createBuildRegisterOverlayShortcutsMainDepsHandler,
|
||||
createBuildSyncOverlayShortcutsMainDepsHandler,
|
||||
createBuildUnregisterOverlayShortcutsMainDepsHandler,
|
||||
} from './overlay-shortcuts-lifecycle-main-deps';
|
||||
|
||||
type RegisterOverlayShortcutsMainDeps = Parameters<
|
||||
typeof createBuildRegisterOverlayShortcutsMainDepsHandler
|
||||
>[0];
|
||||
type RegisterOverlayShortcutsMainDeps = Parameters<typeof createRegisterOverlayShortcutsHandler>[0];
|
||||
|
||||
export function createOverlayShortcutsRuntimeHandlers(deps: {
|
||||
overlayShortcutsRuntimeMainDeps: RegisterOverlayShortcutsMainDeps;
|
||||
}) {
|
||||
const registerOverlayShortcutsMainDeps = createBuildRegisterOverlayShortcutsMainDepsHandler(
|
||||
deps.overlayShortcutsRuntimeMainDeps,
|
||||
)();
|
||||
const registerOverlayShortcutsHandler = createRegisterOverlayShortcutsHandler(
|
||||
registerOverlayShortcutsMainDeps,
|
||||
deps.overlayShortcutsRuntimeMainDeps,
|
||||
);
|
||||
|
||||
const unregisterOverlayShortcutsMainDeps = createBuildUnregisterOverlayShortcutsMainDepsHandler(
|
||||
deps.overlayShortcutsRuntimeMainDeps,
|
||||
)();
|
||||
const unregisterOverlayShortcutsHandler = createUnregisterOverlayShortcutsHandler(
|
||||
unregisterOverlayShortcutsMainDeps,
|
||||
deps.overlayShortcutsRuntimeMainDeps,
|
||||
);
|
||||
|
||||
const syncOverlayShortcutsMainDeps = createBuildSyncOverlayShortcutsMainDepsHandler(
|
||||
deps.overlayShortcutsRuntimeMainDeps,
|
||||
)();
|
||||
const syncOverlayShortcutsHandler = createSyncOverlayShortcutsHandler(
|
||||
syncOverlayShortcutsMainDeps,
|
||||
deps.overlayShortcutsRuntimeMainDeps,
|
||||
);
|
||||
|
||||
const refreshOverlayShortcutsMainDeps = createBuildRefreshOverlayShortcutsMainDepsHandler(
|
||||
deps.overlayShortcutsRuntimeMainDeps,
|
||||
)();
|
||||
const refreshOverlayShortcutsHandler = createRefreshOverlayShortcutsHandler(
|
||||
refreshOverlayShortcutsMainDeps,
|
||||
deps.overlayShortcutsRuntimeMainDeps,
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -7,10 +7,6 @@ import {
|
||||
createBuildToggleVisibleOverlayMainDepsHandler,
|
||||
} from './overlay-visibility-actions-main-deps';
|
||||
import { createSetOverlayVisibleHandler, createToggleOverlayHandler } from './overlay-main-actions';
|
||||
import {
|
||||
createBuildSetOverlayVisibleMainDepsHandler,
|
||||
createBuildToggleOverlayMainDepsHandler,
|
||||
} from './overlay-main-actions-main-deps';
|
||||
|
||||
type SetVisibleOverlayVisibleMainDeps = Parameters<
|
||||
typeof createBuildSetVisibleOverlayVisibleMainDepsHandler
|
||||
@@ -36,15 +32,13 @@ export function createOverlayVisibilityRuntime(deps: OverlayVisibilityRuntimeDep
|
||||
})();
|
||||
const toggleVisibleOverlay = createToggleVisibleOverlayHandler(toggleVisibleOverlayMainDeps);
|
||||
|
||||
const setOverlayVisibleMainDeps = createBuildSetOverlayVisibleMainDepsHandler({
|
||||
const setOverlayVisible = createSetOverlayVisibleHandler({
|
||||
setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible),
|
||||
})();
|
||||
const setOverlayVisible = createSetOverlayVisibleHandler(setOverlayVisibleMainDeps);
|
||||
});
|
||||
|
||||
const toggleOverlayMainDeps = createBuildToggleOverlayMainDepsHandler({
|
||||
const toggleOverlay = createToggleOverlayHandler({
|
||||
toggleVisibleOverlay: () => toggleVisibleOverlay(),
|
||||
})();
|
||||
const toggleOverlay = createToggleOverlayHandler(toggleOverlayMainDeps);
|
||||
});
|
||||
|
||||
return {
|
||||
setVisibleOverlayVisible,
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import type { AnilistStateRuntimeDeps } from './anilist-state';
|
||||
import type { ConfigDerivedRuntimeDeps } from './config-derived';
|
||||
import type { ImmersionMediaRuntimeDeps } from './immersion-media';
|
||||
import type { MainSubsyncRuntimeDeps } from './subsync-runtime';
|
||||
|
||||
export function createBuildImmersionMediaRuntimeMainDepsHandler(deps: ImmersionMediaRuntimeDeps) {
|
||||
return (): ImmersionMediaRuntimeDeps => ({
|
||||
getResolvedConfig: () => deps.getResolvedConfig(),
|
||||
defaultImmersionDbPath: deps.defaultImmersionDbPath,
|
||||
getTracker: () => deps.getTracker(),
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
getCurrentMediaPath: () => deps.getCurrentMediaPath(),
|
||||
getCurrentMediaTitle: () => deps.getCurrentMediaTitle(),
|
||||
sleep: deps.sleep,
|
||||
seedWaitMs: deps.seedWaitMs,
|
||||
seedAttempts: deps.seedAttempts,
|
||||
logDebug: (message: string) => deps.logDebug(message),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildAnilistStateRuntimeMainDepsHandler(deps: AnilistStateRuntimeDeps) {
|
||||
return (): AnilistStateRuntimeDeps => ({
|
||||
getClientSecretState: () => deps.getClientSecretState(),
|
||||
setClientSecretState: (next) => deps.setClientSecretState(next),
|
||||
getRetryQueueState: () => deps.getRetryQueueState(),
|
||||
setRetryQueueState: (next) => deps.setRetryQueueState(next),
|
||||
getUpdateQueueSnapshot: () => deps.getUpdateQueueSnapshot(),
|
||||
clearStoredToken: () => deps.clearStoredToken(),
|
||||
clearCachedAccessToken: () => deps.clearCachedAccessToken(),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildConfigDerivedRuntimeMainDepsHandler(deps: ConfigDerivedRuntimeDeps) {
|
||||
return (): ConfigDerivedRuntimeDeps => ({
|
||||
getResolvedConfig: () => deps.getResolvedConfig(),
|
||||
getRuntimeOptionsManager: () => deps.getRuntimeOptionsManager(),
|
||||
defaultJimakuLanguagePreference: deps.defaultJimakuLanguagePreference,
|
||||
defaultJimakuMaxEntryResults: deps.defaultJimakuMaxEntryResults,
|
||||
defaultJimakuApiBaseUrl: deps.defaultJimakuApiBaseUrl,
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildMainSubsyncRuntimeMainDepsHandler(deps: MainSubsyncRuntimeDeps) {
|
||||
return (): MainSubsyncRuntimeDeps => ({
|
||||
getMpvClient: () => deps.getMpvClient(),
|
||||
getResolvedConfig: () => deps.getResolvedConfig(),
|
||||
getSubsyncInProgress: () => deps.getSubsyncInProgress(),
|
||||
setSubsyncInProgress: (inProgress: boolean) => deps.setSubsyncInProgress(inProgress),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
openManualPicker: (payload) => deps.openManualPicker(payload),
|
||||
});
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import type { SecondarySubMode } from '../../types';
|
||||
|
||||
export function createBuildCycleSecondarySubModeMainDepsHandler(deps: {
|
||||
getSecondarySubMode: () => SecondarySubMode;
|
||||
setSecondarySubMode: (mode: SecondarySubMode) => void;
|
||||
getLastSecondarySubToggleAtMs: () => number;
|
||||
setLastSecondarySubToggleAtMs: (timestampMs: number) => void;
|
||||
broadcastToOverlayWindows: (channel: string, mode: SecondarySubMode) => void;
|
||||
showMpvOsd: (text: string) => void;
|
||||
}) {
|
||||
return () => ({
|
||||
getSecondarySubMode: () => deps.getSecondarySubMode(),
|
||||
setSecondarySubMode: (mode: SecondarySubMode) => deps.setSecondarySubMode(mode),
|
||||
getLastSecondarySubToggleAtMs: () => deps.getLastSecondarySubToggleAtMs(),
|
||||
setLastSecondarySubToggleAtMs: (timestampMs: number) =>
|
||||
deps.setLastSecondarySubToggleAtMs(timestampMs),
|
||||
broadcastSecondarySubMode: (mode: SecondarySubMode) =>
|
||||
deps.broadcastToOverlayWindows('secondary-subtitle:mode', mode),
|
||||
showMpvOsd: (text: string) => deps.showMpvOsd(text),
|
||||
});
|
||||
}
|
||||
@@ -1,18 +1,8 @@
|
||||
import { createBuildCycleSecondarySubModeMainDepsHandler } from './secondary-sub-mode-main-deps';
|
||||
|
||||
type CycleSecondarySubModeMainDeps = Parameters<
|
||||
typeof createBuildCycleSecondarySubModeMainDepsHandler
|
||||
>[0];
|
||||
type CycleSecondarySubModeDeps = ReturnType<
|
||||
ReturnType<typeof createBuildCycleSecondarySubModeMainDepsHandler>
|
||||
>;
|
||||
import type { CycleSecondarySubModeDeps } from '../../core/services/subtitle-position';
|
||||
|
||||
export function createCycleSecondarySubModeRuntimeHandler(deps: {
|
||||
cycleSecondarySubModeMainDeps: CycleSecondarySubModeMainDeps;
|
||||
cycleSecondarySubModeMainDeps: CycleSecondarySubModeDeps;
|
||||
cycleSecondarySubMode: (deps: CycleSecondarySubModeDeps) => void;
|
||||
}) {
|
||||
const buildCycleSecondarySubModeMainDepsHandler = createBuildCycleSecondarySubModeMainDepsHandler(
|
||||
deps.cycleSecondarySubModeMainDeps,
|
||||
);
|
||||
return () => deps.cycleSecondarySubMode(buildCycleSecondarySubModeMainDepsHandler());
|
||||
return () => deps.cycleSecondarySubMode(deps.cycleSecondarySubModeMainDeps);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import type { createCriticalConfigErrorHandler, createReloadConfigHandler } from './startup-config';
|
||||
|
||||
type ReloadConfigMainDeps = Parameters<typeof createReloadConfigHandler>[0];
|
||||
type CriticalConfigErrorMainDeps = Parameters<typeof createCriticalConfigErrorHandler>[0];
|
||||
|
||||
export function createBuildReloadConfigMainDepsHandler(deps: ReloadConfigMainDeps) {
|
||||
return (): ReloadConfigMainDeps => ({
|
||||
reloadConfigStrict: () => deps.reloadConfigStrict(),
|
||||
logInfo: (message: string) => deps.logInfo(message),
|
||||
logDebug: (message: string) => deps.logDebug(message),
|
||||
logWarning: (message: string) => deps.logWarning(message),
|
||||
showDesktopNotification: (title: string, options: { body: string }) =>
|
||||
deps.showDesktopNotification(title, options),
|
||||
startConfigHotReload: () => deps.startConfigHotReload(),
|
||||
shouldRefreshAnilistClientSecretState: deps.shouldRefreshAnilistClientSecretState
|
||||
? () => deps.shouldRefreshAnilistClientSecretState?.() !== false
|
||||
: undefined,
|
||||
refreshAnilistClientSecretState: (options: { force: boolean }) =>
|
||||
deps.refreshAnilistClientSecretState(options),
|
||||
failHandlers: {
|
||||
logError: (details: string) => deps.failHandlers.logError(details),
|
||||
showErrorBox: (title: string, details: string) =>
|
||||
deps.failHandlers.showErrorBox(title, details),
|
||||
setExitCode: deps.failHandlers.setExitCode
|
||||
? (code: number) => deps.failHandlers.setExitCode?.(code)
|
||||
: undefined,
|
||||
quit: () => deps.failHandlers.quit(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildCriticalConfigErrorMainDepsHandler(deps: CriticalConfigErrorMainDeps) {
|
||||
return (): CriticalConfigErrorMainDeps => ({
|
||||
getConfigPath: () => deps.getConfigPath(),
|
||||
failHandlers: {
|
||||
logError: (details: string) => deps.failHandlers.logError(details),
|
||||
showErrorBox: (title: string, details: string) =>
|
||||
deps.failHandlers.showErrorBox(title, details),
|
||||
setExitCode: deps.failHandlers.setExitCode
|
||||
? (code: number) => deps.failHandlers.setExitCode?.(code)
|
||||
: undefined,
|
||||
quit: () => deps.failHandlers.quit(),
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import type { AppLifecycleRuntimeRunnerParams } from '../startup-lifecycle';
|
||||
|
||||
export function createBuildAppLifecycleRuntimeRunnerMainDepsHandler(
|
||||
deps: AppLifecycleRuntimeRunnerParams,
|
||||
) {
|
||||
return (): AppLifecycleRuntimeRunnerParams => ({
|
||||
app: deps.app,
|
||||
platform: deps.platform,
|
||||
shouldStartApp: deps.shouldStartApp,
|
||||
parseArgs: deps.parseArgs,
|
||||
handleCliCommand: deps.handleCliCommand,
|
||||
printHelp: deps.printHelp,
|
||||
logNoRunningInstance: deps.logNoRunningInstance,
|
||||
startControlServer: deps.startControlServer,
|
||||
onReady: deps.onReady,
|
||||
onWillQuitCleanup: deps.onWillQuitCleanup,
|
||||
shouldRestoreWindowsOnActivate: deps.shouldRestoreWindowsOnActivate,
|
||||
restoreWindowsOnActivate: deps.restoreWindowsOnActivate,
|
||||
shouldQuitOnWindowAllClosed: deps.shouldQuitOnWindowAllClosed,
|
||||
});
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
import { createBuildStartupBootstrapRuntimeFactoryDepsHandler } from './startup-bootstrap-deps-builder';
|
||||
import { createBuildAppLifecycleRuntimeRunnerMainDepsHandler } from './startup-lifecycle-main-deps';
|
||||
import type { AppLifecycleRuntimeRunnerParams } from '../startup-lifecycle';
|
||||
import { createBuildStartupBootstrapMainDepsHandler } from './startup-bootstrap-main-deps';
|
||||
|
||||
type AppLifecycleRuntimeRunnerMainDeps = Parameters<
|
||||
typeof createBuildAppLifecycleRuntimeRunnerMainDepsHandler
|
||||
>[0];
|
||||
type StartupBootstrapMainDeps = Parameters<typeof createBuildStartupBootstrapMainDepsHandler>[0];
|
||||
type StartupBootstrapRuntimeFactoryDeps = Parameters<
|
||||
typeof createBuildStartupBootstrapRuntimeFactoryDepsHandler
|
||||
@@ -15,9 +12,9 @@ export function createStartupRuntimeHandlers<
|
||||
TStartupState,
|
||||
TStartupBootstrapRuntimeDeps = unknown,
|
||||
>(deps: {
|
||||
appLifecycleRuntimeRunnerMainDeps: AppLifecycleRuntimeRunnerMainDeps;
|
||||
appLifecycleRuntimeRunnerMainDeps: AppLifecycleRuntimeRunnerParams;
|
||||
createAppLifecycleRuntimeRunner: (
|
||||
params: AppLifecycleRuntimeRunnerMainDeps,
|
||||
params: AppLifecycleRuntimeRunnerParams,
|
||||
) => (args: TCliArgs) => void;
|
||||
buildStartupBootstrapMainDeps: (
|
||||
startAppLifecycle: (args: TCliArgs) => void,
|
||||
@@ -28,11 +25,8 @@ export function createStartupRuntimeHandlers<
|
||||
runStartupBootstrapRuntime: (deps: TStartupBootstrapRuntimeDeps) => TStartupState;
|
||||
applyStartupState: (startupState: TStartupState) => void;
|
||||
}) {
|
||||
const appLifecycleRuntimeRunnerMainDeps = createBuildAppLifecycleRuntimeRunnerMainDepsHandler(
|
||||
deps.appLifecycleRuntimeRunnerMainDeps,
|
||||
)();
|
||||
const appLifecycleRuntimeRunner = deps.createAppLifecycleRuntimeRunner(
|
||||
appLifecycleRuntimeRunnerMainDeps,
|
||||
deps.appLifecycleRuntimeRunnerMainDeps,
|
||||
);
|
||||
|
||||
const startupBootstrapMainDeps = createBuildStartupBootstrapMainDepsHandler(
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import type {
|
||||
createLaunchBackgroundWarmupTaskHandler,
|
||||
createStartBackgroundWarmupsHandler,
|
||||
} from './startup-warmups';
|
||||
|
||||
type LaunchBackgroundWarmupTaskMainDeps = Parameters<
|
||||
typeof createLaunchBackgroundWarmupTaskHandler
|
||||
>[0];
|
||||
type StartBackgroundWarmupsMainDeps = Parameters<typeof createStartBackgroundWarmupsHandler>[0];
|
||||
|
||||
export function createBuildLaunchBackgroundWarmupTaskMainDepsHandler(
|
||||
deps: LaunchBackgroundWarmupTaskMainDeps,
|
||||
) {
|
||||
return (): LaunchBackgroundWarmupTaskMainDeps => ({
|
||||
now: () => deps.now(),
|
||||
logDebug: (message: string) => deps.logDebug(message),
|
||||
logWarn: (message: string) => deps.logWarn(message),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildStartBackgroundWarmupsMainDepsHandler(
|
||||
deps: StartBackgroundWarmupsMainDeps,
|
||||
) {
|
||||
return (): StartBackgroundWarmupsMainDeps => ({
|
||||
getStarted: () => deps.getStarted(),
|
||||
setStarted: (started: boolean) => deps.setStarted(started),
|
||||
isTexthookerOnlyMode: () => deps.isTexthookerOnlyMode(),
|
||||
launchTask: (label: string, task: () => Promise<void>) => deps.launchTask(label, task),
|
||||
createMecabTokenizerAndCheck: () => deps.createMecabTokenizerAndCheck(),
|
||||
ensureYomitanExtensionLoaded: () => deps.ensureYomitanExtensionLoaded(),
|
||||
prewarmSubtitleDictionaries: () => deps.prewarmSubtitleDictionaries(),
|
||||
shouldWarmupMecab: () => deps.shouldWarmupMecab(),
|
||||
shouldWarmupYomitanExtension: () => deps.shouldWarmupYomitanExtension(),
|
||||
shouldWarmupSubtitleDictionaries: () => deps.shouldWarmupSubtitleDictionaries(),
|
||||
shouldWarmupJellyfinRemoteSession: () => deps.shouldWarmupJellyfinRemoteSession(),
|
||||
shouldAutoConnectJellyfinRemote: () => deps.shouldAutoConnectJellyfinRemote(),
|
||||
startJellyfinRemoteSession: () => deps.startJellyfinRemoteSession(),
|
||||
...(deps.onYomitanExtensionWarmupScheduled
|
||||
? {
|
||||
onYomitanExtensionWarmupScheduled: (promise: Promise<void>) =>
|
||||
deps.onYomitanExtensionWarmupScheduled!(promise),
|
||||
}
|
||||
: {}),
|
||||
...(deps.onTokenizationWarmupScheduled
|
||||
? {
|
||||
onTokenizationWarmupScheduled: (promise: Promise<void>) =>
|
||||
deps.onTokenizationWarmupScheduled!(promise),
|
||||
}
|
||||
: {}),
|
||||
logDebug: deps.logDebug,
|
||||
});
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import type {
|
||||
createLoadSubtitlePositionHandler,
|
||||
createSaveSubtitlePositionHandler,
|
||||
} from './subtitle-position';
|
||||
|
||||
type LoadSubtitlePositionMainDeps = Parameters<typeof createLoadSubtitlePositionHandler>[0];
|
||||
type SaveSubtitlePositionMainDeps = Parameters<typeof createSaveSubtitlePositionHandler>[0];
|
||||
|
||||
export function createBuildLoadSubtitlePositionMainDepsHandler(deps: LoadSubtitlePositionMainDeps) {
|
||||
return (): LoadSubtitlePositionMainDeps => ({
|
||||
loadSubtitlePositionCore: () => deps.loadSubtitlePositionCore(),
|
||||
setSubtitlePosition: (position) => deps.setSubtitlePosition(position),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildSaveSubtitlePositionMainDepsHandler(deps: SaveSubtitlePositionMainDeps) {
|
||||
return (): SaveSubtitlePositionMainDeps => ({
|
||||
saveSubtitlePositionCore: (position) => deps.saveSubtitlePositionCore(position),
|
||||
setSubtitlePosition: (position) => deps.setSubtitlePosition(position),
|
||||
});
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import type { SubtitleProcessingControllerDeps } from '../../core/services/subtitle-processing-controller';
|
||||
|
||||
export function createBuildSubtitleProcessingControllerMainDepsHandler(
|
||||
deps: SubtitleProcessingControllerDeps,
|
||||
) {
|
||||
return (): SubtitleProcessingControllerDeps => ({
|
||||
tokenizeSubtitle: (text: string) => deps.tokenizeSubtitle(text),
|
||||
emitSubtitle: (payload) => deps.emitSubtitle(payload),
|
||||
onProcessingSettled: () => deps.onProcessingSettled?.(),
|
||||
logDebug: deps.logDebug,
|
||||
now: deps.now,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createPrefetchAwareSubtitleProcessingController } from './subtitle-processing-runtime';
|
||||
import type { SubtitleData } from '../../types';
|
||||
|
||||
function flushMicrotasks(): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, 0));
|
||||
}
|
||||
|
||||
function createHarness() {
|
||||
const events: string[] = [];
|
||||
let resolveTokenization: ((value: SubtitleData | null) => void) | undefined;
|
||||
const controller = createPrefetchAwareSubtitleProcessingController({
|
||||
tokenizeSubtitle: () =>
|
||||
new Promise<SubtitleData | null>((resolve) => {
|
||||
resolveTokenization = resolve;
|
||||
}),
|
||||
emitSubtitlePayload: (payload, options) =>
|
||||
events.push(
|
||||
`emit:${payload.text}:tokens=${payload.tokens ? 'yes' : 'no'}:resume=${options.resumePrefetch}`,
|
||||
),
|
||||
resumePrefetch: () => events.push('resume'),
|
||||
logDebug: () => {},
|
||||
now: () => 0,
|
||||
});
|
||||
return {
|
||||
events,
|
||||
controller,
|
||||
resolveTokenization: (value: SubtitleData | null) => resolveTokenization?.(value),
|
||||
};
|
||||
}
|
||||
|
||||
test('subtitle processing resumes prefetch after the tokenized emit settles', async () => {
|
||||
const { events, controller, resolveTokenization } = createHarness();
|
||||
|
||||
controller.onSubtitleChange('一行目');
|
||||
await flushMicrotasks();
|
||||
// The provisional plain payload is out, but tokenization is still pending.
|
||||
assert.deepEqual(events, ['emit:一行目:tokens=no:resume=false']);
|
||||
|
||||
resolveTokenization({ text: '一行目', tokens: [] });
|
||||
await flushMicrotasks();
|
||||
await flushMicrotasks();
|
||||
assert.deepEqual(events, [
|
||||
'emit:一行目:tokens=no:resume=false',
|
||||
'emit:一行目:tokens=yes:resume=false',
|
||||
'resume',
|
||||
]);
|
||||
});
|
||||
|
||||
test('subtitle processing resumes prefetch when tokenization fails without another emit', async () => {
|
||||
const { events, controller, resolveTokenization } = createHarness();
|
||||
|
||||
controller.onSubtitleChange('一行目');
|
||||
await flushMicrotasks();
|
||||
assert.deepEqual(events, ['emit:一行目:tokens=no:resume=false']);
|
||||
|
||||
resolveTokenization(null);
|
||||
await flushMicrotasks();
|
||||
await flushMicrotasks();
|
||||
assert.deepEqual(events, ['emit:一行目:tokens=no:resume=false', 'resume']);
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import {
|
||||
createSubtitleProcessingController,
|
||||
type SubtitleProcessingControllerDeps,
|
||||
} from '../../core/services/subtitle-processing-controller';
|
||||
import type { SubtitleData } from '../../types';
|
||||
|
||||
/**
|
||||
* Creates the main-process subtitle processing controller and ties it to the
|
||||
* subtitle prefetch pause.
|
||||
*
|
||||
* Controller emits never release the prefetch pause: the first emit for an
|
||||
* uncached line is the provisional plain payload, sent before tokenization
|
||||
* starts, so resuming on it would put prefetch back in contention with the
|
||||
* on-screen line for the single parser window. The pause is released once the
|
||||
* controller has no work left, which covers the runs that end without an emit
|
||||
* (suppressed duplicate, failed tokenization) as well as the ones that deliver
|
||||
* a payload.
|
||||
*/
|
||||
export function createPrefetchAwareSubtitleProcessingController(deps: {
|
||||
tokenizeSubtitle: SubtitleProcessingControllerDeps['tokenizeSubtitle'];
|
||||
emitSubtitlePayload: (payload: SubtitleData, options: { resumePrefetch: boolean }) => void;
|
||||
resumePrefetch: () => void;
|
||||
logDebug: (message: string) => void;
|
||||
now: () => number;
|
||||
}) {
|
||||
return createSubtitleProcessingController({
|
||||
tokenizeSubtitle: deps.tokenizeSubtitle,
|
||||
emitSubtitle: (payload) => deps.emitSubtitlePayload(payload, { resumePrefetch: false }),
|
||||
onProcessingSettled: () => deps.resumePrefetch(),
|
||||
logDebug: deps.logDebug,
|
||||
now: deps.now,
|
||||
});
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
import type { DictionaryBackend } from '../../types/config';
|
||||
|
||||
export function createBuildResolveTrayIconPathMainDepsHandler(deps: {
|
||||
resolveTrayIconPathRuntime: (options: {
|
||||
platform: string;
|
||||
resourcesPath: string;
|
||||
appPath: string;
|
||||
dirname: string;
|
||||
joinPath: (...parts: string[]) => string;
|
||||
fileExists: (path: string) => boolean;
|
||||
}) => string | null;
|
||||
platform: string;
|
||||
resourcesPath: string;
|
||||
appPath: string;
|
||||
dirname: string;
|
||||
joinPath: (...parts: string[]) => string;
|
||||
fileExists: (path: string) => boolean;
|
||||
}) {
|
||||
return () => ({
|
||||
resolveTrayIconPathRuntime: deps.resolveTrayIconPathRuntime,
|
||||
platform: deps.platform,
|
||||
resourcesPath: deps.resourcesPath,
|
||||
appPath: deps.appPath,
|
||||
dirname: deps.dirname,
|
||||
joinPath: deps.joinPath,
|
||||
fileExists: deps.fileExists,
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildTrayMenuTemplateMainDepsHandler<TMenuItem>(deps: {
|
||||
buildTrayMenuTemplateRuntime: (handlers: {
|
||||
platform?: string;
|
||||
openSessionHelp: () => void;
|
||||
openChangelog: () => void;
|
||||
openTexthookerInBrowser: () => void;
|
||||
showTexthookerPage: boolean;
|
||||
openFirstRunSetup: () => void;
|
||||
showFirstRunSetup: boolean;
|
||||
openWindowsMpvLauncherSetup: () => void;
|
||||
showWindowsMpvLauncherSetup: boolean;
|
||||
dictionaryBackend: DictionaryBackend;
|
||||
openHachidoriSettings: () => void;
|
||||
openYomitanSettings: () => void;
|
||||
openConfigSettings: () => void;
|
||||
openSyncUi: () => void;
|
||||
openYoutubeBrowser: () => void;
|
||||
exportLogs: () => void;
|
||||
openJellyfinSetup: () => void;
|
||||
showJellyfinDiscovery: boolean;
|
||||
jellyfinDiscoveryActive: boolean;
|
||||
toggleJellyfinDiscovery: (checked: boolean) => void;
|
||||
openAnilistSetup: () => void;
|
||||
checkForUpdates: () => void;
|
||||
quitApp: () => void;
|
||||
}) => TMenuItem[];
|
||||
initializeOverlayRuntime: () => void;
|
||||
isOverlayRuntimeInitialized: () => boolean;
|
||||
openSessionHelpModal: () => void;
|
||||
openChangelogModal: () => void;
|
||||
openTexthookerInBrowser: () => void;
|
||||
showTexthookerPage: () => boolean;
|
||||
showFirstRunSetup: () => boolean;
|
||||
openFirstRunSetupWindow: (force?: boolean) => void;
|
||||
showWindowsMpvLauncherSetup: () => boolean;
|
||||
getDictionaryBackend: () => DictionaryBackend;
|
||||
openHachidoriSettings: () => void;
|
||||
openYomitanSettings: () => void;
|
||||
openConfigSettingsWindow: () => void;
|
||||
openSyncUiWindow: () => void;
|
||||
openYoutubeBrowserWindow: () => void;
|
||||
exportLogs: () => void;
|
||||
openJellyfinSetupWindow: () => void;
|
||||
isJellyfinConfigured: () => boolean;
|
||||
isJellyfinDiscoveryActive: () => boolean;
|
||||
toggleJellyfinDiscovery: (checked: boolean) => void | Promise<void>;
|
||||
platform?: string;
|
||||
openAnilistSetupWindow: () => void;
|
||||
checkForUpdates: () => void;
|
||||
quitApp: () => void;
|
||||
}) {
|
||||
return () => ({
|
||||
buildTrayMenuTemplateRuntime: deps.buildTrayMenuTemplateRuntime,
|
||||
platform: deps.platform,
|
||||
initializeOverlayRuntime: deps.initializeOverlayRuntime,
|
||||
isOverlayRuntimeInitialized: deps.isOverlayRuntimeInitialized,
|
||||
openSessionHelpModal: deps.openSessionHelpModal,
|
||||
openChangelogModal: deps.openChangelogModal,
|
||||
openTexthookerInBrowser: deps.openTexthookerInBrowser,
|
||||
showTexthookerPage: deps.showTexthookerPage,
|
||||
showFirstRunSetup: deps.showFirstRunSetup,
|
||||
openFirstRunSetupWindow: deps.openFirstRunSetupWindow,
|
||||
showWindowsMpvLauncherSetup: deps.showWindowsMpvLauncherSetup,
|
||||
getDictionaryBackend: deps.getDictionaryBackend,
|
||||
openHachidoriSettings: deps.openHachidoriSettings,
|
||||
openYomitanSettings: deps.openYomitanSettings,
|
||||
openConfigSettingsWindow: deps.openConfigSettingsWindow,
|
||||
openSyncUiWindow: deps.openSyncUiWindow,
|
||||
openYoutubeBrowserWindow: deps.openYoutubeBrowserWindow,
|
||||
exportLogs: deps.exportLogs,
|
||||
openJellyfinSetupWindow: deps.openJellyfinSetupWindow,
|
||||
isJellyfinConfigured: deps.isJellyfinConfigured,
|
||||
isJellyfinDiscoveryActive: deps.isJellyfinDiscoveryActive,
|
||||
toggleJellyfinDiscovery: deps.toggleJellyfinDiscovery,
|
||||
openAnilistSetupWindow: deps.openAnilistSetupWindow,
|
||||
checkForUpdates: deps.checkForUpdates,
|
||||
quitApp: deps.quitApp,
|
||||
});
|
||||
}
|
||||
@@ -7,16 +7,10 @@ import {
|
||||
createBuildTrayMenuTemplateHandler,
|
||||
createResolveTrayIconPathHandler,
|
||||
} from './tray-main-actions';
|
||||
import {
|
||||
createBuildResolveTrayIconPathMainDepsHandler,
|
||||
createBuildTrayMenuTemplateMainDepsHandler,
|
||||
} from './tray-main-deps';
|
||||
|
||||
type ResolveTrayIconPathMainDeps = Parameters<
|
||||
typeof createBuildResolveTrayIconPathMainDepsHandler
|
||||
>[0];
|
||||
type ResolveTrayIconPathMainDeps = Parameters<typeof createResolveTrayIconPathHandler>[0];
|
||||
type BuildTrayMenuTemplateMainDeps<TMenuItem> = Parameters<
|
||||
typeof createBuildTrayMenuTemplateMainDepsHandler<TMenuItem>
|
||||
typeof createBuildTrayMenuTemplateHandler<TMenuItem>
|
||||
>[0];
|
||||
type EnsureTrayMainDeps<TTrayMenu> = Parameters<
|
||||
typeof createBuildEnsureTrayMainDepsHandler<TrayLike, TTrayMenu, TrayIconLike>
|
||||
@@ -32,12 +26,8 @@ export function createTrayRuntimeHandlers<TMenuItem, TMenu>(deps: {
|
||||
destroyTrayDeps: DestroyTrayMainDeps;
|
||||
buildMenuFromTemplate: (template: TMenuItem[]) => TMenu;
|
||||
}) {
|
||||
const resolveTrayIconPath = createResolveTrayIconPathHandler(
|
||||
createBuildResolveTrayIconPathMainDepsHandler(deps.resolveTrayIconPathDeps)(),
|
||||
);
|
||||
const buildTrayMenuTemplate = createBuildTrayMenuTemplateHandler(
|
||||
createBuildTrayMenuTemplateMainDepsHandler(deps.buildTrayMenuTemplateDeps)(),
|
||||
);
|
||||
const resolveTrayIconPath = createResolveTrayIconPathHandler(deps.resolveTrayIconPathDeps);
|
||||
const buildTrayMenuTemplate = createBuildTrayMenuTemplateHandler(deps.buildTrayMenuTemplateDeps);
|
||||
const buildTrayMenu = () => deps.buildMenuFromTemplate(buildTrayMenuTemplate());
|
||||
|
||||
const ensureTray = createEnsureTrayHandler(
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import type {
|
||||
createEnsureYomitanExtensionLoadedHandler,
|
||||
createLoadYomitanExtensionHandler,
|
||||
} from './yomitan-extension-loader';
|
||||
|
||||
type LoadYomitanExtensionMainDeps = Parameters<typeof createLoadYomitanExtensionHandler>[0];
|
||||
type EnsureYomitanExtensionLoadedMainDeps = Parameters<
|
||||
typeof createEnsureYomitanExtensionLoadedHandler
|
||||
>[0];
|
||||
|
||||
export function createBuildLoadYomitanExtensionMainDepsHandler(deps: LoadYomitanExtensionMainDeps) {
|
||||
return (): LoadYomitanExtensionMainDeps => ({
|
||||
loadYomitanExtensionCore: (options) => deps.loadYomitanExtensionCore(options),
|
||||
userDataPath: deps.userDataPath,
|
||||
externalProfilePath: deps.externalProfilePath,
|
||||
getYomitanParserWindow: () => deps.getYomitanParserWindow(),
|
||||
setYomitanParserWindow: (window) => deps.setYomitanParserWindow(window),
|
||||
setYomitanParserReadyPromise: (promise) => deps.setYomitanParserReadyPromise(promise),
|
||||
setYomitanParserInitPromise: (promise) => deps.setYomitanParserInitPromise(promise),
|
||||
setYomitanExtension: (extension) => deps.setYomitanExtension(extension),
|
||||
setYomitanSession: (session) => deps.setYomitanSession(session),
|
||||
});
|
||||
}
|
||||
|
||||
export function createBuildEnsureYomitanExtensionLoadedMainDepsHandler(
|
||||
deps: EnsureYomitanExtensionLoadedMainDeps,
|
||||
) {
|
||||
return (): EnsureYomitanExtensionLoadedMainDeps => ({
|
||||
getYomitanExtension: () => deps.getYomitanExtension(),
|
||||
getLoadInFlight: () => deps.getLoadInFlight(),
|
||||
setLoadInFlight: (promise) => deps.setLoadInFlight(promise),
|
||||
loadYomitanExtension: () => deps.loadYomitanExtension(),
|
||||
});
|
||||
}
|
||||
@@ -3,17 +3,11 @@ import {
|
||||
createLoadYomitanExtensionHandler,
|
||||
} from './yomitan-extension-loader';
|
||||
import type { Extension } from 'electron';
|
||||
import {
|
||||
createBuildEnsureYomitanExtensionLoadedMainDepsHandler,
|
||||
createBuildLoadYomitanExtensionMainDepsHandler,
|
||||
} from './yomitan-extension-loader-main-deps';
|
||||
|
||||
type LoadYomitanExtensionMainDeps = Parameters<
|
||||
typeof createBuildLoadYomitanExtensionMainDepsHandler
|
||||
>[0];
|
||||
type LoadYomitanExtensionMainDeps = Parameters<typeof createLoadYomitanExtensionHandler>[0];
|
||||
|
||||
type EnsureYomitanExtensionLoadedMainDeps = Omit<
|
||||
Parameters<typeof createBuildEnsureYomitanExtensionLoadedMainDepsHandler>[0],
|
||||
Parameters<typeof createEnsureYomitanExtensionLoadedHandler>[0],
|
||||
'loadYomitanExtension'
|
||||
>;
|
||||
|
||||
@@ -23,7 +17,7 @@ export type YomitanExtensionRuntimeDeps = LoadYomitanExtensionMainDeps &
|
||||
};
|
||||
|
||||
export function createYomitanExtensionRuntime(deps: YomitanExtensionRuntimeDeps) {
|
||||
const buildLoadYomitanExtensionMainDepsHandler = createBuildLoadYomitanExtensionMainDepsHandler({
|
||||
const loadYomitanExtensionHandler = createLoadYomitanExtensionHandler({
|
||||
loadYomitanExtensionCore: deps.loadYomitanExtensionCore,
|
||||
userDataPath: deps.userDataPath,
|
||||
externalProfilePath: deps.externalProfilePath,
|
||||
@@ -34,20 +28,13 @@ export function createYomitanExtensionRuntime(deps: YomitanExtensionRuntimeDeps)
|
||||
setYomitanExtension: deps.setYomitanExtension,
|
||||
setYomitanSession: deps.setYomitanSession,
|
||||
});
|
||||
const loadYomitanExtensionHandler = createLoadYomitanExtensionHandler(
|
||||
buildLoadYomitanExtensionMainDepsHandler(),
|
||||
);
|
||||
|
||||
const buildEnsureYomitanExtensionLoadedMainDepsHandler =
|
||||
createBuildEnsureYomitanExtensionLoadedMainDepsHandler({
|
||||
getYomitanExtension: deps.getYomitanExtension,
|
||||
getLoadInFlight: deps.getLoadInFlight,
|
||||
setLoadInFlight: deps.setLoadInFlight,
|
||||
loadYomitanExtension: () => loadYomitanExtensionHandler(),
|
||||
});
|
||||
const ensureYomitanExtensionLoadedHandler = createEnsureYomitanExtensionLoadedHandler(
|
||||
buildEnsureYomitanExtensionLoadedMainDepsHandler(),
|
||||
);
|
||||
const ensureYomitanExtensionLoadedHandler = createEnsureYomitanExtensionLoadedHandler({
|
||||
getYomitanExtension: deps.getYomitanExtension,
|
||||
getLoadInFlight: deps.getLoadInFlight,
|
||||
setLoadInFlight: deps.setLoadInFlight,
|
||||
loadYomitanExtension: () => loadYomitanExtensionHandler(),
|
||||
});
|
||||
|
||||
let lastNotifiedExtension: Extension | null = null;
|
||||
let notifyingExtension: Extension | null = null;
|
||||
|
||||
Reference in new issue
Block a user