Skip to main content

Extract YouTube transcripts and translate them with AI — standalone alternative to youtube-transcript-api

Project description

U-Transkript

Extract YouTube transcripts and translate them with AI — no official API, no API keys for extraction, one dependency.

PyPI Python License

U-Transkript is a standalone alternative to youtube-transcript-api with built-in AI translation. It talks to YouTube's InnerTube endpoint directly using the ANDROID client, so transcript extraction needs no official API key and no PoToken.

  • Transcript extraction via YouTube's InnerTube ANDROID client, with watch-page scraping as a fallback
  • AI translation to any language via Google Gemini (gemini-3.5-flash by default)
  • YouTube server-side translation (transcript.translate("es")) — free, no AI key needed
  • Output formats: pretty text, plain text, JSON, SRT, WebVTT
  • CLI with single-video and bulk channel mode, plus an optional Flask HTTP API
  • Transparent disk cache (24h) on the CLI's fetch paths — repeated fetches of the same video are instant
  • Python 3.10+, a single runtime dependency (requests), resilient retries with backoff

Installation

pip install u-transkript

Optional extras:

pip install "u-transkript[api]"   # Flask HTTP API wrapper
pip install "u-transkript[dev]"   # pytest, pytest-cov, ruff

Quick start

u-transkript dQw4w9WgXcQ
from youtube_transcript import YouTubeTranscriptApi

transcript = YouTubeTranscriptApi.get_transcript("dQw4w9WgXcQ")
for entry in transcript:
    print(f"[{entry['start']:7.2f}] {entry['text']}")

get_transcript returns a list of {"text", "start", "duration"} dicts.

CLI

# Single video — pretty-printed transcript to stdout
u-transkript dQw4w9WgXcQ
u-transkript "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

# Language preference (first available wins)
u-transkript dQw4w9WgXcQ -l de en

# Output formats: pretty (default), json, text, srt, vtt
u-transkript dQw4w9WgXcQ -f srt -o subtitles.srt

# See which transcript languages a video offers
u-transkript dQw4w9WgXcQ --list-transcripts

# Translate with Gemini AI (reads GEMINI_API_KEY from the environment)
u-transkript dQw4w9WgXcQ --translate Turkish -o ceviri.txt

# Channel mode — downloads recent videos as 1_<videoId>.srt, 2_<videoId>.srt, ...
u-transkript @MrBeast -f srt -o transcripts/ -n 25

# From a source checkout (no install needed)
python run.py dQw4w9WgXcQ -f json
Flag Description
target Video URL/ID, or @handle / channel URL for bulk download
-l, --languages Language codes in order of preference (e.g. en es fr)
-f, --format pretty (default), json, text, srt, vtt
-o, --output Output file (single video) or directory (channel mode)
-n, --count How many recent videos to download in channel mode (default: 10)
--list-transcripts List available transcript languages and exit
--translate LANGUAGE Translate with Gemini AI (needs GEMINI_API_KEY; not for srt/vtt)
--no-cache Bypass the 24-hour transcript disk cache (cache applies to fetching, not --translate)
--version Print version and exit

Fetched transcripts are cached for 24 hours in ~/.cache/u-transkript (single-video and channel modes; --translate always fetches fresh). Exit codes: 0 success, 1 user error, 2 network error, 3 transcript/API error.

Config file

Defaults can be set in ~/.u-transkriptrc:

language = en
format = srt

or ~/.config/u-transkript/config.toml:

language = "en"
format = "srt"

The first file found wins entirely. Only language and format are recognized; explicit CLI flags override.

Python library

Pick a language, list what's available

from youtube_transcript import YouTubeTranscriptApi

# Preferred languages, in order
transcript = YouTubeTranscriptApi.get_transcript("dQw4w9WgXcQ", languages=["de", "en"])

# Inspect everything YouTube offers for a video
transcripts = YouTubeTranscriptApi.list_transcripts("dQw4w9WgXcQ")
for t in transcripts:
    print(t.language_code, t.language, "(auto)" if t.is_generated else "(manual)")

# Let YouTube translate server-side — no AI key required
english = transcripts.find_transcript(["en"])
if english.is_translatable:
    spanish_entries = english.translate("es").fetch()

Export to subtitle formats

from formatters import SRTFormatter, get_formatter
from youtube_transcript import YouTubeTranscriptApi

entries = YouTubeTranscriptApi.get_transcript("dQw4w9WgXcQ")

srt = SRTFormatter().format_transcript(entries)
vtt = get_formatter("vtt").format_transcript(entries)  # registry: pretty, json, text, srt, vtt

with open("subtitles.srt", "w", encoding="utf-8") as f:
    f.write(srt)

Batch fetch

results = YouTubeTranscriptApi.get_transcripts(
    ["dQw4w9WgXcQ", "jNQXAC9IVRw"],
    languages=["en"],
    continue_on_failure=True,
)
for r in results:
    status = f"{len(r['transcript'])} entries" if r["error"] is None else f"failed: {r['error']}"
    print(r["video_id"], status)

Error handling

Every exception derives from TranscriptRetrievalError and carries a .suggestion with an actionable hint:

from exceptions import NoTranscriptFound, TooManyRequests, TranscriptRetrievalError
from youtube_transcript import YouTubeTranscriptApi

try:
    transcript = YouTubeTranscriptApi.get_transcript("dQw4w9WgXcQ", languages=["fi"])
except NoTranscriptFound as e:
    print(e)             # includes the languages that ARE available
    print(e.suggestion)
