-- media.lua — MIME metadata and content sniffing for uploaded files. -- -- Uploads are stored as `docs` rows in the content table (slug, title, -- mime_type, file_data) and served at /docs/:slug. Images uploaded -- from the post editor go through the same store. local M = {} M.MIME_EXT = { ["application/pdf"] = ".pdf", ["application/epub+zip"] = ".epub", ["text/plain"] = ".txt", ["application/zip"] = ".zip", ["image/png"] = ".png", ["image/jpeg"] = ".jpg", ["image/gif"] = ".gif", ["image/webp"] = ".webp", } M.MIME_LABELS = { ["application/pdf"] = "PDF Document", ["application/epub+zip"] = "EPUB e-book", ["text/plain"] = "Plain text", ["application/zip"] = "ZIP archive", ["image/png"] = "PNG image", ["image/jpeg"] = "JPEG image", ["image/gif"] = "GIF image", ["image/webp"] = "WebP image", ["application/octet-stream"] = "Other binary", } --- Detect the MIME type of a binary blob from its magic bytes. --- Returns a mime string, or nil when unrecognised. function M.sniff(data) if not data or #data < 12 then return nil end local head = data:sub(1, 12) if head:sub(1, 8) == "\137PNG\r\n\26\10" then return "image/png" end if head:sub(1, 3) == "\255\216\255" then return "image/jpeg" end if head:sub(1, 6) == "GIF87a" or head:sub(1, 6) == "GIF89a" then return "image/gif" end if head:sub(1, 4) == "RIFF" and head:sub(9, 12) == "WEBP" then return "image/webp" end if head:sub(1, 5) == "%PDF-" then return "application/pdf" end if head:sub(1, 4) == "PK\3\4" then return "application/zip" end return nil end --- True for MIME types the editor's image-upload widget accepts. function M.is_image(mime) return mime == "image/png" or mime == "image/jpeg" or mime == "image/gif" or mime == "image/webp" end return M