2026-11-05 10:28:10 +09:00

49 lines
2.0 KiB
JavaScript

'use strict';
const path = require('path');
// Types a browser can show inline. The type is derived from the file name on the
// server, the type the client claimed at upload time is never trusted.
// Text is always served as text/plain, html is deliberately not listed.
const MEDIA = {
png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif',
webp: 'image/webp', avif: 'image/avif', bmp: 'image/bmp', svg: 'image/svg+xml',
pdf: 'application/pdf',
mp4: 'video/mp4', m4v: 'video/mp4', mov: 'video/quicktime', webm: 'video/webm', ogv: 'video/ogg',
mp3: 'audio/mpeg', wav: 'audio/wav', ogg: 'audio/ogg', m4a: 'audio/mp4', flac: 'audio/flac',
};
const TEXT = ['txt', 'md', 'log', 'json', 'xml', 'csv', 'tsv', 'yml', 'yaml', 'ini', 'conf', 'cfg',
'js', 'mjs', 'ts', 'jsx', 'tsx', 'vue', 'css', 'scss', 'less', 'sh', 'bat', 'cmd', 'ps1', 'py',
'java', 'c', 'h', 'cpp', 'hpp', 'cs', 'php', 'sql', 'lua', 'pug', 'go', 'rs', 'rb'];
const PREVIEW = { ...MEDIA };
TEXT.forEach(ext => { PREVIEW[ext] = 'text/plain; charset=utf-8'; });
function extname(name) {
return path.extname(String(name || '')).slice(1).toLowerCase();
}
/** Content-Type for inline preview or null when the file has to be downloaded. */
function previewMime(name) {
return PREVIEW[extname(name)] || null;
}
/** 'image' | 'pdf' | 'video' | 'audio' | 'text' | null */
function previewKind(name) {
const mime = previewMime(name);
if (!mime) return null;
if (mime === 'application/pdf') return 'pdf';
return mime.split('/')[0];
}
/** Detect the image type of a thumbnail by its signature. */
function sniffImage(buf) {
if (!Buffer.isBuffer(buf) || buf.length < 12) return null;
if (buf.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) return 'image/png';
if (buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff) return 'image/jpeg';
if (buf.subarray(0, 4).toString('latin1') === 'RIFF' && buf.subarray(8, 12).toString('latin1') === 'WEBP') return 'image/webp';
return null;
}
module.exports = { previewMime, previewKind, sniffImage };