mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-11-10 04:46:07 -08:00
* refactor(main): move the YouTube domain into an assembly createYoutubeAssembly owns the YouTube flow, playback, media cache, whisper subtitles, primary-subtitle notifications, and the in-app browser, plus the browser quit-on-close state. main.ts builds it once where the first YouTube runtime used to be and calls through the result. Siblings built later are passed as getters or callbacks; tests pin that construction calls none of them. * docs(architecture): describe per-domain assemblies * test(e2e): blank the line before mining the sub-delay cue The previous test leaves the same cue on screen, so the overlay check passed before the seek landed and --mine-sentence could read mpv's empty mid-seek sub-text and skip the card. * refactor(main): move the Jellyfin domain into an assembly createJellyfinAssembly owns the Jellyfin composer call, its playback and remote-progress state, the subtitle cache IO, mpv defaults, and the tray discovery deps. main.ts builds it where the composer call used to be and reads state through getActivePlayback/getQuitOnDisconnectArmed. * refactor(main): move the AniList domain into an assembly createAnilistAssembly owns the AniList setup and tracking composer calls, the setup window, the state runtime, and the token, media-guess, in-flight and attempted-update state they share. main.ts builds it where the setup composer call used to be and keeps the rate limiter, which the stats cover-art fetcher also uses. * refactor(main): move config hot-reload, settings, and sync UI into assemblies createSettingsAssembly owns config hot-reload and the settings window, which share the hot-reload-applied handler; main.ts still supplies that handler's cross-domain deps and the Yomitan deck-name helper. createSyncAssembly owns the sync window, sync IPC runtime, and auto-sync scheduler. Both are built where their blocks were; main.ts keeps the registerHandlers()/start() calls at the same points. * refactor(main): move dictionary runtimes into assemblies createDictionariesAssembly owns the JLPT and frequency lookups and their dictionary-root builders; main.ts still resolves the root paths at the same point. createCharacterDictionaryAssembly owns the character dictionary runtime, Yomitan auto-sync, and the portrait and name-candidate lookups. Both are built where their blocks were; later siblings (Yomitan profile policy, notifications, OSD, subtitle refresh) come in as getters or callbacks. * refactor(main): move overlay modal openers into an assembly createOverlayModalsAssembly owns the shared open-with-notification helper and the runtime options, Jimaku, TsukiHime, subtitle generation, session help, changelog, character dictionary manager, controller, and playlist browser openers. main.ts builds it where the openers used to live. * refactor(logger): export the Logger type for assembly deps The build emits declarations, and the Jellyfin assembly returns the logger in its tray discovery deps, so tsc needs a nameable Logger type. Assemblies now Pick from it directly.
48 lines
2.1 KiB
TypeScript
48 lines
2.1 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createJellyfinAssembly, type JellyfinAssemblyDeps } from './jellyfin';
|
|
|
|
// Every callback throws, so a test fails if the assembly calls a dep it should only call later.
|
|
function makeDeps(): JellyfinAssemblyDeps {
|
|
const lazy = (name: string) => (): never => {
|
|
throw new Error(`${name} called unexpectedly`);
|
|
};
|
|
return {
|
|
appState: {
|
|
mpvClient: null,
|
|
mpvSocketPath: '/tmp/subminer-test.sock',
|
|
immersionTracker: null,
|
|
jellyfinRemoteSession: null,
|
|
jellyfinSetupWindow: null,
|
|
},
|
|
configService: { getConfig: lazy('getConfig'), patchRawConfig: lazy('patchRawConfig') },
|
|
jellyfinTokenStore: {
|
|
loadSession: lazy('loadSession'),
|
|
saveSession: lazy('saveSession'),
|
|
clearSession: lazy('clearSession'),
|
|
},
|
|
logger: { info: () => {}, warn: () => {}, debug: () => {}, error: () => {} },
|
|
defaultMpvLogPath: '/tmp/mpv.log',
|
|
getAppDataPath: lazy('getAppDataPath'),
|
|
getRuntimePluginEntrypoint: lazy('getRuntimePluginEntrypoint'),
|
|
getMpvPluginRuntimeConfig: lazy('getMpvPluginRuntimeConfig'),
|
|
createMpvClient: lazy('createMpvClient'),
|
|
initSubtitlePrefetch: lazy('initSubtitlePrefetch'),
|
|
showVisibleOverlay: lazy('showVisibleOverlay'),
|
|
getOverlayNotifications: lazy('getOverlayNotifications'),
|
|
updateCurrentMediaTitle: lazy('updateCurrentMediaTitle'),
|
|
ensureImmersionTrackerStarted: lazy('ensureImmersionTrackerStarted'),
|
|
refreshTrayMenu: lazy('refreshTrayMenu'),
|
|
setupPreloadPath: '/tmp/preload-jellyfin-setup.js',
|
|
createBrowserWindow: lazy('createBrowserWindow'),
|
|
ipcMain: { handle: lazy('ipcMain.handle'), removeHandler: lazy('ipcMain.removeHandler') },
|
|
};
|
|
}
|
|
|
|
// main.ts builds the assembly before several siblings exist, so construction must stay lazy.
|
|
test('createJellyfinAssembly does not call its deps while constructing', () => {
|
|
const jellyfin = createJellyfinAssembly(makeDeps());
|
|
assert.equal(jellyfin.getActivePlayback(), null);
|
|
assert.equal(jellyfin.getQuitOnDisconnectArmed(), false);
|
|
});
|