Webラジオ録音・通知を自動化! ラズパイ5とn8nとSynologyチャット Pi5 × n8n × Synology Chat × ffmpegでネットラジオ録音を自動化する 但し、ラジコには手を出すな!!

はじめに

以前にラズパイ3bにvolumioを作成したのですが、あんまり活躍する機会がないので、ラジコを録音するような仕組みにしようとチャレンジしました。

しかし、以前、ラジコを組んだものは、しばらくすると使えなくなりました。

その後、色々なDockerを試してみましたが、全く上手く行きません。

結論として分かったのは、ラジコを録音しようとすると運営側とのイタチごっこなようで。。

果てしない追いかけっことなるようです。

「あぁ、それじゃ、だめだなぁ。」となった訳ですが、

なにか、音楽番組が録音できればいいのだけど?と思って、調べると、

ネットラジオがあるので、それを定期的に録音させてもらおうと思ったわけです。

しかも、ログは明瞭に、スクリプトは保守しやすく、録音ファイルは整理されていてほしい。

そんな思いから始まった、Raspberry Piによるネットワークラジオ録音システムの構築の巻です。

良かったら、読んでみてください。

構成概要

ラズパイ3Bを有効活用したいので、システム(アプリ)だけラズパイ3Bで録音とスケジュールファイルはSynologyのNASで管理します。
(途中からラズパイ5に変更しました。ラズパイ3でvolumioと併用は厳しかったようです。)

