From ffdedfe29d0033af43b4f14681befc5e2e1077ba Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Mon, 4 May 2026 15:12:32 -0300 Subject: [PATCH] feat: keep MOV in video allow-list, drop only WebM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous attempt dropped both video/quicktime and video/webm citing narrow platform support. Re-investigated: - Modern .mov files (iPhone recordings, screen captures) are ISO BMFF containers — the same format MP4 uses. Social platforms decode them like MP4 even when PHP's mime_content_type() reports 'video/quicktime'. Postiz quietly accepts MOV via this same trick: their file-type lib detects the magic bytes as 'video/mp4' and renames the upload before storage. - WebM is genuinely incompatible (Matroska + VP8/VP9 stack) — X / IG / TikTok / FB / Pinterest / Bluesky / Threads all reject it. So allow MOV, keep WebM out. Rejecting MOV would force every iPhone user to transcode before uploading — real UX cost for no gain since the publishers handle it. --- app/Enums/Media/Type.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/app/Enums/Media/Type.php b/app/Enums/Media/Type.php index c916501e..935da839 100644 --- a/app/Enums/Media/Type.php +++ b/app/Enums/Media/Type.php @@ -18,20 +18,32 @@ public function label(): string } /** + * Allow-list of MIME types we accept on upload / URL fetch. + * + * Video accepts MP4 plus QuickTime/MOV. Modern .mov files (iPhone + * recordings, screen captures) are ISO BMFF containers — the same + * format MP4 uses — so social platforms decode them like MP4 even + * if PHP reports `video/quicktime`. Accepting MOV avoids forcing + * iPhone users to transcode before uploading. + * + * WebM is rejected: X / IG / TikTok / FB / Pinterest / Bluesky / + * Threads all reject the Matroska + VP8/VP9 stack. Without + * server-side transcoding, accepting WebM would just produce + * platform-specific publish failures down the line. + * * @return array */ public function allowedMimeTypes(): array { return match ($this) { self::Image => ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], - self::Video => ['video/mp4', 'video/quicktime', 'video/webm'], + self::Video => ['video/mp4', 'video/quicktime'], }; } /** - * Filename extensions that match this type. Used by callers that - * validate by name (chunked upload, URL fetch fallback) instead of - * by MIME. + * Filename extensions that match this type. Mirrors allowedMimeTypes + * for callers that validate by name instead of MIME. * * @return array */ @@ -39,7 +51,7 @@ public function extensions(): array { return match ($this) { self::Image => ['jpg', 'jpeg', 'png', 'gif', 'webp'], - self::Video => ['mp4', 'mov', 'webm'], + self::Video => ['mp4', 'mov'], }; }