mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
refactor: extract jimaku helpers and overlay shortcut service
This commit is contained in:
158
src/core/services/overlay-shortcut-service.ts
Normal file
158
src/core/services/overlay-shortcut-service.ts
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
import { globalShortcut } from "electron";
|
||||||
|
import { ConfiguredShortcuts } from "../utils/shortcut-config";
|
||||||
|
import { isGlobalShortcutRegisteredSafe } from "./shortcut-fallback-service";
|
||||||
|
|
||||||
|
export interface OverlayShortcutHandlers {
|
||||||
|
copySubtitle: () => void;
|
||||||
|
copySubtitleMultiple: (timeoutMs: number) => void;
|
||||||
|
updateLastCardFromClipboard: () => void;
|
||||||
|
triggerFieldGrouping: () => void;
|
||||||
|
triggerSubsync: () => void;
|
||||||
|
mineSentence: () => void;
|
||||||
|
mineSentenceMultiple: (timeoutMs: number) => void;
|
||||||
|
toggleSecondarySub: () => void;
|
||||||
|
markAudioCard: () => void;
|
||||||
|
openRuntimeOptions: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerOverlayShortcutsService(
|
||||||
|
shortcuts: ConfiguredShortcuts,
|
||||||
|
handlers: OverlayShortcutHandlers,
|
||||||
|
): boolean {
|
||||||
|
let registeredAny = false;
|
||||||
|
const registerOverlayShortcut = (
|
||||||
|
accelerator: string,
|
||||||
|
handler: () => void,
|
||||||
|
label: string,
|
||||||
|
): void => {
|
||||||
|
if (isGlobalShortcutRegisteredSafe(accelerator)) {
|
||||||
|
registeredAny = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ok = globalShortcut.register(accelerator, handler);
|
||||||
|
if (!ok) {
|
||||||
|
console.warn(
|
||||||
|
`Failed to register overlay shortcut ${label}: ${accelerator}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
registeredAny = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (shortcuts.copySubtitleMultiple) {
|
||||||
|
registerOverlayShortcut(
|
||||||
|
shortcuts.copySubtitleMultiple,
|
||||||
|
() => handlers.copySubtitleMultiple(shortcuts.multiCopyTimeoutMs),
|
||||||
|
"copySubtitleMultiple",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcuts.copySubtitle) {
|
||||||
|
registerOverlayShortcut(
|
||||||
|
shortcuts.copySubtitle,
|
||||||
|
() => handlers.copySubtitle(),
|
||||||
|
"copySubtitle",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcuts.triggerFieldGrouping) {
|
||||||
|
registerOverlayShortcut(
|
||||||
|
shortcuts.triggerFieldGrouping,
|
||||||
|
() => handlers.triggerFieldGrouping(),
|
||||||
|
"triggerFieldGrouping",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcuts.triggerSubsync) {
|
||||||
|
registerOverlayShortcut(
|
||||||
|
shortcuts.triggerSubsync,
|
||||||
|
() => handlers.triggerSubsync(),
|
||||||
|
"triggerSubsync",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcuts.mineSentence) {
|
||||||
|
registerOverlayShortcut(
|
||||||
|
shortcuts.mineSentence,
|
||||||
|
() => handlers.mineSentence(),
|
||||||
|
"mineSentence",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcuts.mineSentenceMultiple) {
|
||||||
|
registerOverlayShortcut(
|
||||||
|
shortcuts.mineSentenceMultiple,
|
||||||
|
() => handlers.mineSentenceMultiple(shortcuts.multiCopyTimeoutMs),
|
||||||
|
"mineSentenceMultiple",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcuts.toggleSecondarySub) {
|
||||||
|
registerOverlayShortcut(
|
||||||
|
shortcuts.toggleSecondarySub,
|
||||||
|
() => handlers.toggleSecondarySub(),
|
||||||
|
"toggleSecondarySub",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcuts.updateLastCardFromClipboard) {
|
||||||
|
registerOverlayShortcut(
|
||||||
|
shortcuts.updateLastCardFromClipboard,
|
||||||
|
() => handlers.updateLastCardFromClipboard(),
|
||||||
|
"updateLastCardFromClipboard",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcuts.markAudioCard) {
|
||||||
|
registerOverlayShortcut(
|
||||||
|
shortcuts.markAudioCard,
|
||||||
|
() => handlers.markAudioCard(),
|
||||||
|
"markAudioCard",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shortcuts.openRuntimeOptions) {
|
||||||
|
registerOverlayShortcut(
|
||||||
|
shortcuts.openRuntimeOptions,
|
||||||
|
() => handlers.openRuntimeOptions(),
|
||||||
|
"openRuntimeOptions",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return registeredAny;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unregisterOverlayShortcutsService(
|
||||||
|
shortcuts: ConfiguredShortcuts,
|
||||||
|
): void {
|
||||||
|
if (shortcuts.copySubtitle) {
|
||||||
|
globalShortcut.unregister(shortcuts.copySubtitle);
|
||||||
|
}
|
||||||
|
if (shortcuts.copySubtitleMultiple) {
|
||||||
|
globalShortcut.unregister(shortcuts.copySubtitleMultiple);
|
||||||
|
}
|
||||||
|
if (shortcuts.updateLastCardFromClipboard) {
|
||||||
|
globalShortcut.unregister(shortcuts.updateLastCardFromClipboard);
|
||||||
|
}
|
||||||
|
if (shortcuts.triggerFieldGrouping) {
|
||||||
|
globalShortcut.unregister(shortcuts.triggerFieldGrouping);
|
||||||
|
}
|
||||||
|
if (shortcuts.triggerSubsync) {
|
||||||
|
globalShortcut.unregister(shortcuts.triggerSubsync);
|
||||||
|
}
|
||||||
|
if (shortcuts.mineSentence) {
|
||||||
|
globalShortcut.unregister(shortcuts.mineSentence);
|
||||||
|
}
|
||||||
|
if (shortcuts.mineSentenceMultiple) {
|
||||||
|
globalShortcut.unregister(shortcuts.mineSentenceMultiple);
|
||||||
|
}
|
||||||
|
if (shortcuts.toggleSecondarySub) {
|
||||||
|
globalShortcut.unregister(shortcuts.toggleSecondarySub);
|
||||||
|
}
|
||||||
|
if (shortcuts.markAudioCard) {
|
||||||
|
globalShortcut.unregister(shortcuts.markAudioCard);
|
||||||
|
}
|
||||||
|
if (shortcuts.openRuntimeOptions) {
|
||||||
|
globalShortcut.unregister(shortcuts.openRuntimeOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
import * as http from "http";
|
import * as http from "http";
|
||||||
import * as https from "https";
|
import * as https from "https";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
import * as fs from "fs";
|
||||||
import * as childProcess from "child_process";
|
import * as childProcess from "child_process";
|
||||||
import {
|
import {
|
||||||
JimakuApiResponse,
|
JimakuApiResponse,
|
||||||
JimakuConfig,
|
JimakuConfig,
|
||||||
|
JimakuDownloadResult,
|
||||||
|
JimakuFileEntry,
|
||||||
|
JimakuLanguagePreference,
|
||||||
JimakuMediaInfo,
|
JimakuMediaInfo,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
|
|
||||||
@@ -245,3 +249,107 @@ export function parseMediaInfo(mediaPath: string | null): JimakuMediaInfo {
|
|||||||
rawTitle: name,
|
rawTitle: name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatLangScore(name: string, pref: JimakuLanguagePreference): number {
|
||||||
|
if (pref === "none") return 0;
|
||||||
|
const upper = name.toUpperCase();
|
||||||
|
const hasJa =
|
||||||
|
/(^|[\W_])JA([\W_]|$)/.test(upper) ||
|
||||||
|
/(^|[\W_])JPN([\W_]|$)/.test(upper) ||
|
||||||
|
upper.includes(".JA.");
|
||||||
|
const hasEn =
|
||||||
|
/(^|[\W_])EN([\W_]|$)/.test(upper) ||
|
||||||
|
/(^|[\W_])ENG([\W_]|$)/.test(upper) ||
|
||||||
|
upper.includes(".EN.");
|
||||||
|
if (pref === "ja") {
|
||||||
|
if (hasJa) return 2;
|
||||||
|
if (hasEn) return 1;
|
||||||
|
} else if (pref === "en") {
|
||||||
|
if (hasEn) return 2;
|
||||||
|
if (hasJa) return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sortJimakuFiles(
|
||||||
|
files: JimakuFileEntry[],
|
||||||
|
pref: JimakuLanguagePreference,
|
||||||
|
): JimakuFileEntry[] {
|
||||||
|
if (pref === "none") return files;
|
||||||
|
return [...files].sort((a, b) => {
|
||||||
|
const scoreDiff =
|
||||||
|
formatLangScore(b.name, pref) - formatLangScore(a.name, pref);
|
||||||
|
if (scoreDiff !== 0) return scoreDiff;
|
||||||
|
return a.name.localeCompare(b.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRemoteMediaPath(mediaPath: string): boolean {
|
||||||
|
return /^[a-z][a-z0-9+.-]*:\/\//i.test(mediaPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function downloadToFile(
|
||||||
|
url: string,
|
||||||
|
destPath: string,
|
||||||
|
headers: Record<string, string>,
|
||||||
|
redirectCount = 0,
|
||||||
|
): Promise<JimakuDownloadResult> {
|
||||||
|
if (redirectCount > 3) {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
error: { error: "Too many redirects while downloading subtitle." },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
const transport = parsedUrl.protocol === "https:" ? https : http;
|
||||||
|
|
||||||
|
const req = transport.get(parsedUrl, { headers }, (res) => {
|
||||||
|
const status = res.statusCode || 0;
|
||||||
|
if ([301, 302, 303, 307, 308].includes(status) && res.headers.location) {
|
||||||
|
const redirectUrl = new URL(res.headers.location, parsedUrl).toString();
|
||||||
|
res.resume();
|
||||||
|
downloadToFile(redirectUrl, destPath, headers, redirectCount + 1).then(
|
||||||
|
resolve,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status < 200 || status >= 300) {
|
||||||
|
res.resume();
|
||||||
|
resolve({
|
||||||
|
ok: false,
|
||||||
|
error: {
|
||||||
|
error: `Failed to download subtitle (HTTP ${status}).`,
|
||||||
|
code: status,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileStream = fs.createWriteStream(destPath);
|
||||||
|
res.pipe(fileStream);
|
||||||
|
fileStream.on("finish", () => {
|
||||||
|
fileStream.close(() => {
|
||||||
|
resolve({ ok: true, path: destPath });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
fileStream.on("error", (err: Error) => {
|
||||||
|
resolve({
|
||||||
|
ok: false,
|
||||||
|
error: {
|
||||||
|
error: `Failed to save subtitle: ${(err as Error).message}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on("error", (err) => {
|
||||||
|
resolve({
|
||||||
|
ok: false,
|
||||||
|
error: { error: `Download request failed: ${(err as Error).message}` },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
323
src/main.ts
323
src/main.ts
@@ -91,9 +91,12 @@ import { SubtitleTimingTracker } from "./subtitle-timing-tracker";
|
|||||||
import { AnkiIntegration } from "./anki-integration";
|
import { AnkiIntegration } from "./anki-integration";
|
||||||
import { RuntimeOptionsManager } from "./runtime-options";
|
import { RuntimeOptionsManager } from "./runtime-options";
|
||||||
import {
|
import {
|
||||||
|
downloadToFile,
|
||||||
|
isRemoteMediaPath,
|
||||||
jimakuFetchJson as jimakuFetchJsonRequest,
|
jimakuFetchJson as jimakuFetchJsonRequest,
|
||||||
parseMediaInfo,
|
parseMediaInfo,
|
||||||
resolveJimakuApiKey as resolveJimakuApiKeyFromConfig,
|
resolveJimakuApiKey as resolveJimakuApiKeyFromConfig,
|
||||||
|
sortJimakuFiles,
|
||||||
} from "./jimaku/utils";
|
} from "./jimaku/utils";
|
||||||
import {
|
import {
|
||||||
CommandResult,
|
CommandResult,
|
||||||
@@ -136,6 +139,10 @@ import {
|
|||||||
isGlobalShortcutRegisteredSafe,
|
isGlobalShortcutRegisteredSafe,
|
||||||
shortcutMatchesInputForLocalFallback,
|
shortcutMatchesInputForLocalFallback,
|
||||||
} from "./core/services/shortcut-fallback-service";
|
} from "./core/services/shortcut-fallback-service";
|
||||||
|
import {
|
||||||
|
registerOverlayShortcutsService,
|
||||||
|
unregisterOverlayShortcutsService,
|
||||||
|
} from "./core/services/overlay-shortcut-service";
|
||||||
import {
|
import {
|
||||||
ConfigService,
|
ConfigService,
|
||||||
DEFAULT_CONFIG,
|
DEFAULT_CONFIG,
|
||||||
@@ -2841,110 +2848,6 @@ async function triggerSubsyncFromConfig(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatLangScore(name: string, pref: JimakuLanguagePreference): number {
|
|
||||||
if (pref === "none") return 0;
|
|
||||||
const upper = name.toUpperCase();
|
|
||||||
const hasJa =
|
|
||||||
/(^|[\W_])JA([\W_]|$)/.test(upper) ||
|
|
||||||
/(^|[\W_])JPN([\W_]|$)/.test(upper) ||
|
|
||||||
upper.includes(".JA.");
|
|
||||||
const hasEn =
|
|
||||||
/(^|[\W_])EN([\W_]|$)/.test(upper) ||
|
|
||||||
/(^|[\W_])ENG([\W_]|$)/.test(upper) ||
|
|
||||||
upper.includes(".EN.");
|
|
||||||
if (pref === "ja") {
|
|
||||||
if (hasJa) return 2;
|
|
||||||
if (hasEn) return 1;
|
|
||||||
} else if (pref === "en") {
|
|
||||||
if (hasEn) return 2;
|
|
||||||
if (hasJa) return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortJimakuFiles(
|
|
||||||
files: JimakuFileEntry[],
|
|
||||||
pref: JimakuLanguagePreference,
|
|
||||||
): JimakuFileEntry[] {
|
|
||||||
if (pref === "none") return files;
|
|
||||||
return [...files].sort((a, b) => {
|
|
||||||
const scoreDiff =
|
|
||||||
formatLangScore(b.name, pref) - formatLangScore(a.name, pref);
|
|
||||||
if (scoreDiff !== 0) return scoreDiff;
|
|
||||||
return a.name.localeCompare(b.name);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRemoteMediaPath(mediaPath: string): boolean {
|
|
||||||
return /^[a-z][a-z0-9+.-]*:\/\//i.test(mediaPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function downloadToFile(
|
|
||||||
url: string,
|
|
||||||
destPath: string,
|
|
||||||
headers: Record<string, string>,
|
|
||||||
redirectCount = 0,
|
|
||||||
): Promise<JimakuDownloadResult> {
|
|
||||||
if (redirectCount > 3) {
|
|
||||||
return {
|
|
||||||
ok: false,
|
|
||||||
error: { error: "Too many redirects while downloading subtitle." },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const parsedUrl = new URL(url);
|
|
||||||
const transport = parsedUrl.protocol === "https:" ? https : http;
|
|
||||||
|
|
||||||
const req = transport.get(parsedUrl, { headers }, (res) => {
|
|
||||||
const status = res.statusCode || 0;
|
|
||||||
if ([301, 302, 303, 307, 308].includes(status) && res.headers.location) {
|
|
||||||
const redirectUrl = new URL(res.headers.location, parsedUrl).toString();
|
|
||||||
res.resume();
|
|
||||||
downloadToFile(redirectUrl, destPath, headers, redirectCount + 1).then(
|
|
||||||
resolve,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status < 200 || status >= 300) {
|
|
||||||
res.resume();
|
|
||||||
resolve({
|
|
||||||
ok: false,
|
|
||||||
error: {
|
|
||||||
error: `Failed to download subtitle (HTTP ${status}).`,
|
|
||||||
code: status,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileStream = fs.createWriteStream(destPath);
|
|
||||||
res.pipe(fileStream);
|
|
||||||
fileStream.on("finish", () => {
|
|
||||||
fileStream.close(() => {
|
|
||||||
resolve({ ok: true, path: destPath });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
fileStream.on("error", (err) => {
|
|
||||||
resolve({
|
|
||||||
ok: false,
|
|
||||||
error: {
|
|
||||||
error: `Failed to save subtitle: ${(err as Error).message}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
req.on("error", (err) => {
|
|
||||||
resolve({
|
|
||||||
ok: false,
|
|
||||||
error: { error: `Download request failed: ${(err as Error).message}` },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelPendingMultiCopy(): void {
|
function cancelPendingMultiCopy(): void {
|
||||||
if (!pendingMultiCopy) return;
|
if (!pendingMultiCopy) return;
|
||||||
|
|
||||||
@@ -3194,140 +3097,51 @@ function handleMineSentenceDigit(count: number): void {
|
|||||||
|
|
||||||
function registerOverlayShortcuts(): void {
|
function registerOverlayShortcuts(): void {
|
||||||
const shortcuts = getConfiguredShortcuts();
|
const shortcuts = getConfiguredShortcuts();
|
||||||
let registeredAny = false;
|
shortcutsRegistered = registerOverlayShortcutsService(shortcuts, {
|
||||||
const registerOverlayShortcut = (
|
copySubtitle: () => {
|
||||||
accelerator: string,
|
copyCurrentSubtitle();
|
||||||
handler: () => void,
|
},
|
||||||
label: string,
|
copySubtitleMultiple: (timeoutMs) => {
|
||||||
): void => {
|
startPendingMultiCopy(timeoutMs);
|
||||||
if (isGlobalShortcutRegisteredSafe(accelerator)) {
|
},
|
||||||
registeredAny = true;
|
updateLastCardFromClipboard: () => {
|
||||||
return;
|
updateLastCardFromClipboard().catch((err) => {
|
||||||
}
|
console.error("updateLastCardFromClipboard failed:", err);
|
||||||
const ok = globalShortcut.register(accelerator, handler);
|
showMpvOsd(`Update failed: ${(err as Error).message}`);
|
||||||
if (!ok) {
|
});
|
||||||
console.warn(
|
},
|
||||||
`Failed to register overlay shortcut ${label}: ${accelerator}`,
|
triggerFieldGrouping: () => {
|
||||||
);
|
triggerFieldGrouping().catch((err) => {
|
||||||
return;
|
console.error("triggerFieldGrouping failed:", err);
|
||||||
}
|
showMpvOsd(`Field grouping failed: ${(err as Error).message}`);
|
||||||
registeredAny = true;
|
});
|
||||||
};
|
},
|
||||||
|
triggerSubsync: () => {
|
||||||
if (shortcuts.copySubtitleMultiple) {
|
triggerSubsyncFromConfig().catch((err) => {
|
||||||
registerOverlayShortcut(
|
console.error("triggerSubsyncFromConfig failed:", err);
|
||||||
shortcuts.copySubtitleMultiple,
|
showMpvOsd(`Subsync failed: ${(err as Error).message}`);
|
||||||
() => {
|
});
|
||||||
startPendingMultiCopy(shortcuts.multiCopyTimeoutMs);
|
},
|
||||||
},
|
mineSentence: () => {
|
||||||
"copySubtitleMultiple",
|
mineSentenceCard().catch((err) => {
|
||||||
);
|
console.error("mineSentenceCard failed:", err);
|
||||||
}
|
showMpvOsd(`Mine sentence failed: ${(err as Error).message}`);
|
||||||
|
});
|
||||||
if (shortcuts.copySubtitle) {
|
},
|
||||||
registerOverlayShortcut(
|
mineSentenceMultiple: (timeoutMs) => {
|
||||||
shortcuts.copySubtitle,
|
startPendingMineSentenceMultiple(timeoutMs);
|
||||||
() => {
|
},
|
||||||
copyCurrentSubtitle();
|
toggleSecondarySub: () => cycleSecondarySubMode(),
|
||||||
},
|
markAudioCard: () => {
|
||||||
"copySubtitle",
|
markLastCardAsAudioCard().catch((err) => {
|
||||||
);
|
console.error("markLastCardAsAudioCard failed:", err);
|
||||||
}
|
showMpvOsd(`Audio card failed: ${(err as Error).message}`);
|
||||||
|
});
|
||||||
if (shortcuts.triggerFieldGrouping) {
|
},
|
||||||
registerOverlayShortcut(
|
openRuntimeOptions: () => {
|
||||||
shortcuts.triggerFieldGrouping,
|
openRuntimeOptionsPalette();
|
||||||
() => {
|
},
|
||||||
triggerFieldGrouping().catch((err) => {
|
});
|
||||||
console.error("triggerFieldGrouping failed:", err);
|
|
||||||
showMpvOsd(`Field grouping failed: ${(err as Error).message}`);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
"triggerFieldGrouping",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shortcuts.triggerSubsync) {
|
|
||||||
registerOverlayShortcut(
|
|
||||||
shortcuts.triggerSubsync,
|
|
||||||
() => {
|
|
||||||
triggerSubsyncFromConfig().catch((err) => {
|
|
||||||
console.error("triggerSubsyncFromConfig failed:", err);
|
|
||||||
showMpvOsd(`Subsync failed: ${(err as Error).message}`);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
"triggerSubsync",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shortcuts.mineSentence) {
|
|
||||||
registerOverlayShortcut(
|
|
||||||
shortcuts.mineSentence,
|
|
||||||
() => {
|
|
||||||
mineSentenceCard().catch((err) => {
|
|
||||||
console.error("mineSentenceCard failed:", err);
|
|
||||||
showMpvOsd(`Mine sentence failed: ${(err as Error).message}`);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
"mineSentence",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shortcuts.mineSentenceMultiple) {
|
|
||||||
registerOverlayShortcut(
|
|
||||||
shortcuts.mineSentenceMultiple,
|
|
||||||
() => {
|
|
||||||
startPendingMineSentenceMultiple(shortcuts.multiCopyTimeoutMs);
|
|
||||||
},
|
|
||||||
"mineSentenceMultiple",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shortcuts.toggleSecondarySub) {
|
|
||||||
registerOverlayShortcut(
|
|
||||||
shortcuts.toggleSecondarySub,
|
|
||||||
() => cycleSecondarySubMode(),
|
|
||||||
"toggleSecondarySub",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shortcuts.updateLastCardFromClipboard) {
|
|
||||||
registerOverlayShortcut(
|
|
||||||
shortcuts.updateLastCardFromClipboard,
|
|
||||||
() => {
|
|
||||||
updateLastCardFromClipboard().catch((err) => {
|
|
||||||
console.error("updateLastCardFromClipboard failed:", err);
|
|
||||||
showMpvOsd(`Update failed: ${(err as Error).message}`);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
"updateLastCardFromClipboard",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shortcuts.markAudioCard) {
|
|
||||||
registerOverlayShortcut(
|
|
||||||
shortcuts.markAudioCard,
|
|
||||||
() => {
|
|
||||||
markLastCardAsAudioCard().catch((err) => {
|
|
||||||
console.error("markLastCardAsAudioCard failed:", err);
|
|
||||||
showMpvOsd(`Audio card failed: ${(err as Error).message}`);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
"markAudioCard",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shortcuts.openRuntimeOptions) {
|
|
||||||
registerOverlayShortcut(
|
|
||||||
shortcuts.openRuntimeOptions,
|
|
||||||
() => {
|
|
||||||
openRuntimeOptionsPalette();
|
|
||||||
},
|
|
||||||
"openRuntimeOptions",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
shortcutsRegistered = registeredAny;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function unregisterOverlayShortcuts(): void {
|
function unregisterOverlayShortcuts(): void {
|
||||||
@@ -3336,38 +3150,7 @@ function unregisterOverlayShortcuts(): void {
|
|||||||
cancelPendingMultiCopy();
|
cancelPendingMultiCopy();
|
||||||
cancelPendingMineSentenceMultiple();
|
cancelPendingMineSentenceMultiple();
|
||||||
|
|
||||||
const shortcuts = getConfiguredShortcuts();
|
unregisterOverlayShortcutsService(getConfiguredShortcuts());
|
||||||
|
|
||||||
if (shortcuts.copySubtitle) {
|
|
||||||
globalShortcut.unregister(shortcuts.copySubtitle);
|
|
||||||
}
|
|
||||||
if (shortcuts.copySubtitleMultiple) {
|
|
||||||
globalShortcut.unregister(shortcuts.copySubtitleMultiple);
|
|
||||||
}
|
|
||||||
if (shortcuts.updateLastCardFromClipboard) {
|
|
||||||
globalShortcut.unregister(shortcuts.updateLastCardFromClipboard);
|
|
||||||
}
|
|
||||||
if (shortcuts.triggerFieldGrouping) {
|
|
||||||
globalShortcut.unregister(shortcuts.triggerFieldGrouping);
|
|
||||||
}
|
|
||||||
if (shortcuts.triggerSubsync) {
|
|
||||||
globalShortcut.unregister(shortcuts.triggerSubsync);
|
|
||||||
}
|
|
||||||
if (shortcuts.mineSentence) {
|
|
||||||
globalShortcut.unregister(shortcuts.mineSentence);
|
|
||||||
}
|
|
||||||
if (shortcuts.mineSentenceMultiple) {
|
|
||||||
globalShortcut.unregister(shortcuts.mineSentenceMultiple);
|
|
||||||
}
|
|
||||||
if (shortcuts.toggleSecondarySub) {
|
|
||||||
globalShortcut.unregister(shortcuts.toggleSecondarySub);
|
|
||||||
}
|
|
||||||
if (shortcuts.markAudioCard) {
|
|
||||||
globalShortcut.unregister(shortcuts.markAudioCard);
|
|
||||||
}
|
|
||||||
if (shortcuts.openRuntimeOptions) {
|
|
||||||
globalShortcut.unregister(shortcuts.openRuntimeOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
shortcutsRegistered = false;
|
shortcutsRegistered = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user