add support for uploading archives

This commit is contained in:
2026-07-12 17:03:19 +02:00
parent ab1ea7b368
commit d424b24221
15 changed files with 168 additions and 45 deletions

View File

@@ -10,6 +10,15 @@ import { getManualApproval, getMinTags, getTrustedUploads, getBypassDuplicateChe
import { parseMultipart, collectBody } from "./inc/multipart.mjs";
import f0cklib from "./inc/routeinc/f0cklib.mjs";
// Derive archive MIME types from cfg.mimes — any application/* that isn't swf or pdf.
// Adding a new archive type to config.json is sufficient; no code change needed.
const ARCHIVE_MIMES = new Set(
Object.entries(cfg.mimes)
.filter(([mime, ext]) => mime.startsWith('application/') && !['swf', 'pdf'].includes(ext))
.map(([mime]) => mime)
);
const isArchiveMime = (mime) => ARCHIVE_MIMES.has(mime);
// Helper for JSON response
const sendJson = (res, data, code = 200) => {
res.writeHead(code, { 'Content-Type': 'application/json' });
@@ -264,6 +273,11 @@ export const handleUpload = async (req, res, self) => {
return sendJson(res, { success: false, msg: 'PDF uploads are currently disabled.' }, 403);
}
if (isArchiveMime(actualMime) && cfg.websrv.enable_archive === false) {
await fs.unlink(tmpPath).catch(() => { });
return sendJson(res, { success: false, msg: 'Archive uploads are currently disabled.' }, 403);
}
// Reclassify audio-only MP4 containers (e.g. .m4a files detected as video/mp4)
if (actualMime === 'video/mp4' || actualMime === 'video/quicktime') {
const origExt = file.filename.split('.').pop().toLowerCase();
@@ -308,8 +322,9 @@ export const handleUpload = async (req, res, self) => {
}
}
// PHash check
// PHash check (skip for archives — binary blobs have no perceptual similarity)
let phash = null;
if (!isArchiveMime(actualMime)) {
try {
phash = await queue.generatePHash(tmpPath);
if (phash && !getBypassDuplicateCheck()) {
@@ -326,6 +341,7 @@ export const handleUpload = async (req, res, self) => {
} catch (e) {
console.error('[UPLOAD] PHash error:', e);
}
}
// When bypass is active, symlink to the existing file if one already exists on disk.
// We write the symlink straight into cfg.paths.b so we can skip the pending flow entirely.
@@ -375,9 +391,10 @@ export const handleUpload = async (req, res, self) => {
// Suffix it so the INSERT can proceed — the file is genuinely a new item entry.
const insertChecksum = getBypassDuplicateCheck() ? `${checksum}_bypass_${Date.now()}` : checksum;
// Probe pixel dimensions for images and videos (null for audio/flash/pdf/youtube)
// Probe pixel dimensions for images and videos (null for audio/flash/pdf/archive/youtube)
let itemWidth = null;
let itemHeight = null;
if (!isArchiveMime(actualMime)) {
try {
if (actualMime.startsWith('image/')) {
// Use magick identify — handles all image formats, already present for thumbnailing
@@ -412,6 +429,7 @@ export const handleUpload = async (req, res, self) => {
} catch (dimErr) {
console.warn(`[UPLOAD] Dimension probe failed for ${actualMime} (non-fatal):`, dimErr.message);
}
}
// Insert
const originalFilename = file.filename || null;
@@ -575,6 +593,7 @@ export const handleUpload = async (req, res, self) => {
}
}
// Action if auto-approved
if (!manualApproval) {
// Bust the count cache so page totals update immediately