mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-05-26 00:55:16 -07:00
feat(launcher): add mpv.profile config option for managed launches (#80)
This commit is contained in:
@@ -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.
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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', {});
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user