feat(launcher): add mpv.profile config option for managed launches (#80)

This commit is contained in:
2026-05-23 15:14:19 -07:00
committed by GitHub
parent c4f99fec2f
commit 7e86c4ea3d
20 changed files with 110 additions and 4 deletions
+4
View File
@@ -0,0 +1,4 @@
type: added
area: launcher
- Added `mpv.profile` config and settings support for passing an mpv profile to SubMiner-managed mpv launches.
+2
View File
@@ -611,11 +611,13 @@
// Set mpv.socketPath to the IPC socket used by the launcher, Electron app, and bundled plugin. // Set mpv.socketPath to the IPC socket used by the launcher, Electron app, and bundled plugin.
// autoStartSubMiner starts SubMiner in the background; auto_start_overlay only controls visible overlay display. // autoStartSubMiner starts SubMiner in the background; auto_start_overlay only controls visible overlay display.
// Set mpv.launchMode to choose normal, maximized, or fullscreen SubMiner-managed mpv playback. // Set mpv.launchMode to choose normal, maximized, or fullscreen SubMiner-managed mpv playback.
// Set mpv.profile to pass an mpv profile to managed mpv launches; leave it blank to pass none.
// Leave mpv.executablePath blank to auto-discover mpv.exe from SUBMINER_MPV_PATH or PATH. // Leave mpv.executablePath blank to auto-discover mpv.exe from SUBMINER_MPV_PATH or PATH.
// ========================================== // ==========================================
"mpv": { "mpv": {
"executablePath": "", // Optional absolute path to mpv.exe for Windows launch flows. Leave empty to auto-discover from SUBMINER_MPV_PATH or PATH. "executablePath": "", // Optional absolute path to mpv.exe for Windows launch flows. Leave empty to auto-discover from SUBMINER_MPV_PATH or PATH.
"launchMode": "normal", // Default window state for SubMiner-managed mpv launches. Values: normal | maximized | fullscreen "launchMode": "normal", // Default window state for SubMiner-managed mpv launches. Values: normal | maximized | fullscreen
"profile": "", // Optional mpv profile name passed to SubMiner-managed mpv launches. Leave empty to pass no profile.
"socketPath": "/tmp/subminer-socket", // mpv IPC socket path used by SubMiner-managed playback and the bundled mpv plugin. "socketPath": "/tmp/subminer-socket", // mpv IPC socket path used by SubMiner-managed playback and the bundled mpv plugin.
"backend": "auto", // Window tracking backend passed to the bundled mpv plugin. Auto detects the current platform. Values: auto | hyprland | sway | x11 | macos | windows "backend": "auto", // Window tracking backend passed to the bundled mpv plugin. Auto detects the current platform. Values: auto | hyprland | sway | x11 | macos | windows
"autoStartSubMiner": true, // Start SubMiner in the background when SubMiner-managed mpv loads a file. Values: true | false "autoStartSubMiner": true, // Start SubMiner in the background when SubMiner-managed mpv loads a file. Values: true | false
+6 -2
View File
@@ -178,7 +178,7 @@ The configuration file includes several main sections:
- [**Discord Rich Presence**](#discord-rich-presence) - Optional Discord activity card updates - [**Discord Rich Presence**](#discord-rich-presence) - Optional Discord activity card updates
- [**Immersion Tracking**](#immersion-tracking) - Track subtitle sessions and mining activity in SQLite - [**Immersion Tracking**](#immersion-tracking) - Track subtitle sessions and mining activity in SQLite
- [**Stats Dashboard**](#stats-dashboard) - Local dashboard and overlay for immersion progress - [**Stats Dashboard**](#stats-dashboard) - Local dashboard and overlay for immersion progress
- [**MPV Launcher**](#mpv-launcher) - mpv executable path and window launch mode - [**MPV Launcher**](#mpv-launcher) - mpv executable path, profile, and window launch mode
- [**YouTube Playback Settings**](#youtube-playback-settings) - Defaults for YouTube subtitle loading - [**YouTube Playback Settings**](#youtube-playback-settings) - Defaults for YouTube subtitle loading
- [**Updates**](#updates) - Automatic update checks, notifications, and prerelease testing - [**Updates**](#updates) - Automatic update checks, notifications, and prerelease testing
@@ -1455,12 +1455,13 @@ Usage notes:
### MPV Launcher ### MPV Launcher
Configure the mpv executable and window state for SubMiner-managed mpv launches (launcher playback, Windows `--launch-mpv`, and Jellyfin idle mpv startup): Configure the mpv executable, profile, and window state for SubMiner-managed mpv launches (launcher playback, Windows `--launch-mpv`, and Jellyfin idle mpv startup):
```json ```json
{ {
"mpv": { "mpv": {
"executablePath": "", "executablePath": "",
"profile": "",
"launchMode": "normal" "launchMode": "normal"
} }
} }
@@ -1469,8 +1470,11 @@ Configure the mpv executable and window state for SubMiner-managed mpv launches
| Option | Values | Description | | Option | Values | Description |
| ---------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | ---------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `executablePath` | string | Absolute path to `mpv.exe` for Windows launch flows. Leave empty to auto-discover from `SUBMINER_MPV_PATH` or `PATH` (default `""`) | | `executablePath` | string | Absolute path to `mpv.exe` for Windows launch flows. Leave empty to auto-discover from `SUBMINER_MPV_PATH` or `PATH` (default `""`) |
| `profile` | string | mpv profile name passed as `--profile=<name>`. Leave empty to pass no profile (default `""`) |
| `launchMode` | `"normal"` \| `"maximized"` \| `"fullscreen"` | Window state when SubMiner spawns mpv (default `"normal"`) | | `launchMode` | `"normal"` \| `"maximized"` \| `"fullscreen"` | Window state when SubMiner spawns mpv (default `"normal"`) |
If `mpv.profile` is configured and the launcher also receives `--profile`, SubMiner passes both as a comma-separated mpv profile list.
Launch mode behavior: Launch mode behavior:
- **`normal`** — mpv opens at its default window size with no extra flags. - **`normal`** — mpv opens at its default window size with no extra flags.
+2
View File
@@ -611,11 +611,13 @@
// Set mpv.socketPath to the IPC socket used by the launcher, Electron app, and bundled plugin. // Set mpv.socketPath to the IPC socket used by the launcher, Electron app, and bundled plugin.
// autoStartSubMiner starts SubMiner in the background; auto_start_overlay only controls visible overlay display. // autoStartSubMiner starts SubMiner in the background; auto_start_overlay only controls visible overlay display.
// Set mpv.launchMode to choose normal, maximized, or fullscreen SubMiner-managed mpv playback. // Set mpv.launchMode to choose normal, maximized, or fullscreen SubMiner-managed mpv playback.
// Set mpv.profile to pass an mpv profile to managed mpv launches; leave it blank to pass none.
// Leave mpv.executablePath blank to auto-discover mpv.exe from SUBMINER_MPV_PATH or PATH. // Leave mpv.executablePath blank to auto-discover mpv.exe from SUBMINER_MPV_PATH or PATH.
// ========================================== // ==========================================
"mpv": { "mpv": {
"executablePath": "", // Optional absolute path to mpv.exe for Windows launch flows. Leave empty to auto-discover from SUBMINER_MPV_PATH or PATH. "executablePath": "", // Optional absolute path to mpv.exe for Windows launch flows. Leave empty to auto-discover from SUBMINER_MPV_PATH or PATH.
"launchMode": "normal", // Default window state for SubMiner-managed mpv launches. Values: normal | maximized | fullscreen "launchMode": "normal", // Default window state for SubMiner-managed mpv launches. Values: normal | maximized | fullscreen
"profile": "", // Optional mpv profile name passed to SubMiner-managed mpv launches. Leave empty to pass no profile.
"socketPath": "/tmp/subminer-socket", // mpv IPC socket path used by SubMiner-managed playback and the bundled mpv plugin. "socketPath": "/tmp/subminer-socket", // mpv IPC socket path used by SubMiner-managed playback and the bundled mpv plugin.
"backend": "auto", // Window tracking backend passed to the bundled mpv plugin. Auto detects the current platform. Values: auto | hyprland | sway | x11 | macos | windows "backend": "auto", // Window tracking backend passed to the bundled mpv plugin. Auto detects the current platform. Values: auto | hyprland | sway | x11 | macos | windows
"autoStartSubMiner": true, // Start SubMiner in the background when SubMiner-managed mpv loads a file. Values: true | false "autoStartSubMiner": true, // Start SubMiner in the background when SubMiner-managed mpv loads a file. Values: true | false
+23
View File
@@ -229,6 +229,29 @@ test('getDefaultSocketPath returns Windows named pipe default', () => {
assert.equal(getDefaultSocketPath('win32'), '\\\\.\\pipe\\subminer-socket'); assert.equal(getDefaultSocketPath('win32'), '\\\\.\\pipe\\subminer-socket');
}); });
test('parseLauncherMpvConfig reads configured mpv profile', () => {
assert.deepEqual(
parseLauncherMpvConfig({
mpv: {
profile: ' anime ',
},
}),
{
launchMode: undefined,
socketPath: undefined,
backend: undefined,
autoStartSubMiner: undefined,
pauseUntilOverlayReady: undefined,
subminerBinaryPath: undefined,
profile: 'anime',
aniskipEnabled: undefined,
aniskipButtonKey: undefined,
},
);
assert.equal(parseLauncherMpvConfig({ mpv: { profile: ' ' } }).profile, undefined);
});
test('readExternalYomitanProfilePath detects configured external profile paths', () => { test('readExternalYomitanProfilePath detects configured external profile paths', () => {
assert.equal( assert.equal(
readExternalYomitanProfilePath({ readExternalYomitanProfilePath({
+14
View File
@@ -45,6 +45,20 @@ test('createDefaultArgs normalizes configured language codes and env thread over
} }
}); });
test('createDefaultArgs seeds mpv profile from launcher config', () => {
const parsed = createDefaultArgs({}, { profile: 'anime' });
assert.equal(parsed.profile, 'anime');
});
test('applyRootOptionsToArgs appends CLI mpv profile to configured profile', () => {
const parsed = createDefaultArgs({}, { profile: 'anime' });
applyRootOptionsToArgs(parsed, { profile: 'hdr' }, undefined);
assert.equal(parsed.profile, 'anime,hdr');
});
test('applyRootOptionsToArgs maps file, directory, and url targets', () => { test('applyRootOptionsToArgs maps file, directory, and url targets', () => {
withTempDir((dir) => { withTempDir((dir) => {
const filePath = path.join(dir, 'movie.mkv'); const filePath = path.join(dir, 'movie.mkv');
+9 -2
View File
@@ -68,6 +68,12 @@ function parseBackend(value: string): Backend {
fail(`Invalid backend: ${value} (must be auto, hyprland, sway, x11, macos, or windows)`); fail(`Invalid backend: ${value} (must be auto, hyprland, sway, x11, macos, or windows)`);
} }
function appendMpvProfile(current: string, next: string): string {
const trimmed = next.trim();
if (!trimmed) return current;
return current ? `${current},${trimmed}` : trimmed;
}
function parseDictionaryTarget(value: string): string { function parseDictionaryTarget(value: string): string {
const trimmed = value.trim(); const trimmed = value.trim();
if (!trimmed) { if (!trimmed) {
@@ -121,7 +127,7 @@ export function createDefaultArgs(
backend: mpvConfig.backend ?? 'auto', backend: mpvConfig.backend ?? 'auto',
directory: '.', directory: '.',
recursive: false, recursive: false,
profile: '', profile: mpvConfig.profile ?? '',
startOverlay: false, startOverlay: false,
whisperBin: process.env.SUBMINER_WHISPER_BIN || launcherConfig.whisperBin || '', whisperBin: process.env.SUBMINER_WHISPER_BIN || launcherConfig.whisperBin || '',
whisperModel: process.env.SUBMINER_WHISPER_MODEL || launcherConfig.whisperModel || '', whisperModel: process.env.SUBMINER_WHISPER_MODEL || launcherConfig.whisperModel || '',
@@ -215,7 +221,8 @@ export function applyRootOptionsToArgs(
if (typeof options.backend === 'string') parsed.backend = parseBackend(options.backend); if (typeof options.backend === 'string') parsed.backend = parseBackend(options.backend);
if (typeof options.directory === 'string') parsed.directory = options.directory; if (typeof options.directory === 'string') parsed.directory = options.directory;
if (options.recursive === true) parsed.recursive = true; if (options.recursive === true) parsed.recursive = true;
if (typeof options.profile === 'string') parsed.profile = options.profile; if (typeof options.profile === 'string')
parsed.profile = appendMpvProfile(parsed.profile, options.profile);
if (options.start === true) parsed.startOverlay = true; if (options.start === true) parsed.startOverlay = true;
if (typeof options.logLevel === 'string') parsed.logLevel = parseLogLevel(options.logLevel); if (typeof options.logLevel === 'string') parsed.logLevel = parseLogLevel(options.logLevel);
if (typeof options.passwordStore === 'string') parsed.passwordStore = options.passwordStore; if (typeof options.passwordStore === 'string') parsed.passwordStore = options.passwordStore;
+1
View File
@@ -31,6 +31,7 @@ export function parseLauncherMpvConfig(root: Record<string, unknown>): LauncherM
return { return {
launchMode: parseMpvLaunchMode(mpv.launchMode), launchMode: parseMpvLaunchMode(mpv.launchMode),
profile: parseNonEmptyString(mpv.profile),
socketPath: parseNonEmptyString(mpv.socketPath), socketPath: parseNonEmptyString(mpv.socketPath),
backend: parseBackend(mpv.backend), backend: parseBackend(mpv.backend),
autoStartSubMiner: autoStartSubMiner:
+12
View File
@@ -268,6 +268,18 @@ test('buildConfiguredMpvDefaultArgs appends maximized launch mode to configured
}); });
}); });
test('buildConfiguredMpvDefaultArgs passes configured mpv profile before SubMiner defaults', () => {
withPlatform('linux', () => {
assert.deepEqual(
buildConfiguredMpvDefaultArgs(makeArgs({ profile: 'anime,hdr' }), {
DISPLAY: ':1',
XDG_SESSION_TYPE: 'x11',
}).slice(0, 2),
['--profile=anime,hdr', '--sub-auto=fuzzy'],
);
});
});
test('buildConfiguredMpvDefaultArgs disables macOS menu shortcuts so SubMiner bindings reach mpv', () => { test('buildConfiguredMpvDefaultArgs disables macOS menu shortcuts so SubMiner bindings reach mpv', () => {
withPlatform('darwin', () => { withPlatform('darwin', () => {
assert.equal( assert.equal(
+6
View File
@@ -30,6 +30,12 @@ test('parseArgs captures mpv args string', () => {
assert.equal(parsed.mpvArgs, '--pause=yes --title="movie night"'); assert.equal(parsed.mpvArgs, '--pause=yes --title="movie night"');
}); });
test('parseArgs appends CLI mpv profile to configured mpv profile', () => {
const parsed = parseArgs(['--profile', 'hdr'], 'subminer', {}, { profile: 'anime' });
assert.equal(parsed.profile, 'anime,hdr');
});
test('parseArgs maps root settings window option', () => { test('parseArgs maps root settings window option', () => {
const parsed = parseArgs(['--settings'], 'subminer', {}); const parsed = parseArgs(['--settings'], 'subminer', {});
+1
View File
@@ -175,6 +175,7 @@ export interface LauncherJellyfinConfig {
export interface LauncherMpvConfig { export interface LauncherMpvConfig {
launchMode?: MpvLaunchMode; launchMode?: MpvLaunchMode;
profile?: string;
socketPath?: string; socketPath?: string;
backend?: MpvBackend; backend?: MpvBackend;
autoStartSubMiner?: boolean; autoStartSubMiner?: boolean;
+6
View File
@@ -150,6 +150,7 @@ test('loads defaults when config is missing', () => {
assert.equal(config.updates.channel, 'stable'); assert.equal(config.updates.channel, 'stable');
assert.equal(config.mpv.socketPath, '/tmp/subminer-socket'); assert.equal(config.mpv.socketPath, '/tmp/subminer-socket');
assert.equal(config.mpv.backend, 'auto'); assert.equal(config.mpv.backend, 'auto');
assert.equal(config.mpv.profile, '');
assert.equal(config.mpv.autoStartSubMiner, true); assert.equal(config.mpv.autoStartSubMiner, true);
assert.equal(config.mpv.pauseUntilOverlayReady, true); assert.equal(config.mpv.pauseUntilOverlayReady, true);
assert.equal(config.mpv.subminerBinaryPath, ''); assert.equal(config.mpv.subminerBinaryPath, '');
@@ -357,6 +358,7 @@ test('parses managed mpv plugin runtime settings from config', () => {
"mpv": { "mpv": {
"socketPath": "/tmp/custom-subminer.sock", "socketPath": "/tmp/custom-subminer.sock",
"backend": "x11", "backend": "x11",
"profile": " anime ",
"autoStartSubMiner": false, "autoStartSubMiner": false,
"pauseUntilOverlayReady": false, "pauseUntilOverlayReady": false,
"subminerBinaryPath": "/opt/SubMiner/SubMiner.AppImage", "subminerBinaryPath": "/opt/SubMiner/SubMiner.AppImage",
@@ -371,6 +373,7 @@ test('parses managed mpv plugin runtime settings from config', () => {
const config = validService.getConfig(); const config = validService.getConfig();
assert.equal(config.mpv.socketPath, '/tmp/custom-subminer.sock'); assert.equal(config.mpv.socketPath, '/tmp/custom-subminer.sock');
assert.equal(config.mpv.backend, 'x11'); assert.equal(config.mpv.backend, 'x11');
assert.equal(config.mpv.profile, 'anime');
assert.equal(config.mpv.autoStartSubMiner, false); assert.equal(config.mpv.autoStartSubMiner, false);
assert.equal(config.mpv.pauseUntilOverlayReady, false); assert.equal(config.mpv.pauseUntilOverlayReady, false);
assert.equal(config.mpv.subminerBinaryPath, '/opt/SubMiner/SubMiner.AppImage'); assert.equal(config.mpv.subminerBinaryPath, '/opt/SubMiner/SubMiner.AppImage');
@@ -384,6 +387,7 @@ test('parses managed mpv plugin runtime settings from config', () => {
"mpv": { "mpv": {
"socketPath": "", "socketPath": "",
"backend": "weston", "backend": "weston",
"profile": 12,
"autoStartSubMiner": "yes", "autoStartSubMiner": "yes",
"pauseUntilOverlayReady": "no", "pauseUntilOverlayReady": "no",
"subminerBinaryPath": 42, "subminerBinaryPath": 42,
@@ -399,6 +403,7 @@ test('parses managed mpv plugin runtime settings from config', () => {
const warnings = invalidService.getWarnings(); const warnings = invalidService.getWarnings();
assert.equal(invalidConfig.mpv.socketPath, DEFAULT_CONFIG.mpv.socketPath); assert.equal(invalidConfig.mpv.socketPath, DEFAULT_CONFIG.mpv.socketPath);
assert.equal(invalidConfig.mpv.backend, DEFAULT_CONFIG.mpv.backend); assert.equal(invalidConfig.mpv.backend, DEFAULT_CONFIG.mpv.backend);
assert.equal(invalidConfig.mpv.profile, DEFAULT_CONFIG.mpv.profile);
assert.equal(invalidConfig.mpv.autoStartSubMiner, DEFAULT_CONFIG.mpv.autoStartSubMiner); assert.equal(invalidConfig.mpv.autoStartSubMiner, DEFAULT_CONFIG.mpv.autoStartSubMiner);
assert.equal(invalidConfig.mpv.pauseUntilOverlayReady, DEFAULT_CONFIG.mpv.pauseUntilOverlayReady); assert.equal(invalidConfig.mpv.pauseUntilOverlayReady, DEFAULT_CONFIG.mpv.pauseUntilOverlayReady);
assert.equal(invalidConfig.mpv.subminerBinaryPath, DEFAULT_CONFIG.mpv.subminerBinaryPath); assert.equal(invalidConfig.mpv.subminerBinaryPath, DEFAULT_CONFIG.mpv.subminerBinaryPath);
@@ -406,6 +411,7 @@ test('parses managed mpv plugin runtime settings from config', () => {
assert.equal(invalidConfig.mpv.aniskipButtonKey, DEFAULT_CONFIG.mpv.aniskipButtonKey); assert.equal(invalidConfig.mpv.aniskipButtonKey, DEFAULT_CONFIG.mpv.aniskipButtonKey);
assert.ok(warnings.some((warning) => warning.path === 'mpv.socketPath')); assert.ok(warnings.some((warning) => warning.path === 'mpv.socketPath'));
assert.ok(warnings.some((warning) => warning.path === 'mpv.backend')); assert.ok(warnings.some((warning) => warning.path === 'mpv.backend'));
assert.ok(warnings.some((warning) => warning.path === 'mpv.profile'));
assert.ok(warnings.some((warning) => warning.path === 'mpv.autoStartSubMiner')); assert.ok(warnings.some((warning) => warning.path === 'mpv.autoStartSubMiner'));
assert.ok(warnings.some((warning) => warning.path === 'mpv.pauseUntilOverlayReady')); assert.ok(warnings.some((warning) => warning.path === 'mpv.pauseUntilOverlayReady'));
assert.ok(warnings.some((warning) => warning.path === 'mpv.subminerBinaryPath')); assert.ok(warnings.some((warning) => warning.path === 'mpv.subminerBinaryPath'));
@@ -94,6 +94,7 @@ export const INTEGRATIONS_DEFAULT_CONFIG: Pick<
mpv: { mpv: {
executablePath: '', executablePath: '',
launchMode: 'normal', launchMode: 'normal',
profile: '',
socketPath: getDefaultMpvSocketPath(), socketPath: getDefaultMpvSocketPath(),
backend: 'auto', backend: 'auto',
autoStartSubMiner: true, autoStartSubMiner: true,
@@ -105,6 +105,7 @@ test('config option registry includes critical paths and has unique entries', ()
'anilist.characterDictionary.collapsibleSections.description', 'anilist.characterDictionary.collapsibleSections.description',
'mpv.executablePath', 'mpv.executablePath',
'mpv.launchMode', 'mpv.launchMode',
'mpv.profile',
'mpv.socketPath', 'mpv.socketPath',
'mpv.backend', 'mpv.backend',
'mpv.autoStartSubMiner', 'mpv.autoStartSubMiner',
@@ -449,6 +449,13 @@ export function buildIntegrationConfigOptionRegistry(
defaultValue: defaultConfig.mpv.launchMode, defaultValue: defaultConfig.mpv.launchMode,
description: 'Default window state for SubMiner-managed mpv launches.', description: 'Default window state for SubMiner-managed mpv launches.',
}, },
{
path: 'mpv.profile',
kind: 'string',
defaultValue: defaultConfig.mpv.profile,
description:
'Optional mpv profile name passed to SubMiner-managed mpv launches. Leave empty to pass no profile.',
},
{ {
path: 'mpv.socketPath', path: 'mpv.socketPath',
kind: 'string', kind: 'string',
@@ -175,6 +175,7 @@ const INTEGRATION_TEMPLATE_SECTIONS: ConfigTemplateSection[] = [
'Set mpv.socketPath to the IPC socket used by the launcher, Electron app, and bundled plugin.', 'Set mpv.socketPath to the IPC socket used by the launcher, Electron app, and bundled plugin.',
'autoStartSubMiner starts SubMiner in the background; auto_start_overlay only controls visible overlay display.', 'autoStartSubMiner starts SubMiner in the background; auto_start_overlay only controls visible overlay display.',
'Set mpv.launchMode to choose normal, maximized, or fullscreen SubMiner-managed mpv playback.', 'Set mpv.launchMode to choose normal, maximized, or fullscreen SubMiner-managed mpv playback.',
'Set mpv.profile to pass an mpv profile to managed mpv launches; leave it blank to pass none.',
'Leave mpv.executablePath blank to auto-discover mpv.exe from SUBMINER_MPV_PATH or PATH.', 'Leave mpv.executablePath blank to auto-discover mpv.exe from SUBMINER_MPV_PATH or PATH.',
], ],
key: 'mpv', key: 'mpv',
+7
View File
@@ -254,6 +254,13 @@ export function applyIntegrationConfig(context: ResolveContext): void {
); );
} }
const profile = asString(src.mpv.profile);
if (profile !== undefined) {
resolved.mpv.profile = profile.trim();
} else if (src.mpv.profile !== undefined) {
warn('mpv.profile', src.mpv.profile, resolved.mpv.profile, 'Expected string.');
}
const socketPath = asString(src.mpv.socketPath); const socketPath = asString(src.mpv.socketPath);
if (socketPath !== undefined && socketPath.trim().length > 0) { if (socketPath !== undefined && socketPath.trim().length > 0) {
resolved.mpv.socketPath = socketPath.trim(); resolved.mpv.socketPath = socketPath.trim();
+3
View File
@@ -24,6 +24,8 @@ test('settings registry splits viewing into appearance and behavior categories',
assert.equal(field('youtube.primarySubLanguages').section, 'YouTube Playback Settings'); assert.equal(field('youtube.primarySubLanguages').section, 'YouTube Playback Settings');
assert.equal(field('mpv.launchMode').category, 'behavior'); assert.equal(field('mpv.launchMode').category, 'behavior');
assert.equal(field('mpv.launchMode').section, 'mpv Playback'); assert.equal(field('mpv.launchMode').section, 'mpv Playback');
assert.equal(field('mpv.profile').category, 'behavior');
assert.equal(field('mpv.profile').section, 'mpv Playback');
assert.ok( assert.ok(
fields.findIndex((candidate) => candidate.configPath === 'subtitleStyle.primaryDefaultMode') < fields.findIndex((candidate) => candidate.configPath === 'subtitleStyle.primaryDefaultMode') <
fields.findIndex((candidate) => candidate.configPath === 'secondarySub.defaultMode'), fields.findIndex((candidate) => candidate.configPath === 'secondarySub.defaultMode'),
@@ -298,6 +300,7 @@ test('settings registry keeps unsafe config siblings restart-required', () => {
'ankiConnect.url', 'ankiConnect.url',
'ankiConnect.proxy.enabled', 'ankiConnect.proxy.enabled',
'mpv.socketPath', 'mpv.socketPath',
'mpv.profile',
'websocket.port', 'websocket.port',
]) { ]) {
assert.equal(field(path).restartBehavior, 'restart', path); assert.equal(field(path).restartBehavior, 'restart', path);
+2
View File
@@ -184,6 +184,7 @@ const PATH_ORDER = new Map<string, number>(
'mpv.backend', 'mpv.backend',
'mpv.subminerBinaryPath', 'mpv.subminerBinaryPath',
'mpv.aniskipEnabled', 'mpv.aniskipEnabled',
'mpv.profile',
'mpv.launchMode', 'mpv.launchMode',
'mpv.executablePath', 'mpv.executablePath',
'mpv.aniskipButtonKey', 'mpv.aniskipButtonKey',
@@ -225,6 +226,7 @@ const LABEL_OVERRIDES: Record<string, string> = {
'mpv.executablePath': 'mpv Executable Path', 'mpv.executablePath': 'mpv Executable Path',
'mpv.subminerBinaryPath': 'SubMiner Binary Path', 'mpv.subminerBinaryPath': 'SubMiner Binary Path',
'mpv.socketPath': 'mpv IPC Socket Path', 'mpv.socketPath': 'mpv IPC Socket Path',
'mpv.profile': 'mpv Profile',
'mpv.autoStartSubMiner': 'Auto-start SubMiner', 'mpv.autoStartSubMiner': 'Auto-start SubMiner',
'mpv.pauseUntilOverlayReady': 'Pause Until Overlay Ready', 'mpv.pauseUntilOverlayReady': 'Pause Until Overlay Ready',
'mpv.aniskipEnabled': 'Enable AniSkip', 'mpv.aniskipEnabled': 'Enable AniSkip',
+2
View File
@@ -58,6 +58,7 @@ export type MpvBackend = 'auto' | 'hyprland' | 'sway' | 'x11' | 'macos' | 'windo
export interface MpvConfig { export interface MpvConfig {
executablePath?: string; executablePath?: string;
launchMode?: MpvLaunchMode; launchMode?: MpvLaunchMode;
profile?: string;
socketPath?: string; socketPath?: string;
backend?: MpvBackend; backend?: MpvBackend;
autoStartSubMiner?: boolean; autoStartSubMiner?: boolean;
@@ -156,6 +157,7 @@ export interface ResolvedConfig {
mpv: { mpv: {
executablePath: string; executablePath: string;
launchMode: MpvLaunchMode; launchMode: MpvLaunchMode;
profile: string;
socketPath: string; socketPath: string;
backend: MpvBackend; backend: MpvBackend;
autoStartSubMiner: boolean; autoStartSubMiner: boolean;