File preview and streaming

Last updated: May 19, 2026

File preview and streaming

Preview modal opens on file click — supports images (full-size view) and videos (streaming with seek). Backed by GET /api/v1/creative-hub/media/:fileId/thumbnail (verified apps/backend/src/routes/api/creative-hub-media.route.ts, 189 LOC). 3-tier fetch: in-memory cache → S3 cache → FFmpeg generation on-demand. HTTP Range requests supported for video seeking. No auth required on thumbnail endpoint (read-only; fileId acts as access token).

Who is this for

Anyone reviewing what they uploaded or generated. Also: anyone using the picker in ch-106.

How preview works

For images

  1. Click file in grid → preview modal opens

  2. Loads full-resolution image inline (or higher-res variant of thumbnail)

  3. Pan / zoom via mouse / touch

  4. Action buttons in modal: Download, Share, Use in Campaign, Delete

For videos

  1. Click video → preview modal opens with player

  2. Video streams progressively via HTTP Range requests (browser fetches byte ranges)

  3. Seek to any timestamp without full download

  4. Standard player controls: play / pause / mute / fullscreen

  5. Thumbnail (poster frame) shown before play

The 3-tier thumbnail cache

To make preview fast for huge libraries, thumbnails (and video poster frames) flow through 3 cache layers:

Tier

Latency

What

In-memory cache

< 10 ms

Hot recent thumbnails kept in app memory

S3 cache

50-200 ms

Persisted thumbnails for cold files

FFmpeg generation

5-30 sec

Generated on first request if cache miss

Cache miss = first preview of a file may show "Generating thumbnail..." for a few seconds.

HTTP Range request support

The thumbnail endpoint accepts HTTP Range headers. Browsers use this to:

  • Request the first byte range (video header) for player initialization

  • Request progressive byte ranges as you scrub the timeline

  • Avoid downloading the full video file

For very large videos: scrubbing is responsive after initial 1-2 second buffer.

No auth on thumbnail endpoint

The thumbnail endpoint deliberately requires no auth header:

  • fileId itself is a unguessable UUID — knowing it is implicit access

  • Lets the image / video tag fetch directly without Bearer token logic

  • Wevion's main file metadata endpoints (list / detail / delete) DO require auth — only the thumbnail render endpoint is open

This trade-off: rapid serving + simpler client code, accepted because file IDs are unguessable + the render is read-only.

Endpoint

GET /api/v1/creative-hub/media/:fileId/thumbnail (verified):

  • No auth header required

  • Supports Range header

  • Returns image/jpeg or video/mp4 (depending on file type) with proper Content-Type + Content-Length + Accept-Ranges headers

Preview modal actions

Per file type:

Action

Image

Video

Download

Share

(via ch-105)

Use in Campaign

(via picker)

Delete

Generate variant

(re-run AI)

(re-run AI)

Rotate / crop

(basic)

Quality + resolution

  • Image thumbnails: 320px / 640px variants (lower = smaller download for grid; higher = sharper for preview)

  • Image full preview: original resolution

  • Video poster: extracted from frame at t=1s by FFmpeg

  • Video stream: original encoding (MP4 H.264 typical; may not work in some browsers for exotic codecs)

For best playback compatibility: upload H.264 MP4. Other codecs may need transcode.

Common issues

  • "Loading thumbnail..." stays > 30 sec: FFmpeg failed (corrupted file, unsupported codec); re-upload or convert format

  • Video won't play: codec not supported by browser; convert to H.264 MP4

  • Image appears low-resolution in preview: hitting 640px thumbnail instead of full file; click "Download original" or check browser cache

  • Preview modal blank: file deleted on Drive but Wevion metadata still references it; refresh page; if persists, file is broken — re-upload

  • Slow scrubbing on long video: large file, slow network; expected behavior on first scrub

Related