npx skills add https://github.com/video-db/skills --skill videodb视频、直播流和桌面会话的感知 + 记忆 + 操作。
在需要以下功能时使用此技能:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
https://console.videodb.io/player?url={STREAM_URL}关键: 在运行 Python 代码之前,始终先 cd 到用户的项目目录。这确保 load_dotenv(".env") 能找到正确的 .env 文件。
from dotenv import load_dotenv
load_dotenv(".env")
import videodb
conn = videodb.connect()
这会从以下位置读取 VIDEO_DB_API_KEY:
.env 文件如果密钥缺失,videodb.connect() 会自动引发 AuthenticationError。
当简短的命令行内代码有效时,不要编写脚本文件。
在编写命令行内 Python 代码(python -c "...")时,始终使用格式正确的代码——使用分号分隔语句并保持可读性。对于任何超过约 3 条语句的代码,请改用 heredoc:
python << 'EOF'
from dotenv import load_dotenv
load_dotenv(".env")
import videodb
conn = videodb.connect()
coll = conn.get_collection()
print(f"Videos: {len(coll.get_videos())}")
EOF
当用户要求“设置 videodb”或类似操作时:
pip install "videodb[capture]" python-dotenv
如果在 Linux 上 videodb[capture] 失败,请安装不带 capture 扩展的版本:
pip install videodb python-dotenv
用户必须使用任一方法设置 VIDEO_DB_API_KEY:
export VIDEO_DB_API_KEY=your-key.env 文件:在项目的 .env 文件中保存 VIDEO_DB_API_KEY=your-key在 https://console.videodb.io 获取免费 API 密钥(50 次免费上传,无需信用卡)。
切勿自行读取、写入或处理 API 密钥。始终让用户自行设置。
# URL
video = coll.upload(url="https://example.com/video.mp4")
# YouTube
video = coll.upload(url="https://www.youtube.com/watch?v=VIDEO_ID")
# 本地文件
video = coll.upload(file_path="/path/to/video.mp4")
# force=True 跳过视频已索引时的错误
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() 会引发 InvalidRequestError。
# 始终用 try/except 包装,并将“未找到结果”视为空结果。
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
import re
from videodb import SearchType, IndexType, SceneExtractionType
from videodb.exceptions import InvalidRequestError
# index_scenes() 没有 force 参数——如果场景索引已存在,它会引发错误。
# 从错误中提取现有的索引 ID。
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
# 使用 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
使用 Editor API 来组合视频、图像、音频和文本。完整工作流程请参阅 reference/editor.md。
from videodb.editor import Timeline, Track, Clip, VideoAsset, ImageAsset, AudioAsset, Fit
timeline = Timeline(conn)
timeline.resolution = "1280x720"
video_track = Track()
video_track.add_clip(0, Clip(asset=VideoAsset(id=video.id, start=10), duration=20))
audio_track = Track()
audio_track.add_clip(0, Clip(asset=AudioAsset(id=music.id, volume=0.2), duration=20))
timeline.add_track(video_track)
timeline.add_track(audio_track)
stream_url = timeline.generate_stream()
from videodb import TranscodeMode, VideoConfig, AudioConfig
# 在服务器端更改分辨率、质量或宽高比
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() 是一个缓慢的服务器端操作。对于长视频,可能需要几分钟并可能超时。最佳实践:
尽可能使用 start/end 限制为短片段
对于全长视频,使用 callback_url 进行异步处理
先在 Timeline 上修剪视频,然后调整较短结果的宽高比
from videodb import ReframeMode
reframed = video.reframe(start=0, end=60, target="vertical", mode=ReframeMode.smart)
video.reframe(target="vertical", callback_url="https://example.com/webhook")
reframed = video.reframe(start=0, end=60, target="square")
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("检查你的 VIDEO_DB_API_KEY")
try:
video = coll.upload(url="https://example.com/video.mp4")
except InvalidRequestError as e:
print(f"上传失败: {e}")
| 场景 | 错误信息 | 解决方案 |
|---|---|---|
| 索引已索引的视频 | 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 = []) |
| 调整宽高比超时 | 长视频无限期阻塞 | 使用 start/end 限制片段,或传递 callback_url 进行异步处理 |
| 时间线上出现负时间戳 | 静默产生损坏的流 | 在创建 VideoAsset 之前始终验证 start >= 0 |
generate_video() / create_collection() 失败 | Operation not allowed 或 maximum limit | 计划限制的功能——告知用户计划限制 |
参考文档位于与此 SKILL.md 文件相邻的 reference/ 目录中。如果需要,请使用 Glob 工具定位。
使用 ws_listener.py 在录制会话期间捕获 WebSocket 事件。桌面捕获仅支持 macOS。
python scripts/ws_listener.py --cwd=<PROJECT_ROOT> &cat /tmp/videodb_ws_id/tmp/videodb_events.jsonlimport json
events = [json.loads(l) for l in open("/tmp/videodb_events.jsonl")]
# 获取所有转录文本
transcripts = [e["data"]["text"] for e in events if e.get("channel") == "transcript"]
# 获取最近 5 分钟的视觉描述
import time
cutoff = time.time() - 300
recent_visual = [e for e in events
if e.get("channel") == "visual_index" and e["unix_ts"] > cutoff]
完整捕获工作流程,请参阅 reference/capture.md。
当 VideoDB 支持该操作时,不要使用 ffmpeg、moviepy 或本地编码工具。 以下所有操作均由 VideoDB 在服务器端处理——修剪、合并片段、叠加音频或音乐、添加字幕、文本/图像叠加层、转码、分辨率更改、宽高比转换、为平台要求调整大小、转录、音量控制、淡入淡出过渡和媒体生成。仅当 reference/editor.md 中“限制”部分列出的操作(速度变化、裁剪/缩放、色彩分级、关键帧动画)才回退到本地工具。
| 问题 | VideoDB 解决方案 |
|---|---|
| 平台拒绝视频宽高比或分辨率 | video.reframe() 或带有 VideoConfig 的 conn.transcode() |
| 需要为 Twitter/Instagram/TikTok 调整视频大小 | video.reframe(target="vertical") 或 target="square" |
| 需要更改分辨率(例如 1080p → 720p) | 带有 VideoConfig(resolution=720) 的 conn.transcode() |
| 需要在视频上叠加音频/音乐 | 带有音量控制的 Editor Timeline 上的 AudioAsset |
| 需要添加字幕 | video.add_subtitle() 或 Editor Timeline 上的 CaptionAsset |
| 需要合并/修剪片段 | Editor Timeline 上的 VideoAsset |
| 需要组合图像与画外音 | 在单独的 Editor 轨道上使用 ImageAsset + AudioAsset |
| 需要生成画外音、音乐或音效 | coll.generate_voice()、generate_music()、generate_sound_effect() |
每周安装量
134
代码仓库
GitHub 星标数
48
首次出现
2026年2月25日
安全审计
安装于
codex134
github-copilot133
kimi-cli133
gemini-cli133
cursor133
amp133
Perception + memory + actions for video, live streams, and desktop sessions.
Use this skill when you need to:
https://console.videodb.io/player?url={STREAM_URL}CRITICAL: Always cd to the user's project directory before running Python code. This ensures load_dotenv(".env") finds the correct .env file.
from dotenv import load_dotenv
load_dotenv(".env")
import videodb
conn = videodb.connect()
This reads VIDEO_DB_API_KEY from:
.env file in current directoryIf the key is missing, videodb.connect() raises AuthenticationError automatically.
Do NOT write a script file when a short inline command works.
When writing inline Python (python -c "..."), always use properly formatted code — use semicolons to separate statements and keep it readable. For anything longer than ~3 statements, use a heredoc instead:
python << 'EOF'
from dotenv import load_dotenv
load_dotenv(".env")
import videodb
conn = videodb.connect()
coll = conn.get_collection()
print(f"Videos: {len(coll.get_videos())}")
EOF
When the user asks to "setup videodb" or similar:
pip install "videodb[capture]" python-dotenv
If videodb[capture] fails on Linux, install without the capture extra:
pip install videodb python-dotenv
The user must set VIDEO_DB_API_KEY using either method:
export VIDEO_DB_API_KEY=your-key.env file: Save VIDEO_DB_API_KEY=your-key in the project's .env fileGet a free API key at https://console.videodb.io (50 free uploads, no credit card).
Do NOT read, write, or handle the API key yourself. Always let the user set it.
# 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:
raise
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 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:
raise
Use the Editor API to compose videos, images, audio, and text. See reference/editor.md for full workflow.
from videodb.editor import Timeline, Track, Clip, VideoAsset, ImageAsset, AudioAsset, Fit
timeline = Timeline(conn)
timeline.resolution = "1280x720"
video_track = Track()
video_track.add_clip(0, Clip(asset=VideoAsset(id=video.id, start=10), duration=20))
audio_track = Track()
audio_track.add_clip(0, Clip(asset=AudioAsset(id=music.id, volume=0.2), duration=20))
timeline.add_track(video_track)
timeline.add_track(audio_track)
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),
)
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
from videodb import ReframeMode
reframed = video.reframe(start=0, end=60, target="vertical", mode=ReframeMode.smart)
video.reframe(target="vertical", callback_url="https://example.com/webhook")
reframed = video.reframe(start=0, end=60, target="square")
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 | 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 |
Reference documentation is in the reference/ directory adjacent to this SKILL.md file. Use the Glob tool to locate it if needed.
Use ws_listener.py to capture WebSocket events during recording sessions. Desktop capture supports macOS only.
python scripts/ws_listener.py --cwd=<PROJECT_ROOT> &cat /tmp/videodb_ws_id/tmp/videodb_events.jsonlimport json
events = [json.loads(l) for l in open("/tmp/videodb_events.jsonl")]
# Get all transcripts
transcripts = [e["data"]["text"] for e in events if e.get("channel") == "transcript"]
# Get visual descriptions from last 5 minutes
import time
cutoff = time.time() - 300
recent_visual = [e for e in events
if e.get("channel") == "visual_index" and e["unix_ts"] > cutoff]
For complete capture workflow, see reference/capture.md.
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, volume control, fade transitions, and media generation. Only fall back to local tools for operations listed under Limitations in reference/editor.md (speed changes, crop/zoom, colour grading, keyframe animation).
| Problem | VideoDB 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 |
Weekly Installs
134
Repository
GitHub Stars
48
First Seen
Feb 25, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
codex134
github-copilot133
kimi-cli133
gemini-cli133
cursor133
amp133
Skills CLI 使用指南:AI Agent 技能包管理器安装与管理教程
46,600 周安装
PrivateInvestigator 道德人员查找工具 | 公开数据调查、反向搜索与背景研究
69 周安装
TorchTitan:PyTorch原生分布式大语言模型预训练平台,支持4D并行与H100 GPU加速
69 周安装
screenshot 截图技能:跨平台桌面截图工具,支持macOS/Linux权限管理与多模式捕获
69 周安装
tmux进程管理最佳实践:交互式Shell初始化、会话命名与生命周期管理
69 周安装
Git Rebase Sync:安全同步分支的Git变基工具,解决冲突与备份
69 周安装
LinkedIn自动化工具 - Claude Code专属,自然对话拓展人脉,避免垃圾信息
69 周安装
Catch the exception and treat as empty results (shots = []) |
| Reframe times out | Blocks indefinitely on long videos | Use start/end to limit segment, or pass callback_url for async |
| Negative timestamps on Timeline | Silently produces broken stream | Always 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 |
AudioAsset on an Editor Timeline with volume control |
| Need to add subtitles | video.add_subtitle() or CaptionAsset on Editor Timeline |
| Need to combine/trim clips | VideoAsset on an Editor Timeline |
| Need to compose images with voiceover | ImageAsset + AudioAsset on separate Editor tracks |
| Need to generate voiceover, music, or SFX | coll.generate_voice(), generate_music(), generate_sound_effect() |