cobalt tools(imputnet/cobalt)は、URLを1つ渡すとそのページで配信されているメディアの直リンクを返すだけの道具で、★42,283・fork 3,662を集めている。広告もトラッカーもアナリティクスも持たず、取得したファイルをサーバーに残さない——という設計が支持された結果だが、その規模から想像するほど今のcobaltは元気ではない。手元でセルフホストし、公式のテスト165件を全部走らせて、どこが生きていてどこが死んでいるかを数えた。
この記事のポイント
・公式テストの合格率は 115/165(69.7%)。reddit・vimeo・twitch・newgrounds の4サービスは全滅
・リポジトリは21サービスを持つが、公開インスタンスが提供しているのは20(youtube が無い)
・main の最終コミットは 2026-04-06。他ブランチも main より進んでいない
セルフホストできる自動化基盤の選び方そのものを見渡したい場合は、AI自動化ツール|ノーコードからコードまで2026年版の比較と選び方に全体像がある。ここではcobalt1本に絞って、コードと実測から中身を見ていく。
cobalt tools の仕組み——「保存しない」ための2つの返し方
cobaltのAPIは驚くほど単純で、POST / にURLを投げると JSON が返る。返り方には主に2種類ある。
・redirect — 元のサービスが配信している直リンクをそのまま返す。cobaltのサーバーはデータを一切通さない
・tunnel — cobaltのサーバーを経由するURLを返す。映像と音声が別ストリームで配信されている場合など、その場で結合が必要なときに使う
この2択が、cobaltが「ファイルをサーバーに保存しない」と言える根拠になっている。redirect はそもそも通らない。tunnel は通るが、ストリームとして中継するだけでディスクには書かない。加えてトンネルURLは短命な署名付きで、発行したインスタンス以外では使えない。
このほか picker(複数候補があるとき選ばせる)と error がある。実測で観測した error は error.api.fetch.empty——上流サービスが期待した内容を返さなかった、という抽象度の高いコードで、原因の切り分けにはあまり役立たない。
構成は pnpm ワークスペースで3つに分かれている。
| ディレクトリ | 役割 | 備考 |
|---|---|---|
api/ |
解析とトンネルの本体 | @imput/cobalt-api v11.7.1・Node 18.17以上 |
web/ |
SvelteベースのWeb UI | Cloudflare Workers 前提の wrangler.jsonc を同梱 |
packages/ |
共有ライブラリ | バージョン情報など |
APIだけを立てればUIは無くても動く。逆にUIだけを別ホストに置いて、APIは自前という分離もできる。Web UIはブラウザ上で動き、取得処理はAPI側が担うので、UIをどこに置くかとデータがどこを通るかは独立している。
実測:cobalt tools の公式テスト165件のうち50件が落ちる
cobaltは api/src/util/tests/ にサービスごとのテストフィクスチャを持っている。node src/util/test を走らせると、各URLに対して「どの status が返るべきか」を検証する。重要なのは、このテストがメディアを取得しないことである。runTest() は URL を正規化し、extract() でホストとパターンを判定し、match() で解決を試み、返ってきた status と HTTP コードが期待どおりかだけを見る。つまりこれは抽出器の生存確認であって、ダウンロードのテストではない。
既定では不安定なサービス(bilibili・instagram・facebook・youtube・vk・twitter・reddit)が除外されるので、TEST_IGNORE_SERVICES を空に近い値で上書きして全21サービスを走らせた。
git clone --depth 1 https://github.com/imputnet/cobalt.git
cd cobalt/api && pnpm install
API_URL="http://localhost:9000/" TEST_IGNORE_SERVICES="none" node src/util/test
結果は 115件合格・50件不合格(合格率69.7%)。サービス別に並べると差が極端だった。
| 状態 | サービス | 合格 |
|---|---|---|
| 全滅 | 0/8 | |
| 全滅 | vimeo | 0/6 |
| 全滅 | twitch(clips) | 0/4 |
| 全滅 | newgrounds | 0/4 |
| ほぼ全滅 | bilibili | 1/7 |
| 半分 | loom | 3/6 |
| 半分 | tiktok | 3/5 |
| 半分 | vk | 5/8 |
| おおむね健全 | 10/14 | |
| おおむね健全 | youtube | 15/20 |
| おおむね健全 | facebook / streamable | 4/5 |
| 良好 | rutube / soundcloud | 9/10 |
| 良好 | 21/22 | |
| 満点 | bsky・dailymotion・ok・pinterest・snapchat・tumblr | 全件 |
分布が二極化しているのは、抽出器の壊れ方に理由がある。上流サービスがAPIの形やプレイヤーの実装を変えると、そのサービスの抽出器は一斉に効かなくなる。 vimeo が 0/6 なのは「4k progressive」「720p progressive」「1080p dash」など全パターンが同じ経路で解決に失敗しているからで、個別のケースが偶然落ちているのではない。逆に bsky や pinterest が満点なのは、配信の形が単純で変更も少ないためだ。
一方で instagram の 10/14 のように、同じサービス内でも成否が割れるケースもある。instagram では「reel」が期待した redirect ではなく tunnel を返し、「single photo post」が error.api.fetch.empty で落ちた。テスト側の期待値が古い可能性と、抽出器が劣化した可能性の両方があり、実行結果だけでは切り分けられない。
開発者自身が「不安定」と名指ししているサービスがある
テストランナーのソースには、外的要因で頻繁に落ちるサービスが定数として書き込まれている。
// services that are known to frequently fail due to external
// factors (e.g. rate limiting)
const finnicky = new Set(
process.env.TEST_IGNORE_SERVICES
? process.env.TEST_IGNORE_SERVICES.split(',')
: ['bilibili', 'instagram', 'facebook', 'youtube', 'vk', 'twitter', 'reddit']
);
既定でテストから除外される7サービスがこれである。cobalt側が「安定して通らない」と認めている一覧と読める。ここに挙がっているものは、自分の環境で通らなくても仕様の範囲内と考えたほうがよい。
興味深いのは、この7つと実測結果が完全には一致しないことだ。twitter は 21/22、facebook は 4/5 と高い合格率を出した一方、除外リストに載っていない vimeo・twitch・newgrounds が全滅している。つまり除外リストは古く、劣化の実態を反映していない。リストが更新されていないこと自体が、4.7か月の停止を裏づける材料にもなっている。
TEST_IGNORE_SERVICES を空文字にすると '' が1要素として入ってしまうので、実測では "none" のような存在しないサービス名を渡して全件を対象にした。除外を効かせたいときはカンマ区切りでサービス名を並べる。
APIの叩き方——最小のリクエストとよく使う指定
docs/api.md にある仕様のうち、実際に使う部分は少ない。POST / に Accept: application/json と Content-Type: application/json を付け、本文に url を入れるだけが最小形になる。
curl -s -X POST http://localhost:9000/ \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"url": "<自分が権利を持つ、または許諾済みの素材のURL>"}'
返る JSON の status が前述の4種(redirect / tunnel / picker / error)で、redirect と tunnel では url に取得先が入る。よく使う追加指定は次のあたりになる。
・videoQuality — max / 4320 〜 144。要求より高い解像度が無ければ最も近いものに落ちる
・downloadMode — auto / audio(音声のみ)/ mute(音声を落とした映像)
・audioFormat — best / mp3 / ogg / wav / opus
・filenameStyle — classic / pretty / basic / nerdy。返却されるファイル名の作り方が変わる
テストフィクスチャの名前(「1080p video muted」「reel (isAudioOnly)」など)は、これらの組み合わせをそのまま指しているので、どの指定が壊れているかまでテスト結果から読める。実測で loom が 3/6 だったのは「1080p video」と「1080p video (muted)」が両方落ちたためで、解像度指定まわりの解決に失敗していると分かる。
公開する場合の保護と、運用範囲を絞る設定
自分だけで使うならローカルで完結するが、社内の複数人で共有する時点で保護が要る。docs/protect-an-instance.md が示す選択肢は2つある。
・Cloudflare Turnstile — ブラウザからの利用を想定。人間確認を通ったリクエストだけを受ける
・APIキー方式 — プログラムからの利用を想定。キーファイルで許可先を管理する
併用もできる。いずれも設定しないインスタンスを公開すると、第三者に自由に使われる。cobaltは取得したファイルを保存しないので情報漏洩の形は取りにくいが、帯域と、上流サービスから見たときの発信元が自分になるという点で無防備な公開は避けたい。
あわせて docs/api-env-variables.md には、有効にするサービスを絞る指定がある。用途が「自組織の配信アーカイブの回収」に限られるなら、その配信基盤に対応するサービスだけを有効化し、残りは無効のままにしておくのが運用として明快になる。何を有効にしたかが、そのインスタンスが何のための道具かの宣言になる。
リポジトリにある機能が、公開インスタンスにあるとは限らない
ここが実務的にいちばん重要な発見だった。公開インスタンスの状態を確認する。
curl -s https://api.cobalt.tools/ | python3 -m json.tool
2026-08-27 時点の応答は次のとおりだった。
・cobalt.tools — HTTP 200(応答 0.09秒)
・api.cobalt.tools — HTTP 200、version: 11.7.1、url: https://sunny.imput.net/
・git.branch: fix-redis、commit: 971168eb(リポジトリの公開ブランチ一覧には無い名前)
・services[] — 20件
この20件に youtube が入っていない。リポジトリの service-config.js が持つのは21サービスで、youtube は含まれる。しかも前節のとおり youtube の抽出器テストは 15/20 で合格しており、コードとしては動いている。それでも公開インスタンスは提供していない。
service-config.js"] --> B["21サービス
(youtube を含む)"] B --> C{"公開インスタンス
api.cobalt.tools"} B --> D{"自前インスタンス"} C --> E["services[] は 20
youtube は提供しない"] D --> F["21すべてが対象
ただし合格率 69.7%"] style E fill:#fff4e5 style F fill:#e8f5e9
この差は運用上の判断であって、技術的な故障ではない。cobaltは「何を提供するか」をインスタンス運用者が決められる設計になっていて、docs/api-env-variables.md にはサービスの有効・無効を環境変数で切り替える指定がある。公開インスタンスを運用する側が範囲を絞るのは自然な選択で、リポジトリのREADMEやtopicsに youtube-downloader が残っていることと矛盾はしない——コードの能力と、運用の方針は別のレイヤーにあるという、それだけのことである。
裏を返せば、自分でインスタンスを立てるということは、その判断を自分で引き受けるということでもある。自分がアップロードした素材の回収や、明示的に再利用が許諾されている素材(CC ライセンスの映像・自組織の配信アーカイブなど)を扱う用途に範囲を限るなら、有効にするサービスもその範囲に絞って設定するのが素直な運用になる。
どこまでが「使ってよい範囲」かを設定で表明する
cobaltは取得先を選ばない。だから範囲を決めるのは道具ではなく運用側になる。実務で無理なく成立するのは、取得対象が自分の管理下にあるか、再利用が明示的に許諾されているケースに絞る使い方だ。具体的には次のような場面が挙がる。
・自組織が配信したライブアーカイブや、自分のアカウントに上げた素材を、配信基盤から手元へ回収する
・クリエイティブ・コモンズなど、再配布・改変が明示的に許諾されたライセンスの素材を集める
・権利者から素材提供の合意を得たうえで、受け渡しの手段としてURLを使う
この3つはいずれも「誰の素材か」がはっきりしている。逆に言えば、そこが曖昧なものを取りにいく用途にcobaltを使う構成にはしない、という判断が先に来る。有効化するサービスを絞る設定は、その判断を設定ファイルの形で残す手段として使える。監査のときに「このインスタンスは何のためのものか」を口頭でなく設定で説明できるのは、社内ツールとしては小さくない利点になる。
なお、cobaltは認証の壁や暗号化された配信を破る仕組みを持たない。解析しているのはそのページが公開の形で配信しているストリームであり、ログインが必要なコンテンツを扱うには利用者自身のCookieを cookies.json として渡す必要がある(examples/cookies.example.json に雛形がある)。つまり「自分がアクセスできるものにしかアクセスしない」という前提の上に立っている。この点は、道具の能力を過大にも過小にも見積もらないために押さえておきたい。
main は4.7か月止まっている
★42,283という数字から連想する開発の勢いと、実際のコミット状況は一致しない。
・main の最終コミット — 2026-04-06(api/package: revert redis to 4.7.1)。実測時点で約4.7か月前
・develop ブランチ — main より3コミット遅れ、main より進んだコミットは0
・公開ブランチは api-client / develop / main / nicovideo / temp-forced-yt-player の5本
・GitHub Releases — 公開なし(タグによるリリース運用をしていない)
・オープンな Issue / PR — 266件
nicovideo や temp-forced-yt-player といったブランチ名は、日本のサービス対応や YouTube プレイヤー変更への対処が試みられた痕跡に見えるが、いずれも main には入っていない。前節で見た「4サービス全滅」は、この停止期間と整合する。上流サービスは変わり続けるのに、抽出器の更新が4.7か月止まれば、壊れる先から壊れていく。
これは cobalt に限らず、この種のツール全般に共通する構造だ。当サイトでも yt-dlp使い方完全ガイド2026 で更新頻度が実用性に直結することを、gallery-dl使い方完全ガイド2026 で対応サイト数の読み方を扱っている。cobaltを選ぶ判断は、「今動くか」ではなく「壊れたときに直る見込みがあるか」で下すべきというのが実測から出る結論になる。
「壊れている」と「提供していない」を自分で切り分ける
実測を通して分かったのは、cobaltで何かが取得できないとき、原因は少なくとも3層に分かれるということだった。切り分けの順序を決めておくと、無駄な調査を避けられる。
| 層 | 症状 | 確認方法 |
|---|---|---|
| インスタンスの提供範囲 | そのサービス自体が対象外 | curl -s <API>/ の services[] に名前があるか |
| 抽出器の劣化 | error.api.fetch.empty が返る |
node src/util/test <service> でそのサービスだけ流す |
| 指定の組み合わせ | 特定の解像度・モードだけ落ちる | 落ちたテストケース名を読む(例: 1080p video muted) |
上から順に見ると速い。公開インスタンスで youtube が使えないのは1層目の話で、コードやネットワークをいくら調べても答えは出ない。逆に vimeo が全滅しているのは2層目で、これはインスタンスを変えても直らない。loom の 3/6 は3層目で、解像度指定を落とせば通る可能性がある。
node src/util/test <サービス名> は個別実行にも対応しているので、導入判断のときは自分が使うサービスだけを流すのが実際的だ。21サービス全部を流すと数分かかるが、1サービスなら数秒で終わる。
cd cobalt/api && API_URL="http://localhost:9000/" node src/util/test vimeo
この1コマンドで「そのサービスが今のcobaltで生きているか」が分かる。★の数やREADMEの対応表を読むより、はるかに確度が高い判断材料になる。
セルフホスト手順と、実際につまずく場所
起動自体は簡単だった。必須の環境変数は API_URL だけである。
# Node 18.17 以上 / pnpm が必要
git clone --depth 1 https://github.com/imputnet/cobalt.git
cd cobalt/api
pnpm install # 手元では 24.1秒で完了
echo 'API_URL="http://localhost:9000/"' > .env
pnpm start
Docker Compose を使う場合は docs/run-an-instance.md にサンプルがあり、watchtower による自動更新まで含まれている。ただし更新元のイメージが4.7か月更新されていないので、自動更新の恩恵は現状ほぼ無い。
公開インターネットに出す場合の注意は docs/protect-an-instance.md にまとまっている。要点は2つで、Cloudflare Turnstile による人間確認か APIキー方式、あるいは両方を使うこと。無防備なインスタンスは第三者に踏み台として使われるため、社内利用でも最低限アクセス制御は要る。JWT の秘密鍵生成用に pnpm token:jwt が用意されている。
環境固有のつまずきとして、公式ドキュメントが挙げているのは Ubuntu 22.04 の DNS 問題である。同梱の ffmpeg-static バイナリが名前解決できず、nscd を入れて起動する必要がある。
sudo apt install nscd && sudo service nscd start
手元の macOS では発生しなかった。逆に macOS で気をつけるのは、redis を使うクラスタ構成(instanceCount > 1)にしたときの依存で、最終コミットがまさに redis のバージョン差し戻し(4.7.1 へ revert)だった点からも、この周辺は安定していないと見たほうがよい。
何と比べるか——同種ツールとの棲み分け
| ツール | 形態 | 対応範囲 | 更新状況(2026-08-27) |
|---|---|---|---|
| cobalt | API+Web UI | 21サービス(公開版20) | main が4.7か月停止 |
| yt-dlp | CLI | 数千サイト | 活発 |
| gallery-dl | CLI(画像主体) | 269サイト | 活発 |
| MeTube | yt-dlp の Web UI | yt-dlp に準拠 | yt-dlp に追随 |
cobaltの強みはAPIとして組み込めることとUIの完成度にあって、対応範囲の広さではない。逆に「対応サイトが多く、更新が続いていること」を最優先するなら、抽出器を持つ層は yt-dlp に任せ、UIが欲しければ MeTube のような薄いラッパーを重ねるほうが現実的だ。cobaltを選ぶ理由になるのは、自前サービスにメディア解決の機能をHTTP API として組み込みたいケースだろう。その場合でも、対象を自分が権利を持つ素材や許諾済みの素材に限定し、必要なサービスだけを有効化して運用範囲を明示しておくのが扱いやすい。
まとめ
・cobalt tools は URL からメディアの直リンクかトンネルURLを返すAPI。ファイルをサーバーに保存せず、広告もトラッカーも持たない。★42,283・AGPL-3.0
・公式テストの合格率は 115/165(69.7%)。 reddit・vimeo・twitch・newgrounds の4サービスは全滅で、bsky・pinterest・tumblr など6サービスは満点
・公開インスタンスは21サービス中20しか提供せず、youtube が無い。 コードには存在し、テストも15/20 で合格している。運用上の判断であってバグではない
・main は 2026-04-06 から4.7か月止まっている。 develop も main より進んでいない。抽出器は上流の変更で壊れ続けるため、この停止は合格率に直結する
・セルフホストは容易(Node 18.17+pnpm、必須の環境変数は API_URL のみ)。公開する場合は Turnstile かAPIキーでの保護が要る
「星が多い=今も健全」という読み替えが最も危険な種類のリポジトリである。取得対象を自分の素材や許諾済みの素材に限って組み込むぶんには十分に使えるが、壊れたサービスが直る見込みは現時点で薄い。採用するなら、必要なサービスが自分の環境で通ることを node src/util/test で先に確認してから決めたい。この確認は数分で終わり、しかもメディアを取得せずに済む。
参照ソース
・imputnet/cobalt — 公式リポジトリ。★42,283・fork 3,662・AGPL-3.0・api v11.7.1(2026-08-27 時点)
・docs/run-an-instance.md — セルフホスト手順(Docker / 素の Node 両方)
・docs/protect-an-instance.md — Turnstile / APIキーによる保護
・docs/api.md — API仕様(redirect / tunnel / picker / error)
・本記事の実測は 2026-08-27 に macOS・Node v22.13.1 で実行した結果です。テストはメディアの解決可否のみを検証するもので、ファイルの取得は行っていません