Compare commits
2 Commits
e216c95b61
...
2efbc355b3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2efbc355b3 | ||
|
|
0a607adb29 |
@ -17,7 +17,10 @@
|
||||
const parts = trimmed.split('|');
|
||||
if (parts.length < 5) return null;
|
||||
const hoster = (parts[1] || '').trim();
|
||||
const fileName = (parts[4] || '').trim();
|
||||
let fileName = '';
|
||||
for (let i = parts.length - 1; i >= 4; i--) {
|
||||
if (parts[i].trim() !== '') { fileName = parts[i]; break; }
|
||||
}
|
||||
if (!hoster || !fileName) return null;
|
||||
const tsStr = (parts[0] || '').trim();
|
||||
const tsParsed = tsStr ? Date.parse(tsStr.replace(' ', 'T')) : NaN;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "multi-hoster-uploader",
|
||||
"version": "3.3.81",
|
||||
"version": "3.3.82",
|
||||
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
||||
@ -671,6 +671,12 @@ function applyHosterSelection() {
|
||||
selectedFiles.push(..._pendingFiles);
|
||||
_pendingFiles = [];
|
||||
}
|
||||
if (pendingPaths.size > 0) {
|
||||
for (const key of [..._completedUploadKeys]) {
|
||||
const sep = key.lastIndexOf('|');
|
||||
if (sep > 0 && pendingPaths.has(key.slice(0, sep))) _completedUploadKeys.delete(key);
|
||||
}
|
||||
}
|
||||
renderHosterSummary();
|
||||
|
||||
// During an active upload, build preview jobs for the new files and inject
|
||||
@ -713,6 +719,12 @@ function restoreQueueStateFromConfig() {
|
||||
? pending.savedAt
|
||||
: null;
|
||||
|
||||
if (Array.isArray(pending.completedKeys)) {
|
||||
for (const k of pending.completedKeys) {
|
||||
if (typeof k === 'string' && k) _completedUploadKeys.add(k);
|
||||
}
|
||||
}
|
||||
|
||||
selectedUploadHosters = Array.isArray(pending.selectedUploadHosters)
|
||||
? pending.selectedUploadHosters.filter(Boolean)
|
||||
: selectedUploadHosters;
|
||||
@ -785,10 +797,16 @@ function buildPersistedQueueState() {
|
||||
// consistent "Bereit" for everything that didn't actually terminate.
|
||||
// Only true terminal states (done / error / skipped) survive as-is.
|
||||
const TERMINAL = new Set(['done', 'error', 'skipped']);
|
||||
const completedKeys = [];
|
||||
for (const k of _completedUploadKeys) {
|
||||
const sep = k.lastIndexOf('|');
|
||||
if (sep > 0 && selectedFileMap.has(k.slice(0, sep))) completedKeys.push(k);
|
||||
}
|
||||
return {
|
||||
savedAt: Date.now(),
|
||||
selectedUploadHosters: getSelectedHosters(),
|
||||
selectedFiles: Array.from(selectedFileMap.values()),
|
||||
completedKeys,
|
||||
queueJobs: queueJobs.map(job => {
|
||||
const isTerminal = TERMINAL.has(job.status);
|
||||
return {
|
||||
@ -1060,7 +1078,7 @@ function buildQueuePreview() {
|
||||
// Build a Set for fast existence checks
|
||||
const existingKeys = new Set();
|
||||
for (const j of queueJobs) {
|
||||
if (j.status !== 'error') existingKeys.add(`${j.file}|${j.hoster}`);
|
||||
existingKeys.add(`${j.file}|${j.hoster}`);
|
||||
}
|
||||
|
||||
for (const file of selectedFiles) {
|
||||
@ -1099,14 +1117,14 @@ function indexJob(job) {
|
||||
if (job.uploadId) _jobIndexByUploadId.set(job.uploadId, job);
|
||||
}
|
||||
|
||||
function removeJobFromIndex(job) {
|
||||
function removeJobFromIndex(job, keepCompletedKey) {
|
||||
_jobIndexById.delete(job.id);
|
||||
if (job.uploadId) _jobIndexByUploadId.delete(job.uploadId);
|
||||
// Track deletion so handleProgress() won't re-create this job from stale callbacks
|
||||
_deletedJobIds.add(job.id);
|
||||
if (job.uploadId) _deletedJobIds.add(job.uploadId);
|
||||
// Allow re-uploading same file+hoster after deletion
|
||||
if (job.file && job.hoster) _completedUploadKeys.delete(`${job.file}|${job.hoster}`);
|
||||
if (!keepCompletedKey && job.file && job.hoster) _completedUploadKeys.delete(`${job.file}|${job.hoster}`);
|
||||
}
|
||||
|
||||
// --- Queue Table Rendering (debounced with virtual scrolling) ---
|
||||
@ -2249,7 +2267,7 @@ function _handleProgressImpl(data) {
|
||||
// updated synchronously so subsequent lookups see the right state — only
|
||||
// the array rewrite is deferred.
|
||||
if (job.status === 'done' && config.globalSettings && config.globalSettings.removeFromQueueOnDone) {
|
||||
removeJobFromIndex(job);
|
||||
removeJobFromIndex(job, true);
|
||||
selectedJobIds.delete(job.id);
|
||||
if (_doneRemovalCoalescer) {
|
||||
_doneRemovalCoalescer.add(job.id);
|
||||
@ -2315,7 +2333,7 @@ function handleBatchDone(summary) {
|
||||
const nextJobs = [];
|
||||
for (const job of queueJobs) {
|
||||
if (job.status === 'done') {
|
||||
removeJobFromIndex(job);
|
||||
removeJobFromIndex(job, true);
|
||||
selectedJobIds.delete(job.id);
|
||||
} else {
|
||||
nextJobs.push(job);
|
||||
@ -2337,7 +2355,7 @@ function handleBatchDone(summary) {
|
||||
const result = window.QueuePrune?.pruneOldestTerminalJobs(queueJobs, TERMINAL_KEEP_LIMIT);
|
||||
if (result) {
|
||||
for (const j of result.dropped) {
|
||||
removeJobFromIndex(j);
|
||||
removeJobFromIndex(j, true);
|
||||
selectedJobIds.delete(j.id);
|
||||
}
|
||||
queueJobs = result.kept;
|
||||
|
||||
@ -50,3 +50,31 @@ test('parseUploadLogLine: missing/garbage timestamp yields ts=undefined (legacy
|
||||
assert.equal(parsed.fileName, 'a.mkv');
|
||||
assert.equal(parsed.ts, undefined);
|
||||
});
|
||||
|
||||
test('parseUploadLogLine: a pipe in the link does NOT shift the filename field (entry not lost)', () => {
|
||||
const line = formatUploadLogLine(new Date(2026, 5, 19, 12, 0, 0), 'byse.sx', 'https://h.io/a|b', 'movie.mkv');
|
||||
const parsed = parseUploadLogLine(line);
|
||||
assert.equal(parsed.hoster, 'byse.sx');
|
||||
assert.equal(parsed.fileName, 'movie.mkv', 'filename is taken as the last non-empty field, robust to link pipes');
|
||||
});
|
||||
|
||||
test('parseUploadLogLine: two pipes in the link still parse the correct filename', () => {
|
||||
const line = formatUploadLogLine(new Date(2026, 5, 19, 12, 0, 0), 'byse.sx', 'https://h.io/a|b|c', 'movie.mkv');
|
||||
const parsed = parseUploadLogLine(line);
|
||||
assert.equal(parsed.fileName, 'movie.mkv');
|
||||
});
|
||||
|
||||
test('parseUploadLogLine: a leading-space filename is preserved (matches the untrimmed queue-job key)', () => {
|
||||
const line = formatUploadLogLine(new Date(2026, 5, 19, 12, 0, 0), 'voe.sx', 'https://h.io/a', ' movie.mkv');
|
||||
const parsed = parseUploadLogLine(line);
|
||||
assert.equal(parsed.fileName, ' movie.mkv', 'filename is NOT trimmed, so it matches the OS basename verbatim');
|
||||
});
|
||||
|
||||
test('SEAM: a leading-space filename round-trips and the gate still drops its ghost', () => {
|
||||
const completion = new Date(2026, 5, 19, 12, 0, 30);
|
||||
const parsed = parseUploadLogLine(formatUploadLogLine(completion, 'voe.sx', 'l', ' spaced.mp4'));
|
||||
const savedAt = completion.getTime() - 5000;
|
||||
const job = { status: 'preview', fileName: ' spaced.mp4', hoster: 'voe.sx', file: 'C:/dl/ spaced.mp4' };
|
||||
const { removed } = partitionRestoredJobsByLog([job], [parsed], savedAt);
|
||||
assert.equal(removed.length, 1, 'leading-space filename now matches end-to-end (was a mismatch before)');
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user