// Client-side media processing — pure helpers over Files and canvases, no // network and no keys. Images are downscaled + re-encoded before upload // (which also strips EXIF/GPS) and get a BlurHash placeholder; videos give up // a poster frame, dimensions, and duration. Everything here returns bytes for // the caller to encrypt — the server only ever sees ciphertext. import { encodeBlurhash } from "/static/blurhash.js"; const MAX_IMAGE_DIM = 2048; // long-edge cap; bigger images are downscaled in-browser // Pull a poster frame (JPEG), native dimensions, and duration out of a video // File entirely client-side — the server only ever holds ciphertext, so it can't // make a thumbnail. We draw the first decodable frame to a canvas and re-encode // it small (which also strips any metadata). Resolves with a null posterBytes on // failure (a codec the browser can't decode, a draw that throws) — the clip still // uploads and plays wherever the format is supported. Never rejects. export function videoMeta(file, maxPosterDim = 640) { return new Promise((resolve) => { const url = URL.createObjectURL(file); const v = document.createElement("video"); v.muted = true; v.playsInline = true; v.preload = "auto"; // Safari won't decode/paint frames from a *detached*