Files
pretranscode/README.md
T

115 lines
3.9 KiB
Markdown

# 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, 8-bit `yuv420p`, CRF 18, capped at 15 Mbps.
Resolution and frame rate are preserved. Existing audio, subtitles, chapters,
and Matroska attachments are copied. Ten-bit SDR is converted with
error-diffusion dithering; sources carrying explicit HDR10 or HLG transfer
metadata are tone-mapped to BT.709 SDR.
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. Encoding settings form part of
each cache manifest, so a global quality-policy change automatically invalidates
and replaces older renditions without touching originals.
## Cache resizing
`CACHE_MAX_BYTES` is the worker's configurable LRU limit. After changing it and
restarting the container:
- A smaller value evicts the oldest unlocked entries until usage fits.
- A larger value immediately makes the additional capacity available for
background population, up to the size of the mounted cache filesystem.
The host filesystem is deliberately separate from application logic. Enlarge or
shrink its preallocated image during infrastructure maintenance, then set the
matching `CACHE_MAX_BYTES` value in Coolify.
## 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.