https://www.radiojapan.org/ ラジオ日本の画像、色んなジャンルがあるので、凄く助かります。感謝
  • 録音対象:ネットラジオ(例:DanceMachine:https://www.radiojapan.org/ae/dance-machine)
  • 録音方式:ffmpegによるストリーム録音
  • スケジュール管理:NAS上のconfig.json
  • 実行環境:Raspberry Pi 3(IP: 192.168.0.74)
  • 保存先:Synology NAS(/volume1/radiko)をラズパイにマウント(/mnt/music/radiko)

ストリームURLの取得方法
対象サイト(例:https://www.radiojapan.org)でF12(chromeで言う所のデベロッパーツール) → ネットワークタブ → 「radio.aac」などを右クリック → URLをコピー。
例:https://ice1.streeemer.com:8030/radio.aac

ここまでが第一段階ですね。

第二段階は、n8nでスケジュール化、録音、通知となってます。

n8nの作成途中画面

n8nだと、一気に通知までできてしまいますね。

便利だと思います。

今回、通知はSynologyChatにしてますが、どこに変更しても良いかと思います。

あらかじめ免責事項を書いておきますね。

あくまで、環境構築に関しては、自己責任でお願いします。

例を出してはおきますが、AIと会話しながら環境を構築するがおススメです。

私としての責任事項はn8nのワークフローに関してのみとなります。

スケジュールした時間で実行して、指定したWebラジオを録音して、Synologyの共有フォルダに保存する、そして終了通知をSynologyChatへ通知するという仕組みです。

Shellセクション

ここはn8nの前はshellで、動かしていたいう話です。

n8nのところまで、読み飛ばしても構いません。

マウント設定(ラズパイ側)

sudo mkdir -p /mnt/music/radiko
sudo mount -t cifs -o username=user,password=yourpass,vers=3.0,uid=1000,gid=1000 //192.168.0.4/radiko /mnt/music/radiko

自動マウントは /etc/fstab に記述。

録音予約(config.json)

[
  {
    "title": "DanceMachine",
    "url": "https://ice1.streeemer.com:8030/radio.aac",
    "start": "2025-09-13T07:00:00+09:00",
    "duration": 3600
  }
]

録音スクリプト(record_radio.sh)

#!/bin/bash
CONFIG="/mnt/music/radiko/config.json"
SAVE_DIR="/mnt/music/radiko"
NOW_EPOCH=$(date +%s)

jq -c '.[]' "$CONFIG" | while read -r entry; do
  title=$(echo "$entry" | jq -r '.title')
  url=$(echo "$entry" | jq -r '.url')
  start=$(echo "$entry" | jq -r '.start')
  duration=$(echo "$entry" | jq -r '.duration')

  start_epoch=$(date -d "$start" +%s)
  end_epoch=$((start_epoch + duration))

  if [ "$NOW_EPOCH" -ge "$start_epoch" ] && [ "$NOW_EPOCH" -le "$end_epoch" ]; then
    timestamp=$(date -d "$start" +"%Y%m%d_%H%M")
    filename="${SAVE_DIR}/${title}_${timestamp}.m4a"
    ffmpeg -i "$url" -t "$duration" -c copy "$filename"
  fi
done

cron設定(毎分チェック)

crontab -e
* * * * * /home/volumio/record_radio.sh

トラブルシューティング

  1. Permission denied → マウント時にuid/gid指定 or chown
  2. ffmpegエラー → URLが音声ストリームでない可能性。.aac, .mp3, .m3u8 を探す
  3. crontabが使えない → sudo apt install cronsystemctl enable/start cron
  4. 録音されない → start時刻が過去 or 未来すぎる。±60秒の範囲で判定
  5. 再生できない → 拡張子を.m4aにすると互換性向上

改善と運用しやすさの実践

  • ロケールを ja_JP.UTF-8 に設定し、日本語ログの文字化けを解消
  • nano の代わりに micro エディタを導入し、日本語表示を安定化
  • 過去のスクリプトが吐いていた rec.log を整理し、ログを record_log.txt に統一
  • スクリプトに録音成功・失敗・スキップのログ出力を追加し、透明性を確保

■ microエディタの使い方(推奨)

  1. インストール(1行でOK)
    curl https://getmic.ro | bash
  2. micro 実行ファイルがカレントディレクトリに作成される
  3. スクリプトを開く  ./micro record_radio.sh
  4. 基本操作
    • 保存:Ctrl + S
    • 終了:Ctrl + Q
    • 検索:Ctrl + F
    • 行番号表示:Alt + G(ジャンプも可能)
  5. 特長
    • 日本語表示が安定(文字化けしない)
    • カラー表示で見やすい
    • nano と同じ感覚で使えるが、操作性はより快適
    • 設定ファイルでカスタマイズも可能(~/.config/micro)
  6. 補足
    • micro はインストール不要で、実行ファイルだけで動作
    • 必要なら /usr/local/bin に移動して、どこからでも呼び出せるようにできる sudo mv micro /usr/local/bin/

ここまでが第一段階ですね。

一応、2週間ほど実用しましたが、ラズパイ3はvolumioマシーンと併用でしたので、重かったのかなぁ。

SDカードがクラッシュしました。

なので、ラズパイ5は記事にしましたが、SSDだし、スペック段違いなので、ラズパイ5で再構成することにしました。

n8nのワークフローを起動させるまで。

私のn8nのワークフローはこんな感じになりました。

ラズパイ5の環境構築

1.ubuntuサーバー 24.04ver

desktopでも良いです。

ラズパイイメージャーが簡単でおススメです。

環境を構築してください。

2.ラズパイ5とSynology Nasのマウント(ラズパイのn8nで実行したファイルを保存するのはSynologyにするということ)

🧩 Raspberry Pi 5 × Synology NAS マウント手順(Ubuntu Server)

✅ 前提

項目内容
Pi側OSUbuntu Server 24.04 LTS(arm64)
NAS側Synology DSM(SMB共有有効)
共有名radio(Synology側の共有フォルダ)
マウント先/mnt/music/radio(Pi側の保存先)
ユーザーNASの認証ユーザー名

🛠️ ステップ①:必要パッケージのインストール

sudo apt update
sudo apt install cifs-utils -y

🛠️ ステップ②:マウントポイントの作成

sudo mkdir -p /mnt/music/radio

🛠️ ステップ③:マウントテスト(手動)

sudo mount -t cifs //192.168.1.100/radio /mnt/music/radio \
  -o username=YOUR_NAME,password=YOUR_PASSWORD,iocharset=utf8,file_mode=0755,dir_mode=0755

YOUR_NAME,YOUR_PASSWORDはNASのログイン名とパスワード
※ IPはSynologyのローカルアドレス


🛠️ ステップ④:自動マウント設定(/etc/fstab

sudo nano /etc/fstab

追記:

//192.168.1.100/radio /mnt/music/radio cifs username=YOUR_NAME,password=YOUR_PASSWORD,iocharset=utf8,file_mode=0755,dir_mode=0755,nounix,serverino,soft 0 0

🛠️ ステップ⑤:マウント確認

mount | grep /mnt/music
df -h | grep /mnt/music

//192.168.1.100/radiotype cifs で表示されればOK
→ 容量やアクセス権も確認できる


✨ 運用美ポイント

  • 🎯 保存先が明示的に分離 → 録音処理の構成美が保たれる
  • 🧘‍♂️ fstabで自動マウント → 再起動後も安心
  • 📦 file_mode=0755 → ffmpegやn8nからの書き込みも安全

この構成で、録音ファイルが「構成の意図通りにNASへ保存される」ことが保証される。

3.n8nをsystemdで構築

以下はCopilotがまとめた構築手順となります。

分からないときは、以下のテキストを適宜張り付けたり、エラーを貼り付けたりしながら、チャットすれば完成すると思います。

n8nの本番運用では、PostgreSQLを使うのが推奨構成です。

SQLite(デフォルト)でも動くけど、同時実行や信頼性、バックアップ、拡張性を考えるとPostgreSQLが圧倒的に美しい。


✅ なぜPostgreSQLなのか?

比較項目SQLite(デフォルト)PostgreSQL(推奨)
同時実行弱い(ロックされやすい)強い(複数ワークフローOK)
データ整合性単純高い(トランザクション管理)
バックアップファイルコピーpg_dumpなどで柔軟
拡張性限定的高い(外部連携・分析)
運用美テスト向き本番向き・構成美あり

🛠️ Pi5 Ubuntu ServerでPostgreSQL構成のn8nをsystemdで動かす手順

① PostgreSQLのインストール

sudo apt update
sudo apt install postgresql postgresql-contrib -y

② データベースとユーザーの作成

sudo -u postgres psql
CREATE DATABASE n8n;
CREATE USER n8n_user WITH PASSWORD 'your_secure_password';
GRANT ALL PRIVILEGES ON DATABASE n8n TO n8n_user;
\q

③ n8n用の環境変数を設定(.env or systemd)

DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=localhost
DB_POSTGRESDB_PORT=5432
DB_POSTGRESDB_DATABASE=n8n
DB_POSTGRESDB_USER=n8n_user
DB_POSTGRESDB_PASSWORD=your_secure_password

④ systemdサービスファイルに環境変数を追加

Environment=DB_TYPE=postgresdb
Environment=DB_POSTGRESDB_HOST=localhost
Environment=DB_POSTGRESDB_PORT=5432
Environment=DB_POSTGRESDB_DATABASE=n8n
Environment=DB_POSTGRESDB_USER=n8n_user
Environment=DB_POSTGRESDB_PASSWORD=your_secure_password

⑤ 起動&確認

sudo systemctl daemon-reload
sudo systemctl restart n8n
sudo systemctl status n8n

Active: active (running) が出ればOK
http://localhost:5678 でアクセス可能


✨ 運用美ポイント

  • 🎯 PostgreSQLで構成美 → データの信頼性と拡張性が担保される
  • 🧘‍♂️ systemdで常駐 → Pi5再起動後も自律的に起動
  • 📦 .env or systemdで環境変数管理 → 明示的で未来の自分に優しい

4.ffmpegの環境構築


以下は Raspberry Pi(Pi5でもPi4でもOK)で ffmpeg を構築・運用するための手順まとめです。構成美と運用美を意識して、明示的・再現可能・未来の自分に優しい形で整理しました。

🧩 構成概要

要素内容
OSRaspberry Pi OS(Debianベース)
ffmpeg録音・変換用コマンドラインツール
保存先/mnt/music/radio/(NASマウント)
タイムゾーンAsia/Tokyo(JST)
実行方法手動 or n8n経由で自動化

🛠️ ffmpegのインストール手順

① パッケージ更新

sudo apt update && sudo apt upgrade -y

② ffmpegのインストール(公式パッケージ)

sudo apt install ffmpeg -y

③ 動作確認

ffmpeg -version

→ バージョンが表示されればOK(例:ffmpeg version 5.1.2


📁 保存先の構成美(NASマウント)

① NASをマウント(例:Synology)

sudo mkdir -p /mnt/music/radio
sudo mount -t cifs //192.168.1.100/music /mnt/music/radio -o username=youruser,password=yourpass,iocharset=utf8,file_mode=0777,dir_mode=0777

fstab に追記すれば再起動後も自動マウント可能


🕒 タイムゾーンの統一(JST)

sudo timedatectl set-timezone Asia/Tokyo

date コマンドでJSTになっていることを確認


🎙️ 録音コマンドテンプレート

ffmpeg -i "http://stream-url" -t 3600 -c copy "/mnt/music/radio/番組名_$(date +%Y%m%d_%H%M).m4a"
  • -i:録音対象のURL(radikoなど)
  • -t:録音時間(秒)
  • -c copy:再エンコードせずに保存
  • $(date +%Y%m%d_%H%M):JSTタイムスタンプ付きファイル名

✨ 運用美ポイント

  • 🎯 ffmpegは公式パッケージで十分 → ビルド不要
  • 🧘‍♂️ NAS保存先は明示的に分離 → 構成の意図がファイルに反映
  • 📦 JSTタイムスタンプでログ・通知・ファイル名が一貫

5.n8nワークフロー

まず、以下をダウンロードしてください。

Radio_Rec_Sample.jsonをダウンロード

これをn8nにアップロードしますので、解凍しておいてください。

n8nの操作「Create Workflow」を押します。

空っぽのワークフローが開きますが、右の…を押します。

そして、Import from Fileで先ほどダウンロードした「Radio_REC_sample.json」を選択します。

以下のようなワークフローが出たと思います。

ワークフローは左から右に流れますので、左から説明をしていきます。

各アイコンをダブルクリックすると、設定になりますよ。

説明の前に触って見るのが良いかもしれません。

①タイムゾーンの確認

上の順番でタイムゾーンを確認できます。

今回、タイムスケジュールを使うので、重要です。

必ず、住んでいる所のタイムゾーンに合わせてください。

まぁ、Asia/Tokyoだとは思いますが、違っていたら変更してください。

②Schedule Trigger

Trigger Interval:動かす周期ですね、今回は週単位ですので、Weeks

Weeks Between Triggers:毎週としますので、今回は1、隔週は2です。

Trigger on Weekdays:実行する曜日です。任意のものを選択

Trigger at Hour:実行時間です。ここも任意の時間を選択

Trigger at Minute:分単位の設定です。ここも任意ですね。

まぁ、好きなように設定すれば良いと思います。

戻る時は「Back to canvas」(この図で一番上)で前画面に戻ります。

③Edit Fields

以下、そのままですが、説明を下記に書いておきますね。

{
“title”: “80s-90s-super-pop-hits”,
“url”: “https://s4.myradiostream.com/7344/listen.mp3”,
“duration”: 60
}

ここで、録音するためのパラメータを決めてます。

title:ファイル名となります。ファイル名+日付.mp3

url:録音したい音源

duration:録音時間、単位は秒なので、サンプルは1分間

こういう構成です。

Jsonですが、UTF-8を外れるとエラーになるので、注意してください。

編集時は必ずUTF-8保存です。

ここでエラー出てもワークフローでエラーは出ますが、SynologyChatへは反映されないので注意です。

タイトルとURLですが、以下の画面を参考にしてください。

chromeでF12ボタンを押します。

画面のようなものが右側に出ます。

赤枠の順番に押していき、URLをゲットして上記のjsonに貼り付けます。

若干、その目的の音楽ファイルが表示されるまで、遅いときがあります。

そして、拡張子にmp3とあるものは確実に録音できますが、サイトによって、配信方法が違うので、録音できるものとできないものがあります。

④Execute Command

ここで録音を実行してますよ。

ffmpeg -i “{{ $json.url }}” -t {{ $json.duration }} -c copy “/mnt/music/radio/{{ $json.title }}$(date +%Y%m%d%H%M).mp3″

ちなみにmp3で書いてますが、m4aと書けばm4aで録音できますが、ラズパイ5で安定しないので、mp3にしてます。

内容は、$jsonが付いたところが前のノード(前ステップ)からもらった値が入る所ですね。

dateの所はそういう書式で書くと日付が得られるってことです。

まぁ、単純と言えば単純ですが、システマチックに動かすにはn8nは便利では無いかと思います。

⑤if

書いてある通りなんですが、前のノードで実行するとexitCodeってのを返すので、それを判断子にしてます。

{{ $json.exitCode }}
is equal to
0

exitCodeが0だったら正常終了で録音終了。それ以外は異常となり録音失敗ってことになります。

まぁ、振り分けですね。

⑥HTTP Request

ちょっと長いです。

Method:post

URL:https://your.domain.com:5001/webapi/entry.cgi

このURLどこよ?ってなると思いますが、このセクションの次で説明します。

Authentication:none

Send Query Parameters:ON

Specify Query Parameters:Using Fields Below

Query Parametersセクション

 Name:api

 Value:SYNO.Chat.External

 Name:method

 Value:incoming

 Name:version

 Value:2

 Name:token

 Value:xxxx

ここも後ほど書きます。

Send Headers:OFF

Send Body:ON

Body Content Type:Form Urlencoded

Specify Body:Using Fields Below

Body Parametersセクション

 Name:payload

 Value:{“text”:”録音失敗”}

 Value:{“text”:”録音完了\n保存先: /mnt/music/radio”}

このValueが成功と失敗の時のSynologyChatへのメッセージです。

SynologyChatはこんな感じですね。

アイコンはなんかcopilot君に作ってもらいましたよ。

n8nの説明は以上です。

6.SynologyChatの設定

n8nで最後の通知の所(Httpリクエスト)ですが、いくつかどこから出てきたのよ。っていうのがありましたね。

以下がそれですよ。

Synology Chatを開きます。

①右上の自分のアイコンを押します。(丸いやつ)

②インテグレーション

①着信 Webhook

あれば、上記を選択、無ければ作成です。

作成すると、Webhook URLが出来ますよ。

これの内容は以下のような感じになります。

https://your.domain.com:5001/webapi/entry.cgi?api=SYNO.Chat.External&method=incoming&version=2&token=%221abcdefghijklmnopqrstuvwxyz0123456789xxxxxxxxxxx

これを分解するとHttpリクエストになります。

https://your.domain.com:5001/webapi/entry.cgi
api=SYNO.Chat.External
method=incoming
version=2
token=%221abcdefghijklmnopqrstuvwxyz0123456789xxxxxxxxxxx

注意点が2つあります。

一つ目はURLです。

DDNSでの接続をトライする時と、IPアドレスで接続をトライするケースがあります。

例文はPortを指定していますが、指定する場合と、しない場合があります。

いずれも上手く行く方でOKです。

二つ目はHttpsとHttpで若干パラメータを変更する時があります。

Httpsの時で、OptionsのIgnore SSL issues(insecure)をONにするケースがあります。

いずれも上手く行かないケースの時です。

n8nでのデバッグ

簡単な例を、①、②、③と開きますが、ちょっと説明を

①Executions:実行した結果を表示します。

②いくつか実行した結果が左に出ますので、押すとそのときの結果を表示

③赤枠の所がエラーで止まった所です。

左がInputの情報、右がOutputの情報です。

当然ながらOutputがエラーですね。

エラーの「押す」と言うコピーマークを押して、Copilotなどに投げてください。

対応を教えてくれますよ。

その時は、どういう状況なのかの説明を忘れずに。

以上です。

まとめ

第一段階から、第二段階に進化しました。

Schedule Trigger+Edit Fieldsを増やすと、色んな時間で録音できますので、試してみてくださいね。