Initial portable pretranscode service

This commit is contained in:
SpiderFish
2026-08-26 09:53:42 +10:00
commit 093315b382
11 changed files with 1077 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
# Pretranscode
A small Jellyfin compatibility cache. It converts only known-incompatible video
codecs to uniform 8-bit H.264 while preserving immutable originals.
## Design
- Originals are mounted read-only at `/source`.
- Jellyfin reads a mirror tree at `/data/library` containing symlinks.
- Each symlink points either to `/data/original` or a validated file under
`/data/cache`.
- Completed cache files replace symlinks atomically. Partial files are never
exposed.
- Cache eviction restores the original symlink before deleting cached content.
- Jellyfin integration uses only its supported HTTP API.
There is one worker process. x264 uses available CPU cores; `nice 19`, idle I/O
priority, and minimal Docker CPU shares make normal services take precedence.
## Requirements
- Linux, Docker Compose, and ext4 tools
- An existing Jellyfin server and API key
- A shared Docker network between Jellyfin and Pretranscode
- Jellyfin must have read-only access to the originals and cache
## Installation
1. Copy `.env.example` to `.env` and set all host paths and the Jellyfin API key.
2. Provision the claimed cache allocation:
```bash
sudo scripts/provision-cache.sh .env
```
3. Mount the same paths in Jellyfin while keeping its existing logical library
path:
```yaml
volumes:
- ${PRETRANSCODE_VIEW_PATH}:/data/library:ro
- ${MEDIA_LIBRARY_PATH}:/data/original:ro
- ${PRETRANSCODE_CACHE_PATH}:/data/cache:ro
```
4. Start Pretranscode:
```bash
docker compose --env-file .env up -d --build
```
For Coolify, import `compose.yaml` as a Custom Docker Compose resource and enter
the `.env.example` values through Coolify's environment-variable UI.
## Codec policy
Cached video is H.264 High Profile, Level 4.1, 8-bit `yuv420p`, CRF 20, capped
at 12 Mbps. Existing audio, subtitles, chapters, and Matroska attachments are
preserved when the container supports them.
The fixed source blacklist is:
- HEVC/H.265, including Dolby Vision
- H.264 Hi10/10-bit
- MPEG-2
- VC-1
Client error reports never modify this list.
## Playback locking
- An active movie locks that movie.
- An active episode locks its complete series.
- Encoding is cancelled and its partial deleted if the item becomes locked.
- A series remains locked for `SERIES_COOLDOWN_SECONDS` after playback.
- Recently stopped content receives queue priority.
## Failure behavior
Graceful stops delete partial output. After a crash, startup removes stale
partials and orphan files. Atomic symlinks always point to either an original or
a completed cache file. If the cache mount marker is absent, the worker refuses
to start.
## Migration
Copy or recreate these resources on the destination:
- Repository and `.env`
- State directory
- Symlink-view directory
- Cache image/mount, if retaining completed transcodes
The cache is optional and can be rebuilt. The source fingerprint in every
manifest prevents stale cache files from replacing changed originals. No
Coolify UUID, Docker volume UUID, container name, or Jellyfin database path is
stored by the application.