Local Deployment
Requirements
Python versions:
Installation
Install the correct version of PyTorch by following the official instructions: https://pytorch.org/get-started/locally
Install
DuoSubsvia pip:pip install duosubs
Basic Usage
Let’s say you have two subtitle files, from the same cut and all their timestamps overlap (see Merging Modes for other subtitle file types) — in any supported format like SRT, VTT, MPL2, TTML, ASS, SSA — for example:
primary_sub.srt
secondary_sub.srt
And you want to merge them using the timestamps from primary_sub.srt.
Then, you can do it by:
— whichever suits your workflow. Both methods can be run from the command line or via Python code.
Launching Web UI
duosubs launch-webui
from duosubs import create_duosubs_gr_blocks
# Build the Web UI layout (Gradio Blocks)
webui = create_duosubs_gr_blocks()
# These commands work just like launching a regular Gradio app
webui.queue(default_concurrency_limit=None) # Allow unlimited concurrent requests
webui.launch(inbrowser=True) # Start the Web UI and open it in a browser tab
This will start a local server and display a URL (e.g., http://127.0.0.1:7860), and the Web UI will be started in a new browser tab.
Tip
You can also launch the server on a different host address (e.g. 0.0.0.0) and port (e.g 8000):
duosubs launch-webui --host 0.0.0.0 --port 8000
from duosubs import create_duosubs_gr_blocks
webui = create_duosubs_gr_blocks()
webui.queue(default_concurrency_limit=None)
webui.launch(
server_name = "0.0.0.0", # use different address
server_port = 8000, # use different port number
inbrowser=True
)
Warning
The Web UI caches files during processing, and clears files older than 4 hours every 1 hour. Cached data may remain if the server stops unexpectedly, and you may need to delete them manually.
Sometimes, older model may fail to be released after switching or closing sessions. If you run out of RAM or VRAM, simply restart the script.
Merging Subtitles Directly
duosubs merge -p primary_sub.srt -s secondary_sub.srt
from duosubs import MergeArgs, run_merge_pipeline
# Store all arguments
args = MergeArgs(
primary="primary_sub.srt",
secondary="secondary_sub.srt"
)
# Load, merge, and save subtitles.
run_merge_pipeline(args, print)
Default Options and Outputs
This tool uses LaBSE as its default Sentence Transformer model and runs on GPU or MPS (Apple) if available — otherwise it falls back to CPU.
Tip
You can experiment with different models, by choosing one from 🤗 Hugging Face or leaderboard.
For example, if the model chosen is Qwen/Qwen3-Embedding-0.6B, you can run the followings instead:
duosubs merge -p primary_sub.srt -s secondary_sub.srt --model Qwen/Qwen3-Embedding-0.6B
from duosubs import MergeArgs, run_merge_pipeline
# Store all arguments
args = MergeArgs(
primary="primary_sub.srt",
secondary="secondary_sub.srt",
model="Qwen/Qwen3-Embedding-0.6B"
)
# Load, merge, and save subtitles.
run_merge_pipeline(args, print)
Configurations → Model & Device → Sentence Transformer Model, replace sentence-transformers/LaBSE with Qwen/Qwen3-Embedding-0.6B.Warning
Some models may require significant RAM or GPU (VRAM) to run and might not be compatible with all devices — especially larger models.
Please ensure the selected model supports your desired language for reliable results.
After merging, you’ll get primary_sub.zip in the Output Zip section (Web UI) or in the same directory as primary_sub.srt (CLI/Python), with the following structure:
primary_sub.zip
├── primary_sub_combined.ass # Merged subtitles
├── primary_sub_primary.ass # Original primary subtitles
└── primary_sub_secondary.ass # Time-shifted secondary subtitles
All these subtitles are saved in .ass format by default.
In the merged file (primary_sub_combined.ass), the displayed subtitles will have primary subtitles placed above the secondary subtitles, and line breaks are removed for cleaner formatting.
You can customize all these options in the configurations section of the Web UI, CLI or Python API.
Merging Modes
This tool supports three merging modes:
Mode |
Same cut |
Timestamps overlap |
|---|---|---|
|
✓ |
✓ (all timestamps) |
|
✓ |
✗ (some or all may not overlap) |
|
✗ (primary being longer version) |
✗ |
Here are some of the simple guidelines to choose the appropriate mode:
If both subtitle files are timestamp-synced, use
syncedfor the cleanest result.If timestamps drift or only partially overlap, use
mixed.If subtitles come from different editions of the video, with primary subtitles being the extended or longer version, use
cuts.
Tip
For mixed and cuts modes, try to use subtitle files without scene annotations
if possible, as they may reduce alignment quality.
To merge with a specific mode (e.g. cuts), run:
duosubs merge -p primary_sub.srt -s secondary_sub.srt --mode cuts
from duosubs import MergeArgs, MergingMode, run_merge_pipeline
# Store all arguments
args = MergeArgs(
primary="primary_sub.srt",
secondary="secondary_sub.srt",
merging_mode=MergingMode.CUTS # Modes available: MergingMode.SYNCED, MergingMode.MIXED, MergingMode.CUTS
)
# Load, merge, and save subtitles.
run_merge_pipeline(args, print)
Configurations → Alignment Behavior → Merging Mode, choose Cuts.