From 3bbee6029fb225e6880351c5f33c106f4bfce66a Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Wed, 15 Jul 2026 18:03:06 +0200 Subject: [PATCH] repost check for upload --- public/s/js/f0ckm.js | 20 ++++++++++--- public/s/js/upload.js | 53 ++++++++++++++++++++++++++------- src/inc/routes/apiv2/upload.mjs | 8 +++-- 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/public/s/js/f0ckm.js b/public/s/js/f0ckm.js index 9af707a..1af7dd6 100644 --- a/public/s/js/f0ckm.js +++ b/public/s/js/f0ckm.js @@ -304,9 +304,13 @@ window.cancelAnimFrame = (function () { } const flash = document.createElement('div'); - flash.textContent = text; + if (typeof text === 'string' && text.includes(' { const flash = document.createElement('div'); flash.className = `flash-message flash-${type}`; - flash.textContent = message; + if (typeof message === 'string' && message.includes(' flash.remove(); + flash.onclick = (e) => { + if (e.target.tagName.toLowerCase() !== 'a') { + flash.remove(); + } + }; container.appendChild(flash); diff --git a/public/s/js/upload.js b/public/s/js/upload.js index aa958e0..64d105d 100644 --- a/public/s/js/upload.js +++ b/public/s/js/upload.js @@ -175,7 +175,11 @@ window.escapeHtmlUpload = window.escapeHtmlUpload || ((unsafe) => { const errMsg = notif.data?.msg || i18n().url_tracker_failed || 'Upload failed'; const stageEl = row.querySelector('.uut-stage'); if (stageEl) { - stageEl.textContent = errMsg; + if (notif.item_id) { + stageEl.innerHTML = `${window.escapeHtmlUpload(errMsg)} (view existing)`; + } else { + stageEl.textContent = errMsg; + } stageEl.style.color = '#ff5050'; } const spinner = row.querySelector('.uut-spinner'); @@ -250,7 +254,14 @@ window.escapeHtmlUpload = window.escapeHtmlUpload || ((unsafe) => { if (row) { const errMsg = n.data?.msg || i18n().url_tracker_failed || 'Upload failed'; 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)} (view existing)`; + } else { + stageEl.textContent = errMsg; + } + stageEl.style.color = '#ff5050'; + } const spinner = row.querySelector('.uut-spinner'); if (spinner) spinner.style.display = 'none'; const barFill = row.querySelector('.uut-bar-fill'); @@ -2425,12 +2436,18 @@ window.initUploadForm = (selector) => { } catch(e) {} } } 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) { console.error('[UPLOAD ERROR]', err); if (!isShitpost) { - statusDiv.textContent = '✕ ' + err.message; + if (err.repost) { + statusDiv.innerHTML = '✕ ' + window.escapeHtmlUpload(err.message) + ` (view existing)`; + } else { + statusDiv.textContent = '✕ ' + err.message; + } statusDiv.className = 'upload-status error'; restoreBtn(); return; @@ -2596,29 +2613,43 @@ window.initUploadForm = (selector) => { const errMsg = res.msg || 'Upload failed'; if (isShitpost) { // In shitpost mode there's no persistent statusDiv — use flash + let flashMsg = `✕ ${errMsg}`; + if (res.repost) { + flashMsg += ` (view existing)`; + } if (typeof window.flashMessage === 'function') { - window.flashMessage(`✕ ${errMsg}`, 5000, 'error'); + window.flashMessage(flashMsg, 5000, 'error'); } else if (typeof window.showFlash === 'function') { - window.showFlash(errMsg, 'error'); + window.showFlash(res.repost ? errMsg + ` (view existing)` : errMsg, 'error'); } } else { - throw new Error(errMsg); + const err = new Error(errMsg); + if (res.repost) err.repost = res.repost; + throw err; } } } catch (err) { console.error('[UPLOAD ERROR]', err); if (!isShitpost) { - statusDiv.textContent = '✕ ' + err.message; + if (err.repost) { + statusDiv.innerHTML = '✕ ' + window.escapeHtmlUpload(err.message) + ` (view existing)`; + } else { + statusDiv.textContent = '✕ ' + err.message; + } statusDiv.className = 'upload-status error'; if (progressContainer) progressContainer.style.display = 'none'; restoreBtn(); return; } else { - // Shitpost mode: show via flash toast + // Shitpost mode: show via flash toast for general exceptions + let flashMsg = `✕ ${err.message}`; + if (err.repost) { + flashMsg += ` (view existing)`; + } if (typeof window.flashMessage === 'function') { - window.flashMessage(`✕ ${err.message}`, 5000, 'error'); + window.flashMessage(flashMsg, 5000, 'error'); } else if (typeof window.showFlash === 'function') { - window.showFlash(err.message, 'error'); + window.showFlash(err.repost ? err.message + ` (view existing)` : err.message, 'error'); } } } diff --git a/src/inc/routes/apiv2/upload.mjs b/src/inc/routes/apiv2/upload.mjs index eac1d52..ab89c8e 100644 --- a/src/inc/routes/apiv2/upload.mjs +++ b/src/inc/routes/apiv2/upload.mjs @@ -625,7 +625,9 @@ export default router => { const repostSum = await queue.checkrepostsum(checksum); if (repostSum) { 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; } } @@ -637,7 +639,9 @@ export default router => { const phashMatch = await queue.checkrepostphash(phash); if (phashMatch) { 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; } }