fix(uploads): graceful fallback for browser-unplayable video (HEVC .mov)
macOS screen recordings are HEVC inside a .mov container, which Chromium, Firefox and stock Electron can't decode. The file uploaded fine and a server-side ffmpeg poster was generated, but inline <video> playback failed silently — stuck at 0:00 with no error, since AttachmentRenderer had no error handling. Root cause: the system had no concept of web-playability. Server detects, client degrades: - mediaPlayable.ts: classifyVideoPlayable(mimetype, codec) — tri-state (false = known-undecodable e.g. HEVC/ProRes, true = web codec in web container, null = unknown/optimistic). Never widens `false` beyond codecs that fail everywhere, so ffmpeg-less instances keep prior behaviour. - probeMediaMeta now captures the video codec_name; the upload finish hook stores the verdict in the new attachments.playable column (migration 0007). - Flag propagated through every serializer: space messages, DMs, WS, and federation relay (outbound + inbound) — federation-compatible. - VideoAttachment component: playable===false renders a download card (poster + "Can't play here — download" + name/duration/size) with no dead-player flash; otherwise plays inline with an onError fallback to the same card. Specs updated: uploads.md, database.md, federation.md.
This commit is contained in:
@@ -2911,6 +2911,7 @@ export async function federationRoutes(app: FastifyInstance): Promise<void> {
|
||||
width: a.width ?? undefined,
|
||||
height: a.height ?? undefined,
|
||||
duration: a.duration ?? undefined,
|
||||
playable: a.playable ?? null,
|
||||
thumbnailFilename: a.thumbnailFilename ?? undefined,
|
||||
sourceUrl: `${localOrigin}/api/uploads/${a.filename}`,
|
||||
}));
|
||||
@@ -3656,6 +3657,7 @@ async function processCreateEvent(
|
||||
width: attachment.width ?? null,
|
||||
height: attachment.height ?? null,
|
||||
duration: attachment.duration ?? null,
|
||||
playable: attachment.playable ?? null,
|
||||
thumbnailFilename: null, // Don't copy source thumbnail — it doesn't exist locally
|
||||
sourceUrl: attachment.sourceUrl,
|
||||
createdAt: now,
|
||||
@@ -3830,6 +3832,7 @@ function processUpdateEvent(
|
||||
width: a.width,
|
||||
height: a.height,
|
||||
duration: a.duration,
|
||||
playable: a.playable ?? null,
|
||||
createdAt: a.createdAt,
|
||||
}));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user