0310c46fdd
* fix(uploads): keep videos when thumbnail generation fails processUploadedVideo() (ffmpeg probe + thumbnail) was unguarded in both pipeline paths, while the image branch next to each already survives its thumbnail failures: - processUploadedPhotos (sync): the throw failed the whole upload — the video was lost. - processPhoto (async worker, the path real uploads take): the throw marked the row 'failed', and the guest gallery only lists 'complete' — the video became permanently invisible despite being fully uploaded. Both call sites now fall back to extractVideoMetadata() alone and keep the video without a preview; if even the probe fails, the video is kept with no metadata. Idea from the munin92 fork (2026-07-02), reimplemented for both paths + regression test. * fix(uploads): placeholder thumbnail for rescued videos (codex review of #845) A completed video with a NULL thumbnail made the gallery grid fetch the ORIGINAL video file as an <img> blob (thumbnail_url || url) — a potentially multi-GB download for a broken tile. Both fallback paths now generate the existing sharp-rendered play-button placeholder (generateVideoPlaceholder — ffmpeg-free), so rescued videos get a real tile. Test asserts the placeholder key lands in thumbnail_path.