- write thumbnails to a .part file and os.replace() them, so concurrent
requests never read a half-written JPEG
- a stale thumbnail plus a vanished source no longer raises through the
request (getmtime on a missing file returned 500); it falls back cleanly
- ensure_thumbnail(item) warms the preview when a file is indexed, keeping
image decoding out of the request path