mcpField
V
videodb

videodb

github.com/video-dbクリエイティブ・メディア1391.5k 回インストール今日更新
リポジトリ

videodb について

videodb は、VideoDB の Python SDK を使い、サーバー上で動画を処理する方法を案内するスキルです。開発者やエージェント向けに、取り込み、分析、検索、編集を説明し、一般的な作業には個別スキルを案内します。

主な機能

  1. 01URL やローカルファイルから動画をアップロード
  2. 02設定可能なアナライザーで動画を分析
  3. 03意味検索や条件指定で動画を検索
  4. 04文字起こしと字幕を生成
  5. 05動画の合成・トランスコード・リフレーム

活用シーン

  1. 01動画コレクションから該当シーンを検索
  2. 02字幕や翻訳済み動画素材を作成
  3. 03音声・画像・テキストを使ってクリップを合成
  4. 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.example
reference/
api-reference.md
capture-reference.md
capture.md
editor-reference.md
editor.md
generative.md
indexing-reference.md
indexing.md
migration.md
rtstream-reference.md
rtstream.md
sandbox-reference.md
sandbox.md
search-reference.md
search.md
streaming.md
use-cases.md
reference/legacy/
index-reference.md
index.md
search.md
scripts/
ws_listener.py

詳細

VideoDB:セットアップと Python SDK

VideoDB は、取り込み、理解、インデックス作成、検索、クリップ作成、字幕作成、合成、ストリーミングといった動画処理をサーバー上で実行します。このスキルでは、セットアップと Python SDK について説明します。よくある作業を扱う小規模なスキルが 5 つあります。該当する場合は、まずそちらを使用してください。

作業スキル
場面を見つける、動画について質問する、登場するものを数えるvideo-search
クリップ、ハイライト動画、縦型動画、MP4video-clips
トランスクリプト、字幕、翻訳video-subtitles
音楽、オーバーレイ、キャプション、合成video-edit
カメラ、ライブストリーム、会議、画面キャプチャvideo-live

利用する方法

  1. VideoDB コネクターツールがある場合(upload_media、search_video、generate_clip などの名前):それらを使用します。これは、Web、デスクトップ、モバイルの Claude チャットと Cowork での方法です。インストールも API キーも必要ありません。
  2. VideoDB ツールはないものの、シェルが使える場合(Claude Code、Cowork、Python を実行できる任意のエージェント):VideoDB API キーを一言で丁寧に依頼します(https://console.videodb.io で無料で取得でき、クレジットが 20 ドル分付与されます。カードは不要です)。ユーザーからキーを受け取ったら、自分でプロジェクトの .env に保存し(以下の「セットアップ」を参照)、決して表示せず、SDK を使って作業を続けます。Claude Code では、/mcp を実行してバンドルされている videodb サーバーを認証する方法もあります。
  3. 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 を読み込みます。

  1. 環境変数(すでにエクスポートされている場合)
  2. 現在のディレクトリにあるプロジェクトの .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 existsforce=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 からの相対パスです。

レガシー v1 のインデックス作成と検索。これらの API は引き続き動作し、非推奨ではありませんが、既存の v1 コードを保守する場合にのみ参照してください。

画面録画(デスクトップキャプチャ)

録画セッション中の WebSocket イベントをキャプチャするには、ws_listener.py を使用してください。デスクトップキャプチャは macOS と Windows で動作します。

${CLAUDE_SKILL_DIR} は、このスキルのインストールディレクトリで、Claude Code によって設定されます。この変数が設定されないエージェントでは、この SKILL.md が置かれているディレクトリに置き換えてください。

クイックスタート
  1. リスナーを起動する:python "${CLAUDE_SKILL_DIR}/scripts/ws_listener.py" --cwd=<PROJECT_ROOT> &
  2. WebSocket ID を取得する:cat /tmp/videodb_ws_id
  3. キャプチャコードを実行する(ワークフロー全体については reference/capture.md を参照)
  4. イベントの書き込み先:/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()

コメント