Files
Tdarr-plugin/README.md
T
2026-09-19 12:34:04 +02:00

283 lines
9.6 KiB
Markdown

# Tdarr Local Flow Plugin Suite
A collection of [Tdarr](https://tdarr.io/) Flow plugins for automated media transcoding with **x265 2-pass encoding**, **audio track selection**, **subtitle extraction** and **OCR fallback**.
> **Server**: Docker (Linux) **Workers**: Windows (mapped drives)
---
## ⚡ Quick Install via curl
### Full Suite (all 7 plugins)
```bash
# Replace vX.Y.Z with the desired release tag, or use "latest"
VERSION=latest
PLUGIN_DIR=/path/to/tdarr/plugins/FlowPlugins
curl -L https://git.cdtech.freeddns.org/PickleRick/Tdarr-plugin/releases/download/${VERSION}/Tdarr-plugins-${VERSION}.zip \
-o tdarr-plugins.zip
unzip -o tdarr-plugins.zip -d "${PLUGIN_DIR}"
rm tdarr-plugins.zip
```
After extracting, restart the Tdarr server so it picks up the new plugins:
```bash
docker restart tdarr-server
```
### Individual Plugin
Each plugin is also released as its own ZIP (e.g. `transcode2PassX265-latest.zip`):
```bash
PLUGIN=transcode2PassX265
VERSION=latest
DEST=/path/to/tdarr/plugins/FlowPlugins/LocalFlowPlugins/video/${PLUGIN}/1.0.0
mkdir -p "${DEST}"
curl -L https://git.cdtech.freeddns.org/PickleRick/Tdarr-plugin/releases/download/${VERSION}/${PLUGIN}-${VERSION}.zip \
-o ${PLUGIN}.zip
unzip -o ${PLUGIN}.zip -d "${DEST}"
rm ${PLUGIN}.zip
```
Available plugin names: `mediaAnalyzerGOP`, `setAnimationFlag`, `extractChaptersXml`,
`audioSelectorClamping`, `backupSourceAudio`, `extractSubtitlesAndOcr`, `transcode2PassX265`
---
## 📁 Directory Layout
```
LocalFlowPlugins/
├── utility/
│ ├── mediaAnalyzerGOP/1.0.0/index.js
│ ├── setAnimationFlag/1.0.0/index.js
│ └── extractChaptersXml/1.0.0/index.js
├── audio/
│ ├── audioSelectorClamping/1.0.0/index.js
│ └── backupSourceAudio/1.0.0/index.js
├── subtitles/
│ └── extractSubtitlesAndOcr/1.0.0/index.js
└── video/
└── transcode2PassX265/1.0.0/index.js
```
---
## 🔌 Plugin Reference
### 1. `mediaAnalyzerGOP` — Media Analyzer & GOP Calculator
**Category**: `utility` · **Step**: 1st in flow
Reads video stream metadata and populates `args.variables` for all downstream plugins.
| Input | Default | Description |
|---|---|---|
| `moviePathPatterns` | `/Radarr` | Pipe-separated path fragments that identify a Film library (e.g. `/Radarr\|/films`) |
| `animeSeries` | _(empty)_ | Pipe-separated anime series names to auto-detect (e.g. `Naruto\|One Piece`) |
| `filmBitrate` | `3000` | Target kbps for live-action films |
| `seriesBitrate` | `3000` | Target kbps for TV series |
| `animeBitrateHd` | `2000` | Target kbps for anime ≥720p |
| `animeBitrateSd` | `1000` | Target kbps for anime <720p |
**Outputs**: `1` → continue
**Variables set**: `gopKeyint`, `gopMinKeyint`, `isAnimation`, `isMovie`, `vBitrate`, `vMaxRate`, `vBufSize`, `x265Tune`, `videoHeight`, `videoFps`
---
### 2. `setAnimationFlag` — Set Animation Flag
**Category**: `utility` · **Step**: optional, after `mediaAnalyzerGOP`
Manually forces `isAnimation=true` and `x265Tune=animation` when a file was not auto-detected as anime. Optionally recalculates bitrate targets.
| Input | Default | Description |
|---|---|---|
| `animeBitrateHd` | `2000` | Bitrate (kbps) for anime ≥720p |
| `animeBitrateSd` | `1000` | Bitrate (kbps) for anime <720p |
**Outputs**: `1` → continue
---
### 3. `extractChaptersXml` — Extract Chapters to XML
**Category**: `utility` · **Step**: before transcode
Runs `mkvextract` to dump chapter markers to an XML file in `workDir`. Stores the path in `variables.chaptersXmlPath` for downstream use. Safe to run even when the source has no chapters (mkvextract exit 1 is treated as "no chapters").
**No inputs required.**
**Outputs**: `1` → continue
> **Requires**: MKVToolNix (`mkvextract`) — automatically located from the `mkvpropeditPath` node setting.
---
### 4. `audioSelectorClamping` — Audio Selector & Opus Bitrate Clamping
**Category**: `audio` · **Step**: after `mediaAnalyzerGOP`
Selects the best ITA and ENG audio tracks by codec+bitrate scoring, then calculates clamped Opus target bitrates. No upcoding — output bitrate never exceeds source.
**Codec scoring** (higher = better): TrueHD 100 · DTS-HD MA 95 · FLAC 90 · EAC3 75 · DTS 60 · AC3 45 · AAC 35 · Opus 30
| Input | Default | Description |
|---|---|---|
| `filmMultiChannelBitrate` | `640` | Max kbps for 5.1+ film audio |
| `seriesMultiChannelThreshold` | `384` | kbps threshold: ≥threshold → 384k, else → 256k |
| `stereoBitrateMax` | `128` | Max kbps for stereo tracks |
**Outputs**: `1` → ITA or ENG track found · `2` → no target tracks found
**Variables set**: `audioHasIta`, `audioItaStreamIndex`, `audioItaOpusBitrate`, `audioItaChannels`, `audioItaCodecName`, `audioHasEng`, `audioEngStreamIndex`, `audioEngOpusBitrate`, `audioEngCodecName`
---
### 5. `backupSourceAudio` — Backup Source Audio (DTS / TrueHD ITA)
**Category**: `audio` · **Step**: after `audioSelectorClamping`
Extracts the ITA audio track as a lossless bitstream copy (`-c:a copy`) **only when** the codec is DTS or TrueHD. Output is saved next to the source file. Silently skips if no backup is needed.
**No inputs required.**
**Outputs**: `1` → continue
**Variables set**: `audioBackupPath` (path of the extracted file, if created)
---
### 6. `extractSubtitlesAndOcr` — Extract Subtitles & OCR Fallback
**Category**: `subtitles` · **Step**: after `audioSelectorClamping`
Extracts ITA and ENG subtitle streams to SRT files **next to the source file**.
- **Text-based** codecs (`subrip`, `srt`, `ass`, `ssa`, `webvtt`, `mov_text`): direct FFmpeg extraction
- **Bitmap-based** codecs (`hdmv_pgs_subtitle`, `dvd_subtitle`, `pgssub`, `dvbsub`): FFmpeg `.sup` extract → SubtitleEdit CLI OCR → `.srt`
OCR failures are logged as **warnings** without stopping the pipeline.
**Output naming**: `<basename>.<lang>[.forced][.default][.sdh].srt`
| Input | Default | Description |
|---|---|---|
| `subtitleEditPath` | `SubtitleEdit` | Name or full path of SubtitleEdit CLI. Must be in PATH or provide absolute path. |
| `languages` | `ita,eng` | Comma-separated ISO 639-2 language codes to extract |
**Outputs**: `1` → continue (warnings in log if OCR failed)
> **Requires**: SubtitleEdit CLI for PGS/VOBSUB OCR (Windows workers only).
---
### 7. `transcode2PassX265` — 2-Pass x265 Transcode
**Category**: `video` · **Step**: last
Performs 2-pass libx265 encoding using VBV parameters from `args.variables`.
- **Video**: bound-1080p Lanczos scaling (no letterbox, even dimensions)
- **Audio**: Opus re-encode with per-track indexed bitrate (ITA default, ENG secondary)
- **Subtitles**: stripped (`-sn`)
- **Chapters**: preserved (`-map_chapters 0`)
- **2-pass logs**: automatically cleaned up after encode
| Input | Default | Description |
|---|---|---|
| `x265Preset` | `slow` | x265 preset (`ultrafast` … `veryslow`). Slower = better quality. |
| `outputContainer` | `mkv` | Output file extension |
**Outputs**: `1` → transcode complete
**Reads from variables**: `gopKeyint`, `gopMinKeyint`, `vBitrate`, `vMaxRate`, `vBufSize`, `x265Tune`, `audioHasIta`, `audioItaStreamIndex`, `audioItaOpusBitrate`, `audioHasEng`, `audioEngStreamIndex`, `audioEngOpusBitrate`
---
## 🔗 Flow Variable Map
```
mediaAnalyzerGOP ──► gopKeyint, gopMinKeyint, vBitrate, vMaxRate, vBufSize
──► isAnimation, isMovie, x265Tune, videoHeight, videoFps
│
(optional) setAnimationFlag ──► overrides vBitrate, vMaxRate, vBufSize, x265Tune
│
audioSelectorClamping ──► audioHasIta, audioItaStreamIndex, audioItaOpusBitrate, audioItaCodecName
──► audioHasEng, audioEngStreamIndex, audioEngOpusBitrate
│
backupSourceAudio ──► audioBackupPath
│
transcode2PassX265 ◄── all of the above
```
---
## 🛠 Requirements
### Tdarr Server (Docker/Linux)
- Tdarr ≥ 2.11.01
- Plugins folder mounted at the path configured in Tdarr settings
### Tdarr Worker (Windows)
| Tool | Purpose | Download |
|---|---|---|
| FFmpeg (with libopus) | Video/audio/subtitle processing | https://ffmpeg.org/download.html |
| MKVToolNix | Chapter extraction (`mkvextract`) | https://mkvtoolnix.download/ |
| SubtitleEdit CLI | PGS/VOBSUB OCR to SRT | https://www.nikse.dk/subtitleedit |
Add to Windows system PATH: `ffmpeg\bin`, `MKVToolNix`, `SubtitleEdit`
Configure in Tdarr node settings:
- **FFmpeg Path**: `C:\Tools\ffmpeg\bin\ffmpeg.exe`
- **FFprobe Path**: `C:\Tools\ffmpeg\bin\ffprobe.exe`
- **MKVPropedit Path**: `C:\Program Files\MKVToolNix\mkvpropedit.exe`
---
## 🧪 Local Testing
```bash
# Prerequisites: Node.js, FFmpeg in PATH
cd /path/to/Tdarr-plugin
# 1. Generate sample test files (requires FFmpeg)
node tests/generate-test-files.js
# 2. Run logic tests (no real encode)
node tests/quick-logic-test.js
# 3. Run full integration tests
node tests/run-tests.js
# 4. Run integration tests skipping real x265 encode
node tests/run-tests.js --skip-transcode
```
---
## 📦 Release & Update
Releases are created automatically via GitHub Actions on every push to `main` or on git tag `v*`.
To trigger a manual release from the Actions tab, use **"Run workflow"** and specify the version (e.g. `v1.0.1`).
To update plugins on the server to the latest release:
```bash
VERSION=latest
PLUGIN_DIR=/path/to/tdarr/plugins/FlowPlugins
curl -L https://git.cdtech.freeddns.org/PickleRick/Tdarr-plugin/releases/download/${VERSION}/Tdarr-plugins-${VERSION}.zip \
-o tdarr-plugins.zip
unzip -o tdarr-plugins.zip -d "${PLUGIN_DIR}"
rm tdarr-plugins.zip
docker restart tdarr-server
```