Skip to main content

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. transcriber enables whichever it finds on your PATH automatically. 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
--clean Drop hallucinated repeats, [Music] tags, stutters, English fillers
--llm LLM-ready markdown: metadata header + timestamped paragraphs; implies --clean
-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, it is skipped with a warning saying why, the rest still run, and the closing summary lists it as skipped. Unlisted videos need nothing special — having the link is enough. Private videos your own account can watch are reachable with --cookies-from-browser firefox.

Duplicates are skipped automatically: the same link or file given twice, a video listed twice in one playlist, or the same video reached through two different inputs all transcribe exactly once.

Feeding transcripts to an LLM

$ transcriber "https://youtu.be/xyz" --llm -o notes/

--llm produces markdown built for pasting into Claude, ChatGPT, or a RAG pipeline: a metadata header (title, source, uploader, duration, language), then the transcript in short paragraphs that each open with their [mm:ss] timestamp — so the model can cite and deep-link any passage, and chunking tools never split mid-thought. It implies --clean, which drops the noise that trips models up: hallucinated repeated lines, [Music]/(applause) tags, three-plus stutters, and English hesitation sounds (um, uh). Cleanup never rewrites wording — everything else is exactly what was said. Use --clean on its own to tidy any other format the same way.

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 a cookies.txt with 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.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for omni-transcriber 0.1.7
File Size Uploaded
omni_transcriber-0.1.7.tar.gz 33.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for omni-transcriber 0.1.7
File Interpreter ABI Platform
omni_transcriber-0.1.7-py3-none-any.whl Python 3 none any Details

Total release size: 73.7 kB

Release files / omni_transcriber-0.1.7.tar.gz

Download URL omni_transcriber-0.1.7.tar.gz
Size 33.3 kB
Tags Source
SHA-256 checksum
How to use checksums
7c7ecb2a636c7f4df899cb63770deef9f996378bbe8928bebd0fb8c11ee8a63b
BLAKE2b-256 checksum
How to use checksums
0d35a9dd30591fda21e90195dd7c966ac28332953343f54125e6b3c983017a8a
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.7-py3-none-any.whl

Download URL omni_transcriber-0.1.7-py3-none-any.whl
Size 40.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
836ec6b4d657be2eebe46607656990a67699bfcfcccccbac18f4d129044cb73f
BLAKE2b-256 checksum
How to use checksums
ee0001ce3ee59a7b1f73b810dc970dbfb0364031fa55ecadc0dce66ebea0101b
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 history Release notifications | RSS feed

0.1.10

2 release files

0.1.9

2 release files

This release

0.1.7 This release

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page