tech-feed-catalog.notebooklm-radio 導入ガイド
← ビルダー
0 / 10

はじめに

追っている技術の新着記事を、毎朝 NotebookLM の音声ラジオにして届ける仕組みを、自分の GitHub に作ります。作業は約 20 分。最初の音声ができるまでさらに 20 分ほどです。

流れビルダーで設定を作る → GitHub にコピーを作る → 設定を入れる → PC でウィザードを一度だけ走らせる → 翌朝から勝手に届く。
GitHub無料アカウント。ここで毎朝の処理が動く
Google / NotebookLMhttps://notebooklm.google.com が開けること。無料枠でも動く
Slack か Discord通知先。無くても動くが、エラーも届かなくなる
PC + ブラウザ初回と 3.5 週ごとの Google ログイン用。常駐はしない

PC には Python 3.10 以上、uv、GitHub CLI(入れたら一度 gh auth login)が要りますが、足りなければステップ 4 のウィザードが教えてくれます。

知っておくこと NotebookLM に公式 API は無く、非公式の CLI であなた自身の Google セッションを使います。Google 側の変更で止まることがあり、約 3.5 週ごとに再ログインが要ります(ステップ 8)。音声の生成には上限があり、番組の数 × 1 日の実行回数がその日の本数です。
1 / 10

設定を作る

設定ファイルは config.yaml の 1 枚だけ。ビルダーで 3 分で作れます。ブラウザだけで完結します(外に問い合わせるのは、カタログ外フィードの「確認」だけ)。

ビルダーの最初の画面1
1「はじめる」を押す(前回の続きがあれば「続きから」になる)
技術名のチップとおすすめセット234
2おすすめセットを押す → 5 フィードが 1 つの番組として入る
3技術名のチップを押して足す
4右上の件数が増えるのを確認
  1. 何を追う? — おすすめセットかチップを押す。カタログに無いもの(Zenn のトピック、Qiita のタグ、任意の URL)は同じ画面の下から。「確認」で本当にフィードかを見に行く。
  2. 番組に分ける — 番組 = NotebookLM のノートブック 1 冊 = 1 日 1 本のラジオ。混ぜて違和感がある話題は分ける。名前は自由、雰囲気は「じっくり / 手短に」。
  3. いつ聴く? — 朝の時刻、2 回目の有無、NotebookLM のプラン。「番組数 × 実行回数 = 1 日の本数」が上限を超えると赤くなる。
  4. できあがり — config.yaml をダウンロードし、cron の 2 行をコピーしておく。
できあがり画面56
5「ダウンロード」で config.yaml を保存
6cron の「コピー」を押す(ステップ 3 で貼る)
共有リンク 「共有リンク」を押すと、この構成を丸ごと復元できる URL がコピーされます。あとで足し引きするときはそこから。
2 / 10

GitHub に自分のコピーを作る

notebooklm-radio はテンプレートリポジトリです。「Use this template」で、あなたのアカウントの下に同じ中身の新しいリポジトリができます。fork ではなく、作者との繋がりの無い完全に自分のものです。

notebooklm-radio リポジトリのページ1
1緑の「Use this template」→「Create a new repository」を押す
Create a new repository のフォーム23
2テンプレートが inoueUJ/notebooklm-radio になっているか確認
3Owner が自分になっているか確認し、名前を入れる(例: my-radio)
Choose visibility の欄4
4Choose visibility を Private にしてから「Create repository」を押す
なぜ Private? 毎朝の処理が「どこまで読んだか」の記録(state.json)をあなたのリポジトリにコミットし続けます。購読の履歴なので、公開しない方がよいものです。
3 / 10

設定をコピーに入れる

リポジトリを PC に clone し、ステップ 1 のファイルで置き換えて push します。まだ何も動きません(ログイン情報が無いので、動いても止まります)。

