Youtube Transcript
glebis/claude-skills
Extract YouTube video transcripts with metadata and save as Markdown to Obsidian vault.
Agent skill
by EfficientStreet in EfficientStreet/youtube-subscriptions-ingest
Pull metadata from YouTube subscription videos into a second-brain vault as a real cross-linked knowledge graph — not just a flat archive.
$ npx skills add EfficientStreet/youtube-subscriptions-ingest --skill subscription-videos-metadata -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install EfficientStreet/youtube-subscriptions-ingest subscription-videos-metadata --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
Claude Code skills documentation · loads skills from .claude/skills/
Install the "subscription-videos-metadata" agent skill from https://github.com/EfficientStreet/youtube-subscriptions-ingest/tree/main into .claude/skills/subscription-videos-metadata/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "subscription-videos-metadata", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add EfficientStreet/youtube-subscriptions-ingest --skill subscription-videos-metadata -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install EfficientStreet/youtube-subscriptions-ingest subscription-videos-metadata --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "subscription-videos-metadata" agent skill from https://github.com/EfficientStreet/youtube-subscriptions-ingest/tree/main into .agents/skills/subscription-videos-metadata/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "subscription-videos-metadata", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add EfficientStreet/youtube-subscriptions-ingest --skill subscription-videos-metadata -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install EfficientStreet/youtube-subscriptions-ingest subscription-videos-metadata --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "subscription-videos-metadata" agent skill from https://github.com/EfficientStreet/youtube-subscriptions-ingest/tree/main into .cursor/skills/subscription-videos-metadata/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "subscription-videos-metadata", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add EfficientStreet/youtube-subscriptions-ingest --skill subscription-videos-metadata -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install EfficientStreet/youtube-subscriptions-ingest subscription-videos-metadata --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "subscription-videos-metadata" agent skill from https://github.com/EfficientStreet/youtube-subscriptions-ingest/tree/main into .gemini/skills/subscription-videos-metadata/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "subscription-videos-metadata", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install EfficientStreet/youtube-subscriptions-ingest subscription-videos-metadataInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add EfficientStreet/youtube-subscriptions-ingest --skill subscription-videos-metadata -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "subscription-videos-metadata" agent skill from https://github.com/EfficientStreet/youtube-subscriptions-ingest/tree/main into .github/skills/subscription-videos-metadata/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "subscription-videos-metadata", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add EfficientStreet/youtube-subscriptions-ingest --skill subscription-videos-metadata -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install EfficientStreet/youtube-subscriptions-ingest subscription-videos-metadata --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "subscription-videos-metadata" agent skill from https://github.com/EfficientStreet/youtube-subscriptions-ingest/tree/main into .opencode/skills/subscription-videos-metadata/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "subscription-videos-metadata", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
subscription-videos-metadataPull metadata from YouTube subscription videos into a second-brain vault as a real cross-linked knowledge graph — not just a flat archive.
Subscription Videos Metadata is an agent skill from EfficientStreet/youtube-subscriptions-ingest. Pull metadata from YouTube subscription videos into a second-brain vault as a real cross-linked knowledge graph — not just a flat archive. Trigger on 'pull my subscription videos', 'fetch latest subscription videos', 'ingest my videos', 'update my video list', 'check new subscription videos', 'show my saved videos', 'fetch transcripts', 'get transcripts for my videos'. Three-phase: fetch pulls verbatim metadata into a configured raw/ folder; transcript pulls each video's caption track via youtubetranscriptapi…
Its SKILL.md is about 7.1k tokens, which your agent loads only when the skill is triggered. The skill folder holds 11 other files, including scripts (for example `GUIDE.md`, `README.md` and `scripts/fetch_transcript.py`).
It sits in Knowledge Management, covering Transcription, Video and podcast notes and Second brain. It works with YouTube and Obsidian. The repository describes itself as: Pull YouTube subscription metadata into a real cross-linked knowledge graph in your second-brain vault. The licence is MIT.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 26f91e3. It shows what the files ask for, not the result of running them.
Pre-approves these tools, so the agent can use them without asking each time:
Bash(python "${CLAUDE_PROJECT_DIR}/scripts/youtube_subscriptions.py":*)Bash(python "${CLAUDE_PROJECT_DIR}/scripts/fetch_transcript.py":*)ReadGrepAskUserQuestionArtifactFrom allowed-tools in the SKILL.md frontmatter.
Ships 2 files in scripts/ (Python), which the agent can run.
Shell commands in SKILL.md call:
pythonFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
github.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
GOOGLE_YOUTUBE_CLIENT_SECRETFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Subscription Videos Metadata loads about 7.1k tokens when it runs. Until then it costs about 248 tokens; SKILL.md has 3,486 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
GLE_YOUTUBE_CLIENT_SECRET` are empty in `.env`: tell the user they need to create a Google Cloud OAuth Desktop-app clien3. Once `.env` is filled in: `python scripts/youtube_subscriptions.py auth` — opens a local browser window to consent. TYT_WEBSHARE_USER`/`YT_WEBSHARE_PASS` in `.env`) if IP blocks turn out to be a real problem in practice — off by default,Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from EfficientStreet/youtube-subscriptions-ingest at commit 26f91e3, republished under its MIT licence (© EfficientStreet). 3,486 words, ~7,124 tokens.
.claude/skills/subscription-videos-metadata/SKILL.md (or your agent's skills folder). This skill also uses 9 other files; get the full folder from GitHub.Pulls video metadata from a real YouTube account's subscriptions (via OAuth) using scripts/youtube_subscriptions.py, and turns it into a real knowledge graph in a second-brain vault — not just a searchable list. Replaces manually checking the YouTube subscription feed.
Not hardcoded to any one project or vault. The script asks where to put things on first run (see "First-time setup" below) and remembers — portable to any machine/checkout, any Brain-Matter-style vault. For Jeffrey's own setup specifically, it's currently configured with --raw-dir "Brain Matter/raw/youtube-videos" and --wiki-root "Brain Matter", but nothing in the script assumes that path — treat every path in this document as "wherever it's configured," not a hardcoded constant.
This is the working copy — the one Claude actually loads each session in this project. The canonical, publicly-released source lives at https://github.com/SomewhereSimulated/youtube-subscriptions-ingest (public repo, MIT license, generalized from this project's version 2026-08-11 — first of hopefully many standalone releases from here). That repo's SKILL.md/README.md/GUIDE.md/scripts/youtube_subscriptions.py are the source of truth for the portable version; this copy is specifically wired for Jeffrey's own Brain Matter vault (frontmatter, allowed-tools, and behavior are otherwise identical). When either copy changes in a way that should apply to both — a bug fix, a new capability, a taxonomy improvement — port the change to the other manually and note it in decisions/log.md here. Don't let them silently drift: Jeffrey-specific config/paths stay local-only, but logic/behavior fixes belong in both places.
Three-phase, mirroring Brain Matter's own raw/ → wiki/ convention (Brain Matter/CLAUDE.md — read that file if you haven't; this skill follows its schema, doesn't replace it):
<raw_dir>/. Verbatim metadata only, no interpretation. Raw source material is immutable per Brain Matter's rule.scripts/fetch_transcript.py (youtube_transcript_api, cached/throttled/retried per video — a straight caption scrape, no audio transcription, no fallback if captions are off) and appends it directly onto the raw .md file as a ## Transcript section, right after the description (plus a plain-text .transcript.txt convenience copy — see Archive structure). A video with no captions gets a ## Transcript section too, reading "Unavailable" — recorded as unavailable, not an error.<raw_dir>/ → <wiki_root>/wiki/sources/, <wiki_root>/wiki/concepts/, <wiki_root>/wiki/entities/, <wiki_root>/index.md, <wiki_root>/log.md. Auto-detects concept/entity matches via keyword taxonomy and writes real [[Page Name]] Obsidian links between a video's source page and the concepts/entities it touches — creating stub pages for new ones, appending to existing ones (hand-written or previously auto-created) without disturbing their prose. Carries the raw file's ## Transcript section (if the transcript phase already ran for that video) onto the source page in the same position — directly after ## Description, before ## Concepts/## Entities.This is deliberately the lightweight, automated tier of Brain Matter ingest — real links and auto-created stubs, but no hand-written synthesis prose (that's the full manual process: "read it, talk through takeaways, write real analysis," which doesn't scale to hundreds of videos per fetch). Full manual treatment for one specific video that actually matters is still just a normal conversation — ask for it directly, video by video, following Brain Matter/CLAUDE.md's real ingest workflow instead of this one.
Relative layout under wherever configure points — shown here with Jeffrey's actual current configuration (raw_dir = Brain Matter/raw/youtube-videos, wiki_root = Brain Matter):
<raw_dir>/ e.g. Brain Matter/raw/youtube-videos/
<Channel Name>/<published-date>-<video-id>.md verbatim — written by fetch; transcript phase APPENDS a
"## Transcript" section directly onto this file, right
after the description — this is the canonical copy
<Channel Name>/<published-date>-<video-id>.transcript.txt plain-text convenience copy of the same transcript,
written alongside it (may not exist: unavailable or
transcript phase hasn't run yet) — not the source of
truth, just grep-able without frontmatter parsing
_fetch-index.tsv internal: fetch dedup (not a real source, don't ingest it)
_transcript-index.tsv internal: transcript dedup — only ok/cached/unavailable are terminal; errors retry next run
_ingest-index.tsv internal: ingest dedup
<wiki_root>/ e.g. Brain Matter/
wiki/
sources/youtube-videos/
<Channel Name>/<Video Title> [<Video ID>].md one page per video — written by ingest
concepts/<slug>.md auto-created/updated by ingest (or hand-written)
entities/<slug>.md auto-created/updated by ingest (or hand-written)
index.md concept/entity catalog — updated by ingest
log.md one entry per ingest RUN — updated by ingestGitignored (bulk data, local-only): raw/youtube-videos/, wiki/sources/youtube-videos/. Tracked in git (the actual synthesized knowledge, small and worth versioning): wiki/concepts/, wiki/entities/, index.md, log.md.
The [<Video ID>] filename suffix on source pages is load-bearing, not decorative — titles are not unique (a real collision: two different Greg Isenberg videos, different IDs, identical title, one a rebroadcast — silently overwrote one note with the other before the ID suffix was added). Never drop it for a cleaner-looking filename.
Two separate one-time steps — neither is specific to Jeffrey's machine or this particular project, so a fresh checkout (or a different user entirely) needs both before the skill does anything.
The script has no hardcoded path to any particular vault — check whether scripts/.youtube_subscriptions_config.json exists. If it doesn't, this is a genuine first run: ask via AskUserQuestion before running fetch, refresh, or ingest (all three will error out clearly if this step is skipped, so it's safe to attempt them and let the error prompt this rather than pre-checking every time — but if you already know it's unconfigured, ask up front instead of waiting for the error).
Two things to ask, each needs a real folder path — check for an existing likely default first (e.g. a Brain Matter/ folder already in this project) and offer it as the recommended option, with "Other" (built into AskUserQuestion) as the free-text path for anything else:
--raw-dirwiki/sources/youtube-videos/, wiki/concepts/, wiki/entities/, index.md, and log.md under whatever folder is given here, same relative layout Brain Matter itself uses) → --wiki-rootThen run:
python scripts/youtube_subscriptions.py configure --raw-dir "<path>" --wiki-root "<path>"This is safe to run against an existing vault — it only scaffolds index.md/log.md if they're genuinely missing, never overwrites real content. Confirm the resolved absolute paths back from the JSON it prints.
test reports not authenticated)python scripts/youtube_subscriptions.py testGOOGLE_YOUTUBE_CLIENT_ID/GOOGLE_YOUTUBE_CLIENT_SECRET are empty in .env: tell the user they need to create a Google Cloud OAuth Desktop-app client first (console.cloud.google.com — enable "YouTube Data API v3", then Credentials → Create Credentials → OAuth client ID → Desktop app) and paste the client ID/secret into .env. Do not attempt this for them — it requires their Google login..env is filled in: python scripts/youtube_subscriptions.py auth — opens a local browser window to consent. Token caches to scripts/.credentials/youtube_token.json (gitignored) and auto-refreshes after that; this is a one-time step.test to confirm — it prints the account's channel name and subscription count.Use AskUserQuestion with four options:
raw/. Does NOT make anything searchable in the wiki sense by itself.ingest after so the transcript actually lands on the source page.raw/ and not yet ingested into the real wiki (wiki/sources/, wiki/concepts/, wiki/entities/). Folds in a transcript sidecar if one already exists for that video.If Jeffrey just says "pull my videos" without specifying, fetch alone is the literal ask — but mention that transcript + ingest are separate steps needed before the new videos are actually searchable (with transcript) in the wiki, and offer to run them too.
A subtlety worth knowing: ingest dedups by video ID like every other phase — a video already ingested before its transcript was fetched will NOT automatically get the transcript folded in on a later ingest run. There is no ingest --force/backfill path yet (flagged as a known gap, not built — see decisions/log.md, 2026-08-14). If Jeffrey wants the transcript backfilled into an already-ingested video's source page, that's a manual ask for now, not something a normal ingest run will pick up.
Every time, before running — not just on a first ever run — ask via AskUserQuestion: "How far back should this fetch look?" Options (max 4 + the built-in "Other" free-text slot):
--days at all.Convert a chosen/typed window to a day count and pass --days N explicitly (90 → 90, 6 months → 182, 1 year → 365; parse free text by judgment — a bare number is days, "N weeks"/"N months"/"N years" scale accordingly). Any explicit --days value overrides the normal incremental cutoff, even on an already-established archive — that's what makes "go back further than normal" a real, repeatable option (e.g. to backfill a channel that was missed before), not just a first-run-only setting. Dedup by Video ID makes this safe to run repeatedly.
Run:
python scripts/youtube_subscriptions.py fetch [--days N]The script handles everything: paginating subscriptions, resolving each channel's uploads playlist, walking it newest-first with an early stop at the cutoff date, pulling full metadata in batched calls, deduping against raw/'s fetch index by Video ID, and writing one verbatim file per new video into raw/youtube-videos/<Channel>/. No per-channel video cap by default — the archive's value is being a comprehensive local search corpus, not a small curated feed, so a prolific channel gets its full history within the day window. --max-per-channel N exists only as an explicit override for deliberately bounding one run — never assume it.
refresh (no args) re-fetches metadata for every video already in raw/ and overwrites those files in place (e.g. to pick up updated view counts). Touches raw/ only — does not re-run ingest.
Report back from the JSON it prints: videos added, channels touched, total channels checked. If added: 0, say so plainly — could mean the archive's already current, or that there are no subscriptions. Mention that transcript (optional) and ingest are the next steps if anything was added.
Run:
python scripts/youtube_subscriptions.py transcript [--limit N]For each raw video without a terminal transcript result yet, calls scripts/fetch_transcript.py (importable — same folder), which pulls the caption track via youtube_transcript_api, caches it (yt_<id>.txt in the configured cache dir, C:\tmp by default on Windows), throttles between requests, and retries with backoff on IP/rate blocks.
On success, the transcript text is written to two places: appended onto the raw .md file itself as a ## Transcript section directly after the description (the canonical copy — write_transcript_into_raw_file, idempotent, replaces rather than duplicates on a re-run), and a plain-text <date>-<id>.transcript.txt sidecar next to it (convenience copy only). refresh re-writing a raw file's metadata preserves an existing Transcript section rather than wiping it.
Three outcomes per video, tracked in _transcript-index.tsv:
## Transcript section on the raw file (reading "Unavailable"), so this is distinguishable at a glance from "not attempted yet". Terminal (indexed, not retried) — there's no audio-transcription fallback.transcript run rather than silently given up on.Use --limit N before a big run, same as ingest. This can be slow at archive scale (thousands of videos, throttled ~1.5s apart plus request time) — don't run it unprompted against the full untried backlog; confirm the scope with Jeffrey first if it's more than a handful.
Report back from the JSON: fetched, already_cached, unavailable, errors_this_run, remaining_untried.
Not yet built (Phase 2, only after Phase 1 is proven — see decisions/log.md, 2026-08-14): chapter-based slicing for 3+ hour videos via yt-dlp chapter metadata, and bulk concurrent fetch via ThreadPoolExecutor for faster large runs. fetch_transcript.py also supports an optional Webshare rotating proxy (YT_WEBSHARE_USER/YT_WEBSHARE_PASS in .env) if IP blocks turn out to be a real problem in practice — off by default, not yet needed.
Run:
python scripts/youtube_subscriptions.py ingestDefault scope is everything currently un-ingested in raw/ — the script tracks what's already been processed (raw/youtube-videos/_ingest-index.tsv) so re-running only picks up what's new since the last ingest. For testing before a big run, use --limit N to process just the first N (this short-circuits properly — it doesn't scan the whole archive first and then slice).
For each raw video, the script:
CONCEPT_TAXONOMY and ENTITY_TAXONOMY (both defined in the script) — a fixed keyword taxonomy, not an LLM call per video (wouldn't scale to a whole-archive ingest). Concepts = categories/frameworks ("Automation", "CRM"); entities = named products/companies ("GoHighLevel", "Claude"). Extend either dict directly when a real recurring topic isn't getting caught. MAX_CONCEPTS_PER_VIDEO is 12 (raised from 6 the same day, to give the much larger transcript-driven match surface room — a video with a thin promo-link description but a substantive transcript can now surface far more of its real topics instead of getting capped at whatever the description happened to mention). MAX_ENTITIES_PER_VIDEO stays 4. The unavailable-transcript placeholder text is explicitly excluded from matching, so a video with no captions can't accidentally pick up a stray tag from it.wiki/sources/youtube-videos/<Channel>/<Title> [ID].md page — full metadata, real line breaks, chapter timestamps linked to that exact moment in the video, and outbound ## Concepts / ## Entities sections linking to whatever it matched.wiki/concepts/<slug>.md or wiki/entities/<slug>.md), or appends this source to an existing page's sources: frontmatter and a dedicated ## Linked Video Sources section — never touches any other part of an existing page, so hand-written prose on a concept page is always safe.index.md — lists PAGES only (concepts/entities), never individual video sources. A bulk ingest can add thousands of sources in one run; listing each in index.md would reproduce the exact bloat problem master-list.md (the old flat archive's index) hit before this restructure. Browse video sources via wiki/sources/youtube-videos/<Channel>/ directly, or through whichever concept/entity page links to them.log.md entry per ingest run (not one per video) summarizing counts.Report back from the JSON: videos ingested, concepts/entities created vs. updated, remaining un-ingested count.
Known real bugs already found and fixed here — don't reintroduce any of them:
rstrip + one newline.sources: entries must be quoted ("[[Page Name]]", not bare [[Page Name]]) — video source page names contain [Video ID], and an unquoted entry produces ambiguous nested YAML flow-sequence brackets that can break a real YAML parser (Dataview, etc.) even though Obsidian's own frontmatter reader tolerates it._ingest-index.tsv), not a full directory walk + per-file existence check — that made even a --limit 5 test scan and disk-check all ~11,800 raw files before doing anything. video_id comes straight out of the filename (fixed-width date prefix), not from opening/parsing every file just to filter.parse_raw_file must split the Transcript section off rest before treating it as the description — once the transcript phase started appending a ## Transcript section onto the same raw .md file (2026-08-14), a naive "everything after the title line is the description" swallowed the transcript into the description, producing a duplicated/malformed ## Transcript heading on the resulting wiki page. Caught in testing that same day, before it ever reached the real archive.Ask (via AskUserQuestion): researching a topic, browsing a specific channel, or the whole archive?
wiki/concepts/<slug>.md or wiki/entities/<slug>.md page already exists first — if so, Read it directly, its ## Linked Video Sources (or hand-written equivalent) already lists every source that touches it. Far cheaper than grepping. Only fall back to Grep-ing wiki/sources/youtube-videos/**/*.md if no matching concept/entity page exists (a genuinely new topic the taxonomy hasn't caught yet).wiki/sources/youtube-videos/<Channel Name>/ directly.wiki/sources/youtube-videos/**/*.md.Every one of these produces a full-metadata report, not a chat summary — see "Report format" below.
Before building, ask (AskUserQuestion) two things:
## Transcript section verbatim (e.g. "Not fetched yet") rather than blank space.One channel subheading per channel in scope, each video underneath with its full metadata block (Title, URL, Video ID, Views, Published, Description, Transcript, Tags/Concepts/Entities, Added) — Transcript positioned right after Description, same order as the source pages themselves. This is a reference document — completeness matters more than brevity; for "list every video," list every single one, no "and N more."
Sort order: newest first, oldest last — always. Within every channel section (and within a topic report's matches, whether grouped by channel or flat), sort by the Published field descending before rendering. Source pages/raw files aren't stored in date order (filenames are title-based, not date-prefixed), so this means an explicit sort step in the report-building script — don't rely on directory listing order, which is alphabetical by title and not remotely chronological.
Data source: wiki/sources/youtube-videos/<Channel>/*.md (or the matched concept/entity page's linked sources, for a topic report) — never Read these in bulk to build the report (dumps every entry into the visible tool trace, exactly what publishing to an Artifact is meant to avoid). Build the report with a script that reads the source files and writes the output on disk without printing the content.
Timestamps: chapter-marker lines (e.g. "0:00 Intro") should link to that exact moment in the video, matching what the source pages already have — apply the same linkify_timestamp_line-equivalent logic if re-deriving from raw text.
Line breaks: if reading from wiki/sources/ pages, they already have real formatting (source pages are written with real newlines and <br> hard breaks, not the old single-line-escaped storage format master-list.md used to require) — no restoration needed. Only raw/ files might still need this if reading from there directly, and even those store real newlines now (verbatim, not escaped — that escaping was specific to the old shared-file format).
Size and encoding, at full-archive scale (thousands of videos):
content.replace(chr(0xFFFD), "")) — a genuinely corrupted character in one video's source data will otherwise make the Artifact deploy fail outright with an encoding error on the whole file. Cheap to always do.Publish as an Artifact (Markdown file) — load artifact-design first per its own requirement, keep the design plain/functional (this is a reference dump, not a marketing page), favicon 📺. Each report is a genuinely new document per query (different scope/choice = different content), so publish a fresh Artifact each time rather than trying to update a prior one.
playlistItems/channels().list batching instead of search().list, so even 100+ subscriptions stay well under YouTube's 10,000-unit daily free quota per fetch.raw/youtube-videos/_fetch-index.tsv tracks what's been pulled from YouTube (fetch's concern); raw/youtube-videos/_transcript-index.tsv tracks caption-fetch attempts, terminal outcomes only — ok/cached/unavailable, never a transient error (transcript's concern); raw/youtube-videos/_ingest-index.tsv tracks what's been processed into the wiki (ingest's concern). A video can be fetched but not yet transcript-fetched or ingested — that's the normal in-between state, not a bug.youtube_transcript_api scrapes the caption track directly, a completely separate mechanism from the fetch phase's OAuth-based API calls.auth, not a full re-setup..claude/rules/skill-authoring.md's symptom table rather than re-explaining the same fix in a future conversation.Brain Matter/, check it's actually this skill's own output — Brain Matter/wiki/ is shared space with other things, including at least one other skill (youtube-video-summaries, a completely different skill with a similarly-named output folder, wiki/Video Summaries/ — capitalized, space-separated, NOT the same as this skill's wiki/sources/youtube-videos/). A file belonging to that skill was found misplaced inside this skill's old folder and nearly lost during a cleanup pass — always verify a file's actual owner/origin before deleting it as "old stuff."Thanks to Ryan Cunningham for providing the code that powers the transcript-fetch phase — the fetch_transcript.py script and its integration into the ingest pipeline, including cache-first logic, retry behavior with backoff, and the approach to handling unavailable transcripts gracefully. Added 2026-08-14.
© EfficientStreet, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 9 other files (scripts) in the repository root of EfficientStreet/youtube-subscriptions-ingest.
Open the folder on GitHubat commit 26f91e3
Subscription Videos Metadata next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Subscription Videos Metadata this skillEfficientStreet/youtube-subscriptions-ingest | 180 | — | ~7.1k | Automated safety check: Notes | MIT | |
| Youtube Transcriptglebis/claude-skills | 391 | — | ~613 | Automated safety check: Pass | MIT | |
| Obsidian Canvas BoardsAgriciDaniel/claude-obsidian | 15k | — | ~1.4k | Automated safety check: Pass | MIT | |
| Video To NotesKIRVO-REPORTING/video-to-notes | 105 | — | ~1.5k | Automated safety check: Pass | MIT | |
| Video Lenskar2phi/video-lens | 113 | — | ~8.2k | Automated safety check: Notes | MIT | |
| Youtube Transcript Analysis API Skillbrowser-act/skills | 6.1k | 1 repos | ~3.6k | Automated safety check: Pass | MIT |
glebis/claude-skills
Extract YouTube video transcripts with metadata and save as Markdown to Obsidian vault.
AgriciDaniel/claude-obsidian
Creates, inspects and updates Obsidian JSON Canvas boards in a vault, with text, file, link, group and edge nodes, using safe recoverable edits.
KIRVO-REPORTING/video-to-notes
Use immediately for any bare YouTube or YouTube Shorts URL, youtu.be link, Bilibili or b23.tv link, or other video URL; do not ask what the user wants.
kar2phi/video-lens
Fetch a YouTube transcript and generate an executive summary, key points, and timestamped topic list as a polished HTML report.
browser-act/skills
This skill helps users extract YouTube video transcripts and perform deep competitive analysis on the content.
browser-act/skills
This skill helps users automatically extract YouTube video transcripts and metadata via the BrowserAct API.
Categories
Pull metadata from YouTube subscription videos into a second-brain vault as a real cross-linked knowledge graph — not just a flat archive. Subscription Videos Metadata is an agent skill from EfficientStreet/youtube-subscriptions-ingest. Pull metadata from YouTube subscription videos into a second-brain vault as a real cross-linked knowledge graph — not just a flat archive.
Subscription Videos Metadata fits situations like: pull my subscription videos; fetch latest subscription videos; ingest my videos; update my video list.
Run `npx skills add EfficientStreet/youtube-subscriptions-ingest --skill subscription-videos-metadata -a claude-code`. Or copy the skill folder (the EfficientStreet/youtube-subscriptions-ingest repository) into .claude/skills/subscription-videos-metadata in your project. Claude Code loads it when a task matches its description.
Run `npx skills add EfficientStreet/youtube-subscriptions-ingest --skill subscription-videos-metadata -a codex`. Or copy the skill folder (the EfficientStreet/youtube-subscriptions-ingest repository) into .agents/skills/subscription-videos-metadata in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add EfficientStreet/youtube-subscriptions-ingest --skill subscription-videos-metadata -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/subscription-videos-metadata, .gemini/skills/subscription-videos-metadata, .github/skills/subscription-videos-metadata and .opencode/skills/subscription-videos-metadata in your project.
Going by SKILL.md and its folder, Subscription Videos Metadata needs Python for the scripts in its folder, the command-line tools its instructions call (python) and credentials named GOOGLE_YOUTUBE_CLIENT_SECRET. Our summary lists: Python 3; A credential in GOOGLE_YOUTUBE_CLIENT_SECRET. Its frontmatter pre-approves these tools: Bash(python "${CLAUDE_PROJECT_DIR}/scripts/youtube_subscriptions.py":*), Bash(python "${CLAUDE_PROJECT_DIR}/scripts/fetch_transcript.py":*), Read, Grep, AskUserQuestion, Artifact.
SKILL.md names 1 domain. As links in the text: github.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Subscription Videos Metadata is published under the MIT licence (from the LICENSE file in the skill folder). It allows redistribution, so the full SKILL.md is shown on this page.
About 7.1k tokens (SKILL.md is roughly 28k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Subscription Videos Metadata: Youtube Transcript (glebis/claude-skills, 391 stars), Obsidian Canvas Boards (AgriciDaniel/claude-obsidian, 15k stars), Video To Notes (KIRVO-REPORTING/video-to-notes, 105 stars) and Video Lens (kar2phi/video-lens, 113 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
EfficientStreet (a GitHub user) maintains it in EfficientStreet/youtube-subscriptions-ingest, which has 180 GitHub stars. The repository was last updated on August 14, 2026.
Source: EfficientStreet/youtube-subscriptions-ingest on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.