Auto-generate and embed subtitles for .mp4 videos — 100% local, no uploads, no API keys.
For creators who want subtitles without uploading to cloud services or paying for APIs. Everything runs on your machine — your videos never leave it.
- Toggleable subtitles — add as a track viewers can turn on/off, original quality preserved
- Always-visible subtitles — burn into video for Instagram, TikTok, GitHub
- Font customization — choose font, size, color, outline, shadow, alignment and preview before generating
- Local web UI — upload a video, pick your settings, download the result — all from the browser
- GPU accelerated — uses NVIDIA GPU if available, falls back to CPU automatically
- Prerequisites
- Quick Start
- Using the Web UI
- Example
- How it works
- Advanced Usage
- Configuration
- Docker (optional)
- Troubleshooting
- Acknowledgments
- License
- ffmpeg — free video processing tool. The launcher can install it automatically, or install it yourself:
apt install ffmpeg(Linux) /brew install ffmpeg(Mac) /winget install ffmpeg(Windows) - Python 3.10+ — download here (Windows: check "Add to PATH")
- NVIDIA GPU — optional but makes subtitle generation much faster. Works without one.
- Click the green Code button above → Download ZIP
- Extract the ZIP file
- Windows: double-click
start.batMac: double-clickstart.commandLinux: open a terminal in the extracted folder and run./start.sh
Mac users: If double-clicking
start.commandsays "cannot be opened," right-click it → Open → click Open again. This is a one-time macOS security step.
Windows 11 with Smart App Control enabled? The ZIP download may block
start.batwith a "potentially unsafe file" warning. See Troubleshooting to unblock it.
git clone https://github.com/nick8592/video-subtitler.git
cd video-subtitlerThen run the launcher:
Mac / Linux:
./start.shWindows:
start.bat
Tip: Add
--yes(or-y) to auto-accept all prompts — fully non-interactive:./start.sh --yes # Mac / Linux start.bat --yes # Windows
git clone https://github.com/nick8592/video-subtitler.git
cd video-subtitler
./setup.sh
source .venv/bin/activate
python3 server.pyAll three options will: check for required tools (ffmpeg, Python) and offer to install anything missing, set up the Python environment, download the AI model (~3 GB) on first run, and start the web UI in your browser.
Prefer a container? You can run the same app with Docker instead of installing Python locally. Container images run as Linux even on Windows/macOS, so this works on all three platforms — but note it runs CPU-only (no NVIDIA CUDA) unless you're on a Linux host with the NVIDIA Container Toolkit installed.
docker build -t video-subtitler .
docker run --rm -p 7860:7860 -v "$(pwd)/videos:/data" video-subtitlerThen open http://127.0.0.1:7860 in your browser. The container is CPU-optimized (small Whisper model, int8) — use the native install above if you need GPU-accelerated transcription.
- Open
http://127.0.0.1:7860(opens automatically withstart.sh) - Upload your video
- Choose subtitle mode: Toggleable (viewers can turn on/off) or Always visible (burned into the video)
- Click Generate Subtitles
- Download the result
Tip: The "Always visible" mode lets you customize fonts, colors, and positioning. Click "Render Frame" to preview how subtitles will look before generating the full video.
Note: The web UI processes one video at a time. For batch processing of multiple videos, use the command line.
A 10-second sample from a 4K travel video (Indonesia, Mount Bromo — cloud river) is included in example/.
sample.mp4
sample_subtitled.mp4
Note: GitHub's video player doesn't support soft subtitle tracks. The "After" example above has subtitles burned in for visibility. The actual script outputs toggleable subtitles by default — use
--hardcodeto burn them in instead.
| File | Resolution | Duration | Size | Codec |
|---|---|---|---|---|
sample.mp4 |
1920×1440 | 5.5s | 4 MB | H.264 |
sample_subtitled.mp4 |
1920×1440 | 5.5s | 4 MB | H.264 (subtitles burned in) |
1
00:00:01,200 --> 00:00:04,200
Yeah, the cloud is climbing through the hill.For each .mp4 in the target directory:
- Extract audio — 16 kHz mono WAV via ffmpeg
- Transcribe — faster-whisper AI model detects speech and generates timestamps
- Save
.srt— written next to the original video - Embed — add subtitles into a new
_subtitled.mp4(no quality loss for toggleable mode)
Idempotent — skips files that already have .srt or _subtitled.mp4. Delete those files to re-run.
For batch processing multiple videos:
⚠️ Activate the virtual environment first:source .venv/bin/activate
# Generate toggleable subtitles for all videos in a folder
python3 add_subtitles.py /path/to/videos
# Burn subtitles into video (always visible, for social media)
python3 add_subtitles.py /path/to/videos --hardcode
# Generate .srt files only (for editing in CapCut, etc.)
python3 add_subtitles.py /path/to/videos --srt
# Process a single .mp4 file
python3 add_subtitles.py /path/to/video.mp4 --file
# Override model and language
python3 add_subtitles.py /path/to/videos --model medium --language en
# Customize font styling (always-visible mode only)
python3 add_subtitles.py /path/to/videos --hardcode --font-name "Arial" --font-size 18 --font-color "#FFFF00" --outline 2All settings are configured through the web interface. The app automatically detects whether you have an NVIDIA GPU — if not, it uses CPU mode.
- Model size — bigger = more accurate but slower (default: large-v3)
- Advanced settings — device (GPU/CPU) and quality level are available under "Advanced Settings"
Font customization controls (font name, size, color, outline, shadow, border style, alignment, vertical margin) are available when Always visible mode is selected. A Render Frame button shows exactly how subtitles will look before generating the full video.
Set via environment variables or edit the constants at the top of add_subtitles.py:
| Setting | Env Variable | Default | Description |
|---|---|---|---|
| Model size | WHISPER_MODEL |
large-v3 |
tiny, base, small, medium, or large-v3 |
| Device | WHISPER_DEVICE |
auto |
cuda for GPU, cpu for CPU (auto = cuda if available, else cpu) |
| Quality | WHISPER_COMPUTE_TYPE |
auto |
float16 for GPU, int8_float16 for less memory, int8 for CPU (auto = float16 on GPU, int8 on CPU) |
| Language | — | auto |
Language code (e.g. en, zh) or auto to detect |
| Skip silence | — | True |
Ignores silent parts during transcription |
Font styling options (always-visible mode only):
| Setting | CLI Flag | Default | Description |
|---|---|---|---|
| Font name | --font-name |
Literata |
Font family name |
| Font size | --font-size |
12 |
Font size in points |
| Font color | --font-color |
#FFFFFF |
Text color (hex) |
| Outline | --outline |
0 |
Outline/border thickness |
| Shadow | --shadow |
0 |
Shadow depth in pixels |
| Border style | --border-style |
1 |
1 = outline + shadow, 3 = opaque box |
| Alignment | --alignment |
2 |
Position: 1–3 bottom, 5–7 top, 9–11 mid |
| Vertical margin | --margin-v |
20 |
Vertical margin from edge in pixels |
| Horizontal margin | --margin-h |
10 |
Horizontal margin from edge in pixels |
On Windows 11 with Smart App Control enabled, files extracted from a browser-downloaded ZIP are stamped with Mark of the Web and unsigned .bat scripts may be blocked with a "potentially unsafe file" warning. This is a Windows security feature, not a bug in the scripts.
How to unblock (choose one):
- Easiest — unblock everything in the folder. Open PowerShell in the extracted folder and run:
Then double-click
Get-ChildItem -Recurse -File | Unblock-File
start.batagain. - One file at a time: right-click
start.bat→ Properties → tick Unblock → OK. - Avoid the ZIP entirely:
git clone https://github.com/nick8592/video-subtitler.git— files cloned via git are not marked as downloaded, so nothing gets blocked.
⚠️ Don't disable Smart App Control to work around this. On Windows 11 it can only be turned back on by resetting Windows. Unblocking the files (above) is the supported path.
- faster-whisper — GPU-accelerated Whisper transcription using CTranslate2
- OpenAI Whisper — the original Whisper speech recognition model
MIT
