From 8b508177b5a4de789c0264ca932cc49ecbba1258 Mon Sep 17 00:00:00 2001 From: xRangerDE Date: Fri, 20 Feb 2026 21:59:37 +0100 Subject: [PATCH] Reduce queue IPC churn and cancel removed active downloads (v4.1.7) --- typescript-version/package-lock.json | 4 +- typescript-version/package.json | 2 +- typescript-version/src/index.html | 4 +- typescript-version/src/main.ts | 72 ++++++++++++++++++++++------ 4 files changed, 63 insertions(+), 19 deletions(-) diff --git a/typescript-version/package-lock.json b/typescript-version/package-lock.json index 975ddce..89827e5 100644 --- a/typescript-version/package-lock.json +++ b/typescript-version/package-lock.json @@ -1,12 +1,12 @@ { "name": "twitch-vod-manager", - "version": "4.1.6", + "version": "4.1.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twitch-vod-manager", - "version": "4.1.6", + "version": "4.1.7", "license": "MIT", "dependencies": { "axios": "^1.6.0", diff --git a/typescript-version/package.json b/typescript-version/package.json index 24b7f2e..62ab971 100644 --- a/typescript-version/package.json +++ b/typescript-version/package.json @@ -1,6 +1,6 @@ { "name": "twitch-vod-manager", - "version": "4.1.6", + "version": "4.1.7", "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 ee254fd..fa4a751 100644 --- a/typescript-version/src/index.html +++ b/typescript-version/src/index.html @@ -457,7 +457,7 @@

Updates

-

Version: v4.1.6

+

Version: v4.1.7

@@ -502,7 +502,7 @@
Nicht verbunden - v4.1.6 + v4.1.7 diff --git a/typescript-version/src/main.ts b/typescript-version/src/main.ts index 4765ce8..aade707 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 = '4.1.6'; +const APP_VERSION = '4.1.7'; const UPDATE_CHECK_URL = 'http://24-music.de/version.json'; // Paths @@ -344,10 +344,13 @@ let mainWindow: BrowserWindow | null = null; let config = loadConfig(); let accessToken: string | null = null; let downloadQueue: QueueItem[] = loadQueue(); +let queueIdCounter = 0; +let lastQueueBroadcastFingerprint = ''; let isDownloading = false; let currentProcess: ChildProcess | null = null; let currentDownloadCancelled = false; let pauseRequested = false; +let activeQueueItemId: string | null = null; let downloadStartTime = 0; let downloadedBytes = 0; const userIdLoginCache = new Map(); @@ -1416,6 +1419,34 @@ function getQueueCounts(queueData: QueueItem[] = downloadQueue): RuntimeMetricsS return counts; } +function generateQueueItemId(): string { + queueIdCounter = (queueIdCounter + 1) % 1000; + return `${Date.now()}-${queueIdCounter}`; +} + +function getQueueBroadcastFingerprint(queueData: QueueItem[] = downloadQueue): string { + return queueData.map((item) => [ + item.id, + item.status, + Math.round((Number(item.progress) || 0) * 10), + item.currentPart || 0, + item.totalParts || 0, + item.speed || '', + item.eta || '', + item.last_error || '' + ].join(':')).join('|'); +} + +function emitQueueUpdated(force = false): void { + const nextFingerprint = getQueueBroadcastFingerprint(downloadQueue); + if (!force && nextFingerprint === lastQueueBroadcastFingerprint) { + return; + } + + lastQueueBroadcastFingerprint = nextFingerprint; + mainWindow?.webContents.send('queue-updated', downloadQueue); +} + function getRuntimeMetricsSnapshot(): RuntimeMetricsSnapshot { return { ...runtimeMetrics, @@ -2634,7 +2665,7 @@ async function processQueue(): Promise { isDownloading = true; pauseRequested = false; mainWindow?.webContents.send('download-started'); - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); while (isDownloading && !pauseRequested) { const item = pickNextPendingQueueItem(); @@ -2652,11 +2683,12 @@ async function processQueue(): Promise { runtimeMetrics.downloadsStarted += 1; runtimeMetrics.activeItemId = item.id; runtimeMetrics.activeItemTitle = item.title; + activeQueueItemId = item.id; currentDownloadCancelled = false; item.status = 'downloading'; saveQueue(downloadQueue); - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); item.last_error = ''; @@ -2710,7 +2742,7 @@ async function processQueue(): Promise { totalParts: item.totalParts } as DownloadProgress); saveQueue(downloadQueue); - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); await sleep(retryDelaySeconds * 1000); } else { runtimeMetrics.retriesExhausted += 1; @@ -2730,6 +2762,7 @@ async function processQueue(): Promise { runtimeMetrics.activeItemId = null; runtimeMetrics.activeItemTitle = null; + activeQueueItemId = null; appendDebugLog('queue-item-finished', { itemId: item.id, @@ -2738,16 +2771,17 @@ async function processQueue(): Promise { }); saveQueue(downloadQueue); - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); } isDownloading = false; pauseRequested = false; runtimeMetrics.activeItemId = null; runtimeMetrics.activeItemTitle = null; + activeQueueItemId = null; saveQueue(downloadQueue); - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); mainWindow?.webContents.send('download-finished'); appendDebugLog('queue-finished', { items: downloadQueue.length }); } @@ -2969,27 +3003,37 @@ ipcMain.handle('add-to-queue', (_, item: Omit { + const wasActiveItem = activeQueueItemId === id; + + if (wasActiveItem) { + currentDownloadCancelled = true; + if (currentProcess) { + currentProcess.kill(); + } + appendDebugLog('queue-item-removed-active-cancelled', { id }); + } + downloadQueue = downloadQueue.filter(item => item.id !== id); saveQueue(downloadQueue); - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); return downloadQueue; }); ipcMain.handle('clear-completed', () => { downloadQueue = downloadQueue.filter(item => item.status !== 'completed'); saveQueue(downloadQueue); - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); return downloadQueue; }); @@ -3003,7 +3047,7 @@ ipcMain.handle('reorder-queue', (_, orderIds: string[]) => { downloadQueue = withOrder; saveQueue(downloadQueue); - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); return downloadQueue; }); @@ -3020,7 +3064,7 @@ ipcMain.handle('retry-failed-downloads', () => { }); saveQueue(downloadQueue); - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); if (!isDownloading) { void processQueue(); @@ -3034,12 +3078,12 @@ ipcMain.handle('start-download', async () => { const hasPendingItems = downloadQueue.some(item => item.status === 'pending'); if (!hasPendingItems) { - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); return false; } saveQueue(downloadQueue); - mainWindow?.webContents.send('queue-updated', downloadQueue); + emitQueueUpdated(); processQueue(); return true;