Loading...
Loading...
Process videos with the VideoDB Python SDK. Handles trimming, combining clips, audio overlays, background music, subtitles, transcription, voiceover, text/image overlays, transcoding, resolution change, aspect-ratio fix, resizing for social platforms, media generation, search, and real-time capture — all server-side with no ffmpeg or local encoding tools needed.
npx skill4agent add video-db/skills videodb| Problem | VideoDB solution |
|---|---|
| Platform rejects video aspect ratio or resolution | |
| Need to resize video for Twitter/Instagram/TikTok | |
| Need to change resolution (e.g. 1080p → 720p) | |
| Need to overlay audio/music on video | |
| Need to add subtitles | |
| Need to combine/trim clips | |
| Need to generate voiceover, music, or SFX | |
test -f ~/.videodb/.env && grep -q VIDEO_DB_API_KEY ~/.videodb/.envQuestion: "What is your VideoDB API key?"
Description: "Get your free API key from https://console.videodb.io (50 free uploads, no credit card required)"mkdir -p ~/.videodb
echo "VIDEO_DB_API_KEY=<user-provided-key>" > ~/.videodb/.envpython3 "${CLAUDE_PLUGIN_ROOT}/python/scripts/setup_venv.py""${CLAUDE_PLUGIN_ROOT}/python/.venv/bin/python" "${CLAUDE_PLUGIN_ROOT}/python/scripts/check_connection.py"import videodb
from dotenv import load_dotenv
load_dotenv()
conn = videodb.connect()
coll = conn.get_collection()~/.videodb/.env.env# URL
video = coll.upload(url="https://example.com/video.mp4")
# YouTube
video = coll.upload(url="https://www.youtube.com/watch?v=VIDEO_ID")
# Local file
video = coll.upload(file_path="/path/to/video.mp4")# force=True skips the error if the video is already indexed
video.index_spoken_words(force=True)
text = video.get_transcript_text()
stream_url = video.add_subtitle()from videodb.exceptions import InvalidRequestError
video.index_spoken_words(force=True)
# search() raises InvalidRequestError when no results are found.
# Always wrap in try/except and treat "No results found" as empty.
try:
results = video.search("product demo")
shots = results.get_shots()
stream_url = results.compile()
except InvalidRequestError as e:
if "No results found" in str(e):
shots = []
else:
raiseimport re
from videodb import SearchType, IndexType, SceneExtractionType
from videodb.exceptions import InvalidRequestError
# index_scenes() has no force parameter — it raises an error if a scene
# index already exists. Extract the existing index ID from the error.
try:
scene_index_id = video.index_scenes(
extraction_type=SceneExtractionType.shot_based,
prompt="Describe the visual content in this scene.",
)
except Exception as e:
match = re.search(r"id\s+([a-f0-9]+)", str(e))
if match:
scene_index_id = match.group(1)
else:
raise
# Use score_threshold to filter low-relevance noise (recommended: 0.3+)
try:
results = video.search(
query="person writing on a whiteboard",
search_type=SearchType.semantic,
index_type=IndexType.scene,
scene_index_id=scene_index_id,
score_threshold=0.3,
)
shots = results.get_shots()
stream_url = results.compile()
except InvalidRequestError as e:
if "No results found" in str(e):
shots = []
else:
raisestartstartendendvideo.lengthfrom videodb.timeline import Timeline
from videodb.asset import VideoAsset, TextAsset, TextStyle
timeline = Timeline(conn)
timeline.add_inline(VideoAsset(asset_id=video.id, start=10, end=30))
timeline.add_overlay(0, TextAsset(text="The End", duration=3, style=TextStyle(fontsize=36)))
stream_url = timeline.generate_stream()from videodb import TranscodeMode, VideoConfig, AudioConfig
# Change resolution, quality, or aspect ratio server-side
job_id = conn.transcode(
source="https://example.com/video.mp4",
callback_url="https://example.com/webhook",
mode=TranscodeMode.economy,
video_config=VideoConfig(resolution=720, quality=23, aspect_ratio="16:9"),
audio_config=AudioConfig(mute=False),
)reframe()startendcallback_urlTimelinefrom videodb import ReframeMode
# Always prefer reframing a short segment:
reframed = video.reframe(start=0, end=60, target="vertical", mode=ReframeMode.smart)
# Async reframe for full-length videos (returns None, result via webhook):
video.reframe(target="vertical", callback_url="https://example.com/webhook")
# Presets: "vertical" (9:16), "square" (1:1), "landscape" (16:9)
reframed = video.reframe(start=0, end=60, target="square")
# Custom dimensions
reframed = video.reframe(start=0, end=60, target={"width": 1280, "height": 720})image = coll.generate_image(
prompt="a sunset over mountains",
aspect_ratio="16:9",
)from videodb.exceptions import AuthenticationError, InvalidRequestError
try:
conn = videodb.connect()
except AuthenticationError:
print("Check your VIDEO_DB_API_KEY")
try:
video = coll.upload(url="https://example.com/video.mp4")
except InvalidRequestError as e:
print(f"Upload failed: {e}")| Scenario | Error message | Solution |
|---|---|---|
| Indexing an already-indexed video | | Use |
| Scene index already exists | | Extract the existing |
| Search finds no matches | | Catch the exception and treat as empty results ( |
| Reframe times out | Blocks indefinitely on long videos | Use |
| Negative timestamps on Timeline | Silently produces broken stream | Always validate |
| | Plan-gated features — inform the user about plan limits |
${CLAUDE_PLUGIN_ROOT}/python/reference/api-reference.md${CLAUDE_PLUGIN_ROOT}/python/reference/search.md${CLAUDE_PLUGIN_ROOT}/python/reference/editor.md${CLAUDE_PLUGIN_ROOT}/python/reference/generative.md${CLAUDE_PLUGIN_ROOT}/python/reference/meetings.md${CLAUDE_PLUGIN_ROOT}/python/reference/rtstream.md${CLAUDE_PLUGIN_ROOT}/python/reference/capture.md${CLAUDE_PLUGIN_ROOT}/python/reference/use-cases.md