mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-07-28 04:49:49 -07:00
feat(animetosho): add English/Japanese subtitle download integration (#159)
This commit is contained in:
@@ -228,6 +228,7 @@ export interface MpvCommandRuntimeServiceDepsParams {
|
||||
triggerSubsyncFromConfig: HandleMpvCommandFromIpcOptions['triggerSubsyncFromConfig'];
|
||||
openRuntimeOptionsPalette: HandleMpvCommandFromIpcOptions['openRuntimeOptionsPalette'];
|
||||
openJimaku: HandleMpvCommandFromIpcOptions['openJimaku'];
|
||||
openAnimetosho: HandleMpvCommandFromIpcOptions['openAnimetosho'];
|
||||
openYoutubeTrackPicker: HandleMpvCommandFromIpcOptions['openYoutubeTrackPicker'];
|
||||
openPlaylistBrowser: HandleMpvCommandFromIpcOptions['openPlaylistBrowser'];
|
||||
showMpvOsd: HandleMpvCommandFromIpcOptions['showMpvOsd'];
|
||||
@@ -434,6 +435,7 @@ export function createMpvCommandRuntimeServiceDeps(
|
||||
triggerSubsyncFromConfig: params.triggerSubsyncFromConfig,
|
||||
openRuntimeOptionsPalette: params.openRuntimeOptionsPalette,
|
||||
openJimaku: params.openJimaku,
|
||||
openAnimetosho: params.openAnimetosho,
|
||||
openYoutubeTrackPicker: params.openYoutubeTrackPicker,
|
||||
openPlaylistBrowser: params.openPlaylistBrowser,
|
||||
runtimeOptionsCycle: params.runtimeOptionsCycle,
|
||||
|
||||
@@ -13,6 +13,7 @@ export interface MpvCommandFromIpcRuntimeDeps {
|
||||
triggerSubsyncFromConfig: () => void;
|
||||
openRuntimeOptionsPalette: () => void;
|
||||
openJimaku: () => void;
|
||||
openAnimetosho: () => void;
|
||||
openYoutubeTrackPicker: () => void | Promise<void>;
|
||||
openPlaylistBrowser: () => void | Promise<void>;
|
||||
cycleRuntimeOption: (id: RuntimeOptionId, direction: 1 | -1) => RuntimeOptionApplyResult;
|
||||
@@ -38,6 +39,7 @@ export function handleMpvCommandFromIpcRuntime(
|
||||
triggerSubsyncFromConfig: deps.triggerSubsyncFromConfig,
|
||||
openRuntimeOptionsPalette: deps.openRuntimeOptionsPalette,
|
||||
openJimaku: deps.openJimaku,
|
||||
openAnimetosho: deps.openAnimetosho,
|
||||
openYoutubeTrackPicker: deps.openYoutubeTrackPicker,
|
||||
openPlaylistBrowser: deps.openPlaylistBrowser,
|
||||
runtimeOptionsCycle: deps.cycleRuntimeOption,
|
||||
|
||||
@@ -49,6 +49,7 @@ export interface OverlayModalRuntime {
|
||||
) => boolean;
|
||||
openRuntimeOptionsPalette: () => void;
|
||||
openJimaku: () => void;
|
||||
openAnimetosho: () => void;
|
||||
handleOverlayModalClosed: (modal: OverlayHostedModal) => void;
|
||||
notifyOverlayModalOpened: (modal: OverlayHostedModal) => void;
|
||||
waitForModalOpen: (modal: OverlayHostedModal, timeoutMs: number) => Promise<boolean>;
|
||||
@@ -432,6 +433,12 @@ export function createOverlayModalRuntimeService(
|
||||
});
|
||||
};
|
||||
|
||||
const openAnimetosho = (): void => {
|
||||
sendToActiveOverlayWindow('animetosho:open', undefined, {
|
||||
restoreOnModalClose: 'animetosho',
|
||||
});
|
||||
};
|
||||
|
||||
const handleOverlayModalClosed = (modal: OverlayHostedModal): void => {
|
||||
openedModals.delete(modal);
|
||||
if (!restoreVisibleOverlayOnModalClose.has(modal)) return;
|
||||
@@ -511,6 +518,7 @@ export function createOverlayModalRuntimeService(
|
||||
sendToActiveOverlayWindow,
|
||||
openRuntimeOptionsPalette,
|
||||
openJimaku,
|
||||
openAnimetosho,
|
||||
handleOverlayModalClosed,
|
||||
notifyOverlayModalOpened,
|
||||
waitForModalOpen,
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface OverlayShortcutRuntimeServiceInput {
|
||||
openRuntimeOptionsPalette: () => void;
|
||||
openCharacterDictionaryManager: () => void;
|
||||
openJimaku: () => void;
|
||||
openAnimetosho: () => void;
|
||||
markAudioCard: () => Promise<void>;
|
||||
copySubtitleMultiple: (timeoutMs: number) => void;
|
||||
copySubtitle: () => void;
|
||||
@@ -56,6 +57,9 @@ export function createOverlayShortcutsRuntimeService(
|
||||
openJimaku: () => {
|
||||
input.openJimaku();
|
||||
},
|
||||
openAnimetosho: () => {
|
||||
input.openAnimetosho();
|
||||
},
|
||||
markAudioCard: () => {
|
||||
return input.markAudioCard();
|
||||
},
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import type { OverlayHostedModal } from '../../shared/ipc/contracts';
|
||||
import { IPC_CHANNELS } from '../../shared/ipc/contracts';
|
||||
import { openOverlayHostedModal, retryOverlayModalOpen } from './overlay-hosted-modal-open';
|
||||
|
||||
const ANIMETOSHO_MODAL: OverlayHostedModal = 'animetosho';
|
||||
const ANIMETOSHO_OPEN_TIMEOUT_MS = 1500;
|
||||
|
||||
export async function openAnimetoshoModal(deps: {
|
||||
ensureOverlayStartupPrereqs: () => void;
|
||||
ensureOverlayWindowsReadyForVisibilityActions: () => void;
|
||||
sendToActiveOverlayWindow: (
|
||||
channel: string,
|
||||
payload?: unknown,
|
||||
runtimeOptions?: {
|
||||
restoreOnModalClose?: OverlayHostedModal;
|
||||
preferModalWindow?: boolean;
|
||||
},
|
||||
) => boolean;
|
||||
waitForModalOpen: (modal: OverlayHostedModal, timeoutMs: number) => Promise<boolean>;
|
||||
logWarn: (message: string) => void;
|
||||
}): Promise<boolean> {
|
||||
return await retryOverlayModalOpen(
|
||||
{
|
||||
waitForModalOpen: deps.waitForModalOpen,
|
||||
logWarn: deps.logWarn,
|
||||
},
|
||||
{
|
||||
modal: ANIMETOSHO_MODAL,
|
||||
timeoutMs: ANIMETOSHO_OPEN_TIMEOUT_MS,
|
||||
retryWarning:
|
||||
'Animetosho modal did not acknowledge modal open on first attempt; retrying dedicated modal window.',
|
||||
sendOpen: () =>
|
||||
openOverlayHostedModal(
|
||||
{
|
||||
ensureOverlayStartupPrereqs: deps.ensureOverlayStartupPrereqs,
|
||||
ensureOverlayWindowsReadyForVisibilityActions:
|
||||
deps.ensureOverlayWindowsReadyForVisibilityActions,
|
||||
sendToActiveOverlayWindow: deps.sendToActiveOverlayWindow,
|
||||
},
|
||||
{
|
||||
channel: IPC_CHANNELS.event.animetoshoOpen,
|
||||
modal: ANIMETOSHO_MODAL,
|
||||
preferModalWindow: true,
|
||||
},
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -11,6 +11,7 @@ test('composeIpcRuntimeHandlers returns callable IPC handlers and registration b
|
||||
triggerSubsyncFromConfig: async () => {},
|
||||
openRuntimeOptionsPalette: () => {},
|
||||
openJimaku: () => {},
|
||||
openAnimetosho: () => {},
|
||||
openYoutubeTrackPicker: () => {},
|
||||
openPlaylistBrowser: () => {},
|
||||
cycleRuntimeOption: () => ({ ok: true }),
|
||||
|
||||
@@ -54,6 +54,7 @@ function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {
|
||||
openControllerSelect: false,
|
||||
openControllerDebug: false,
|
||||
openJimaku: false,
|
||||
openAnimetosho: false,
|
||||
openYoutubePicker: false,
|
||||
openPlaylistBrowser: false,
|
||||
replayCurrentSubtitle: false,
|
||||
|
||||
@@ -97,6 +97,7 @@ function hasAnyStartupCommandBeyondSetup(args: CliArgs): boolean {
|
||||
args.openControllerSelect ||
|
||||
args.openControllerDebug ||
|
||||
args.openJimaku ||
|
||||
args.openAnimetosho ||
|
||||
args.openYoutubePicker ||
|
||||
args.openPlaylistBrowser ||
|
||||
args.replayCurrentSubtitle ||
|
||||
|
||||
@@ -19,6 +19,7 @@ function createShortcuts(): ConfiguredShortcuts {
|
||||
openCharacterDictionaryManager: null,
|
||||
openRuntimeOptions: null,
|
||||
openJimaku: null,
|
||||
openAnimetosho: null,
|
||||
openSessionHelp: null,
|
||||
openControllerSelect: null,
|
||||
openControllerDebug: null,
|
||||
|
||||
@@ -23,6 +23,7 @@ function createShortcuts(): ConfiguredShortcuts {
|
||||
openCharacterDictionaryManager: null,
|
||||
openRuntimeOptions: null,
|
||||
openJimaku: null,
|
||||
openAnimetosho: null,
|
||||
openSessionHelp: null,
|
||||
openControllerSelect: null,
|
||||
openControllerDebug: null,
|
||||
|
||||
@@ -14,6 +14,7 @@ test('ipc bridge action main deps builders map callbacks', async () => {
|
||||
triggerSubsyncFromConfig: async () => {},
|
||||
openRuntimeOptionsPalette: () => {},
|
||||
openJimaku: () => {},
|
||||
openAnimetosho: () => {},
|
||||
openYoutubeTrackPicker: () => {},
|
||||
openPlaylistBrowser: () => {},
|
||||
cycleRuntimeOption: () => ({ ok: false as const, error: 'x' }),
|
||||
|
||||
@@ -11,6 +11,7 @@ test('handle mpv command handler forwards command and built deps', () => {
|
||||
triggerSubsyncFromConfig: () => {},
|
||||
openRuntimeOptionsPalette: () => {},
|
||||
openJimaku: () => {},
|
||||
openAnimetosho: () => {},
|
||||
openYoutubeTrackPicker: () => {},
|
||||
openPlaylistBrowser: () => {},
|
||||
cycleRuntimeOption: () => ({ ok: false as const, error: 'x' }),
|
||||
|
||||
@@ -8,6 +8,7 @@ test('ipc mpv command main deps builder maps callbacks', () => {
|
||||
triggerSubsyncFromConfig: () => calls.push('subsync'),
|
||||
openRuntimeOptionsPalette: () => calls.push('palette'),
|
||||
openJimaku: () => calls.push('jimaku'),
|
||||
openAnimetosho: () => calls.push('animetosho'),
|
||||
openYoutubeTrackPicker: () => {
|
||||
calls.push('youtube-picker');
|
||||
},
|
||||
@@ -29,6 +30,7 @@ test('ipc mpv command main deps builder maps callbacks', () => {
|
||||
deps.triggerSubsyncFromConfig();
|
||||
deps.openRuntimeOptionsPalette();
|
||||
deps.openJimaku();
|
||||
deps.openAnimetosho();
|
||||
void deps.openYoutubeTrackPicker();
|
||||
void deps.openPlaylistBrowser();
|
||||
assert.deepEqual(deps.cycleRuntimeOption('anki.nPlusOneMatchMode', 1), { ok: false, error: 'x' });
|
||||
@@ -45,6 +47,7 @@ test('ipc mpv command main deps builder maps callbacks', () => {
|
||||
'subsync',
|
||||
'palette',
|
||||
'jimaku',
|
||||
'animetosho',
|
||||
'youtube-picker',
|
||||
'playlist-browser',
|
||||
'osd:hello',
|
||||
|
||||
@@ -10,6 +10,7 @@ export function createBuildMpvCommandFromIpcRuntimeMainDepsHandler(
|
||||
triggerSubsyncFromConfig: () => deps.triggerSubsyncFromConfig(),
|
||||
openRuntimeOptionsPalette: () => deps.openRuntimeOptionsPalette(),
|
||||
openJimaku: () => deps.openJimaku(),
|
||||
openAnimetosho: () => deps.openAnimetosho(),
|
||||
openYoutubeTrackPicker: () => deps.openYoutubeTrackPicker(),
|
||||
openPlaylistBrowser: () => deps.openPlaylistBrowser(),
|
||||
cycleRuntimeOption: (id, direction) => deps.cycleRuntimeOption(id, direction),
|
||||
|
||||
@@ -18,6 +18,7 @@ test('overlay shortcuts runtime main deps builder maps lifecycle and action call
|
||||
openRuntimeOptionsPalette: () => calls.push('runtime-options'),
|
||||
openCharacterDictionaryManager: () => calls.push('character-dictionary-manager'),
|
||||
openJimaku: () => calls.push('jimaku'),
|
||||
openAnimetosho: () => calls.push('animetosho'),
|
||||
markAudioCard: async () => {
|
||||
calls.push('mark-audio');
|
||||
},
|
||||
|
||||
@@ -13,6 +13,7 @@ export function createBuildOverlayShortcutsRuntimeMainDepsHandler(
|
||||
openRuntimeOptionsPalette: () => deps.openRuntimeOptionsPalette(),
|
||||
openCharacterDictionaryManager: () => deps.openCharacterDictionaryManager(),
|
||||
openJimaku: () => deps.openJimaku(),
|
||||
openAnimetosho: () => deps.openAnimetosho(),
|
||||
markAudioCard: () => deps.markAudioCard(),
|
||||
copySubtitleMultiple: (timeoutMs: number) => deps.copySubtitleMultiple(timeoutMs),
|
||||
copySubtitle: () => deps.copySubtitle(),
|
||||
|
||||
Reference in New Issue
Block a user