feat(config): add configuration window (#70)

This commit is contained in:
2026-05-21 04:16:21 -07:00
committed by GitHub
parent a54f03f0cd
commit dc52bc2fba
287 changed files with 14507 additions and 8134 deletions
+13 -3
View File
@@ -6,6 +6,7 @@ test('createMainBootServices builds boot-phase service bundle', () => {
type MockAppLifecycleApp = {
requestSingleInstanceLock: () => boolean;
quit: () => void;
exit: (code?: number) => void;
on: (event: string, listener: (...args: unknown[]) => void) => MockAppLifecycleApp;
whenReady: () => Promise<void>;
};
@@ -20,7 +21,7 @@ test('createMainBootServices builds boot-phase service bundle', () => {
{ targetPath: string },
{ targetPath: string },
{ targetPath: string },
{ kind: string },
{ kind: string; payloadMode: 'plain' | 'annotated' },
{ scope: string; warn: () => void; info: () => void; error: () => void },
{ registry: boolean },
{ getMainWindow: () => null; getModalWindow: () => null },
@@ -54,6 +55,9 @@ test('createMainBootServices builds boot-phase service bundle', () => {
setPathValue = value;
},
quit: () => {},
exit: (code?: number) => {
calls.push(`exit:${code ?? 0}`);
},
on: (event: string) => {
appOnCalls.push(event);
return {};
@@ -72,7 +76,7 @@ test('createMainBootServices builds boot-phase service bundle', () => {
createAnilistTokenStore: (targetPath) => ({ targetPath }),
createJellyfinTokenStore: (targetPath) => ({ targetPath }),
createAnilistUpdateQueue: (targetPath) => ({ targetPath }),
createSubtitleWebSocket: () => ({ kind: 'ws' }),
createSubtitleWebSocket: (payloadMode) => ({ kind: 'ws', payloadMode }),
createLogger: (scope) =>
({
scope,
@@ -111,6 +115,11 @@ test('createMainBootServices builds boot-phase service bundle', () => {
assert.deepEqual(services.anilistUpdateQueue, {
targetPath: '/tmp/subminer-config/anilist-retry-queue.json',
});
assert.deepEqual(services.subtitleWsService, { kind: 'ws', payloadMode: 'plain' });
assert.deepEqual(services.annotationSubtitleWsService, {
kind: 'ws',
payloadMode: 'annotated',
});
assert.deepEqual(services.appState, {
mpvSocketPath: '/tmp/subminer.sock',
texthookerPort: 5174,
@@ -123,8 +132,9 @@ test('createMainBootServices builds boot-phase service bundle', () => {
services.appLifecycleApp.on('second-instance', () => {}),
services.appLifecycleApp,
);
services.appLifecycleApp.exit(7);
assert.deepEqual(appOnCalls, ['ready']);
assert.equal(secondInstanceHandlerRegistered, true);
assert.deepEqual(calls, ['mkdir:/tmp/subminer-config']);
assert.deepEqual(calls, ['mkdir:/tmp/subminer-config', 'exit:7']);
assert.equal(setPathValue, '/tmp/subminer-config');
});
+6 -3
View File
@@ -4,6 +4,7 @@ import { ConfigStartupParseError } from '../../config';
export interface AppLifecycleShape {
requestSingleInstanceLock: () => boolean;
quit: () => void;
exit: (code?: number) => void;
on: (event: string, listener: (...args: unknown[]) => void) => unknown;
whenReady: () => Promise<void>;
}
@@ -50,6 +51,7 @@ export interface MainBootServicesParams<
app: {
setPath: (name: string, value: string) => void;
quit: () => void;
exit: (code?: number) => void;
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type -- Electron App.on has 50+ overloaded signatures
on: Function;
whenReady: () => Promise<void>;
@@ -62,7 +64,7 @@ export interface MainBootServicesParams<
createAnilistTokenStore: (targetPath: string) => TAnilistTokenStore;
createJellyfinTokenStore: (targetPath: string) => TJellyfinTokenStore;
createAnilistUpdateQueue: (targetPath: string) => TAnilistUpdateQueue;
createSubtitleWebSocket: () => TSubtitleWebSocket;
createSubtitleWebSocket: (payloadMode: 'plain' | 'annotated') => TSubtitleWebSocket;
createLogger: (scope: string) => TLogger & {
warn: (message: string) => void;
info: (message: string) => void;
@@ -203,8 +205,8 @@ export function createMainBootServices<
const anilistUpdateQueue = params.createAnilistUpdateQueue(
params.joinPath(userDataPath, 'anilist-retry-queue.json'),
);
const subtitleWsService = params.createSubtitleWebSocket();
const annotationSubtitleWsService = params.createSubtitleWebSocket();
const subtitleWsService = params.createSubtitleWebSocket('plain');
const annotationSubtitleWsService = params.createSubtitleWebSocket('annotated');
const logger = params.createLogger('main');
const runtimeRegistry = params.createMainRuntimeRegistry();
const overlayManager = params.createOverlayManager();
@@ -260,6 +262,7 @@ export function createMainBootServices<
requestSingleInstanceLock: () =>
params.shouldBypassSingleInstanceLock() ? true : params.requestSingleInstanceLockEarly(),
quit: () => params.app.quit(),
exit: (code?: number) => params.app.exit(code),
on: (event: string, listener: (...args: unknown[]) => void) => {
if (event === 'second-instance') {
params.registerSecondInstanceHandlerEarly(