repost check for upload

This commit is contained in:
2026-07-15 18:03:06 +02:00
parent f057ea29d6
commit 3bbee6029f
3 changed files with 64 additions and 17 deletions

View File

@@ -304,9 +304,13 @@ window.cancelAnimFrame = (function () {
} }
const flash = document.createElement('div'); const flash = document.createElement('div');
flash.textContent = text; if (typeof text === 'string' && text.includes('<a ')) {
flash.innerHTML = text;
} else {
flash.textContent = text;
}
let baseStyle = 'color:#fff;padding:10px 18px;border-radius:6px;font-size:13px;opacity:0;transition:opacity 0.3s,transform 0.3s;box-shadow:0 4px 12px rgba(0,0,0,0.4);border:1px solid rgba(255,255,255,0.1);transform:translateY(6px);'; let baseStyle = 'color:#fff;padding:10px 18px;border-radius:6px;font-size:13px;opacity:0;transition:opacity 0.3s,transform 0.3s;box-shadow:0 4px 12px rgba(0,0,0,0.4);border:1px solid rgba(255,255,255,0.1);transform:translateY(6px);pointer-events:auto;';
if (type === 'error') { if (type === 'error') {
baseStyle += 'background:rgba(200,30,30,0.95);'; baseStyle += 'background:rgba(200,30,30,0.95);';
} else if (type === 'success') { } else if (type === 'success') {
@@ -8775,10 +8779,18 @@ document.addEventListener('DOMContentLoaded', () => {
const flash = document.createElement('div'); const flash = document.createElement('div');
flash.className = `flash-message flash-${type}`; flash.className = `flash-message flash-${type}`;
flash.textContent = message; if (typeof message === 'string' && message.includes('<a ')) {
flash.innerHTML = message;
} else {
flash.textContent = message;
}
// Add close behavior on click // Add close behavior on click
flash.onclick = () => flash.remove(); flash.onclick = (e) => {
if (e.target.tagName.toLowerCase() !== 'a') {
flash.remove();
}
};
container.appendChild(flash); container.appendChild(flash);

View File

@@ -175,7 +175,11 @@ window.escapeHtmlUpload = window.escapeHtmlUpload || ((unsafe) => {
const errMsg = notif.data?.msg || i18n().url_tracker_failed || 'Upload failed'; const errMsg = notif.data?.msg || i18n().url_tracker_failed || 'Upload failed';
const stageEl = row.querySelector('.uut-stage'); const stageEl = row.querySelector('.uut-stage');
if (stageEl) { if (stageEl) {
stageEl.textContent = errMsg; if (notif.item_id) {
stageEl.innerHTML = `${window.escapeHtmlUpload(errMsg)} (<a href="/${notif.item_id}" class="repost-link">view existing</a>)`;
} else {
stageEl.textContent = errMsg;
}
stageEl.style.color = '#ff5050'; stageEl.style.color = '#ff5050';
} }
const spinner = row.querySelector('.uut-spinner'); const spinner = row.querySelector('.uut-spinner');
@@ -250,7 +254,14 @@ window.escapeHtmlUpload = window.escapeHtmlUpload || ((unsafe) => {
if (row) { if (row) {
const errMsg = n.data?.msg || i18n().url_tracker_failed || 'Upload failed'; const errMsg = n.data?.msg || i18n().url_tracker_failed || 'Upload failed';
const stageEl = row.querySelector('.uut-stage'); const stageEl = row.querySelector('.uut-stage');
if (stageEl) { stageEl.textContent = errMsg; stageEl.style.color = '#ff5050'; } if (stageEl) {
if (n.item_id) {
stageEl.innerHTML = `${window.escapeHtmlUpload(errMsg)} (<a href="/${n.item_id}" class="repost-link">view existing</a>)`;
} else {
stageEl.textContent = errMsg;
}
stageEl.style.color = '#ff5050';
}
const spinner = row.querySelector('.uut-spinner'); const spinner = row.querySelector('.uut-spinner');
if (spinner) spinner.style.display = 'none'; if (spinner) spinner.style.display = 'none';
const barFill = row.querySelector('.uut-bar-fill'); const barFill = row.querySelector('.uut-bar-fill');
@@ -2425,12 +2436,18 @@ window.initUploadForm = (selector) => {
} catch(e) {} } catch(e) {}
} }
} else if (!isShitpost) { } else if (!isShitpost) {
throw new Error(data.msg || 'Upload failed'); const err = new Error(data.msg || 'Upload failed');
if (data.repost) err.repost = data.repost;
throw err;
} }
} catch (err) { } catch (err) {
console.error('[UPLOAD ERROR]', err); console.error('[UPLOAD ERROR]', err);
if (!isShitpost) { if (!isShitpost) {
statusDiv.textContent = '✕ ' + err.message; if (err.repost) {
statusDiv.innerHTML = '✕ ' + window.escapeHtmlUpload(err.message) + ` (<a href="/${err.repost}" class="repost-link">view existing</a>)`;
} else {
statusDiv.textContent = '✕ ' + err.message;
}
statusDiv.className = 'upload-status error'; statusDiv.className = 'upload-status error';
restoreBtn(); restoreBtn();
return; return;
@@ -2596,29 +2613,43 @@ window.initUploadForm = (selector) => {
const errMsg = res.msg || 'Upload failed'; const errMsg = res.msg || 'Upload failed';
if (isShitpost) { if (isShitpost) {
// In shitpost mode there's no persistent statusDiv — use flash // In shitpost mode there's no persistent statusDiv — use flash
let flashMsg = `${errMsg}`;
if (res.repost) {
flashMsg += ` (<a href="/${res.repost}" style="color:#1fb2b0;text-decoration:underline;">view existing</a>)`;
}
if (typeof window.flashMessage === 'function') { if (typeof window.flashMessage === 'function') {
window.flashMessage(`${errMsg}`, 5000, 'error'); window.flashMessage(flashMsg, 5000, 'error');
} else if (typeof window.showFlash === 'function') { } else if (typeof window.showFlash === 'function') {
window.showFlash(errMsg, 'error'); window.showFlash(res.repost ? errMsg + ` (<a href="/${res.repost}" style="color:#1fb2b0;text-decoration:underline;">view existing</a>)` : errMsg, 'error');
} }
} else { } else {
throw new Error(errMsg); const err = new Error(errMsg);
if (res.repost) err.repost = res.repost;
throw err;
} }
} }
} catch (err) { } catch (err) {
console.error('[UPLOAD ERROR]', err); console.error('[UPLOAD ERROR]', err);
if (!isShitpost) { if (!isShitpost) {
statusDiv.textContent = '✕ ' + err.message; if (err.repost) {
statusDiv.innerHTML = '✕ ' + window.escapeHtmlUpload(err.message) + ` (<a href="/${err.repost}" class="repost-link">view existing</a>)`;
} else {
statusDiv.textContent = '✕ ' + err.message;
}
statusDiv.className = 'upload-status error'; statusDiv.className = 'upload-status error';
if (progressContainer) progressContainer.style.display = 'none'; if (progressContainer) progressContainer.style.display = 'none';
restoreBtn(); restoreBtn();
return; return;
} else { } else {
// Shitpost mode: show via flash toast // Shitpost mode: show via flash toast for general exceptions
let flashMsg = `${err.message}`;
if (err.repost) {
flashMsg += ` (<a href="/${err.repost}" style="color:#1fb2b0;text-decoration:underline;">view existing</a>)`;
}
if (typeof window.flashMessage === 'function') { if (typeof window.flashMessage === 'function') {
window.flashMessage(`${err.message}`, 5000, 'error'); window.flashMessage(flashMsg, 5000, 'error');
} else if (typeof window.showFlash === 'function') { } else if (typeof window.showFlash === 'function') {
window.showFlash(err.message, 'error'); window.showFlash(err.repost ? err.message + ` (<a href="/${err.repost}" style="color:#1fb2b0;text-decoration:underline;">view existing</a>)` : err.message, 'error');
} }
} }
} }

View File

@@ -625,7 +625,9 @@ export default router => {
const repostSum = await queue.checkrepostsum(checksum); const repostSum = await queue.checkrepostsum(checksum);
if (repostSum) { if (repostSum) {
await fs.unlink(source).catch(() => {}); await fs.unlink(source).catch(() => {});
await db`INSERT INTO notifications (user_id, type, reference_id, item_id, data) VALUES (${session.id}, 'upload_error', 0, ${repostSum}, ${db.json({ jobId, url, msg: 'Duplicate detected (Checksum)' })})`; setProgress(jobId, { stage: 'error', done: true, error: 'This file already exists', itemId: repostSum });
cleanupJob(jobId);
await db`INSERT INTO notifications (user_id, type, reference_id, item_id, data) VALUES (${session.id}, 'upload_error', 0, ${repostSum}, ${db.json({ jobId, url, msg: 'This file already exists' })})`;
return; return;
} }
} }
@@ -637,7 +639,9 @@ export default router => {
const phashMatch = await queue.checkrepostphash(phash); const phashMatch = await queue.checkrepostphash(phash);
if (phashMatch) { if (phashMatch) {
await fs.unlink(source).catch(() => {}); await fs.unlink(source).catch(() => {});
await db`INSERT INTO notifications (user_id, type, reference_id, item_id, data) VALUES (${session.id}, 'upload_error', 0, ${phashMatch}, ${db.json({ jobId, url, msg: 'Visual duplicate detected (PHash)' })})`; setProgress(jobId, { stage: 'error', done: true, error: 'This file is a visual duplicate', itemId: phashMatch });
cleanupJob(jobId);
await db`INSERT INTO notifications (user_id, type, reference_id, item_id, data) VALUES (${session.id}, 'upload_error', 0, ${phashMatch}, ${db.json({ jobId, url, msg: 'This file is a visual duplicate' })})`;
return; return;
} }
} }