Reduce queue IPC churn and cancel removed active downloads (v4.1.7)
This commit is contained in:
parent
10b80b3f48
commit
8b508177b5
4
typescript-version/package-lock.json
generated
4
typescript-version/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "4.1.6",
|
"version": "4.1.7",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "4.1.6",
|
"version": "4.1.7",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.6.0",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "twitch-vod-manager",
|
"name": "twitch-vod-manager",
|
||||||
"version": "4.1.6",
|
"version": "4.1.7",
|
||||||
"description": "Twitch VOD Manager - Download Twitch VODs easily",
|
"description": "Twitch VOD Manager - Download Twitch VODs easily",
|
||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"author": "xRangerDE",
|
"author": "xRangerDE",
|
||||||
|
|||||||
@ -457,7 +457,7 @@
|
|||||||
|
|
||||||
<div class="settings-card">
|
<div class="settings-card">
|
||||||
<h3 id="updateTitle">Updates</h3>
|
<h3 id="updateTitle">Updates</h3>
|
||||||
<p id="versionInfo" style="margin-bottom: 10px; color: var(--text-secondary);">Version: v4.1.6</p>
|
<p id="versionInfo" style="margin-bottom: 10px; color: var(--text-secondary);">Version: v4.1.7</p>
|
||||||
<button class="btn-secondary" id="checkUpdateBtn" onclick="checkUpdate()">Nach Updates suchen</button>
|
<button class="btn-secondary" id="checkUpdateBtn" onclick="checkUpdate()">Nach Updates suchen</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -502,7 +502,7 @@
|
|||||||
<div class="status-dot" id="statusDot"></div>
|
<div class="status-dot" id="statusDot"></div>
|
||||||
<span id="statusText">Nicht verbunden</span>
|
<span id="statusText">Nicht verbunden</span>
|
||||||
</div>
|
</div>
|
||||||
<span id="versionText">v4.1.6</span>
|
<span id="versionText">v4.1.7</span>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { autoUpdater } from 'electron-updater';
|
|||||||
// ==========================================
|
// ==========================================
|
||||||
// CONFIG & CONSTANTS
|
// CONFIG & CONSTANTS
|
||||||
// ==========================================
|
// ==========================================
|
||||||
const APP_VERSION = '4.1.6';
|
const APP_VERSION = '4.1.7';
|
||||||
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
|
const UPDATE_CHECK_URL = 'http://24-music.de/version.json';
|
||||||
|
|
||||||
// Paths
|
// Paths
|
||||||
@ -344,10 +344,13 @@ let mainWindow: BrowserWindow | null = null;
|
|||||||
let config = loadConfig();
|
let config = loadConfig();
|
||||||
let accessToken: string | null = null;
|
let accessToken: string | null = null;
|
||||||
let downloadQueue: QueueItem[] = loadQueue();
|
let downloadQueue: QueueItem[] = loadQueue();
|
||||||
|
let queueIdCounter = 0;
|
||||||
|
let lastQueueBroadcastFingerprint = '';
|
||||||
let isDownloading = false;
|
let isDownloading = false;
|
||||||
let currentProcess: ChildProcess | null = null;
|
let currentProcess: ChildProcess | null = null;
|
||||||
let currentDownloadCancelled = false;
|
let currentDownloadCancelled = false;
|
||||||
let pauseRequested = false;
|
let pauseRequested = false;
|
||||||
|
let activeQueueItemId: string | null = null;
|
||||||
let downloadStartTime = 0;
|
let downloadStartTime = 0;
|
||||||
let downloadedBytes = 0;
|
let downloadedBytes = 0;
|
||||||
const userIdLoginCache = new Map<string, string>();
|
const userIdLoginCache = new Map<string, string>();
|
||||||
@ -1416,6 +1419,34 @@ function getQueueCounts(queueData: QueueItem[] = downloadQueue): RuntimeMetricsS
|
|||||||
return counts;
|
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 {
|
function getRuntimeMetricsSnapshot(): RuntimeMetricsSnapshot {
|
||||||
return {
|
return {
|
||||||
...runtimeMetrics,
|
...runtimeMetrics,
|
||||||
@ -2634,7 +2665,7 @@ async function processQueue(): Promise<void> {
|
|||||||
isDownloading = true;
|
isDownloading = true;
|
||||||
pauseRequested = false;
|
pauseRequested = false;
|
||||||
mainWindow?.webContents.send('download-started');
|
mainWindow?.webContents.send('download-started');
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
|
|
||||||
while (isDownloading && !pauseRequested) {
|
while (isDownloading && !pauseRequested) {
|
||||||
const item = pickNextPendingQueueItem();
|
const item = pickNextPendingQueueItem();
|
||||||
@ -2652,11 +2683,12 @@ async function processQueue(): Promise<void> {
|
|||||||
runtimeMetrics.downloadsStarted += 1;
|
runtimeMetrics.downloadsStarted += 1;
|
||||||
runtimeMetrics.activeItemId = item.id;
|
runtimeMetrics.activeItemId = item.id;
|
||||||
runtimeMetrics.activeItemTitle = item.title;
|
runtimeMetrics.activeItemTitle = item.title;
|
||||||
|
activeQueueItemId = item.id;
|
||||||
|
|
||||||
currentDownloadCancelled = false;
|
currentDownloadCancelled = false;
|
||||||
item.status = 'downloading';
|
item.status = 'downloading';
|
||||||
saveQueue(downloadQueue);
|
saveQueue(downloadQueue);
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
|
|
||||||
item.last_error = '';
|
item.last_error = '';
|
||||||
|
|
||||||
@ -2710,7 +2742,7 @@ async function processQueue(): Promise<void> {
|
|||||||
totalParts: item.totalParts
|
totalParts: item.totalParts
|
||||||
} as DownloadProgress);
|
} as DownloadProgress);
|
||||||
saveQueue(downloadQueue);
|
saveQueue(downloadQueue);
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
await sleep(retryDelaySeconds * 1000);
|
await sleep(retryDelaySeconds * 1000);
|
||||||
} else {
|
} else {
|
||||||
runtimeMetrics.retriesExhausted += 1;
|
runtimeMetrics.retriesExhausted += 1;
|
||||||
@ -2730,6 +2762,7 @@ async function processQueue(): Promise<void> {
|
|||||||
|
|
||||||
runtimeMetrics.activeItemId = null;
|
runtimeMetrics.activeItemId = null;
|
||||||
runtimeMetrics.activeItemTitle = null;
|
runtimeMetrics.activeItemTitle = null;
|
||||||
|
activeQueueItemId = null;
|
||||||
|
|
||||||
appendDebugLog('queue-item-finished', {
|
appendDebugLog('queue-item-finished', {
|
||||||
itemId: item.id,
|
itemId: item.id,
|
||||||
@ -2738,16 +2771,17 @@ async function processQueue(): Promise<void> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
saveQueue(downloadQueue);
|
saveQueue(downloadQueue);
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
isDownloading = false;
|
isDownloading = false;
|
||||||
pauseRequested = false;
|
pauseRequested = false;
|
||||||
runtimeMetrics.activeItemId = null;
|
runtimeMetrics.activeItemId = null;
|
||||||
runtimeMetrics.activeItemTitle = null;
|
runtimeMetrics.activeItemTitle = null;
|
||||||
|
activeQueueItemId = null;
|
||||||
|
|
||||||
saveQueue(downloadQueue);
|
saveQueue(downloadQueue);
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
mainWindow?.webContents.send('download-finished');
|
mainWindow?.webContents.send('download-finished');
|
||||||
appendDebugLog('queue-finished', { items: downloadQueue.length });
|
appendDebugLog('queue-finished', { items: downloadQueue.length });
|
||||||
}
|
}
|
||||||
@ -2969,27 +3003,37 @@ ipcMain.handle('add-to-queue', (_, item: Omit<QueueItem, 'id' | 'status' | 'prog
|
|||||||
|
|
||||||
const queueItem: QueueItem = {
|
const queueItem: QueueItem = {
|
||||||
...item,
|
...item,
|
||||||
id: Date.now().toString(),
|
id: generateQueueItemId(),
|
||||||
status: 'pending',
|
status: 'pending',
|
||||||
progress: 0
|
progress: 0
|
||||||
};
|
};
|
||||||
downloadQueue.push(queueItem);
|
downloadQueue.push(queueItem);
|
||||||
saveQueue(downloadQueue);
|
saveQueue(downloadQueue);
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
return downloadQueue;
|
return downloadQueue;
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('remove-from-queue', (_, id: string) => {
|
ipcMain.handle('remove-from-queue', (_, id: string) => {
|
||||||
|
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);
|
downloadQueue = downloadQueue.filter(item => item.id !== id);
|
||||||
saveQueue(downloadQueue);
|
saveQueue(downloadQueue);
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
return downloadQueue;
|
return downloadQueue;
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('clear-completed', () => {
|
ipcMain.handle('clear-completed', () => {
|
||||||
downloadQueue = downloadQueue.filter(item => item.status !== 'completed');
|
downloadQueue = downloadQueue.filter(item => item.status !== 'completed');
|
||||||
saveQueue(downloadQueue);
|
saveQueue(downloadQueue);
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
return downloadQueue;
|
return downloadQueue;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -3003,7 +3047,7 @@ ipcMain.handle('reorder-queue', (_, orderIds: string[]) => {
|
|||||||
|
|
||||||
downloadQueue = withOrder;
|
downloadQueue = withOrder;
|
||||||
saveQueue(downloadQueue);
|
saveQueue(downloadQueue);
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
return downloadQueue;
|
return downloadQueue;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -3020,7 +3064,7 @@ ipcMain.handle('retry-failed-downloads', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
saveQueue(downloadQueue);
|
saveQueue(downloadQueue);
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
|
|
||||||
if (!isDownloading) {
|
if (!isDownloading) {
|
||||||
void processQueue();
|
void processQueue();
|
||||||
@ -3034,12 +3078,12 @@ ipcMain.handle('start-download', async () => {
|
|||||||
|
|
||||||
const hasPendingItems = downloadQueue.some(item => item.status === 'pending');
|
const hasPendingItems = downloadQueue.some(item => item.status === 'pending');
|
||||||
if (!hasPendingItems) {
|
if (!hasPendingItems) {
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveQueue(downloadQueue);
|
saveQueue(downloadQueue);
|
||||||
mainWindow?.webContents.send('queue-updated', downloadQueue);
|
emitQueueUpdated();
|
||||||
|
|
||||||
processQueue();
|
processQueue();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user