Offline AI subtitle generation for macOS Apple Silicon.
Transcribes video audio using faster-whisper and burns subtitles using a bundled static ffmpeg with libass.
- 🔒 Fully offline — no internet required after first model download
- 🍎 Apple Silicon native — arm64 binary, optimized for M1/M2/M3
- 🎬 Subtitle burn-in — permanent subtitles via ffmpeg + libass
- 🎨 Customizable — font, size, color, outline, position
- 📦 Self-contained — no Homebrew, no system dependencies
- macOS 12.0+ (Monterey or later)
- Apple Silicon (M1/M2/M3)
- Python 3.10+ (arm64) — from python.org
Download from https://evermeet.cx/ffmpeg/:
ffmpeg→ place atassets/bin/ffmpegffprobe→ place atassets/bin/ffprobe
chmod +x assets/bin/ffmpeg assets/bin/ffprobeVerify:
# Must be arm64
file assets/bin/ffmpeg
# Must show ONLY /usr/lib/* — NO /opt/homebrew
otool -L assets/bin/ffmpeg
# Must show 'ass' filter
assets/bin/ffmpeg -filters 2>&1 | grep assPlace TTF/OTF fonts in assets/fonts/:
cd assets/fonts
curl -fsSL -o NotoSans-Regular.ttf \
"https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSans/NotoSans-Regular.ttf"
curl -fsSL -o NotoSans-Bold.ttf \
"https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSans/NotoSans-Bold.ttf"Place assets/icons/app_icon.icns for a custom icon.
See assets/icons/README.md for creation instructions.
pip install -r requirements.txtchmod +x build_app.sh
./build_app.shOutput: dist/AutoSubtitle.app
chmod +x build_dmg.sh
./build_dmg.shOutput: dist/AutoSubtitle-1.0.0-arm64.dmg
# Build .app
pyinstaller auto_subtitle.spec --clean --noconfirm
# Create DMG
codesign --force --deep --sign - dist/AutoSubtitle.app
mkdir -p dist/dmg_staging
cp -R dist/AutoSubtitle.app dist/dmg_staging/
ln -s /Applications dist/dmg_staging/Applications
hdiutil create \
-volname "Auto Subtitle" \
-srcfolder dist/dmg_staging \
-ov -format UDZO \
dist/AutoSubtitle-1.0.0-arm64.dmg
rm -rf dist/dmg_stagingdist/AutoSubtitle.app/
└── Contents/
├── Info.plist
├── MacOS/
│ ├── AutoSubtitle ← main executable (arm64)
│ ├── bin/
│ │ ├── ffmpeg ← static arm64 ffmpeg (libass included)
│ │ └── ffprobe ← static arm64 ffprobe
│ ├── assets/
│ │ └── fonts/
│ │ ├── NotoSans-Regular.ttf
│ │ └── NotoSans-Bold.ttf
│ ├── faster_whisper/
│ │ └── assets/
│ │ └── silero_vad_v6.onnx
│ ├── PySide6/ ← Qt frameworks
│ ├── ctranslate2/ ← CTranslate2 inference engine
│ └── *.so / *.dylib ← Python extensions
├── Resources/
│ └── app_icon.icns
└── Frameworks/
| Check | Command | Expected |
|---|---|---|
| No Homebrew dylibs in ffmpeg | otool -L assets/bin/ffmpeg |
Only /usr/lib/* |
| libass support | assets/bin/ffmpeg -filters | grep ass |
ass, subtitles |
| arm64 binary | file dist/AutoSubtitle.app/Contents/MacOS/AutoSubtitle |
arm64 |
| No console window | Launch app | No terminal opens |
| Fonts bundled | ls dist/AutoSubtitle.app/Contents/MacOS/assets/fonts/ |
TTF files |
| VAD model bundled | ls dist/AutoSubtitle.app/Contents/MacOS/faster_whisper/assets/ |
silero_vad_v6.onnx |
| ffmpeg executable | ls -la dist/AutoSubtitle.app/Contents/MacOS/bin/ffmpeg |
-rwxr-xr-x |
| Settings no crash | First launch on clean machine | No crash |
| Offline operation | Disconnect network, run app | Works |
Whisper models are downloaded to ~/.cache/huggingface/hub/ on first use.
This requires internet on first run per model size.
After the model is cached, the app works fully offline.
Model sizes:
| Size | VRAM | Speed | Accuracy |
|---|---|---|---|
| tiny | ~75MB | Fastest | Lower |
| base | ~145MB | Fast | Good |
| small | ~465MB | Medium | Better |
| medium | ~1.5GB | Slow | High |
| large-v3 | ~3GB | Slowest | Best |
- Open
AutoSubtitle-1.0.0-arm64.dmg - Drag
AutoSubtitle.apptoApplications - Right-click → Open (first launch only, to bypass Gatekeeper)
- Select a video file and click Start
xattr -dr com.apple.quarantine /Applications/AutoSubtitle.appEnsure assets/bin/ffmpeg exists and is executable before building.
Verify ffmpeg has libass: assets/bin/ffmpeg -filters 2>&1 | grep ass
Check ~/Library/Logs/AutoSubtitle/app.log for details.