mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-07-27 04:49:49 -07:00
feat(shortcuts): make clipboard-video-append shortcut configurable (#158)
This commit is contained in:
@@ -103,6 +103,7 @@ export const CORE_DEFAULT_CONFIG: Pick<
|
||||
openControllerDebug: 'Alt+Shift+C',
|
||||
toggleSubtitleSidebar: 'Backslash',
|
||||
toggleNotificationHistory: 'CommandOrControl+N',
|
||||
appendClipboardVideoToQueue: 'CommandOrControl+A',
|
||||
},
|
||||
secondarySub: {
|
||||
secondarySubLanguages: [],
|
||||
|
||||
@@ -646,5 +646,11 @@ export function buildCoreConfigOptionRegistry(
|
||||
defaultValue: defaultConfig.shortcuts.toggleNotificationHistory,
|
||||
description: 'Accelerator that toggles the overlay notification history panel.',
|
||||
},
|
||||
{
|
||||
path: 'shortcuts.appendClipboardVideoToQueue',
|
||||
kind: 'string',
|
||||
defaultValue: defaultConfig.shortcuts.appendClipboardVideoToQueue,
|
||||
description: 'Accelerator that appends a video path from the clipboard to the mpv playlist.',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -236,7 +236,12 @@ export function applyCoreDomainConfig(context: ResolveContext): void {
|
||||
'openCharacterDictionaryManager',
|
||||
'openRuntimeOptions',
|
||||
'openJimaku',
|
||||
'openSessionHelp',
|
||||
'openControllerSelect',
|
||||
'openControllerDebug',
|
||||
'toggleSubtitleSidebar',
|
||||
'toggleNotificationHistory',
|
||||
'appendClipboardVideoToQueue',
|
||||
] as const;
|
||||
|
||||
for (const key of shortcutKeys) {
|
||||
|
||||
@@ -600,7 +600,7 @@ function subsectionForPath(path: string): string | undefined {
|
||||
) {
|
||||
return 'Open Panels';
|
||||
}
|
||||
if (leaf === 'triggerSubsync') return 'Playback';
|
||||
if (leaf === 'triggerSubsync' || leaf === 'appendClipboardVideoToQueue') return 'Playback';
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
|
||||
@@ -33,6 +33,7 @@ function makeShortcuts(overrides: Partial<ConfiguredShortcuts> = {}): Configured
|
||||
openControllerDebug: null,
|
||||
toggleSubtitleSidebar: null,
|
||||
toggleNotificationHistory: null,
|
||||
appendClipboardVideoToQueue: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ function createShortcuts(overrides: Partial<ConfiguredShortcuts> = {}): Configur
|
||||
openControllerDebug: null,
|
||||
toggleSubtitleSidebar: null,
|
||||
toggleNotificationHistory: null,
|
||||
appendClipboardVideoToQueue: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ function createDeps(overrides: Partial<SessionActionExecutorDeps> = {}) {
|
||||
toggleSecondarySub: () => calls.push('secondary'),
|
||||
toggleSubtitleSidebar: () => calls.push('sidebar'),
|
||||
toggleNotificationHistory: () => calls.push('notification-history'),
|
||||
appendClipboardVideoToQueue: () => calls.push('append-clipboard-video'),
|
||||
markLastCardAsAudioCard: async () => {
|
||||
calls.push('audio');
|
||||
},
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface SessionActionExecutorDeps {
|
||||
toggleSecondarySub: () => void;
|
||||
toggleSubtitleSidebar: () => void;
|
||||
toggleNotificationHistory: () => void;
|
||||
appendClipboardVideoToQueue: () => void;
|
||||
markLastCardAsAudioCard: () => Promise<void>;
|
||||
markActiveVideoWatched: () => Promise<boolean>;
|
||||
openRuntimeOptionsPalette: () => void;
|
||||
@@ -82,6 +83,9 @@ export async function dispatchSessionAction(
|
||||
case 'toggleNotificationHistory':
|
||||
deps.toggleNotificationHistory();
|
||||
return;
|
||||
case 'appendClipboardVideoToQueue':
|
||||
deps.appendClipboardVideoToQueue();
|
||||
return;
|
||||
case 'markAudioCard':
|
||||
await deps.markLastCardAsAudioCard();
|
||||
return;
|
||||
|
||||
@@ -27,6 +27,7 @@ function createShortcuts(overrides: Partial<ConfiguredShortcuts> = {}): Configur
|
||||
openControllerDebug: null,
|
||||
toggleSubtitleSidebar: null,
|
||||
toggleNotificationHistory: null,
|
||||
appendClipboardVideoToQueue: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
@@ -515,6 +516,8 @@ test('compileSessionBindings wires every configured shortcut key into the shared
|
||||
'openControllerSelect',
|
||||
'openControllerDebug',
|
||||
'toggleSubtitleSidebar',
|
||||
'toggleNotificationHistory',
|
||||
'appendClipboardVideoToQueue',
|
||||
];
|
||||
const shortcuts = createShortcuts();
|
||||
shortcutKeys.forEach((key, index) => {
|
||||
@@ -582,6 +585,42 @@ test('buildPluginSessionBindingsArtifact emits CLI args for plugin-bound session
|
||||
});
|
||||
});
|
||||
|
||||
test('appendClipboardVideoToQueue shortcut compiles to a session action with plugin CLI args', () => {
|
||||
const result = compileSessionBindings({
|
||||
shortcuts: createShortcuts({
|
||||
appendClipboardVideoToQueue: 'CommandOrControl+A',
|
||||
}),
|
||||
keybindings: [],
|
||||
platform: 'linux',
|
||||
});
|
||||
|
||||
assert.deepEqual(result.warnings, []);
|
||||
const binding = result.bindings.find(
|
||||
(candidate) =>
|
||||
candidate.actionType === 'session-action' &&
|
||||
candidate.actionId === 'appendClipboardVideoToQueue',
|
||||
);
|
||||
assert.ok(binding);
|
||||
assert.deepEqual(binding.key, { code: 'KeyA', modifiers: ['ctrl'] });
|
||||
|
||||
const artifact = buildPluginSessionBindingsArtifact({
|
||||
bindings: result.bindings,
|
||||
warnings: result.warnings,
|
||||
numericSelectionTimeoutMs: 2500,
|
||||
now: new Date('2026-05-26T00:00:00.000Z'),
|
||||
});
|
||||
const pluginBinding = artifact.bindings.find(
|
||||
(candidate) =>
|
||||
candidate.actionType === 'session-action' &&
|
||||
candidate.actionId === 'appendClipboardVideoToQueue',
|
||||
);
|
||||
assert.ok(pluginBinding && 'cliArgs' in pluginBinding);
|
||||
assert.equal(pluginBinding.cliArgs?.[0], '--session-action');
|
||||
assert.deepEqual(JSON.parse(pluginBinding.cliArgs?.[1] ?? ''), {
|
||||
actionId: 'appendClipboardVideoToQueue',
|
||||
});
|
||||
});
|
||||
|
||||
test('buildPluginSessionBindingsArtifact preserves plugin selector CLI for no-count multi-line actions', () => {
|
||||
const result = compileSessionBindings({
|
||||
shortcuts: createShortcuts({
|
||||
|
||||
@@ -60,6 +60,7 @@ const SESSION_SHORTCUT_ACTIONS: Array<{
|
||||
{ key: 'openControllerDebug', actionId: 'openControllerDebug' },
|
||||
{ key: 'toggleSubtitleSidebar', actionId: 'toggleSubtitleSidebar' },
|
||||
{ key: 'toggleNotificationHistory', actionId: 'toggleNotificationHistory' },
|
||||
{ key: 'appendClipboardVideoToQueue', actionId: 'appendClipboardVideoToQueue' },
|
||||
];
|
||||
|
||||
function normalizeModifiers(modifiers: SessionKeyModifier[]): SessionKeyModifier[] {
|
||||
|
||||
@@ -20,6 +20,7 @@ export interface ConfiguredShortcuts {
|
||||
openControllerDebug: string | null | undefined;
|
||||
toggleSubtitleSidebar: string | null | undefined;
|
||||
toggleNotificationHistory: string | null | undefined;
|
||||
appendClipboardVideoToQueue: string | null | undefined;
|
||||
}
|
||||
|
||||
export function resolveConfiguredShortcuts(
|
||||
@@ -69,5 +70,6 @@ export function resolveConfiguredShortcuts(
|
||||
openControllerDebug: normalizeShortcut(shortcutValue('openControllerDebug')),
|
||||
toggleSubtitleSidebar: normalizeShortcut(shortcutValue('toggleSubtitleSidebar')),
|
||||
toggleNotificationHistory: normalizeShortcut(shortcutValue('toggleNotificationHistory')),
|
||||
appendClipboardVideoToQueue: normalizeShortcut(shortcutValue('appendClipboardVideoToQueue')),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5416,6 +5416,9 @@ async function dispatchSessionAction(request: SessionActionDispatchRequest): Pro
|
||||
toggleSecondarySub: () => handleCycleSecondarySubMode(),
|
||||
toggleSubtitleSidebar: () => toggleSubtitleSidebar(),
|
||||
toggleNotificationHistory: () => toggleNotificationHistoryPanel(),
|
||||
appendClipboardVideoToQueue: () => {
|
||||
appendClipboardVideoToQueue();
|
||||
},
|
||||
markLastCardAsAudioCard: () => markLastCardAsAudioCard(),
|
||||
markActiveVideoWatched: async () => {
|
||||
ensureImmersionTrackerStarted();
|
||||
|
||||
@@ -24,6 +24,7 @@ function createShortcuts(): ConfiguredShortcuts {
|
||||
openControllerDebug: null,
|
||||
toggleSubtitleSidebar: null,
|
||||
toggleNotificationHistory: null,
|
||||
appendClipboardVideoToQueue: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ function createShortcuts(): ConfiguredShortcuts {
|
||||
openControllerDebug: null,
|
||||
toggleSubtitleSidebar: null,
|
||||
toggleNotificationHistory: null,
|
||||
appendClipboardVideoToQueue: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ function createEmptyShortcuts(): ConfiguredShortcuts {
|
||||
openControllerDebug: null,
|
||||
toggleSubtitleSidebar: null,
|
||||
toggleNotificationHistory: null,
|
||||
appendClipboardVideoToQueue: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -508,7 +509,6 @@ function createKeyboardHandlerHarness() {
|
||||
openControllerDebugModal: () => {
|
||||
openControllerDebugCount += 1;
|
||||
},
|
||||
appendClipboardVideoToQueue: () => {},
|
||||
getPlaybackPaused: () => testGlobals.getPlaybackPaused(),
|
||||
});
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ export function createKeyboardHandlers(
|
||||
}) => void;
|
||||
openControllerSelectModal?: () => void;
|
||||
openControllerDebugModal?: () => void;
|
||||
appendClipboardVideoToQueue: () => void;
|
||||
getPlaybackPaused: () => Promise<boolean | null>;
|
||||
toggleSubtitleSidebarModal?: () => void;
|
||||
},
|
||||
@@ -1221,12 +1220,6 @@ export function createKeyboardHandlers(
|
||||
return;
|
||||
}
|
||||
|
||||
if ((e.ctrlKey || e.metaKey) && !e.altKey && !e.shiftKey && e.code === 'KeyA' && !e.repeat) {
|
||||
e.preventDefault();
|
||||
options.appendClipboardVideoToQueue();
|
||||
return;
|
||||
}
|
||||
|
||||
const keyString = keyEventToString(e);
|
||||
const binding = ctx.state.sessionBindingMap.get(keyString);
|
||||
if (binding) {
|
||||
|
||||
@@ -203,6 +203,8 @@ function describeSessionAction(
|
||||
return 'Toggle subtitle sidebar';
|
||||
case 'toggleNotificationHistory':
|
||||
return 'Toggle notification history';
|
||||
case 'appendClipboardVideoToQueue':
|
||||
return 'Append clipboard video path to playlist';
|
||||
case 'markAudioCard':
|
||||
return 'Mark audio card';
|
||||
case 'markWatched':
|
||||
@@ -267,6 +269,7 @@ function sectionForSessionBinding(binding: CompiledSessionBinding): string {
|
||||
return 'Modals and tools';
|
||||
case 'replayCurrentSubtitle':
|
||||
case 'playNextSubtitle':
|
||||
case 'appendClipboardVideoToQueue':
|
||||
return 'Playback and navigation';
|
||||
case 'cycleRuntimeOption':
|
||||
return 'Runtime settings';
|
||||
@@ -346,7 +349,6 @@ function buildFixedOverlaySections(): SessionHelpSection[] {
|
||||
title: 'Fixed overlay controls',
|
||||
rows: [
|
||||
{ shortcut: 'V', action: 'Toggle primary subtitle bar visibility' },
|
||||
{ shortcut: 'Ctrl/Cmd + A', action: 'Append clipboard video path to playlist' },
|
||||
{ shortcut: 'Right-click', action: 'Toggle playback outside subtitle area' },
|
||||
{ shortcut: 'Right-click + drag', action: 'Reposition subtitles on subtitle area' },
|
||||
],
|
||||
|
||||
@@ -215,9 +215,6 @@ const keyboardHandlers = createKeyboardHandlers(ctx, {
|
||||
window.electronAPI.notifyOverlayModalOpened('controller-debug');
|
||||
}
|
||||
},
|
||||
appendClipboardVideoToQueue: () => {
|
||||
void window.electronAPI.appendClipboardVideoToQueue();
|
||||
},
|
||||
getPlaybackPaused: () => window.electronAPI.getPlaybackPaused(),
|
||||
toggleSubtitleSidebarModal: () => {
|
||||
void subtitleSidebarModal.toggleSubtitleSidebarModal();
|
||||
|
||||
@@ -33,6 +33,7 @@ const SESSION_ACTION_IDS: SessionActionId[] = [
|
||||
'markAudioCard',
|
||||
'toggleSubtitleSidebar',
|
||||
'toggleNotificationHistory',
|
||||
'appendClipboardVideoToQueue',
|
||||
'openRuntimeOptions',
|
||||
'openSessionHelp',
|
||||
'openCharacterDictionaryManager',
|
||||
|
||||
@@ -127,6 +127,7 @@ export interface ShortcutsConfig {
|
||||
openControllerDebug?: string | null;
|
||||
toggleSubtitleSidebar?: string | null;
|
||||
toggleNotificationHistory?: string | null;
|
||||
appendClipboardVideoToQueue?: string | null;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
|
||||
@@ -14,6 +14,7 @@ export type SessionActionId =
|
||||
| 'toggleSecondarySub'
|
||||
| 'toggleSubtitleSidebar'
|
||||
| 'toggleNotificationHistory'
|
||||
| 'appendClipboardVideoToQueue'
|
||||
| 'markAudioCard'
|
||||
| 'openRuntimeOptions'
|
||||
| 'openSessionHelp'
|
||||
|
||||
Reference in New Issue
Block a user