diff --git a/typescript-version/package-lock.json b/typescript-version/package-lock.json index d5c4242..7db1956 100644 --- a/typescript-version/package-lock.json +++ b/typescript-version/package-lock.json @@ -1,12 +1,12 @@ { "name": "twitch-vod-manager", - "version": "3.8.0", + "version": "3.8.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twitch-vod-manager", - "version": "3.8.0", + "version": "3.8.1", "license": "MIT", "dependencies": { "axios": "^1.6.0", diff --git a/typescript-version/package.json b/typescript-version/package.json index 0b5304d..e7a1757 100644 --- a/typescript-version/package.json +++ b/typescript-version/package.json @@ -1,6 +1,6 @@ { "name": "twitch-vod-manager", - "version": "3.8.0", + "version": "3.8.1", "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 2d01a93..250dc9b 100644 --- a/typescript-version/src/index.html +++ b/typescript-version/src/index.html @@ -335,7 +335,7 @@

Updates

-

Version: v3.8.0

+

Version: v3.8.1

@@ -346,7 +346,7 @@
Nicht verbunden - v3.8.0 + v3.8.1 diff --git a/typescript-version/src/main.ts b/typescript-version/src/main.ts index d41c133..a662bfb 100644 --- a/typescript-version/src/main.ts +++ b/typescript-version/src/main.ts @@ -1,14 +1,14 @@ import { app, BrowserWindow, ipcMain, dialog, shell } from 'electron'; import * as path from 'path'; import * as fs from 'fs'; -import { spawn, ChildProcess, execSync, exec, execFileSync, spawnSync } from 'child_process'; +import { spawn, ChildProcess, execSync, exec, spawnSync } from 'child_process'; import axios from 'axios'; import { autoUpdater } from 'electron-updater'; // ========================================== // CONFIG & CONSTANTS // ========================================== -const APP_VERSION = '3.8.0'; +const APP_VERSION = '3.8.1'; const UPDATE_CHECK_URL = 'http://24-music.de/version.json'; // Paths @@ -273,15 +273,36 @@ async function downloadFile(url: string, destinationPath: string): Promise { try { fs.mkdirSync(destinationDir, { recursive: true }); - execFileSync('powershell', [ - '-NoProfile', - '-ExecutionPolicy', 'Bypass', - '-Command', - `Expand-Archive -Path '${zipPath.replace(/'/g, "''")}' -DestinationPath '${destinationDir.replace(/'/g, "''")}' -Force` - ], { windowsHide: true, stdio: 'ignore' }); + + const command = `Expand-Archive -Path '${zipPath.replace(/'/g, "''")}' -DestinationPath '${destinationDir.replace(/'/g, "''")}' -Force`; + + await new Promise((resolve, reject) => { + const proc = spawn('powershell', [ + '-NoProfile', + '-ExecutionPolicy', 'Bypass', + '-Command', + command + ], { windowsHide: true }); + + let stderr = ''; + proc.stderr?.on('data', (data) => { + stderr += data.toString(); + }); + + proc.on('close', (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`Expand-Archive exit code ${code}: ${stderr.trim()}`)); + } + }); + + proc.on('error', (err) => reject(err)); + }); + return true; } catch (e) { appendDebugLog('extract-zip-failed', { zipPath, destinationDir, error: String(e) }); @@ -327,7 +348,7 @@ async function ensureStreamlinkInstalled(): Promise { fs.rmSync(TOOLS_STREAMLINK_DIR, { recursive: true, force: true }); fs.mkdirSync(TOOLS_STREAMLINK_DIR, { recursive: true }); - const extractOk = extractZip(zipPath, TOOLS_STREAMLINK_DIR); + const extractOk = await extractZip(zipPath, TOOLS_STREAMLINK_DIR); try { fs.unlinkSync(zipPath); } catch { } if (!extractOk) return false; @@ -368,7 +389,7 @@ async function ensureFfmpegInstalled(): Promise { fs.rmSync(TOOLS_FFMPEG_DIR, { recursive: true, force: true }); fs.mkdirSync(TOOLS_FFMPEG_DIR, { recursive: true }); - const extractOk = extractZip(zipPath, TOOLS_FFMPEG_DIR); + const extractOk = await extractZip(zipPath, TOOLS_FFMPEG_DIR); try { fs.unlinkSync(zipPath); } catch { } if (!extractOk) return false; @@ -1653,12 +1674,7 @@ ipcMain.handle('save-video-dialog', async (_, defaultName: string) => { app.whenReady().then(() => { refreshBundledToolPaths(); createWindow(); - - void (async () => { - const streamlinkOk = await ensureStreamlinkInstalled(); - const ffmpegOk = await ensureFfmpegInstalled(); - appendDebugLog('startup-tools-check', { streamlinkOk, ffmpegOk }); - })(); + appendDebugLog('startup-tools-check-skipped', 'Deferred to first use'); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { diff --git a/typescript-version/src/renderer.ts b/typescript-version/src/renderer.ts index e33e9fe..a80b095 100644 --- a/typescript-version/src/renderer.ts +++ b/typescript-version/src/renderer.ts @@ -21,7 +21,7 @@ async function init(): Promise { updateDownloadButtonState(); window.api.onQueueUpdated((q: QueueItem[]) => { - queue = Array.isArray(q) ? q : []; + queue = mergeQueueState(Array.isArray(q) ? q : []); renderQueue(); }); @@ -82,6 +82,33 @@ async function init(): Promise { }, 2000); } +function mergeQueueState(nextQueue: QueueItem[]): QueueItem[] { + const prevById = new Map(queue.map((item) => [item.id, item])); + + return nextQueue.map((item) => { + const prev = prevById.get(item.id); + if (!prev) { + return item; + } + + if (item.status !== 'downloading') { + return item; + } + + return { + ...item, + progress: item.progress > 0 ? item.progress : prev.progress, + speed: item.speed || prev.speed, + eta: item.eta || prev.eta, + currentPart: item.currentPart || prev.currentPart, + totalParts: item.totalParts || prev.totalParts, + downloadedBytes: item.downloadedBytes || prev.downloadedBytes, + totalBytes: item.totalBytes || prev.totalBytes, + progressStatus: item.progressStatus || prev.progressStatus + }; + }); +} + function updateDownloadButtonState(): void { const btn = byId('btnStart'); btn.textContent = downloading ? 'Stoppen' : 'Start'; @@ -90,7 +117,7 @@ function updateDownloadButtonState(): void { async function syncQueueAndDownloadState(): Promise { const latestQueue = await window.api.getQueue(); - queue = Array.isArray(latestQueue) ? latestQueue : []; + queue = mergeQueueState(Array.isArray(latestQueue) ? latestQueue : []); renderQueue(); const backendDownloading = await window.api.isDownloading();