feat(settings): add external player arguments (#932)

* feat(settings): add external player arguments

* fix(settings): address external player argument review

* fix(settings): require external player argument settings

* feat(settings): add external player argument placeholders

Closes https://github.com/4gray/iptvnator/issues/835
This commit is contained in:
4gray authored and GitHub committed 2026-05-14 11:04:01 +02:00
1 parent 2f9aef1578
commit a40d5447e7
35 files changed
+584 -70

No files matched your search

@@ -35,8 +35,10 @@ import {
} from '../services/store.service';
import {
buildExternalPlayerSpawnSpec,
buildPlayerArgsWithCustomArguments,
buildVlcEnqueueCommands,
isRunningInFlatpak,
parseExternalPlayerArguments,
parseVlcRcPlaybackState,
parseVlcRcNumericResponse,
resolveExternalPlayerLaunchContext,
@@ -67,21 +69,25 @@ function getIpcMainHandler(channel: string): (...args: unknown[]) => unknown {
describe('player.events Flatpak launch helpers', () => {
it('detects Flatpak only on Linux when /.flatpak-info exists', () => {
expect(isRunningInFlatpak(createPathExists(['/.flatpak-info']), 'linux')).toBe(
true
);
expect(isRunningInFlatpak(createPathExists(['/.flatpak-info']), 'darwin')).toBe(
false
);
expect(
isRunningInFlatpak(createPathExists(['/.flatpak-info']), 'linux')
).toBe(true);
expect(
isRunningInFlatpak(createPathExists(['/.flatpak-info']), 'darwin')
).toBe(false);
expect(isRunningInFlatpak(createPathExists([]), 'linux')).toBe(false);
});
it('keeps direct Linux player launching outside Flatpak', () => {
const launchContext = resolveExternalPlayerLaunchContext('mpv', undefined, {
platform: 'linux',
isFlatpak: false,
pathExists: createPathExists(['/usr/local/bin/mpv']),
});
const launchContext = resolveExternalPlayerLaunchContext(
'mpv',
undefined,
{
platform: 'linux',
isFlatpak: false,
pathExists: createPathExists(['/usr/local/bin/mpv']),
}
);
const spawnSpec = buildExternalPlayerSpawnSpec(launchContext, [
'--ytdl=no',
'https://example.com/stream.m3u8',
@@ -102,11 +108,15 @@ describe('player.events Flatpak launch helpers', () => {
});
it('builds Flatpak host launches with bare player names by default', () => {
const launchContext = resolveExternalPlayerLaunchContext('vlc', undefined, {
platform: 'linux',
isFlatpak: true,
pathExists: createPathExists(['/usr/bin/vlc']),
});
const launchContext = resolveExternalPlayerLaunchContext(
'vlc',
undefined,
{
platform: 'linux',
isFlatpak: true,
pathExists: createPathExists(['/usr/bin/vlc']),
}
);
const spawnSpec = buildExternalPlayerSpawnSpec(launchContext, [
'--extraintf=rc',
'https://example.com/stream.m3u8',
@@ -199,6 +209,38 @@ describe('player.events Flatpak launch helpers', () => {
});
});
it('parses custom player arguments as one argument per non-empty line', () => {
expect(
parseExternalPlayerArguments(
' --screen=1\n\n--geometry=1280x720\r\n --hwdec=auto-safe '
)
).toEqual(['--screen=1', '--geometry=1280x720', '--hwdec=auto-safe']);
});
it('treats missing custom player arguments as no arguments', () => {
expect(parseExternalPlayerArguments(undefined)).toEqual([]);
expect(parseExternalPlayerArguments(' \n ')).toEqual([]);
});
it('adds custom player arguments before IPTVnator runtime arguments', () => {
expect(
buildPlayerArgsWithCustomArguments(
'--screen=1\n--geometry=1280x720',
[
'--ytdl=no',
'--force-media-title=News',
'https://example.com/stream.m3u8',
]
)
).toEqual([
'--screen=1',
'--geometry=1280x720',
'--ytdl=no',
'--force-media-title=News',
'https://example.com/stream.m3u8',
]);
});
it('disables MPV reuse and socket bridging only in Flatpak', () => {
expect(shouldReuseMpvInstance(true, true)).toBe(false);
expect(shouldUseMpvSocketBridge(true)).toBe(false);
@@ -315,9 +357,7 @@ describe('buildVlcEnqueueCommands', () => {
origin: 'https://origin.example',
});
expect(commands[1]).toContain(
':http-referrer=https://origin.example'
);
expect(commands[1]).toContain(':http-referrer=https://origin.example');
});
it('appends a seek command when startTime is provided', () => {
@@ -4,12 +4,16 @@ import {
EXTERNAL_PLAYER_SESSION_UPDATE,
ExternalPlayerName,
ExternalPlayerSession,
parseExternalPlayerArguments,
type ExternalPlayerArgumentsInput,
} from 'shared-interfaces';
import App from '../app';
import {
MPV_PLAYER_ARGUMENTS,
MPV_PLAYER_PATH,
MPV_REUSE_INSTANCE,
store,
VLC_PLAYER_ARGUMENTS,
VLC_PLAYER_PATH,
VLC_REUSE_INSTANCE,
} from '../services/store.service';
@@ -43,7 +47,10 @@ interface ExternalPlaybackSnapshot {
function sendExternalPlayerSessionUpdate(session: ExternalPlayerSession) {
if (App.mainWindow && !App.mainWindow.isDestroyed()) {
App.mainWindow.webContents.send(EXTERNAL_PLAYER_SESSION_UPDATE, session);
App.mainWindow.webContents.send(
EXTERNAL_PLAYER_SESSION_UPDATE,
session
);
}
}
@@ -202,6 +209,15 @@ export function buildExternalPlayerSpawnSpec(
};
}
export { parseExternalPlayerArguments };
export function buildPlayerArgsWithCustomArguments(
customArguments: ExternalPlayerArgumentsInput,
playerArgs: string[]
): string[] {
return [...parseExternalPlayerArguments(customArguments), ...playerArgs];
}
export function shouldReuseMpvInstance(
requestedReuseInstance: boolean,
isFlatpak: boolean = isRunningInFlatpak()
@@ -504,8 +520,10 @@ function isStalkerDirectStreamProfile(
const icyMetaData = headers['Icy-MetaData'] ?? headers['icy-metadata'];
const userAgent = headers['User-Agent'] ?? headers['user-agent'];
return String(icyMetaData).trim() === '1' &&
String(userAgent).trim().toLowerCase() === 'ksplayer';
return (
String(icyMetaData).trim() === '1' &&
String(userAgent).trim().toLowerCase() === 'ksplayer'
);
}
function startPositionPolling(
@@ -592,9 +610,7 @@ async function getVlcProperty(port: number, command: string): Promise<string> {
}
async function getVlcPlaybackState(port: number): Promise<string | null> {
return parseVlcRcPlaybackState(
await getVlcCommandResponse(port, 'status')
);
return parseVlcRcPlaybackState(await getVlcCommandResponse(port, 'status'));
}
async function getVlcPlaybackSnapshot(
@@ -661,7 +677,10 @@ function startVlcPositionPolling(
}
// Helper function to send command to MPV via IPC
function sendMpvCommand(command: string, args: Array<string | number>): Promise<void> {
function sendMpvCommand(
command: string,
args: Array<string | number>
): Promise<void> {
return new Promise((resolve, reject) => {
if (!mpvSocketPath) {
reject(new Error('No MPV socket path available'));
@@ -715,6 +734,7 @@ ipcMain.handle(
getMpvPath({ isFlatpak }),
{ isFlatpak }
);
const customMpvArguments = store.get(MPV_PLAYER_ARGUMENTS, '');
const requestedReuseInstance = store.get(MPV_REUSE_INSTANCE, false);
const reuseInstance = shouldReuseMpvInstance(
requestedReuseInstance,
@@ -760,6 +780,8 @@ ipcMain.handle(
headerCount: headerFields.length,
hasContentInfo: Boolean(contentInfo),
startTime: startTime ?? null,
customArgumentCount:
parseExternalPlayerArguments(customMpvArguments).length,
});
// If reuse is enabled and there's an existing process, try to use it
@@ -810,15 +832,18 @@ ipcMain.handle(
'Successfully loaded new URL in existing MPV instance'
);
externalPlayerSessions.attachCloser(session.id, async () => {
try {
await sendMpvCommand('quit', []);
} catch {
if (mpvProcess && !mpvProcess.killed) {
mpvProcess.kill();
externalPlayerSessions.attachCloser(
session.id,
async () => {
try {
await sendMpvCommand('quit', []);
} catch {
if (mpvProcess && !mpvProcess.killed) {
mpvProcess.kill();
}
}
}
});
);
// Seek if startTime provided
if (startTime) {
@@ -904,7 +929,7 @@ ipcMain.handle(
await new Promise<void>((resolve, reject) => {
const spawnSpec = buildExternalPlayerSpawnSpec(
mpvLaunchContext,
args
buildPlayerArgsWithCustomArguments(customMpvArguments, args)
);
const proc = spawn(spawnSpec.command, spawnSpec.args, {
shell: false,
@@ -1114,10 +1139,8 @@ ipcMain.handle(
getVlcPath({ isFlatpak }),
{ isFlatpak }
);
const requestedReuseInstance = store.get(
VLC_REUSE_INSTANCE,
false
);
const customVlcArguments = store.get(VLC_PLAYER_ARGUMENTS, '');
const requestedReuseInstance = store.get(VLC_REUSE_INSTANCE, false);
const reuseInstance = shouldReuseVlcInstance(
requestedReuseInstance,
isFlatpak
@@ -1155,6 +1178,8 @@ ipcMain.handle(
hasOrigin: Boolean(effectiveOrigin),
hasContentInfo: Boolean(contentInfo),
startTime: startTime ?? null,
customArgumentCount:
parseExternalPlayerArguments(customVlcArguments).length,
});
// Try to drive an already-running VLC via its RC port instead of
@@ -1316,7 +1341,10 @@ ipcMain.handle(
const spawnVlc = (playerArgs: string[], isRetry = false) => {
const spawnSpec = buildExternalPlayerSpawnSpec(
vlcLaunchContext,
playerArgs
buildPlayerArgsWithCustomArguments(
customVlcArguments,
playerArgs
)
);
const trackProcess = reuseInstance && !isRetry;
const proc = spawn(spawnSpec.command, spawnSpec.args, {
@@ -1338,8 +1366,8 @@ ipcMain.handle(
const markVlcSessionClosed = () => {
if (
externalPlayerSessions.getSession(session.id)?.status ===
'closed'
externalPlayerSessions.getSession(session.id)
?.status === 'closed'
) {
return;
}
@@ -1375,27 +1403,30 @@ ipcMain.handle(
);
};
externalPlayerSessions.attachCloser(session.id, async () => {
await flushVlcPlaybackPosition();
if (!proc.killed) {
proc.kill();
externalPlayerSessions.attachCloser(
session.id,
async () => {
await flushVlcPlaybackPosition();
if (!proc.killed) {
proc.kill();
}
}
});
);
// Start polling if we have port and content info and NOT retrying (RC disabled on retry)
if (!isRetry && rcPort > 0 && contentInfo) {
startVlcPositionPolling(
rcPort,
contentInfo,
session.id,
(snapshot) => {
lastVlcSnapshot = snapshot;
},
() => {
markVlcSessionClosed();
}
);
}
if (!isRetry && rcPort > 0 && contentInfo) {
startVlcPositionPolling(
rcPort,
contentInfo,
session.id,
(snapshot) => {
lastVlcSnapshot = snapshot;
},
() => {
markVlcSessionClosed();
}
);
}
// Capture stdout
if (proc.stdout) {
@@ -1,7 +1,10 @@
import { ipcMain } from 'electron';
import { normalizeExternalPlayerArguments } from 'shared-interfaces';
import {
MPV_PLAYER_ARGUMENTS,
MPV_REUSE_INSTANCE,
store,
VLC_PLAYER_ARGUMENTS,
VLC_REUSE_INSTANCE,
} from '../services/store.service';
import { httpServer } from '../server/http-server';
@@ -15,6 +18,20 @@ export default class SettingsEvents {
ipcMain.handle('SETTINGS_UPDATE', (_event, arg) => {
console.log('Received SETTINGS_UPDATE with data:', arg);
if (arg.mpvPlayerArguments !== undefined) {
store.set(
MPV_PLAYER_ARGUMENTS,
normalizeExternalPlayerArguments(arg.mpvPlayerArguments)
);
}
if (arg.vlcPlayerArguments !== undefined) {
store.set(
VLC_PLAYER_ARGUMENTS,
normalizeExternalPlayerArguments(arg.vlcPlayerArguments)
);
}
// Only set values that are defined
if (arg.mpvReuseInstance !== undefined) {
store.set(MPV_REUSE_INSTANCE, arg.mpvReuseInstance);
@@ -25,9 +42,13 @@ ipcMain.handle('SETTINGS_UPDATE', (_event, arg) => {
}
// Handle remote control settings
if (arg.remoteControl !== undefined || arg.remoteControlPort !== undefined) {
if (
arg.remoteControl !== undefined ||
arg.remoteControlPort !== undefined
) {
const enabled = arg.remoteControl ?? store.get('remoteControl', false);
const port = arg.remoteControlPort ?? store.get('remoteControlPort', 8765);
const port =
arg.remoteControlPort ?? store.get('remoteControlPort', 8765);
// Save to store
if (arg.remoteControl !== undefined) {
@@ -3,14 +3,18 @@ import { getElectronConfigDirectory } from 'database';
export const WINDOW_BOUNDS = 'WINDOW_BOUNDS';
export const MPV_PLAYER_PATH = 'MPV_PLAYER_PATH';
export const MPV_PLAYER_ARGUMENTS = 'MPV_PLAYER_ARGUMENTS';
export const VLC_PLAYER_PATH = 'VLC_PLAYER_PATH';
export const VLC_PLAYER_ARGUMENTS = 'VLC_PLAYER_ARGUMENTS';
export const MPV_REUSE_INSTANCE = 'MPV_REUSE_INSTANCE';
export const VLC_REUSE_INSTANCE = 'VLC_REUSE_INSTANCE';
export type StoreType = {
[WINDOW_BOUNDS]: Electron.Rectangle;
[MPV_PLAYER_PATH]: string;
[MPV_PLAYER_ARGUMENTS]: string;
[VLC_PLAYER_PATH]: string;
[VLC_PLAYER_ARGUMENTS]: string;
[MPV_REUSE_INSTANCE]: boolean;
[VLC_REUSE_INSTANCE]: boolean;
};
+2
View File
@@ -44,8 +44,10 @@ const DEFAULT_SETTINGS: Settings = {
showExternalPlaybackBar: true,
theme: Theme.SystemTheme,
mpvPlayerPath: '',
mpvPlayerArguments: '',
mpvReuseInstance: false,
vlcPlayerPath: '',
vlcPlayerArguments: '',
vlcReuseInstance: false,
remoteControl: false,
remoteControlPort: 8765,
@@ -174,6 +174,39 @@
</div>
</div>
<div
class="setting-item setting-item--external-player-arguments"
data-test-id="mpv-player-arguments-setting"
>
<div class="setting-item__meta">
<h4>{{ 'SETTINGS.MPV_PLAYER_ARGUMENTS_LABEL' | translate }}</h4>
<p>
{{
'SETTINGS.MPV_PLAYER_ARGUMENTS_DESCRIPTION' | translate
}}
</p>
</div>
<div class="setting-item__control">
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-label for="mpvPlayerArguments">{{
'SETTINGS.MPV_PLAYER_ARGUMENTS' | translate
}}</mat-label>
<textarea
matInput
id="mpvPlayerArguments"
formControlName="mpvPlayerArguments"
[placeholder]="mpvPlayerArgumentsPlaceholder"
rows="3"
spellcheck="false"
autocomplete="off"
></textarea>
<mat-hint>{{
'SETTINGS.EXTERNAL_PLAYER_ARGUMENTS_HINT' | translate
}}</mat-hint>
</mat-form-field>
</div>
</div>
<div class="setting-item">
<div class="setting-item__meta">
<h4>{{ 'SETTINGS.MPV_REUSE_INSTANCE_LABEL' | translate }}</h4>
@@ -210,6 +243,39 @@
</div>
</div>
<div
class="setting-item setting-item--external-player-arguments"
data-test-id="vlc-player-arguments-setting"
>
<div class="setting-item__meta">
<h4>{{ 'SETTINGS.VLC_PLAYER_ARGUMENTS_LABEL' | translate }}</h4>
<p>
{{
'SETTINGS.VLC_PLAYER_ARGUMENTS_DESCRIPTION' | translate
}}
</p>
</div>
<div class="setting-item__control">
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-label for="vlcPlayerArguments">{{
'SETTINGS.VLC_PLAYER_ARGUMENTS' | translate
}}</mat-label>
<textarea
matInput
id="vlcPlayerArguments"
formControlName="vlcPlayerArguments"
[placeholder]="vlcPlayerArgumentsPlaceholder"
rows="3"
spellcheck="false"
autocomplete="off"
></textarea>
<mat-hint>{{
'SETTINGS.EXTERNAL_PLAYER_ARGUMENTS_HINT' | translate
}}</mat-hint>
</mat-form-field>
</div>
</div>
<div class="setting-item">
<div class="setting-item__meta">
<h4>{{ 'SETTINGS.VLC_REUSE_INSTANCE_LABEL' | translate }}</h4>
@@ -11,6 +11,9 @@ const MPV_COMPATIBLE_PLAYER_TIP =
'IINA can be launched as an MPV-compatible player on macOS, but use its executable path, such as /Applications/IINA.app/Contents/MacOS/iina-cli or /Applications/IINA.app/Contents/MacOS/IINA. IPTVnator controls, position polling, and reuse-instance behavior are guaranteed only for MPV IPC.';
const VLC_PATH_DESCRIPTION =
'Set the path to VLC. On macOS you can use the VLC app bundle, such as /Applications/VLC.app, or the executable path.';
const MPV_ARGUMENTS_PLACEHOLDER =
'--ontop\n--autofit=640x360\n--geometry=+80+80';
const VLC_ARGUMENTS_PLACEHOLDER = '--video-on-top\n--width=640\n--height=360';
describe('SettingsPlaybackSectionComponent', () => {
let fixture: ComponentFixture<SettingsPlaybackSectionComponent>;
@@ -226,6 +229,56 @@ describe('SettingsPlaybackSectionComponent', () => {
)
).toBeNull();
});
it('shows MPV command-line arguments only when MPV is selected', () => {
fixture.componentRef.setInput('form', createForm(VideoPlayer.MPV));
fixture.componentRef.setInput('isDesktop', true);
fixture.detectChanges();
expect(
fixture.nativeElement.querySelector(
'[data-test-id="mpv-player-arguments-setting"]'
)
).not.toBeNull();
expect(
fixture.nativeElement.querySelector(
'[data-test-id="vlc-player-arguments-setting"]'
)
).toBeNull();
expect(fixture.nativeElement.textContent).toContain(
'SETTINGS.MPV_PLAYER_ARGUMENTS_LABEL'
);
expect(
fixture.nativeElement.querySelector<HTMLTextAreaElement>(
'#mpvPlayerArguments'
)?.placeholder
).toBe(MPV_ARGUMENTS_PLACEHOLDER);
});
it('shows VLC command-line arguments only when VLC is selected', () => {
fixture.componentRef.setInput('form', createForm(VideoPlayer.VLC));
fixture.componentRef.setInput('isDesktop', true);
fixture.detectChanges();
expect(
fixture.nativeElement.querySelector(
'[data-test-id="vlc-player-arguments-setting"]'
)
).not.toBeNull();
expect(
fixture.nativeElement.querySelector(
'[data-test-id="mpv-player-arguments-setting"]'
)
).toBeNull();
expect(fixture.nativeElement.textContent).toContain(
'SETTINGS.VLC_PLAYER_ARGUMENTS_LABEL'
);
expect(
fixture.nativeElement.querySelector<HTMLTextAreaElement>(
'#vlcPlayerArguments'
)?.placeholder
).toBe(VLC_ARGUMENTS_PLACEHOLDER);
});
});
function createForm(player = VideoPlayer.VideoJs): FormGroup {
@@ -235,8 +288,10 @@ function createForm(player = VideoPlayer.VideoJs): FormGroup {
openStreamOnDoubleClick: new FormControl(false),
showExternalPlaybackBar: new FormControl(true),
mpvPlayerPath: new FormControl(''),
mpvPlayerArguments: new FormControl(''),
mpvReuseInstance: new FormControl(false),
vlcPlayerPath: new FormControl(''),
vlcPlayerArguments: new FormControl(''),
vlcReuseInstance: new FormControl(false),
recordingFolder: new FormControl(''),
});
@@ -29,6 +29,17 @@ import { SettingsPlayerOption } from './settings.models';
styles: [':host { display: contents; }'],
})
export class SettingsPlaybackSectionComponent {
readonly mpvPlayerArgumentsPlaceholder = [
'--ontop',
'--autofit=640x360',
'--geometry=+80+80',
].join('\n');
readonly vlcPlayerArgumentsPlaceholder = [
'--video-on-top',
'--width=640',
'--height=360',
].join('\n');
readonly form = input.required<FormGroup>();
readonly activeSection = input.required<string>();
readonly players = input.required<SettingsPlayerOption[]>();
@@ -211,6 +211,30 @@
justify-content: stretch;
}
.setting-item--external-player-arguments {
grid-template-columns: 1fr;
gap: 10px;
.setting-item__control {
justify-content: stretch;
align-items: stretch;
}
mat-form-field {
width: 100%;
}
textarea {
min-height: 86px;
resize: vertical;
font-family:
'JetBrains Mono', 'SFMono-Regular', Menlo, Monaco, Consolas,
monospace;
font-size: 0.84rem;
line-height: 1.45;
}
}
.theme-switcher {
width: min(100%, 540px);
display: grid;
@@ -76,8 +76,10 @@ const DEFAULT_SETTINGS = {
showExternalPlaybackBar: true,
theme: Theme.SystemTheme,
mpvPlayerPath: '',
mpvPlayerArguments: '',
mpvReuseInstance: false,
vlcPlayerPath: '',
vlcPlayerArguments: '',
vlcReuseInstance: false,
remoteControl: false,
remoteControlPort: 8765,
@@ -953,4 +955,31 @@ describe('SettingsComponent', () => {
expect(setMpvPlayerPath).toHaveBeenCalledWith('');
expect(setVlcPlayerPath).toHaveBeenCalledWith('');
});
it('saves external player command-line arguments with the settings payload', async () => {
const mockStore = settingsStore as unknown as MockSettingsStore;
mockStore.updateSettings.mockResolvedValue(undefined);
const updateSettings = jest.spyOn(window.electron, 'updateSettings');
component.settingsForm.patchValue({
mpvPlayerArguments: '--screen=1\n--geometry=1280x720',
vlcPlayerArguments: '--qt-fullscreen-screennumber=1',
});
component.onSubmit();
await fixture.whenStable();
expect(mockStore.updateSettings).toHaveBeenCalledWith(
expect.objectContaining({
mpvPlayerArguments: '--screen=1\n--geometry=1280x720',
vlcPlayerArguments: '--qt-fullscreen-screennumber=1',
})
);
expect(updateSettings).toHaveBeenCalledWith(
expect.objectContaining({
mpvPlayerArguments: '--screen=1\n--geometry=1280x720',
vlcPlayerArguments: '--qt-fullscreen-screennumber=1',
})
);
});
});
@@ -47,6 +47,7 @@ import {
EmbeddedMpvSupport,
CoverSize,
Language,
normalizeExternalPlayerArguments,
StartupBehavior,
StreamFormat,
Theme,
@@ -187,8 +188,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
showExternalPlaybackBar: true,
theme: Theme.SystemTheme,
mpvPlayerPath: '',
mpvPlayerArguments: '',
mpvReuseInstance: false,
vlcPlayerPath: '',
vlcPlayerArguments: '',
vlcReuseInstance: false,
remoteControl: false,
remoteControlPort: [
@@ -465,13 +468,21 @@ export class SettingsComponent implements OnInit, OnDestroy {
* the indexed db store
*/
onSubmit(): void {
const settings = this.settingsForm.value;
const mpvPlayerPath = this.normalizeExternalPlayerPath(
settings.mpvPlayerPath
);
const vlcPlayerPath = this.normalizeExternalPlayerPath(
settings.vlcPlayerPath
);
const settings = {
...this.settingsForm.value,
mpvPlayerPath: this.normalizeExternalPlayerPath(
this.settingsForm.value.mpvPlayerPath
),
vlcPlayerPath: this.normalizeExternalPlayerPath(
this.settingsForm.value.vlcPlayerPath
),
mpvPlayerArguments: normalizeExternalPlayerArguments(
this.settingsForm.value.mpvPlayerArguments
),
vlcPlayerArguments: normalizeExternalPlayerArguments(
this.settingsForm.value.vlcPlayerArguments
),
};
this.settingsStore.updateSettings(settings).then(() => {
this.applyChangedSettings();
@@ -479,8 +490,8 @@ export class SettingsComponent implements OnInit, OnDestroy {
if (window.electron) {
window.electron.updateSettings(settings);
window.electron.setMpvPlayerPath(mpvPlayerPath);
window.electron.setVlcPlayerPath(vlcPlayerPath);
window.electron.setMpvPlayerPath(settings.mpvPlayerPath);
window.electron.setVlcPlayerPath(settings.vlcPlayerPath);
}
});
if (this.isDialog) {
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "حدد مسار MPV. على macOS يمكنك استخدام حزمة تطبيق MPV مثل /Applications/mpv.app أو مسار الملف التنفيذي.",
"MPV_COMPATIBLE_PLAYER_TIP": "يمكن تشغيل IINA كمشغل متوافق مع MPV على macOS، لكن استخدم مسار الملف التنفيذي مثل /Applications/IINA.app/Contents/MacOS/iina-cli أو /Applications/IINA.app/Contents/MacOS/IINA. عناصر تحكم IPTVnator وتتبع الموضع وإعادة استخدام النافذة مضمونة فقط مع MPV IPC.",
"MPV_PLAYER_PATH": "مسار مشغل MPV",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "إعادة استخدام نسخة MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "عند التفعيل، سيتم إعادة استخدام نفس نافذة MPV لتشغيل البثوث المختلفة. عند التعطيل، يفتح كل بث في نافذة MPV جديدة.",
"VLC_PLAYER_PATH_LABEL": "مسار VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "حدد مسار VLC. على macOS يمكنك استخدام حزمة تطبيق VLC مثل /Applications/VLC.app أو مسار الملف التنفيذي.",
"VLC_PLAYER_PATH": "مسار مشغل VLC",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "إعادة استخدام نسخة VLC",
"VLC_REUSE_INSTANCE_DESCRIPTION": "عند التفعيل، سيتم إعادة استخدام نفس نافذة VLC لتشغيل البثوث المختلفة. عند التعطيل، يفتح كل بث في نافذة VLC جديدة.",
"REMOTE_CONTROL": "التحكم عن بعد",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "حدد مسار MPV. فـ macOS تقدر تستعمل باقة تطبيق MPV بحال /Applications/mpv.app أو مسار الملف التنفيذي.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA يقدر يتفتح كمشغل متوافق مع MPV فـ macOS، ولكن استعمل مسار الملف التنفيذي بحال /Applications/IINA.app/Contents/MacOS/iina-cli أو /Applications/IINA.app/Contents/MacOS/IINA. تحكم IPTVnator وتتبع الموضع وإعادة استعمال النافذة مضمونين غير مع MPV IPC.",
"MPV_PLAYER_PATH": "مسار مشغل mpv",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "إعادة استخدام نسخة MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "إلى كانت مفعلة، نفس نافذة MPV غادي تستعمل لتشغيل بثوث مختلفة. إلى كانت معطلة، كل بث كيتحل في نافذة MPV جديدة.",
"VLC_PLAYER_PATH_LABEL": "مسار VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "حدد مسار VLC. فـ macOS تقدر تستعمل باقة تطبيق VLC بحال /Applications/VLC.app أو مسار الملف التنفيذي.",
"VLC_PLAYER_PATH": "مسار مشغل VLC",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "إعادة استخدام نسخة VLC",
"VLC_REUSE_INSTANCE_DESCRIPTION": "إلى كانت مفعلة، نفس نافذة VLC غادي تستعمل لتشغيل بثوث مختلفة. إلى كانت معطلة، كل بث كيتحل في نافذة VLC جديدة.",
"REMOTE_CONTROL": "التحكم عن بعد",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Укажыце шлях да MPV. На macOS можна выкарыстоўваць пакет праграмы MPV, напрыклад /Applications/mpv.app, або шлях да выканальнага файла.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA можна запускаць як MPV-сумяшчальны прайгравальнік на macOS, але выкарыстоўвайце шлях да выканальнага файла, напрыклад /Applications/IINA.app/Contents/MacOS/iina-cli або /Applications/IINA.app/Contents/MacOS/IINA. Кіраванне IPTVnator, апытанне пазіцыі і паўторнае выкарыстанне акна гарантаваныя толькі для MPV IPC.",
"MPV_PLAYER_PATH": "Шлях да mpv прайгравальніка",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "Паўторна выкарыстоўваць асобнік MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Калі ўключана, тое ж акно MPV будзе паўторна выкарыстоўвацца для прайгравання розных патокаў. Калі адключана, кожны паток адкрываецца ў новым акне MPV.",
"VLC_PLAYER_PATH_LABEL": "Шлях да VLC прайгравальніка",
"VLC_PLAYER_PATH_DESCRIPTION": "Укажыце шлях да VLC. На macOS можна выкарыстоўваць пакет праграмы VLC, напрыклад /Applications/VLC.app, або шлях да выканальнага файла.",
"VLC_PLAYER_PATH": "Шлях да VLC прайгравальніка",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "Паўторна выкарыстоўваць асобнік VLC",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Калі ўключана, тое ж акно VLC будзе паўторна выкарыстоўвацца для прайгравання розных патокаў. Калі адключана, кожны паток адкрываецца ў новым акне VLC.",
"REMOTE_CONTROL": "Аддаленае кіраванне",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Lege den Pfad zu MPV fest. Unter macOS kannst du das MPV-App-Bundle wie /Applications/mpv.app oder den ausführbaren Pfad verwenden.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA kann unter macOS als MPV-kompatibler Player gestartet werden, verwende dafür aber den ausführbaren Pfad wie /Applications/IINA.app/Contents/MacOS/iina-cli oder /Applications/IINA.app/Contents/MacOS/IINA. IPTVnator-Steuerung, Positionsabfrage und Wiederverwendung der Instanz sind nur für MPV IPC garantiert.",
"MPV_PLAYER_PATH": "MPV-Player-Pfad",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "MPV-Instanz wiederverwenden",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Wenn aktiviert, wird dasselbe MPV-Fenster zum Abspielen verschiedener Streams wiederverwendet. Wenn deaktiviert, wird jeder Stream in einem neuen MPV-Fenster geöffnet.",
"VLC_PLAYER_PATH_LABEL": "VLC-Pfad",
"VLC_PLAYER_PATH_DESCRIPTION": "Lege den Pfad zu VLC fest. Unter macOS kannst du das VLC-App-Bundle wie /Applications/VLC.app oder den ausführbaren Pfad verwenden.",
"VLC_PLAYER_PATH": "VLC-Playerpfad",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "VLC-Instanz wiederverwenden",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Wenn aktiviert, wird dasselbe VLC-Fenster zum Abspielen verschiedener Streams wiederverwendet. Wenn deaktiviert, wird jeder Stream in einem neuen VLC-Fenster geöffnet.",
"REMOTE_CONTROL": "Fernsteuerung",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Ορίστε τη διαδρομή προς το MPV. Στο macOS μπορείτε να χρησιμοποιήσετε το πακέτο εφαρμογής MPV, όπως /Applications/mpv.app, ή τη διαδρομή του εκτελέσιμου αρχείου.",
"MPV_COMPATIBLE_PLAYER_TIP": "Το IINA μπορεί να εκκινηθεί ως συμβατό με MPV πρόγραμμα αναπαραγωγής στο macOS, αλλά χρησιμοποιήστε τη διαδρομή του εκτελέσιμου, όπως /Applications/IINA.app/Contents/MacOS/iina-cli ή /Applications/IINA.app/Contents/MacOS/IINA. Τα στοιχεία ελέγχου του IPTVnator, η παρακολούθηση θέσης και η επαναχρησιμοποίηση instance είναι εγγυημένα μόνο για MPV IPC.",
"MPV_PLAYER_PATH": "διαδρομή mpv προγράμματος αναπαραγωγής",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "Επαναχρησιμοποίηση της παρουσίας MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Όταν είναι ενεργοποιημένη, το ίδιο παράθυρο MPV θα επαναχρησιμοποιηθεί για την αναπαραγωγή διαφορετικών ροών. Όταν είναι απενεργοποιημένη, κάθε ροή ανοίγει σε ένα νέο παράθυρο MPV.",
"VLC_PLAYER_PATH_LABEL": "διαδρομή VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Ορίστε τη διαδρομή προς το VLC. Στο macOS μπορείτε να χρησιμοποιήσετε το πακέτο εφαρμογής VLC, όπως /Applications/VLC.app, ή τη διαδρομή του εκτελέσιμου αρχείου.",
"VLC_PLAYER_PATH": "διαδρομή VLC player",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "Επαναχρησιμοποίηση της παρουσίας VLC",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Όταν είναι ενεργοποιημένη, το ίδιο παράθυρο VLC θα επαναχρησιμοποιηθεί για την αναπαραγωγή διαφορετικών ροών. Όταν είναι απενεργοποιημένη, κάθε ροή ανοίγει σε ένα νέο παράθυρο VLC.",
"REMOTE_CONTROL": "Τηλεχειριστήριο",
+7
View File
@@ -323,6 +323,9 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Set the path to MPV. On macOS you can use the MPV app bundle, such as /Applications/mpv.app, or the executable path.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA can be launched as an MPV-compatible player on macOS, but use its executable path, such as /Applications/IINA.app/Contents/MacOS/iina-cli or /Applications/IINA.app/Contents/MacOS/IINA. IPTVnator controls, position polling, and reuse-instance behavior are guaranteed only for MPV IPC.",
"MPV_PLAYER_PATH": "mpv player path",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "Reuse MPV instance",
"MPV_REUSE_INSTANCE_DESCRIPTION": "When enabled, the same MPV window will be reused for playing different streams. When disabled, each stream opens in a new MPV window.",
"RECORDING_FOLDER_LABEL": "Recording folder",
@@ -332,6 +335,10 @@
"VLC_PLAYER_PATH_LABEL": "VLC path",
"VLC_PLAYER_PATH_DESCRIPTION": "Set the path to VLC. On macOS you can use the VLC app bundle, such as /Applications/VLC.app, or the executable path.",
"VLC_PLAYER_PATH": "VLC player path",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "Reuse VLC instance",
"VLC_REUSE_INSTANCE_DESCRIPTION": "When enabled, the same VLC window will be reused for playing different streams. When disabled, each stream opens in a new VLC window.",
"REMOTE_CONTROL": "Remote control",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Establece la ruta a MPV. En macOS puedes usar el paquete de la app MPV, como /Applications/mpv.app, o la ruta del ejecutable.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA puede iniciarse como reproductor compatible con MPV en macOS, pero usa su ruta ejecutable, como /Applications/IINA.app/Contents/MacOS/iina-cli o /Applications/IINA.app/Contents/MacOS/IINA. Los controles de IPTVnator, el seguimiento de posición y la reutilización de instancia solo están garantizados con MPV IPC.",
"MPV_PLAYER_PATH": "ruta del reproductor mpv",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "Reutilizar instancia de MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Cuando esta opción está activada, se reutiliza la misma ventana de MPV para reproducir distintos streams. Cuando está desactivada, cada stream se abre en una nueva ventana de MPV.",
"VLC_PLAYER_PATH_LABEL": "ruta VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Establece la ruta a VLC. En macOS puedes usar el paquete de la app VLC, como /Applications/VLC.app, o la ruta del ejecutable.",
"VLC_PLAYER_PATH": "Ruta del reproductor VLC",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "Reutilizar instancia de VLC",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Cuando esta opción está activada, se reutiliza la misma ventana de VLC para reproducir distintos streams. Cuando está desactivada, cada stream se abre en una nueva ventana de VLC.",
"REMOTE_CONTROL": "Control remoto",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Définissez le chemin vers MPV. Sur macOS, vous pouvez utiliser le bundle de l’app MPV, comme /Applications/mpv.app, ou le chemin de l’exécutable.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA peut être lancé comme lecteur compatible MPV sur macOS, mais utilisez son chemin exécutable, comme /Applications/IINA.app/Contents/MacOS/iina-cli ou /Applications/IINA.app/Contents/MacOS/IINA. Les contrôles IPTVnator, le suivi de position et la réutilisation d’instance ne sont garantis qu’avec MPV IPC.",
"MPV_PLAYER_PATH": "Chemin du lecteur mpv",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "Réutiliser l'instance MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Lorsqu'elle est activée, la même fenêtre MPV sera réutilisée pour lire différents flux. Lorsqu'elle est désactivée, chaque flux s'ouvre dans une nouvelle fenêtre MPV.",
"VLC_PLAYER_PATH_LABEL": "Chemin VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Définissez le chemin vers VLC. Sur macOS, vous pouvez utiliser le bundle de l’app VLC, comme /Applications/VLC.app, ou le chemin de l’exécutable.",
"VLC_PLAYER_PATH": "Chemin du lecteur VLC",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "Réutiliser l'instance VLC",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Lorsqu'elle est activée, la même fenêtre VLC sera réutilisée pour lire différents flux. Lorsqu'elle est désactivée, chaque flux s'ouvre dans une nouvelle fenêtre VLC.",
"REMOTE_CONTROL": "Télécommande",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Imposta il percorso di MPV. Su macOS puoi usare il bundle dell’app MPV, come /Applications/mpv.app, oppure il percorso dell’eseguibile.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA può essere avviato come player compatibile con MPV su macOS, ma usa il suo percorso eseguibile, come /Applications/IINA.app/Contents/MacOS/iina-cli o /Applications/IINA.app/Contents/MacOS/IINA. I controlli di IPTVnator, il polling della posizione e il riuso dell’istanza sono garantiti solo con MPV IPC.",
"MPV_PLAYER_PATH": "percorso riproduttore mpv",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "Riutilizza istanza MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Quando attivo, la stessa finestra MPV viene riutilizzata per riprodurre stream diversi. Quando disattivo, ogni stream viene aperto in una nuova finestra MPV.",
"VLC_PLAYER_PATH_LABEL": "Percorso VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Imposta il percorso di VLC. Su macOS puoi usare il bundle dell’app VLC, come /Applications/VLC.app, oppure il percorso dell’eseguibile.",
"VLC_PLAYER_PATH": "Percorso lettore VLC",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "Riutilizza istanza VLC",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Quando attivo, la stessa finestra VLC viene riutilizzata per riprodurre stream diversi. Quando disattivo, ogni stream viene aperto in una nuova finestra VLC.",
"REMOTE_CONTROL": "Telecomando",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "MPV へのパスを設定します。macOS では /Applications/mpv.app のような MPV アプリバンドル、または実行ファイルのパスを使用できます。",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA は macOS で MPV 互換プレーヤーとして起動できますが、/Applications/IINA.app/Contents/MacOS/iina-cli または /Applications/IINA.app/Contents/MacOS/IINA のような実行ファイルのパスを指定してください。IPTVnator の操作、位置ポーリング、インスタンス再利用は MPV IPC でのみ保証されます。",
"MPV_PLAYER_PATH": "mpvプレーヤーのパス",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "MPVインスタンスを再利用",
"MPV_REUSE_INSTANCE_DESCRIPTION": "有効にすると、異なるストリームの再生に同じMPVウィンドウが再利用されます。無効にすると、各ストリームが新しいMPVウィンドウで開きます。",
"VLC_PLAYER_PATH_LABEL": "VLCのパス",
"VLC_PLAYER_PATH_DESCRIPTION": "VLC へのパスを設定します。macOS では /Applications/VLC.app のような VLC アプリバンドル、または実行ファイルのパスを使用できます。",
"VLC_PLAYER_PATH": "VLCプレーヤーのパス",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "VLCインスタンスを再利用",
"VLC_REUSE_INSTANCE_DESCRIPTION": "有効にすると、異なるストリームの再生に同じVLCウィンドウが再利用されます。無効にすると、各ストリームが新しいVLCウィンドウで開きます。",
"REMOTE_CONTROL": "リモートコントロール",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "MPV 경로를 설정합니다. macOS에서는 /Applications/mpv.app 같은 MPV 앱 번들이나 실행 파일 경로를 사용할 수 있습니다.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA는 macOS에서 MPV 호환 플레이어로 실행할 수 있지만 /Applications/IINA.app/Contents/MacOS/iina-cli 또는 /Applications/IINA.app/Contents/MacOS/IINA 같은 실행 파일 경로를 사용하세요. IPTVnator 컨트롤, 위치 폴링, 인스턴스 재사용 동작은 MPV IPC에서만 보장됩니다.",
"MPV_PLAYER_PATH": "mpv 플레이어 경로",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "MPV 인스턴스 재사용",
"MPV_REUSE_INSTANCE_DESCRIPTION": "활성화하면 동일한 MPV 창에서 다른 스트림을 재생합니다. 비활성화하면 각 스트림이 새 MPV 창에서 열립니다.",
"VLC_PLAYER_PATH_LABEL": "VLC 경로",
"VLC_PLAYER_PATH_DESCRIPTION": "VLC 경로를 설정합니다. macOS에서는 /Applications/VLC.app 같은 VLC 앱 번들이나 실행 파일 경로를 사용할 수 있습니다.",
"VLC_PLAYER_PATH": "VLC 플레이어 경로",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "VLC 인스턴스 재사용",
"VLC_REUSE_INSTANCE_DESCRIPTION": "활성화하면 동일한 VLC 창에서 다른 스트림을 재생합니다. 비활성화하면 각 스트림이 새 VLC 창에서 열립니다.",
"REMOTE_CONTROL": "원격 제어",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Stel het pad naar MPV in. Op macOS kun je de MPV-appbundel gebruiken, zoals /Applications/mpv.app, of het pad naar het uitvoerbare bestand.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA kan op macOS als MPV-compatibele speler worden gestart, maar gebruik het uitvoerbare pad, zoals /Applications/IINA.app/Contents/MacOS/iina-cli of /Applications/IINA.app/Contents/MacOS/IINA. IPTVnator-bediening, positie-polling en hergebruik van de instantie zijn alleen gegarandeerd met MPV IPC.",
"MPV_PLAYER_PATH": "mpv-speler bestandspad",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "MPV-instantie hergebruiken",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Wanneer ingeschakeld, wordt hetzelfde MPV-venster hergebruikt voor het afspelen van verschillende streams. Wanneer uitgeschakeld, wordt elke stream geopend in een nieuw MPV-venster.",
"VLC_PLAYER_PATH_LABEL": "VLC-bestandspad",
"VLC_PLAYER_PATH_DESCRIPTION": "Stel het pad naar VLC in. Op macOS kun je de VLC-appbundel gebruiken, zoals /Applications/VLC.app, of het pad naar het uitvoerbare bestand.",
"VLC_PLAYER_PATH": "VLC-speler bestandspad",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "VLC-instantie hergebruiken",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Wanneer ingeschakeld, wordt hetzelfde VLC-venster hergebruikt voor het afspelen van verschillende streams. Wanneer uitgeschakeld, wordt elke stream geopend in een nieuw VLC-venster.",
"REMOTE_CONTROL": "Afstandsbediening",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Ustaw ścieżkę do MPV. W macOS możesz użyć pakietu aplikacji MPV, np. /Applications/mpv.app, albo ścieżki do pliku wykonywalnego.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA można uruchomić jako odtwarzacz zgodny z MPV w macOS, ale użyj ścieżki do pliku wykonywalnego, np. /Applications/IINA.app/Contents/MacOS/iina-cli lub /Applications/IINA.app/Contents/MacOS/IINA. Sterowanie IPTVnator, odpytywanie pozycji i ponowne użycie instancji są gwarantowane tylko dla MPV IPC.",
"MPV_PLAYER_PATH": "Ścieżka odtwarzacza mpv",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "Użyj ponownie instancji MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Po włączeniu to samo okno MPV będzie używane do odtwarzania różnych strumieni. Po wyłączeniu każdy strumień otwiera się w nowym oknie MPV.",
"VLC_PLAYER_PATH_LABEL": "Ścieżka VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Ustaw ścieżkę do VLC. W macOS możesz użyć pakietu aplikacji VLC, np. /Applications/VLC.app, albo ścieżki do pliku wykonywalnego.",
"VLC_PLAYER_PATH": "Ścieżka odtwarzacza VLC",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "Użyj ponownie instancji VLC",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Po włączeniu to samo okno VLC będzie używane do odtwarzania różnych strumieni. Po wyłączeniu każdy strumień otwiera się w nowym oknie VLC.",
"REMOTE_CONTROL": "Zdalne sterowanie",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Defina o caminho para o MPV. No macOS você pode usar o pacote do app MPV, como /Applications/mpv.app, ou o caminho do executável.",
"MPV_COMPATIBLE_PLAYER_TIP": "O IINA pode ser iniciado como player compatível com MPV no macOS, mas use o caminho do executável, como /Applications/IINA.app/Contents/MacOS/iina-cli ou /Applications/IINA.app/Contents/MacOS/IINA. Controles do IPTVnator, consulta de posição e reutilização de instância são garantidos apenas com MPV IPC.",
"MPV_PLAYER_PATH": "Caminho do reprodutor mpv",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "Reutilizar instância do MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Quando ativado, a mesma janela do MPV será reutilizada para reproduzir streams diferentes. Quando desativado, cada stream abre em uma nova janela do MPV.",
"VLC_PLAYER_PATH_LABEL": "Caminho do VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Defina o caminho para o VLC. No macOS você pode usar o pacote do app VLC, como /Applications/VLC.app, ou o caminho do executável.",
"VLC_PLAYER_PATH": "Caminho do reprodutor VLC",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "Reutilizar instância do VLC",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Quando ativado, a mesma janela do VLC será reutilizada para reproduzir streams diferentes. Quando desativado, cada stream abre em uma nova janela do VLC.",
"REMOTE_CONTROL": "Controle remoto",
+7
View File
@@ -321,6 +321,9 @@
"MPV_PLAYER_PATH_DESCRIPTION": "Укажите путь к MPV. В macOS можно использовать пакет приложения MPV, например /Applications/mpv.app, или путь к исполняемому файлу.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA можно запускать как MPV-совместимый плеер в macOS, но указывайте путь к исполняемому файлу, например /Applications/IINA.app/Contents/MacOS/iina-cli или /Applications/IINA.app/Contents/MacOS/IINA. Управление из IPTVnator, опрос позиции и переиспользование экземпляра гарантированы только для MPV IPC.",
"MPV_PLAYER_PATH": "Путь к mpv плееру",
"MPV_PLAYER_ARGUMENTS_LABEL": "Аргументы командной строки mpv",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Необязательные аргументы, которые передаются в mpv при запуске нового внешнего процесса плеера.",
"MPV_PLAYER_ARGUMENTS": "Аргументы mpv",
"MPV_REUSE_INSTANCE_LABEL": "Переиспользовать экземпляр MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Когда включено, одно и то же окно MPV будет использоваться для воспроизведения разных потоков. Когда отключено, каждый поток открывается в новом окне MPV.",
"RECORDING_FOLDER_LABEL": "Папка для записей",
@@ -330,6 +333,10 @@
"VLC_PLAYER_PATH_LABEL": "Путь к VLC плееру",
"VLC_PLAYER_PATH_DESCRIPTION": "Укажите путь к VLC. В macOS можно использовать пакет приложения VLC, например /Applications/VLC.app, или путь к исполняемому файлу.",
"VLC_PLAYER_PATH": "Путь к VLC плееру",
"VLC_PLAYER_ARGUMENTS_LABEL": "Аргументы командной строки VLC",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Необязательные аргументы, которые передаются в VLC при запуске нового внешнего процесса плеера.",
"VLC_PLAYER_ARGUMENTS": "Аргументы VLC",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Один аргумент на строку. Эти значения применяются перед параметрами IPTVnator для конкретного потока.",
"VLC_REUSE_INSTANCE_LABEL": "Переиспользовать экземпляр VLC",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Когда включено, одно и то же окно VLC будет использоваться для воспроизведения разных потоков. Когда отключено, каждый поток открывается в новом окне VLC.",
"REMOTE_CONTROL": "Удалённое управление",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "MPV yolunu ayarlayın. macOS’ta /Applications/mpv.app gibi MPV uygulama paketini veya yürütülebilir dosya yolunu kullanabilirsiniz.",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA, macOS’ta MPV uyumlu bir oynatıcı olarak başlatılabilir; ancak /Applications/IINA.app/Contents/MacOS/iina-cli veya /Applications/IINA.app/Contents/MacOS/IINA gibi yürütülebilir dosya yolunu kullanın. IPTVnator kontrolleri, konum yoklama ve örnek yeniden kullanımı yalnızca MPV IPC için garanti edilir.",
"MPV_PLAYER_PATH": "mpv oynatıcı yolu",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "MPV örneğini yeniden kullan",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Etkinleştirildiğinde, farklı yayınları oynatmak için aynı MPV penceresi yeniden kullanılır. Devre dışı bırakıldığında, her yayın yeni bir MPV penceresinde açılır.",
"VLC_PLAYER_PATH_LABEL": "VLC yolu",
"VLC_PLAYER_PATH_DESCRIPTION": "VLC yolunu ayarlayın. macOS’ta /Applications/VLC.app gibi VLC uygulama paketini veya yürütülebilir dosya yolunu kullanabilirsiniz.",
"VLC_PLAYER_PATH": "VLC oynatıcı yolu",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "VLC örneğini yeniden kullan",
"VLC_REUSE_INSTANCE_DESCRIPTION": "Etkinleştirildiğinde, farklı yayınları oynatmak için aynı VLC penceresi yeniden kullanılır. Devre dışı bırakıldığında, her yayın yeni bir VLC penceresinde açılır.",
"REMOTE_CONTROL": "Uzaktan kontrol",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "设置 MPV 路径。在 macOS 上可以使用 MPV 应用包,例如 /Applications/mpv.app,也可以使用可执行文件路径。",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA 可以在 macOS 上作为兼容 MPV 的播放器启动,但请使用它的可执行文件路径,例如 /Applications/IINA.app/Contents/MacOS/iina-cli 或 /Applications/IINA.app/Contents/MacOS/IINA。IPTVnator 控制、位置轮询和实例复用行为仅对 MPV IPC 保证可用。",
"MPV_PLAYER_PATH": "mpv 播放器路径",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "复用 MPV 实例",
"MPV_REUSE_INSTANCE_DESCRIPTION": "启用后,将复用同一个 MPV 窗口播放不同的视频流。禁用后,每个视频流都会在新的 MPV 窗口中打开。",
"VLC_PLAYER_PATH_LABEL": "VLC路径",
"VLC_PLAYER_PATH_DESCRIPTION": "设置 VLC 路径。在 macOS 上可以使用 VLC 应用包,例如 /Applications/VLC.app,也可以使用可执行文件路径。",
"VLC_PLAYER_PATH": "VLC播放器路径",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "复用 VLC 实例",
"VLC_REUSE_INSTANCE_DESCRIPTION": "启用后,将复用同一个 VLC 窗口播放不同的视频流。禁用后,每个视频流都会在新的 VLC 窗口中打开。",
"REMOTE_CONTROL": "远程控制",
+7
View File
@@ -321,11 +321,18 @@
"MPV_PLAYER_PATH_DESCRIPTION": "設定 MPV 路徑。在 macOS 上可以使用 MPV App bundle,例如 /Applications/mpv.app,也可以使用可執行檔路徑。",
"MPV_COMPATIBLE_PLAYER_TIP": "IINA 可以在 macOS 上作為相容 MPV 的播放器啟動,但請使用它的可執行檔路徑,例如 /Applications/IINA.app/Contents/MacOS/iina-cli 或 /Applications/IINA.app/Contents/MacOS/IINA。IPTVnator 控制、位置輪詢與 instance 重複使用僅保證適用於 MPV IPC。",
"MPV_PLAYER_PATH": "mpv 播放器路徑",
"MPV_PLAYER_ARGUMENTS_LABEL": "mpv command-line arguments",
"MPV_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to mpv when IPTVnator starts a new external player process.",
"MPV_PLAYER_ARGUMENTS": "mpv arguments",
"MPV_REUSE_INSTANCE_LABEL": "重複使用 MPV 實體",
"MPV_REUSE_INSTANCE_DESCRIPTION": "啟用後,相同的 MPV 視窗將重複用於播放不同串流。停用時,每個串流會在新的 MPV 視窗中開啟。",
"VLC_PLAYER_PATH_LABEL": "VLC 路徑",
"VLC_PLAYER_PATH_DESCRIPTION": "設定 VLC 路徑。在 macOS 上可以使用 VLC App bundle,例如 /Applications/VLC.app,也可以使用可執行檔路徑。",
"VLC_PLAYER_PATH": "VLC 播放器路徑",
"VLC_PLAYER_ARGUMENTS_LABEL": "VLC command-line arguments",
"VLC_PLAYER_ARGUMENTS_DESCRIPTION": "Optional arguments passed to VLC when IPTVnator starts a new external player process.",
"VLC_PLAYER_ARGUMENTS": "VLC arguments",
"EXTERNAL_PLAYER_ARGUMENTS_HINT": "Use one argument per line. These values are applied before stream-specific IPTVnator options.",
"VLC_REUSE_INSTANCE_LABEL": "重複使用 VLC 實體",
"VLC_REUSE_INSTANCE_DESCRIPTION": "啟用後,相同的 VLC 視窗將重複用於播放不同串流。停用時,每個串流會在新的 VLC 視窗中開啟。",
"REMOTE_CONTROL": "遠端控制",
@@ -160,6 +160,24 @@ When a diagnostic is actionable in Electron, the inline banner may offer `Open i
`PortalPlayer.openExternalPlayback(playback, player)` is the forced external launch API. It sends the playback payload to MPV or VLC regardless of the current saved player setting, so fallback buttons do not mutate preferences.
## External Player Arguments
Electron settings expose optional MPV and VLC command-line argument fields only
when the corresponding external player is selected. The executable path remains a
path-only setting; extra flags are stored separately as `mpvPlayerArguments` and
`vlcPlayerArguments`.
Argument fields are line-oriented: one non-empty trimmed line becomes one argv
entry. IPTVnator prepends those custom entries before its stream-specific runtime
arguments, then keeps the stream URL last. This avoids shell parsing, keeps paths
with spaces safe, and preserves existing settings for users who never configured
extra arguments.
The arguments apply only when IPTVnator spawns a new external player process. If
MPV or VLC instance reuse is active and an existing process is reused, subsequent
streams are loaded through MPV IPC or VLC RC commands and new process arguments
are not re-applied until a fresh process starts.
## Flatpak External Players
Flatpak cannot execute host-installed `mpv` or `vlc` binaries directly from the sandbox.
@@ -29,8 +29,10 @@ const DEFAULT_SETTINGS: Settings = {
showExternalPlaybackBar: true,
theme: Theme.SystemTheme,
mpvPlayerPath: '',
mpvPlayerArguments: '',
mpvReuseInstance: false,
vlcPlayerPath: '',
vlcPlayerArguments: '',
vlcReuseInstance: false,
remoteControl: false,
remoteControlPort: 8765,
@@ -136,8 +138,10 @@ export const SettingsStore = signalStore(
showExternalPlaybackBar: store.showExternalPlaybackBar!(),
theme: store.theme(),
mpvPlayerPath: store.mpvPlayerPath(),
mpvPlayerArguments: store.mpvPlayerArguments(),
mpvReuseInstance: store.mpvReuseInstance(),
vlcPlayerPath: store.vlcPlayerPath(),
vlcPlayerArguments: store.vlcPlayerArguments(),
vlcReuseInstance: store.vlcReuseInstance(),
remoteControl: store.remoteControl(),
remoteControlPort: store.remoteControlPort(),
+1
View File
@@ -6,6 +6,7 @@ export * from './lib/epg-channel-with-programs.interface';
export * from './lib/epg-channel.model';
export * from './lib/epg-item.interface';
export * from './lib/epg-program.model';
export * from './lib/external-player-arguments.utils';
export * from './lib/external-player-session.interface';
export * from './lib/indexed-db.config';
export * from './lib/ipc-command.class';
@@ -0,0 +1,33 @@
import {
normalizeExternalPlayerArguments,
parseExternalPlayerArguments,
} from './external-player-arguments.utils';
describe('external player arguments utils', () => {
it('parses one argument per non-empty trimmed line', () => {
expect(
parseExternalPlayerArguments(
' --screen=1\n\n--geometry=1280x720\r\n --hwdec=auto-safe '
)
).toEqual(['--screen=1', '--geometry=1280x720', '--hwdec=auto-safe']);
});
it('normalizes arguments to newline-separated trimmed lines', () => {
expect(
normalizeExternalPlayerArguments([
' --screen=1 ',
'',
' --geometry=1280x720 ',
])
).toBe('--screen=1\n--geometry=1280x720');
});
it('treats missing or unsupported values as empty arguments', () => {
expect(parseExternalPlayerArguments(undefined)).toEqual([]);
expect(parseExternalPlayerArguments(null)).toEqual([]);
expect(parseExternalPlayerArguments(123 as unknown as string)).toEqual(
[]
);
expect(normalizeExternalPlayerArguments(' \n ')).toBe('');
});
});
@@ -0,0 +1,28 @@
export type ExternalPlayerArgumentsInput =
| string
| readonly unknown[]
| null
| undefined;
export function parseExternalPlayerArguments(
value: ExternalPlayerArgumentsInput
): string[] {
if (Array.isArray(value)) {
return value.map((argument) => String(argument).trim()).filter(Boolean);
}
if (typeof value !== 'string') {
return [];
}
return value
.split(/\r?\n/)
.map((argument) => argument.trim())
.filter(Boolean);
}
export function normalizeExternalPlayerArguments(
value: ExternalPlayerArgumentsInput
): string {
return parseExternalPlayerArguments(value).join('\n');
}
@@ -37,8 +37,18 @@ export interface Settings {
showExternalPlaybackBar?: boolean;
theme: Theme;
mpvPlayerPath: string;
/**
* Extra MPV CLI arguments entered one argument per line. Applied only when
* starting a new external MPV process.
*/
mpvPlayerArguments: string;
mpvReuseInstance: boolean;
vlcPlayerPath: string;
/**
* Extra VLC CLI arguments entered one argument per line. Applied only when
* starting a new external VLC process.
*/
vlcPlayerArguments: string;
vlcReuseInstance: boolean;
remoteControl: boolean;
remoteControlPort: number;