EPGStationの状態をDiscordのWebhookでDiscordに送るシェルスクリプトです。
必要なもの
EPGStationが導入済のLinux PC
Discordアカウント
環境
Ubuntu 24.04.2 LTS
EPGStation v2.10.0
Docker 28.4.0
docker-mirakurun-epgstationでepgstationを構築済み
DiscordのWebhookURLを作成
画像の通りに進めていってください。やり方が分かる方は読み飛ばしてください。
サーバーを作成
プログラムを保存
以下のシェルスクリプトをrun.sh
という名前でローカルに保存してください。
必ず「UnixLF」で保存してください。CRLFなどだと正しく動きません。
#!/bin/bash
set -eu
#ここにWebHookURLを貼り付け
DISCORD_WEBHOOK_URL="${DISCORD_WEBHOOK_URL:-https://discord.com/api/webhooks/XXXXXXXXXXXXXXXXX}"
########################################################################
# JSON エスケープ(簡易)
########################################################################
escape_json() {
local s="$1"
s="${s//\\/\\\\}"
s="${s//\"/\\\"}"
s="${s//$'\n'/\\n}"
s="${s//$'\r'/\\r}"
s="${s//$'\t'/\\t}"
printf '%s' "$s"
}
########################################################################
# epoch -> JST 表示
########################################################################
epoch_to_jst() {
local epoch_s="$1"
if [ -z "$epoch_s" ] || [ "$epoch_s" = "0" ]; then
printf '%s' "未設定"
return
fi
local utc
utc=$(date -u -d "@${epoch_s}" '+%Y-%m-%d %H:%M:%S')
date -d "${utc} +9 hours" '+%m/%d(%a) %H:%M'
}
########################################################################
# main
########################################################################
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <reserve|update|delete|prestart|prepfailed|start|end|recfailed|encod_end>" >&2
exit 1
fi
ret="$1"
CHANNELNAME="${CHANNELNAME:-放送局名なし}"
NAME="${NAME:-タイトル未設定}"
DESCRIPTION="${DESCRIPTION:-番組概要が指定されていません。}"
EXTENDED="${EXTENDED:-}"
STARTAT_MS="${STARTAT:-}"
ENDAT_MS="${ENDAT:-}"
DURATION_MS="${DURATION:-}"
ERROR_CNT="${ERROR_CNT:-N/A}"
DROP_CNT="${DROP_CNT:-N/A}"
SCRAMBLING_CNT="${SCRAMBLING_CNT:-N/A}"
start_epg_time=""
end_epg_time=""
if [ -n "$STARTAT_MS" ] && printf '%s' "$STARTAT_MS" | grep -qE '^[0-9]+$'; then
start_epg_time=$(( STARTAT_MS / 1000 ))
fi
if [ -n "$ENDAT_MS" ] && printf '%s' "$ENDAT_MS" | grep -qE '^[0-9]+$'; then
end_epg_time=$(( ENDAT_MS / 1000 ))
fi
startat="$(epoch_to_jst "${start_epg_time:-}")"
endat="$(epoch_to_jst "${end_epg_time:-}")"
if [ -n "$DURATION_MS" ] && printf '%s' "$DURATION_MS" | grep -qE '^[0-9]+$'; then
duration_minutes=$(( DURATION_MS / 60000 ))
else
duration_minutes="未設定"
fi
# ----- ここから printf -v を使わない組み立て -----
case "$ret" in
reserve)
content=$(printf '%s\n%s\n%s\n%s ~ %s %s分\n%s\n%s' \
"✅ 予約追加" "$NAME" "$CHANNELNAME" "$startat" "$endat" "$duration_minutes" "$DESCRIPTION" "$EXTENDED")
;;
delete)
content=$(printf '%s\n%s\n%s' "💨 予約削除" "$NAME" "$CHANNELNAME")
;;
update)
content=$(printf '%s\n%s\n%s\n%s ~ %s %s分' \
"🔁 予約更新" "$NAME" "$CHANNELNAME" "$startat" "$endat" "$duration_minutes")
;;
prestart)
content=$(printf '%s\n%s\n%s' "🔷 録画準備開始" "$NAME" "$CHANNELNAME")
;;
prepfailed)
content=$(printf '%s\n%s\n%s' "💥 録画準備失敗" "$NAME" "$CHANNELNAME")
;;
start)
content=$(printf '%s\n%s\n%s\n%s' "⏺ 録画開始" "$NAME" "$CHANNELNAME" "$startat")
;;
encod_end)
content=$(printf '%s\n%s\n%s' "⏹ エンコード終了" "$NAME" "$CHANNELNAME")
;;
end)
content=$(printf '%s\n%s\n%s\n%s ~ %s %s分\n%s' \
"⏹ 録画終了" "$NAME" "$CHANNELNAME" "$startat" "$endat" "...ラー: ${ERROR_CNT}, ドロップ: ${DROP_CNT}, スクランブル: ${SCRAMBLING_CNT}")
;;
recfailed)
content=$(printf '%s\n%s\n%s' "❌ 録画失敗" "$NAME" "$CHANNELNAME")
;;
*)
echo "未知のコマンド: $ret" >&2
exit 1
;;
esac
# ----- 終わり -----
# Discord の webhook はメッセージ本文を JSON の content に入れます
escaped_text=$(escape_json "$content")
# Discord の制限(1 メッセージあたり約 2000 文字)を考慮して簡単に切り詰める
max_len=1900
if [ "${#escaped_text}" -gt "$max_len" ]; then
# bash の部分文字列で切り詰め
trimmed="${escaped_text:0:1896}..."
else
trimmed="${escaped_text}"
fi
json="{\"content\":\"${trimmed}\"}"
curl -sS -X POST "${DISCORD_WEBHOOK_URL}" \
-H "Content-Type: application/json" \
-d "${json}" || {
echo "Discord webhook post failed" >&2
exit 1
}
exit 0
WebHookURLを設定
先程コピーしたWebHookURLをrun.shに貼り付けます。
DISCORD_WEBHOOK_URL="${DISCORD_WEBHOOK_URL:-https://discord.com/api/webhooks/XXXXXXXXXXXXXXXXX}"
↓
DISCORD_WEBHOOK_URL="${DISCORD_WEBHOOK_URL:-https://discord.com/api/webhooks/12561567152671/bxtyfTDRiftfftfeftfTDTDRYSvpppp}"
#このURLは適当です。正しいURLに置き換えてください。
スクリプトの設置と設定
docker-mirakurun-epgstationで構築している場合はこの先の手順を行っても正しく動作しない場合があります。
docker-mirakurun-epgstationで構築している場合は
https://qiita.com/saturi/items/b32c384600fa2f79b020#docker-mirakurun-epgstationで構築している場合
も参考にしてください。
run.shをEPGStationのルートディレクトリ(%ROOT%)の下のconfigディレクトリに保存
(例: /path/to/epgstation/config/run.sh)
。
必ず「UnixLF」で保存してください。CRLFなどだと正しく動きません。
実行権限を付与
chmod +x /path/to/epgstation/config/run.sh
EPGStationでのConfig設定
EPGStationのconfigファイルに以下を追記します。
reserveNewAddtionCommand: '/bin/sh %ROOT%/config/run.sh reserve'
reserveUpdateCommand: '/bin/sh %ROOT%/config/run.sh update'
reservedeletedCommand: '/bin/sh %ROOT%/config/run.sh delete'
recordingPreStartCommand: '/bin/sh %ROOT%/config/run.sh prestart'
recordingPrepRecFailedCommand: '/bin/sh %ROOT%/config/run.sh prepfailed'
recordingStartCommand: '/bin/sh %ROOT%/config/run.sh start'
recordingFinishCommand: '/bin/sh %ROOT%/config/run.sh end'
recordingFailedCommand: '/bin/sh %ROOT%/config/run.sh recfailed'
encodingFinishCommand: '/bin/sh %ROOT%/config/run.sh encod_end'
設定項目名 | イベント発生タイミング |
---|---|
reserveNewAddtionCommand | 新しい予約が追加されたとき |
reserveUpdateCommand | 既存の予約が更新されたとき |
reservedeletedCommand | 予約が削除されたとき |
recordingPreStartCommand | 録画開始直前(チューナー準備中) |
recordingPrepRecFailedCommand | 録画準備に失敗したとき |
recordingStartCommand | 録画が開始されたとき |
recordingFinishCommand | 録画が完了したとき |
recordingFailedCommand | 録画中に失敗したとき |
encodingFinishCommand | エンコードが完了したとき |
EPGStationを再起動して適用
停止
cd ~/git/docker-mirakurun-epgstation (Pathは自分の環境に合わせて変えてください。)
docker compose down
起動
cd ~/git/docker-mirakurun-epgstation (Pathは自分の環境に合わせて変えてください。)
docker compose up -d
テスト
プログラムが正しく動くかテストします。
以下コマンドを実行し、Discordに正しくメッセージが来るか確認してください。
cd /path/to/epgstation/config (Pathは自分の環境に合わせて変えてください。)
bash run.sh reserve
あとはEPGStationのWebUIから録画予約などをしてみて正しくメッセージが届けば成功です。
docker-mirakurun-epgstationで構築している場合
dockerコンテナ内にEPGStationがある場合、上記の方法ではEPGStation側からrun.shを呼び出せません。
(つまり手動でrun.shを打つと動くのにEPGStationでrun.shを呼び出そうとしてもrun.shが呼び出されないという問題が起こります。)
docker内からrun.shを呼び出す方法
docker psを実行してコンテナ名を確認
docker psを実行してコンテナ名を確認します。
euser@SV-REC01:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
697917e7b531 docker-mirakurun-epgstation-epgstation "npm start" 4 hours ago Up 4 hours 0.0.0.0:8888-8889->8888-8889/tcp, [::]:8888-8889->8888-8889/tcp epgstation-v2
a99c725ceacb mariadb:10.5 "docker-entrypoint.s…" 4 hours ago Up 4 hours 3306/tcp mysql-epgstation-v2
61b0245f5ec9 chinachu/mirakurun "docker-entrypoint.s…" 4 hours ago Up 4 hours 0.0.0.0:9229->9229/tcp, [::]:9229->9229/tcp, 0.0.0.0:40772->40772/tcp, [::]:40772->40772/tcp mirakurun
一番右側のNAMES
の部分にある名前がコンテナ名です。(この場合は[epgstation-v2]です。)
docker cpでrun.shをコピー(お手軽)
この方法は簡単ですが、dockerの再起動 (もしくはPC自体の再起動)でrun.shが消えてしまいます。
永続化したい場合はこの次の方法をおすすめします。
ホストPCからコンテナ内にコピー
docker cp ./run.sh epgstation-v2:/app/config/run.sh
コンテナ内で実行権限を付与
docker exec -it epgstation-v2 chmod +x /app/config/run.sh
これで EPGStation から呼び出せるようになります。
メモ:
/app
は epgstation の %ROOT%
にあたるディレクトリです
docker-compose.yml にマウント設定を入れる(永続化・おすすめ)
この方法であれば再起動しても消えないのでこの方法がおすすめです。
docker-compose.ymlにマウント設定をする
書き方はホストPCのPath:Docker内のPath
です。
epgstation:
container_name: epgstation-v2
build:
context: "./epgstation"
dockerfile: "debian.Dockerfile"
volumes:
#この下の行を追加 (Pathは環境に合わせて変えてください。) (相対パスでも動くはずですが、トラブルを避けるために絶対パスにしています。)
- /home/euser/git/docker-mirakurun-epgstation/epgstation/config/run.sh:/app/config/run.sh # ← ☆追加
- /etc/localtime:/etc/localtime:ro
- ./epgstation/config:/app/config
- ./epgstation/data:/app/data
- ./epgstation/thumbnail:/app/thumbnail
- ./epgstation/logs:/app/logs
- /mnt/data1:/app/recorded
こうすると、ホスト側の ./config フォルダに置いた run.sh が 自動でコンテナの /app/config と同期されます。
→ 以降はホストで run.sh を編集するだけでコンテナ内に反映されます。
実行権限を付与
chmod +x /path/to/epgstation/config/run.sh
ホスト側で実行権限をつけるとDockerにも反映されます。
Docker再起動して適用
停止
cd ~/git/docker-mirakurun-epgstation (Pathは自分の環境に合わせて変えてください。)
docker compose down
起動
cd ~/git/docker-mirakurun-epgstation (Pathは自分の環境に合わせて変えてください。)
docker compose up -d
送信テスト
以下を実行し正しくメッセージが届くか確認してください。
docker exec -it epgstation-v2 /bin/bash /app/config/run.sh reserve
届く場合は成功です。EPGStationのWebUI側から操作して正しく動くか確認してください。
届かない場合はrun.shで使われているcURLがDockerコンテナにインストールされていない可能性があります。以下コマンドでcURLをインストールしてください。
#Dockerコンテナへ入る
docker exec -it epgstation-v2 /bin/bash
#パッケージリストの更新
apt update
#cURLのインストール
apt install curl
再度以下を実行し正しくメッセージが届くか確認してください。
docker exec -it epgstation-v2 /bin/bash /app/config/run.sh reserve
メッセージが届けば成功です。EPGStationのWebUI側から操作して正しく動くか確認してください。
この方法ではDockerコンテナ・PCの再起動でcURLが消えてしまい、run.shを動かすには再度インストールが必要です。永続化したい場合は下記の手順を参考にDockerファイルにapt-get install curlを追加し、ビルドしてください。
DockerコンテナのcURLのインストールと再ビルド
Dockerコンテナ・PCの再起動後もcURLが使えるようにDockerfileを書き換えてからDockerコンテナを再ビルドします。
再ビルドではデータは消えないはずですが、バックアップを取っておくことをおすすめします。
EPGStationを停止
cd ~/git/docker-mirakurun-epgstation (Pathは自分の環境に合わせて変えてください。)
docker compose down
Dockerfileは以下のようになっていると仮定して進めます。この部分は環境によって変えてください。
DockerfileのPath/home/euser/git/docker-mirakurun-epgstation/epgstation/debian.Dockerfile
FROM l3tnun/epgstation:master-debian
ENV DEV="make gcc git g++ automake curl wget autoconf build-essential libass-dev libfreetype6-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texinfo zlib1g-dev"
ENV FFMPEG_VERSION=7.0
RUN apt-get update && \
apt-get -y install $DEV && \
apt-get -y install yasm libx264-dev libmp3lame-dev libopus-dev libvpx-dev && \
apt-get -y install libx265-dev libnuma-dev && \
apt-get -y install libasound2 libass9 libvdpau1 libva-x11-2 libva-drm2 libxcb-shm0 libxcb-xfixes0 libxcb-shape0 libvorbisenc2 libtheora0 libaribb24-dev && \
\
#ffmpeg build
mkdir /tmp/ffmpeg_sources && \
cd /tmp/ffmpeg_sources && \
curl -fsSL http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2 | tar -xj --strip-components=1 && \
./configure \
--prefix=/usr/local \
--disable-shared \
--pkg-config-flags=--static \
--enable-gpl \
--enable-libass \
--enable-libfreetype \
--enable-libmp3lame \
--enable-libopus \
--enable-libtheora \
--enable-libvorbis \
--enable-libvpx \
--enable-libx264 \
--enable-libx265 \
--enable-version3 \
--enable-libaribb24 \
--enable-nonfree \
--disable-debug \
--disable-doc \
&& \
make -j$(nproc) && \
make install && \
\
# 不要なパッケージを削除
apt-get -y remove $DEV && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
rm -rf /tmp/*
これを以下のように変更します。
FROM l3tnun/epgstation:master-debian
ENV DEV="make gcc git g++ automake curl wget autoconf build-essential libass-dev libfreetype6-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texinfo zlib1g-dev"
ENV FFMPEG_VERSION=7.0
RUN apt-get update && \
apt-get -y install $DEV && \
apt-get -y install yasm libx264-dev libmp3lame-dev libopus-dev libvpx-dev && \
apt-get -y install libx265-dev libnuma-dev && \
apt-get -y install libasound2 libass9 libvdpau1 libva-x11-2 libva-drm2 libxcb-shm0 libxcb-xfixes0 libxcb-shape0 libvorbisenc2 libtheora0 libaribb24-dev && \
\
#ffmpeg build
mkdir /tmp/ffmpeg_sources && \
cd /tmp/ffmpeg_sources && \
curl -fsSL http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2 | tar -xj --strip-components=1 && \
./configure \
--prefix=/usr/local \
--disable-shared \
--pkg-config-flags=--static \
--enable-gpl \
--enable-libass \
--enable-libfreetype \
--enable-libmp3lame \
--enable-libopus \
--enable-libtheora \
--enable-libvorbis \
--enable-libvpx \
--enable-libx264 \
--enable-libx265 \
--enable-version3 \
--enable-libaribb24 \
--enable-nonfree \
--disable-debug \
--disable-doc \
&& \
make -j$(nproc) && \
make install && \
\
# 不要なパッケージを削除
apt-get -y remove $DEV && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
rm -rf /tmp/* && \ #☆この行から変更あり
\
# --- 最終イメージに curl と httpsを使うための ca-certificates を残す ---
apt-get update && \
apt-get -y install --no-install-recommends curl ca-certificates && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
プロジェクトルートフォルダに移動し、ビルド実行
cd ~/git/docker-mirakurun-epgstation (Pathは自分の環境に合わせて変えてください。)
docker compose build --no-cache epgstation
コマンドは「epgstation」です。「epgstation-v2」ではありません。
実行できない場合はdocker-compose.ymlにかかれている名前を使用してください。
services:
epgstation: # ←この部分
container_name: epgstation-v2
...
全文
services:
mirakurun:
container_name: mirakurun
build:
context: Mirakurun
dockerfile: docker/Dockerfile
image: chinachu/mirakurun
cap_add:
- SYS_ADMIN
- SYS_NICE
ports:
- "40772:40772"
- "9229:9229"
volumes:
- /etc/localtime:/etc/localtime:ro
- ./Mirakurun/config/:/app-config/
- ./Mirakurun/data/:/app-data/
environment:
TZ: "Asia/Tokyo"
devices:
- /dev/px4video0:/dev/px4video0
- /dev/px4video1:/dev/px4video1
- /dev/px4video2:/dev/px4video2
- /dev/px4video3:/dev/px4video3
- /dev/bus:/dev/bus
restart: always
logging:
driver: json-file
options:
max-file: "1"
max-size: 10m
mysql:
container_name: mysql-epgstation-v2
image: mariadb:10.5
volumes:
- mysql-db:/var/lib/mysql
environment:
MYSQL_USER: epgstation
MYSQL_PASSWORD: epgstation
MYSQL_ROOT_PASSWORD: epgstation
MYSQL_DATABASE: epgstation
TZ: "Asia/Tokyo"
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --performance-schema=false --expire_logs_days=1 # for mariadb
restart: always
logging:
options:
max-size: "10m"
max-file: "3"
epgstation: # ← !!!この部分!!!
container_name: epgstation-v2
build:
context: "./epgstation"
dockerfile: "debian.Dockerfile"
volumes:
- /home/euser/git/docker-mirakurun-epgstation/epgstation/config/run.sh:/app/config/run.sh
- /etc/localtime:/etc/localtime:ro
- ./epgstation/config:/app/config
- ./epgstation/data:/app/data
- ./epgstation/thumbnail:/app/thumbnail
- ./epgstation/logs:/app/logs
- /mnt/data1:/app/recorded
environment:
TZ: "Asia/Tokyo"
depends_on:
- mirakurun
- mysql
ports:
- "8888:8888"
- "8889:8889"
#user: "1000:1000"
restart: always
volumes:
mysql-db:
driver: local
必ず「--no-cache」をつけてください。つけないと古いレイヤーが使われ変更が反映されない場合があります。
ビルドが終わったらEPGStationを立ち上げます。
cd ~/git/docker-mirakurun-epgstation (Pathは自分の環境に合わせて変えry)
docker compose up -d
Dockerコンテナ内でcURLが使えるか確認
docker exec -it epgstation-v2 bash
curl --version
トラブルシューティング
ありがちなトラブルです。
無効なオプションです。と表示される
bash run.sh
: 無効なオプションです set: 使用法: set [-abefhkmnptuvxBCEHPT] [-o option-name] [--] [-] [arg ...] run.sh: 行 5: $'\r': コマンドが見つかりません run.sh: 行 12: $'\r': コマンドが見つかりません run.sh: 行 18: 予期しないトークン $'{\r'' 周辺に構文エラーがあります 'un.sh: 行 18: escape_json() {
このエラーの原因は基本的にCRLFで保存したことによる「改行コードが Windows(CRLF) のまま(\r が残っている)」または「ファイル先頭に UTF-8 BOM が混入している」です。
対処法 → UnixLFで保存し直してください。
EPGStationから呼び出せない。かつEPGStationのSystemログに以下のようなものが残っている。
[2025-10-04T14:12:50.630] [INFO] system - execute cmd: /bin/bash /app/config/run.sh delete
[2025-10-04T14:12:50.664] [ERROR] system - failed: /bin/bash /app/config/run.sh delete. exit: 1
exit: 1
は「EPGStation がスクリプトを呼べているがスクリプトが途中で失敗した」ことを意味します。
このエラーはcURLがインストールされていない環境で起きやすいです。cURLがインストールされているか確認し、されていなければインストールしてください。
インストール方法
#Dockerコンテナへ入る(dockerを使っていない場合はスキップ)
docker exec -it epgstation-v2 /bin/bash
#パッケージリストの更新
apt update
#cURLのインストール
apt install curl