fix(stories): video picker not showing videos on story creation

The story upload input's accept attribute listed explicit image+video
MIME subtypes (image/jpeg,...,video/mp4,...). Several mobile
browsers'/OS's native 'Photos & Videos' pickers only reliably offer
both media kinds when given the broad image/*,video/* wildcard
categories - the explicit mixed list was silently narrowing the picker
to photos only, matching the user's report ('nur Zugriff auf Fotos,
Videos werden gar nicht angezeigt').

The actual accept/reject decision is unchanged (still enforced in
handleFile() against the specific ALLOWED_IMAGE_TYPES/
ALLOWED_VIDEO_TYPES lists) - this only relaxes what the OS offers in
the picker dialog.

Code-reviewed before commit (WORKFLOW.md step 6) - fixed the one
finding that became newly reachable by this fix: videos were
previously never selectable at all, so a parameterized/codec-suffixed
MIME string (e.g.  from some Android camera-roll
pickers) could never surface as a rejection; now strips codec
parameters before the ALLOWED_VIDEO_TYPES comparison. Documented two
other findings as accepted, not-fixed-here trade-offs in code comments
(iOS HEIC auto-transcode interaction, broader picker surfacing formats
that still get rejected post-selection) rather than silently ignoring
them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Sonnet 5 committed 2026-09-19 19:08:07 +02:00
1 parent ea3cf1dcd4
commit aa75fe612b
1 file changed
+36 -3
+36 -3
View File
@@ -23,7 +23,33 @@ const MAX_IMAGE_SIZE = 10 * 1024 * 1024;
const ALLOWED_VIDEO_TYPES = ["video/mp4", "video/quicktime", "video/webm"] as const;
const MAX_VIDEO_SIZE = 500 * 1024 * 1024; // same as normal video posts (VideoUploadForm.tsx)
const ACCEPT_ATTR = [...ALLOWED_IMAGE_TYPES, ...ALLOWED_VIDEO_TYPES].join(",");
// Wildcard categories, not the explicit MIME list (`image/jpeg,...,video/mp4,...`)
// — several mobile browsers'/OS's native "Photos & Videos" pickers only
// reliably offer *both* media kinds when given the broad `image/*`/`video/*`
// categories; a long explicit list mixing image and video subtypes was
// silently narrowing the picker down to photos only on at least one such
// picker (user report: "beim Story erstellen nur Zugriff auf Fotos, Videos
// werden gar nicht angezeigt"). This only relaxes what the OS *offers* in
// the picker dialog — the actual accept/reject decision still happens in
// handleFile() below against the specific
// ALLOWED_IMAGE_TYPES/ALLOWED_VIDEO_TYPES lists, unchanged. The two are
// deliberately decoupled now (this is a fixed category string, not derived
// from those lists) — a wildcard category can't meaningfully express "just
// these three video subtypes" to the OS picker, so narrowing
// ALLOWED_VIDEO_TYPES later won't narrow what the picker offers; it'll
// still be enforced right here after selection, just with an extra
// pick-then-reject round trip for a now-disallowed type — an accepted
// trade-off for actually being able to pick a video at all. Two related,
// deliberately-not-fixed-here risks (flagged in code review): (1) the OS
// picker now also surfaces formats this form never accepted (GIF, MKV,
// 3GPP, ...), each ending in the same pick-then-reject round trip; (2) iOS
// Safari's HEIC->JPEG auto-transcode for gallery photos is reportedly tied
// to the accept list being specific — `image/*` may let a raw HEIC file
// through where `image/jpeg,image/png,image/webp` didn't, and
// ALLOWED_IMAGE_TYPES doesn't list `image/heic`/`image/heif`. Neither is
// confirmed against a real device in this session; revisit if iPhone users
// report photo uploads failing here specifically.
const ACCEPT_ATTR = "image/*,video/*";
interface StoryFormProps {
onClose: () => void;
@@ -181,8 +207,15 @@ export function StoryForm({ onClose }: StoryFormProps) {
}
setErrorMessage(null);
const isVideo = (ALLOWED_VIDEO_TYPES as readonly string[]).includes(file.type);
const isImage = (ALLOWED_IMAGE_TYPES as readonly string[]).includes(file.type);
// Strip codec parameters before comparing — some Android camera-roll
// pickers report e.g. `video/mp4;codecs=hvc1` for HEVC-recorded clips,
// which never matched the bare `ALLOWED_VIDEO_TYPES` strings. This was
// unreachable while the accept attribute only offered photos (see
// ACCEPT_ATTR above); now that videos are actually selectable, a real
// mp4 could otherwise still get rejected as "invalid type" here.
const bareMimeType = file.type.split(";")[0].trim().toLowerCase();
const isVideo = (ALLOWED_VIDEO_TYPES as readonly string[]).includes(bareMimeType);
const isImage = (ALLOWED_IMAGE_TYPES as readonly string[]).includes(bareMimeType);
if (!isVideo && !isImage) {
setErrorMessage(t("invalidType"));