129 lines
2.9 KiB
JavaScript
129 lines
2.9 KiB
JavaScript
const fs = require("fs");
|
|
|
|
function readByBuffer(buffer) {
|
|
if (!Buffer.isBuffer(buffer) || buffer.length < 4) {
|
|
return { contentType: "application/octet-stream", extension: "" };
|
|
}
|
|
buffer = buffer.slice(0, 16);
|
|
|
|
// ---------- IMAGES ----------
|
|
|
|
// PNG
|
|
if (
|
|
buffer.length >= 8 &&
|
|
buffer[0] === 0x89 &&
|
|
buffer[1] === 0x50 &&
|
|
buffer[2] === 0x4e &&
|
|
buffer[3] === 0x47
|
|
) {
|
|
return { contentType: "image/png", extension: "png" };
|
|
}
|
|
|
|
// JPEG
|
|
if (buffer[0] === 0xff && buffer[1] === 0xd8) {
|
|
return { contentType: "image/jpeg", extension: "jpg" };
|
|
}
|
|
|
|
// GIF
|
|
if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46) {
|
|
return { contentType: "image/gif", extension: "gif" };
|
|
}
|
|
|
|
// WEBP
|
|
if (
|
|
buffer.length >= 12 &&
|
|
buffer[0] === 0x52 && // R
|
|
buffer[1] === 0x49 && // I
|
|
buffer[2] === 0x46 && // F
|
|
buffer[3] === 0x46 && // F
|
|
buffer[8] === 0x57 && // W
|
|
buffer[9] === 0x45 && // E
|
|
buffer[10] === 0x42 && // B
|
|
buffer[11] === 0x50 // P
|
|
) {
|
|
return { contentType: "image/webp", extension: "webp" };
|
|
}
|
|
|
|
// ---------- VIDEO / AUDIO ----------
|
|
|
|
// MP4 / M4V / MOV (ISO BMFF)
|
|
if (buffer.length >= 12 && buffer.slice(4, 8).toString() === "ftyp") {
|
|
const brand = buffer.slice(8, 12).toString();
|
|
|
|
if (["isom", "mp41", "mp42"].includes(brand)) {
|
|
return { contentType: "video/mp4", extension: "mp4" };
|
|
}
|
|
|
|
if (["M4V ", "M4VH"].includes(brand)) {
|
|
return { contentType: "video/x-m4v", extension: "m4v" };
|
|
}
|
|
|
|
if (brand === "qt ") {
|
|
return { contentType: "video/quicktime", extension: "mov" };
|
|
}
|
|
}
|
|
|
|
// MP3
|
|
if (
|
|
buffer.slice(0, 3).toString() === "ID3" ||
|
|
(buffer[0] === 0xff && (buffer[1] & 0xe0) === 0xe0)
|
|
) {
|
|
return { contentType: "audio/mpeg", extension: "mp3" };
|
|
}
|
|
|
|
// WAV
|
|
if (
|
|
buffer.slice(0, 4).toString() === "RIFF" &&
|
|
buffer.slice(8, 12).toString() === "WAVE"
|
|
) {
|
|
return { contentType: "audio/wav", extension: "wav" };
|
|
}
|
|
|
|
// OGG
|
|
if (buffer.slice(0, 4).toString() === "OggS") {
|
|
return { contentType: "audio/ogg", extension: "ogg" };
|
|
}
|
|
|
|
// ---------- DOCUMENTS ----------
|
|
|
|
// PDF
|
|
if (buffer.slice(0, 4).toString() === "%PDF") {
|
|
return { contentType: "application/pdf", extension: "pdf" };
|
|
}
|
|
|
|
// ZIP (docx, xlsx, apk, etc.)
|
|
if (buffer[0] === 0x50 && buffer[1] === 0x4b) {
|
|
return { contentType: "application/zip", extension: "zip" };
|
|
}
|
|
|
|
// ---------- TEXT ----------
|
|
|
|
// UTF-8 text (heuristic)
|
|
const text = buffer.toString("utf8");
|
|
if (/^[\x09\x0A\x0D\x20-\x7E]*$/.test(text)) {
|
|
return { contentType: "text/plain", extension: "txt" };
|
|
}
|
|
|
|
// ---------- FALLBACK ----------
|
|
return {
|
|
contentType: "application/octet-stream",
|
|
extension: "",
|
|
};
|
|
}
|
|
|
|
function readByPath(pathToFile) {
|
|
const size = 16;
|
|
const fd = fs.openSync(pathToFile, "r");
|
|
try {
|
|
const buffer = Buffer.alloc(size);
|
|
fs.readSync(fd, buffer, 0, size, 0);
|
|
return readByBuffer(buffer);
|
|
} catch (err) {
|
|
console.error(err);
|
|
} finally {
|
|
fs.closeSync(fd);
|
|
}
|
|
}
|
|
|
|
module.exports = { byPath: readByPath, byBuffer: readByBuffer };
|