Files
Multi-Hoster-Upload/lib/upload-log.js
T
Sucukdeluxe bfb3a39fed fix: harden upload cancellation and audit logging
Preserve pre-start and batch cancellation requests, reject late upload success after cancellation, and wait for cancellation acknowledgements before removing queue entries.

Separate formatted link logs from privacy-safe source cleanup and upload plan audits, persist audit fallback paths, redact support bundles, and expose audit diagnostics safely.

Improve queue selection and destructive-action clarity, show the Settings save action only while changes are pending, and add regression coverage for all updated behavior.
2026-08-13 14:31:46 +02:00

80 lines
3.2 KiB
JavaScript

(function (root) {
'use strict';
function _pad(n) { return String(n).padStart(2, '0'); }
function formatUploadLogLine(date, hoster, link, fileName) {
const d = date instanceof Date ? date : new Date();
const dateStr = `${d.getFullYear()}-${_pad(d.getMonth() + 1)}-${_pad(d.getDate())} ` +
`${_pad(d.getHours())}:${_pad(d.getMinutes())}:${_pad(d.getSeconds())}`;
return `${dateStr}|${hoster}|${link}||${fileName}|\n`;
}
function parseUploadLogLine(line) {
if (typeof line !== 'string') return null;
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) return null;
const parts = trimmed.split('|');
if (parts.length < 5) return null;
const hoster = (parts[1] || '').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;
const ts = isNaN(tsParsed) ? undefined : tsParsed;
return { hoster, fileName, ts };
}
function summarizeBatchPlan(payload) {
const source = payload && typeof payload === 'object' ? payload : {};
const jobs = Array.isArray(source.jobs) ? source.jobs : [];
if (jobs.length > 0) {
const files = new Set();
const destinations = new Set();
let plannedUploadCount = 0;
for (const job of jobs) {
if (!job || typeof job !== 'object') continue;
const file = typeof job.file === 'string' ? job.file.trim() : '';
const hoster = typeof job.hoster === 'string' ? job.hoster.trim() : '';
if (!file || !hoster) continue;
files.add(file);
destinations.add(hoster);
plannedUploadCount++;
}
return {
fileCount: files.size,
destinationCount: destinations.size,
plannedUploadCount
};
}
const files = new Set((Array.isArray(source.files) ? source.files : []).filter(value => typeof value === 'string' && value.trim()));
const destinations = new Set((Array.isArray(source.hosters) ? source.hosters : []).filter(value => typeof value === 'string' && value.trim()));
return {
fileCount: files.size,
destinationCount: destinations.size,
plannedUploadCount: files.size * destinations.size
};
}
function formatUploadPlanLogLine(date, plan, mode) {
const inputDate = date instanceof Date && !Number.isNaN(date.getTime()) ? date : new Date();
const source = plan && typeof plan === 'object' ? plan : {};
const count = value => Number.isFinite(Number(value)) ? Math.max(0, Math.floor(Number(value))) : 0;
return `# UPLOAD-PLAN ${JSON.stringify({
timestamp: inputDate.toISOString(),
mode: mode === 'add' ? 'add' : 'start',
fileCount: count(source.fileCount),
destinationCount: count(source.destinationCount),
plannedUploadCount: count(source.plannedUploadCount)
})}\r\n`;
}
const api = { formatUploadLogLine, parseUploadLogLine, summarizeBatchPlan, formatUploadPlanLogLine };
if (typeof module !== 'undefined' && module.exports) module.exports = api;
else if (root) root.UploadLog = api;
})(typeof window !== 'undefined' ? window : this);