Files
SubMiner/src/types/runtime.ts
T

783 lines
26 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { MpvInputBindingsSnapshot } from './session-bindings';
import type {
KikuFieldGroupingChoice,
KikuFieldGroupingRequestData,
KikuMergePreviewRequest,
KikuMergePreviewResponse,
MediaTimingReviewActionResult,
MediaTimingReviewOpenPayload,
MediaTimingReviewPreviewPosition,
MediaTimingReviewPreviewRequest,
MediaTimingReviewResolveRequest,
MediaTimingReviewFrameRequest,
MediaTimingReviewFrameResult,
MediaTimingReviewWaveformRequest,
MediaTimingReviewWaveformResult,
} from './anki';
import type { ChangelogSnapshot } from './changelog';
import type { SubtitleGenerationProgress } from '../shared/subtitle-generation';
import type { SubtitleGenerationModelId } from '../shared/subtitle-generation-model-catalog';
import type {
SubtitleGenerationResult,
SubtitleGenerationStatus,
} from '../shared/subtitle-generation-ipc';
import type { ResolvedConfig, ShortcutsConfig } from './config';
import type {
CompiledSessionBinding,
SessionActionId,
SessionActionPayload,
SessionBindingWarning,
} from './session-bindings';
import type {
TsukihimeApiResponse,
TsukihimeDownloadQuery,
TsukihimeDownloadResult,
TsukihimeEntry,
TsukihimeFilesQuery,
TsukihimeSearchQuery,
TsukihimeSubtitleFile,
JimakuApiResponse,
JimakuDownloadQuery,
JimakuDownloadResult,
JimakuEntry,
JimakuFileEntry,
JimakuFilesQuery,
JimakuMediaInfo,
JimakuSearchQuery,
YoutubePickerOpenPayload,
YoutubePickerResolveRequest,
YoutubePickerResolveResult,
} from './integrations';
import type {
PrimarySubMode,
ResolvedSubtitleSidebarConfig,
SecondarySubMode,
SubtitleData,
SubtitleMiningContext,
SubtitlePosition,
SubtitleSidebarPlaybackState,
SubtitleSidebarSnapshot,
SubtitleRendererStyleConfig,
} from './subtitle';
import type {
RuntimeOptionApplyResult,
RuntimeOptionId,
RuntimeOptionState,
RuntimeOptionValue,
} from './runtime-options';
import type {
OverlayNotificationAction,
OverlayNotificationEventPayload,
OverlayNotificationPosition,
} from './notification';
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;
/** mpv `sub-delay`; `sub-start`/`sub-end` do not include it. */
currentSubDelay: number;
currentAudioStreamIndex: number | null;
requestProperty?: (name: string) => Promise<unknown>;
send(command: { command: unknown[]; request_id?: number }): boolean;
}
export interface SubsyncSubtitleTrack {
id: number;
label: string;
}
export interface SubsyncManualPayload {
subtitleTracks: SubsyncSubtitleTrack[];
defaultReferenceTrackId: number | null;
defaultTargetTrackId: number | null;
videoReferenceAvailable: boolean;
ffsubsyncAvailable: boolean;
}
export type SubsyncReferenceMode = 'track' | 'video';
export interface SubsyncManualRunRequest {
engine: 'alass' | 'ffsubsync';
/** alass reference source: another subtitle track, or the loaded media file itself. */
referenceMode?: SubsyncReferenceMode;
referenceTrackId?: number | null;
/** Subtitle track to retime. Defaults to the active primary track. */
targetTrackId?: 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';
/**
* Face button style: Xbox (A at the bottom), Nintendo (A on the right) or PlayStation
* (╳ at the bottom, laid out like Xbox). Decides button names and where letters land.
*/
export type ControllerFaceButtonLabels = 'xbox' | 'nintendo' | 'playstation';
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;
holdSecondarySub?: ControllerDiscreteBindingConfig;
previousEntry?: ControllerDiscreteBindingConfig;
nextEntry?: ControllerDiscreteBindingConfig;
previousSubtitle?: ControllerDiscreteBindingConfig;
nextSubtitle?: ControllerDiscreteBindingConfig;
replaySubtitle?: ControllerDiscreteBindingConfig;
playNextSubtitle?: 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;
holdSecondarySub?: ResolvedControllerDiscreteBinding;
previousEntry?: ResolvedControllerDiscreteBinding;
nextEntry?: ResolvedControllerDiscreteBinding;
previousSubtitle?: ResolvedControllerDiscreteBinding;
nextSubtitle?: ResolvedControllerDiscreteBinding;
replaySubtitle?: ResolvedControllerDiscreteBinding;
playNextSubtitle?: 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;
}
/** Every button on the media timing review dialog, named by what it does. */
export type ControllerReviewAction =
| 'confirm'
| 'cancel'
| 'play'
| 'resetTiming'
| 'showEarlier'
| 'showLater'
| 'framePrevious'
| 'frameNext'
| 'frameReset'
| 'startBack'
| 'startForward'
| 'previousLineAdd'
| 'previousLineRemove'
| 'endBack'
| 'endForward'
| 'nextLineAdd'
| 'nextLineRemove'
| 'useOriginal'
| 'keepEditing'
| 'skipMedia'
| 'discard';
/** Every button on the duplicate-card field grouping dialog, named by what it does. */
export type ControllerFieldGroupingAction =
| 'selectOriginal'
| 'selectNew'
| 'toggleDeleteDuplicate'
| 'continue'
| 'cancel'
| 'confirmMerge'
| 'back'
| 'cancelMerge'
| 'toggleView'
| 'scrollUp'
| 'scrollDown';
export type ControllerFaceLetter = 'a' | 'b' | 'x' | 'y';
export type ControllerDpadDirection = 'left' | 'right' | 'up' | 'down';
/**
* One input in a review binding. `button` and `axis` are raw indices recorded by Learn;
* `face` (printed letter, via `faceButtonLabels`) and `dpad` (any D-pad report) keep the
* defaults working on every controller layout.
*/
export type ControllerReviewInput =
| { kind: 'button'; buttonIndex: number }
| { kind: 'axis'; axisIndex: number; direction: ControllerAxisDirection }
| { kind: 'face'; letter: ControllerFaceLetter }
| { kind: 'dpad'; direction: ControllerDpadDirection };
/** Press `press`, optionally while holding `hold`. */
export type ControllerReviewBindingConfig =
| { kind: 'none' }
| { kind?: 'combo'; press: ControllerReviewInput; hold?: ControllerReviewInput | null };
export type ResolvedControllerReviewBinding =
| { kind: 'none' }
| { kind: 'combo'; press: ControllerReviewInput; hold: ControllerReviewInput | null };
export type ControllerReviewBindingsConfig = Partial<
Record<ControllerReviewAction, ControllerReviewBindingConfig>
>;
export type ResolvedControllerReviewBindings = Record<
ControllerReviewAction,
ResolvedControllerReviewBinding
>;
export type ControllerFieldGroupingBindingsConfig = Partial<
Record<ControllerFieldGroupingAction, ControllerReviewBindingConfig>
>;
export type ResolvedControllerFieldGroupingBindings = Record<
ControllerFieldGroupingAction,
ResolvedControllerReviewBinding
>;
export interface ControllerProfileConfig {
label?: string;
/** Overrides `controller.faceButtonLabels` for this controller; set from Alt+C. */
faceButtonLabels?: ControllerFaceButtonLabels;
buttonIndices?: ControllerButtonIndicesConfig;
bindings?: ControllerBindingsConfig;
reviewBindings?: ControllerReviewBindingsConfig;
fieldGroupingBindings?: ControllerFieldGroupingBindingsConfig;
}
export interface ResolvedControllerProfileConfig {
label: string;
faceButtonLabels: ControllerFaceButtonLabels;
buttonIndices: Required<ControllerButtonIndicesConfig>;
bindings: Required<ResolvedControllerBindingsConfig>;
reviewBindings: ResolvedControllerReviewBindings;
fieldGroupingBindings: ResolvedControllerFieldGroupingBindings;
}
export interface ControllerConfig {
enabled?: boolean;
preferredGamepadId?: string;
preferredGamepadLabel?: string;
smoothScroll?: boolean;
scrollPixelsPerSecond?: number;
horizontalJumpPixels?: number;
stickDeadzone?: number;
triggerInputMode?: ControllerTriggerInputMode;
faceButtonLabels?: ControllerFaceButtonLabels;
triggerDeadzone?: number;
repeatDelayMs?: number;
repeatIntervalMs?: number;
buttonIndices?: ControllerButtonIndicesConfig;
bindings?: ControllerBindingsConfig;
reviewBindings?: ControllerReviewBindingsConfig;
fieldGroupingBindings?: ControllerFieldGroupingBindingsConfig;
profiles?: Record<string, ControllerProfileConfig>;
}
export type ControllerConfigUpdate = ControllerConfig;
export interface ControllerDeviceInfo {
id: string;
index: number;
mapping: string;
connected: boolean;
/** Gamepad API timestamp of the pad's last input; the newest is the one being used. */
timestamp?: number;
}
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;
interactiveRects?: OverlayContentRect[];
}
export interface MecabStatus {
available: boolean;
enabled: boolean;
path: string | null;
}
export interface ClipboardAppendResult {
ok: boolean;
message: string;
}
export interface ConfigHotReloadPayload {
keybindings: Keybinding[];
sessionBindings: CompiledSessionBinding[];
sessionBindingWarnings: SessionBindingWarning[];
subtitleStyle: SubtitleRendererStyleConfig | null;
subtitleSidebar: ResolvedSubtitleSidebarConfig;
primarySubMode: PrimarySubMode;
secondarySubMode: SecondarySubMode;
}
/** Content of the shared plugin panel. `panelId` changes each time a plugin opens a new panel. */
export interface PluginPanelSnapshot {
panelId: number;
title: string;
markdown: string;
}
export interface SessionActionDispatchRequest {
actionId: SessionActionId;
payload?: SessionActionPayload;
}
export type ResolvedControllerConfig = ResolvedConfig['controller'];
export interface CharacterDictionaryCandidate {
id: number;
title: string;
episodes: number | null;
}
export interface CharacterDictionarySelectionSnapshot {
seriesKey: string;
guessTitle: string | null;
current: CharacterDictionaryCandidate | null;
override: CharacterDictionaryCandidate | null;
candidates: CharacterDictionaryCandidate[];
}
export interface CharacterDictionarySelectionResult {
ok: boolean;
seriesKey: string;
selected: CharacterDictionaryCandidate;
staleMediaIds: number[];
}
export interface CharacterDictionaryManagerEntry {
mediaId: number;
label: string;
title: string;
current: boolean;
}
export interface CharacterDictionaryManagerSnapshot {
entries: CharacterDictionaryManagerEntry[];
}
export type CharacterDictionaryManagerMutationResult =
| (CharacterDictionaryManagerSnapshot & { ok: true; rebuildRequired?: boolean })
| { ok: false; message: string; entries: CharacterDictionaryManagerEntry[] };
/** Sent with session-help:open; commands only run when a video is loaded in mpv. */
export interface SessionHelpOpenPayload {
commandsEnabled: boolean;
}
export interface SessionNumericSelectionStartPayload {
actionId: Extract<SessionActionId, 'copySubtitleMultiple' | 'mineSentenceMultiple'>;
timeoutMs: number;
}
export interface ElectronAPI {
requestSubtitleGenerationOpen: () => Promise<boolean>;
onSubtitleGenerationOpen: (callback: () => void) => void;
getSubtitleGenerationStatus: () => Promise<SubtitleGenerationStatus>;
selectSubtitleGenerationModel: (
model: SubtitleGenerationModelId,
) => Promise<SubtitleGenerationStatus>;
startSubtitleGeneration: () => Promise<SubtitleGenerationResult>;
downloadSubtitleGenerationModel: () => Promise<SubtitleGenerationResult>;
downloadSubtitleGenerationVadModel: () => Promise<SubtitleGenerationResult>;
setSubtitleGenerationVadEnabled: (enabled: boolean) => Promise<SubtitleGenerationStatus>;
cancelSubtitleGeneration: () => Promise<void>;
onSubtitleGenerationProgress: (
callback: (progress: SubtitleGenerationProgress) => void,
) => () => void;
getOverlayLayer: () => 'visible' | 'modal' | null;
getPathForFile: (file: File) => string;
onSubtitle: (callback: (data: SubtitleData) => void) => void;
onOverlayPointerRecoveryRequested: (callback: () => void) => void;
onOverlayNotification: (callback: (payload: OverlayNotificationEventPayload) => void) => void;
sendOverlayNotificationAction?: (
notificationId: string,
actionId: string,
options?: Pick<OverlayNotificationAction, 'noteId'>,
) => void;
onNotificationHistoryToggle: (callback: () => void) => void;
onSubtitlePosition: (callback: (position: SubtitlePosition | null) => void) => void;
getCurrentSubtitle: () => Promise<SubtitleData>;
getCurrentSubtitleRaw: () => Promise<string>;
getSubtitleSidebarSnapshot: () => Promise<SubtitleSidebarSnapshot>;
getSubtitleSidebarPlaybackState: () => Promise<SubtitleSidebarPlaybackState>;
copySubtitleSidebarSelection: (text: string) => Promise<void>;
getSubtitleSidebarOpen: () => Promise<boolean>;
getPlaybackPaused: () => Promise<boolean | null>;
setIgnoreMouseEvents: (ignore: boolean, options?: { forward?: boolean }) => void;
reportOverlayInteractive: (interactive: boolean) => void;
recordYomitanLookup: (context?: SubtitleMiningContext | null) => void;
getSubtitlePosition: () => Promise<SubtitlePosition | null>;
saveSubtitlePosition: (position: SubtitlePosition) => void;
sendMpvCommand: (command: (string | number)[]) => void;
getMpvInputBindings: () => Promise<MpvInputBindingsSnapshot>;
getSessionBindings: () => Promise<CompiledSessionBinding[]>;
getConfiguredShortcuts: () => Promise<Required<ShortcutsConfig>>;
dispatchSessionAction: (
actionId: SessionActionId,
payload?: SessionActionPayload,
) => Promise<void>;
getStatsToggleKey: () => Promise<string>;
getMarkWatchedKey: () => Promise<string>;
getOverlayNotificationPosition: () => Promise<OverlayNotificationPosition>;
markActiveVideoWatched: () => Promise<boolean>;
getControllerConfig: () => Promise<ResolvedControllerConfig>;
saveControllerConfig: (update: ControllerConfigUpdate) => Promise<void>;
/** The overlay reports which controller it is reading (null when none). */
reportActiveController: (gamepadId: string | null) => void;
/** The controller the overlay last reported, for Alt+C before it sees a pad itself. */
getActiveControllerId: () => Promise<string | null>;
getJimakuMediaInfo: () => Promise<JimakuMediaInfo>;
jimakuSearchEntries: (query: JimakuSearchQuery) => Promise<JimakuApiResponse<JimakuEntry[]>>;
jimakuListFiles: (query: JimakuFilesQuery) => Promise<JimakuApiResponse<JimakuFileEntry[]>>;
jimakuDownloadFile: (query: JimakuDownloadQuery) => Promise<JimakuDownloadResult>;
tsukihimeSearchEntries: (
query: TsukihimeSearchQuery,
) => Promise<TsukihimeApiResponse<TsukihimeEntry[]>>;
tsukihimeListFiles: (
query: TsukihimeFilesQuery,
) => Promise<TsukihimeApiResponse<TsukihimeSubtitleFile[]>>;
tsukihimeDownloadFile: (query: TsukihimeDownloadQuery) => Promise<TsukihimeDownloadResult>;
tsukihimeGetSecondaryLanguages: () => Promise<string[]>;
toggleDevTools: () => void;
toggleStatsOverlay: () => void;
onSecondarySub: (callback: (text: string) => void) => void;
onSecondarySubMode: (callback: (mode: SecondarySubMode) => void) => void;
getSecondarySubMode: () => Promise<SecondarySubMode>;
getCurrentSecondarySub: () => Promise<string>;
focusMainWindow: () => Promise<void>;
activatePlaybackWindowForOverlayInteraction: () => Promise<boolean>;
getSubtitleStyle: () => Promise<SubtitleRendererStyleConfig | null>;
onSubtitleSelectionOpen: (callback: () => void) => void;
getSubtitleSelection: () => Promise<
import('../shared/subtitle-selection').SubtitleSelectionState
>;
applySubtitleSelection: (
request: import('../shared/subtitle-selection').SubtitleSelectionRequest,
) => Promise<void>;
onSubsyncManualOpen: (callback: (payload: SubsyncManualPayload) => void) => void;
runSubsyncManual: (request: SubsyncManualRunRequest) => Promise<SubsyncResult>;
onKikuFieldGroupingRequest: (callback: (data: KikuFieldGroupingRequestData) => void) => void;
onKikuFieldGroupingCancel: (callback: () => void) => void;
kikuBuildMergePreview: (request: KikuMergePreviewRequest) => Promise<KikuMergePreviewResponse>;
kikuFieldGroupingRespond: (choice: KikuFieldGroupingChoice) => void;
getRuntimeOptions: () => Promise<RuntimeOptionState[]>;
setRuntimeOptionValue: (
id: RuntimeOptionId,
value: RuntimeOptionValue,
) => Promise<RuntimeOptionApplyResult>;
onRuntimeOptionsChanged: (callback: (options: RuntimeOptionState[]) => void) => void;
onOpenRuntimeOptions: (callback: () => void) => void;
onOpenSessionHelp: (callback: (payload: SessionHelpOpenPayload) => void) => void;
onOpenChangelog: (callback: () => void) => void;
getChangelogSnapshot: (options?: { refresh?: boolean }) => Promise<ChangelogSnapshot>;
onOpenPluginPanel: (callback: (snapshot: PluginPanelSnapshot) => void) => void;
onPluginPanelUpdate: (callback: (snapshot: PluginPanelSnapshot) => void) => void;
onPluginPanelClose: (callback: (panelId: number) => void) => void;
onOpenControllerSelect: (callback: () => void) => void;
onOpenControllerDebug: (callback: () => void) => void;
onOpenJimaku: (callback: () => void) => void;
onOpenTsukihime: (callback: () => void) => void;
onOpenYoutubeTrackPicker: (callback: (payload: YoutubePickerOpenPayload) => void) => void;
onOpenMediaTimingReview: (callback: (payload: MediaTimingReviewOpenPayload) => void) => void;
onMediaTimingReviewPreviewEnded: (callback: (reviewId: string) => void) => void;
onMediaTimingReviewPreviewPosition: (
callback: (position: MediaTimingReviewPreviewPosition) => void,
) => void;
previewMediaTimingReview: (
request: MediaTimingReviewPreviewRequest,
) => Promise<MediaTimingReviewActionResult>;
getMediaTimingReviewFrame: (
request: MediaTimingReviewFrameRequest,
) => Promise<MediaTimingReviewFrameResult>;
getMediaTimingReviewWaveform: (
request: MediaTimingReviewWaveformRequest,
) => Promise<MediaTimingReviewWaveformResult>;
stopMediaTimingReviewPreview: (reviewId: string) => Promise<MediaTimingReviewActionResult>;
resolveMediaTimingReview: (
request: MediaTimingReviewResolveRequest,
) => Promise<MediaTimingReviewActionResult>;
onOpenPlaylistBrowser: (callback: () => void) => void;
onOpenCharacterDictionaryManager: (callback: () => void) => void;
onSubtitleSidebarToggle: (callback: () => void) => void;
onPrimarySubtitleBarToggle: (callback: () => void) => void;
onCancelYoutubeTrackPicker: (callback: () => void) => void;
onSessionNumericSelectionStart: (
callback: (payload: SessionNumericSelectionStartPayload) => void,
) => void;
onKeyboardModeToggleRequested: (callback: () => void) => void;
onControllerSuspendedChanged: (callback: (suspended: boolean) => void) => void;
/** Alt+C saved controller settings; reload them with `getControllerConfig`. */
onControllerConfigChanged: (callback: () => void) => void;
/** macOS: a button pressed while mpv was in front, which the Gamepad API never saw. */
onControllerBackgroundPress: (callback: (buttonIndex: number) => void) => void;
/** mpv's pause property changed, from any source. */
onPlaybackPauseChanged: (callback: (paused: boolean) => void) => void;
onLookupWindowToggleRequested: (callback: () => void) => void;
getPlaylistBrowserSnapshot: () => Promise<PlaylistBrowserSnapshot>;
appendPlaylistBrowserFile: (path: string) => Promise<PlaylistBrowserMutationResult>;
playPlaylistBrowserIndex: (index: number) => Promise<PlaylistBrowserMutationResult>;
removePlaylistBrowserIndex: (index: number) => Promise<PlaylistBrowserMutationResult>;
movePlaylistBrowserIndex: (
index: number,
direction: 1 | -1,
) => Promise<PlaylistBrowserMutationResult>;
youtubePickerResolve: (
request: YoutubePickerResolveRequest,
) => Promise<YoutubePickerResolveResult>;
getCharacterDictionarySelection: (
searchTitle?: string,
) => Promise<CharacterDictionarySelectionSnapshot>;
setCharacterDictionarySelection: (
mediaId: number,
replaceManagedMediaId?: number,
mediaTitle?: string,
) => Promise<CharacterDictionarySelectionResult | CharacterDictionaryManagerMutationResult>;
getCharacterDictionaryManagerSnapshot: () => Promise<CharacterDictionaryManagerSnapshot>;
removeCharacterDictionaryManagedEntry: (
mediaId: number,
) => Promise<CharacterDictionaryManagerMutationResult>;
moveCharacterDictionaryManagedEntry: (
mediaId: number,
direction: 1 | -1,
) => Promise<CharacterDictionaryManagerMutationResult>;
notifyOverlayModalClosed: (
modal:
| 'runtime-options'
| 'subsync'
| 'subtitle-selection'
| 'subtitle-generation'
| 'jimaku'
| 'tsukihime'
| 'youtube-track-picker'
| 'media-timing-review'
| 'playlist-browser'
| 'kiku'
| 'controller-select'
| 'controller-debug'
| 'subtitle-sidebar'
| 'session-help'
| 'character-dictionary'
| 'changelog'
| 'plugin-panel',
/** Which instance closed, for modals that swap content in place (the plugin panel's id). */
instanceId?: number,
) => void;
notifyOverlayModalOpened: (
modal:
| 'runtime-options'
| 'subsync'
| 'subtitle-selection'
| 'subtitle-generation'
| 'jimaku'
| 'tsukihime'
| 'youtube-track-picker'
| 'media-timing-review'
| 'playlist-browser'
| 'kiku'
| 'controller-select'
| 'controller-debug'
| 'subtitle-sidebar'
| 'session-help'
| 'character-dictionary'
| 'changelog'
| 'plugin-panel',
) => void;
reportOverlayContentBounds: (measurement: OverlayContentMeasurement) => void;
onSessionBindingsChanged: (callback: (bindings: CompiledSessionBinding[]) => void) => void;
onMpvInputBindingsChanged: (callback: () => void) => void;
onConfigHotReload: (callback: (payload: ConfigHotReloadPayload) => void) => void;
}
declare global {
interface Window {
electronAPI: ElectronAPI;
}
}