add thumbnail generation

This commit is contained in:
2026-03-25 16:59:09 -04:00
parent 90528c4768
commit bf54b45fa1
9 changed files with 317 additions and 39 deletions

View File

@@ -5,7 +5,8 @@ A self-hosted web UI for browsing media libraries on a NAS or local filesystem.
## Features
- **Games library** — displays a grid of game cover art scanned from folders. Each game folder is expected to contain a `.zip` archive and optional artwork (`cover.*`, `widecover.*`). Clicking a game opens a detail modal with a download link for the zip.
- **Mixed media library** — a folder-navigable browser that mirrors the directory structure on disk. Videos open in an inline player (with full seek support via HTTP range requests). Images open in a lightbox. Other files are opened in a new tab.
- **Mixed media library** — a folder-navigable browser that mirrors the directory structure on disk. Image and video files display auto-generated square thumbnails. Videos open in an inline player (with full seek support via HTTP range requests). Images open in a lightbox. Other files are opened in a new tab.
- **Thumbnail generation** — lazy on-demand thumbnails for images (via `sharp`) and video frames (via `ffmpeg`). Thumbnails are cached to disk in `.thumbnails/` and regenerated automatically when the source file changes.
- **Library management UI** — add and remove libraries at `/manage` without touching any config files. Configuration persists across restarts in `libraries.json`.
- **Path-jailed file serving** — all file access is verified to stay within the configured library root before being served.
@@ -14,6 +15,7 @@ A self-hosted web UI for browsing media libraries on a NAS or local filesystem.
```
MediaLoreWeb/
├── libraries.json # Runtime library config (managed via UI, do not edit by hand)
├── .thumbnails/ # Disk cache for generated thumbnails (auto-created, gitignored)
├── data/ # Example media (not committed to production)
├── src/
│ ├── app/
@@ -26,7 +28,8 @@ MediaLoreWeb/
│ │ ├── libraries/[id]/route.ts # DELETE /api/libraries/:id
│ │ ├── games/route.ts # GET /api/games?libraryId=
│ │ ├── browse/route.ts # GET /api/browse?libraryId=&path=
│ │ ── file/route.ts # GET /api/file?libraryId=&path=
│ │ ── file/route.ts # GET /api/file?libraryId=&path=
│ │ └── thumbnail/route.ts # GET /api/thumbnail?libraryId=&path=
│ ├── components/
│ │ ├── LibraryCard.tsx
│ │ ├── NavLink.tsx
@@ -40,14 +43,21 @@ MediaLoreWeb/
│ ├── lib/
│ │ ├── libraries.ts # Config read/write, path resolution, add/remove helpers
│ │ ├── games.ts # Games library scanner
│ │ ── files.ts # Mixed library directory scanner
│ │ ── files.ts # Mixed library directory scanner
│ │ └── thumbnails.ts # Thumbnail cache + generation (sharp / ffmpeg)
│ └── types/
│ └── index.ts
```
## Developer Setup
**Requirements:** Node.js 18+
**Requirements:** Node.js 18+, `ffmpeg` and `ffprobe` (for video thumbnails)
> Video thumbnails require `ffmpeg` and `ffprobe` to be installed and available on `$PATH`. If they are missing, video tiles gracefully fall back to a generic icon — no errors are thrown.
>
> **macOS:** `brew install ffmpeg`
> **Ubuntu/Debian:** `sudo apt install ffmpeg`
> **Windows:** Download from [ffmpeg.org](https://ffmpeg.org/download.html) and add to `PATH`
```bash
# 1. Install dependencies
@@ -121,6 +131,7 @@ All API routes are server-side. File paths are never exposed in client-side stat
| `/api/games?libraryId=<id>` | GET | Scans the games library and returns structured game entries |
| `/api/browse?libraryId=<id>&path=<subpath>` | GET | Lists the contents of a directory within a mixed library |
| `/api/file?libraryId=<id>&path=<relpath>` | GET | Streams a file; supports HTTP `Range` requests for seekable video playback |
| `/api/thumbnail?libraryId=<id>&path=<relpath>` | GET | Returns a cached square thumbnail (JPEG) for an image or video file; `404` if generation fails or ffmpeg is unavailable |
## Tech Stack