Skip to main content

subtitle-engine

PyPI Downloads

Generate .srt subtitle files from audio or video files using WhisperX. Optionally generate a caption from the transcript with a local Ollama LLM.

Installation

Requires Python 3.12 or newer.

pip install subtitle-engine

Or install from source:

git clone https://github.com/leevipuntanen/subtitle-engine.git
cd subtitle-engine
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Usage

# Basic usage — writes <input>.srt next to the source file
subeng video.mp4

# Specify output file
subeng video.mp4 --output subtitles.srt

# Use a different model or language
subeng video.mp4 --model medium --language fi

# Force CPU / CUDA
subeng video.mp4 --device cpu

# Speaker diarization (requires a Hugging Face token)
subeng video.mp4 --diarize --hf-token $HF_TOKEN

# Generate a caption from the transcript using Ollama
subeng video.mp4 --caption --ollama-model qwen3.5:0.6b

# Generate a caption from an existing SRT file
subeng caption subtitles.srt

# Short-form subtitles (2-5 words per line, default)
subeng video.mp4 --preset shortform

# Long-form subtitles (10-14 words per line)
subeng video.mp4 --preset longform

# Burn subtitles into the video (requires ffmpeg on PATH)
subeng video.mp4 --burn

# Burn with a custom .ass style file
subeng video.mp4 --burn --style-file my-style.ass

Subtitle quality

The segmenter applies several quality passes by default. Each can be turned off or tuned via a CLI flag.

Pass Default Flag to disable Flag to tune
Hallucination cleanup (Thanks for watching, [Music], Subtitles by …) on --no-cleanup
Clause-aware line breaking (prefer splits at , . ? ! ; :) on --no-clause-boundaries
Sentence-boundary splitting (split at . ? ! when at least one of: next word capitalized, ≥ 0.2s pause after, or speaker change) on --no-sentence-split --sentence-pause-threshold 0.3
Two-line balancing (longform only — splits long lines at the midpoint clause) on (longform) --no-line-balance
Characters-per-second limit 21 cps --no-cps-limit --max-cps 17
Minimum on-screen duration 1.0 s --no-min-duration --min-duration 1.5

The sentence splitter now considers context before splitting, so a mid-thought period like I found a bug. reports say... stays in the same subtitle (no capital, no pause, no speaker change → no split). To get the old aggressive behavior back, set --sentence-pause-threshold 0.

Disable every quality pass to reproduce the legacy behavior:

subeng video.mp4 \
  --no-cleanup \
  --no-clause-boundaries \
  --no-sentence-split \
  --no-line-balance \
  --no-cps-limit \
  --no-min-duration

Burning subtitles

Pass --burn to also re-encode the input video with the generated SRT rasterized into the frames (hardsub). The result is written next to the original as <input>.subtitled.<ext>; the source file is never modified.

subeng video.mp4 --burn

Burn requires ffmpeg on your PATH. Audio is stream-copied where possible, so only the video is re-encoded. To apply custom styling, point --style-file at an .ass file; the first Style: line is converted to ffmpeg's force_style argument:

subeng video.mp4 --burn --style-file my-style.ass

If the burn step fails (missing ffmpeg, no video stream, ffmpeg error), the SRT that was already written is kept on disk and its path is shown in the error message.

Options

Option Description
--output, -o Output SRT file path
--model, -m WhisperX model: tiny, base, small (default), medium, large-v2, large-v3
--language, -l ISO language code, e.g. en, fi. Auto-detected if omitted.
--device, -d cpu or cuda. Auto-detected if omitted.
--batch-size, -b Inference batch size (default: 16)
--compute-type, -c int8 or float16. Auto-selected if omitted.
--diarize Enable speaker diarization
--hf-token Hugging Face token for diarization (or set HF_TOKEN env var)
--caption Generate a caption from the transcript via Ollama
--ollama-model Ollama model name. If omitted, installed models are listed and you can pick one.
--ollama-host Ollama API host (default: http://localhost:11434)
caption Generate a caption from an existing SRT file (e.g. subeng caption file.srt)
--preset, -p Subtitle style: shortform (2-5 words, default) or longform (10-14 words)
--no-cleanup Disable hallucination cleanup (e.g. Thanks for watching, [Music])
--no-clause-boundaries Disable clause-aware line breaking
--no-sentence-split Disable sentence-boundary splitting (so mission. Building in public stays as one subtitle)
--sentence-pause-threshold <float> Minimum pause (seconds) after a period for the gap to count as evidence of a real sentence boundary (default: 0.2). Set to 0 to rely on capital letters / speaker change only.
--no-line-balance Disable two-line balancing (enabled by default for longform)
--max-cps <float> Maximum characters per second per subtitle (default: 21). Use 0 to disable.
--no-cps-limit Disable the CPS post-processor
--min-duration <float> Minimum on-screen duration in seconds (default: 1.0). Use 0 to disable.
--no-min-duration Disable the minimum-duration post-processor
--burn Re-encode the input video with the generated SRT burned into the frames. Writes <input>.subtitled.<ext> next to the source. Requires ffmpeg on PATH.
--style-file Path to a .ass style file used when --burn is set. The first Style: line is applied via ffmpeg's force_style.

Development

Run the test suite:

pytest

License

MIT

Release files for subtitle-engine 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for subtitle-engine 0.3.0
File Size Uploaded
subtitle_engine-0.3.0.tar.gz 49.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for subtitle-engine 0.3.0
File Interpreter ABI Platform
subtitle_engine-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 81.7 kB

Release files / subtitle_engine-0.3.0.tar.gz

Download URL subtitle_engine-0.3.0.tar.gz
Size 49.2 kB
Tags Source
SHA-256 checksum
How to use checksums
1e1d634a085528bf158c84ebd90895e3f9e2f14969b547b37ecaeb39051bf2f9
BLAKE2b-256 checksum
How to use checksums
045030c42d14b1158acdd26eb51ce2577b234138541db67726256c5e3db7a7e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.11

Release files / subtitle_engine-0.3.0-py3-none-any.whl

Download URL subtitle_engine-0.3.0-py3-none-any.whl
Size 32.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2a0e6afe9d47812e2e93331187b01a3732f8ae2647c9033693794d93bf17f94d
BLAKE2b-256 checksum
How to use checksums
6698b87cdf11e12c632c12a193c6115194bf197ca294d4cb5d05f1ba26d7a009
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.11

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page