YouTube→Obsidian自動変換ツールをGitHubで公開して汎用化した
前回、YouTube料理動画をObsidianのレシピノートに自動変換する仕組みを作った。~/scripts/ に直置きしたスクリプト2本で、とりあえず43本の料理動画を捌けるところまでは行った。あの後Claude Codeと一緒にコードレビュー、テスト追加、CI整備をやってGitHubで公開し、さらにレシピ専用ツールから汎用ツールへと作り変えたので、その過程を書いておく。
コードレビューと修正
まずClaude Codeに既存のスクリプトをレビューしてもらった。指摘されたのは主にこのあたり:
- 文字起こしファイルの書き込みが非アトミック(途中で落ちると壊れたファイルが残る)
- エラーハンドリングが雑(全滅しても正常終了してしまう)
- mlx-whisperのインポートチェックが遅い
アトミック書き込みは tempfile.mkstemp で一時ファイルに書いてから rename する定番パターンに修正。エラー時の終了コードも直した。
テストとCI
外部依存(yt-dlp、mlx-whisper、ファイルシステム)をモックして25本のテストを書いた。pytest + GitHub Actionsで回している。mlx-whisperはApple Silicon専用なのでCI上ではインストールせず、モックだけで検証する構成にした。
地味にハマったのが、テスト用のモックテキストが短すぎてハルシネーション検出に引っかかる問題。「こんにちは」みたいな短い文字列を返すモックにしていたら、50文字未満で自動的にハルシネーション扱いになっていた。
Whisperのハルシネーション対策
実際に43本処理してみると、何本かでWhisperが同じフレーズを延々繰り返す「ハルシネーション」が発生した。無音や環境音だけの区間で起きやすい。
対策として is_hallucinated() 関数を入れた。チェックしているのは3つ:
- テキストが50文字未満(短すぎる)
- 同一フレーズが5回以上連続する正規表現パターン
- 句読点・記号の比率が80%超(内容がない)
運用の改善
細かいが実際に使ってみて効いた改善をいくつか。
- 1件ずつ処理 — 最初は全文字起こしを一括でClaude CLIに渡していたが、処理が詰まって進まなくなった。1件ずつループに変更し、成功したらdoneディレクトリに移動、失敗したらそのまま残してリトライ可能にした
- Ctrl-Cで止まるようにする — ループ処理にしたら中断しても次のファイルに進んでしまう。
trap INTでシグナルを捕捉して即座に終了するようにした - Macが重くならないようにする — WhisperとClaude CLIを同時に動かすとファンが回りっぱなしになる。
nice -n 10で優先度を下げて、caffeinate -iでスリープを防止 - Obsidianとの共存 —
_transcripts/だとObsidianのファイルエクスプローラに表示されてしまう。.transcripts/に変更してドットプレフィックスで非表示にした
GitHubで公開
ここまで育てたスクリプトを youtube-to-obsidian としてGitHubに上げた。~/scripts/ にはシンボリックリンクだけ残す構成。curl 一発でセットアップできるインストールスクリプトも用意した。
curl -fsSL https://raw.githubusercontent.com/nobu666/youtube-to-obsidian/main/install.sh | bashClaude Code のスキル(グローバルコマンド)としても登録できるので、どのプロジェクトで作業中でも /youtube-to-obsidian で呼び出せる。
レシピ専用から汎用ツールへ
公開した時点ではまだ recipe というコマンド名で、プロンプトも料理動画専用だった。でも文字起こし部分は完全に汎用だし、変換プロンプトを差し替えればレシピ以外にも使える。ということで汎用化することにした。
コマンド名とプロンプトの切り替え
コマンド名を recipe から youtube-to-obsidian に改名。変数名も RECIPE_DIR → OUTPUT_DIR のように汎用的なものに揃えた。
プロンプトは prompts/ ディレクトリに複数置けるようにして、-p オプションで切り替える方式にした。
# デフォルト(汎用ノート形式)
youtube-to-obsidian https://www.youtube.com/watch?v=XXXXX
# レシピ
youtube-to-obsidian -p recipe https://www.youtube.com/watch?v=XXXXX
# 講義ノート
youtube-to-obsidian -p lecture https://www.youtube.com/playlist?list=XXXXX用意したプロンプトは5種類。
| プロンプト | 用途 | 出力例 |
|---|---|---|
default | 汎用(構造化ノート) | 要約 + セクション分け |
recipe | 料理動画 → レシピ | 材料リスト + 手順 |
lecture | 講義・セミナー → 要約ノート | 要旨 + キーポイント + 詳細ノート |
workout | 筋トレ・ヨガ → メニュー表 | 種目テーブル + フォーム解説 |
tool | ツール解説 → 手順書 | セットアップ + 使い方 + Tips |
出力先をプロンプトごとに分ける
レシピと講義ノートと筋トレメニューが同じフォルダに入るのは嫌なので、プロンプトファイルのヘッダで出力先を指定できるようにした。
output_dir: ~/Library/Mobile Documents/.../Obsidian/Vault/YouTube/レシピ
---
上の文字起こしをObsidianレシピ形式に変換して...output_dir: ヘッダで出力先を指定し、--- 以降がClaudeに渡されるプロンプト本文。フォルダがなければ自動作成する。-o オプションで一時的に上書きもできる。
全体の構成
前回の記事ではシンプルな直列パイプラインだったが、プロンプト切り替えと出力先分岐が加わってこうなった。
字幕優先で爆速化
汎用化したので講義動画を試してみたら、問題が発覚した。Whisperでの文字起こしが遅すぎる。20分の動画に10分以上かかる。料理動画は5〜10分のものが多かったからギリギリ許容範囲だったが、1時間の講義には使い物にならない。
解決策はシンプルで、YouTubeの字幕を先に取りに行くようにした。日本語の動画ならほとんどの場合、手動字幕か自動生成字幕がある。字幕があれば数秒で取得できるので、Whisperの出番はほぼなくなった。
あわせてWhisperのモデルをlarge-v3からlarge-v3-turboに変更した。前回の記事でmediumからlarge-v3に上げた経緯を書いたが、large-v3は精度はいいものの遅い。large-v3-turboは精度をほぼ維持したまま速度が改善されている。もっとも字幕優先にしたことで、Whisperが動くケース自体がほとんどなくなったのだが、フォールバック先として速いに越したことはない。
実際に試してみた
3種類の動画で試した結果。
ツール解説動画(obsidian-skills) — 字幕から取得、数秒で文字起こし完了。セットアップ手順、使い方、Tipsがきれいに分かれたノートになった。
筋トレ動画(腹筋スーパーセット) — 字幕から取得。種目テーブル + フォームのポイントという形式で出力された。「膝は絶対に曲げない(曲げると効きが激減)」みたいな実践的な注意点もちゃんと拾っている。
講義動画(堀江貴文 拓殖大学講演 1時間) — 字幕から取得、文字起こし自体は速いがClaude CLIでの構造化に2〜3分。要旨 + キーポイント + 詳細ノート + 引用という構成で、1時間の講演がきれいに整理された。Whisperで文字起こしから始めていたら30分以上かかっていたはずなので、字幕優先の効果が一番大きいのはこういう長尺動画だ。
振り返り
前回の記事を書いた時点では ~/scripts/ に直置きした料理専用スクリプトだったものが、GitHubで公開された汎用ツールになった。レビュー、テスト、CI、コマンド改名、プロンプトシステム、字幕優先化、モデル変更。これを全部Claude Codeとの対話で進めた。
特に字幕優先への変更は、講義動画を実際に試してみなければ気づかなかった。料理動画だけで使っているうちはWhisperの速度が問題にならなかったので、用途を広げたことで初めて見えたボトルネックだった。「汎用化したら新しい課題が見つかり、それを解決したらさらに良くなった」というのは、ものを作っていて一番楽しい瞬間かもしれない。
youtube-to-obsidian — Apple Silicon Macと Claude Code があれば動く。プロンプトを追加すればどんな動画でもObsidianノートにできるので、自分の用途に合わせてカスタマイズしてほしい。