omni-transcriber
Transcribe anything from the command line: a YouTube link, an Instagram reel, any yt-dlp-supported URL, a local video or audio file, or a whole folder of media. Transcription runs locally via faster-whisper — no API key, no audio leaves your machine.
$ transcriber https://youtu.be/jNQXAC9IVRw
Alright, so here we are, one of the elephants...
$ transcriber lecture.mp4 -f srt -o lecture.srt
$ transcriber ~/podcasts -r -m turbo -o transcripts/
Install
Needs Python 3.10 or newer. uv is the smoothest route, but pipx and pip work too.
$ uv tool install omni-transcriber # or: pipx install omni-transcriber
$ uvx --from omni-transcriber ots --help # or run it without installing
That installs two commands for the same tool: transcriber and the shorter
ots. Use whichever you prefer.
From source:
$ git clone https://github.com/AyushShah2/omni-transcriber
$ cd omni-transcriber && uv sync && uv run transcriber --help
With NVIDIA GPU acceleration:
$ uv tool install "omni-transcriber[gpu]"
| Install | Download size | Notes |
|---|---|---|
| default (CPU) | ~450 MB | Works everywhere. Fine for short clips. |
[gpu] extra |
~2.7 GB | Adds the CUDA cuBLAS/cuDNN wheels. NVIDIA only. |
The [gpu] extra is never required. On a machine with an NVIDIA card but no
[gpu] install, --device cuda prints a warning and falls back to the CPU
rather than failing.
Optional companions
- A JavaScript runtime — YouTube increasingly needs one. Deno is
yt-dlp's preferred runtime; Node.js also works.
transcriberenables whichever it finds on yourPATHautomatically. Without one, some videos lose formats or fail outright. - ffmpeg — not used for transcription (the bundled PyAV decoder reads audio straight out of any container). yt-dlp needs it only for a few stream types; if it is missing when that happens, a static build is fetched automatically.
Usage
transcriber INPUTS... files, folders, and/or URLs — mix freely
ots INPUTS... the same command, less typing
Both names are installed and do exactly the same thing; every example below
works with either. (If you also use OpenTimestamps, which ships its own
ots command, one will shadow the other on your PATH — transcriber always
works.)
| Flag | Meaning |
|---|---|
-f, --format |
txt (default), srt, vtt, json, md |
-t, --timestamps |
Timestamps in txt/md (srt/vtt always have them) |
-m, --model |
Whisper model — see the table below (default small) |
-o, --output |
A file for one input, or a directory (-o out/) for many |
-l, --language |
Force a language (en, fr, ...); default is auto-detect |
-r, --recursive |
Recurse into subfolders |
--device |
auto (default), cpu, cuda |
--compute-type |
auto (default), int8, float16, int8_float16 |
--batch-size N |
Decoding batch size; default 8 on CUDA, sequential on CPU |
--no-vad |
Disable voice-activity filtering (keeps silence) |
--playlist / --limit N |
Expand a playlist link; cap how many entries |
--cookies-from-browser / --cookies |
Authenticate for private/login-walled media |
--keep-audio |
Keep the downloaded audio next to the transcript |
--overwrite |
Re-transcribe items that already have a transcript |
-v, --verbose |
yt-dlp and engine detail on stderr |
--engine |
Transcription backend (local; cloud backends may follow) |
--version |
Print the version and exit |
Where output goes
- One input, no
-o→ the transcript goes to stdout, so it pipes:transcriber talk.mp4 | wc -w. Progress bars and warnings all go to stderr. -o FILE→ that exact file.- Several inputs, a folder, a playlist, or
-o DIR/→ one<title>.<format>file per item.
Playlists and channels
A link that is only a playlist or a channel expands to every video in it, one transcript file each:
$ transcriber "https://www.youtube.com/playlist?list=PL..." -o transcripts/
$ transcriber "https://www.youtube.com/@someone/videos" --limit 10 -o transcripts/
A link to a single video that also carries a &list= parameter is treated as
just that one video, which is almost always what you meant. Pass --playlist
when you want the whole list:
| Link | Default | With --playlist |
|---|---|---|
youtube.com/playlist?list=PL... |
whole playlist | whole playlist |
youtube.com/@name/videos |
every video | every video |
youtube.com/watch?v=X&list=PL... |
just video X |
whole playlist |
--limit N caps how many entries are fetched — worth using before you point it
at a 200-video channel. If one entry is private, deleted, or region-locked, the
rest still run and the closing summary shows which failed.
Everything above works for any site yt-dlp supports, not just YouTube.
Existing transcripts are skipped with a notice rather than overwritten, so
re-running an interrupted batch resumes it for free. Pass --overwrite to redo
them. If two items in the same run would produce the same filename — two videos
with identical titles, or a/interview.mp4 and b/interview.mp4 — the later
ones get (2), (3) suffixes so no transcript is lost. A batch keeps going when one item fails and prints a summary at the end;
the exit code is 1 if anything failed.
Models
You never download or place a model by hand. The first time you use one it is fetched automatically and cached; every run after that reuses it. There is no models folder to manage and nothing to put anywhere.
The cache lives at ~/.cache/huggingface/hub on Linux and macOS, and at
C:\Users\<you>\.cache\huggingface\hub on Windows.
| Model | Download | Good for |
|---|---|---|
tiny |
75 MB | Quick drafts, testing |
base |
145 MB | Clear speech, low resources |
small |
484 MB | Default — the accuracy/speed sweet spot on CPU |
medium |
1.5 GB | Better accuracy, noticeably slower on CPU |
large-v3 |
3.1 GB | Best accuracy. GPU strongly recommended |
turbo |
1.6 GB | Near-large-v3 accuracy, much faster. Best GPU pick |
distil-large-v3 |
1.5 GB | Distilled, English-only, very fast |
Add .en to tiny/base/small/medium for slightly better English-only
accuracy.
Speed: on an RTX 5070 Ti, small transcribes 468 s of audio in 3.7 s;
the same job on CPU takes 122 s.
Moving the cache
Large models on a small home partition is a common squeeze. Point HF_HOME
somewhere roomier:
$ export HF_HOME=/mnt/data/huggingface # bash/zsh
> $env:HF_HOME = "D:\huggingface" # PowerShell
Pre-downloading and offline use
To fetch a model ahead of time, just run it once on any short clip — the download happens on first use, and a progress bar shows it:
$ transcriber some-short-clip.mp3 -m turbo
Once cached, transcription needs no network at all. Set HF_HUB_OFFLINE=1 to
guarantee it: cached models keep working, and an uncached one fails immediately
with a clear message instead of reaching out.
Using your own model
-m also takes a HuggingFace CTranslate2 repo id, or a path to a model
directory you converted or downloaded yourself:
$ transcriber talk.mp4 -m Systran/faster-whisper-large-v3
$ transcriber talk.mp4 -m /models/my-finetuned-whisper
Authentication for private media
Instagram reels, members-only videos, and anything else behind a login need your browser's cookies:
$ transcriber <reel-url> --cookies-from-browser firefox -f md -t
$ transcriber <reel-url> --cookies cookies.txt
Windows note: Chrome's app-bound cookie encryption usually defeats
--cookies-from-browser chrome. Use Firefox, or export acookies.txtwith a browser extension and pass--cookies.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Everything transcribed (or was already done) |
| 1 | At least one item failed — the message says why |
| 2 | Bad command-line usage |
| 130 | Interrupted with Ctrl-C |
Development
From a checkout:
$ uv sync # dev environment
$ uv run pytest # fast tests: no network, no models
$ uv run pytest -m slow # real tiny-model smoke test (~75 MB, once)
$ uv run ruff check . && uv run ruff format .
CI runs the suite on Linux, macOS, and Windows across Python 3.10 and 3.12. Python 3.10 through 3.14 are verified locally on Linux.
Contributing
Source, issues, and pull requests: https://github.com/AyushShah2/omni-transcriber
License
MIT — see LICENSE.
Metadata
Release files for omni-transcriber 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| omni_transcriber-0.1.3.tar.gz | 27.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| omni_transcriber-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 61.3 kB
Release files / omni_transcriber-0.1.3.tar.gz
| Download URL | omni_transcriber-0.1.3.tar.gz |
|---|---|
| Size | 27.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
83249ed67739683fdbfbde1b0173fdec1e691c770707cafc781319ab6d1413c9
|
|
BLAKE2b-256 checksum How to use checksums |
dc906396d9854c21423fa27bafc7e3e52b917992defc446de75ab1365efc29f0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / omni_transcriber-0.1.3-py3-none-any.whl
| Download URL | omni_transcriber-0.1.3-py3-none-any.whl |
|---|---|
| Size | 33.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
76d2973450dedc2cda823545e09e749b23ed2ecf2853cfb20806ebc6ea119745
|
|
BLAKE2b-256 checksum How to use checksums |
f66f0eaca3cd1fb90aa5aeae61496bf537b8a212a46a1dbb7f39bf68644ad8ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|