mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-28 06:22:45 -08:00
refactor(cli): remove deprecated verbose logging flags
This commit is contained in:
@@ -12,7 +12,7 @@ test("parseArgs parses booleans and value flags", () => {
|
||||
"6000",
|
||||
"--log-level",
|
||||
"warn",
|
||||
"--verbose",
|
||||
"--debug",
|
||||
]);
|
||||
|
||||
assert.equal(args.start, true);
|
||||
@@ -20,7 +20,7 @@ test("parseArgs parses booleans and value flags", () => {
|
||||
assert.equal(args.backend, "hyprland");
|
||||
assert.equal(args.texthookerPort, 6000);
|
||||
assert.equal(args.logLevel, "warn");
|
||||
assert.equal(args.verbose, true);
|
||||
assert.equal(args.debug, true);
|
||||
});
|
||||
|
||||
test("parseArgs ignores missing value after --log-level", () => {
|
||||
@@ -38,7 +38,7 @@ test("hasExplicitCommand and shouldStartApp preserve command intent", () => {
|
||||
assert.equal(hasExplicitCommand(toggle), true);
|
||||
assert.equal(shouldStartApp(toggle), true);
|
||||
|
||||
const noCommand = parseArgs(["--verbose"]);
|
||||
const noCommand = parseArgs(["--log-level", "warn"]);
|
||||
assert.equal(hasExplicitCommand(noCommand), false);
|
||||
assert.equal(shouldStartApp(noCommand), false);
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export interface CliArgs {
|
||||
socketPath?: string;
|
||||
backend?: string;
|
||||
texthookerPort?: number;
|
||||
verbose: boolean;
|
||||
debug: boolean;
|
||||
logLevel?: "debug" | "info" | "warn" | "error";
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export function parseArgs(argv: string[]): CliArgs {
|
||||
autoStartOverlay: false,
|
||||
generateConfig: false,
|
||||
backupOverwrite: false,
|
||||
verbose: false,
|
||||
debug: false,
|
||||
};
|
||||
|
||||
const readValue = (value?: string): string | undefined => {
|
||||
@@ -114,7 +114,7 @@ export function parseArgs(argv: string[]): CliArgs {
|
||||
else if (arg === "--generate-config") args.generateConfig = true;
|
||||
else if (arg === "--backup-overwrite") args.backupOverwrite = true;
|
||||
else if (arg === "--help") args.help = true;
|
||||
else if (arg === "--verbose") args.verbose = true;
|
||||
else if (arg === "--debug") args.debug = true;
|
||||
else if (arg.startsWith("--log-level=")) {
|
||||
const value = arg.split("=", 2)[1]?.toLowerCase();
|
||||
if (
|
||||
|
||||
@@ -26,16 +26,15 @@ SubMiner CLI commands:
|
||||
--mark-audio-card Mark last card as audio card
|
||||
--open-runtime-options Open runtime options palette
|
||||
--auto-start-overlay Auto-hide mpv subtitles on connect (show overlay)
|
||||
--socket PATH Override MPV IPC socket/pipe path
|
||||
--backend BACKEND Override window tracker backend (auto, hyprland, sway, x11, macos)
|
||||
--port PORT Texthooker server port (default: ${defaultTexthookerPort})
|
||||
--verbose Enable debug logging (equivalent to --log-level debug)
|
||||
--log-level LEVEL Set log level: debug, info, warn, error
|
||||
--generate-config Generate default config.jsonc from centralized config registry
|
||||
--config-path PATH Target config path for --generate-config
|
||||
--backup-overwrite With --generate-config, backup and overwrite existing file
|
||||
--dev Run in development mode
|
||||
--debug Alias for --dev
|
||||
--help Show this help
|
||||
--socket PATH Override MPV IPC socket/pipe path
|
||||
--backend BACKEND Override window tracker backend (auto, hyprland, sway, x11, macos)
|
||||
--port PORT Texthooker server port (default: ${defaultTexthookerPort})
|
||||
--debug Enable app/dev mode
|
||||
--log-level LEVEL Set log level: debug, info, warn, error
|
||||
--generate-config Generate default config.jsonc from centralized config registry
|
||||
--config-path PATH Target config path for --generate-config
|
||||
--backup-overwrite With --generate-config, backup and overwrite existing file
|
||||
--dev Alias for --debug (app/dev mode)
|
||||
--help Show this help
|
||||
`);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {
|
||||
autoStartOverlay: false,
|
||||
generateConfig: false,
|
||||
backupOverwrite: false,
|
||||
verbose: false,
|
||||
debug: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ export class MpvIpcClient implements MpvClient {
|
||||
this.transport = new MpvSocketTransport({
|
||||
socketPath,
|
||||
onConnect: () => {
|
||||
logger.info("Connected to MPV socket");
|
||||
logger.debug("Connected to MPV socket");
|
||||
this.connected = true;
|
||||
this.connecting = false;
|
||||
this.socket = this.transport.getSocket();
|
||||
@@ -192,7 +192,7 @@ export class MpvIpcClient implements MpvClient {
|
||||
this.deps.autoStartOverlay ||
|
||||
this.deps.getResolvedConfig().auto_start_overlay === true;
|
||||
if (this.firstConnection && shouldAutoStart) {
|
||||
logger.info("Auto-starting overlay, hiding mpv subtitles");
|
||||
logger.debug("Auto-starting overlay, hiding mpv subtitles");
|
||||
setTimeout(() => {
|
||||
this.deps.setOverlayVisible(true);
|
||||
}, 100);
|
||||
|
||||
@@ -35,7 +35,7 @@ function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {
|
||||
autoStartOverlay: false,
|
||||
generateConfig: false,
|
||||
backupOverwrite: false,
|
||||
verbose: false,
|
||||
debug: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
@@ -43,7 +43,7 @@ function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {
|
||||
test("runStartupBootstrapRuntimeService configures startup state and starts lifecycle", () => {
|
||||
const calls: string[] = [];
|
||||
const args = makeArgs({
|
||||
verbose: true,
|
||||
logLevel: "debug",
|
||||
socketPath: "/tmp/custom.sock",
|
||||
texthookerPort: 9001,
|
||||
backend: "x11",
|
||||
@@ -52,7 +52,7 @@ test("runStartupBootstrapRuntimeService configures startup state and starts life
|
||||
});
|
||||
|
||||
const result = runStartupBootstrapRuntimeService({
|
||||
argv: ["node", "main.ts", "--verbose"],
|
||||
argv: ["node", "main.ts", "--log-level", "debug"],
|
||||
parseArgs: () => args,
|
||||
setLogLevel: (level, source) => calls.push(`setLog:${level}:${source}`),
|
||||
forceX11Backend: () => calls.push("forceX11"),
|
||||
@@ -77,15 +77,14 @@ test("runStartupBootstrapRuntimeService configures startup state and starts life
|
||||
]);
|
||||
});
|
||||
|
||||
test("runStartupBootstrapRuntimeService prefers --log-level over --verbose", () => {
|
||||
test("runStartupBootstrapRuntimeService keeps log-level precedence for repeated calls", () => {
|
||||
const calls: string[] = [];
|
||||
const args = makeArgs({
|
||||
logLevel: "warn",
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
runStartupBootstrapRuntimeService({
|
||||
argv: ["node", "main.ts", "--log-level", "warn", "--verbose"],
|
||||
argv: ["node", "main.ts", "--log-level", "warn"],
|
||||
parseArgs: () => args,
|
||||
setLogLevel: (level, source) => calls.push(`setLog:${level}:${source}`),
|
||||
forceX11Backend: () => calls.push("forceX11"),
|
||||
@@ -103,6 +102,27 @@ test("runStartupBootstrapRuntimeService prefers --log-level over --verbose", ()
|
||||
]);
|
||||
});
|
||||
|
||||
test("runStartupBootstrapRuntimeService keeps --debug separate from log verbosity", () => {
|
||||
const calls: string[] = [];
|
||||
const args = makeArgs({
|
||||
debug: true,
|
||||
});
|
||||
|
||||
runStartupBootstrapRuntimeService({
|
||||
argv: ["node", "main.ts", "--debug"],
|
||||
parseArgs: () => args,
|
||||
setLogLevel: (level, source) => calls.push(`setLog:${level}:${source}`),
|
||||
forceX11Backend: () => calls.push("forceX11"),
|
||||
enforceUnsupportedWaylandMode: () => calls.push("enforceWayland"),
|
||||
getDefaultSocketPath: () => "/tmp/default.sock",
|
||||
defaultTexthookerPort: 5174,
|
||||
runGenerateConfigFlow: () => false,
|
||||
startAppLifecycle: () => calls.push("startLifecycle"),
|
||||
});
|
||||
|
||||
assert.deepEqual(calls, ["forceX11", "enforceWayland", "startLifecycle"]);
|
||||
});
|
||||
|
||||
test("runStartupBootstrapRuntimeService skips lifecycle when generate-config flow handled", () => {
|
||||
const calls: string[] = [];
|
||||
const args = makeArgs({ generateConfig: true, logLevel: "warn" });
|
||||
|
||||
@@ -47,8 +47,6 @@ export function runStartupBootstrapRuntimeService(
|
||||
|
||||
if (initialArgs.logLevel) {
|
||||
deps.setLogLevel(initialArgs.logLevel, "cli");
|
||||
} else if (initialArgs.verbose) {
|
||||
deps.setLogLevel("debug", "cli");
|
||||
}
|
||||
|
||||
deps.forceX11Backend(initialArgs);
|
||||
|
||||
@@ -791,7 +791,7 @@ async function enrichYomitanPos1(
|
||||
mecabTokens = await deps.tokenizeWithMecab(text);
|
||||
} catch (err) {
|
||||
const error = err as Error;
|
||||
console.warn(
|
||||
logger.warn(
|
||||
"Failed to enrich Yomitan tokens with MeCab POS:",
|
||||
error.message,
|
||||
`tokenCount=${tokens.length}`,
|
||||
@@ -801,7 +801,7 @@ async function enrichYomitanPos1(
|
||||
}
|
||||
|
||||
if (!mecabTokens || mecabTokens.length === 0) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
"MeCab enrichment returned no tokens; preserving Yomitan token output.",
|
||||
`tokenCount=${tokens.length}`,
|
||||
`textLength=${text.length}`,
|
||||
@@ -886,7 +886,7 @@ async function ensureYomitanParserWindow(
|
||||
}
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(
|
||||
logger.error(
|
||||
"Failed to initialize Yomitan parser window:",
|
||||
(err as Error).message,
|
||||
);
|
||||
@@ -977,8 +977,8 @@ async function parseWithYomitanInternalParser(
|
||||
}
|
||||
|
||||
return enrichYomitanPos1(yomitanTokens, deps, text);
|
||||
} catch (err) {
|
||||
console.error("Yomitan parser request failed:", (err as Error).message);
|
||||
} catch (err) {
|
||||
logger.error("Yomitan parser request failed:", (err as Error).message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1066,7 +1066,7 @@ export async function tokenizeSubtitleService(
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Tokenization error:", (err as Error).message);
|
||||
logger.error("Tokenization error:", (err as Error).message);
|
||||
}
|
||||
|
||||
return { text: displayText, tokens: null };
|
||||
|
||||
@@ -2,6 +2,9 @@ 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");
|
||||
|
||||
function formatBackupTimestamp(date = new Date()): string {
|
||||
const pad = (v: number): string => String(v).padStart(2, "0");
|
||||
@@ -40,13 +43,13 @@ export async function generateDefaultConfigFile(
|
||||
const backupPath = `${targetPath}.bak.${formatBackupTimestamp()}`;
|
||||
fs.copyFileSync(targetPath, backupPath);
|
||||
fs.writeFileSync(targetPath, template, "utf-8");
|
||||
console.log(`Backed up existing config to ${backupPath}`);
|
||||
console.log(`Generated config at ${targetPath}`);
|
||||
logger.info(`Backed up existing config to ${backupPath}`);
|
||||
logger.info(`Generated config at ${targetPath}`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
||||
console.error(
|
||||
logger.error(
|
||||
`Config exists at ${targetPath}. Re-run with --backup-overwrite to back up and overwrite.`,
|
||||
);
|
||||
return 1;
|
||||
@@ -56,15 +59,15 @@ export async function generateDefaultConfigFile(
|
||||
`Config exists at ${targetPath}. Back up and overwrite? [y/N] `,
|
||||
);
|
||||
if (!confirmed) {
|
||||
console.log("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");
|
||||
console.log(`Backed up existing config to ${backupPath}`);
|
||||
console.log(`Generated config at ${targetPath}`);
|
||||
logger.info(`Backed up existing config to ${backupPath}`);
|
||||
logger.info(`Generated config at ${targetPath}`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -73,6 +76,6 @@ export async function generateDefaultConfigFile(
|
||||
fs.mkdirSync(parentDir, { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(targetPath, template, "utf-8");
|
||||
console.log(`Generated config at ${targetPath}`);
|
||||
logger.info(`Generated config at ${targetPath}`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { CliArgs, shouldStartApp } from "../../cli/args";
|
||||
import { createLogger } from "../../logger";
|
||||
|
||||
const logger = createLogger("core:electron-backend");
|
||||
|
||||
function getElectronOzonePlatformHint(): string | null {
|
||||
const hint = process.env.ELECTRON_OZONE_PLATFORM_HINT?.trim().toLowerCase();
|
||||
@@ -34,6 +37,6 @@ export function enforceUnsupportedWaylandMode(args: CliArgs): void {
|
||||
|
||||
const message =
|
||||
"Unsupported Electron backend: Wayland. Set ELECTRON_OZONE_PLATFORM_HINT=x11 and restart SubMiner.";
|
||||
console.error(message);
|
||||
logger.error(message);
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { Notification, nativeImage } from "electron";
|
||||
import * as fs from "fs";
|
||||
import { createLogger } from "../../logger";
|
||||
|
||||
const logger = createLogger("core:notification");
|
||||
|
||||
export function showDesktopNotification(
|
||||
title: string,
|
||||
@@ -24,7 +27,7 @@ export function showDesktopNotification(
|
||||
if (fs.existsSync(options.icon)) {
|
||||
notificationOptions.icon = options.icon;
|
||||
} else {
|
||||
console.warn("Notification icon file not found:", options.icon);
|
||||
logger.warn("Notification icon file not found", options.icon);
|
||||
}
|
||||
} else if (
|
||||
typeof options.icon === "string" &&
|
||||
@@ -36,14 +39,14 @@ export function showDesktopNotification(
|
||||
Buffer.from(base64Data, "base64"),
|
||||
);
|
||||
if (image.isEmpty()) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
"Notification icon created from base64 is empty - image format may not be supported by Electron",
|
||||
);
|
||||
} else {
|
||||
notificationOptions.icon = image;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to create notification icon from base64:", err);
|
||||
logger.error("Failed to create notification icon from base64", err);
|
||||
}
|
||||
} else {
|
||||
notificationOptions.icon = options.icon;
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as https from "https";
|
||||
import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
import * as childProcess from "child_process";
|
||||
import { createLogger } from "../logger";
|
||||
import {
|
||||
JimakuApiResponse,
|
||||
JimakuConfig,
|
||||
@@ -12,6 +13,8 @@ import {
|
||||
JimakuMediaInfo,
|
||||
} from "../types";
|
||||
|
||||
const logger = createLogger("main:jimaku");
|
||||
|
||||
function execCommand(
|
||||
command: string,
|
||||
): Promise<{ stdout: string; stderr: string }> {
|
||||
@@ -30,28 +33,26 @@ export async function resolveJimakuApiKey(
|
||||
config: JimakuConfig,
|
||||
): Promise<string | null> {
|
||||
if (config.apiKey && config.apiKey.trim()) {
|
||||
console.log("[jimaku] API key found in config");
|
||||
logger.debug("API key found in config");
|
||||
return config.apiKey.trim();
|
||||
}
|
||||
if (config.apiKeyCommand && config.apiKeyCommand.trim()) {
|
||||
try {
|
||||
const { stdout } = await execCommand(config.apiKeyCommand);
|
||||
const key = stdout.trim();
|
||||
console.log(
|
||||
`[jimaku] apiKeyCommand result: ${key.length > 0 ? "key obtained" : "empty output"}`,
|
||||
logger.debug(
|
||||
`apiKeyCommand result: ${key.length > 0 ? "key obtained" : "empty output"}`,
|
||||
);
|
||||
return key.length > 0 ? key : null;
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"Failed to run jimaku.apiKeyCommand:",
|
||||
logger.error(
|
||||
"Failed to run jimaku.apiKeyCommand",
|
||||
(err as Error).message,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
console.log(
|
||||
"[jimaku] No API key configured (neither apiKey nor apiKeyCommand set)",
|
||||
);
|
||||
logger.debug("No API key configured (neither apiKey nor apiKeyCommand set)");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ export async function jimakuFetchJson<T>(
|
||||
url.searchParams.set(key, String(value));
|
||||
}
|
||||
|
||||
console.log(`[jimaku] GET ${url.toString()}`);
|
||||
logger.debug(`GET ${url.toString()}`);
|
||||
const transport = url.protocol === "https:" ? https : http;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
@@ -95,13 +96,13 @@ export async function jimakuFetchJson<T>(
|
||||
});
|
||||
res.on("end", () => {
|
||||
const status = res.statusCode || 0;
|
||||
console.log(`[jimaku] Response HTTP ${status} for ${endpoint}`);
|
||||
logger.debug(`Response HTTP ${status} for ${endpoint}`);
|
||||
if (status >= 200 && status < 300) {
|
||||
try {
|
||||
const parsed = JSON.parse(data) as T;
|
||||
resolve({ ok: true, data: parsed });
|
||||
} catch {
|
||||
console.error(`[jimaku] JSON parse error: ${data.slice(0, 200)}`);
|
||||
logger.error(`JSON parse error: ${data.slice(0, 200)}`);
|
||||
resolve({
|
||||
ok: false,
|
||||
error: { error: "Failed to parse Jimaku response JSON." },
|
||||
@@ -119,7 +120,7 @@ export async function jimakuFetchJson<T>(
|
||||
} catch {
|
||||
// Ignore parse errors.
|
||||
}
|
||||
console.error(`[jimaku] API error: ${errorMessage}`);
|
||||
logger.error(`API error: ${errorMessage}`);
|
||||
|
||||
resolve({
|
||||
ok: false,
|
||||
@@ -135,7 +136,7 @@ export async function jimakuFetchJson<T>(
|
||||
);
|
||||
|
||||
req.on("error", (err) => {
|
||||
console.error(`[jimaku] Network error: ${(err as Error).message}`);
|
||||
logger.error(`Network error: ${(err as Error).message}`);
|
||||
resolve({
|
||||
ok: false,
|
||||
error: { error: `Jimaku request failed: ${(err as Error).message}` },
|
||||
|
||||
Reference in New Issue
Block a user