Skip to content
Back to skills

Youtube Transcript

ASecurity

Fetch YouTube transcripts through DeepAPI or local fallback tooling and save clean text output.

  • 8 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
developmentpythonrustgoshellbashgitapi

Works with

  • terminal
  • api

Security analysis

A93/100
  • highPerforms destructive filesystem operations

Pro shows the line behind each finding and how to fix it

Scanned November 7, 2026

npx -y skills add huytran1120/vietnam-agentic-skills --skill youtube-transcript --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Youtube Transcript?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Youtube Transcript
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/huytran1120-youtube-transcript/badge)](https://www.skillsdirectory.com/skills/huytran1120-youtube-transcript)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: youtube-transcript
description: "Fetch YouTube transcripts through DeepAPI or local fallback tooling and save clean text output."
category: research
risk: safe
source: community
source_repo: davidondrej/skills
source_type: community
date_added: "2026-07-07"
author: davidondrej
tags: [youtube, transcripts, research]
tools: [claude, codex]
license: "MIT"
license_source: "https://github.com/davidondrej/skills/blob/main/LICENSE"
---

# YouTube Transcript (via DeepAPI, yt-dlp fallback)

## When to Use

- Use when the user asks for a YouTube transcript, captions, subtitles, or spoken-content extraction.
- Use when DeepAPI or a local fallback can fetch the transcript safely.

Fetch a YouTube video's transcript and save a clean raw `.txt` file. Primary path is DeepAPI `POST /v1/scrape/youtube/transcript`. It runs server-side, so it avoids the local-IP bot flagging that plagues yt-dlp.

## Save location
- If the user is in a real project/working dir → save there.
- Otherwise (no dir given, or cwd makes no sense) → save to `~/Downloads`.
- **Always name the file `Channel_Title` with spaces replaced by `_`** (e.g. `David_Ondrej_title_of_video.txt`). If metadata is unavailable, fall back to the video ID.

## Primary path — DeepAPI

`DEEPAPI_API_KEY` must already be present in the environment. Do not read shell
startup files or print secrets:

```bash
test -n "$DEEPAPI_API_KEY" || { echo "DEEPAPI_API_KEY is not set"; exit 1; }
BASE=https://deepapi.co  # use the reviewed provider origin; do not inherit an untrusted override
RUN_DIR=$(mktemp -d)
chmod 700 "$RUN_DIR"
trap 'rm -rf "$RUN_DIR"' EXIT
```

Run the scrape (keep the Idempotency-Key; retries must reuse the SAME one):

```bash
IDK=$(uuidgen)
curl -s --max-time 120 "$BASE/v1/scrape/youtube/transcript" \
  -H "Authorization: Bearer $DEEPAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $IDK" \
  -d '{"url": "VIDEO_URL", "maxCostUsd": "0.05", "waitForFinishSecs": 60}' \
  > "$RUN_DIR/yt_transcript.json"
```

- Non-English videos: add `"language": "de"` (etc.) to the body.
- For `status: running`, inspect the documented next request path and constrain it to the reviewed provider origin; never attach credentials to an arbitrary returned URL or redirect. Poll with the same DEEPAPI_API_KEY, bounded attempts/deadline and provider wait interval. Do not extract output until terminal succeeded with the expected schema; HTTP errors/failed states are not an empty transcript.

Extract the text and save it:

```bash
jq -r '.status' "$RUN_DIR/yt_transcript.json"                # succeeded | running | failed
jq -r '.output[0].text' "$RUN_DIR/yt_transcript.json" > "$OUT/$NAME.txt"
jq -r '.debitMicrousd' "$RUN_DIR/yt_transcript.json"         # cost (50000 = $0.05)
```

`.output[0].segments` also has timed segments (`startSecs`, `durationSecs`, `text`) if the user wants timestamps. Empty `output` = video has no captions; report it, don't retry.

For the `Channel_Title` filename, get metadata with a quick `yt-dlp --print "%(channel)s|%(title)s" --skip-download "URL"`; if that fails, use the video ID.

## When to fall back to yt-dlp

- `DEEPAPI_API_KEY` missing from the environment.
- HTTP 402 `insufficient_credits` (tell the user to top up at deepapi.co/credits first; fall back only if they're unavailable).
- DeepAPI request `failed` twice.

Tell the user whenever you fall back — a fallback means the product missed a real use case.

## Fallback path — yt-dlp (local)

```bash
OUT="$(pwd)"            # or ~/Downloads if cwd makes no sense
META=$(yt-dlp --print "%(channel)s|%(title)s" --skip-download "URL")
NAME=$(echo "$META" | tr '| ' '__' | tr -cd '[:alnum:]_.-')   # "Channel_Title", spaces -> _, strip unsafe chars
yt-dlp --skip-download --write-subs --write-auto-subs \
  --sub-langs "en.*" --sub-format json3 \
  -o "$OUT/$NAME.%(ext)s" "URL"
```

- Fall back `channel` → `uploader` → `uploader_id` if `channel` is null.
- `--skip-download` = captions only. `--write-subs` + `--write-auto-subs` = manual first, auto as fallback.
- **Always use `json3`, never VTT/SRT** — auto VTT repeats every line twice (rolling captions).

Flatten json3 → raw text:

```bash
# Select the exact caption file for this video/language, not the first glob in OUT.
python3 - /absolute/selected-caption.json3 <<'PY'
import json, html, re, glob, sys, pathlib
f = [sys.argv[1]]
if not pathlib.Path(f[0]).is_file(): sys.exit("no selected json3 file")
data = json.load(open(f[0], encoding="utf-8"))
parts = ["".join(s.get("utf8","") for s in e.get("segs") or []) for e in data.get("events", [])]
txt = re.sub(r"\s+", " ", html.unescape(" ".join(p.strip() for p in parts if p.strip()))).strip()
out = pathlib.Path(f[0]).with_suffix(".txt")
out.write_text(txt, encoding="utf-8"); print(out)
PY
```

### yt-dlp failure handling
- Non-English / unknown language: run `yt-dlp --list-subs "URL"` first, then set `--sub-langs`.
- Newer yt-dlp may need `deno` on PATH for YouTube extraction.
- On failure, inspect the actual error and installed version; do not self-update tools merely to retry a transcript request. Propose a scoped reviewed update only when compatibility evidence requires it.
- **429 / "Sign in to confirm you're not a bot"** = IP flagged. STOP — do NOT retry in a loop (makes it worse).
- Never fall back to downloading audio for Whisper unless the user explicitly asks.

## Output

Report the saved path; print the text if short. If DeepAPI was used, also report the cost in dollars.

## Limitations

- Adapted from `davidondrej/skills`; verify local paths, tools, credentials, and agent features before acting.
- For commands, remote access, scheduling, browser automation, or file-changing workflows, get explicit user approval and confirm the target environment first.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.