videodb について
videodb は、VideoDB の Python SDK を使い、サーバー上で動画を処理する方法を案内するスキルです。開発者やエージェント向けに、取り込み、分析、検索、編集を説明し、一般的な作業には個別スキルを案内します。
主な機能
- 01URL やローカルファイルから動画をアップロード
- 02設定可能なアナライザーで動画を分析
- 03意味検索や条件指定で動画を検索
- 04文字起こしと字幕を生成
- 05動画の合成・トランスコード・リフレーム
活用シーン
- 01動画コレクションから該当シーンを検索
- 02字幕や翻訳済み動画素材を作成
- 03音声・画像・テキストを使ってクリップを合成
- 04Python プロジェクトから動画処理を実行
MCP 対応
このスキルでは、Claude Code 向けのホスト型 VideoDB MCP サーバーを紹介しており、SDK の API キーとは別に認証します。MCP ツールはローカルの Python 環境や API キーなしで動画操作を行えます。このプラグイン構成以外では、SDK を使う方法が記載されています。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ video-db/ skills --skill videodbインストール後、Claude Code で/videodbを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.env.examplereference/api-reference.mdcapture-reference.mdcapture.mdeditor-reference.mdeditor.mdgenerative.mdindexing-reference.mdindexing.mdmigration.mdrtstream-reference.mdrtstream.mdsandbox-reference.mdsandbox.mdsearch-reference.mdsearch.mdstreaming.mduse-cases.mdreference/legacy/index-reference.mdindex.mdsearch.mdscripts/ws_listener.py詳細
VideoDB:セットアップと Python SDK
VideoDB は、取り込み、理解、インデックス作成、検索、クリップ作成、字幕作成、合成、ストリーミングといった動画処理をサーバー上で実行します。このスキルでは、セットアップと Python SDK について説明します。よくある作業を扱う小規模なスキルが 5 つあります。該当する場合は、まずそちらを使用してください。
| 作業 | スキル |
|---|---|
| 場面を見つける、動画について質問する、登場するものを数える | video-search |
| クリップ、ハイライト動画、縦型動画、MP4 | video-clips |
| トランスクリプト、字幕、翻訳 | video-subtitles |
| 音楽、オーバーレイ、キャプション、合成 | video-edit |
| カメラ、ライブストリーム、会議、画面キャプチャ | video-live |
利用する方法
- VideoDB コネクターツールがある場合(
upload_media、search_video、generate_clipなどの名前):それらを使用します。これは、Web、デスクトップ、モバイルの Claude チャットと Cowork での方法です。インストールも API キーも必要ありません。 - VideoDB ツールはないものの、シェルが使える場合(Claude Code、Cowork、Python を実行できる任意のエージェント):VideoDB API キーを一言で丁寧に依頼します(https://console.videodb.io で無料で取得でき、クレジットが 20 ドル分付与されます。カードは不要です)。ユーザーからキーを受け取ったら、自分でプロジェクトの
.envに保存し(以下の「セットアップ」を参照)、決して表示せず、SDK を使って作業を続けます。Claude Code では、/mcpを実行してバンドルされている videodb サーバーを認証する方法もあります。 - VideoDB ツールもシェルも使えない場合:Claude チャットを利用しています。ユーザーの依頼に合わせて調整し、次の文だけを返信します。「VideoDB はまだ接続されていません。設定 → コネクターを開き、VideoDB を見つけて[接続]をクリックし、ログインしてください(無料、カード不要)。それから同じ依頼をもう一度送っていただければ、こちらで対応します。」チャットではどれも該当せず、チャットに貼り付けられたキーはコードを実行できないため使用できません。ここでは API キー、
.env、シェル、Claude Code、/mcpについて言及しないでください。
コード、スクリプト、ノートブック、デスクトップキャプチャ、AI 生成、吹き替え、サンドボックスコンピューティングにも SDK の方法が必要です。コネクターではこれらを実行できません。ユーザーへの返信では、「インデックス」「インデックス済み」「インデックス作成中」と書かず、「検索可能」と表現してください。
コネクターで時間のかかるジョブを実行すると、status: processing が返されます。返信には output_url と、ポーリングに使うツール名(poll_with、古いサーバーでは retry_with)が含まれます。done になるまで、そのツールに output_url を渡して呼び出してください。processing が何度か続くのは正常です(YouTube への 10 分の動画のアップロードには約 5 分かかります)。done の返信に結果が含まれていない場合は、もう一度ポーリングしてください。書き込み処理を再実行しないでください。2 つ目のジョブが開始されます。
出力
- ストリーム URL。
https://console.videodb.io/player?url={STREAM_URL}で再生できます。コネクターツールはplayer_urlも返します。 - タイムスタンプと再生可能な証拠を含む検索結果
- 生成されたアセット:字幕、音声、画像、クリップ
- ライブストリームのイベントおよびアラートのペイロード
- デスクトップセッションの要約と検索可能なタイムライン
Python コードの実行
重要: 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 つ程度を超える場合は、代わりにヒアドキュメントを使用してください。
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 をセットアップして」などの依頼があった場合:
1. SDK をインストールする
pip install "videodb[capture]>=0.5.0" python-dotenv
Linux で videodb[capture] のインストールに失敗する場合は、capture extra を付けずにインストールしてください。
pip install "videodb>=0.5.0" python-dotenv
>=0.5.0 の指定は重要です。理解、インデックス作成、質問、集計の各 API は、それ以前のバージョンには存在しません。
2. API キーを設定する
ユーザーに VideoDB API キーを一行で尋ねます。https://console.videodb.io で無料で取得でき、20 ドル分の無料クレジットが付与され、クレジットカードは不要です。ユーザーがチャットなどでキーを渡したら、代わりに保存して処理を続けます。
- プロジェクトの
.envにVIDEO_DB_API_KEY=<key>を書き込みます(必要に応じてファイルを作成)。また、.envが.gitignoreに記載されていることを確認します。 - キーを表示、エコー、ログ出力、コミットしたり、SDK 以外の経路で送信したりしてはいけません。
- 自分で設定したい場合は、ターミナルで
export VIDEO_DB_API_KEY=<key>を実行する方法もあります。
キーを繰り返さずに、何をどこに保存したかを伝えます。
3. ホスト型 MCP サーバーを認証する(Claude Code プラグインのみ)
このプラグインには、https://mcp.videodb.io/mcp にあるホスト型 MCP サーバーが含まれています。このサーバーは、上記の SDK キーとは別に認証されます。ユーザーに /mcp を実行して
videodb を選択し、VideoDB アカウントを使ってブラウザーで認証を完了するよう伝えます。「list my VideoDB collections」で確認します。
MCP ツールにはローカルの Python インストールも API キーも必要ありません。スキルが npx skills add でインストールされた場合、または Claude Code 以外で実行されている場合は、この手順を省略します。その場合、MCP サーバーはなく、利用できるのは上記の SDK 経由の方法のみです。
クイックリファレンス
メディアをアップロードする
# 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")
理解 → インデックス作成 → 検索(デフォルトの手順)
3 つの段階で進めます。アナライザーを実行してアーティファクトを生成し、各アーティファクトをインデックス化してから、検索します。
import time
# 1. Understand. Naming each analyzer keeps `analyzer.name` meaningful downstream.
understanding = video.understand(
analyzers=[
{"type": "spoken_words", "name": "transcript"},
{"type": "vlm", "name": "scene",
"config": {"prompt": "Describe the scene and any on-screen text."}},
],
segmentation={"type": "shot", "threshold": 30},
)
# A run with a failed or skipped analyzer ends `partial`, which the SDK does not
# treat as terminal — wait_until_complete() would poll to TimeoutError. Poll the
# analyzers instead. The `analyzers and` guard is load-bearing: a refresh can
# transiently return an empty list, and all([]) is True, which would exit the
# loop while the run is still going.
deadline = time.time() + 3600
while time.time() < deadline:
analyzers = understanding.refresh().list_analyzers()
if analyzers and all(a.is_complete for a in analyzers):
break
time.sleep(15)
# 2. Index each artifact that succeeded.
for analyzer in understanding.list_analyzers():
if analyzer.is_successful:
video.index(source=analyzer, name=analyzer.name).wait_until_complete()
# 3. Retrieve.
response = video.search("discussion about pricing")
for shot in response.shots:
print(f"[{shot.start:.1f}s - {shot.end:.1f}s] {shot.text}")
if response.response_type in ("shots", "deepsearch") and len(response):
stream_url = response.compile() # raises SearchError otherwise
アナライザーの種類:spoken_words(→ アーティファクト transcript)、vlm(→ scene)、object_detection(→ objects)、ocr、brand_detection(→ brands)、activity_recognition(→ activity)、location_detection(→ location)、faces、audio_event_detection。これらは単なる文字列で、SDK の列挙型はありません。
セグメンテーション、サンプリング、フィールド設定、コスト調整については、reference/indexing.md を参照してください。
検索
search(query) がデフォルトです。検索の手順を計画し、使用するインデックスを自動的に選択します。特定のものが必要な場合は、次のメソッドを直接使用します。
# Target a specific index, with a relevance floor
video.semantic_search("a customer holding the product", index_names=["scene"], score_threshold=0.7)
# Exact filtering, no natural-language interpretation
video.query(index_name="objects",
filter=[{"field": "frames.detections.label", "op": "contains", "value": "car"}])
# Counts and facets — returns the raw server payload, not a SearchResult
video.aggregate(index_name="objects", group_by="frames.detections.label", metric="count")
# A written answer plus the moments it came from
answer = video.ask("What did they say about pricing?", include_sources=True)
5 つのメソッドはすべて Collection にもあり、インデックス化されたすべての動画を対象に検索します。reference/search.md を参照してください。
search() は SearchResult ではなく、SearchResponse を返すようになりました。 get_shots()、compile()、play()、イテレーションは引き続き利用できますが、.stream_url はありません。.compile() を使用してください。
トランスクリプトと字幕
video.generate_transcript() # returns the existing transcript if there is one; force=True re-runs it
text = video.get_transcript_text()
stream_url = video.add_subtitle()
add_subtitle() と CaptionAsset(src="auto") は動画のトランスクリプトを読み取ります。generate_transcript() でトランスクリプトを作成できます。また、understand() から spoken_words アナライザーを実行しても作成されます。字幕やキャプションにレガシーの index_spoken_words() は必要ありません。
レガシーのインデックス作成(既存のコードベース)
# v1 API, legacy. Only for codebases that already use it; new code uses understand() + index() above.
from videodb import IndexType
video.index_spoken_words(force=True)
scene_index_id = video.index_scenes(prompt="Describe the visual content.")
results = video.legacy_search(
"person writing on a whiteboard",
index_type=IndexType.scene,
scene_index_id=scene_index_id,
)
既存のリポジトリでこのパターンを見つけたら、移行を依頼されない限りそのままにしてください。引き続き動作します。移行する場合は reference/migration.md を、保守する場合は reference/legacy/search.md を参照してください。
タイムライン編集
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
# 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() はサーバー側で時間のかかる処理です。長い動画では数分かかることがあり、タイムアウトする場合もあります。ベストプラクティス:
- 可能な場合は、
start/endを指定して短いセグメントに限定します - 動画全体を処理する場合は、非同期処理用に
callback_urlを使用します - まず
Timelineで動画をトリミングし、短くした動画をリフレームします
from 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",
)
Sandbox Compute(セルフホスト/オープンウェイトモデル)
サンドボックスを作成し、sandbox_id を対応するジョブに渡すことで、オープンウェイトモデル(Gemma、Qwen、Whisper、OmniVoice、FLUX、RT-DETR)を実行できます。videodb>=0.5.1 が必要です。
from videodb import SandboxTier, SandboxModel
# 1. Create a sandbox sized for the largest model, then wait until active.
sandbox = conn.create_sandbox(
tier=SandboxTier.medium,
models=[SandboxModel.GEMMA_4_31B.value], # exact ID, NO -FP8 suffix
)
sandbox.wait_for_ready(timeout=300, interval=5)
# 2. Understanding: set config.model + config.sandbox_id on the analyzer.
understanding = video.understand(analyzers=[{
"type": "vlm", "name": "scene",
"config": {"model": "google/gemma-4-31B-it", "sandbox_id": sandbox.id,
"prompt": "Describe the scene."},
}])
# 2b. Generation: pass model_name + sandbox_id (jobs return GenerationJob → .wait()).
response = coll.generate_text(prompt="Summarize this.", model_name="Qwen/Qwen3.5-9B",
sandbox_id=sandbox.id, max_tokens=300)
job = coll.generate_image(prompt="a city at sunset", model_name="black-forest-labs/FLUX.1-dev",
sandbox_id=sandbox.id)
image = job.wait(timeout=900, interval=5)
# 3. Stop when done — provisioning/active/alert all count toward the tier limit.
sandbox.stop(); sandbox.wait_for_stop()
モデル ID はカタログと完全に一致している必要があります(-FP8 サフィックスは付けないでください)。一致しない場合、create_sandbox は Unsupported sandbox model を発生させます。モデルカタログ、ティア、カテゴリ、料金、注意点については、reference/sandbox.md を参照してください。
エラー処理
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}")
よくある落とし穴
| シナリオ | エラーメッセージ | 解決策 |
|---|---|---|
| 検索結果にストリーム URL がない | AttributeError: 'SearchResponse' object has no attribute 'stream_url' | 0.5.0 では search() は SearchResponse を返します。results.compile() を使用してください |
search(score_threshold=) が誤ったインデックスを検索する | エラーなし、予期しない結果 | score_threshold はレガシーにはルーティングしません。semantic_search(score_threshold=) を使用するか、v1 インデックスには legacy_search() を使用してください |
| オブジェクト検出でのセマンティックインデックス | use_for includes semantic but no scene has embeddable text | オブジェクトアーティファクトにはトップレベルのテキストがありません。use_for を省略する(自動的に機能が縮退します)か、["query", "aggregate"] を渡してください |
| 存在しないフィールドのインデックス作成 | fields.filter names not present in any scene's data | エラーに使用可能なフィールド名が表示されます。それを確認してください。または index.field_schema を確認してください |
| 検索で一致が見つからない | v2 は空の SearchResponse を返します。InvalidRequestError: No results found が発生するのは legacy_search() のみです | len(response) を確認してください。try/except で囲むのはレガシーの呼び出しのみにしてください |
すでにインデックス化された動画(v1)でレガシーの index_spoken_words() を使用する | Spoken word index for video already exists | force=True を渡すか、呼び出しを省略してください。字幕とキャプションには generate_transcript() のみが必要です |
| リフレームがタイムアウトする | 長い動画で処理が無期限にブロックされる | start/end を使ってセグメントを制限するか、非同期処理用に callback_url を渡してください |
| Timeline で負のタイムスタンプを指定する | ストリームが気付かれないまま壊れる | VideoAsset を作成する前に、必ず start >= 0 を検証してください |
generate_video()/create_collection() が失敗する | Operation not allowed または maximum limit | プランによって利用が制限される機能です。プランの上限をユーザーに伝えてください |
追加ドキュメント
リファレンスドキュメントは ${CLAUDE_SKILL_DIR}/reference/ にあります。ファイルを読む際はこのプレフィックスを使用してください。以下のリンクは、この SKILL.md からの相対パスです。
- reference/api-reference.md - VideoDB Python SDK の完全な API リファレンス
- reference/indexing.md - Understand → index パイプラインについて:アナライザー、アーティファクト、セグメンテーション、フィールド設定
- reference/indexing-reference.md - アナライザーカタログと Understand/Index クラスのリファレンス
- reference/search.md - 検索ガイド:search、ask、semantic_search、query、aggregate
- reference/search-reference.md - 検索シグネチャー、フィルター構文、レスポンスオブジェクト
- reference/migration.md - v1 → v2 の対応表と SDK 0.5.0 の破壊的変更。v1 のコードを見つけた場合に読んでください
- reference/editor.md - タイムライン編集ワークフローガイド(4 層モデル、ユースケース、例)
- reference/editor-reference.md - エディターのコードリファレンス(コンストラクター、パラメーター、列挙型)
- reference/streaming.md - HLS ストリーミングと即時再生
- reference/generative.md - AI を活用したメディア生成(画像、動画、音声)
- reference/sandbox.md - Sandbox Compute ワークフロー(オープンウェイトモデルの実行:Gemma、Qwen、Whisper、OmniVoice、FLUX、RT-DETR)
- reference/sandbox-reference.md - Sandbox のコードリファレンス(create/get/list/stop、ティア、モデルカタログ、Sandbox 対応の生成)
- reference/rtstream.md - ライブストリーム取り込みワークフロー(RTSP/RTMP)
- reference/rtstream-reference.md - RTStream SDK メソッドと AI パイプライン
- reference/capture.md - デスクトップキャプチャのワークフロー
- reference/capture-reference.md - Capture SDK と WebSocket イベント
- reference/use-cases.md - 一般的な動画処理パターンと例
レガシー v1 のインデックス作成と検索。これらの API は引き続き動作し、非推奨ではありませんが、既存の v1 コードを保守する場合にのみ参照してください。
- reference/legacy/index.md - v1 シーンのインデックス作成とフレーム抽出のワークフロー
- reference/legacy/index-reference.md - v1 シーンインデックスのコードリファレンス(SceneCollection/Scene/Frame)
- reference/legacy/search.md - v1 の発話語句検索とシーン検索
画面録画(デスクトップキャプチャ)
録画セッション中の WebSocket イベントをキャプチャするには、ws_listener.py を使用してください。デスクトップキャプチャは macOS と Windows で動作します。
${CLAUDE_SKILL_DIR} は、このスキルのインストールディレクトリで、Claude Code によって設定されます。この変数が設定されないエージェントでは、この SKILL.md が置かれているディレクトリに置き換えてください。
クイックスタート
- リスナーを起動する:
python "${CLAUDE_SKILL_DIR}/scripts/ws_listener.py" --cwd=<PROJECT_ROOT> & - WebSocket ID を取得する:
cat /tmp/videodb_ws_id - キャプチャコードを実行する(ワークフロー全体については reference/capture.md を参照)
- イベントの書き込み先:
/tmp/videodb_events.jsonl
イベントをクエリする
import 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]
ユーティリティスクリプト
${CLAUDE_SKILL_DIR}/scripts/ws_listener.py- WebSocket イベントリスナー(JSONL に出力)
キャプチャのワークフロー全体については、reference/capture.md を参照してください。
VideoDB が対応している操作には、ffmpeg、moviepy、ローカルエンコードツールを使用しないでください。以下の操作はすべて VideoDB のサーバー側で処理されます:トリミング、クリップの結合、音声や音楽のオーバーレイ、字幕の追加、テキスト/画像のオーバーレイ、トランスコード、解像度の変更、アスペクト比の変換、プラットフォーム要件に合わせたサイズ変更、文字起こし、音量調整、フェードトランジション、メディア生成。ローカルツールへのフォールバックは、reference/editor.md の「制限事項」に記載された操作(速度変更、クロップ/ズーム、カラーグレーディング、キーフレームアニメーション)に限ってください。
用途別の選択肢
| 課題 | VideoDB のソリューション |
|---|---|
| 動画を検索可能にする | video.understand(analyzers=[...]) を実行し、その後 video.index(source=analyzer) を実行します |
| 話された内容や映っているものからシーンを見つける | video.search(query)、または特定のインデックスを対象にするには semantic_search(index_names=[...]) を使います |
| 動画について質問する | video.ask(question, include_sources=True) |
| 動画に登場するものを数えたり、グループ化したりする | video.aggregate(index_name=..., group_by=..., metric="count") |
| 正確なフィールド値でシーンを絞り込む | video.query(index_name=..., filter={...}) |
| プラットフォームで動画のアスペクト比や解像度が拒否される | VideoConfig を使って video.reframe() または 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() |