python

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

VideoDB Python Skill

VideoDB Python 技能指南

Use this skill for VideoDB Python SDK workflows: upload, transcript, subtitle, search, timeline editing, generative media, and real-time capture.
Do not use ffmpeg, moviepy, or local encoding tools when VideoDB supports the operation. The following are all handled server-side by VideoDB — trimming, combining clips, overlaying audio or music, adding subtitles, text/image overlays, transcoding, resolution changes, aspect-ratio conversion, resizing for platform requirements, transcription, and media generation. Only fall back to local tools for operations listed under Limitations in reference/editor.md (transitions, speed changes, crop/zoom, colour grading, volume mixing).
本技能适用于VideoDB Python SDK的各类工作流:上传、语音转文字、字幕生成、视频内搜索、时间轴编辑、生成式媒体以及实时采集。
当VideoDB支持对应操作时,请勿使用ffmpeg、moviepy或本地编码工具。以下所有操作均由VideoDB在云端完成:剪辑、合并片段、音频/音乐叠加、添加字幕、文本/图片叠加、转码、分辨率调整、宽高比转换、适配平台尺寸调整、语音转文字以及媒体生成。仅当操作属于reference/editor.md中列出的限制项(转场效果、变速、裁剪/缩放、色彩分级、音量混合)时,才需 fallback 到本地工具。

When to use what

场景与对应方案

ProblemVideoDB solution
Platform rejects video aspect ratio or resolution
video.reframe()
or
conn.transcode()
with
VideoConfig
Need to resize video for Twitter/Instagram/TikTok
video.reframe(target="vertical")
or
target="square"
Need to change resolution (e.g. 1080p → 720p)
conn.transcode()
with
VideoConfig(resolution=720)
Need to overlay audio/music on video
AudioAsset
on a
Timeline
Need to add subtitles
video.add_subtitle()
or
CaptionAsset
Need to combine/trim clips
VideoAsset
on a
Timeline
Need to generate voiceover, music, or SFX
coll.generate_voice()
,
generate_music()
,
generate_sound_effect()
场景问题VideoDB解决方案
平台不支持视频的宽高比或分辨率
video.reframe()
或搭配
VideoConfig
使用
conn.transcode()
需要调整视频尺寸适配Twitter/Instagram/TikTok
video.reframe(target="vertical")
target="square"
需要调整分辨率(如1080p → 720p)搭配
VideoConfig(resolution=720)
使用
conn.transcode()
需要在视频上叠加音频/音乐
Timeline
中使用
AudioAsset
需要添加字幕
video.add_subtitle()
CaptionAsset
需要合并/剪辑片段
Timeline
中使用
VideoAsset
需要生成旁白、音乐或音效
coll.generate_voice()
generate_music()
generate_sound_effect()

Setup

环境搭建

Run setup from the plugin root using absolute paths so it works regardless of current directory:
bash
python "${CLAUDE_PLUGIN_ROOT}/python/scripts/setup_venv.py"
python "${CLAUDE_PLUGIN_ROOT}/python/scripts/check_connection.py"
从插件根目录使用绝对路径执行以下命令完成搭建,确保无论当前目录如何都能正常运行:
bash
python "${CLAUDE_PLUGIN_ROOT}/python/scripts/setup_venv.py"
python "${CLAUDE_PLUGIN_ROOT}/python/scripts/check_connection.py"

API Key

API密钥

An API key from https://console.videodb.io is required.
python
import videodb
from dotenv import load_dotenv

load_dotenv()
conn = videodb.connect()
coll = conn.get_collection()
If
VIDEO_DB_API_KEY
is not set and no key is passed to
videodb.connect()
, ask the user for it.
python
import videodb
from dotenv import load_dotenv

load_dotenv()
conn = videodb.connect()
coll = conn.get_collection()
如果未设置
VIDEO_DB_API_KEY
且未向
videodb.connect()
传入密钥,请向用户索要。

Quick Reference

快速参考

Upload media

媒体上传

python
undefined
python
undefined

URL

URL链接

video = coll.upload(url="https://example.com/video.mp4")
video = coll.upload(url="https://example.com/video.mp4")

YouTube

YouTube视频

video = coll.upload(url="https://www.youtube.com/watch?v=VIDEO_ID")
video = coll.upload(url="https://www.youtube.com/watch?v=VIDEO_ID")

Local file

本地文件

video = coll.upload(file_path="/path/to/video.mp4")
undefined
video = coll.upload(file_path="/path/to/video.mp4")
undefined

Transcript + subtitle

语音转文字与字幕

python
undefined
python
undefined

force=True skips the error if the video is already indexed

force=True会跳过视频已索引时的错误

video.index_spoken_words(force=True) text = video.get_transcript_text() stream_url = video.add_subtitle()
undefined
video.index_spoken_words(force=True) text = video.get_transcript_text() stream_url = video.add_subtitle()
undefined

Search inside videos

视频内内容搜索

python
from videodb.exceptions import InvalidRequestError

video.index_spoken_words(force=True)
python
from videodb.exceptions import InvalidRequestError

video.index_spoken_words(force=True)

search() raises InvalidRequestError when no results are found.

