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
--screen OCR what is shown on screen into timestamped snapshots (needs [screen])
-j, --jobs N Fetch N inputs in parallel while one transcribes; playlists split per entry
--retry FILE Re-run the URLs a previous run saved to its transcriber-retry.txt
-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.

When the network is your bottleneck, add --jobs:

$ transcriber "https://www.youtube.com/playlist?list=PL..." -j 4 -m large-v3 -o out/

-j N turns a playlist into independent per-entry downloads, keeps up to N of them running while a single worker transcribes (one loaded model — your GPU never waits on the network), pauses downloading when a couple of finished files are already queued so a fast connection cannot fill your disk, and waits for free memory rather than crashing when the system is busy. Private or deleted entries are skipped exactly as in sequential runs.

When downloads fail mid-run

Cookies expire, sites rate-limit. Every URL a run fails to fetch is saved — with the reason — to transcriber-retry.txt next to your transcripts, and after five identical failures in a row a --jobs run stops fetching instead of burning through the rest of the playlist: the untouched remainder goes straight to the retry list. Fix the cause (refresh cookies, wait out the rate limit), then continue exactly where you left off:

$ transcriber --retry out/transcriber-retry.txt --cookies-from-browser firefox -j 4 -o out/

Only the failed entries are re-fetched — everything already transcribed stays untouched.

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.

Seeing the screen too (--screen)

When a speaker says "this function calls that object", the words alone are useless — the meaning is on their screen. --screen reads it: video keyframes are sampled, frames that actually changed are OCR'd locally (PP-OCR models on ONNX Runtime — no cloud, no PyTorch), and each distinct screen state becomes a timestamped snapshot woven into the --llm markdown right before the words spoken over it:

**[On screen 12:26]**
```
class Portfolio:
    def rebalance(self, weights):
```

[12:28] So this needs to have a function which calls that object...

It reads text — code, slides, terminals, docs. Pictures and diagrams without words stay opaque. Repeated content is emitted once: static IDE chrome appears in the first snapshot only, and scrolling through a file yields each line once.

$ uv tool install "omni-transcriber[screen]"   # or [gpu,screen] for both
$ transcriber lecture.mp4 --screen -o notes/
$ transcriber "https://youtu.be/xyz" --screen -o notes/   # downloads video too

For links, --screen additionally downloads a video-only stream (up to 720p, where on-screen code stays legible) — roughly 150–300 MB per half hour, which is why it is never the default. In -f json output the snapshots appear as a screen array instead.

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.10

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.10
File Size Uploaded
omni_transcriber-0.1.10.tar.gz 43.2 kB Details

Built distribution (wheel)

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

Total release size: 94.3 kB

Release files / omni_transcriber-0.1.10.tar.gz

Download URL omni_transcriber-0.1.10.tar.gz
Size 43.2 kB
Tags Source
SHA-256 checksum
How to use checksums
65c425b179dccce385c1f19164b518c7f974a1506fdcc801b4e27ce422ef51dd
BLAKE2b-256 checksum
How to use checksums
3130e7fac9e4d4a34e28f34f4d51800cf928f67496187cea19fc268a18eb6eda
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.10-py3-none-any.whl

Download URL omni_transcriber-0.1.10-py3-none-any.whl
Size 51.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8e38c0b6eea38fa6d1cd3c84938bd1887b91eb8f50c4e69896e0b5d24ba19c78
BLAKE2b-256 checksum
How to use checksums
63ac9b0a9845515c89dcf91db5ba0e5dc6348fd6f1bd3fcdf13ded1a92ead9b6
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

This release

0.1.10 This release

2 release files

0.1.9

2 release files

0.1.7

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