| name | media-fetcher |
| description | Fetch supplementary media (logos, GIFs, landing pages, diagrams, videos) to accompany video clips. Uses APIs and Playwright MCP for browser automation. |
Media Fetcher Skill
Fetches contextual media assets to supplement video clips created by the clipper skill. Retrieves logos, reaction GIFs, landing page screenshots, diagrams, and social media videos based on content mentioned in clips.
Prerequisites
Required MCP Server: Playwright
This skill requires the Microsoft Playwright MCP server for browser automation. Add to your Claude Code MCP settings:
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest", "--caps", "vision", "--headless"]
}
}
}
Required Tools
-
yt-dlp: For downloading videos from YouTube, TikTok, Instagram, X
brew install yt-dlp
pip install yt-dlp
-
Node.js 18+: For Mermaid diagram rendering
npm install -g @mermaid-js/mermaid-cli
Optional API Keys (Environment Variables)
Set these for enhanced functionality:
export GIPHY_API_KEY="your_key"
export BRANDFETCH_API_KEY="your_key"
Quick Start
When the clipper skill has created segments.json, you can fetch media for the clips:
User: "Fetch media for my clips"
You will automatically:
- Read
segments.json to understand clip content
- Extract entities (products, companies, concepts) from each clip
- Fetch relevant media for each clip
- Save to
media/ directory with manifest
Workflow
Step 1: Analyze Clip Content
Read segments.json from the clipper skill. For each clip, extract:
- Companies/Products: Brand names mentioned (for logos, landing pages)
- Concepts: Technical terms (for diagrams)
- Emotions: Reactions, humor (for GIFs)
- References: URLs, videos mentioned (for screenshots, video clips)
- Timestamps: When each entity is mentioned (for timing media overlays)
Important: Always note the timestamp (in seconds) when each entity is mentioned. This is critical for timing media overlays correctly in the final video.
Example analysis:
Clip: "014_When_Will_Local_LLMs_Be_Worth_It.mp4"
Duration: 32.5s
Entities with timestamps:
- 0:02 - "local LLMs" → diagram showing local vs cloud
- 0:08 - "Ollama" → Ollama logo
- 0:12 - "LM Studio" → LM Studio logo
- 0:18 - "NVIDIA" → NVIDIA logo
- 0:25 - "mid 2026" → timeline diagram
Step 2: Fetch Media by Type
For each clip, determine what media would enhance it:
Logos (Companies/Products Mentioned)
Use the Brandfetch CDN (no API key needed):
python .claude/skills/media-fetcher/scripts/fetch_logos.py "github.com" "vercel.com" --output media/logos/
Or use Playwright MCP to:
- Navigate to the company website
- Screenshot the logo element
- Save to
media/logos/
Reaction GIFs (Emotional Moments)
python .claude/skills/media-fetcher/scripts/fetch_gifs.py "mind blown" "excited" --output media/gifs/
Requires GIPHY_API_KEY environment variable.
Landing Pages (Products/Services Mentioned)
Use the capture_screenshot.py script which automatically matches video dimensions:
python .claude/skills/media-fetcher/scripts/capture_screenshot.py \
"https://github.com/aj47/SpeakMCP" \
"https://speakmcp.com" \
--video clips/001_Example.mp4 \
--output media/screenshots/
python .claude/skills/media-fetcher/scripts/capture_screenshot.py \
"https://vercel.com" \
--width 1080 --height 1920
Dimension Matching:
- Screenshots match your clip video dimensions exactly (ready for overlay)
- Default: Portrait 1080x1920 (9:16 for TikTok/Reels/Shorts)
- Uses ffprobe to detect video dimensions automatically
- Captures viewport only (not full page) to maintain exact dimensions
Alternative: Use Playwright MCP directly for interactive capture:
1. browser_navigate("https://vercel.com")
2. [Claude sees the page, decides to dismiss cookie banner]
3. browser_click("[data-testid='cookie-accept']")
4. browser_screenshot() -> save to media/screenshots/vercel.png
Diagrams (Technical Concepts)
Generate Mermaid diagrams based on clip content:
python .claude/skills/media-fetcher/scripts/render_diagram.py diagram.mmd --output media/diagrams/
Process:
- Analyze the technical content in the clip
- Generate appropriate Mermaid diagram code
- Render to PNG using mermaid-cli
Videos (YouTube, TikTok, Instagram, X)
When a clip references a video or you find a relevant one:
python .claude/skills/media-fetcher/scripts/download_video.py "https://youtube.com/watch?v=xxx" --output media/videos/
Discovery workflow using Playwright MCP:
browser_navigate to YouTube/TikTok search
- Enter search query based on clip keywords
- Claude reviews results and selects most relevant
- Extract video URL
- Download using yt-dlp
Step 3: Create Media Manifest
After fetching, create media_manifest.json with timestamp information for each media asset:
{
"generated_at": "2025-01-15T10:30:00Z",
"clips": [
{
"clip_file": "001_OAuth_Setup_Guide.mp4",
"clip_title": "OAuth Setup Guide",
"clip_duration": 45.5,
"media": [
{
"type": "logo",
"source": "brandfetch",
"entity": "github.com",
"path": "media/logos/github.png",
"relevance": "GitHub mentioned as OAuth provider",
"timestamp_start": 5.0,
"timestamp_end": 12.0,
"trigger_text": "we're going to use GitHub for OAuth"
},
{
"type": "screenshot",
"source": "playwright",
"url": "https://github.com/settings/developers",
"path": "media/screenshots/github_oauth_settings.png",
"relevance": "OAuth app registration page shown",
"timestamp_start": 15.5,
"timestamp_end": 25.0,
"trigger_text": "go to your GitHub developer settings"
},
{
"type": "diagram",
"source": "mermaid",
"description": "OAuth flow diagram",
"path": "media/diagrams/oauth_flow.png",
"relevance": "Visualizes the authentication flow discussed",
"timestamp_start": 30.0,
"timestamp_end": 42.0,
"trigger_text": "the flow works like this"
}
]
}
],
"shared_media": {
"gifs": [
{
"query": "mind blown",
"files": ["media/gifs/mind_blown_001.mp4"],
"use_for": "Impressive technical moments"
}
]
},
"summary": {
"total_clips": 15,
"logos_fetched": 8,
"screenshots_captured": 12,
"gifs_downloaded": 5,
"diagrams_generated": 3,
"videos_downloaded": 2
}
}
Media Manifest Schema
Each media item in a clip should include:
| Field | Type | Required | Description |
|---|
type | string | Yes | Media type: logo, screenshot, diagram, gif, video |
path | string | Yes | Relative path to the media file |
relevance | string | Yes | Why this media is relevant to the clip |
timestamp_start | float | Yes | Seconds into the clip when media should appear |
timestamp_end | float | No | Seconds when media should disappear (default: start + 5s) |
trigger_text | string | No | The spoken text that triggers this media |
source | string | No | Where the media came from (brandfetch, playwright, giphy, mermaid) |
entity | string | No | For logos: the domain (e.g., "github.com") |
url | string | No | For screenshots: the source URL |
Determining Timestamps
To find the right timestamps for media:
- From segments.json: If the clipper skill provides word-level timestamps, use those to find when entities are mentioned
- From transcription: Search for trigger phrases like "let me show you", "as you can see", or entity names
- Manual review: Watch the clip and note when visual aids would help
Example workflow with transcription timestamps:
Transcription: "...at 5.2s: 'GitHub' ...at 15.8s: 'developer settings'..."
→ Logo appears at 5.0s (slightly before mention)
→ Screenshot appears at 15.5s
Media Types Reference
See MEDIA_TYPES.md for detailed guidance on:
- When to use each media type
- Quality considerations
- Best practices for each source
Scripts Reference
fetch_logos.py
Fetches company logos using Brandfetch CDN.
python .claude/skills/media-fetcher/scripts/fetch_logos.py <domain1> [domain2...] [--output DIR]
Arguments:
domains: One or more company domains (e.g., "github.com", "stripe.com")
--output: Output directory (default: "media/logos/")
Output: PNG files named by domain
fetch_gifs.py
Searches and downloads GIFs from GIPHY.
python .claude/skills/media-fetcher/scripts/fetch_gifs.py <query1> [query2...] [--output DIR] [--limit N]
Arguments:
queries: Search terms (e.g., "mind blown", "celebration")
--output: Output directory (default: "media/gifs/")
--limit: Max GIFs per query (default: 3)
Requires: GIPHY_API_KEY environment variable
download_video.py
Downloads videos using yt-dlp.
python .claude/skills/media-fetcher/scripts/download_video.py <url1> [url2...] [--output DIR] [--max-duration SECONDS]
Arguments:
urls: Video URLs (YouTube, TikTok, Instagram, X, etc.)
--output: Output directory (default: "media/videos/")
--max-duration: Skip videos longer than N seconds (default: 300)
Requires: yt-dlp installed
render_diagram.py
Renders Mermaid diagrams to PNG.
python .claude/skills/media-fetcher/scripts/render_diagram.py <input.mmd> [--output DIR]
Arguments:
input: Mermaid diagram file (.mmd)
--output: Output directory (default: "media/diagrams/")
Requires: @mermaid-js/mermaid-cli (mmdc) installed
capture_screenshot.py
Captures screenshots with dimensions matching your video clips.
python .claude/skills/media-fetcher/scripts/capture_screenshot.py <url1> [url2...] [options]
Arguments:
urls: One or more URLs to capture
--video, -v: Video file to match dimensions from (uses ffprobe)
--width, -W: Viewport width (default: 1080)
--height, -H: Viewport height (default: 1920)
--output, -o: Output directory (default: "media/screenshots/")
Features:
- Auto-detects video dimensions via ffprobe
- Default: Portrait 1080x1920 (9:16 ratio for TikTok/Reels/Shorts)
- Auto-dismisses cookie banners and popups
- 2x device scale for retina quality
- Viewport-only capture (matches exact dimensions)
Requires: playwright Python package, Chromium browser
Using Playwright MCP for Browser Tasks
For landing pages and video discovery, use the Playwright MCP tools directly:
Available Tools
| Tool | Description |
|---|
browser_navigate | Go to URL |
browser_screenshot | Capture current page |
browser_click | Click element by selector or text |
browser_type | Type text into input field |
browser_scroll | Scroll page up/down |
browser_snapshot | Get accessibility tree (structured data) |
Example: Capture Landing Page
1. browser_navigate("https://stripe.com")
→ Page loads, Claude sees accessibility snapshot
2. [If cookie banner detected]
browser_click("Accept cookies")
→ Banner dismissed
3. browser_screenshot()
→ Returns base64 image, save to media/screenshots/stripe.png
Example: Find YouTube Video
1. browser_navigate("https://youtube.com")
2. browser_type("[name='search_query']", "OAuth tutorial 2024")
3. browser_click("[id='search-icon-legacy']")
→ Search results load
4. [Claude reviews results, picks most relevant]
browser_snapshot()
→ Get video URLs from accessibility tree
5. Extract URL, pass to download_video.py
Output Structure
media/
├── logos/
│ ├── github.png
│ ├── vercel.png
│ └── stripe.png
├── screenshots/
│ ├── github_oauth_settings.png
│ └── stripe_dashboard.png
├── gifs/
│ ├── mind_blown_001.gif
│ └── celebration_001.gif
├── diagrams/
│ ├── oauth_flow.png
│ └── api_architecture.png
├── videos/
│ ├── youtube_abc123.mp4
│ └── tiktok_xyz789.mp4
└── media_manifest.json
Integration with Clipper Skill
This skill is designed to work alongside the clipper skill:
- Clipper analyzes transcription → creates
segments.json with word-level timestamps
- Media-fetcher reads
segments.json → extracts entities AND their timestamps
- Media-fetcher fetches relevant media for each entity
- Media-fetcher creates
media_manifest.json linking media to clips with precise timestamps
- Output: Clips in
clips/ or highlights/ + media in media/ + media_manifest.json
Getting Timestamps from segments.json
The clipper skill's segments.json contains word-level timing. Use this to find when entities are mentioned:
{
"segments": [
{
"file": "014_When_Will_Local_LLMs_Be_Worth_It.mp4",
"words": [
{"word": "local", "start": 2.1, "end": 2.4},
{"word": "LLMs", "start": 2.5, "end": 2.9},
{"word": "Ollama", "start": 8.2, "end": 8.7}
]
}
]
}
When creating media entries, use these timestamps:
{
"type": "logo",
"entity": "ollama.com",
"path": "media/logos/ollama_com.png",
"timestamp_start": 8.0,
"timestamp_end": 13.0,
"trigger_text": "Ollama"
}
If No Word-Level Timestamps Available
If only clip-level info exists:
- Use
ffprobe to get clip duration
- Watch/listen to the clip to identify key moments
- Estimate timestamps based on content flow
Troubleshooting
"Playwright MCP not found": Ensure the MCP server is configured in your Claude Code settings. Run npx @playwright/mcp@latest to verify it's installed.
"yt-dlp: command not found": Install with brew install yt-dlp or pip install yt-dlp.
"GIPHY_API_KEY not set": Get a free API key from developers.giphy.com and set the environment variable.
"mmdc: command not found": Install Mermaid CLI with npm install -g @mermaid-js/mermaid-cli.
Rate limits: GIPHY has 100 requests/hour on beta keys. Brandfetch CDN has no limits. YouTube search via Playwright has no API limits.