feat(plugins): add JavaScript plugin system with overlay panel (#303)

This commit is contained in:
sudacode authored and GitHub committed 2026-10-31 19:09:54 -07:00
1 parent 90fc7cf940
commit a9a4c4f083
110 files changed
+5897 -344

No files matched your search

+9
View File
@@ -142,6 +142,13 @@ export interface RawShortcutsConfig extends ShortcutsConfig {
export type DictionaryBackend = 'yomitan' | 'hachidori';
/** One `plugins.<id>` entry; the id names the directory under `<config dir>/plugins/`. */
export interface PluginConfig {
enabled?: boolean;
/** Passed to the plugin as `ctx.settings`. */
settings?: Record<string, unknown>;
}
export interface Config {
dictionaryBackend?: DictionaryBackend;
subtitlePosition?: SubtitlePosition;
@@ -176,6 +183,7 @@ export interface Config {
stats?: StatsConfig;
updates?: UpdatesConfig;
notifications?: NotificationsConfig;
plugins?: Record<string, PluginConfig>;
logging?: {
level?: 'debug' | 'info' | 'warn' | 'error';
rotation?: LogRotation;
@@ -427,6 +435,7 @@ export interface ResolvedConfig {
};
updates: Required<UpdatesConfig>;
notifications: Required<NotificationsConfig>;
plugins: Record<string, Required<PluginConfig>>;
logging: {
level: 'debug' | 'info' | 'warn' | 'error';
rotation: LogRotation;
+16 -2
View File
@@ -388,6 +388,13 @@ export interface ConfigHotReloadPayload {
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;
@@ -538,6 +545,9 @@ export interface ElectronAPI {
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;
@@ -615,7 +625,10 @@ export interface ElectronAPI {
| 'subtitle-sidebar'
| 'session-help'
| 'character-dictionary'
| 'changelog',
| 'changelog'
| 'plugin-panel',
/** Which instance closed, for modals that swap content in place (the plugin panel's id). */
instanceId?: number,
) => void;
notifyOverlayModalOpened: (
modal:
@@ -634,7 +647,8 @@ export interface ElectronAPI {
| 'subtitle-sidebar'
| 'session-help'
| 'character-dictionary'
| 'changelog',
| 'changelog'
| 'plugin-panel',
) => void;
reportOverlayContentBounds: (measurement: OverlayContentMeasurement) => void;
onSessionBindingsChanged: (callback: (bindings: CompiledSessionBinding[]) => void) => void;
+3 -37
View File
@@ -1,35 +1,7 @@
export type SessionKeyModifier = 'ctrl' | 'alt' | 'shift' | 'meta';
import type { SessionActionId, SessionActionPayload } from '../plugin-api';
export type { SessionActionId, SessionActionPayload } from '../plugin-api';
export type SessionActionId =
| 'toggleStatsOverlay'
| 'markWatched'
| 'toggleVisibleOverlay'
| 'copySubtitle'
| 'copySubtitleMultiple'
| 'updateLastCardFromClipboard'
| 'triggerFieldGrouping'
| 'triggerSubsync'
| 'mineSentence'
| 'mineSentenceMultiple'
| 'toggleSecondarySub'
| 'toggleSubtitleSidebar'
| 'toggleNotificationHistory'
| 'appendClipboardVideoToQueue'
| 'markAudioCard'
| 'openRuntimeOptions'
| 'openSessionHelp'
| 'openCharacterDictionaryManager'
| 'openControllerSelect'
| 'openControllerDebug'
| 'openJimaku'
| 'openTsukihime'
| 'openSubtitleSelection'
| 'openSubtitleGeneration'
| 'openYoutubePicker'
| 'openPlaylistBrowser'
| 'replayCurrentSubtitle'
| 'playNextSubtitle'
| 'cycleRuntimeOption';
export type SessionKeyModifier = 'ctrl' | 'alt' | 'shift' | 'meta';
export interface SessionKeySpec {
code: string;
@@ -49,12 +21,6 @@ export interface SessionBindingWarning {
conflictingPaths?: string[];
}
export interface SessionActionPayload {
count?: number;
runtimeOptionId?: string;
direction?: 1 | -1;
}
type CompiledSessionBindingBase = {
sourcePath: string;
originalKey: string;