115 lines
3.9 KiB
Markdown
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.
|