Transcript Scripts
Ready-to-run transcript examples with benchmark results
The lyra-sdk repo includes runnable scripts in the scripts/ directory for testing transcript features. All transcript scripts run without a YouTube API key.
Prerequisites
No API key is needed. Just run:
npx tsx scripts/transcript-basic.tsBasic Transcript
Fetches and prints all transcript lines with timestamps.
import { transcribeVideo, toPlainText } from '../packages/core/src/modules/transcript.js'
const lines = await transcribeVideo('dQw4w9WgXcQ')
for (const line of lines) {
console.log(`[${line.offset.toFixed(1)}s] ${line.text}`)
}
console.log(toPlainText(lines))Expected output:
Fetching transcript for: dQw4w9WgXcQ
Got 61 lines
[0.0s] ♪ We're no strangers to love ♪
[3.6s] ♪ You know the rules and so do I ♪
[6.0s] ♪ A full commitment's what I'm thinking of ♪
...List Caption Languages
Discovers all available caption tracks for a video.
import { listCaptionTracks } from '../packages/core/src/modules/transcript.js'
const tracks = await listCaptionTracks('dQw4w9WgXcQ')
for (const track of tracks) {
const auto = track.isAutoGenerated ? ' (auto-generated)' : ''
console.log(` ${track.languageCode} — ${track.languageName}${auto}`)
}Expected output:
Fetching caption tracks for: dQw4w9WgXcQ
Found 2 caption track(s):
en — English (auto-generated)
es — SpanishTranscript with Metadata
Fetches transcript lines plus video metadata, then outputs in SRT, VTT, and plain text formats.
import { transcribeVideo, toSRT, toVTT, toPlainText } from '../packages/core/src/modules/transcript.js'
const result = await transcribeVideo('dQw4w9WgXcQ', { includeMeta: true })
console.log(result.meta.title) // Video title
console.log(result.meta.author) // Channel name
console.log(result.meta.views) // View count
// Output as SRT
console.log(toSRT(result.lines))
// Output as VTT
console.log(toVTT(result.lines))
// Plain text
console.log(toPlainText(result.lines))TranscriptClient
Demonstrates the class-based API with shared configuration.
import { TranscriptClient } from '../packages/core/src/modules/transcript.js'
const client = new TranscriptClient({ lang: 'en' })
const lines = await client.transcribe('dQw4w9WgXcQ')
const tracks = await client.availableTracks('dQw4w9WgXcQ')Cache Benchmark
Compares no-cache vs InMemoryCache vs FsCache performance across multiple runs.
npx tsx scripts/transcript-cache-bench.tsHow it works
Run 1: No Cache (baseline)
Fetches the transcript 3 times with no caching. Every call makes 3 HTTP requests to YouTube (watch page, Innertube API, transcript XML).
Run 2: InMemoryCache
Creates a new InMemoryCache() and fetches 3 times. The first call is a cold fetch; runs 2 and 3 read from the in-process Map.
Run 3: FsCache
Creates a new FsCache() pointing to a temp directory and fetches 3 times. The first call is a cold fetch; runs 2 and 3 read from JSON files on disk.
Summary metrics
The script calculates averages, cache hit times, and speedup ratios for each strategy.
Sample results
=== Cache Benchmark: dQw4w9WgXcQ ===
--- No Cache ---
Run 1: 1791ms (cold — 3 HTTP requests)
Run 2: 1567ms (cold — 3 HTTP requests)
Run 3: 1547ms (cold — 3 HTTP requests)
Avg: 1635ms
--- InMemoryCache ---
Run 1: 1629ms (cold — 3 HTTP requests)
Run 2: 0.04ms (cache HIT — 61 lines from cache)
Run 3: 0.02ms (cache HIT — 61 lines from cache)
Avg: 543ms | Cache entries: 1
--- FsCache ---
Run 1: 1704ms (cold — 3 HTTP requests)
Run 2: 0.37ms (cache HIT — 61 lines from cache)
Run 3: 0.20ms (cache HIT — 61 lines from cache)
Avg: 568ms
=== Summary ===
No Cache avg: 1635ms
InMemoryCache avg: 543ms (3.0x faster overall)
FsCache avg: 568ms (2.9x faster overall)
InMemoryCache hit: ~0.03ms (44561x faster than no-cache)
FsCache hit: ~0.27ms (5560x faster than no-cache)| Strategy | Cold fetch | Cache hit | Overall avg |
|---|---|---|---|
| No Cache | ~1600ms | N/A | ~1635ms |
| InMemoryCache | ~1600ms | ~0.03ms | ~543ms |
| FsCache | ~1700ms | ~0.27ms | ~568ms |
Retry Benchmark
Tests retry behavior with simulated failures and shows backoff timing.
npx tsx scripts/transcript-retry-bench.tsHow it works
Test 1: Baseline (no retries)
Fetches a transcript with retries: 0. Measures raw fetch time as a baseline.
Test 2: Recovery after failure
Uses a custom fetch that returns 503 once, then succeeds with real data. Shows the overhead of a single retry.
Test 3: Exhausted retries
All requests return 503. Shows the full exponential backoff timeline over 3 attempts.
Test 4: AbortSignal cancellation
Aborts after 150ms during retries. Demonstrates early termination.
Sample results
=== Retry Benchmark ===
--- Test 1: No retries, success (baseline) ---
Time: 1299ms
Attempts: 1
--- Test 2: retries=3, retryDelay=100 — recovers after 1 failure ---
0ms → Attempt 1: 503 (retryable, waiting 100ms)
1489ms → Attempt 2: 200 OK — 61 lines
Time: 1489ms (115% of baseline)
Attempts: 2 (1 failed + 1 succeeded)
Overhead: ~190ms from retry
--- Test 3: retries=2, retryDelay=200 — all requests fail ---
50ms → Attempt 1: 503 (retryable, waiting 200ms)
300ms → Attempt 2: 503 (retryable, waiting 400ms)
750ms → Attempt 3: 503 (retries exhausted)
Time: 604ms
Attempts: 3 (all failed)
Backoff: 200ms, 400ms
--- Test 4: retries=5, retryDelay=100 — aborted after ~150ms ---
Aborted: true
Time: 151ms (stopped early by AbortSignal)| Test | Retries | Outcome | Total time | Backoff delays |
|---|---|---|---|---|
| Baseline | 0 | Success | ~1300ms | — |
| Recovery | 3 | Success (retry) | ~1490ms | 100ms |
| Exhausted | 2 | All fail | ~604ms | 200ms, 400ms |
| Abort | 5 | Cancelled | ~151ms | stopped early |