Automatically synchronize subtitles with video audio using ffsubsync.
Adds a "Sync Subtitles" option to the video detail page's More dropdown menu in Jellyfin.
- Select a subtitle track from any video in your library
- The plugin runs ffsubsync to analyze the video's audio track and align the subtitle timings
- The original subtitle is safely replaced with the synced version (with automatic rollback on failure)
- External subtitle support — syncs
.srtsidecar files, replaces in-place with backup - Embedded subtitle support — extracts embedded subtitles, syncs, and remuxes into the video container (original streams preserved)
- Real-time progress — live progress bar with phase labels, elapsed timer, and animated spinner
- Safe file handling — atomic file replacement with backup and automatic rollback on failure
- Managed ffsubsync — installs ffsubsync into an isolated Python virtualenv (no system-wide pip needed)
- Configurable — VAD method, offset limits, encoding, ffmpeg path, golden-section search
- Jellyfin 10.11+
- Python 3 (for the managed ffsubsync virtualenv)
- ffmpeg (usually bundled with Jellyfin)
- Download
Jellyfin.Plugin.SubSync.dllandmeta.jsonfrom the latest release - Create a directory at
/var/lib/jellyfin/plugins/SubSync_1.0.0.0/ - Copy both files into that directory
- Restart Jellyfin (
sudo systemctl restart jellyfin)
git clone https://github.com/YOUR_USERNAME/jellysubsync.git
cd jellysubsync
dotnet build -c ReleaseThe built DLL is at Jellyfin.Plugin.SubSync/bin/Release/net9.0/Jellyfin.Plugin.SubSync.dll.
After installing:
- Go to Dashboard → Plugins → SubSync
- Click "Install/Update ffsubsync" — this creates a Python virtualenv and installs ffsubsync automatically
- Navigate to any video with subtitles, click More → Sync Subtitles
- Open any video details page in Jellyfin
- Click the "More" (⋯) button
- Select "Sync Subtitles"
- Choose a subtitle track from the list
- Click Sync and watch the real-time progress
The sync process has these phases:
- Analyzing speech — ffsubsync decodes the audio and runs voice activity detection
- Computing alignment — finds the optimal timing offset between speech and subtitles
- Replacing subtitle / Remuxing video — safely writes the synced subtitle
- Verifying — confirms the output file is valid
A typical movie takes 60–90 seconds to sync.
| Option | Default | Description |
|---|---|---|
| FfSubSync Path | (managed) | Path to ffsubsync binary. Leave default to use the managed virtualenv. |
| FFmpeg Path | (system) | Path to ffmpeg. Leave empty to use system PATH. |
| VAD Method | subs_then_webrtc |
Voice activity detection: subs (fast), webrtc (accurate), subs_then_webrtc (adaptive) |
| Max Offset Seconds | 60 |
Maximum allowed subtitle offset in seconds |
| Max Subtitle Seconds | 10 |
Maximum on-screen duration for a subtitle |
| Output Encoding | utf-8 |
Character encoding for synced subtitles |
| Golden Section Search | false |
Use golden-section search for framerate ratio optimization |
| Overwrite Existing | true |
Allow re-syncing subtitles that have already been synced |
Plugin.cs — Entry point, DI registration, index.html script injection
├── Services/
│ └── SubSyncService.cs — ffsubsync runner, job tracker, venv installer, file operations
├── Api/
│ └── SubSyncController.cs — REST API endpoints
├── Configuration/
│ └── PluginConfiguration.cs — Settings model
└── Web/
├── subsync.js — Client-side script (injected into Jellyfin pages)
└── configPage.html — Dashboard configuration UI
- Subtitle replacements are atomic: backup → copy → verify → cleanup
- If anything fails after the backup is created, the original file is automatically restored
- If the rollback itself fails, the backup file (
.bak.subsync) is preserved for manual recovery - Embedded subtitle remuxing preserves all original streams (video, audio, existing subtitles)
dotnet build -c ReleaseThe output DLL is self-contained and references Jellyfin assemblies at runtime.
GPL-2.0-only — see LICENSE.