mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-01 06:22:44 -08:00
pretty
This commit is contained in:
@@ -4,26 +4,26 @@ export function asFiniteNumber(
|
||||
min?: number,
|
||||
max?: number,
|
||||
): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
||||
if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;
|
||||
if (min !== undefined && value < min) return min;
|
||||
if (max !== undefined && value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
export function asString(value: unknown, fallback: string): string {
|
||||
if (typeof value !== "string") return fallback;
|
||||
if (typeof value !== 'string') return fallback;
|
||||
const trimmed = value.trim();
|
||||
return trimmed.length > 0 ? trimmed : fallback;
|
||||
}
|
||||
|
||||
export function asBoolean(value: unknown, fallback: boolean): boolean {
|
||||
if (typeof value === "boolean") return value;
|
||||
if (typeof value === "string") {
|
||||
if (typeof value === 'boolean') return value;
|
||||
if (typeof value === 'string') {
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (normalized === "yes" || normalized === "true" || normalized === "1") {
|
||||
if (normalized === 'yes' || normalized === 'true' || normalized === '1') {
|
||||
return true;
|
||||
}
|
||||
if (normalized === "no" || normalized === "false" || normalized === "0") {
|
||||
if (normalized === 'no' || normalized === 'false' || normalized === '0') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as readline from "readline";
|
||||
import { CliArgs } from "../../cli/args";
|
||||
import { createLogger } from "../../logger";
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as readline from 'readline';
|
||||
import { CliArgs } from '../../cli/args';
|
||||
import { createLogger } from '../../logger';
|
||||
|
||||
const logger = createLogger("core:config-gen");
|
||||
const logger = createLogger('core:config-gen');
|
||||
|
||||
function formatBackupTimestamp(date = new Date()): string {
|
||||
const pad = (v: number): string => String(v).padStart(2, "0");
|
||||
const pad = (v: number): string => String(v).padStart(2, '0');
|
||||
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}-${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ function promptYesNo(question: string): Promise<boolean> {
|
||||
rl.question(question, (answer) => {
|
||||
rl.close();
|
||||
const normalized = answer.trim().toLowerCase();
|
||||
resolve(normalized === "y" || normalized === "yes");
|
||||
resolve(normalized === 'y' || normalized === 'yes');
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -35,14 +35,14 @@ export async function generateDefaultConfigFile(
|
||||
): Promise<number> {
|
||||
const targetPath = args.configPath
|
||||
? path.resolve(args.configPath)
|
||||
: path.join(options.configDir, "config.jsonc");
|
||||
: path.join(options.configDir, 'config.jsonc');
|
||||
const template = options.generateTemplate(options.defaultConfig);
|
||||
|
||||
if (fs.existsSync(targetPath)) {
|
||||
if (args.backupOverwrite) {
|
||||
const backupPath = `${targetPath}.bak.${formatBackupTimestamp()}`;
|
||||
fs.copyFileSync(targetPath, backupPath);
|
||||
fs.writeFileSync(targetPath, template, "utf-8");
|
||||
fs.writeFileSync(targetPath, template, 'utf-8');
|
||||
logger.info(`Backed up existing config to ${backupPath}`);
|
||||
logger.info(`Generated config at ${targetPath}`);
|
||||
return 0;
|
||||
@@ -59,13 +59,13 @@ export async function generateDefaultConfigFile(
|
||||
`Config exists at ${targetPath}. Back up and overwrite? [y/N] `,
|
||||
);
|
||||
if (!confirmed) {
|
||||
logger.info("Config generation cancelled.");
|
||||
logger.info('Config generation cancelled.');
|
||||
return 0;
|
||||
}
|
||||
|
||||
const backupPath = `${targetPath}.bak.${formatBackupTimestamp()}`;
|
||||
fs.copyFileSync(targetPath, backupPath);
|
||||
fs.writeFileSync(targetPath, template, "utf-8");
|
||||
fs.writeFileSync(targetPath, template, 'utf-8');
|
||||
logger.info(`Backed up existing config to ${backupPath}`);
|
||||
logger.info(`Generated config at ${targetPath}`);
|
||||
return 0;
|
||||
@@ -75,7 +75,7 @@ export async function generateDefaultConfigFile(
|
||||
if (!fs.existsSync(parentDir)) {
|
||||
fs.mkdirSync(parentDir, { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(targetPath, template, "utf-8");
|
||||
fs.writeFileSync(targetPath, template, 'utf-8');
|
||||
logger.info(`Generated config at ${targetPath}`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CliArgs, shouldStartApp } from "../../cli/args";
|
||||
import { createLogger } from "../../logger";
|
||||
import { CliArgs, shouldStartApp } from '../../cli/args';
|
||||
import { createLogger } from '../../logger';
|
||||
|
||||
const logger = createLogger("core:electron-backend");
|
||||
const logger = createLogger('core:electron-backend');
|
||||
|
||||
function getElectronOzonePlatformHint(): string | null {
|
||||
const hint = process.env.ELECTRON_OZONE_PLATFORM_HINT?.trim().toLowerCase();
|
||||
@@ -12,31 +12,29 @@ function getElectronOzonePlatformHint(): string | null {
|
||||
}
|
||||
|
||||
function shouldPreferWaylandBackend(): boolean {
|
||||
return Boolean(
|
||||
process.env.HYPRLAND_INSTANCE_SIGNATURE || process.env.SWAYSOCK,
|
||||
);
|
||||
return Boolean(process.env.HYPRLAND_INSTANCE_SIGNATURE || process.env.SWAYSOCK);
|
||||
}
|
||||
|
||||
export function forceX11Backend(args: CliArgs): void {
|
||||
if (process.platform !== "linux") return;
|
||||
if (process.platform !== 'linux') return;
|
||||
if (!shouldStartApp(args)) return;
|
||||
if (shouldPreferWaylandBackend()) return;
|
||||
|
||||
const hint = getElectronOzonePlatformHint();
|
||||
if (hint === "x11") return;
|
||||
if (hint === 'x11') return;
|
||||
|
||||
process.env.ELECTRON_OZONE_PLATFORM_HINT = "x11";
|
||||
process.env.OZONE_PLATFORM = "x11";
|
||||
process.env.ELECTRON_OZONE_PLATFORM_HINT = 'x11';
|
||||
process.env.OZONE_PLATFORM = 'x11';
|
||||
}
|
||||
|
||||
export function enforceUnsupportedWaylandMode(args: CliArgs): void {
|
||||
if (process.platform !== "linux") return;
|
||||
if (process.platform !== 'linux') return;
|
||||
if (!shouldStartApp(args)) return;
|
||||
const hint = getElectronOzonePlatformHint();
|
||||
if (hint !== "wayland") return;
|
||||
if (hint !== 'wayland') return;
|
||||
|
||||
const message =
|
||||
"Unsupported Electron backend: Wayland. Set ELECTRON_OZONE_PLATFORM_HINT=x11 and restart SubMiner.";
|
||||
'Unsupported Electron backend: Wayland. Set ELECTRON_OZONE_PLATFORM_HINT=x11 and restart SubMiner.';
|
||||
logger.error(message);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
export { generateDefaultConfigFile } from "./config-gen";
|
||||
export {
|
||||
enforceUnsupportedWaylandMode,
|
||||
forceX11Backend,
|
||||
} from "./electron-backend";
|
||||
export { asBoolean, asFiniteNumber, asString } from "./coerce";
|
||||
export { resolveKeybindings } from "./keybindings";
|
||||
export { resolveConfiguredShortcuts } from "./shortcut-config";
|
||||
export { showDesktopNotification } from "./notification";
|
||||
export { generateDefaultConfigFile } from './config-gen';
|
||||
export { enforceUnsupportedWaylandMode, forceX11Backend } from './electron-backend';
|
||||
export { asBoolean, asFiniteNumber, asString } from './coerce';
|
||||
export { resolveKeybindings } from './keybindings';
|
||||
export { resolveConfiguredShortcuts } from './shortcut-config';
|
||||
export { showDesktopNotification } from './notification';
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { Config, Keybinding } from "../../types";
|
||||
import { Config, Keybinding } from '../../types';
|
||||
|
||||
export function resolveKeybindings(
|
||||
config: Config,
|
||||
defaultKeybindings: Keybinding[],
|
||||
): Keybinding[] {
|
||||
export function resolveKeybindings(config: Config, defaultKeybindings: Keybinding[]): Keybinding[] {
|
||||
const userBindings = config.keybindings || [];
|
||||
const bindingMap = new Map<string, (string | number)[] | null>();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Notification, nativeImage } from "electron";
|
||||
import * as fs from "fs";
|
||||
import { createLogger } from "../../logger";
|
||||
import { Notification, nativeImage } from 'electron';
|
||||
import * as fs from 'fs';
|
||||
import { createLogger } from '../../logger';
|
||||
|
||||
const logger = createLogger("core:notification");
|
||||
const logger = createLogger('core:notification');
|
||||
|
||||
export function showDesktopNotification(
|
||||
title: string,
|
||||
@@ -20,33 +20,28 @@ export function showDesktopNotification(
|
||||
|
||||
if (options.icon) {
|
||||
const isFilePath =
|
||||
typeof options.icon === "string" &&
|
||||
(options.icon.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(options.icon));
|
||||
typeof options.icon === 'string' &&
|
||||
(options.icon.startsWith('/') || /^[a-zA-Z]:[\\/]/.test(options.icon));
|
||||
|
||||
if (isFilePath) {
|
||||
if (fs.existsSync(options.icon)) {
|
||||
notificationOptions.icon = options.icon;
|
||||
} else {
|
||||
logger.warn("Notification icon file not found", options.icon);
|
||||
logger.warn('Notification icon file not found', options.icon);
|
||||
}
|
||||
} else if (
|
||||
typeof options.icon === "string" &&
|
||||
options.icon.startsWith("data:image/")
|
||||
) {
|
||||
const base64Data = options.icon.replace(/^data:image\/\w+;base64,/, "");
|
||||
} else if (typeof options.icon === 'string' && options.icon.startsWith('data:image/')) {
|
||||
const base64Data = options.icon.replace(/^data:image\/\w+;base64,/, '');
|
||||
try {
|
||||
const image = nativeImage.createFromBuffer(
|
||||
Buffer.from(base64Data, "base64"),
|
||||
);
|
||||
const image = nativeImage.createFromBuffer(Buffer.from(base64Data, 'base64'));
|
||||
if (image.isEmpty()) {
|
||||
logger.warn(
|
||||
"Notification icon created from base64 is empty - image format may not be supported by Electron",
|
||||
'Notification icon created from base64 is empty - image format may not be supported by Electron',
|
||||
);
|
||||
} else {
|
||||
notificationOptions.icon = image;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error("Failed to create notification icon from base64", err);
|
||||
logger.error('Failed to create notification icon from base64', err);
|
||||
}
|
||||
} else {
|
||||
notificationOptions.icon = options.icon;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Config } from "../../types";
|
||||
import { Config } from '../../types';
|
||||
|
||||
export interface ConfiguredShortcuts {
|
||||
toggleVisibleOverlayGlobal: string | null | undefined;
|
||||
@@ -21,13 +21,9 @@ export function resolveConfiguredShortcuts(
|
||||
config: Config,
|
||||
defaultConfig: Config,
|
||||
): ConfiguredShortcuts {
|
||||
const normalizeShortcut = (
|
||||
value: string | null | undefined,
|
||||
): string | null | undefined => {
|
||||
if (typeof value !== "string") return value;
|
||||
return value
|
||||
.replace(/\bKey([A-Z])\b/g, "$1")
|
||||
.replace(/\bDigit([0-9])\b/g, "$1");
|
||||
const normalizeShortcut = (value: string | null | undefined): string | null | undefined => {
|
||||
if (typeof value !== 'string') return value;
|
||||
return value.replace(/\bKey([A-Z])\b/g, '$1').replace(/\bDigit([0-9])\b/g, '$1');
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -43,42 +39,34 @@ export function resolveConfiguredShortcuts(
|
||||
config.shortcuts?.copySubtitle ?? defaultConfig.shortcuts?.copySubtitle,
|
||||
),
|
||||
copySubtitleMultiple: normalizeShortcut(
|
||||
config.shortcuts?.copySubtitleMultiple ??
|
||||
defaultConfig.shortcuts?.copySubtitleMultiple,
|
||||
config.shortcuts?.copySubtitleMultiple ?? defaultConfig.shortcuts?.copySubtitleMultiple,
|
||||
),
|
||||
updateLastCardFromClipboard: normalizeShortcut(
|
||||
config.shortcuts?.updateLastCardFromClipboard ??
|
||||
defaultConfig.shortcuts?.updateLastCardFromClipboard,
|
||||
),
|
||||
triggerFieldGrouping: normalizeShortcut(
|
||||
config.shortcuts?.triggerFieldGrouping ??
|
||||
defaultConfig.shortcuts?.triggerFieldGrouping,
|
||||
config.shortcuts?.triggerFieldGrouping ?? defaultConfig.shortcuts?.triggerFieldGrouping,
|
||||
),
|
||||
triggerSubsync: normalizeShortcut(
|
||||
config.shortcuts?.triggerSubsync ??
|
||||
defaultConfig.shortcuts?.triggerSubsync,
|
||||
config.shortcuts?.triggerSubsync ?? defaultConfig.shortcuts?.triggerSubsync,
|
||||
),
|
||||
mineSentence: normalizeShortcut(
|
||||
config.shortcuts?.mineSentence ?? defaultConfig.shortcuts?.mineSentence,
|
||||
),
|
||||
mineSentenceMultiple: normalizeShortcut(
|
||||
config.shortcuts?.mineSentenceMultiple ??
|
||||
defaultConfig.shortcuts?.mineSentenceMultiple,
|
||||
config.shortcuts?.mineSentenceMultiple ?? defaultConfig.shortcuts?.mineSentenceMultiple,
|
||||
),
|
||||
multiCopyTimeoutMs:
|
||||
config.shortcuts?.multiCopyTimeoutMs ??
|
||||
defaultConfig.shortcuts?.multiCopyTimeoutMs ??
|
||||
5000,
|
||||
config.shortcuts?.multiCopyTimeoutMs ?? defaultConfig.shortcuts?.multiCopyTimeoutMs ?? 5000,
|
||||
toggleSecondarySub: normalizeShortcut(
|
||||
config.shortcuts?.toggleSecondarySub ??
|
||||
defaultConfig.shortcuts?.toggleSecondarySub,
|
||||
config.shortcuts?.toggleSecondarySub ?? defaultConfig.shortcuts?.toggleSecondarySub,
|
||||
),
|
||||
markAudioCard: normalizeShortcut(
|
||||
config.shortcuts?.markAudioCard ?? defaultConfig.shortcuts?.markAudioCard,
|
||||
),
|
||||
openRuntimeOptions: normalizeShortcut(
|
||||
config.shortcuts?.openRuntimeOptions ??
|
||||
defaultConfig.shortcuts?.openRuntimeOptions,
|
||||
config.shortcuts?.openRuntimeOptions ?? defaultConfig.shortcuts?.openRuntimeOptions,
|
||||
),
|
||||
openJimaku: normalizeShortcut(
|
||||
config.shortcuts?.openJimaku ?? defaultConfig.shortcuts?.openJimaku,
|
||||
|
||||
Reference in New Issue
Block a user