except TooManyRequests as e:
    print(e.suggestion)  # rate-limited: wait, or route through a proxy
except TranscriptRetrievalError:
    ...                  # base class for all transcript errors

get_transcript also accepts proxies={"https": "..."}, cookies="..." and preserve_formatting=True. For many fetches in a row, use the context-manager form (with YouTubeTranscriptApi() as api: ...) so the shared HTTP session is closed when you are done.

AI translation with Gemini

Translation requires a Gemini API key from Google AI Studio; extraction itself never needs a key.

from ai_translator import AITranscriptTranslator

translator = AITranscriptTranslator("GEMINI_API_KEY")  # default model: gemini-3.5-flash
text = translator.set_lang("German").translate_transcript("dQw4w9WgXcQ")
# Fluent configuration; output types: "txt" (default), "json", "xml"
result = (
    AITranscriptTranslator("GEMINI_API_KEY")
    .set_model("gemini-3.5-flash")
    .set_lang("Spanish")
    .set_type("json")
    .translate_transcript("dQw4w9WgXcQ")
)
# Custom prompts: a str.format template with {text} and {language} placeholders.
# Literal braces must be doubled ({{ }}).
summary = AITranscriptTranslator("GEMINI_API_KEY").translate_transcript(
    "dQw4w9WgXcQ",
    target_language="English",
    custom_prompt="Summarize this transcript in {language} as 5 bullet points:\n\n{text}",
)

Or the one-line shortcut:

from ai_translator import quick_translate

text = quick_translate("dQw4w9WgXcQ", "GEMINI_API_KEY", target_language="French")

Long transcripts are automatically split into chunks (at entry boundaries) and translated chunk by chunk, so long videos don't silently truncate at the model output limit.

HTTP API

api.py ships in the repository (not in the PyPI package), so run it from a checkout:

git clone https://github.com/U-C4N/u-transkript.git
cd u-transkript
pip install -e ".[api]"
python api.py            # binds 0.0.0.0:8080 — env vars: PORT, HOST, DEBUG
curl "http://localhost:8080/api?url=dQw4w9WgXcQ"
curl "http://localhost:8080/api?url=dQw4w9WgXcQ&format=srt" -o subtitles.srt
curl "http://localhost:8080/api?url=https://youtu.be/dQw4w9WgXcQ&languages=en,es&format=vtt"
Endpoint Description
GET / Usage info
GET /health Health check
GET /api Fetch a transcript

GET /api parameters: url (required), format (json default, pretty, text, srt, vtt), languages (comma-separated), proxy, preserve_formatting (1/true).

Errors come back as JSON with a type and an actionable suggestion; CORS is enabled. On Replit/Render/Railway-style platforms, set the run command to python api.py — the server binds to $PORT.

How it compares

u-transkript youtube-transcript-api
Transcript extraction / SRT / VTT / JSON
Built-in AI translation (Gemini)
Bulk channel download (CLI)
HTTP API wrapper included
ANDROID InnerTube client (no PoToken)
Retry with exponential backoff built in
24h transcript disk cache (CLI)
Single runtime dependency

How it works

  • Talks to YouTube's InnerTube API using the ANDROID client first (no PoToken required), falling back to watch-page scraping and finally a bare timedtext URL.
  • Parses all three transcript wire formats YouTube serves: srv3 XML, legacy XML, and json3.
  • Retries transient failures with exponential backoff and honors HTTP 429 rate-limit responses with escalating waits.

Limitations and disclaimer

  • Not affiliated with or endorsed by YouTube or Google.
  • Relies on undocumented YouTube endpoints that can change without notice.
  • Respect YouTube's Terms of Service and the rights of content owners.
  • Heavy use can get your IP rate-limited (HTTP 429).
  • Channel mode scrapes the channel page HTML, so it can only see the videos that page exposes (roughly the most recent ones); -n is capped by what the page yields.
Development
git clone https://github.com/U-C4N/u-transkript.git
cd u-transkript
pip install -e ".[dev]"

python run.py dQw4w9WgXcQ -f json   # run the CLI from source
pytest                              # test suite
ruff check src/ tests/              # lint

Links

License

MIT — see LICENSE. Built by U-C4N.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

u_transkript-3.3.0.tar.gz (34.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

u_transkript-3.3.0-py3-none-any.whl (34.3 kB view details)

Uploaded Python 3

File details

Details for the file u_transkript-3.3.0.tar.gz.

File metadata

  • Download URL: u_transkript-3.3.0.tar.gz
  • Upload date:
  • Size: 34.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for u_transkript-3.3.0.tar.gz
Algorithm Hash digest
SHA256 1167a4be34cc8df2cb88bf623bc7ec087cfdd54fbeea18bad971586adf10e2ec
MD5 d73d9e3b800fd6a639e28bd96b43121a
BLAKE2b-256 97cf58a98760253aff2737e587053fce5a36cce2408b41f4982a75acf97f8185

See more details on using hashes here.

File details

Details for the file u_transkript-3.3.0-py3-none-any.whl.

File metadata

  • Download URL: u_transkript-3.3.0-py3-none-any.whl
  • Upload date:
  • Size: 34.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for u_transkript-3.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f46ad3cf31e36659a9ba9d79f334df066d7bbe06edb3f8c7197d0a59d2ad9b36
MD5 9bc55b697f06cd8a3649e38480603799
BLAKE2b-256 0d403b24ac064e8debf6613e205a976608ec31063a587477d1d8858e7064b714

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page