Compare commits
2 Commits
1b0be5f817
...
7a025be645
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a025be645 | ||
|
|
b1ad04d9c2 |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "multi-hoster-uploader",
|
"name": "multi-hoster-uploader",
|
||||||
"version": "3.3.82",
|
"version": "3.3.83",
|
||||||
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
|
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -71,6 +71,7 @@ let _sessionUploadedBytes = 0; // Bytes fully uploaded this session (done jobs)
|
|||||||
const _sessionTrackedJobs = new Set(); // Job IDs already counted for totalBytes
|
const _sessionTrackedJobs = new Set(); // Job IDs already counted for totalBytes
|
||||||
const _sessionDoneJobs = new Set(); // Job IDs already counted for uploadedBytes
|
const _sessionDoneJobs = new Set(); // Job IDs already counted for uploadedBytes
|
||||||
const _completedUploadKeys = new Set(); // 'filepath|hoster' keys for done uploads (survives removeFromQueueOnDone)
|
const _completedUploadKeys = new Set(); // 'filepath|hoster' keys for done uploads (survives removeFromQueueOnDone)
|
||||||
|
const _suppressedPreviewKeys = new Set();
|
||||||
const _deletedJobIds = new Set(); // IDs of jobs explicitly deleted by user (prevents re-creation from stale progress callbacks)
|
const _deletedJobIds = new Set(); // IDs of jobs explicitly deleted by user (prevents re-creation from stale progress callbacks)
|
||||||
// Coalesce removeFromQueueOnDone removals into one filter pass per microtask
|
// Coalesce removeFromQueueOnDone removals into one filter pass per microtask
|
||||||
// to avoid O(N²) behaviour when a burst of jobs finish at once. Logic now
|
// to avoid O(N²) behaviour when a burst of jobs finish at once. Logic now
|
||||||
@ -215,6 +216,7 @@ async function init() {
|
|||||||
}
|
}
|
||||||
if (newFiles.length > 0) {
|
if (newFiles.length > 0) {
|
||||||
const newPaths = new Set(newFiles.map(f => f.path));
|
const newPaths = new Set(newFiles.map(f => f.path));
|
||||||
|
clearDedupKeysForPaths(newPaths);
|
||||||
selectedFiles.push(...newFiles);
|
selectedFiles.push(...newFiles);
|
||||||
buildQueuePreview();
|
buildQueuePreview();
|
||||||
updateUploadView();
|
updateUploadView();
|
||||||
@ -671,12 +673,7 @@ function applyHosterSelection() {
|
|||||||
selectedFiles.push(..._pendingFiles);
|
selectedFiles.push(..._pendingFiles);
|
||||||
_pendingFiles = [];
|
_pendingFiles = [];
|
||||||
}
|
}
|
||||||
if (pendingPaths.size > 0) {
|
clearDedupKeysForPaths(pendingPaths);
|
||||||
for (const key of [..._completedUploadKeys]) {
|
|
||||||
const sep = key.lastIndexOf('|');
|
|
||||||
if (sep > 0 && pendingPaths.has(key.slice(0, sep))) _completedUploadKeys.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
renderHosterSummary();
|
renderHosterSummary();
|
||||||
|
|
||||||
// During an active upload, build preview jobs for the new files and inject
|
// During an active upload, build preview jobs for the new files and inject
|
||||||
@ -725,6 +722,12 @@ function restoreQueueStateFromConfig() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(pending.suppressedKeys)) {
|
||||||
|
for (const k of pending.suppressedKeys) {
|
||||||
|
if (typeof k === 'string' && k) _suppressedPreviewKeys.add(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
selectedUploadHosters = Array.isArray(pending.selectedUploadHosters)
|
selectedUploadHosters = Array.isArray(pending.selectedUploadHosters)
|
||||||
? pending.selectedUploadHosters.filter(Boolean)
|
? pending.selectedUploadHosters.filter(Boolean)
|
||||||
: selectedUploadHosters;
|
: selectedUploadHosters;
|
||||||
@ -802,11 +805,17 @@ function buildPersistedQueueState() {
|
|||||||
const sep = k.lastIndexOf('|');
|
const sep = k.lastIndexOf('|');
|
||||||
if (sep > 0 && selectedFileMap.has(k.slice(0, sep))) completedKeys.push(k);
|
if (sep > 0 && selectedFileMap.has(k.slice(0, sep))) completedKeys.push(k);
|
||||||
}
|
}
|
||||||
|
const suppressedKeys = [];
|
||||||
|
for (const k of _suppressedPreviewKeys) {
|
||||||
|
const sep = k.lastIndexOf('|');
|
||||||
|
if (sep > 0 && selectedFileMap.has(k.slice(0, sep))) suppressedKeys.push(k);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
savedAt: Date.now(),
|
savedAt: Date.now(),
|
||||||
selectedUploadHosters: getSelectedHosters(),
|
selectedUploadHosters: getSelectedHosters(),
|
||||||
selectedFiles: Array.from(selectedFileMap.values()),
|
selectedFiles: Array.from(selectedFileMap.values()),
|
||||||
completedKeys,
|
completedKeys,
|
||||||
|
suppressedKeys,
|
||||||
queueJobs: queueJobs.map(job => {
|
queueJobs: queueJobs.map(job => {
|
||||||
const isTerminal = TERMINAL.has(job.status);
|
const isTerminal = TERMINAL.has(job.status);
|
||||||
return {
|
return {
|
||||||
@ -1062,6 +1071,25 @@ function updateQueueActionButtons() {
|
|||||||
if (moveBottomBtn) moveBottomBtn.disabled = !hasMovableSelection;
|
if (moveBottomBtn) moveBottomBtn.disabled = !hasMovableSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearDedupKeysForPaths(pathSet) {
|
||||||
|
if (!pathSet || pathSet.size === 0) return;
|
||||||
|
for (const set of [_completedUploadKeys, _suppressedPreviewKeys]) {
|
||||||
|
for (const key of [...set]) {
|
||||||
|
const sep = key.lastIndexOf('|');
|
||||||
|
if (sep > 0 && pathSet.has(key.slice(0, sep))) set.delete(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function suppressPreviewKeysStillSelected(keys) {
|
||||||
|
if (!keys || keys.length === 0) return;
|
||||||
|
const stillSelected = new Set(selectedFiles.map(f => f.path));
|
||||||
|
for (const key of keys) {
|
||||||
|
const sep = key.lastIndexOf('|');
|
||||||
|
if (sep > 0 && stillSelected.has(key.slice(0, sep))) _suppressedPreviewKeys.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build preview jobs from selected files x selected hosters (before upload starts)
|
// Build preview jobs from selected files x selected hosters (before upload starts)
|
||||||
function buildQueuePreview() {
|
function buildQueuePreview() {
|
||||||
const hosters = getSelectedHosters();
|
const hosters = getSelectedHosters();
|
||||||
@ -1084,7 +1112,7 @@ function buildQueuePreview() {
|
|||||||
for (const file of selectedFiles) {
|
for (const file of selectedFiles) {
|
||||||
for (const hoster of hosters) {
|
for (const hoster of hosters) {
|
||||||
const key = `${file.path}|${hoster}`;
|
const key = `${file.path}|${hoster}`;
|
||||||
if (!existingKeys.has(key) && !_completedUploadKeys.has(key)) {
|
if (!existingKeys.has(key) && !_completedUploadKeys.has(key) && !_suppressedPreviewKeys.has(key)) {
|
||||||
const job = {
|
const job = {
|
||||||
id: `preview-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
id: `preview-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
||||||
file: file.path, fileName: file.name, hoster,
|
file: file.path, fileName: file.name, hoster,
|
||||||
@ -1870,12 +1898,18 @@ document.addEventListener('keydown', (e) => {
|
|||||||
return j && (j.status === 'uploading' || j.status === 'queued' || j.status === 'retrying' || j.status === 'getting-server');
|
return j && (j.status === 'uploading' || j.status === 'queued' || j.status === 'retrying' || j.status === 'getting-server');
|
||||||
});
|
});
|
||||||
if (activeIds.length > 0) window.api.cancelSelectedJobs(activeIds);
|
if (activeIds.length > 0) window.api.cancelSelectedJobs(activeIds);
|
||||||
|
const _deletedKeys = [];
|
||||||
queueJobs = queueJobs.filter(j => {
|
queueJobs = queueJobs.filter(j => {
|
||||||
if (selectedJobIds.has(j.id)) { removeJobFromIndex(j); return false; }
|
if (selectedJobIds.has(j.id)) {
|
||||||
|
if (j.file && j.hoster && j.status !== 'done') _deletedKeys.push(`${j.file}|${j.hoster}`);
|
||||||
|
removeJobFromIndex(j);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
selectedJobIds.clear();
|
selectedJobIds.clear();
|
||||||
syncSelectedFilesFromQueue();
|
syncSelectedFilesFromQueue();
|
||||||
|
suppressPreviewKeysStillSelected(_deletedKeys);
|
||||||
renderQueueTable();
|
renderQueueTable();
|
||||||
if (queueJobs.length === 0) { selectedFiles = []; updateUploadView(); }
|
if (queueJobs.length === 0) { selectedFiles = []; updateUploadView(); }
|
||||||
updateStatusBar();
|
updateStatusBar();
|
||||||
@ -1911,8 +1945,10 @@ async function handleContextAction(action) {
|
|||||||
return j && (j.status === 'uploading' || j.status === 'queued' || j.status === 'retrying' || j.status === 'getting-server');
|
return j && (j.status === 'uploading' || j.status === 'queued' || j.status === 'retrying' || j.status === 'getting-server');
|
||||||
});
|
});
|
||||||
if (activeIds.length > 0) window.api.cancelSelectedJobs(activeIds);
|
if (activeIds.length > 0) window.api.cancelSelectedJobs(activeIds);
|
||||||
|
const _deletedKeys = [];
|
||||||
queueJobs = queueJobs.filter(j => {
|
queueJobs = queueJobs.filter(j => {
|
||||||
if (selectedJobIds.has(j.id)) {
|
if (selectedJobIds.has(j.id)) {
|
||||||
|
if (j.file && j.hoster && j.status !== 'done') _deletedKeys.push(`${j.file}|${j.hoster}`);
|
||||||
removeJobFromIndex(j);
|
removeJobFromIndex(j);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1920,6 +1956,7 @@ async function handleContextAction(action) {
|
|||||||
});
|
});
|
||||||
selectedJobIds.clear();
|
selectedJobIds.clear();
|
||||||
syncSelectedFilesFromQueue();
|
syncSelectedFilesFromQueue();
|
||||||
|
suppressPreviewKeysStillSelected(_deletedKeys);
|
||||||
renderQueueTable();
|
renderQueueTable();
|
||||||
if (queueJobs.length === 0) { selectedFiles = []; updateUploadView(); }
|
if (queueJobs.length === 0) { selectedFiles = []; updateUploadView(); }
|
||||||
updateStatusBar();
|
updateStatusBar();
|
||||||
@ -2604,6 +2641,12 @@ async function retrySelectedJobs() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (retryJobs.length === 0) return;
|
if (retryJobs.length === 0) return;
|
||||||
|
for (const j of retryJobs) {
|
||||||
|
if (j.file && j.hoster) {
|
||||||
|
_completedUploadKeys.delete(`${j.file}|${j.hoster}`);
|
||||||
|
_suppressedPreviewKeys.delete(`${j.file}|${j.hoster}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Select the retry jobs and start them immediately.
|
// Select the retry jobs and start them immediately.
|
||||||
// No renderQueueTable / updateQueueActionButtons / updateStatusBar here:
|
// No renderQueueTable / updateQueueActionButtons / updateStatusBar here:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user