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.