From a3c3c6d2256a5fb263096944a33a047ade56a1dc Mon Sep 17 00:00:00 2001 From: xRangerDE Date: Fri, 13 Feb 2026 12:14:42 +0100 Subject: [PATCH] Add streamlink command fallback and improve ENOENT errors (v3.7.9) Resolve streamlink execution more robustly by trying direct binary and Python module launchers, then return actionable error messages when streamlink is missing on server environments. --- typescript-version/package-lock.json | 4 +- typescript-version/package.json | 2 +- typescript-version/src/index.html | 4 +- typescript-version/src/main.ts | 67 ++++++++++++++++++++++++---- 4 files changed, 64 insertions(+), 13 deletions(-) diff --git a/typescript-version/package-lock.json b/typescript-version/package-lock.json index f628402..c37fb63 100644 --- a/typescript-version/package-lock.json +++ b/typescript-version/package-lock.json @@ -1,12 +1,12 @@ { "name": "twitch-vod-manager", - "version": "3.7.8", + "version": "3.7.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twitch-vod-manager", - "version": "3.7.8", + "version": "3.7.9", "license": "MIT", "dependencies": { "axios": "^1.6.0", diff --git a/typescript-version/package.json b/typescript-version/package.json index b5c4498..2fb00ae 100644 --- a/typescript-version/package.json +++ b/typescript-version/package.json @@ -1,6 +1,6 @@ { "name": "twitch-vod-manager", - "version": "3.7.8", + "version": "3.7.9", "description": "Twitch VOD Manager - Download Twitch VODs easily", "main": "dist/main.js", "author": "xRangerDE", diff --git a/typescript-version/src/index.html b/typescript-version/src/index.html index 3d96f63..65fb60c 100644 --- a/typescript-version/src/index.html +++ b/typescript-version/src/index.html @@ -335,7 +335,7 @@

Updates

-

Version: v3.7.8

+

Version: v3.7.9

@@ -346,7 +346,7 @@
Nicht verbunden - v3.7.8 + v3.7.9 diff --git a/typescript-version/src/main.ts b/typescript-version/src/main.ts index 433ada3..6936eaf 100644 --- a/typescript-version/src/main.ts +++ b/typescript-version/src/main.ts @@ -8,7 +8,7 @@ import { autoUpdater } from 'electron-updater'; // ========================================== // CONFIG & CONSTANTS // ========================================== -const APP_VERSION = '3.7.8'; +const APP_VERSION = '3.7.9'; const UPDATE_CHECK_URL = 'http://24-music.de/version.json'; // Paths @@ -172,6 +172,7 @@ let currentDownloadCancelled = false; let downloadStartTime = 0; let downloadedBytes = 0; const userIdLoginCache = new Map(); +let streamlinkCommandCache: { command: string; prefixArgs: string[] } | null = null; // ========================================== // TOOL PATHS @@ -201,6 +202,52 @@ function getStreamlinkPath(): string { return 'streamlink'; } +function canExecute(cmd: string): boolean { + try { + execSync(cmd, { stdio: 'ignore', windowsHide: true }); + return true; + } catch { + return false; + } +} + +function getStreamlinkCommand(): { command: string; prefixArgs: string[] } { + if (streamlinkCommandCache) { + return streamlinkCommandCache; + } + + const directPath = getStreamlinkPath(); + if (directPath !== 'streamlink' || canExecute('streamlink --version')) { + streamlinkCommandCache = { command: directPath, prefixArgs: [] }; + return streamlinkCommandCache; + } + + if (process.platform === 'win32') { + if (canExecute('py -3 -m streamlink --version')) { + streamlinkCommandCache = { command: 'py', prefixArgs: ['-3', '-m', 'streamlink'] }; + return streamlinkCommandCache; + } + + if (canExecute('python -m streamlink --version')) { + streamlinkCommandCache = { command: 'python', prefixArgs: ['-m', 'streamlink'] }; + return streamlinkCommandCache; + } + } else { + if (canExecute('python3 -m streamlink --version')) { + streamlinkCommandCache = { command: 'python3', prefixArgs: ['-m', 'streamlink'] }; + return streamlinkCommandCache; + } + + if (canExecute('python -m streamlink --version')) { + streamlinkCommandCache = { command: 'python', prefixArgs: ['-m', 'streamlink'] }; + return streamlinkCommandCache; + } + } + + streamlinkCommandCache = { command: directPath, prefixArgs: [] }; + return streamlinkCommandCache; +} + function getFFmpegPath(): string { try { if (process.platform === 'win32') { @@ -777,8 +824,8 @@ function downloadVODPart( totalParts: number ): Promise { return new Promise((resolve) => { - const streamlinkPath = getStreamlinkPath(); - const args = [url, 'best', '-o', filename, '--force']; + const streamlinkCmd = getStreamlinkCommand(); + const args = [...streamlinkCmd.prefixArgs, url, 'best', '-o', filename, '--force']; let lastErrorLine = ''; if (startTime) { @@ -788,10 +835,10 @@ function downloadVODPart( args.push('--hls-duration', endTime); } - console.log('Starting download:', streamlinkPath, args); - appendDebugLog('download-part-start', { itemId, streamlinkPath, filename, args }); + console.log('Starting download:', streamlinkCmd.command, args); + appendDebugLog('download-part-start', { itemId, command: streamlinkCmd.command, filename, args }); - const proc = spawn(streamlinkPath, args, { windowsHide: true }); + const proc = spawn(streamlinkCmd.command, args, { windowsHide: true }); currentProcess = proc; downloadStartTime = Date.now(); @@ -890,8 +937,12 @@ function downloadVODPart( clearInterval(progressInterval); console.error('Process error:', err); currentProcess = null; - appendDebugLog('download-part-process-error', { itemId, error: String(err) }); - resolve({ success: false, error: String(err) }); + const rawError = String(err); + const errorMessage = rawError.includes('ENOENT') + ? 'Streamlink nicht gefunden. Installiere Streamlink oder Python+streamlink (py -3 -m pip install streamlink).' + : rawError; + appendDebugLog('download-part-process-error', { itemId, error: errorMessage, rawError }); + resolve({ success: false, error: errorMessage }); }); }); }