[codex] Replace mpv fullscreen toggle with launch mode config (#48)

Co-authored-by: bee <autumn@skerritt.blog>
This commit is contained in:
Autumn (Bee)
2026-04-07 16:38:15 +09:00
committed by GitHub
parent 7a64488ed5
commit bc7dde3b02
31 changed files with 305 additions and 31 deletions

View File

@@ -26,6 +26,7 @@ test('composeJellyfinRuntimeHandlers returns callable jellyfin runtime handlers'
},
launchMpvIdleForJellyfinPlaybackMainDeps: {
getSocketPath: () => '/tmp/test-mpv.sock',
getLaunchMode: () => 'normal',
platform: 'linux',
execPath: process.execPath,
defaultMpvLogPath: '/tmp/test-mpv.log',

View File

@@ -33,6 +33,7 @@ test('launch mpv for jellyfin main deps builder maps callbacks', () => {
};
const deps = createBuildLaunchMpvIdleForJellyfinPlaybackMainDepsHandler({
getSocketPath: () => '/tmp/mpv.sock',
getLaunchMode: () => 'fullscreen',
platform: 'darwin',
execPath: '/tmp/subminer',
defaultMpvLogPath: '/tmp/mpv.log',
@@ -47,6 +48,7 @@ test('launch mpv for jellyfin main deps builder maps callbacks', () => {
})();
assert.equal(deps.getSocketPath(), '/tmp/mpv.sock');
assert.equal(deps.getLaunchMode(), 'fullscreen');
assert.equal(deps.platform, 'darwin');
assert.equal(deps.execPath, '/tmp/subminer');
assert.equal(deps.defaultMpvLogPath, '/tmp/mpv.log');

View File

@@ -17,6 +17,7 @@ export function createBuildLaunchMpvIdleForJellyfinPlaybackMainDepsHandler(
) {
return (): LaunchMpvForJellyfinDeps => ({
getSocketPath: () => deps.getSocketPath(),
getLaunchMode: () => deps.getLaunchMode(),
platform: deps.platform,
execPath: deps.execPath,
defaultMpvLogPath: deps.defaultMpvLogPath,

View File

@@ -31,6 +31,7 @@ test('createLaunchMpvIdleForJellyfinPlaybackHandler builds expected mpv args', (
const logs: string[] = [];
const launch = createLaunchMpvIdleForJellyfinPlaybackHandler({
getSocketPath: () => '/tmp/subminer.sock',
getLaunchMode: () => 'maximized',
platform: 'darwin',
execPath: '/Applications/SubMiner.app/Contents/MacOS/SubMiner',
defaultMpvLogPath: '/tmp/mp.log',
@@ -49,6 +50,7 @@ test('createLaunchMpvIdleForJellyfinPlaybackHandler builds expected mpv args', (
launch();
assert.equal(spawnedArgs.length, 1);
assert.ok(spawnedArgs[0]!.includes('--window-maximized=yes'));
assert.ok(spawnedArgs[0]!.includes('--idle=yes'));
assert.ok(spawnedArgs[0]!.some((arg) => arg.includes('--input-ipc-server=/tmp/subminer.sock')));
assert.ok(logs.some((entry) => entry.includes('Launched mpv for Jellyfin playback')));

View File

@@ -1,3 +1,6 @@
import { buildMpvLaunchModeArgs } from '../../shared/mpv-launch-mode';
import type { MpvLaunchMode } from '../../types/config';
type MpvClientLike = {
connected: boolean;
connect: () => void;
@@ -34,6 +37,7 @@ export function createWaitForMpvConnectedHandler(deps: WaitForMpvConnectedDeps)
export type LaunchMpvForJellyfinDeps = {
getSocketPath: () => string;
getLaunchMode: () => MpvLaunchMode;
platform: NodeJS.Platform;
execPath: string;
defaultMpvLogPath: string;
@@ -58,6 +62,7 @@ export function createLaunchMpvIdleForJellyfinPlaybackHandler(deps: LaunchMpvFor
const scriptOpts = `--script-opts=subminer-binary_path=${deps.execPath},subminer-socket_path=${socketPath}`;
const mpvArgs = [
...deps.defaultMpvArgs,
...buildMpvLaunchModeArgs(deps.getLaunchMode()),
'--idle=yes',
scriptOpts,
`--log-file=${deps.defaultMpvLogPath}`,

View File

@@ -80,6 +80,35 @@ test('buildWindowsMpvLaunchArgs uses explicit SubMiner defaults and targets', ()
);
});
test('buildWindowsMpvLaunchArgs inserts maximized launch mode before explicit extra args when configured', () => {
assert.deepEqual(
buildWindowsMpvLaunchArgs(
['C:\\video.mkv'],
['--window-maximized=no'],
'C:\\SubMiner\\SubMiner.exe',
'C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
'maximized',
),
[
'--player-operation-mode=pseudo-gui',
'--force-window=immediate',
'--script=C:\\Program Files\\SubMiner\\resources\\plugin\\subminer\\main.lua',
'--input-ipc-server=\\\\.\\pipe\\subminer-socket',
'--alang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
'--slang=ja,jp,jpn,japanese,en,eng,english,enus,en-us',
'--sub-auto=fuzzy',
'--sub-file-paths=subs;subtitles',
'--sid=auto',
'--secondary-sid=auto',
'--secondary-sub-visibility=no',
'--script-opts=subminer-binary_path=C:\\SubMiner\\SubMiner.exe,subminer-socket_path=\\\\.\\pipe\\subminer-socket',
'--window-maximized=yes',
'--window-maximized=no',
'C:\\video.mkv',
],
);
});
test('buildWindowsMpvLaunchArgs keeps shortcut-only launches in idle mode', () => {
assert.deepEqual(
buildWindowsMpvLaunchArgs(

View File

@@ -1,5 +1,7 @@
import fs from 'node:fs';
import { spawn, spawnSync } from 'node:child_process';
import { buildMpvLaunchModeArgs } from '../../shared/mpv-launch-mode';
import type { MpvLaunchMode } from '../../types/config';
export interface WindowsMpvLaunchDeps {
getEnv: (name: string) => string | undefined;
@@ -89,6 +91,7 @@ export function buildWindowsMpvLaunchArgs(
extraArgs: string[] = [],
binaryPath?: string,
pluginEntrypointPath?: string,
launchMode: MpvLaunchMode = 'normal',
): string[] {
const launchIdle = targets.length === 0;
const inputIpcServer =
@@ -119,6 +122,7 @@ export function buildWindowsMpvLaunchArgs(
'--secondary-sid=auto',
'--secondary-sub-visibility=no',
...(scriptOpts ? [scriptOpts] : []),
...buildMpvLaunchModeArgs(launchMode),
...extraArgs,
...targets,
];
@@ -131,6 +135,7 @@ export async function launchWindowsMpv(
binaryPath?: string,
pluginEntrypointPath?: string,
configuredMpvPath?: string,
launchMode: MpvLaunchMode = 'normal',
): Promise<{ ok: boolean; mpvPath: string }> {
const normalizedConfiguredPath = normalizeCandidate(configuredMpvPath);
const mpvPath = resolveWindowsMpvPath(deps, normalizedConfiguredPath);
@@ -147,7 +152,13 @@ export async function launchWindowsMpv(
try {
await deps.spawnDetached(
mpvPath,
buildWindowsMpvLaunchArgs(targets, extraArgs, binaryPath, pluginEntrypointPath),
buildWindowsMpvLaunchArgs(
targets,
extraArgs,
binaryPath,
pluginEntrypointPath,
launchMode,
),
);
return { ok: true, mpvPath };
} catch (error) {