$ gh repo clone you/my-radio
$ cd my-radio
# 1. ダウンロードした config.yaml で丸ごと置き換える(feeds: の下に貼るのではない)
$ cp ~/Downloads/config.yaml ./config.yaml
# 2. .github/workflows/rss-radio.yml の "- cron:" 2 行を、ビルダー「できあがり」の cron 2 行に差し替える
# 3. 検査(何も実行しない。設定ファイルを読んで問題を列挙するだけ)
$ python radio_batch.py --check-config
config.yaml OK: 8 feed(s), topics: AI, インフラ, 言語
$ git add -A && git commit -m "my feeds" && git push
  • 直すのは 2 か所だけ: config.yaml を丸ごと置き換える(ダウンロードしたファイルで上書き。feeds: の下に貼るのではない)と、.github/workflows/rss-radio.yml の - cron: 2 行をビルダーの 2 行に差し替える。
  • 検査が NG と言ったら、列挙された箇所を直します。知らないキーはわざとエラーにしています(typo が黙って既定値に落ちるのが一番怖いため)。
  • 手元に yaml などのパッケージが無くて検査が動かない場合は、pip install -r requirements.txt で入ります。CI でも毎回同じ検査が走るので、飛ばしても壊れたまま動くことはありません。
  • ファイルを GitHub の画面で直接編集しても構いません。clone するのはウィザードのためです。
4 / 10

ウィザードを一度だけ走らせる

NotebookLM に入るには、あなたの Google ログインが要ります。ブラウザでしか取れないので、PC で 1 回だけログインし、その結果をリポジトリの secret(GitHub Actions だけが読める秘密の置き場)に渡します。それを全部やるのが setup.py です。

$ python scripts/setup.py
notebooklm-radio セットアップ

1/6  環境の確認
  ✓ Python                       3.12.4
  ✓ リポジトリ                   you/my-radio
  ✓ 固定バージョン               notebooklm-py 0.8.4(requirements-notebooklm.txt)
  ✓ uv                           uv 0.9.24
  ✓ GitHub CLI                   インストール済み・ログイン済み
  ✗ notebooklm CLI               インストールされていない
    → uv tool install "notebooklm-py[browser]==0.8.4"(このウィザードでもできる)
  ✗ ログイン(ci プロファイル)  認証ファイルがまだ無い
    → notebooklm -p ci login --fresh(このウィザードでもできる)
  ✗ secret NOTEBOOKLM_AUTH_JSON  未設定
    → 上のログインからウィザードが設定する
  ! secret NOTIFY_WEBHOOK_URL    未設定
    → 無いとエラーも含めて通知が一切届かない
  ✓ config.yaml                  config.yaml OK: 8 feed(s), topics: AI, インフラ, 言語

2/6  notebooklm CLI
notebooklm CLI(notebooklm-py[browser]==0.8.4)を uv でインストールしますか? [Y/n] y
  $ uv tool install --force "notebooklm-py[browser]==0.8.4"

3/6  Google ログイン(CI 用プロファイル)
  $ notebooklm -p ci login --fresh
  ブラウザが開きます。NotebookLM を使える Google アカウントでログインしてください。
  ブラウザの古いセッションは消してから開くので、Google へのログインを毎回やり直します。
  ci プロファイルは CI 専用で、普段使いの default プロファイルとは分けておきます。
  ローカルで notebooklm を使うたびに Cookie が更新され、CI に渡したコピーの寿命が縮むためです。
  (ブラウザで普通にログインする。終わるとターミナルに戻る)
  $ notebooklm -p ci auth check --test --passive
  ログインできていることを確認しました。

4/6  リポジトリの secret NOTEBOOKLM_AUTH_JSON
  $ gh secret set NOTEBOOKLM_AUTH_JSON -R you/my-radio(/Users/you/.notebooklm/profiles/ci/storage_state.json から)
  NOTEBOOKLM_AUTH_UPDATED=2026-09-27 をリポジトリ変数に記録しました。

