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:
1 parent
ea3cf1dcd4
commit
aa75fe612b
1 file changed
+36
-3
@@ -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"));
|
||||
|
||||
Reference in new issue
Block a user