Tdarr Local Flow Plugin Suite

A collection of Tdarr 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 / Update via curl

The repo includes an install.sh script that downloads only the index.js files you need directly from Gitea raw URLs.

Update all plugins at once:

curl -fsSL https://git.cdtech.freeddns.org/PickleRick/Tdarr-plugin/raw/branch/main/install.sh \
  | bash -s -- /your/tdarr/plugins/FlowPlugins

Update a single plugin (e.g. after a bug fix):

curl -fsSL https://git.cdtech.freeddns.org/PickleRick/Tdarr-plugin/raw/branch/main/install.sh \
  | bash -s -- /your/tdarr/plugins/FlowPlugins transcode2PassX265

Update two specific plugins:

curl -fsSL https://git.cdtech.freeddns.org/PickleRick/Tdarr-plugin/raw/branch/main/install.sh \
  | bash -s -- /your/tdarr/plugins/FlowPlugins transcode2PassX265 extractSubtitlesAndOcr

Then restart Tdarr:

docker restart tdarr-server

Alternative — Full ZIP (first install)

PLUGIN_DIR=/path/to/tdarr/plugins/FlowPlugins

curl -fsSL https://git.cdtech.freeddns.org/PickleRick/Tdarr-plugin/archive/main.zip \
  -o /tmp/tdarr-plugins.zip
unzip -q -o /tmp/tdarr-plugins.zip -d /tmp/tdarr-extract
cp -r /tmp/tdarr-extract/Tdarr-plugin/LocalFlowPlugins "${PLUGIN_DIR}/"
cp -r /tmp/tdarr-extract/Tdarr-plugin/FlowHelpers     "${PLUGIN_DIR}/"
rm -rf /tmp/tdarr-plugins.zip /tmp/tdarr-extract
docker restart tdarr-server

Alternative — Single raw file

BASE=https://git.cdtech.freeddns.org/PickleRick/Tdarr-plugin/raw/branch/main
PLUGIN=transcode2PassX265
CATEGORY=video
DEST=/path/to/tdarr/plugins/FlowPlugins/LocalFlowPlugins/${CATEGORY}/${PLUGIN}/1.0.0

mkdir -p "${DEST}"
curl -fsSL "${BASE}/LocalFlowPlugins/${CATEGORY}/${PLUGIN}/1.0.0/index.js" -o "${DEST}/index.js"
Plugin Category
mediaAnalyzerGOP utility
setAnimationFlag utility
extractChaptersXml utility
audioSelectorClamping audio
backupSourceAudio audio
extractSubtitlesAndOcr subtitles
transcode2PassX265 video

Tagged Releases (versioned ZIPs)

Once a release is published by the CI workflow, versioned ZIPs are also available:

VERSION=v1.0.1
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

📁 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 next to the original source file. 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: HEVC already within 1080p and strictly below 3000 kbps is copied; all other video is bound-1080p Lanczos scaled and x265-encoded (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
copyHevcBelowKbps 3000 Copy compatible HEVC video below this bitrate instead of re-encoding it. 0 disables copying.

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

# 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:

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
S
Description
No description provided
Readme
485 KiB
0 Stars 1 Watchers 0 Forks
Languages
JavaScript 96.6%
Shell 3.4%