5/6  リポジトリの secret NOTIFY_WEBHOOK_URL
  Slack の Incoming Webhook か Discord の Webhook の URL を貼り付けてください(入力は表示されません)。
  Slack: api.slack.com/apps → 自分のアプリ → Incoming Webhooks → Add New Webhook to Workspace
  Discord: チャンネルの編集 → 連携サービス → ウェブフック → 新しいウェブフック → ウェブフック URL をコピー
  空のまま Enter を押すと飛ばせます(その場合、エラーも含めて通知は届きません)。
  Webhook URL: (貼り付けても表示されない)
  $ gh secret set NOTIFY_WEBHOOK_URL -R you/my-radio

6/6  初回の実行
ワークフローを今すぐ実行しますか?(今日のノートブックを作り、音声の生成を始めます) [Y/n] y
  $ gh workflow run rss-radio.yml -R you/my-radio
  開始しました: https://github.com/you/my-radio/actions/runs/1234567890
終わるまでここで見届けますか?(3〜5 分ほど) [Y/n] y
  $ gh run watch 1234567890 -R you/my-radio --exit-status --compact
  成功しました。結果は Webhook に届きます。音声は NotebookLM の中で 20 分ほどかけて作られます。

完了しました。この後の流れ:
  - 数分以内に、今日の記事一覧とノートブックへのリンクが Webhook に届きます。
  - 音声は NotebookLM の中で 20 分ほどかけて作られます(通知は「開始した」で、「完了した」ではありません)。
  - Google のセッションは約 3.5 週で切れます。エラー通知が来たら python scripts/setup.py renew を実行してください。
  - フィードや話し方は config.yaml で変えられます(https://inoueuj.github.io/tech-feed-catalog/ で作り直すこともできます)。

webhook URL の取り方

  • Slack: api.slack.com/apps → Create New App → From scratch → 左メニュー Incoming Webhooks → On → Add New Webhook to Workspace → チャンネルを選ぶ → https://hooks.slack.com/services/… をコピー。
  • Discord: 通知したいチャンネルの設定 → 連携サービス → ウェブフック → 新しいウェブフック → ウェブフック URL をコピー。
PC の役割はこれだけ 何も常駐しません。ログインは普段使いと別の ci プロファイルに保存されます。分けるのは、混ぜると認証の寿命が 3.5 週から 3 日に縮むためです。認証ファイルの中身は画面にもシェルの履歴にも出ません。Windows(PowerShell)でも同じ手順です。
  • 「workflows are disabled」のような失敗 → テンプレートから作った直後は Actions が無効なことがあります。リポジトリの Actions タブで有効化して、gh workflow run rss-radio.yml かウィザードをもう一度。
  • notebooklm が見つからない → 新しいターミナルを開く(インストール後に PATH が変わる)。
  • python scripts/setup.py doctor はいつでも実行でき、何も変えません。
5 / 10

初回実行を確かめる

3 か所で確かめます。GitHub の Actions、通知、NotebookLM。初回は既読状態の初期化として各フィードの最新 1 件だけを処理し、過去分は読んだことにします(洪水は起きません)。

Actions タブの RSS Radio Automation12
1手動で動かすときは「Run workflow」を押す
2緑のチェックなら成功(1〜4 分で終わる)

届く通知(Slack の例)

Tech RadioAPP09:12
🎙️ Claude Code、OpenAI、Cloudflare が新しい記事出してたよ(3件) ラジオの生成を開始したよ〜A 《AI》 Tech Radio AI 2026-09-27B ・Claude Code 2.1: background agents and the new /review command(Claude Code) ・Introducing GPT-6 Sol(OpenAI・要約のみ)C 《インフラ》 Tech Radio インフラ 2026-09-27 ・Workers AI: new models and lower latency(Cloudflare)
A「生成を開始した」であって「できた」ではない。音声は NotebookLM 側で 10〜20 分かけて作られる。
B番組の見出しがノートブックへのリンク。アプリで探さなくていい。
C「要約のみ」は、記事ページがボット対策で取れず、フィードの要約だけを入れた記事。ラジオもそう断って話す。
NotebookLM のノートブック画面34
3左: その回に入った記事(ソース)
4右の Studio: 音声。▶ で聴く(1 回の実行につき 1 本)
NotebookLM のノートブック一覧5
5「Tech Radio 番組名 日付」のノートブックが 1 日 1 冊ずつ増える(7 日で自動削除。最初は予告の通知だけ)
6 / 10

毎朝の見方

ここからは何もしなくても、予約した時刻に GitHub が動きます。

  • 通知のリンクからノートブックを開き、NotebookLM アプリで聴く。アプリの通知を有効にしておくと、音声の完了が分かる。
  • 新着が無い回は「😪 今回は新着なしだったよ。ラジオはおやすみ〜」が来る。何も来ないのは異常(ステップ 9)。
  • 2 回目の実行では、その回に新しく入った記事だけで別の音声ができる。朝の記事は再放送されない。
  • 見出しに「(音声は未生成)」と付いていたら、記事は入ったが音声を始められなかった。理由は別の通知に出る(多くは生成の上限)。アプリから手動で「音声解説」を作れる。
  • 1 週間ほどで「🧹 [ドライラン] 7日より古いラジオ 2件が削除対象だよ(まだ消してない)」が来る。挙がったのが古いラジオだけなら、config.yaml の cleanup.dry_run を false に。削除対象は「このバッチの命名に完全一致するノートブック」だけで、手で作ったものには触らない。
7 / 10

設定を変える

すべて config.yaml です。変えて push すれば次の実行から反映されます(push しても即実行はされません)。迷ったらビルダーで作り直して丸ごと置き換えるのが確実です。

やりたいことどこを変えるか
フィードを足す・外すfeeds: の項目。ビルダーの共有リンクから作り直すと楽
フィードを別の番組へそのフィードの topic:
番組の形式・長さ・指示文topics: → その番組 → audio:
実行時刻.github/workflows/rss-radio.yml の - cron: 2 行(UTC)。ビルダーの「できあがり」が UTC に変換した 2 行を出す
1 回に処理する記事数settings.limits.per_feed(既定 3)と total(既定 15)。超えた分は次回へ
流量の多いフィードそのフィードに mode: latest(最新 N 件だけ拾い、残りは読んだことにする)
音声の言語settings.language
記事ページがボット対策で取れないサイトそのフィードに source_mode: text

変えたあとは python radio_batch.py --check-config で検査できます。使えるキーは config.schema.json に全部書いてあります。

8 / 10

約 3.5 週ごと: ログインを更新する

手元の Google セッションは生き続けますが、secret に凍結したコピーは約 3.5 週で切れます。コードでは直せません。切れると、原因と手順つきのエラー通知が届きます。

Tech RadioAPP06:52
⚠️ Tech Radio 実行エラー発生 ノートブック「Tech Radio AI 2026-10-21」 の処理中にエラーが発生しました。 エラー内容: NotebookLM command failed. Command: notebooklm list --json Exit code: 2 UNEXPECTED_ERROR: Unexpected error: Authentication expired or invalid. Run 'notebooklm login' to re-authenticate. 認証切れ。CI 専用プロファイルで `notebooklm -p ci login` をやり直し、`gh secret set NOTEBOOKLM_AUTH_JSON < ~/.notebooklm/profiles/ci/storage_state.json` でシークレットを更新すること。環境変数モードは書き戻し先が無く自動更新されないため、放置しても直らない。… 実行ログ: GitHub Actions Run
$ python scripts/setup.py renew
notebooklm-radio 認証の更新

1/4  notebooklm CLI

2/4  Google ログイン(CI 用プロファイル)
  $ notebooklm -p ci login --fresh
  ブラウザが開きます。NotebookLM を使える Google アカウントでログインしてください。
  (ブラウザが開く。ログインし直す)
  $ notebooklm -p ci auth check --test --passive
  ログインできていることを確認しました。

3/4  リポジトリの secret NOTEBOOKLM_AUTH_JSON
  $ gh secret set NOTEBOOKLM_AUTH_JSON -R you/my-radio(/Users/you/.notebooklm/profiles/ci/storage_state.json から)
  NOTEBOOKLM_AUTH_UPDATED=2026-10-21 をリポジトリ変数に記録しました。

4/4  再実行
ワークフローを今すぐ実行しますか?(今日のノートブックを作り、音声の生成を始めます) [Y/n] y
  $ gh workflow run rss-radio.yml -R you/my-radio
  開始しました: https://github.com/you/my-radio/actions/runs/1234567891
終わるまでここで見届けますか?(3〜5 分ほど) [Y/n] y
  $ gh run watch 1234567891 -R you/my-radio --exit-status --compact
  成功しました。結果は Webhook に届きます。音声は NotebookLM の中で 20 分ほどかけて作られます。
  • 2 分ほどで終わります。python scripts/setup.py doctor でログインの古さがいつでも見られ、21 日を超えると先に警告します。
  • 普段 notebooklm を手元で使うときは -p ci を付けないでください。CI 用と混ぜると寿命が 3 日に縮みます。
  • state.json は bot のものです。手で編集もコミットもしないでください。
9 / 10

困ったとき

見えたもの意味やること
何も届かない日が続く通知の仕組みごと止まっているActions タブで最後の実行を見る。NOTIFY_WEBHOOK_URL が入っているか doctor で確認
🚨 テスト/lint が失敗した…テスト・lint・config.yaml の検査で止まった。ラジオは作られないリンク先の実行ログを見る。config.yaml の誤りなら config.yaml NG と原因が出ている
実行エラー + Authentication expired認証切れpython scripts/setup.py renew
(音声は未生成)+ rate_limited音声生成の上限に当たった番組を減らす、2 回目を切る、プランを上げる。記事は入っているので手動生成もできる
⚠️ RSSフィードの取得に問題があるよ ・X: HTTP 403そのフィードが取れない一時的なら放置。続くなら URL を見直す。403 が続くならボット拒否
⚠️ 以下はサイトのボット対策で本文を取り込めなかったから…記事ページがボット対策ページだったそのフィードに source_mode: text
同じ記事が 2 つ入る2 つのフィードが同じ記事を別 URL で配信している(同一 URL なら自動で 1 つにまとまる)片方を外す。ビルダーは選んだ時点で警告する
古い記事ばかり流れる流量が上限を超えていて古い順に消化しているmode: latest、または limits.per_feed を上げる
夕方の回が翌日のノートブックに入ったGitHub の実行が数時間遅れて日付をまたいだcron を早める。:00 と :30 は特に混む
10 / 10

用語

フィード
サイトが配っている「新着一覧」。RSS / Atom が普通の形式で、無いサイトは sitemap.xml で代用する。
config.yaml
設定ファイル。フィード、番組、音声の設定、掃除の設定がすべて入っている。
state.json
「どこまで読んだか」の記録。bot が毎回コミットする。
番組 / トピック / ノートブック
フィードのまとまり。1 日 × 1 番組で NotebookLM に 1 冊でき、1 冊につき実行ごとに 1 本の音声ができる。
音声解説(音声概要)
NotebookLM が生成する二人の対談形式のラジオ。生成には上限がある。
cron
GitHub Actions に「この時刻に実行」と予約する行。UTC で書く。
secret
GitHub Actions だけが読める秘密の値。認証(NOTEBOOKLM_AUTH_JSON)と通知先(NOTIFY_WEBHOOK_URL)の 2 つ。
webhook
Slack や Discord に外から投稿するための URL。
プロファイル(ci / default)
notebooklm CLI のログイン保存先。CI 用と普段用を分ける。
最新だけ / mode: latest
流量の多いフィードで、最新 N 件だけ拾って残りを読んだことにする設定。