feat(config): unify mpv plugin options under main config and add CSS/Ani

- Replace subminer.conf plugin config with mpv.* fields in config.jsonc
- Add socketPath, backend, autoStartSubMiner, pauseUntilOverlayReady, aniskipEnabled/buttonKey, subminerBinaryPath to mpv config
- Add subtitleSidebar.css field; migrate legacy sidebar appearance fields
- Add paintOrder and WebkitTextStroke to subtitle style options
- Update default subtitle/sidebar fontFamily to CJK-first stack
- Fix overlay visible state surviving mpv y-r restart
- Fix live config saves applying subtitle CSS immediately to open overlays
- Migrate legacy primary/secondary subtitle appearance into subtitleStyle.css on load
- Switch AniSkip button key setting to click-to-learn key capture
This commit is contained in:
2026-05-17 18:01:39 -07:00
parent 81830b3372
commit 6ba91780c1
91 changed files with 2241 additions and 727 deletions
+21 -9
View File
@@ -8,10 +8,11 @@ import {
detectInstalledMpvPlugin,
type InstalledMpvPluginDetection,
} from '../src/main/runtime/first-run-setup-plugin.js';
import type { LogLevel, Backend, Args, MpvTrack } from './types.js';
import type { LogLevel, Backend, Args, MpvTrack, PluginRuntimeConfig } from './types.js';
import { DEFAULT_MPV_SUBMINER_ARGS, DEFAULT_YOUTUBE_YTDL_FORMAT } from './types.js';
import { appendToAppLog, getAppLogPath, log, fail, getMpvLogPath } from './log.js';
import { buildSubminerScriptOpts, resolveAniSkipMetadataForFile } from './aniskip-metadata.js';
import { buildPluginRuntimeScriptOptParts } from './config/plugin-runtime-config.js';
import { nowMs } from './time.js';
import {
commandExists,
@@ -849,6 +850,7 @@ export async function startMpv(
startPaused?: boolean;
disableYoutubeSubtitleAutoLoad?: boolean;
runtimePluginPath?: string | null;
runtimePluginConfig?: PluginRuntimeConfig;
},
): Promise<void> {
if (targetKind === 'file' && (!fs.existsSync(target) || !fs.statSync(target).isFile())) {
@@ -916,13 +918,13 @@ export async function startMpv(
options?.disableYoutubeSubtitleAutoLoad === true
? ['subminer-auto_start_pause_until_ready=no']
: [];
const scriptOpts = buildSubminerScriptOpts(
appPath,
socketPath,
aniSkipMetadata,
args.logLevel,
extraScriptOpts,
);
const runtimeScriptOpts = options?.runtimePluginConfig
? buildPluginRuntimeScriptOptParts(options.runtimePluginConfig, appPath)
: [`subminer-binary_path=${appPath}`, `subminer-socket_path=${socketPath}`];
const scriptOpts = buildSubminerScriptOpts(appPath, socketPath, aniSkipMetadata, args.logLevel, [
...runtimeScriptOpts,
...extraScriptOpts,
]);
if (aniSkipMetadata) {
log(
'debug',
@@ -1477,6 +1479,7 @@ export function launchMpvIdleDetached(
appPath: string,
args: Args,
runtimePluginPath?: string | null,
runtimePluginConfig?: PluginRuntimeConfig,
): Promise<void> {
return (async () => {
await terminateTrackedDetachedMpv(args.logLevel);
@@ -1498,8 +1501,17 @@ export function launchMpvIdleDetached(
mpvArgs.push(...parseMpvArgString(args.mpvArgs));
}
mpvArgs.push('--idle=yes');
const runtimeScriptOpts = runtimePluginConfig
? buildPluginRuntimeScriptOptParts(runtimePluginConfig, appPath)
: [`subminer-binary_path=${appPath}`, `subminer-socket_path=${socketPath}`];
mpvArgs.push(
`--script-opts=${buildSubminerScriptOpts(appPath, socketPath, null, args.logLevel)}`,
`--script-opts=${buildSubminerScriptOpts(
appPath,
socketPath,
null,
args.logLevel,
runtimeScriptOpts,
)}`,
);
mpvArgs.push(`--log-file=${getMpvLogPath()}`);
mpvArgs.push(`--input-ipc-server=${socketPath}`);