Files
SubMiner/src/preload-animeui.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

67 lines
3.4 KiB
TypeScript

import { contextBridge, ipcRenderer } from 'electron';
import { IPC_CHANNELS } from './shared/ipc/contracts';
import type {
AnimeBrowserAPI,
AnimeBrowserBridgeState,
AnimeBrowserDetails,
AnimeBrowserEpisode,
AnimeBrowserPlayRequest,
AnimeBrowserPlayResult,
AnimeBrowserSearchResult,
AnimeBrowserSearchUpdate,
AnimeBrowserSnapshot,
AvailableExtensionsResult,
SourcePreferenceView,
} from './types/anime-browser';
const request = IPC_CHANNELS.request;
const animeBrowserAPI: AnimeBrowserAPI = {
getSnapshot: (): Promise<AnimeBrowserSnapshot> =>
ipcRenderer.invoke(request.animeBrowserGetSnapshot),
ensureBridge: (): Promise<AnimeBrowserBridgeState> =>
ipcRenderer.invoke(request.animeBrowserEnsureBridge),
selectSource: (sourceId: string): Promise<void> =>
ipcRenderer.invoke(request.animeBrowserSelectSource, sourceId),
search: (query: string, page?: number): Promise<AnimeBrowserSearchResult> =>
ipcRenderer.invoke(request.animeBrowserSearch, query, page),
getPopular: (page?: number): Promise<AnimeBrowserSearchResult> =>
ipcRenderer.invoke(request.animeBrowserGetPopular, page),
getDetails: (animeUrl: string, sourceId?: string): Promise<AnimeBrowserDetails> =>
ipcRenderer.invoke(request.animeBrowserGetDetails, animeUrl, sourceId),
getEpisodes: (animeUrl: string, sourceId?: string): Promise<AnimeBrowserEpisode[]> =>
ipcRenderer.invoke(request.animeBrowserGetEpisodes, animeUrl, sourceId),
playEpisode: (playRequest: AnimeBrowserPlayRequest): Promise<AnimeBrowserPlayResult> =>
ipcRenderer.invoke(request.animeBrowserPlayEpisode, playRequest),
getPreferences: (sourceId: string): Promise<SourcePreferenceView[]> =>
ipcRenderer.invoke(request.animeBrowserGetPreferences, sourceId),
setPreference: (
sourceId: string,
key: string,
value: string | string[] | boolean,
): Promise<SourcePreferenceView[]> =>
ipcRenderer.invoke(request.animeBrowserSetPreference, sourceId, key, value),
listAvailableExtensions: (): Promise<AvailableExtensionsResult> =>
ipcRenderer.invoke(request.animeBrowserListAvailableExtensions),
installExtension: (pkg: string): Promise<void> =>
ipcRenderer.invoke(request.animeBrowserInstallExtension, pkg),
removeExtension: (pkg: string): Promise<void> =>
ipcRenderer.invoke(request.animeBrowserRemoveExtension, pkg),
rescanExtensions: (): Promise<void> => ipcRenderer.invoke(request.animeBrowserRescanExtensions),
addRepo: (url: string): Promise<void> => ipcRenderer.invoke(request.animeBrowserAddRepo, url),
removeRepo: (url: string): Promise<void> =>
ipcRenderer.invoke(request.animeBrowserRemoveRepo, url),
onBridgeState: (listener: (state: AnimeBrowserBridgeState) => void): (() => void) => {
const handler = (_event: unknown, state: AnimeBrowserBridgeState): void => listener(state);
ipcRenderer.on(IPC_CHANNELS.event.animeBrowserBridgeState, handler);
return () => ipcRenderer.removeListener(IPC_CHANNELS.event.animeBrowserBridgeState, handler);
},
onSearchUpdate: (listener: (update: AnimeBrowserSearchUpdate) => void): (() => void) => {
const handler = (_event: unknown, update: AnimeBrowserSearchUpdate): void => listener(update);
ipcRenderer.on(IPC_CHANNELS.event.animeBrowserSearchUpdate, handler);
return () => ipcRenderer.removeListener(IPC_CHANNELS.event.animeBrowserSearchUpdate, handler);
},
};
contextBridge.exposeInMainWorld('animeBrowserAPI', animeBrowserAPI);