Files
SubMiner/src/shared/ipc/contracts.ts
T
sudacode c5140b0f7b feat(anime): add anime browser powered by Aniyomi extensions
- Add `subminer anime` / `--anime` and a tray entry to open a browser that searches installed Aniyomi extension sources, shows cover art and episodes, and plays into mpv with overlay/mining attached
- Add an Extensions tab to add repos and install/update/remove sources, and per-source settings for sources needing config
- Support searching all sources at once with streaming, per-source results and status
- Prefer Japanese audio/subtitle tracks from the source and keep the primary subtitle slot reserved for Japanese
- Fix window/tray/Dock handling so the browser and mpv can be switched between without quitting the app or losing the Dock icon
- Add anime.repos, anime.extensionsDir, anime.preferredQuality config keys (no bundled repos or discovery)
2026-08-03 02:11:21 -07:00

193 lines
9.1 KiB
TypeScript

import type { OverlayContentMeasurement } from '../../types/runtime';
import type { RuntimeOptionId, RuntimeOptionValue } from '../../types/runtime-options';
export const OVERLAY_HOSTED_MODALS = [
'runtime-options',
'subsync',
'jimaku',
'tsukihime',
'youtube-track-picker',
'playlist-browser',
'kiku',
'controller-select',
'controller-debug',
'subtitle-sidebar',
'session-help',
'character-dictionary',
] as const;
export type OverlayHostedModal = (typeof OVERLAY_HOSTED_MODALS)[number];
export const IPC_CHANNELS = {
command: {
setIgnoreMouseEvents: 'set-ignore-mouse-events',
overlayModalClosed: 'overlay:modal-closed',
openYomitanSettings: 'open-yomitan-settings',
recordYomitanLookup: 'record-yomitan-lookup',
quitApp: 'quit-app',
youtubePickerResolve: 'youtube:picker-resolve',
toggleDevTools: 'toggle-dev-tools',
toggleOverlay: 'toggle-overlay',
saveSubtitlePosition: 'save-subtitle-position',
statsNativeConfirmDialog: 'stats:native-confirm-dialog',
statsNativeDialogOpened: 'stats:native-dialog-opened',
statsNativeDialogClosed: 'stats:native-dialog-closed',
saveControllerConfig: 'save-controller-config',
saveControllerPreference: 'save-controller-preference',
setMecabEnabled: 'set-mecab-enabled',
mpvCommand: 'mpv-command',
setAnkiConnectEnabled: 'set-anki-connect-enabled',
clearAnkiConnectHistory: 'clear-anki-connect-history',
refreshKnownWords: 'anki:refresh-known-words',
kikuFieldGroupingRespond: 'kiku:field-grouping-respond',
reportOverlayContentBounds: 'overlay-content-bounds:report',
reportOverlayInteractive: 'overlay-interactive:report',
overlayModalOpened: 'overlay:modal-opened',
overlayNotificationAction: 'overlay:notification-action',
toggleStatsOverlay: 'stats:toggle-overlay',
markActiveVideoWatched: 'immersion:mark-active-video-watched',
dispatchSessionAction: 'session-action:dispatch',
},
request: {
getVisibleOverlayVisibility: 'get-visible-overlay-visibility',
getCurrentSubtitle: 'get-current-subtitle',
getCurrentSubtitleRaw: 'get-current-subtitle-raw',
getCurrentSubtitleAss: 'get-current-subtitle-ass',
getSubtitleSidebarSnapshot: 'get-subtitle-sidebar-snapshot',
getSubtitleSidebarOpen: 'get-subtitle-sidebar-open',
getPlaybackPaused: 'get-playback-paused',
getSubtitlePosition: 'get-subtitle-position',
getSubtitleStyle: 'get-subtitle-style',
getMecabStatus: 'get-mecab-status',
getKeybindings: 'get-keybindings',
getSessionBindings: 'get-session-bindings',
getConfigShortcuts: 'get-config-shortcuts',
getStatsToggleKey: 'get-stats-toggle-key',
getMarkWatchedKey: 'get-mark-watched-key',
getOverlayNotificationPosition: 'get-overlay-notification-position',
getControllerConfig: 'get-controller-config',
getSecondarySubMode: 'get-secondary-sub-mode',
getCurrentSecondarySub: 'get-current-secondary-sub',
youtubePickerResolve: 'youtube:picker-resolve',
focusMainWindow: 'focus-main-window',
activatePlaybackWindowForOverlayInteraction: 'overlay:activate-playback-window',
runSubsyncManual: 'subsync:run-manual',
getAnkiConnectStatus: 'get-anki-connect-status',
getRuntimeOptions: 'runtime-options:get',
setRuntimeOption: 'runtime-options:set',
cycleRuntimeOption: 'runtime-options:cycle',
getAnilistStatus: 'anilist:get-status',
clearAnilistToken: 'anilist:clear-token',
openAnilistSetup: 'anilist:open-setup',
getAnilistQueueStatus: 'anilist:get-queue-status',
retryAnilistNow: 'anilist:retry-now',
jellyfinSetupSubmit: 'jellyfin:setup-submit',
getCharacterDictionarySelection: 'character-dictionary:get-selection',
setCharacterDictionarySelection: 'character-dictionary:set-selection',
getCharacterDictionaryManagerSnapshot: 'character-dictionary:get-manager-snapshot',
removeCharacterDictionaryManagedEntry: 'character-dictionary:remove-managed-entry',
moveCharacterDictionaryManagedEntry: 'character-dictionary:move-managed-entry',
appendClipboardVideoToQueue: 'clipboard:append-video-to-queue',
getPlaylistBrowserSnapshot: 'playlist-browser:get-snapshot',
appendPlaylistBrowserFile: 'playlist-browser:append-file',
playPlaylistBrowserIndex: 'playlist-browser:play-index',
removePlaylistBrowserIndex: 'playlist-browser:remove-index',
movePlaylistBrowserIndex: 'playlist-browser:move-index',
jimakuGetMediaInfo: 'jimaku:get-media-info',
jimakuSearchEntries: 'jimaku:search-entries',
jimakuListFiles: 'jimaku:list-files',
jimakuDownloadFile: 'jimaku:download-file',
tsukihimeSearchEntries: 'tsukihime:search-entries',
tsukihimeListFiles: 'tsukihime:list-files',
tsukihimeDownloadFile: 'tsukihime:download-file',
tsukihimeGetSecondaryLanguages: 'tsukihime:get-secondary-languages',
kikuBuildMergePreview: 'kiku:build-merge-preview',
getConfigSettingsSnapshot: 'config:get-settings-snapshot',
saveConfigSettingsPatch: 'config:save-settings-patch',
openConfigSettingsFile: 'config:open-settings-file',
openConfigSettingsWindow: 'config:open-settings-window',
getConfigSettingsAnkiDeckNames: 'config-settings:anki-deck-names',
getConfigSettingsAnkiDeckFieldNames: 'config-settings:anki-deck-field-names',
getConfigSettingsAnkiDeckModelNames: 'config-settings:anki-deck-model-names',
getConfigSettingsAnkiModelNames: 'config-settings:anki-model-names',
getConfigSettingsAnkiModelFieldNames: 'config-settings:anki-model-field-names',
getConfigSettingsYomitanAnkiDeckName: 'config-settings:yomitan-anki-deck-name',
syncUiGetSnapshot: 'sync-ui:get-snapshot',
syncUiSaveHost: 'sync-ui:save-host',
syncUiRemoveHost: 'sync-ui:remove-host',
syncUiSetAutoSyncInterval: 'sync-ui:set-auto-sync-interval',
syncUiRunSync: 'sync-ui:run-sync',
syncUiCancelRun: 'sync-ui:cancel-run',
syncUiCheckHost: 'sync-ui:check-host',
syncUiCreateSnapshot: 'sync-ui:create-snapshot',
syncUiMergeSnapshotFile: 'sync-ui:merge-snapshot-file',
syncUiDeleteSnapshot: 'sync-ui:delete-snapshot',
syncUiRevealSnapshot: 'sync-ui:reveal-snapshot',
syncUiPickSnapshotFile: 'sync-ui:pick-snapshot-file',
animeBrowserGetSnapshot: 'anime-browser:get-snapshot',
animeBrowserEnsureBridge: 'anime-browser:ensure-bridge',
animeBrowserSelectSource: 'anime-browser:select-source',
animeBrowserSearch: 'anime-browser:search',
animeBrowserGetPopular: 'anime-browser:get-popular',
animeBrowserGetDetails: 'anime-browser:get-details',
animeBrowserGetEpisodes: 'anime-browser:get-episodes',
animeBrowserPlayEpisode: 'anime-browser:play-episode',
animeBrowserGetPreferences: 'anime-browser:get-preferences',
animeBrowserSetPreference: 'anime-browser:set-preference',
animeBrowserListAvailableExtensions: 'anime-browser:list-available-extensions',
animeBrowserInstallExtension: 'anime-browser:install-extension',
animeBrowserRemoveExtension: 'anime-browser:remove-extension',
animeBrowserRescanExtensions: 'anime-browser:rescan-extensions',
animeBrowserAddRepo: 'anime-browser:add-repo',
animeBrowserRemoveRepo: 'anime-browser:remove-repo',
},
event: {
subtitleSet: 'subtitle:set',
overlayPointerRecoveryRequest: 'overlay:pointer-recovery-request',
subtitleVisibility: 'mpv:subVisibility',
subtitlePositionSet: 'subtitle-position:set',
subtitleAssSet: 'subtitle-ass:set',
secondarySubtitleSet: 'secondary-subtitle:set',
secondarySubtitleMode: 'secondary-subtitle:mode',
subsyncOpenManual: 'subsync:open-manual',
kikuFieldGroupingRequest: 'kiku:field-grouping-request',
kikuFieldGroupingCancel: 'kiku:field-grouping-cancel',
runtimeOptionsChanged: 'runtime-options:changed',
runtimeOptionsOpen: 'runtime-options:open',
jimakuOpen: 'jimaku:open',
tsukihimeOpen: 'tsukihime:open',
youtubePickerOpen: 'youtube:picker-open',
youtubePickerCancel: 'youtube:picker-cancel',
playlistBrowserOpen: 'playlist-browser:open',
sessionNumericSelectionStart: 'session:numeric-selection-start',
keyboardModeToggleRequested: 'keyboard-mode-toggle:requested',
lookupWindowToggleRequested: 'lookup-window-toggle:requested',
sessionHelpOpen: 'session-help:open',
characterDictionaryManagerOpen: 'character-dictionary:manager-open',
controllerSelectOpen: 'controller-select:open',
controllerDebugOpen: 'controller-debug:open',
subtitleSidebarToggle: 'subtitle-sidebar:toggle',
primarySubtitleBarToggle: 'primary-subtitle-bar:toggle',
configHotReload: 'config:hot-reload',
overlayNotification: 'overlay:notification',
notificationHistoryToggle: 'notification-history:toggle',
syncUiProgress: 'sync-ui:progress',
syncUiStateChanged: 'sync-ui:state-changed',
animeBrowserBridgeState: 'anime-browser:bridge-state',
animeBrowserSearchUpdate: 'anime-browser:search-update',
},
} as const;
export type RuntimeOptionsSetRequest = {
id: RuntimeOptionId;
value: RuntimeOptionValue;
};
export type RuntimeOptionsCycleRequest = {
id: RuntimeOptionId;
direction: 1 | -1;
};
export type OverlayContentBoundsReportRequest = {
measurement: OverlayContentMeasurement;
};