diff --git a/apps/electron-backend/src/app/events/player.events.ts b/apps/electron-backend/src/app/events/player.events.ts index 54e40ec65..0edb88137 100644 --- a/apps/electron-backend/src/app/events/player.events.ts +++ b/apps/electron-backend/src/app/events/player.events.ts @@ -140,6 +140,20 @@ function stopPositionPolling() { } } +function maskUrlForLogs(rawUrl: string): string { + try { + const parsed = new URL(rawUrl); + return `${parsed.origin}${parsed.pathname}`; + } catch { + return rawUrl; + } +} + +function shouldIgnoreMpvStdoutLine(line: string): boolean { + // Suppress MPV realtime progress spam. + return /^(\(Paused\)\s*)?AV:\s/.test(line); +} + function startPositionPolling(socketPath: string, contentInfo: any) { stopPositionPolling(); @@ -304,14 +318,16 @@ ipcMain.handle( 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('User-Agent:', userAgent); - console.log('Referer:', referer); - console.log('Origin:', origin); - console.log('Content Info:', contentInfo); - console.log('Start Time:', startTime); + console.log('[MPV] Opening player', { + path: mpvPath, + reuseInstance, + stream: maskUrlForLogs(url), + hasUserAgent: Boolean(userAgent), + hasReferer: Boolean(referer), + hasOrigin: Boolean(origin), + hasContentInfo: Boolean(contentInfo), + startTime: startTime ?? null, + }); // If reuse is enabled and there's an existing process, try to use it if ( @@ -410,8 +426,17 @@ ipcMain.handle( // Capture stdout if (proc.stdout) { proc.stdout.on('data', (data) => { - const output = data.toString().trim(); - if (output) { + const lines = data + .toString() + .split('\n') + .map((line) => line.trim()) + .filter(Boolean); + + for (const output of lines) { + if (shouldIgnoreMpvStdoutLine(output)) { + continue; + } + console.log('[MPV stdout]:', output); // MPV sometimes outputs errors to stdout instead of stderr diff --git a/apps/electron-backend/src/app/events/xtream.events.ts b/apps/electron-backend/src/app/events/xtream.events.ts index f53e366f4..26bfb0ab4 100644 --- a/apps/electron-backend/src/app/events/xtream.events.ts +++ b/apps/electron-backend/src/app/events/xtream.events.ts @@ -12,6 +12,43 @@ export default class XtreamEvents { } } +function formatXtreamError(error: unknown, requestUrl: string, action?: string) { + const parsedUrl = new URL(requestUrl); + const base = { + action, + host: parsedUrl.host, + pathname: parsedUrl.pathname, + }; + + if (axios.isAxiosError(error)) { + return { + ...base, + type: 'AxiosError', + code: error.code, + status: error.response?.status, + message: error.message, + syscall: (error as NodeJS.ErrnoException).syscall, + hostname: (error as any).hostname, + }; + } + + if (error && typeof error === 'object') { + const errObj = error as Record; + return { + ...base, + type: 'ErrorObject', + status: errObj.status, + message: errObj.message, + }; + } + + return { + ...base, + type: 'UnknownError', + message: String(error), + }; +} + /** * Handle Xtream Codes API requests */ @@ -63,7 +100,10 @@ ipcMain.handle( action: params.action, }; } catch (error) { - console.error('Xtream request error:', error); + console.error( + '[XTREAM_REQUEST] Failed', + formatXtreamError(error, payload.url, payload.params?.action) + ); // Format error response if (axios.isAxiosError(error)) {