当无搜索结果时,search()会抛出InvalidRequestError。

Always wrap in try/except and treat "No results found" as empty.

始终使用try/except包裹,并将“No results found”视为空结果。

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: raise
undefined
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: raise
undefined

Scene search

场景搜索

python
import re
from videodb import SearchType, IndexType, SceneExtractionType
from videodb.exceptions import InvalidRequestError
python
import 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_scenes()没有force参数——如果场景索引已存在,会直接抛出错误。需从错误信息中提取已有的索引ID。

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
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+)

使用score_threshold过滤低相关度结果(推荐值: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: raise
undefined
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: raise
undefined

Timeline editing

时间轴编辑

Important: Always validate timestamps before building a timeline:
  • start
    must be >= 0 (negative values are silently accepted but produce broken output)
  • start
    must be <
    end
  • end
    must be <=
    video.length
python
from 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()
注意: 在构建时间轴前务必验证时间戳:
  • start
    必须 >= 0(负值会被静默接受,但会导致输出损坏)
  • start
    必须 <
    end
  • end
    必须 <=
    video.length
python
from 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()

Transcode video (resolution / quality change)

视频转码(分辨率/画质调整)

python
from videodb import TranscodeMode, VideoConfig, AudioConfig
python
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), )
undefined
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), )
undefined

Reframe aspect ratio (for social platforms)

宽高比适配(针对社交平台)

Warning:
reframe()
is a slow server-side operation. For long videos it can take several minutes and may time out. Best practices:
  • Always limit to a short segment using
    start
    /
    end
    when possible
  • For full-length videos, use
    callback_url
    for async processing
  • Trim the video on a
    Timeline
    first, then reframe the shorter result
python
from videodb import ReframeMode
警告:
reframe()
是一个较慢的云端操作。处理长视频可能需要数分钟,甚至超时。最佳实践:
  • 尽可能使用
    start
    /
    end
    限制处理片段长度
  • 处理全长度视频时,使用
    callback_url
    进行异步处理
  • 先在
    Timeline
    上剪辑视频,再对较短的结果进行宽高比适配
python
from videodb import ReframeMode

Always prefer reframing a short segment:

优先适配短片段:

reframed = video.reframe(start=0, end=60, target="vertical", mode=ReframeMode.smart)
reframed = video.reframe(start=0, end=60, target="vertical", mode=ReframeMode.smart)

Async reframe for full-length videos (returns None, result via webhook):

全长度视频异步适配(返回None,结果通过webhook接收):

video.reframe(target="vertical", callback_url="https://example.com/webhook")
video.reframe(target="vertical", callback_url="https://example.com/webhook")

Presets: "vertical" (9:16), "square" (1:1), "landscape" (16:9)

预设值:"vertical"(9:16)、"square"(1:1)、"landscape"(16:9)

reframed = video.reframe(start=0, end=60, target="square")
reframed = video.reframe(start=0, end=60, target="square")

Custom dimensions

自定义尺寸

reframed = video.reframe(start=0, end=60, target={"width": 1280, "height": 720})
undefined
reframed = video.reframe(start=0, end=60, target={"width": 1280, "height": 720})
undefined

Generative media

生成式媒体

python
image = coll.generate_image(
    prompt="a sunset over mountains",
    aspect_ratio="16:9",
)
python
image = coll.generate_image(
    prompt="a sunset over mountains",
    aspect_ratio="16:9",
)

Error handling

错误处理

python
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}")
python
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}")

Common pitfalls

常见陷阱

ScenarioError messageSolution
Indexing an already-indexed video
Spoken word index for video already exists
Use
video.index_spoken_words(force=True)
to skip if already indexed
Scene index already exists
Scene index with id XXXX already exists
Extract the existing
scene_index_id
from the error with
re.search(r"id\s+([a-f0-9]+)", str(e))
Search finds no matches
InvalidRequestError: No results found
Catch the exception and treat as empty results (
shots = []
)
Reframe times outBlocks indefinitely on long videosUse
start
/
end
to limit segment, or pass
callback_url
for async
Negative timestamps on TimelineSilently produces broken streamAlways validate
start >= 0
before creating
VideoAsset
generate_video()
/
create_collection()
fails
Operation not allowed
or
maximum limit
Plan-gated features — inform the user about plan limits
场景错误信息解决方案
为已索引的视频重复索引
Spoken word index for video already exists
使用
video.index_spoken_words(force=True)
跳过已索引的视频
场景索引已存在
Scene index with id XXXX already exists
使用
re.search(r"id\s+([a-f0-9]+)", str(e))
从错误信息中提取已有的
scene_index_id
搜索无匹配结果
InvalidRequestError: No results found
捕获异常并视为空结果(
shots = []
Reframe操作超时处理长视频时无限阻塞使用
start
/
end
限制片段长度,或传入
callback_url
进行异步处理
时间轴使用负时间戳静默生成损坏的流创建
VideoAsset
前务必验证
start >= 0
generate_video()
/
create_collection()
执行失败
Operation not allowed
maximum limit
这些是受套餐限制的功能——告知用户套餐限制

Additional docs in this plugin

插件内附加文档

  • ${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
  • ${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