import type { KikuFieldGroupingChoice, KikuFieldGroupingRequestData, KikuMergePreviewRequest, KikuMergePreviewResponse, } from './anki'; import type { ResolvedConfig, ShortcutsConfig } from './config'; import type { CompiledSessionBinding, SessionActionId, SessionActionPayload, } from './session-bindings'; import type { JimakuApiResponse, JimakuDownloadQuery, JimakuDownloadResult, JimakuEntry, JimakuFileEntry, JimakuFilesQuery, JimakuMediaInfo, JimakuSearchQuery, YoutubePickerOpenPayload, YoutubePickerResolveRequest, YoutubePickerResolveResult, } from './integrations'; import type { SecondarySubMode, SubtitleData, SubtitlePosition, SubtitleSidebarConfig, SubtitleSidebarSnapshot, SubtitleStyleConfig, } from './subtitle'; import type { RuntimeOptionApplyResult, RuntimeOptionId, RuntimeOptionState, RuntimeOptionValue, } from './runtime-options'; export interface WindowGeometry { x: number; y: number; width: number; height: number; } export interface Keybinding { key: string; command: (string | number)[] | null; } export interface MpvClient { currentSubText: string; currentVideoPath: string; currentMediaTitle?: string | null; currentTimePos: number; currentSubStart: number; currentSubEnd: number; currentAudioStreamIndex: number | null; requestProperty?: (name: string) => Promise; send(command: { command: unknown[]; request_id?: number }): boolean; } export interface SubsyncSourceTrack { id: number; label: string; } export interface SubsyncManualPayload { sourceTracks: SubsyncSourceTrack[]; } export interface SubsyncManualRunRequest { engine: 'alass' | 'ffsubsync'; sourceTrackId?: number | null; } export interface SubsyncResult { ok: boolean; message: string; } export interface PlaylistBrowserDirectoryItem { path: string; basename: string; episodeLabel?: string | null; isCurrentFile: boolean; } export interface PlaylistBrowserQueueItem { index: number; id: number | null; filename: string; title: string | null; displayLabel: string; current: boolean; playing: boolean; path: string | null; } export interface PlaylistBrowserSnapshot { directoryPath: string | null; directoryAvailable: boolean; directoryStatus: string; directoryItems: PlaylistBrowserDirectoryItem[]; playlistItems: PlaylistBrowserQueueItem[]; playingIndex: number | null; currentFilePath: string | null; } export interface PlaylistBrowserMutationResult { ok: boolean; message: string; snapshot?: PlaylistBrowserSnapshot; } export type ControllerButtonBinding = | 'none' | 'select' | 'buttonSouth' | 'buttonEast' | 'buttonNorth' | 'buttonWest' | 'leftShoulder' | 'rightShoulder' | 'leftStickPress' | 'rightStickPress' | 'leftTrigger' | 'rightTrigger'; export type ControllerAxisBinding = 'leftStickX' | 'leftStickY' | 'rightStickX' | 'rightStickY'; export type ControllerTriggerInputMode = 'auto' | 'digital' | 'analog'; export type ControllerAxisDirection = 'negative' | 'positive'; export type ControllerDpadFallback = 'none' | 'horizontal' | 'vertical'; export interface ControllerNoneBinding { kind: 'none'; } export interface ControllerButtonInputBinding { kind: 'button'; buttonIndex: number; } export interface ControllerAxisDirectionInputBinding { kind: 'axis'; axisIndex: number; direction: ControllerAxisDirection; } export interface ControllerAxisInputBinding { kind: 'axis'; axisIndex: number; dpadFallback?: ControllerDpadFallback; } export type ControllerDiscreteBindingConfig = | ControllerButtonBinding | ControllerNoneBinding | ControllerButtonInputBinding | ControllerAxisDirectionInputBinding; export type ResolvedControllerDiscreteBinding = | ControllerNoneBinding | ControllerButtonInputBinding | ControllerAxisDirectionInputBinding; export type ControllerAxisBindingConfig = | ControllerAxisBinding | ControllerNoneBinding | ControllerAxisInputBinding; export type ResolvedControllerAxisBinding = | ControllerNoneBinding | { kind: 'axis'; axisIndex: number; dpadFallback: ControllerDpadFallback; }; export interface ControllerBindingsConfig { toggleLookup?: ControllerDiscreteBindingConfig; closeLookup?: ControllerDiscreteBindingConfig; toggleKeyboardOnlyMode?: ControllerDiscreteBindingConfig; mineCard?: ControllerDiscreteBindingConfig; quitMpv?: ControllerDiscreteBindingConfig; previousAudio?: ControllerDiscreteBindingConfig; nextAudio?: ControllerDiscreteBindingConfig; playCurrentAudio?: ControllerDiscreteBindingConfig; toggleMpvPause?: ControllerDiscreteBindingConfig; leftStickHorizontal?: ControllerAxisBindingConfig; leftStickVertical?: ControllerAxisBindingConfig; rightStickHorizontal?: ControllerAxisBindingConfig; rightStickVertical?: ControllerAxisBindingConfig; } export interface ResolvedControllerBindingsConfig { toggleLookup?: ResolvedControllerDiscreteBinding; closeLookup?: ResolvedControllerDiscreteBinding; toggleKeyboardOnlyMode?: ResolvedControllerDiscreteBinding; mineCard?: ResolvedControllerDiscreteBinding; quitMpv?: ResolvedControllerDiscreteBinding; previousAudio?: ResolvedControllerDiscreteBinding; nextAudio?: ResolvedControllerDiscreteBinding; playCurrentAudio?: ResolvedControllerDiscreteBinding; toggleMpvPause?: ResolvedControllerDiscreteBinding; leftStickHorizontal?: ResolvedControllerAxisBinding; leftStickVertical?: ResolvedControllerAxisBinding; rightStickHorizontal?: ResolvedControllerAxisBinding; rightStickVertical?: ResolvedControllerAxisBinding; } export interface ControllerButtonIndicesConfig { select?: number; buttonSouth?: number; buttonEast?: number; buttonNorth?: number; buttonWest?: number; leftShoulder?: number; rightShoulder?: number; leftStickPress?: number; rightStickPress?: number; leftTrigger?: number; rightTrigger?: number; } export interface ControllerConfig { enabled?: boolean; preferredGamepadId?: string; preferredGamepadLabel?: string; smoothScroll?: boolean; scrollPixelsPerSecond?: number; horizontalJumpPixels?: number; stickDeadzone?: number; triggerInputMode?: ControllerTriggerInputMode; triggerDeadzone?: number; repeatDelayMs?: number; repeatIntervalMs?: number; buttonIndices?: ControllerButtonIndicesConfig; bindings?: ControllerBindingsConfig; } export interface ControllerPreferenceUpdate { preferredGamepadId: string; preferredGamepadLabel: string; } export type ControllerConfigUpdate = ControllerConfig; export interface ControllerDeviceInfo { id: string; index: number; mapping: string; connected: boolean; } export interface ControllerButtonSnapshot { value: number; pressed: boolean; touched?: boolean; } export interface ControllerRuntimeSnapshot { connectedGamepads: ControllerDeviceInfo[]; activeGamepadId: string | null; rawAxes: number[]; rawButtons: ControllerButtonSnapshot[]; } export interface MpvSubtitleRenderMetrics { subPos: number; subFontSize: number; subScale: number; subMarginY: number; subMarginX: number; subFont: string; subSpacing: number; subBold: boolean; subItalic: boolean; subBorderSize: number; subShadowOffset: number; subAssOverride: string; subScaleByWindow: boolean; subUseMargins: boolean; osdHeight: number; osdDimensions: { w: number; h: number; ml: number; mr: number; mt: number; mb: number; } | null; } export type OverlayLayer = 'visible'; export interface OverlayContentRect { x: number; y: number; width: number; height: number; } export interface OverlayContentMeasurement { layer: OverlayLayer; measuredAtMs: number; viewport: { width: number; height: number; }; contentRect: OverlayContentRect | null; } export interface MecabStatus { available: boolean; enabled: boolean; path: string | null; } export interface ClipboardAppendResult { ok: boolean; message: string; } export interface ConfigHotReloadPayload { keybindings: Keybinding[]; sessionBindings: CompiledSessionBinding[]; subtitleStyle: SubtitleStyleConfig | null; subtitleSidebar: Required; secondarySubMode: SecondarySubMode; } export interface SessionActionDispatchRequest { actionId: SessionActionId; payload?: SessionActionPayload; } export type ResolvedControllerConfig = ResolvedConfig['controller']; export interface ElectronAPI { getOverlayLayer: () => 'visible' | 'modal' | null; onSubtitle: (callback: (data: SubtitleData) => void) => void; onVisibility: (callback: (visible: boolean) => void) => void; onSubtitlePosition: (callback: (position: SubtitlePosition | null) => void) => void; getOverlayVisibility: () => Promise; getCurrentSubtitle: () => Promise; getCurrentSubtitleRaw: () => Promise; getCurrentSubtitleAss: () => Promise; getSubtitleSidebarSnapshot: () => Promise; getPlaybackPaused: () => Promise; onSubtitleAss: (callback: (assText: string) => void) => void; setIgnoreMouseEvents: (ignore: boolean, options?: { forward?: boolean }) => void; openYomitanSettings: () => void; recordYomitanLookup: () => void; getSubtitlePosition: () => Promise; saveSubtitlePosition: (position: SubtitlePosition) => void; getMecabStatus: () => Promise; setMecabEnabled: (enabled: boolean) => void; sendMpvCommand: (command: (string | number)[]) => void; getKeybindings: () => Promise; getSessionBindings: () => Promise; getConfiguredShortcuts: () => Promise>; dispatchSessionAction: (actionId: SessionActionId, payload?: SessionActionPayload) => Promise; getStatsToggleKey: () => Promise; getMarkWatchedKey: () => Promise; markActiveVideoWatched: () => Promise; getControllerConfig: () => Promise; saveControllerConfig: (update: ControllerConfigUpdate) => Promise; saveControllerPreference: (update: ControllerPreferenceUpdate) => Promise; getJimakuMediaInfo: () => Promise; jimakuSearchEntries: (query: JimakuSearchQuery) => Promise>; jimakuListFiles: (query: JimakuFilesQuery) => Promise>; jimakuDownloadFile: (query: JimakuDownloadQuery) => Promise; quitApp: () => void; toggleDevTools: () => void; toggleOverlay: () => void; toggleStatsOverlay: () => void; getAnkiConnectStatus: () => Promise; setAnkiConnectEnabled: (enabled: boolean) => void; clearAnkiConnectHistory: () => void; onSecondarySub: (callback: (text: string) => void) => void; onSecondarySubMode: (callback: (mode: SecondarySubMode) => void) => void; getSecondarySubMode: () => Promise; getCurrentSecondarySub: () => Promise; focusMainWindow: () => Promise; getSubtitleStyle: () => Promise; onSubsyncManualOpen: (callback: (payload: SubsyncManualPayload) => void) => void; runSubsyncManual: (request: SubsyncManualRunRequest) => Promise; onKikuFieldGroupingRequest: (callback: (data: KikuFieldGroupingRequestData) => void) => void; kikuBuildMergePreview: (request: KikuMergePreviewRequest) => Promise; kikuFieldGroupingRespond: (choice: KikuFieldGroupingChoice) => void; getRuntimeOptions: () => Promise; setRuntimeOptionValue: ( id: RuntimeOptionId, value: RuntimeOptionValue, ) => Promise; cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => Promise; onRuntimeOptionsChanged: (callback: (options: RuntimeOptionState[]) => void) => void; onOpenRuntimeOptions: (callback: () => void) => void; onOpenSessionHelp: (callback: () => void) => void; onOpenControllerSelect: (callback: () => void) => void; onOpenControllerDebug: (callback: () => void) => void; onOpenJimaku: (callback: () => void) => void; onOpenYoutubeTrackPicker: (callback: (payload: YoutubePickerOpenPayload) => void) => void; onOpenPlaylistBrowser: (callback: () => void) => void; onSubtitleSidebarToggle: (callback: () => void) => void; onCancelYoutubeTrackPicker: (callback: () => void) => void; onKeyboardModeToggleRequested: (callback: () => void) => void; onLookupWindowToggleRequested: (callback: () => void) => void; appendClipboardVideoToQueue: () => Promise; getPlaylistBrowserSnapshot: () => Promise; appendPlaylistBrowserFile: (path: string) => Promise; playPlaylistBrowserIndex: (index: number) => Promise; removePlaylistBrowserIndex: (index: number) => Promise; movePlaylistBrowserIndex: ( index: number, direction: 1 | -1, ) => Promise; youtubePickerResolve: ( request: YoutubePickerResolveRequest, ) => Promise; notifyOverlayModalClosed: ( modal: | 'runtime-options' | 'subsync' | 'jimaku' | 'youtube-track-picker' | 'playlist-browser' | 'kiku' | 'controller-select' | 'controller-debug' | 'subtitle-sidebar' | 'session-help', ) => void; notifyOverlayModalOpened: ( modal: | 'runtime-options' | 'subsync' | 'jimaku' | 'youtube-track-picker' | 'playlist-browser' | 'kiku' | 'controller-select' | 'controller-debug' | 'subtitle-sidebar' | 'session-help', ) => void; reportOverlayContentBounds: (measurement: OverlayContentMeasurement) => void; onConfigHotReload: (callback: (payload: ConfigHotReloadPayload) => void) => void; } declare global { interface Window { electronAPI: ElectronAPI; } }