livestill
v0.1.0
Published
Capture current still frames from YouTube live streams.
Maintainers
Readme
📸 LiveStill
Capture one still frame from a YouTube live/video stream.
Channel → live video → stream URL → image.
✨ Features
- 🔴 Find the current live video for a YouTube channel
- 🖼️ Capture one frame as a
Bufferor file - 🧰 Use as an SDK or CLI
- 🧪 Mockable command runner for tests
- 🚫 No AI, OCR, browser automation, or scraping UI required
📦 Install
npm install livestillLiveStill shells out to these tools:
brew install yt-dlp ffmpeg⚡ SDK
import { writeFile } from "node:fs/promises";
import { captureYouTubeLiveFrame, findYouTubeLiveVideo } from "livestill";
const status = await findYouTubeLiveVideo({ url: "https://www.youtube.com/@marvel/" });
if (!status.isLive) {
throw new Error("Channel is not live");
}
const frame = await captureYouTubeLiveFrame(status.video.url, { format: "jpg" });
await writeFile("frame.jpg", frame.image);🖥️ CLI
# Find current live URL
livestill live @marvel
livestill live https://www.youtube.com/@marvel/ --json
# Capture a frame
livestill capture @marvel --out marvel.jpg
livestill capture https://www.youtube.com/watch?v=f17J3AXVK5w --out frame.jpg🧩 API
findYouTubeLiveVideo(options)
await findYouTubeLiveVideo({ handle: "@marvel" });
await findYouTubeLiveVideo({ channelId: "UCxxxxxxxxxxxxxxxxxxxxxx" });
await findYouTubeLiveVideo({ url: "https://www.youtube.com/@marvel/" });Returns:
type YouTubeLiveStatus =
| { isLive: false }
| { isLive: true; video: { videoId: string; url: string; title?: string } };captureYouTubeLiveFrame(youtubeUrl, options?)
const frame = await captureYouTubeLiveFrame("https://www.youtube.com/watch?v=...", {
outputPath: "frame.jpg",
});Lower-level helpers
resolveDirectStreamUrl(youtubeUrl, options?)captureFrame(streamUrl, options?)createYouTubeWatchUrl(videoId)
☁️ Runtime notes
| Runtime | Status | Notes |
| --- | --- | --- |
| Node server / container | ✅ | Install yt-dlp + ffmpeg |
| AWS Lambda | ✅ | Bundle binaries in a layer/container |
| Edge/browser runtimes | ❌ | No child processes/filesystem |
Direct stream URLs expire. Resolve close to capture time and keep yt-dlp
updated.
🧪 Verify
pnpm run verify
pnpm run test:integration
pnpm packMIT
