
Gemini Video Understanding
- 2 installs
- 1 repo stars
- Updated October 28, 2025
- mrgoonie/xxxnaper
Analyze videos with Gemini API to summarize, answer questions, transcribe with timestamps, clip segments, and process YouTube URLs up to 6 hours.
About
A guide to Gemini API video analysis for summarization, question answering, timestamped transcription, and clipping across 9 formats. A developer uses it to understand or compare videos, including direct YouTube URL processing.
- Supports up to 2M-token context (~6 hours) and YouTube URLs
- Timestamp references, video clipping, and multi-video comparison
Gemini Video Understanding by the numbers
- 2 all-time installs (skills.sh)
- Ranked #1,168 of 1,337 Generative Media skills by installs in the Skillselion catalog
- Data as of Jul 26, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mrgoonie/xxxnaper --skill gemini-video-understandingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 1 |
| Last updated | October 28, 2025 |
| Repository | mrgoonie/xxxnaper ↗ |
What it does
Analyze videos with Gemini API to summarize, answer questions, transcribe with timestamps, clip segments, and process YouTube URLs up to 6 hours.
Files
Gemini Video Understanding Skill
This skill enables comprehensive video analysis using Google's Gemini API, including video summarization, question answering, transcription, timestamp references, and more.
Capabilities
- Video Summarization: Create concise summaries of video content
- Question Answering: Answer specific questions about video content
- Transcription: Transcribe audio with visual descriptions and timestamps
- Timestamp References: Query specific moments in videos (MM:SS format)
- Video Clipping: Process specific segments using start/end offsets
- Multiple Videos: Compare and analyze up to 10 videos (Gemini 2.5+)
- YouTube Support: Analyze YouTube videos directly (preview feature)
- Custom Frame Rate: Adjust FPS sampling for different video types
Supported Formats
- MP4, MPEG, MOV, AVI, FLV, MPG, WebM, WMV, 3GPP
Models Available
Gemini 2.5 Series:
gemini-2.5-pro- Best quality, 1M contextgemini-2.5-flash- Balanced quality/speed, 1M contextgemini-2.5-flash-preview-09-2025- Preview features, 1M context
Gemini 2.0 Series:
gemini-2.0-flash- Fast processinggemini-2.0-flash-lite- Lightweight option
Context Windows:
- 2M token models: ~2 hours (default) or ~6 hours (low-res)
- 1M token models: ~1 hour (default) or ~3 hours (low-res)
API Key Configuration
The skill checks for GEMINI_API_KEY in this order: 1. Process environment: process.env.GEMINI_API_KEY or $GEMINI_API_KEY 2. Skill directory: .claude/skills/gemini-video-understanding/.env 3. Project root: .env file in project root
To set up:
# Option 1: Environment variable (recommended)
export GEMINI_API_KEY="your-api-key-here"
# Option 2: Skill directory .env file
echo "GEMINI_API_KEY=your-api-key-here" > .claude/skills/gemini-video-understanding/.env
# Option 3: Project root .env file
echo "GEMINI_API_KEY=your-api-key-here" > .envGet your API key at: https://aistudio.google.com/apikey
Usage Instructions
When to Use This Skill
Use this skill when the user asks to:
- Analyze, summarize, or describe video content
- Answer questions about videos
- Transcribe video audio with visual context
- Extract information from specific timestamps
- Compare multiple videos
- Process YouTube video content
- Create quizzes or educational content from videos
Basic Video Analysis
For video files:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/video.mp4" \
--prompt "Summarize this video in 3 key points"For YouTube URLs:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--youtube-url "https://www.youtube.com/watch?v=VIDEO_ID" \
--prompt "What are the main topics discussed?"Advanced Features
Video Clipping (specific time range):
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/video.mp4" \
--prompt "Summarize this segment" \
--start-offset "40s" \
--end-offset "80s"Custom Frame Rate:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/video.mp4" \
--prompt "Analyze the rapid movements" \
--fps 5Transcription with Timestamps:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/video.mp4" \
--prompt "Transcribe the audio with timestamps and visual descriptions"Multiple Videos (Gemini 2.5+ only):
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-paths "/path/video1.mp4" "/path/video2.mp4" \
--prompt "Compare these two videos and highlight the differences"Model Selection:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/video.mp4" \
--prompt "Detailed analysis" \
--model "gemini-2.5-pro"Script Parameters
Required (one of):
--video-path PATH Path to local video file
--youtube-url URL YouTube video URL
--video-paths PATH [PATH..] Multiple video paths (Gemini 2.5+)
Required:
--prompt TEXT Analysis prompt/question
Optional:
--model NAME Model to use (default: gemini-2.5-flash)
--start-offset TIME Video clip start (e.g., "40s", "1m30s")
--end-offset TIME Video clip end (e.g., "80s", "2m")
--fps NUMBER Frame sampling rate (default: 1)
--output-file PATH Save response to file
--verbose Show detailed processing infoCommon Use Cases
1. Video Summarization
Prompt: "Summarize this video in 3 key points with timestamps"2. Educational Content
Prompt: "Create a quiz with 5 questions and answer key based on this video"3. Timestamp-Specific Questions
Prompt: "What happens at 01:15 and how does it relate to the topic at 02:30?"4. Transcription
Prompt: "Transcribe the audio from this video with timestamps for salient events and visual descriptions"5. Content Comparison
Prompt: "Compare these two product demo videos. Which one explains the features more clearly?"6. Action Detection
Prompt: "List all the actions performed in this tutorial video with timestamps"Rate Limits & Quotas
Free Tier (per model):
- 10-15 RPM (requests per minute)
- 1M-4M TPM (tokens per minute)
- 1,500 RPD (requests per day)
YouTube Limitations:
- Free tier: 8 hours of YouTube video per day
- Paid tier: No length-based limits
- Public videos only (no private/unlisted)
Storage (Files API):
- 20GB per project
- 2GB per file
- 48-hour retention period
Token Calculation
Video tokens depend on resolution:
- Default resolution: ~300 tokens per second of video
- Low resolution: ~100 tokens per second of video
Example: A 10-minute video = 600 seconds × 300 tokens = ~180,000 tokens
Error Handling
Common errors and solutions:
| Error | Cause | Solution |
|---|---|---|
| 400 Bad Request | Invalid video format or corrupt file | Check file format and integrity |
| 403 Forbidden | Invalid/missing API key | Verify GEMINI_API_KEY configuration |
| 404 Not Found | File URI not found | Ensure file is uploaded and active |
| 429 Too Many Requests | Rate limit exceeded | Implement backoff, upgrade to paid tier |
| 500 Internal Error | Server-side issue | Retry with exponential backoff |
Best Practices
1. Use Files API for videos >20MB - More reliable than inline data 2. Wait for file processing - Poll until state is ACTIVE before analysis 3. Optimize FPS - Use lower FPS for static content to save tokens 4. Clip long videos - Process specific segments instead of entire video 5. Cache context - Reuse uploaded files for multiple queries 6. Batch processing - Process multiple short videos in one request (2.5+) 7. Specific prompts - Be precise about what you want to extract
Implementation Notes
For Claude Code:
When a user requests video analysis:
1. Check API key availability first using the helper script 2. Determine video source: local file, YouTube URL, or multiple videos 3. Select appropriate model based on requirements (default: gemini-2.5-flash) 4. Run the analysis script with proper parameters 5. Parse and present results to the user clearly 6. Handle errors gracefully with helpful suggestions
Files API Workflow:
For videos >20MB or reusable content: 1. Upload video using Files API (script handles this automatically) 2. Wait for ACTIVE state (polling included in script) 3. Use file URI for analysis 4. Files auto-delete after 48 hours
Inline Data Workflow:
For videos <20MB: 1. Read video file as bytes 2. Base64 encode for API 3. Send in generateContent request 4. Single-use, no upload needed
Example Workflows
Workflow 1: YouTube Video Summary
# User: "Analyze this YouTube tutorial video"
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--youtube-url "https://www.youtube.com/watch?v=abc123" \
--prompt "Create a structured summary with: 1) Main topics, 2) Key takeaways, 3) Recommended audience"Workflow 2: Interview Transcription
# User: "Transcribe this interview with timestamps"
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "interview.mp4" \
--prompt "Transcribe this interview with speaker labels, timestamps, and visual descriptions of gestures or slides shown"Workflow 3: Product Comparison
# User: "Compare these two product demo videos"
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-paths "demo1.mp4" "demo2.mp4" \
--model "gemini-2.5-pro" \
--prompt "Compare these product demos on: features shown, presentation quality, clarity of explanation, and overall effectiveness"Troubleshooting
API Key Not Found:
# Check API key detection
python .claude/skills/gemini-video-understanding/scripts/check_api_key.pyVideo Too Large:
Error: Request size exceeds 20MB
Solution: Script automatically uses Files API for large videosProcessing Timeout:
Error: File not reaching ACTIVE state
Solution: Check video integrity, try smaller file, or different formatRate Limit Errors:
Error: 429 Too Many Requests
Solution: Wait before retry, or upgrade to paid tierAdditional Resources
- API Documentation: https://ai.google.dev/gemini-api/docs/video-understanding
- Files API Guide: https://ai.google.dev/gemini-api/docs/vision#uploading-files
- Rate Limits: https://ai.google.dev/gemini-api/docs/rate-limits
- Pricing: https://ai.google.dev/pricing
- Get API Key: https://aistudio.google.com/apikey
Version History
- 1.0.0 (2025-10-26): Initial release with full video understanding capabilities
# Gemini API Key
# Get your API key at: https://aistudio.google.com/apikey
GEMINI_API_KEY=your-api-key-here
Gemini Video Understanding - Examples
Setup
1. Install dependencies:
pip install -r .claude/skills/gemini-video-understanding/requirements.txt2. Configure API key:
# Option 1: Environment variable (recommended)
export GEMINI_API_KEY="your-api-key-here"
# Option 2: Copy and edit .env file
cp .claude/skills/gemini-video-understanding/.env.example \
.claude/skills/gemini-video-understanding/.env
# Then edit the .env file with your API key3. Verify configuration:
python .claude/skills/gemini-video-understanding/scripts/check_api_key.pyBasic Examples
Example 1: Simple Video Summary
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/video.mp4" \
--prompt "Summarize this video in 3 key points"Output:
1. The video demonstrates how to use the Gemini API for video analysis
2. It covers three main input methods: Files API, inline data, and YouTube URLs
3. Examples show various use cases including transcription and timestamp queriesExample 2: YouTube Video Analysis
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--youtube-url "https://www.youtube.com/watch?v=dQw4w9WgXcQ" \
--prompt "What is this video about? List the main topics discussed."Example 3: Detailed Transcription
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/interview.mp4" \
--prompt "Transcribe this interview with timestamps and speaker labels" \
--verboseAdvanced Examples
Example 4: Video Clipping
Analyze only a specific portion of a video:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/long-video.mp4" \
--prompt "Summarize this segment" \
--start-offset "2m30s" \
--end-offset "5m15s"Example 5: High Frame Rate Analysis
For videos with fast action:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/sports.mp4" \
--prompt "Describe the key movements and techniques shown" \
--fps 5Example 6: Comparing Multiple Videos
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-paths "/path/video1.mp4" "/path/video2.mp4" \
--prompt "Compare these two product demos. Which one is more effective and why?" \
--model "gemini-2.5-pro"Example 7: Educational Content Generation
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--youtube-url "https://www.youtube.com/watch?v=VIDEO_ID" \
--prompt "Create a quiz with 5 multiple-choice questions based on this video. Include an answer key with explanations."Example 8: Timestamp-Specific Questions
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/tutorial.mp4" \
--prompt "What happens at 01:15 and 02:30? How are these two moments related?"Prompting Best Practices
For Summaries
"Provide a structured summary with:
1. Main topic or theme
2. Key points discussed (3-5 bullet points)
3. Notable quotes or moments with timestamps
4. Target audience or intended purpose"For Transcriptions
"Transcribe this video including:
- Speaker labels (Speaker 1, Speaker 2, etc.)
- Timestamps for each segment (MM:SS format)
- Visual descriptions in [brackets] when relevant
- Key gestures or on-screen text mentioned"For Educational Content
"Analyze this educational video and create:
1. Learning objectives (3-5 points)
2. Key concepts explained with timestamps
3. 5 quiz questions with multiple choice answers
4. Answer key with brief explanations"For Comparisons
"Compare these videos on the following criteria:
1. Content quality and accuracy
2. Presentation style and clarity
3. Production quality (audio, video, editing)
4. Target audience suitability
5. Overall effectiveness
Provide ratings (1-5) for each criterion with justification."Use Case Examples
Use Case 1: Meeting Notes
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "team-meeting.mp4" \
--prompt "Create meeting notes with: 1) Attendees (if visible), 2) Topics discussed with timestamps, 3) Action items identified, 4) Decisions made" \
--output-file "meeting-notes.txt"Use Case 2: Content Moderation
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "user-submitted.mp4" \
--prompt "Analyze this video for: 1) Overall content type, 2) Any inappropriate content, 3) Compliance with community guidelines, 4) Recommended action (approve/review/reject)"Use Case 3: Accessibility - Video Descriptions
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "promotional-video.mp4" \
--prompt "Create an audio description track for visually impaired viewers. Include descriptions of: visual elements, on-screen text, scene changes, and important actions at appropriate timestamps."Use Case 4: Sports Analysis
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "game-footage.mp4" \
--prompt "Analyze this game footage: 1) Key plays with timestamps, 2) Player performance highlights, 3) Strategic decisions, 4) Turning points in the game" \
--fps 2 \
--verboseUse Case 5: Tutorial Enhancement
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--youtube-url "https://www.youtube.com/watch?v=TUTORIAL_ID" \
--prompt "Create an enhanced tutorial outline with: 1) Chapter markers with timestamps, 2) Prerequisites mentioned, 3) Tools/resources needed, 4) Common mistakes to avoid, 5) Practice exercises suggested"Output Options
Save to File
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "video.mp4" \
--prompt "Summarize this video" \
--output-file "summary.txt"JSON Output
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "video.mp4" \
--prompt "Summarize this video" \
--json \
--output-file "summary.json"Verbose Mode (with token usage)
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "video.mp4" \
--prompt "Analyze this video" \
--verboseError Handling
Check API Key
python .claude/skills/gemini-video-understanding/scripts/check_api_key.pyCommon Errors
File Not Found:
# Error: Video file not found: /path/to/video.mp4
# Solution: Check file path and ensure file exists
ls -lh /path/to/video.mp4API Key Invalid:
# Error: 403 Forbidden
# Solution: Verify API key is correct
python .claude/skills/gemini-video-understanding/scripts/check_api_key.pyRate Limit:
# Error: 429 Too Many Requests
# Solution: Wait before retrying, or upgrade to paid tierModel Selection
Fast Processing
--model "gemini-2.0-flash-lite" # Fastest, good for simple tasksBalanced (Default)
--model "gemini-2.5-flash" # Best balance of speed and qualityHighest Quality
--model "gemini-2.5-pro" # Most accurate, slower, higher token usagePerformance Tips
1. Use video clipping to analyze only relevant portions 2. Adjust FPS based on content type (lower for static, higher for action) 3. Use Files API for videos >20MB (handled automatically) 4. Batch process multiple short videos in one request (Gemini 2.5+) 5. Cache uploaded files - reuse file URIs for multiple queries
Resources
- API Documentation: https://ai.google.dev/gemini-api/docs/video-understanding
- Get API Key: https://aistudio.google.com/apikey
- Pricing: https://ai.google.dev/pricing
- Rate Limits: https://ai.google.dev/gemini-api/docs/rate-limits
Quick Start Guide - Gemini Video Understanding
1. Install Dependencies
pip install google-genaiOr use the requirements file:
pip install -r .claude/skills/gemini-video-understanding/requirements.txt2. Configure API Key
Choose one option:
Option A: Environment Variable (Recommended)
export GEMINI_API_KEY="your-api-key-here"Option B: Skill Directory .env
cp .claude/skills/gemini-video-understanding/.env.example \
.claude/skills/gemini-video-understanding/.env
# Edit the .env file with your API keyOption C: Project Root .env
echo "GEMINI_API_KEY=your-api-key-here" > .envGet your API key at: https://aistudio.google.com/apikey
3. Verify Setup
python .claude/skills/gemini-video-understanding/scripts/check_api_key.py4. Analyze Your First Video
Local video file:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "/path/to/video.mp4" \
--prompt "Summarize this video in 3 sentences"YouTube video:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--youtube-url "https://www.youtube.com/watch?v=VIDEO_ID" \
--prompt "What are the main topics discussed?"5. Common Commands
Transcribe with timestamps:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "video.mp4" \
--prompt "Transcribe this video with timestamps and visual descriptions"Analyze specific segment:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "video.mp4" \
--prompt "Summarize this part" \
--start-offset "1m30s" \
--end-offset "3m"Compare videos:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-paths "video1.mp4" "video2.mp4" \
--prompt "Compare these videos"Save to file:
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py \
--video-path "video.mp4" \
--prompt "Analyze this video" \
--output-file "analysis.txt"Help
python .claude/skills/gemini-video-understanding/scripts/analyze_video.py --helpSee EXAMPLES.md for more detailed examples and use cases.
Gemini Video Understanding Skill
A comprehensive Claude Code skill for analyzing videos using Google's Gemini API.
Overview
This skill enables AI-powered video analysis with capabilities including:
- Video summarization and content description
- Question answering about video content
- Audio transcription with visual descriptions
- Timestamp-based queries (MM:SS format)
- Video clipping (specific time ranges)
- Multiple video comparison (Gemini 2.5+)
- YouTube video processing
- Custom frame rate sampling
Features
✅ Three Video Input Methods:
- Local files (Files API for >20MB, inline for <20MB)
- YouTube URLs (preview feature)
- Multiple videos (up to 10 with Gemini 2.5+)
✅ Advanced Processing:
- Video clipping with start/end offsets
- Custom FPS sampling (default: 1 FPS)
- Context windows up to 2M tokens (~6 hours of video)
✅ 9 Supported Video Formats: MP4, MPEG, MOV, AVI, FLV, MPG, WebM, WMV, 3GPP
✅ Multiple Models:
- Gemini 2.5 Series (Pro, Flash, Preview)
- Gemini 2.0 Series (Flash, Flash-Lite)
✅ Flexible API Key Management: Checks in order: Process env → Skill directory → Project root
Quick Start
1. Install: pip install google-genai 2. Configure: export GEMINI_API_KEY="your-key" 3. Verify: python scripts/check_api_key.py 4. Analyze: python scripts/analyze_video.py --video-path video.mp4 --prompt "Summarize"
See QUICKSTART.md for detailed setup instructions.
Documentation
- [SKILL.md](SKILL.md) - Complete skill documentation
- [QUICKSTART.md](QUICKSTART.md) - Quick setup guide
- [EXAMPLES.md](EXAMPLES.md) - Comprehensive examples and use cases
Directory Structure
gemini-video-understanding/
├── SKILL.md # Main skill documentation
├── README.md # This file
├── QUICKSTART.md # Quick start guide
├── EXAMPLES.md # Detailed examples
├── requirements.txt # Python dependencies
├── .env.example # API key template
└── scripts/
├── analyze_video.py # Main video analysis script
└── check_api_key.py # API key verification toolCommon Use Cases
| Use Case | Command |
|---|---|
| Video Summary | --prompt "Summarize this video in 3 points" |
| Transcription | --prompt "Transcribe with timestamps and visual descriptions" |
| YouTube Analysis | --youtube-url "URL" --prompt "What are the main topics?" |
| Time Range | --start-offset "1m30s" --end-offset "3m" |
| Multi-Video | --video-paths vid1.mp4 vid2.mp4 --prompt "Compare" |
| High Quality | --model "gemini-2.5-pro" |
API Key Configuration
The skill automatically checks for GEMINI_API_KEY in this order:
1. Process Environment - $GEMINI_API_KEY 2. Skill Directory - .claude/skills/gemini-video-understanding/.env 3. Project Root - .env file
Get your API key at: https://aistudio.google.com/apikey
Rate Limits & Pricing
Free Tier:
- 10-15 requests per minute
- 1-4M tokens per minute
- 1,500 requests per day
- YouTube: 8 hours per day
Token Usage:
- Default: ~300 tokens/second of video
- Low-res: ~100 tokens/second of video
See full pricing: https://ai.google.dev/pricing
Support
- API Documentation: https://ai.google.dev/gemini-api/docs/video-understanding
- Files API: https://ai.google.dev/gemini-api/docs/vision#uploading-files
- Rate Limits: https://ai.google.dev/gemini-api/docs/rate-limits
- Issue Tracker: [Report issues on GitHub]
License
MIT License - See skill metadata for details.
Version
1.0.0 (2025-10-26)
google-genai>=0.3.0
#!/usr/bin/env python3
"""
Gemini Video Understanding Analysis Script
Analyzes videos using Google's Gemini API with support for:
- Local video files (Files API or inline data)
- YouTube URLs
- Multiple videos
- Video clipping (start/end offsets)
- Custom frame rate sampling
- Multiple models
API Key Configuration:
1. Process environment: $GEMINI_API_KEY
2. Skill directory: .claude/skills/gemini-video-understanding/.env
3. Project root: .env
"""
import argparse
import json
import os
import sys
import time
from pathlib import Path
from typing import Optional, List
def find_api_key() -> Optional[str]:
"""
Search for GEMINI_API_KEY in priority order:
1. Process environment variable
2. Skill directory .env file
3. Project root .env file
"""
# 1. Check process environment
api_key = os.environ.get('GEMINI_API_KEY')
if api_key:
return api_key
# 2. Check skill directory .env
skill_dir = Path(__file__).parent.parent
skill_env = skill_dir / '.env'
if skill_env.exists():
api_key = load_env_file(skill_env, 'GEMINI_API_KEY')
if api_key:
return api_key
# 3. Check project root .env
# Traverse up to find project root (where .git or .claude exists)
current = Path.cwd()
while current != current.parent:
if (current / '.git').exists() or (current / '.claude').exists():
project_env = current / '.env'
if project_env.exists():
api_key = load_env_file(project_env, 'GEMINI_API_KEY')
if api_key:
return api_key
break
current = current.parent
return None
def load_env_file(env_path: Path, key: str) -> Optional[str]:
"""Load a specific key from .env file"""
try:
with open(env_path, 'r') as f:
for line in f:
line = line.strip()
if line.startswith(f'{key}='):
value = line.split('=', 1)[1]
# Remove quotes if present
value = value.strip('"').strip("'")
return value if value else None
except Exception as e:
print(f"Warning: Error reading {env_path}: {e}", file=sys.stderr)
return None
def check_dependencies():
"""Check if required dependencies are installed"""
try:
import google.genai
return True
except ImportError:
print("Error: google-genai package not found", file=sys.stderr)
print("Install it with: pip install google-genai", file=sys.stderr)
return False
def get_file_size(file_path: str) -> int:
"""Get file size in bytes"""
return os.path.getsize(file_path)
def parse_time_offset(offset: str) -> str:
"""
Parse time offset to seconds format.
Accepts: "40s", "1m30s", "1h20m30s"
Returns: "XXs" format
"""
# If already in correct format, return as-is
if offset.endswith('s') and offset[:-1].isdigit():
return offset
# Parse complex formats
total_seconds = 0
current = ""
for char in offset:
if char.isdigit():
current += char
elif char in ['h', 'm', 's']:
if current:
value = int(current)
if char == 'h':
total_seconds += value * 3600
elif char == 'm':
total_seconds += value * 60
elif char == 's':
total_seconds += value
current = ""
return f"{total_seconds}s"
def analyze_video(
prompt: str,
video_path: Optional[str] = None,
youtube_url: Optional[str] = None,
video_paths: Optional[List[str]] = None,
model: str = "gemini-2.5-flash",
start_offset: Optional[str] = None,
end_offset: Optional[str] = None,
fps: Optional[int] = None,
verbose: bool = False
) -> dict:
"""
Analyze video(s) using Gemini API
Returns:
dict with 'text' (response) and 'usage' (token usage) keys
"""
from google import genai
from google.genai import types
# Find API key
api_key = find_api_key()
if not api_key:
raise ValueError(
"GEMINI_API_KEY not found. Set it in:\n"
"1. Environment: export GEMINI_API_KEY=your-key\n"
"2. Skill directory: .claude/skills/gemini-video-understanding/.env\n"
"3. Project root: .env file\n\n"
"Get your API key at: https://aistudio.google.com/apikey"
)
# Initialize client
client = genai.Client(api_key=api_key)
# Prepare video metadata if needed
video_metadata = None
if start_offset or end_offset or fps:
metadata_args = {}
if start_offset:
metadata_args['start_offset'] = parse_time_offset(start_offset)
if end_offset:
metadata_args['end_offset'] = parse_time_offset(end_offset)
if fps:
metadata_args['fps'] = fps
video_metadata = types.VideoMetadata(**metadata_args)
# Build content parts
parts = []
# Handle multiple videos
if video_paths:
if verbose:
print(f"Processing {len(video_paths)} videos...", file=sys.stderr)
for vpath in video_paths:
if not os.path.exists(vpath):
raise FileNotFoundError(f"Video file not found: {vpath}")
file_size = get_file_size(vpath)
use_files_api = file_size > 20 * 1024 * 1024 # 20MB threshold
if use_files_api:
if verbose:
print(f"Uploading {vpath} via Files API ({file_size / 1024 / 1024:.1f}MB)...", file=sys.stderr)
myfile = client.files.upload(file=vpath)
# Wait for file to be processed
while myfile.state == 'PROCESSING':
time.sleep(1)
myfile = client.files.get(name=myfile.name)
if myfile.state == 'FAILED':
raise RuntimeError(f"File upload failed for {vpath}")
if verbose:
print(f"File uploaded: {myfile.uri}", file=sys.stderr)
part_args = {'file_data': types.FileData(file_uri=myfile.uri)}
else:
if verbose:
print(f"Using inline data for {vpath} ({file_size / 1024 / 1024:.1f}MB)...", file=sys.stderr)
with open(vpath, 'rb') as f:
video_bytes = f.read()
mime_type = get_mime_type(vpath)
part_args = {
'inline_data': types.Blob(
data=video_bytes,
mime_type=mime_type
)
}
if video_metadata:
part_args['video_metadata'] = video_metadata
parts.append(types.Part(**part_args))
# Handle single local video file
elif video_path:
if not os.path.exists(video_path):
raise FileNotFoundError(f"Video file not found: {video_path}")
file_size = get_file_size(video_path)
use_files_api = file_size > 20 * 1024 * 1024 # 20MB threshold
if use_files_api:
if verbose:
print(f"Uploading via Files API ({file_size / 1024 / 1024:.1f}MB)...", file=sys.stderr)
myfile = client.files.upload(file=video_path)
# Wait for file to be processed
while myfile.state == 'PROCESSING':
if verbose:
print("Processing...", file=sys.stderr)
time.sleep(1)
myfile = client.files.get(name=myfile.name)
if myfile.state == 'FAILED':
raise RuntimeError("File upload failed")
if verbose:
print(f"File uploaded: {myfile.uri}", file=sys.stderr)
part_args = {'file_data': types.FileData(file_uri=myfile.uri)}
else:
if verbose:
print(f"Using inline data ({file_size / 1024 / 1024:.1f}MB)...", file=sys.stderr)
with open(video_path, 'rb') as f:
video_bytes = f.read()
mime_type = get_mime_type(video_path)
part_args = {
'inline_data': types.Blob(
data=video_bytes,
mime_type=mime_type
)
}
if video_metadata:
part_args['video_metadata'] = video_metadata
parts.append(types.Part(**part_args))
# Handle YouTube URL
elif youtube_url:
if verbose:
print(f"Processing YouTube URL: {youtube_url}", file=sys.stderr)
part_args = {'file_data': types.FileData(file_uri=youtube_url)}
if video_metadata:
part_args['video_metadata'] = video_metadata
parts.append(types.Part(**part_args))
else:
raise ValueError("Must provide video_path, youtube_url, or video_paths")
# Add prompt
parts.append(types.Part(text=prompt))
# Generate content
if verbose:
print(f"Analyzing with {model}...", file=sys.stderr)
response = client.models.generate_content(
model=f'models/{model}' if not model.startswith('models/') else model,
contents=types.Content(parts=parts)
)
# Extract response
result = {
'text': response.text,
'usage': {
'prompt_tokens': getattr(response.usage_metadata, 'prompt_token_count', 0),
'candidates_tokens': getattr(response.usage_metadata, 'candidates_token_count', 0),
'total_tokens': getattr(response.usage_metadata, 'total_token_count', 0)
}
}
return result
def get_mime_type(file_path: str) -> str:
"""Get MIME type based on file extension"""
ext = os.path.splitext(file_path)[1].lower()
mime_types = {
'.mp4': 'video/mp4',
'.mpeg': 'video/mpeg',
'.mov': 'video/mov',
'.avi': 'video/avi',
'.flv': 'video/x-flv',
'.mpg': 'video/mpg',
'.webm': 'video/webm',
'.wmv': 'video/wmv',
'.3gp': 'video/3gpp',
}
return mime_types.get(ext, 'video/mp4')
def main():
parser = argparse.ArgumentParser(
description='Analyze videos using Gemini API',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Analyze local video
%(prog)s --video-path video.mp4 --prompt "Summarize this video"
# Analyze YouTube video
%(prog)s --youtube-url "https://youtube.com/watch?v=abc" --prompt "What are the main topics?"
# Video clipping
%(prog)s --video-path video.mp4 --prompt "Summarize" --start-offset 40s --end-offset 80s
# Custom FPS
%(prog)s --video-path video.mp4 --prompt "Analyze" --fps 5
# Multiple videos
%(prog)s --video-paths video1.mp4 video2.mp4 --prompt "Compare these videos"
# Different model
%(prog)s --video-path video.mp4 --prompt "Detailed analysis" --model gemini-2.5-pro
"""
)
# Video source (mutually exclusive)
source_group = parser.add_mutually_exclusive_group(required=True)
source_group.add_argument('--video-path', help='Path to local video file')
source_group.add_argument('--youtube-url', help='YouTube video URL')
source_group.add_argument('--video-paths', nargs='+', help='Multiple video paths (Gemini 2.5+)')
# Required
parser.add_argument('--prompt', required=True, help='Analysis prompt/question')
# Optional
parser.add_argument('--model', default='gemini-2.5-flash',
help='Model to use (default: gemini-2.5-flash)')
parser.add_argument('--start-offset', help='Video clip start (e.g., "40s", "1m30s")')
parser.add_argument('--end-offset', help='Video clip end (e.g., "80s", "2m")')
parser.add_argument('--fps', type=int, help='Frame sampling rate (default: 1)')
parser.add_argument('--output-file', help='Save response to file')
parser.add_argument('--verbose', action='store_true', help='Show detailed processing info')
parser.add_argument('--json', action='store_true', help='Output as JSON')
args = parser.parse_args()
# Check dependencies
if not check_dependencies():
sys.exit(1)
try:
# Analyze video
result = analyze_video(
prompt=args.prompt,
video_path=args.video_path,
youtube_url=args.youtube_url,
video_paths=args.video_paths,
model=args.model,
start_offset=args.start_offset,
end_offset=args.end_offset,
fps=args.fps,
verbose=args.verbose
)
# Output results
if args.json:
output = json.dumps(result, indent=2)
else:
output = result['text']
if args.verbose:
print(f"\n{'='*60}", file=sys.stderr)
print(f"Token Usage:", file=sys.stderr)
print(f" Prompt: {result['usage']['prompt_tokens']}", file=sys.stderr)
print(f" Response: {result['usage']['candidates_tokens']}", file=sys.stderr)
print(f" Total: {result['usage']['total_tokens']}", file=sys.stderr)
print(f"{'='*60}\n", file=sys.stderr)
# Save to file or print
if args.output_file:
with open(args.output_file, 'w') as f:
f.write(output)
print(f"Response saved to {args.output_file}", file=sys.stderr)
else:
print(output)
sys.exit(0)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
if args.verbose:
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == '__main__':
main()
#!/usr/bin/env python3
"""
Check GEMINI_API_KEY configuration and availability.
Checks in priority order:
1. Process environment variable
2. Skill directory .env file
3. Project root .env file
"""
import os
import sys
from pathlib import Path
def check_api_key():
"""Check for GEMINI_API_KEY in all possible locations"""
print("Checking GEMINI_API_KEY configuration...\n")
found = False
# 1. Check process environment
print("[1] Process Environment Variable")
env_key = os.environ.get('GEMINI_API_KEY')
if env_key:
masked = env_key[:8] + '...' + env_key[-4:] if len(env_key) > 12 else '***'
print(f" ✓ Found: {masked}")
found = True
else:
print(" ✗ Not found")
# 2. Check skill directory .env
print("\n[2] Skill Directory .env File")
skill_dir = Path(__file__).parent.parent
skill_env = skill_dir / '.env'
print(f" Path: {skill_env}")
if skill_env.exists():
skill_key = load_env_file(skill_env)
if skill_key:
masked = skill_key[:8] + '...' + skill_key[-4:] if len(skill_key) > 12 else '***'
print(f" ✓ Found: {masked}")
if not found:
found = True
else:
print(" ✗ File exists but GEMINI_API_KEY not found")
else:
print(" ✗ File does not exist")
# 3. Check project root .env
print("\n[3] Project Root .env File")
current = Path.cwd()
project_root = None
# Find project root
while current != current.parent:
if (current / '.git').exists() or (current / '.claude').exists():
project_root = current
break
current = current.parent
if project_root:
project_env = project_root / '.env'
print(f" Path: {project_env}")
if project_env.exists():
project_key = load_env_file(project_env)
if project_key:
masked = project_key[:8] + '...' + project_key[-4:] if len(project_key) > 12 else '***'
print(f" ✓ Found: {masked}")
if not found:
found = True
else:
print(" ✗ File exists but GEMINI_API_KEY not found")
else:
print(" ✗ File does not exist")
else:
print(" ✗ Project root not found")
# Summary
print("\n" + "="*60)
if found:
print("✓ GEMINI_API_KEY is configured and available")
print("\nYou can now use the gemini-video-understanding skill!")
return 0
else:
print("✗ GEMINI_API_KEY not found")
print("\nTo configure:")
print("\n Option 1 (Recommended): Environment Variable")
print(" export GEMINI_API_KEY='your-api-key-here'")
print("\n Option 2: Skill Directory .env")
print(f" echo 'GEMINI_API_KEY=your-api-key-here' > {skill_env}")
print("\n Option 3: Project Root .env")
if project_root:
print(f" echo 'GEMINI_API_KEY=your-api-key-here' > {project_root}/.env")
else:
print(" echo 'GEMINI_API_KEY=your-api-key-here' > .env")
print("\nGet your API key at: https://aistudio.google.com/apikey")
return 1
def load_env_file(env_path: Path) -> str:
"""Load GEMINI_API_KEY from .env file"""
try:
with open(env_path, 'r') as f:
for line in f:
line = line.strip()
if line.startswith('GEMINI_API_KEY='):
value = line.split('=', 1)[1]
# Remove quotes if present
value = value.strip('"').strip("'")
return value if value else None
except Exception as e:
print(f" ⚠ Error reading file: {e}")
return None
if __name__ == '__main__':
sys.exit(check_api_key())