fix: keep large queue cancellation responsive

This commit is contained in:
Release Bot
2026-08-12 03:22:27 +02:00
parent d1b36b0aaa
commit c843b4e623
7 changed files with 43 additions and 4 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ Multi-Hoster-Upload is a Windows desktop application for sending file batches to
Download the current Setup or Portable build from the [latest GitHub release](https://github.com/Sucukdeluxe/Multi-Hoster-Upload/releases/latest).
The latest public release is version 2.1.12. Use the release page for the executables and the full English changelog.
The latest public release is version 2.1.15. Use the release page for the executables and the full English changelog.
## Features
+1
View File
@@ -471,6 +471,7 @@ class UploadManager extends EventEmitter {
};
const emitFinalStatus = (status, payload = {}) => {
if (status === 'aborted' && this.abortController.signal.aborted) return;
this._emitProgress(uploadId, fileName, task.hoster, { accountId: task.accountId,
jobId,
status,
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "multi-hoster-uploader",
"version": "2.1.14",
"version": "2.1.15",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "multi-hoster-uploader",
"version": "2.1.14",
"version": "2.1.15",
"dependencies": {
"chokidar": "^3.6.0",
"undici": "^7.29.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "multi-hoster-uploader",
"version": "2.1.14",
"version": "2.1.15",
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
"main": "main.js",
"scripts": {
+2
View File
@@ -2305,6 +2305,8 @@ function showRecentContextMenu(row, x, y) {
applyRecentSelectionClasses();
}
const menu = document.getElementById('recentContextMenu');
const copyItem = menu.querySelector('[data-action="recent-copy-links"]');
if (copyItem) copyItem.textContent = selectedRecentIds.size > 1 ? `Links kopieren (${selectedRecentIds.size})` : 'Link kopieren';
menu.style.display = 'block';
menu.style.left = Math.min(x, window.innerWidth - menu.offsetWidth - 5) + 'px';
menu.style.top = Math.min(y, window.innerHeight - menu.offsetHeight - 5) + 'px';
+3
View File
@@ -1486,6 +1486,9 @@ setTimeout(async () => {
const historyWorkspaceLayout = await wc.executeJavaScript('(() => { const view = document.getElementById("history-view"); const sidebar = view?.querySelector(":scope > .view-sidebar"); const main = view?.querySelector(":scope > .view-main"); if (!sidebar || !main) return false; const sidebarRect = sidebar.getBoundingClientRect(); const mainRect = main.getBoundingClientRect(); return sidebarRect.width > 0 && mainRect.width > 0 && sidebarRect.right <= mainRect.left; })()');
check('History view separates sidebar and main workspace', historyWorkspaceLayout === true);
const singleRecentLinkContextLabel = await wc.executeJavaScript('(() => { selectedRecentIds.clear(); const row = document.createElement("tr"); row.dataset.order = "1001"; showRecentContextMenu(row, 8, 8); const label = document.querySelector("#recentContextMenu [data-action=recent-copy-links]")?.textContent?.trim(); hideContextMenu(); return label; })()');
check('Recent upload context menu uses singular copy text for one link', singleRecentLinkContextLabel === 'Link kopieren');
const historySidebarInformation = await wc.executeJavaScript('(() => { const sidebar = document.querySelector("#history-view > .view-sidebar")?.getBoundingClientRect(); const section = document.querySelector("#history-view .view-sidebar-section")?.getBoundingClientRect(); const retention = document.getElementById("historySidebarRetention")?.textContent?.trim(); return Boolean(sidebar && section && section.top >= sidebar.top + sidebar.height * 0.55 && retention === "Alles behalten"); })()');
check('History sidebar shows the active retention in its lower area', historySidebarInformation === true);
+33
View File
@@ -225,6 +225,39 @@ describe('UploadManager', () => {
assert.ok(batchDone, 'batch-done should be emitted even after cancel');
});
it('does not emit one aborted progress event per job when cancelling a whole batch', async () => {
mockUploadFile.mock.mockImplementation(async (hoster, filePath, apiKey, onProgress, signal) => {
await new Promise((resolve, reject) => {
const timer = setTimeout(resolve, 10000);
signal.addEventListener('abort', () => {
clearTimeout(timer);
reject(new Error('Aborted'));
}, { once: true });
});
return { download_url: `https://${hoster}/d/ok123`, embed_url: null, file_code: 'ok123' };
});
const mgr = new UploadManager({
'doodstream.com': { retries: 0, parallelCount: 1, maxSpeedKbs: 0, restartBelowKbs: 0, timeIntervalSec: 0, maxSizeMb: 0 }
});
const statuses = [];
mgr.on('progress', (data) => statuses.push(data.status));
const tasks = Array.from({ length: 60 }, (_, index) => ({
jobId: `cancel-${index}`,
file: `/test/cancel-${index}.mp4`,
hoster: 'doodstream.com',
apiKey: 'key1'
}));
const batchPromise = mgr.startBatch(tasks);
await new Promise((resolve) => setTimeout(resolve, 50));
mgr.cancel();
await batchPromise;
assert.equal(statuses.filter((status) => status === 'aborted').length, 0);
});
it('maxSizeMb filter skips oversized files', async () => {
fakeFileSize = 5 * 1024 * 1024; // 5 MB