はじめに
以前にラズパイ3bにvolumioを作成したのですが、あんまり活躍する機会がないので、ラジコを録音するような仕組みにしようとチャレンジしました。
しかし、以前、ラジコを組んだものは、しばらくすると使えなくなりました。
その後、色々なDockerを試してみましたが、全く上手く行きません。
結論として分かったのは、ラジコを録音しようとすると運営側とのイタチごっこなようで。。
果てしない追いかけっことなるようです。
「あぁ、それじゃ、だめだなぁ。」となった訳ですが、
なにか、音楽番組が録音できればいいのだけど?と思って、調べると、
ネットラジオがあるので、それを定期的に録音させてもらおうと思ったわけです。
しかも、ログは明瞭に、スクリプトは保守しやすく、録音ファイルは整理されていてほしい。
そんな思いから始まった、Raspberry Piによるネットワークラジオ録音システムの構築の巻です。
良かったら、読んでみてください。
構成概要
ラズパイ3Bを有効活用したいので、システム(アプリ)だけラズパイ3Bで録音とスケジュールファイルはSynologyのNASで管理します。
(途中からラズパイ5に変更しました。ラズパイ3でvolumioと併用は厳しかったようです。)
- 録音対象:ネットラジオ(例: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だと、一気に通知までできてしまいますね。
便利だと思います。
今回、通知は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
トラブルシューティング
- Permission denied → マウント時にuid/gid指定 or chown
- ffmpegエラー → URLが音声ストリームでない可能性。
.aac,.mp3,.m3u8を探す - crontabが使えない →
sudo apt install cron→systemctl enable/start cron - 録音されない →
start時刻が過去 or 未来すぎる。±60秒の範囲で判定 - 再生できない → 拡張子を
.m4aにすると互換性向上
改善と運用しやすさの実践
- ロケールを
ja_JP.UTF-8に設定し、日本語ログの文字化けを解消 nanoの代わりにmicroエディタを導入し、日本語表示を安定化- 過去のスクリプトが吐いていた
rec.logを整理し、ログをrecord_log.txtに統一 - スクリプトに録音成功・失敗・スキップのログ出力を追加し、透明性を確保
■ microエディタの使い方(推奨)
- インストール(1行でOK)
curl https://getmic.ro | bash - →
micro実行ファイルがカレントディレクトリに作成される - スクリプトを開く
./micro record_radio.sh - 基本操作
- 保存:
Ctrl + S - 終了:
Ctrl + Q - 検索:
Ctrl + F - 行番号表示:
Alt + G(ジャンプも可能)
- 保存:
- 特長
- 日本語表示が安定(文字化けしない)
- カラー表示で見やすい
nanoと同じ感覚で使えるが、操作性はより快適- 設定ファイルでカスタマイズも可能(~/.config/micro)
- 補足
microはインストール不要で、実行ファイルだけで動作- 必要なら
/usr/local/binに移動して、どこからでも呼び出せるようにできるsudo mv micro /usr/local/bin/
ここまでが第一段階ですね。
一応、2週間ほど実用しましたが、ラズパイ3はvolumioマシーンと併用でしたので、重かったのかなぁ。
SDカードがクラッシュしました。
なので、ラズパイ5は記事にしましたが、SSDだし、スペック段違いなので、ラズパイ5で再構成することにしました。
n8nのワークフローを起動させるまで。
ラズパイ5の環境構築
1.ubuntuサーバー 24.04ver
desktopでも良いです。
ラズパイイメージャーが簡単でおススメです。
環境を構築してください。
2.ラズパイ5とSynology Nasのマウント(ラズパイのn8nで実行したファイルを保存するのはSynologyにするということ)
🧩 Raspberry Pi 5 × Synology NAS マウント手順(Ubuntu Server)
✅ 前提
| 項目 | 内容 |
|---|---|
| Pi側OS | Ubuntu 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/radio が type 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再起動後も自律的に起動
- 📦
.envor systemdで環境変数管理 → 明示的で未来の自分に優しい
4.ffmpegの環境構築
以下は Raspberry Pi(Pi5でもPi4でもOK)で ffmpeg を構築・運用するための手順まとめです。構成美と運用美を意識して、明示的・再現可能・未来の自分に優しい形で整理しました。
🧩 構成概要
| 要素 | 内容 |
|---|---|
| OS | Raspberry 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ワークフロー
まず、以下をダウンロードしてください。
これを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を増やすと、色んな時間で録音できますので、試してみてくださいね。





























