GPU-accelerated video preview thumbnail generation for Plex, Emby, and Jellyfin media servers
50K+
GPU-accelerated video preview thumbnail generation for Plex, Emby, and Jellyfin. Web UI only — no CLI.
Previously named Plex Generate Previews at
stevezzau/plex_generate_vid_previews. That image has been retired and no longer receives updates — this repo (stevezzau/media_preview_generator) is the only one published. If you're still on the old name, update yourcomposefile'simage:line tostevezzau/media_preview_generatorand re-pull — settings and volumes carry over unchanged.
The Problem: Built-in preview generation has gaps depending on which server you run:
The Solution: This tool runs preview generation off the media server on a machine of your choosing, uses every GPU it finds, and processes files in parallel. When two or more servers contain the same file, FFmpeg runs only once — the result is then written out in each server's expected format.
One FFmpeg pass, every server. Point it at Plex, Emby, Jellyfin — any mix, any number — and a single generation run writes the right output format to each (Plex BIF bundle, Emby sidecar BIF, Jellyfin trickplay tiles).
Automation that just works. Radarr / Sonarr / Tdarr / FileFlows webhooks, Plex direct (Plex Pass), Recently Added polling, cron & interval schedules — all share one universal inbound URL with vendor auto-detection. A 5-step backoff retry (30 s → 2 m → 5 m → 15 m → 60 m) handles files your server hasn't indexed yet. Source-aware dedup re-runs automatically when a file is swapped (e.g. a Sonarr/Radarr quality upgrade) and skips when nothing changed.
Hardware you already have. NVIDIA, AMD, Intel — per-GPU worker counts and FFmpeg threads, automatic in-place CPU retry if a codec fails on the GPU, and HDR / Dolby Vision tone mapping (including Profile 5 via libplacebo). A Previews Readiness panel on each server audits every flag that affects whether your previews actually show up, with one-click toggles and typed confirmation for destructive changes.
docker run -d \
--name media-preview-generator \
--restart unless-stopped \
-p 8080:8080 \
--device /dev/dri:/dev/dri \
-e PUID=1000 \
-e PGID=1000 \
-v /path/to/media:/media:ro \
-v /path/to/plex/config:/plex:rw \
-v /path/to/app/config:/config:rw \
-v /etc/localtime:/etc/localtime:ro \
stevezzau/media_preview_generator:latest
Replace /path/to/media, /path/to/plex/config, and /path/to/app/config with your actual paths.
Timezone: The
/etc/localtimemount ensures log timestamps and scheduled jobs use your local time. Alternatively, use-e TZ=America/New_York(replace with your timezone).
Then open http://YOUR_IP:8080, retrieve the authentication token from container logs, and complete the setup wizard. All settings (Plex connection, GPU config, processing options) are configured in the web UI Settings page.
| Tag | Source | Use for |
|---|---|---|
:latest | Latest GitHub release | Recommended. Stable. |
:X.Y.Z (version) | A specific release (e.g. :3.7.5) | Pinning to a known-good version |
:dev | Every push to dev | Bleeding edge — may break |
See the releases page for version history and per-release notes.
| Container Path | Purpose | Mode |
|---|---|---|
/media | Your media files | ro (read-only) |
/plex | Plex application data (where BIF files are stored) | rw |
/config | App settings, schedules, job history | rw |
services:
plex-previews:
image: stevezzau/media_preview_generator:latest
container_name: media-preview-generator
restart: unless-stopped
ports:
- "8080:8080"
# Intel / AMD GPU (VAAPI)
devices:
- /dev/dri:/dev/dri
# NVIDIA: remove 'devices' above, uncomment below
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: all
# capabilities: [gpu]
environment:
# NVIDIA only (uncomment if using NVIDIA):
# - NVIDIA_VISIBLE_DEVICES=all
# Use 'all' so the NVIDIA Vulkan driver is injected; 'graphics' is
# required for Dolby Vision Profile 5 libplacebo tone-mapping.
# - NVIDIA_DRIVER_CAPABILITIES=all
- PUID=1000
- PGID=1000
volumes:
- /path/to/your/media:/media:ro
- /path/to/plex/config:/plex:rw
- /path/to/app/config:/config:rw
- /etc/localtime:/etc/localtime:ro
Set GPU Workers to 0 and CPU Workers as needed in the web UI Settings.
services:
plex-previews:
image: stevezzau/media_preview_generator:latest
container_name: media-preview-generator
restart: unless-stopped
ports:
- "8080:8080"
environment:
- PUID=1000
- PGID=1000
volumes:
- /path/to/your/media:/media:ro
- /path/to/plex/config:/plex:rw
- /path/to/app/config:/config:rw
- /etc/localtime:/etc/localtime:ro
| GPU Type | Platform | Acceleration | Docker Flag |
|---|---|---|---|
| NVIDIA | Linux | CUDA/NVENC | --gpus all |
| AMD | Linux | VAAPI | --device /dev/dri |
| Intel | Linux | QuickSync/VAAPI | --device /dev/dri |
| NVIDIA | Windows | CUDA/NVENC | --gpus all (Docker Desktop, WSL2 backend) |
| AMD/Intel | Windows | — | Not available — CPU only |
| Apple Silicon / Intel | macOS | — | Not available — CPU only |
NVIDIA on Windows works under Docker. The NVIDIA Windows driver exposes CUDA and NVDEC into WSL2, so Docker Desktop with the WSL2 backend accelerates just like Linux — use
--gpus allas below, with no extra install inside WSL.
AMD/Intel on Windows and all GPUs on macOS cannot be accelerated under Docker. Docker Desktop runs a Linux VM, and D3D11VA and VideoToolbox are host-OS frameworks it cannot reach — those setups process on CPU. Run the container on a Linux host if you need GPU acceleration. Apple Silicon still benefits from the native ARM64 image (no Rosetta overhead).
Prerequisites (Linux hosts): NVIDIA drivers + NVIDIA Container Toolkit.
On Windows, skip the Container Toolkit — Docker Desktop provides it. You need the NVIDIA Windows driver, the WSL2 backend, and an up-to-date WSL kernel (wsl --update). Omit --device /dev/dri:/dev/dri on Windows.
docker run -d \
--gpus all \
-e NVIDIA_VISIBLE_DEVICES=all \
-e NVIDIA_DRIVER_CAPABILITIES=all \
-e PUID=1000 \
-e PGID=1000 \
-p 8080:8080 \
-v /path/to/media:/media:ro \
-v /path/to/plex/config:/plex:rw \
-v /path/to/app/config:/config:rw \
-v /etc/localtime:/etc/localtime:ro \
stevezzau/media_preview_generator:latest
CPU fallback is automatic. If a file fails on the GPU (unsupported codec, driver crash, etc.), the same worker automatically retries it on the CPU and the dashboard shows a yellow "CPU fallback" badge so you know it happened. No separate worker pool to configure — increase CPU Workers above 0 only if you have a lot of content that never decodes on the GPU and you want those files to route straight to dedicated CPU workers.
All application settings (Plex, GPU, processing) are configured in the web UI Settings page. settings.json in /config is the single source of truth. The only infrastructure env vars that remain active:
| Variable | Default | Description |
|---|---|---|
CONFIG_DIR | /config | Path to config directory |
WEB_PORT | 8080 | Web server port |
PUID | 1000 | User ID (Unraid: 99) |
PGID | 1000 | Group ID (Unraid: 100) |
TZ | Host | Timezone (e.g. America/New_York) |
CORS_ORIGINS | * | CORS allowed origins |
HTTPS | false | Enable HTTPS |
DEV_RELOAD | false | Enable dev reload |
Application-level env vars (PLEX_URL, PLEX_TOKEN, CPU_THREADS, etc.) act as one-time seed values on first startup. They are migrated into settings.json. After that, settings.json is the source of truth.
Search for "media-preview-generator" in Community Applications, or run manually:
docker run -d \
--name media-preview-generator \
--restart unless-stopped \
-p 8080:8080 \
--device /dev/dri:/dev/dri \
-e PUID=99 \
-e PGID=100 \
-v /mnt/user/data/plex:/data/plex:ro \
-v "/mnt/cache/appdata/plex/Library/Application Support/Plex Media Server":/plex:rw \
-v /mnt/user/appdata/media-preview-generator:/config:rw \
-v /etc/localtime:/etc/localtime:ro \
stevezzau/media_preview_generator:latest
Configure GPU and CPU workers per-GPU in the web UI under Settings.
init: true to your docker-compose file — this container manages its own processes internally, and init: true conflicts with that.localhost on your host. Use http://192.168.1.100:32400, not http://localhost:32400.Full documentation is available on GitHub:
MIT License. See LICENSE for details.
Content type
Image
Digest
sha256:c5697f378…
Size
607.4 MB
Last updated
22 days ago
docker pull stevezzau/media_preview_generator