Command line tool that turns a video or audio file into a translated .srt file, and
optionally into a dubbed video with a synthesised translated audio track.
Installation
Published on PyPI as movie-subtitles.
# Run without installing (recommended)
uvx movie-subtitles --input clip.mp4
# Install as a tool
uv tool install movie-subtitles
# Or with pip
pip install movie-subtitles
# Latest from git instead of the release on PyPI
uvx --from git+https://github.com/mathiasesn/movie-subtitles.git movie-subtitles --input clip.mp4
# Develop locally
git clone https://github.com/mathiasesn/movie-subtitles.git
cd movie-subtitles && uv sync && uv run movie-subtitles --help
Requires Python >= 3.10 and uv.
ffmpeg must be on PATH for --dub; the plain .srt path and --managed do not need it.
Engines
The pipeline has three stages, each backed by a vendor you choose independently:
| Flag | Values |
|---|---|
--asr-engine |
local (faster-whisper large-v3), elevenlabs (Scribe), openai (whisper-1) |
--translation-engine |
local (MADLAD400), anthropic (Claude), openai (chat completions) |
--tts-engine |
elevenlabs, openai (tts-1) |
--engine is a shorthand that sets all three at once; per-stage flags always override it.
| Invocation | ASR | Translation | TTS |
|---|---|---|---|
--engine local (default) |
faster-whisper | MADLAD400 | none |
--engine openai |
OpenAI | OpenAI | OpenAI |
--engine elevenlabs |
Scribe | error | ElevenLabs |
--engine elevenlabs --translation-engine anthropic |
Scribe | Claude | ElevenLabs |
--engine elevenlabs alone errors on purpose. ElevenLabs has no standalone
text-translation endpoint — translation exists only bundled inside the Dubbing job
(--managed) — so there is nothing honest for the shorthand to resolve the translation
stage to. Pass --translation-engine {anthropic,openai,local} explicitly.
Engine values name vendors, not pipelines. An earlier version used
--translation-engine elevenlabs; that value no longer exists, and its replacement is
--translation-engine anthropic, since the call was always Claude.
Known limitation: --asr-engine openai
whisper-1's segment timestamps degrade to uniform 1.000s spans on music-heavy or
dialogue-sparse audio (observed on a movie trailer), which corrupts both .srt cue
timings and dub slots. Prefer --asr-engine elevenlabs on such material.
API keys
--engine local needs no keys and stays fully offline after the first model download.
Everything else reads one or more of:
export ELEVENLABS_API_KEY="..." # --asr-engine/--tts-engine elevenlabs, --managed
export ANTHROPIC_API_KEY="..." # --translation-engine anthropic
export OPENAI_API_KEY="..." # any stage set to openai
Or copy .env.example to .env and fill it in — .env is gitignored and loaded on
startup, searching upward from the directory you run in. Exported variables take
precedence. A missing key exits with a one-line error naming the variable, no traceback.
Usage
# Local, offline, .srt only
movie-subtitles --input clip.mp4
# ElevenLabs ASR + Claude translation, .srt only
movie-subtitles --input clip.mp4 --engine elevenlabs --translation-engine anthropic
# ...and dubbed into clip.dubbed.mp4 (needs ffmpeg)
movie-subtitles --input clip.mp4 --engine elevenlabs --translation-engine anthropic --dub
# OpenAI end to end, .srt only / dubbed
movie-subtitles --input clip.mp4 --engine openai
movie-subtitles --input clip.mp4 --engine openai --dub
# Mixed vendors — Scribe ASR, OpenAI translation and voice
movie-subtitles --input clip.mp4 --asr-engine elevenlabs --translation-engine openai --tts-engine openai --dub
# Managed ElevenLabs Dubbing job — no local ASR/MT/TTS code runs at all
movie-subtitles --input clip.mp4 --managed
Other flags: --audio-lang, --srt-lang, --whisper-model, --mt-model. Run
movie-subtitles --help for the full list.
Dubbing notes
-
--dubreplaces the original audio track, it does not mix with it. Only the synthesised track is mapped onto the source video; the original spoken audio is dropped. -
--duband--managedare mutually exclusive.--managedreplaces the whole pipeline with a single hosted job. -
--dubfails if TTS resolves to something unusable, e.g. plain--engine local --dub, sincelocalhas no TTS backend:[ERROR][cli] --dub requires a usable TTS engine, but it resolved to 'local'. Pass --tts-engine {elevenlabs,openai} explicitly. -
--translation-engine localwith--dubis allowed but warns. MADLAD400 ignores the length budget, so timing-drift fitting degrades to TTS-rate-only.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file movie_subtitles-0.1.1.tar.gz.
File metadata
- Download URL: movie_subtitles-0.1.1.tar.gz
- Upload date:
- Size: 190.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5343daf3e7196e55fc786529d987d86a3cd0e12d78102106c7abca72b77579b
|
|
| MD5 |
153f6ae9ef77a930dc8aaa443162b77a
|
|
| BLAKE2b-256 |
4fadb4f1fadcf6e4d3463e28d177a9b05d6551983a9b9bf5fbabd4d9da6c28c8
|
Provenance
The following attestation bundles were made for movie_subtitles-0.1.1.tar.gz:
Publisher:
publish.yml on mathiasesn/movie-subtitles
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
movie_subtitles-0.1.1.tar.gz -
Subject digest:
a5343daf3e7196e55fc786529d987d86a3cd0e12d78102106c7abca72b77579b - Sigstore transparency entry: 2520688422
- Sigstore integration time:
-
Permalink:
mathiasesn/movie-subtitles@1242cb156cfa768274f14a31505be40048992181 -
Branch / Tag:
refs/tags/0.1.1 - Owner: https://github.com/mathiasesn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1242cb156cfa768274f14a31505be40048992181 -
Trigger Event:
release
-
Statement type:
File details
Details for the file movie_subtitles-0.1.1-py3-none-any.whl.
File metadata
- Download URL: movie_subtitles-0.1.1-py3-none-any.whl
- Upload date:
- Size: 25.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
13029d1bca8b359dff8d1cbaa99cf7df5b0ee98bb7ec76b757c2a4f918f8d1be
|
|
| MD5 |
2dfa5dd82f3c8365330350039013972b
|
|
| BLAKE2b-256 |
0b8ba84b4324784cf612cc86f011827458d7d837ac05993af75e3e6579b16f63
|
Provenance
The following attestation bundles were made for movie_subtitles-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on mathiasesn/movie-subtitles
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
movie_subtitles-0.1.1-py3-none-any.whl -
Subject digest:
13029d1bca8b359dff8d1cbaa99cf7df5b0ee98bb7ec76b757c2a4f918f8d1be - Sigstore transparency entry: 2520689441
- Sigstore integration time:
-
Permalink:
mathiasesn/movie-subtitles@1242cb156cfa768274f14a31505be40048992181 -
Branch / Tag:
refs/tags/0.1.1 - Owner: https://github.com/mathiasesn
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1242cb156cfa768274f14a31505be40048992181 -
Trigger Event:
release
-
Statement type: