npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

youtube2md

v1.0.1

Published

Convert a YouTube video to a Markdown summary file

Readme

youtube2md

npm version npm downloads

Convert any YouTube video into a structured Markdown summary — with chapter detection, clickable timestamp links, and key takeaways.

Two modes:

  • Standalone — fetch transcript + summarize with OpenAI → write Markdown file
  • Extract-only — fetch transcript only, no API key required → output JSON for external processing

Install

npm install -g youtube2md

Or use without installing:

OPENAI_API_KEY=sk-... npx youtube2md --url https://youtu.be/VIDEO_ID

Usage

# Basic usage
youtube2md --url https://www.youtube.com/watch?v=VIDEO_ID

# Custom output path
youtube2md --url https://youtu.be/VIDEO_ID --out ./notes/video.md

# Custom output directory (files saved as <video_id>.md)
youtube2md --url https://youtu.be/VIDEO_ID --out-dir ./output

# Set summary language
youtube2md --url https://youtu.be/VIDEO_ID --lang Korean

# Use a specific model
youtube2md --url https://youtu.be/VIDEO_ID --model gpt-5-mini

# Extract transcript only (no API key required if captions are available)
youtube2md --url https://youtu.be/VIDEO_ID --extract-only

# Machine-readable JSON output from full pipeline
youtube2md --url https://youtu.be/VIDEO_ID --json --stdout

Output is saved to ./summaries/<video_id>.md (full pipeline) or ./summaries/<video_id>.json (extract-only) by default.

Options

| Option | Description | |---|---| | --url <youtube_url> | YouTube video URL (required) | | --model <model> | OpenAI model to use (default: gpt-5-mini). Overrides OPENAI_MODEL env var. | | --lang <language> | Summary output language (default: same as transcript language) | | --out <path> | Output file path | | --out-dir <dir> | Output directory; file is named <video_id>.md (default: ./summaries) | | --extract-only | Skip summarization, output raw transcript as JSON | | --json | Emit result as JSON (success and errors); progress logs go to stderr | | --stdout | Write output to stdout instead of a file | | --help | Show help | | --version | Show version |

Requirements

  • Node.js 18+
  • OpenAI API key — required for summarization; not required for --extract-only when captions are available

Environment variables

| Variable | Description | |---|---| | OPENAI_API_KEY | Required for summarization. Not needed in --extract-only mode if captions are available. | | OPENAI_MODEL | Optional. Fallback model if --model is not passed (default: gpt-5-mini). |

Set your API key before running:

export OPENAI_API_KEY=sk-...
youtube2md --url https://youtu.be/VIDEO_ID

Or create a .env file in your working directory:

OPENAI_API_KEY=sk-...

Output format

Markdown (full pipeline)

# Video Title

> [Watch on YouTube](https://youtu.be/VIDEO_ID) | Duration: 12:34 | Published: 2024-01-01

## Summary

One paragraph overview of the video content.

## Chapters

### [0:00] Introduction

[▶ 0:00](https://youtu.be/VIDEO_ID?t=0)

- First key point from this section.
- Second key point from this section.

## Key Takeaways

- Key point 1
- Key point 2

JSON (extract-only)

{
  "ok": true,
  "videoId": "VIDEO_ID",
  "metadata": {
    "videoId": "VIDEO_ID",
    "title": "Video Title",
    "duration": "12:34",
    "publishDate": "2024-01-01",
    "nativeChapters": []
  },
  "segments": [
    { "text": "Hello world", "startSeconds": 0.0, "durationSeconds": 2.4 }
  ]
}

JSON (full pipeline with --json)

{
  "ok": true,
  "videoId": "VIDEO_ID",
  "metadata": { "..." },
  "outputPath": "/path/to/summaries/VIDEO_ID.md"
}

Error JSON

All errors emit a structured object when --json is active:

{ "ok": false, "code": "E_TRANSCRIPT_UNAVAILABLE", "message": "..." }

| Code | Cause | |---|---| | E_TRANSCRIPT_UNAVAILABLE | No captions found and Whisper fallback unavailable | | E_OPENAI_AUTH | OPENAI_API_KEY missing or invalid | | E_OPENAI_RATE_LIMIT | OpenAI rate limit hit | | E_WHISPER_FAILED | Whisper STT transcription failed | | E_NETWORK | Network or YouTube access error | | E_WRITE_FAILED | Could not write output file |

Transcript strategy

The tool tries these methods in order:

  1. YouTube captions via Android Innertube — uses caption tracks directly (supports json3 and XML timedtext formats)
  2. youtube-transcript fallback — retries with an alternate parser path
  3. OpenAI Whisper STT fallback — downloads audio and transcribes it (requires OPENAI_API_KEY; audio must be under 25 MB). Skipped in --extract-only mode when no API key is set.

Summary process

Summarization runs in two modes based on transcript token count (using tiktoken with model-aware encoding):

  1. Normalize transcript: convert each segment to [MM:SS] spoken text.
  2. Count tokens: compute transcript size with tiktoken (fallback to o200k_base).
  3. Choose mode:
    • Single-pass when total tokens are <= 5000
    • Chunked when total tokens are > 5000
  4. Single-pass mode: one GPT request with metadata, native YouTube chapters, and full transcript.
  5. Chunked mode:
    • Split into chunks targeting 5000 tokens.
    • Merge tiny final chunk (< 25% of limit) into the previous chunk.
    • Summarize each chunk in parallel (up to 4 concurrent jobs).
    • Combine chapters locally (chronological sort + dedupe).
    • One final GPT request for full-video summary and takeaways.
  6. Validate + normalize: require non-empty summary, chapters, takeaways; sort and deduplicate.
  7. Render Markdown: convert to final output.

Token thresholds

Defined in src/summarizer.ts:

| Constant | Value | Meaning | |---|---|---| | SINGLE_PASS_TOKEN_LIMIT | 5000 | Use single-pass below this | | CHUNK_TOKEN_LIMIT | 5000 | Target tokens per chunk | | MIN_LAST_CHUNK_RATIO | 0.25 | Merge final chunk if smaller than 25% of limit |


Development

# Clone and install
git clone https://github.com/sunghyo/youtube2md
cd youtube2md
npm install

# Set your API key
cp .env.example .env
# Edit .env and add your OPENAI_API_KEY

# Run without building
npx tsx src/index.ts --url https://www.youtube.com/watch?v=VIDEO_ID

Build

npm run build   # Compile TypeScript to dist/
npm run dev     # Run directly with tsx (no build needed)
npm run clean   # Remove dist/

Project structure

src/
├── index.ts       # Entry point — pipeline branching and orchestration
├── cli.ts         # CLI argument parsing (Commander)
├── youtube.ts     # Metadata fetch + transcript fetch with fallback
├── summarizer.ts  # OpenAI Responses API prompting + JSON parsing
├── markdown.ts    # Markdown generation + file writing
└── types.ts       # Shared interfaces, AppError, error codes
summaries/         # Default output directory

Attribution

This project was built with AI assistance from Claude (Anthropic) and Codex (OpenAI).