zahori について
zahoriは実際のブラウザーでページを操作し、ネットワークリクエストを調べてメディアストリームを見つけます。HLS、DASH、MP4、音声の情報を必要とするユーザー向けで、再利用可能なJSONサイトプロファイルに対応し、DRMコンテンツは拒否します。
主な機能
- 01ブラウザーでページを操作しリクエストを捕捉
- 02ストリームURLと再生用ヘッダーを取得
- 03HLS、DASH、MP4、音声を識別
- 04言語別の音声トラック選択
- 05JSONサイトプロファイルの作成と修復
- 06DRMコンテンツの検出と拒否
活用シーン
- 01ウェブプレーヤーのメディアURLを特定
- 02ダウンロードツールに再生用ヘッダーを渡す
- 03難しいサイト向けに再利用可能なプロファイルを作成
- 04サイト変更後にプロファイルをテストして修復
MCP 対応
zahoriはMCPサーバーとして、サイトの調査、プロファイルのテストと保存を行うツールをエージェントに提供します。これらのツールでストリームを見つけ、サイト固有の手順を学習できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
6掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| url | string | はい | プレーヤーを含むページ。 |
| lang | string | いいえ | 多言語ストリームで優先する音声言語(例:es)。 |
詳細
zahori
あらゆるウェブページの背後にあるメディアストリームを見つけます。
実際のブラウザーでページを開き、オーバーレイを閉じて再生ボタンを押し、メディアリクエストが現れるまでネットワークを監視します。ストリーム URL(HLS、DASH、MP4、または音声)と、再生に必要なヘッダーを取得できます。
$ npx zahori get https://example.org/live
https://cdn.example.org/hls/live/master.m3u8
サイトごとの設定は不要です。抽出器の対応を待つ必要もありません。ブラウザーで再生できるものなら、zahori で見つけられます。
目次
- 機能
- zahori を選ぶ理由
- インストール
- CLI
- ライブラリ
- プロファイル:zahori がサイトを学習する仕組み
- zahori にサイトを教える
- オラクル
- 責任ある利用
- API
- ドキュメント
- コントリビューション
- ライセンス
機能
- どの URL でもすぐに使えます。 組み込みの汎用フローで、ほとんどのページを設定なしで処理できます。
- 実際のブラウザーエンジンを使用。 Playwright がバックグラウンドでヘッドレスブラウザーを操作します。複数の言語に対応し、同意バナー、再生ボタン、iframe プレーヤーを自動処理します。
- 再生用ヘッダーも取得。 実際のリクエストから Referer/Origin/UA/Cookie を取得するため、ffmpeg などで 403 エラーになりません。
- HLS に対応。 マスタープレイリストとメディアプレイリスト、ライブと VOD の判定、多言語ストリームの音声レンディションの言語別選択に対応します。
- 学習可能。 難しいサイトは小さな JSON プロファイルにして一度保存すれば、その後は常に同じように処理できます。
- エージェントネイティブ(MCP)。 コーディングエージェントがサイトを調査し、プロファイルを作成・テストして保存できます。
- 自己修復機能。
zahori healは、BYO キーのモデルを使ってサイトの変更に応じてプロファイルを修復します。保存前に客観的なオラクルで検証します。 - DRM を拒否する設計。 保護されたコンテンツは常に検出して拒否します。
zahori を選ぶ理由
ウェブのロングテールでは、ダウンローダーが対応していない埋め込みプレーヤーを使って配信しているサイトが数多くあります。地方のテレビ局やラジオ局、ライブイベントのページ、小規模な動画ポータルなどです。yt-dlp は、抽出器を整備している大手プラットフォームに対しては非常に優れています。しかし、ロングテールには抽出器がなく、サイトごとに手作業で作成する方法では規模を拡大できません。
| yt-dlp | zahori | |
|---|---|---|
| 対応範囲 | 厳選された約 1,800 のサイト | ブラウザーで開けるあらゆるページ |
| 方法 | サイトごとの抽出器コード | 実際のブラウザーとネットワークの監視 |
| 新しいサイト | メンテナーの対応を待つ | 汎用的に動作するか、数分で学習させる |
| サイトの変更 | パッチが適用されるまで抽出器が動作しない | zahori heal がプロファイルを修復 |
両者は相互に補完します。YouTube には yt-dlp を使い、抽出器が作られていないページには zahori を使ってください。
インストール
npm install -g zahori # CLI
npm install zahori # library
要件
| Node | ≥ 22 |
| ブラウザー | npx playwright install chromium --only-shell を一度実行してください。実行しない場合は、インストール済みの Google Chrome が使用されます |
| ffmpeg | オプションです。--validate、--download、および検出オラクルでのみ使用します |
pnpm を使用する場合: pnpm はデフォルトで依存関係のビルドスクリプトをブロックするため、Playwright はブラウザーを自動ダウンロードしません。上記の
playwright installの行を一度実行するか、フォールバックとしてシステムの Chrome が使用されます。
CLI
# Resolve the stream URL behind a page (URL to stdout, everything else to stderr)
zahori get https://tv.example.org/live
# Full result as JSON: url, kind, live/VOD, replay headers, all candidates
zahori get https://tv.example.org/live --json
# Prefer an audio language on multilingual streams
zahori get https://tv.example.eu/live --lang es
# Record it (replays the captured headers; needs ffmpeg)
zahori get https://tv.example.org/live --download session.mp4
zahori get https://tv.example.org/live --audio session.m4a
# Check the stream is real media, not a bumper or geo-block slate
zahori get https://tv.example.org/live --validate
# Watch the browser work
zahori get https://tv.example.org/live --headful
--json の出力例:
$ zahori get https://example.org/watch --json
{
"url": "https://cdn.example.org/hls/master.m3u8",
"kind": "hls",
"headers": {
"referer": "https://example.org/",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/150.0.0.0 Safari/537.36"
},
"profileId": "generic",
"candidates": [
"https://cdn.example.org/hls/master.m3u8",
"https://cdn.example.org/hls/720p/index.m3u8",
"https://cdn.example.org/hls/1080p/index.m3u8"
]
}
解決された URL は署名付きで、有効期間が短いことがよくあります。zahori は実行のたびにストリームを新たに特定するため、URL はすぐに使用し、保存しないでください。
ライブラリ
import { resolve } from 'zahori';
const stream = await resolve('https://tv.example.org/live', {
audioLanguage: 'es', // optional, for multilingual masters
});
stream.url; // the media URL
stream.kind; // 'hls' | 'dash' | 'mp4' | 'audio'
stream.live; // true = live, false = VOD, undefined = unknown
stream.headers; // Referer/Origin/UA/Cookie to replay (many CDNs 403 without them)
stream.headers を、URL の取得に使用するものへ渡してください。ffmpeg の場合:
import { download } from 'zahori';
await download(stream, 'session.mp4');
エラーは型で分類されています。NoStreamError(キャプチャしたストリームがない場合)と DrmError(保護されたコンテンツを拒否した場合)です。
お使いのブラウザーを使用する
ログインが必要なサイトでは、ストレージ状態を持つコンテキストなど、ご自身で管理する Playwright コンテキスト内で zahori を操作してください。
import { runProfileOnPage, GENERIC_PROFILE } from 'zahori';
const ctx = await browser.newContext({ storageState: 'auth.json' });
const page = await ctx.newPage();
const stream = await runProfileOnPage(page, GENERIC_PROFILE, url);
プロファイル:zahori がサイトを学習する仕組み
zahori にはサイトの知識が一切ありません。ほとんどのページは組み込みの汎用フローで解決できます。解決できない場合は、プロファイルで対応します。プロファイルは、サイトの開き方(クリックする要素、メディアリクエストの認識方法、選択する候補)を記述した小さな JSON ファイルです。プロファイルはコードではなくデータです。エンジンが実行時に AI を使わず、決定論的に解釈します。
{
"id": "tv-example-org",
"match": ["^https?://([^/]*\\.)?tv\\.example\\.org([/:?#]|$)"],
"steps": [
{ "action": "goto" },
{ "action": "dismissOverlays", "selectors": [] },
{ "action": "click", "selector": ".broadcast-start" }
],
"sniff": { "kinds": ["hls"], "urlPattern": "/live/" }
}
プロファイルは、プロジェクト内の .zahori/profiles/(本番環境やチームメンバーの環境でも使えるよう、コミットしてください)またはグローバルな ~/.zahori/profiles/ に保存されます。プロファイルに保存されるのは、ストリームを再導出する方法であり、ストリーム URL ではありません。そのため、署名付き URL や有効期限付き URL が問題になることはありません。
zahori にサイトを学習させる
コーディングエージェントを使う場合(MCP)
zahori は MCP サーバーです。MCP に対応したエージェントなら、サイトを調査し、プロファイルを提案し、オラクルでテストして、合格した場合に保存できます。すでにお持ちのサブスクリプションを使用するため、API キーは不要です。サーバーはプロトコルのハンドシェイク時にワークフローの指示をエージェントに送信するため、どのクライアントでも同じように動作します。
ほとんどのクライアントでは標準の設定を使用できます。
{
"mcpServers": {
"zahori": { "command": "npx", "args": ["-y", "zahori", "mcp"] }
}
}
| クライアント | 設定 |
|---|---|
| Cursor | 上記のブロックを ~/.cursor/mcp.json(またはプロジェクトごとの .cursor/mcp.json)に追加します |
| VS Code / Copilot | .vscode/mcp.json で、"mcpServers" ではなく "servers" キーの下に追加します |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| Claude Code | claude mcp add zahori -- npx -y zahori mcp |
| Codex CLI | codex mcp add zahori -- npx -y zahori mcp |
| Gemini CLI | gemini mcp add zahori npx -y zahori mcp |
| Claude Desktop | 上記のブロックを claude_desktop_config.json に追加します |
次に、*「https://tricky.example.org のストリームを特定して、プロファイルを保存して」*と依頼してください。公開されるツールは、zahori_get、zahori_probe、zahori_test_profile、zahori_save_profile、zahori_validate、zahori_list_profiles です。
ヘッドレス実行で独自のキーを使用する場合
cron や CI などの無人パイプラインでは、zahori 自身がモデルを操作できます。まず無料の決定論的な方法を必ず試し、それで失敗した場合にのみトークンを消費します。
export ANTHROPIC_API_KEY=... # or OPENAI_API_KEY, or a local Ollama
zahori discover https://tricky.example.org --model anthropic:claude-sonnet-5
zahori heal https://tricky.example.org # when a saved profile stops working
モデルの指定形式は、anthropic:<model>、openai:<model>、ollama:<model>、compat:<model>(OpenAI 互換の任意のエンドポイント)です。または、一度 ZAHORI_MODEL を設定してください。モデルが行うのはプロファイルの提案のみです。エンジンが各提案を実行し、オラクルが評価するため、検証されていないプロファイルが保存されることはありません。
オラクル
「何かダウンロードされたかどうか」だけでは不十分なテストです。これでは広告の前置き、保留音、地域制限の画面まで合格してしまいます。オラクルは、ストリームを信頼する前に、より確かなシグナルを組み合わせて評価します。
- デコードプローブ。 ffmpeg で指定範囲をデコードし、音量を測定します。
- マニフェストの妥当性チェック。 実際のセッションには多数のセグメントがありますが、画面表示には 4 つしかありません。
- 無音の許容。 指定範囲が無音の場合は、さらに先の範囲で 2 回目のプローブを実施します(正当な休憩時間である可能性があるためです)。無音だけを理由にストリームが失敗することはありません。
- 明確なエラー。 403/401 の応答は原因不明として扱わず、ヘッダーの問題として報告します。
判定結果は pass、fail、inconclusive のいずれかです。検出処理では、オラクルに合格したプロファイルのみ保存します。
責任ある利用
zahori は、誰でもアクセスでき、保護されていないストリームを対象に構築されています。通常のブラウザーで、すべての訪問者がすでに再生できるページです。ブラウザーがすでに再生しているものを解決するだけで、不正に侵入することはありません。
設計上、zahori は DRM を拒否します。 マニフェスト内の Widevine、PlayReady、FairPlay のマーカーを検出し、明示的な DrmError を返して拒否します。暗号化やアクセス制御を回避しようとすることは決してありません。これは設定で変更できるものではなく、厳守する方針です。
安全に利用できる範囲。 最も明確に安全なのは、サイトがすべての訪問者に提供するオープンな HLS/DASH を、アーカイブ、アクセシビリティ、文字起こし、研究などの合法的な目的で利用することです。利用先を指定する前に、知っておくべき点がいくつかあります。
- 「公開されている」ことは「パブリックドメイン」であることを意味しません。 ストリームを無料で視聴できても、自由に再利用できるとは限りません。サイトによっては、映像・音声コンテンツに別途ライセンス条件を設けています。サイトの再利用条件を確認してください。
- DRM がないことと、法律上保護されていないことは同じではありません。 一部の法域では、簡易なトークンや署名方式であっても、それを回避すると、迂回禁止に関する問題(米国 DMCA §1201)が生じる可能性があります。zahori は DRM を拒否し、アクセス制限を決して突破しないことで、安全な側にとどまります。この方針を守ってください。
- EU では、テキスト・データマイニングに関する例外(DSM 指令第 3 条および第 4 条)により、権利者が機械可読形式でオプトアウトしていない限り、合法的にアクセスできる著作物の複製が認められます。オプトアウトを尊重してください。
利用するサイトの利用規約、著作権、現地の法律を遵守する責任は、利用者にあります。判断に迷う場合は、明示的にオープンなコンテンツを優先し、機関に問い合わせてください。
API
| エクスポート | 機能 |
|---|---|
resolve(url, opts?) | ページの背後にあるストリームを解決します(プロファイルまたは汎用フロー) |
validate(stream, opts?) | オラクル:これは実際のメディアかどうかを確認します |
download(stream, path, opts?) | ヘッダーを再現しながら、ffmpeg で記録します |
probe(url, opts?) | プロファイル作成向けに、ページの構造化された調査を行います |
testProfile(profile, url, opts?) | 候補プロファイルを実行して評価します |
saveProfile(profile, dir) / loadProfiles() | プロファイルを保存/読み込みます |
discoverProfile(url, opts?) / healProfile(profile, url, opts?) | モデルを使って学習/修復します |
runProfile(profile, url, opts?) / runProfileOnPage(page, ...) | プロファイルを実行します(専用ブラウザー/利用者のブラウザー) |
hostPattern(url) / profileIdFromUrl(url) | プロファイル作成用のヘルパー |
パッケージには、TypeScript の型定義一式が含まれています。
ドキュメント
詳しいガイドは docs/ にあります。
- CLI:すべてのコマンドとフラグ
- ライブラリ API:エクスポートされる関数と型
- プロファイル:zahori にサイトを教えるための JSON 形式
- MCP:コーディングエージェントから zahori を使用する方法
- レシピ:最初から最後までの実例
コントリビューション
Issue や PR を歓迎します。開発環境のセットアップ、テストスイート、リリースプロセスについては、CONTRIBUTING.md をご覧ください。
ライセンス
MIT © Jose Sepulveda
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。