mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
feat(player): use user-agent, referrer, origin for vlc and mpv
Enhance MPV player IPC handler to accept and forward extra parameters (url, path, title, userAgent, referer, origin). Attempt to reuse an existing MPV instance when reuse is enabled and an IPC socket is available; if reuse fails, fall back to spawning a new process. When creating a new MPV process, generate a unique platform-aware IPC socket path, build arguments conditionally from provided metadata (user-agent, referrer, origin via http-header-fields, force-media-title) and append the URL last. Improve logging for debugging and handle process spawn errors by clearing stale process/socket references. These changes enable smoother playback handoff, preserve headers and title for remote resources, and make MPV invocations more robust.
This commit is contained in:
1 parent
e079d268f0
commit
3eed15d806
2 files changed
+164
-88
No files matched your search
@@ -53,87 +53,125 @@ function sendMpvCommand(command: string, args: string[]): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
ipcMain.handle('OPEN_MPV_PLAYER', async (event, url) => {
|
||||
try {
|
||||
const mpvPath = getMpvPath();
|
||||
const reuseInstance = store.get(MPV_REUSE_INSTANCE, false);
|
||||
ipcMain.handle(
|
||||
'OPEN_MPV_PLAYER',
|
||||
async (
|
||||
event,
|
||||
url: string,
|
||||
path: string,
|
||||
title: string,
|
||||
userAgent?: string,
|
||||
referer?: string,
|
||||
origin?: string
|
||||
) => {
|
||||
try {
|
||||
const mpvPath = getMpvPath();
|
||||
const reuseInstance = store.get(MPV_REUSE_INSTANCE, false);
|
||||
|
||||
console.log('Opening MPV player with path:', mpvPath);
|
||||
console.log('Reuse instance:', reuseInstance);
|
||||
console.log('URL:', url);
|
||||
console.log('Opening MPV player with path:', mpvPath);
|
||||
console.log('Reuse instance:', reuseInstance);
|
||||
console.log('URL:', url);
|
||||
console.log('User-Agent:', userAgent);
|
||||
console.log('Referer:', referer);
|
||||
console.log('Origin:', origin);
|
||||
|
||||
// If reuse is enabled and there's an existing process, try to use it
|
||||
if (
|
||||
reuseInstance &&
|
||||
mpvProcess &&
|
||||
!mpvProcess.killed &&
|
||||
mpvSocketPath
|
||||
) {
|
||||
console.log('Reusing existing MPV instance');
|
||||
try {
|
||||
await sendMpvCommand('loadfile', [url, 'replace']);
|
||||
console.log(
|
||||
'Successfully loaded new URL in existing MPV instance'
|
||||
);
|
||||
return;
|
||||
} catch (err) {
|
||||
console.error('Failed to send command to existing MPV:', err);
|
||||
// If it fails, clear the reference and create a new one
|
||||
// If reuse is enabled and there's an existing process, try to use it
|
||||
if (
|
||||
reuseInstance &&
|
||||
mpvProcess &&
|
||||
!mpvProcess.killed &&
|
||||
mpvSocketPath
|
||||
) {
|
||||
console.log('Reusing existing MPV instance');
|
||||
try {
|
||||
await sendMpvCommand('loadfile', [url, 'replace']);
|
||||
console.log(
|
||||
'Successfully loaded new URL in existing MPV instance'
|
||||
);
|
||||
return;
|
||||
} catch (err) {
|
||||
console.error('Failed to send command to existing MPV:', err);
|
||||
// If it fails, clear the reference and create a new one
|
||||
mpvProcess = null;
|
||||
mpvSocketPath = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new MPV process
|
||||
console.log('Creating new MPV instance');
|
||||
|
||||
// Generate unique socket path
|
||||
const socketPath =
|
||||
process.platform === 'win32'
|
||||
? `\\\\.\\pipe\\mpv-${Date.now()}`
|
||||
: `/tmp/mpvsocket-${Date.now()}`;
|
||||
|
||||
const args = [`--input-ipc-server=${socketPath}`, '--idle=yes'];
|
||||
|
||||
// Add user agent if provided
|
||||
if (userAgent) {
|
||||
args.push(`--user-agent=${userAgent}`);
|
||||
}
|
||||
|
||||
// Add referer if provided
|
||||
if (referer) {
|
||||
args.push(`--referrer=${referer}`);
|
||||
}
|
||||
|
||||
// Add origin as custom HTTP header if provided
|
||||
// MPV doesn't have a direct --origin flag, so we use --http-header-fields
|
||||
if (origin) {
|
||||
args.push(`--http-header-fields=Origin: ${origin}`);
|
||||
}
|
||||
|
||||
// Add title if provided
|
||||
if (title) {
|
||||
args.push(`--force-media-title=${title}`);
|
||||
}
|
||||
|
||||
// Add URL last
|
||||
args.push(url);
|
||||
|
||||
const proc = spawn(mpvPath, args, {
|
||||
shell: false,
|
||||
detached: !reuseInstance,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
|
||||
proc.on('error', (err) => {
|
||||
console.error('Failed to start MPV player:', err);
|
||||
mpvProcess = null;
|
||||
mpvSocketPath = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new MPV process
|
||||
console.log('Creating new MPV instance');
|
||||
|
||||
// Generate unique socket path
|
||||
const socketPath =
|
||||
process.platform === 'win32'
|
||||
? `\\\\.\\pipe\\mpv-${Date.now()}`
|
||||
: `/tmp/mpvsocket-${Date.now()}`;
|
||||
|
||||
const args = [`--input-ipc-server=${socketPath}`, '--idle=yes', url];
|
||||
|
||||
const proc = spawn(mpvPath, args, {
|
||||
shell: false,
|
||||
detached: !reuseInstance,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
|
||||
proc.on('error', (err) => {
|
||||
console.error('Failed to start MPV player:', err);
|
||||
mpvProcess = null;
|
||||
mpvSocketPath = null;
|
||||
/* event.sender.send(ERROR, {
|
||||
/* event.sender.send(ERROR, {
|
||||
message: `Error: Failed to start MPV player. Make sure that mpv player is installed on your system and the path is correct.`,
|
||||
}); */
|
||||
});
|
||||
});
|
||||
|
||||
proc.on('exit', (code) => {
|
||||
console.log(`MPV exited with code ${code}`);
|
||||
proc.on('exit', (code) => {
|
||||
console.log(`MPV exited with code ${code}`);
|
||||
mpvProcess = null;
|
||||
mpvSocketPath = null;
|
||||
});
|
||||
|
||||
// Store the process reference if reuse is enabled
|
||||
if (reuseInstance) {
|
||||
mpvProcess = proc;
|
||||
mpvSocketPath = socketPath;
|
||||
console.log(
|
||||
'Stored MPV process for reuse with socket:',
|
||||
socketPath
|
||||
);
|
||||
} else {
|
||||
// Detach the process so it can continue running independently
|
||||
proc.unref();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
mpvProcess = null;
|
||||
mpvSocketPath = null;
|
||||
});
|
||||
|
||||
// Store the process reference if reuse is enabled
|
||||
if (reuseInstance) {
|
||||
mpvProcess = proc;
|
||||
mpvSocketPath = socketPath;
|
||||
console.log(
|
||||
'Stored MPV process for reuse with socket:',
|
||||
socketPath
|
||||
);
|
||||
} else {
|
||||
// Detach the process so it can continue running independently
|
||||
proc.unref();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
mpvProcess = null;
|
||||
mpvSocketPath = null;
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
ipcMain.handle('SET_MPV_PLAYER_PATH', (_event, mpvPlayerPath) => {
|
||||
console.log('... setting mpv player path', mpvPlayerPath);
|
||||
@@ -153,28 +191,65 @@ ipcMain.handle('SET_MPV_REUSE_INSTANCE', (_event, reuseInstance: boolean) => {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('OPEN_VLC_PLAYER', (event, url) => {
|
||||
const vlcPath = getVlcPath();
|
||||
console.log('Opening VLC player with path:', vlcPath);
|
||||
console.log('URL:', url);
|
||||
ipcMain.handle(
|
||||
'OPEN_VLC_PLAYER',
|
||||
(
|
||||
event,
|
||||
url: string,
|
||||
path: string,
|
||||
title: string,
|
||||
userAgent?: string,
|
||||
referer?: string,
|
||||
origin?: string
|
||||
) => {
|
||||
const vlcPath = getVlcPath();
|
||||
console.log('Opening VLC player with path:', vlcPath);
|
||||
console.log('URL:', url);
|
||||
console.log('User-Agent:', userAgent);
|
||||
console.log('Referer:', referer);
|
||||
console.log('Origin:', origin);
|
||||
|
||||
const proc = spawn(vlcPath, [url as string], {
|
||||
shell: false,
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
const args: string[] = [];
|
||||
|
||||
proc.on('error', (err) => {
|
||||
console.error('Failed to start VLC player:', err);
|
||||
});
|
||||
// Add user agent if provided (VLC uses :http-user-agent= format)
|
||||
if (userAgent) {
|
||||
args.push(`:http-user-agent=${userAgent}`);
|
||||
}
|
||||
|
||||
proc.on('exit', (code) => {
|
||||
console.log(`VLC exited with code ${code}`);
|
||||
});
|
||||
// Add referer if provided (VLC uses :http-referrer= format)
|
||||
if (referer) {
|
||||
args.push(`:http-referrer=${referer}`);
|
||||
}
|
||||
|
||||
// Detach the process so it can continue running independently
|
||||
proc.unref();
|
||||
});
|
||||
// Note: VLC doesn't have a direct origin option, but origin is typically
|
||||
// included in referer for most IPTV use cases
|
||||
|
||||
// Add title if provided
|
||||
if (title) {
|
||||
args.push(`--meta-title=${title}`);
|
||||
}
|
||||
|
||||
// Add URL last
|
||||
args.push(url);
|
||||
|
||||
const proc = spawn(vlcPath, args, {
|
||||
shell: false,
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
|
||||
proc.on('error', (err) => {
|
||||
console.error('Failed to start VLC player:', err);
|
||||
});
|
||||
|
||||
proc.on('exit', (code) => {
|
||||
console.log(`VLC exited with code ${code}`);
|
||||
});
|
||||
|
||||
// Detach the process so it can continue running independently
|
||||
proc.unref();
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle('SET_VLC_PLAYER_PATH', (_event, vlcPlayerPath) => {
|
||||
console.log('... setting vlc player path', vlcPlayerPath);
|
||||
|
||||
@@ -80,6 +80,7 @@ export class ElectronService extends DataService {
|
||||
return await window.electron.openInVlc(
|
||||
data.url,
|
||||
data.vlcPlayerPath || '',
|
||||
data.title ?? '',
|
||||
data['user-agent'] ?? undefined,
|
||||
data.referer ?? undefined,
|
||||
data.origin ?? undefined
|
||||
|
||||
Reference in new issue
Block a user