/** * Recognises a file type from its first bytes, independent of AdonisJS. * `nzbe` is an encrypted-NZB container seen on Usenet (LOG.md 2026-09-28 (11)): * "nzbe", 16 random bytes (salt/IV), then ciphertext. * `yencbin` is the encrypted `.bin` container of `yEncBin@Poster.com` * (LOG.md 2026-09-30 (3)): a fixed header, then data with 8 bits/byte of entropy. */ export type ContentType = /** Not sniffed: the server no longer has the file's first article (inspection records it, no retries). */ | 'missing' | 'nzbe' | 'par2' | 'rar4' | 'rar5' | '7z' | 'zip' | 'zstd' | 'gzip' | 'xz' | 'matroska' | 'mp4' | 'rclone' | 'yencbin' | 'iso' | 'udf' | 'pdf' | 'nzb' | 'jpeg' | 'png' | 'mp3' | 'flac' | 'avi' | 'wav' | 'ogg' | 'bzip2' /** Magic bytes at an offset; null matches any byte. */ const SIGNATURES: [ContentType, number, (number | null)[]][] = [ // Two header variants seen (54f399d117c49269 6e4dc4ef5b60c11d…, 54f399e917c49269 6a4e9fb05b60c31d…): // the bytes they share. ['yencbin', 0, [0x54, 0xf3, 0x99, null, 0x17, 0xc4, 0x92, 0x69, null, null, null, null, 0x5b, 0x60, null, 0x1d, 0x7f, 0x83, 0xe9, 0x2d]], ['nzbe', 0, [0x6e, 0x7a, 0x62, 0x65]], ['par2', 0, [0x50, 0x41, 0x52, 0x32, 0x00, 0x50, 0x4b, 0x54]], ['rar5', 0, [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00]], ['rar4', 0, [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00]], ['7z', 0, [0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c]], ['zip', 0, [0x50, 0x4b, 0x03, 0x04]], ['zstd', 0, [0x28, 0xb5, 0x2f, 0xfd]], ['gzip', 0, [0x1f, 0x8b]], ['xz', 0, [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00]], ['matroska', 0, [0x1a, 0x45, 0xdf, 0xa3]], ['mp4', 4, [0x66, 0x74, 0x79, 0x70]], // "ftyp" box ['rclone', 0, [0x52, 0x43, 0x4c, 0x4f, 0x4e, 0x45]], // rclone crypt ['pdf', 0, [0x25, 0x50, 0x44, 0x46, 0x2d]], ['jpeg', 0, [0xff, 0xd8, 0xff]], ['png', 0, [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]], ['mp3', 0, [0x49, 0x44, 0x33]], // "ID3" tag ['flac', 0, [0x66, 0x4c, 0x61, 0x43]], // "fLaC" ['ogg', 0, [0x4f, 0x67, 0x67, 0x53]], // "OggS" ['bzip2', 0, [0x42, 0x5a, 0x68]], // "BZh" ] export function sniffContentType(data: Buffer): ContentType | null { for (const [type, offset, bytes] of SIGNATURES) { if (data.length >= offset + bytes.length && bytes.every((b, i) => b === null || data[offset + i] === b)) return type } // Disc images, visible when the first part is big enough (sector 16 at 32 KiB): // ISO 9660 has "CD001"; UDF (DVD/Blu-ray) has BEA01 followed by NSR02/NSR03. if (data.length >= 0x8006 && data.subarray(0x8001, 0x8006).toString('latin1') === 'CD001') return 'iso' if (data.length >= 0x8806 && data.subarray(0x8001, 0x8006).toString('latin1') === 'BEA01' && /^NSR0[23]$/.test(data.subarray(0x8801, 0x8806).toString('latin1'))) return 'udf' // RIFF container: AVI or WAV by form type. if (data.length >= 12 && data.subarray(0, 4).toString('latin1') === 'RIFF') { const form = data.subarray(8, 12).toString('latin1') if (form === 'AVI ') return 'avi' if (form === 'WAVE') return 'wav' } const head = data.subarray(0, 512).toString('latin1') if (/^\s*(<\?xml[^>]*>\s*)?(])/.test(head)) return 'nzb' return null }