2026 May 12.
2026 Apr. 02.
2026 Mar. 30.
2025 Nov. 07.
2025 Oct. 10.
2025 Sep. 28.
2025 Aug. 24.
2025 Jul. 21.
2025 May 18.
2025 Feb. 24.
2024 Sep. 15.
2024 May 01.
(手順)
PCにPT2チューナー、B-CAS ICカードリーダ、録画ファイル保存用ストレージを接続する。
この記事では、録画ファイル保存ディレクトリを /var/bigdata/02/video とする。
PT2アンテナ端子配置
S1 BS (PCケース上蓋側)
T1 地上
S2 BS
T2 地上 (マザーボード側)
ロケール、タイムゾーンを設定する
$ sudo apt update
$ sudo apt install language-pack-ja
$ sudo update-locale LANG=ja_JP.UTF-8
$ sudo timedatectl set-timezone Asia/Tokyo
時刻サーバーに同期させる
# /etc/systemd/timesyncd.conf に次の設定を記述する
NTP=ntp.nict.jp
FallbackNTP=ntp1.jst.mfeed.ad.jp ntp2.jst.mfeed.ad.jp ntp3.jst.mfeed.ad.jp
# サービス再起動
$ sudo systemctl restart systemd-timesyncd
# 状態確認
$ systemctl status systemd-timesyncd
ビルドツール、インストールツールをインストール
$ sudo apt install build-essential git unzip dkms pkg-config automake cmake curl libssl-dev libtool libboost-all-dev yasm
(オプション)swapを無効化する
$ sudo swapoff --all
$ sudo reboot
(オプション)/tmpをtmpfsにする
/etc/fstabに次の行を書き込み、システムを再起動する。
tmpfs /tmp tmpfs defaults,noatime 0 0
(オプション)ログをRAMディスクに書き込むようにする
$ echo "deb http://packages.azlux.fr/debian/ buster main" | sudo tee /etc/apt/sources.list.d/azlux.list
$ wget -qO - https://azlux.fr/repo.gpg.key | sudo apt-key add -
$ sudo apt update
$ sudo apt install -y log2ram
/etc/log2ram.confのSIZEとUSE_RSYNCの設定を次のようにする。
SIZE=256MB
USE_RSYNC=true
システムを再起動する。
$ sudo reboot
稼働確認
$ df -h | grep "log2ram"
log2ram 256M 60M 197M 24% /var/log
チューナー PT2がPCに接続されていることを確認
$ lspci
03:00.0 Multimedia controller: Xilinx Corporation Device 222a (rev 01)
PT2デバイスを確認
PT2をPCに装着してLinuxを起動すると自動的に/dev/dvb/以下にデバイスノードが作成される。
$ ls /dev/dvb/
adapter0 adapter1 adapter2 adapter3
/dev/dvb/adapterN が作成されない時は次のリンク記事にしたがって作成する。
Xubuntu 24.04 : TVチューナーカードPT2のデバイスノード/(dev/dvb/adapterN)が自動作成されない時 - rokkonet
次の記事を参考に、B-CASカードリーダをXubuntuにインストールする
ICカードリーダライタSCR3310-NTTComをxubuntuにインストール - rokkonet
pcscdを停止する
Mirakurunでは pcscdが稼働していてはいけない。
$ sudo systemctl stop pcscd.socket
$ sudo systemctl disable pcscd.socket
$ pcsc_scan
次の出力があれば成功
SCardEstablishContext: Service not available.
$ sudo apt install dvb-tools
b25デコードツールはmirakurunに含まれているのでインストール不要
Docker、docker-composeをインストール
docker-composeをインストールすると「distutilsファイルがない」とのエラーになるのでdocker-compose-v2をインストールする。
$ sudo apt update && sudo apt install docker.io docker-compose-v2
Dockerがインストールされたことを確認する。
$ docker version
Dockerの自動起動設定
$ sudo systemctl enable docker.service
$ systemctl status docker.service
dockerが稼働していなければ
$ sudo systemctl start docker.service
Docker版のMirakurun、MySQL、EPGStationを運用する任意の一般ユーザーを決める(ここではtvユーザーとする)
tvユーザーをdockerグループ、sudoグループに所属させ、ログインしなおす
・所属グループ追加コマンド例
$ sudo usermod -aG docker,sudo tv
いったんXubuntuからログアウトし、tvユーザーで再度ログインする
tvユーザーのホームディレクトリ内にdockerディレクトリを作成する
$ su - tv
$ mkdir ~/docker
Docker版mirakurun-epgstationをインストールする
[ GitHub - l3tnun/docker-mirakurun-epgstation: Mirakurun + EPGStation on Docker · GitHub ]のsetup.sh
[docker-mirakurun-epgstation/setup.sh at v2 · l3tnun/docker-mirakurun-epgstation · GitHub]
のとおりだが、次の変更を行ったので、下記の「docker-compose-v2でのDocker版mirakurun-epgstationのインストール」を実行する。
$ cd ~/docker
$ git clone https://github.com/l3tnun/docker-mirakurun-epgstation.git
$ cd ~/docker/docker-mirakurun-epgstation
$ cp docker-compose-sample.yml docker-compose.yml && \
cp epgstation/config/enc.js.template epgstation/config/enc.js && \
cp epgstation/config/config.yml.template epgstation/config/config.yml && \
cp epgstation/config/operatorLogConfig.sample.yml epgstation/config/operatorLogConfig.yml && \
cp epgstation/config/epgUpdaterLogConfig.sample.yml epgstation/config/epgUpdaterLogConfig.yml && \
cp epgstation/config/serviceLogConfig.sample.yml epgstation/config/serviceLogConfig.yml
BS15_2 channelの設定を修正する(dvbv5_channels_isdbs.confを修正する)
Mirakurun/config at master · Chinachu/Mirakurun · GitHub を開く。
"dvbconf-for-isdb"で始まるディレクトリを開く。
"conf"ディレクトリを開く。
dvbv5_channels_isdbs.confファイルの[BS15_2]セクションのSTREAM_IDが18675であれば修正の必要なし。
[BS15_2]
DELIVERY_SYSTEM = ISDBS
FREQUENCY = 1318000
STREAM_ID = 18675
修正作業
Mirakurun/config at master · Chinachu/Mirakurun · GitHub を開く。
"dvbconf-for-isdb @ XXXXXXX"ディレクトリのURLの最後の/(スラッシュ)の後の文字列(dvbconf-for-isdb @ XXXXXXXのXXXXXXXから始まる文字列)をメモする。ここでは"e337342d140f24d8d22e1ab75d72a475192dd6ba"とする。
任意の作業ディレクトリに移る。
$ cd /WORK/DIR/
$ git clone https://github.com/Chinachu/dvbconf-for-isdb.git
$ cd dvbconf-for-isdb
$ git checkout e337342d140f24d8d22e1ab75d72a475192dd6ba
dvbv5_channels_isdbs.confをローカルホストのmirakurunコンテナイメージのソースリポジトリに配置する。
$ cp conf/dvbv5_channels_isdbs.conf ~/docker/docker-mirakurun-epgstation/mirakurun/conf/
~/docker/docker-mirakurun-epgstation/mirakurun/conf/dvbv5_channels_isdbs.confの [BS15_2]のセクションのSTREAM_ID設定を18675にする。
[BS15_2]
DELIVERY_SYSTEM = ISDBS
FREQUENCY = 1318000
STREAM_ID = 18675
mirakurunのDockerfileの作成
Docker版MirakurunのDockerfile - rokkonet にしたがって、"~/docker/docker-mirakurun-epgstation/mirakurun/container-init.sh"と"~/docker/docker-mirakurun-epgstation/mirakurun/my.Dockerfile"を作成する。
MySQLのDockerfileの作成
Dockerfileが読み込むentrypointスクリプト作成
$ mkdir ~/docker/docker-mirakurun-epgstation/mysql
~/docker/docker-mirakurun-epgstation/mysql/entrypoint.sh
#!/bin/bash
# cron をバックグラウンドで起動
# cron
service cron start
# cron のログファイルが存在しない場合は作成
touch /var/log/cron.log
# MySQL をフォアグラウンドで起動
exec docker-entrypoint.sh mysqld
実行属性を付ける。
$ chmod +x ~/docker/docker-mirakurun-epgstation/mysql/entrypoint.sh
~/docker/docker-mirakurun-epgstation/mysql/my.Dockerfile を次の内容で作成
FROM mariadb:10.5
RUN apt-get update && apt-get install -y --no-install-recommends \
vim \
less \
cron \
locales \
tzdata \
procps \
&& echo "ja_JP.UTF-8 UTF-8" > /etc/locale.gen \
&& locale-gen \
&& update-locale LANG=ja_JP.UTF-8 \
&& ln -snf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& echo Asia/Tokyo > /etc/timezone \
&& dpkg-reconfigure -f noninteractive tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& touch /var/log/cron.log
# スクリプトをコンテナにコピー
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# ENTRYPOINT を変更
ENTRYPOINT ["/entrypoint.sh"]
EPGStationのDockerfileの作成
~/docker/docker-mirakurun-epgstation/epgstation/entrypoint.sh を作成する。
entrypoint.sh
#!/usr/bin/env bash
set -euo pipefail
# ----------------------------------------
# entrypoint.sh for Docker版EPGStation
# - cron をデーモンとして起動
# - EPGStation をフォアグラウンドで起動
# ----------------------------------------
# ログファイルがなければ作成
: > /var/log/cron.log
# cron デーモンをバックグラウンドで起動
echo ">>> Starting cron daemon..."
# cron
service cron start
# (オプション)cron のログをコンテナ stdout に流す
# tail -F /var/log/cron.log &
# EPGStation の起動
echo ">>> Launching EPGStation..."
exec npm run start
実行属性を付ける
$ chmod +x ~/docker/docker-mirakurun-epgstation/epgstation/entrypoint.sh
~/docker/docker-mirakurun-epgstation/epgstation/my.Dockerfile を次の内容で作成する。
########################################
# 1. Build Stage: FFmpeg をコンパイル
########################################
FROM debian:bookworm-slim AS builder
ARG DEV="make gcc git g++ automake curl wget autoconf build-essential pkg-config \
texinfo zlib1g-dev"
ARG DEVFFMPEG="yasm libx264-dev libmp3lame-dev libopus-dev libvpx-dev libass-dev \
libfreetype6-dev libsdl1.2-dev libtheora-dev libtool libva-dev \
libvdpau-dev libvorbis-dev libx265-dev libnuma-dev libaribb24-dev"
ARG FFMPEGVERSION=7.0.1
ENV FFMPEGVERSION=${FFMPEGVERSION}
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
$DEV \
$DEVFFMPEG \
ca-certificates; \
mkdir -p /tmp/ffmpeg_sources; \
cd /tmp/ffmpeg_sources; \
curl -fsSL "http://ffmpeg.org/releases/ffmpeg-${FFMPEGVERSION}.tar.bz2" \
| tar -xj --strip-components=1; \
./configure \
--prefix=/usr/local \
--disable-shared \
--pkg-config-flags="--static" \
--enable-gpl --enable-version3 --enable-nonfree \
--enable-libass --enable-libfreetype \
--enable-libmp3lame --enable-libopus --enable-libtheora \
--enable-libvorbis --enable-libvpx \
--enable-libx264 --enable-libx265 --enable-libaribb24 \
--disable-debug --disable-doc; \
make -j"$(nproc)"; \
make install; \
apt-get purge -y --auto-remove $DEV $DEVFFMPEG; \
rm -rf /var/lib/apt/lists/* /tmp/ffmpeg_sources
##################################
# 2. Runtime Stage: 必要最小限の共有ライブラリのみ
##################################
FROM l3tnun/epgstation:master-debian
# ビルド成果物をコピー
COPY --from=builder /usr/local /usr/local
ENV LANG=ja_JP.UTF-8 \
TZ=Asia/Tokyo \
DEBIAN_FRONTEND=noninteractive
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
cron locales tzdata procps vim less \
libasound2 libass9 libvdpau1 \
libva-drm2 libva-x11-2 \
libvorbisenc2 libtheora0 \
libvpx7 libopus0 libmp3lame0 libaribb24-0 \
libx264-164 libx265-199; \
echo "/usr/local/lib" > /etc/ld.so.conf.d/local-ffmpeg.conf; \
ldconfig; \
echo "ja_JP.UTF-8 UTF-8" > /etc/locale.gen; \
locale-gen; \
update-locale LANG=ja_JP.UTF-8; \
ln -snf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime; \
echo "Asia/Tokyo" > /etc/timezone; \
dpkg-reconfigure -f noninteractive tzdata; \
touch /var/log/cron.log; \
chmod 0644 /var/log/cron.log; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
ホストのtvユーザーで、
$ mkdir ~/docker/docker-mirakurun-epgstation/epgstation/crontab
$ chmod 755 ~/docker/docker-mirakurun-epgstation/epgstation/crontab
ホストに共有ディレクトリを作成する。
Mirakurun
$ mkdir ~/docker/docker-mirakurun-epgstation/mirakurun/crontab # コンテナのcron設定を保管する場所
$ chmod 755 ~/docker/docker-mirakurun-epgstation/mirakurun/crontab
$ sudo mkdir /var/bigdata/02/video/mirakurun # EPGStationを使わずMirakurunの機能だけで録画したファイルの保管場所
$ sudo chmod 777 /var/bigdata/02/video/mirakurun
MySQL
$ mkdir -p ~/docker/docker-mirakurun-epgstation/mysql/crontab # コンテナのcron設定を保管する場所
$ chmod 755 ~/docker/docker-mirakurun-epgstation/mysql/crontab
$ mkdir ~/docker/docker-mirakurun-epgstation/mysql/my.cnf # コンテナのMySQL設定を保管する場所
$ sudo chown 999:999 ~/docker/docker-mirakurun-epgstation/mysql/my.cnf # mysqlコンテナ内のmysqlユーザーID999に合わせる
$ sudo chmod 700 ~/docker/docker-mirakurun-epgstation/mysql/my.cnf
$ mkdir ~/mysql-share # mysqlコンテナとのデータ共有場所
$ chmod 777 ~/mysql-share
EPGStation
これは上記までに作成済み -> $ mkdir ~/docker/docker-mirakurun-epgstation/epgstation/crontab # コンテナのcron設定を保管する場所
これは上記までに設定済み -> $ chmod 755 ~/docker/docker-mirakurun-epgstation/epgstation/crontab
$ sudo mkdir -p /var/bigdata/02/video/epgstation250803/video # 録画ファイル保管場所
$ sudo chmod 777 /var/bigdata/02/video/epgstation250803/video
$ sudo mkdir /var/bigdata/02/video/epgstation250803/thumbnail # 録画ファイルサムネイル保管場所
$ sudo chmod 777 /var/bigdata/02/video/epgstation250803/thumbnail
docker-compose.ymlの作成
元ファイルのバックアップ
$ cp ~/docker/docker-mirakurun-epgstation/docker-compose.yml ~/docker/docker-mirakurun-epgstation/docker-compose.yml.original
~/docker/docker-mirakurun-epgstation/docker-compose.yml を以下の記述に沿って 修正する
各コンテナ内のディレクトリをホストと共有できるようにdocker-compose.ymlの各サービスのvolumes:セクションを修正する
(書式)
- ホスト側の(docker-compose.ymlから見た相対)パス:コンテナの絶対パス
mirakurun
mirakurunのvolumes:セクションにMirakurun録画ファイルを保管するディレクトリを設定する。
- /var/bigdata/02/video/mirakurun:/app-recorded
cron設定保管ディレクトリ設定
- ./mirakurun/crontab:/var/spool/cron/crontabs
EPGStation
録画ファイルをコンテナ外で保存するように、epgstationのvolumes:セクションを修正する。
録画サムネイルファイル保存用と録画ファイル保存用のホスト側ディレクトリは以下とした。
* コンテナ内のthumbnailに結びつけるホスト側ディレクトリ:/var/bigdata/02/video/epgstation240501/thumbnail
* コンテナ内のrecordedに結びつけるホスト側ディレクトリ:/var/bigdata/02/video/epgstation240501/video
* コンテナ内のcrontabに結びつけるホスト側ディレクトリ:~/docker/docker-mirakurun-epgstation/epgstation/crontab
volume設定
* 52行目あたりの"- ./epgstation/thumbnail:/app/thumbnail"の:(コロン)の前は録画サムネイルファイル保存ディレクトリのパスにする。
* 54行目あたりの"- ./recorded:/app/recorded"の:(コロン)の前は録画ファイル保存ディレクトリのパスにする。
MySQL
mysql:のvolumes:セクションに次を記述する。
mysql:
volumes:
- mysql-db:/var/lib/mysql
- /home/tv-xu2404/mysql-share:/tmp # ホストとのデータ共有
- ./mysql/crontab:/var/spool/cron/crontabs # ホストとのcron設定の共有
- ./mysql/my.cnf:/etc/mysql/conf.d # ホストとのmysql設定の共有
docker-compose.yml のvolumesへの記述例
[mirakurunのvolumes設定]
volumes:
- ./mirakurun/conf:/app-config
- ./mirakurun/data:/app-data
- /var/bigdata/02/video/mirakurun:/app-recorded
- ./mirakurun/crontab:/var/spool/cron/crontabs
[mysqlのvolumes設定]
volumes:
- mysql-db:/var/lib/mysql
- /home/tv-xubuntu2404/mysql-share:/tmp
- ./mysql/crontab:/var/spool/cron/crontabs
- ./mysql/my.cnf:/etc/mysql/conf.d
[epgstationのvolumes設定]
volumes:
- ./epgstation/config:/app/config
- ./epgstation/data:/app/data
- ./epgstation/logs:/app/logs
- ./epgstation/crontab:/var/spool/cron/crontabs
- /var/bigdata/02/video/epgstation250222/video:/app/recorded
- /var/bigdata/02/video/epgstation250222/thumbnail:/app/thumbnail
MySQLのパスワード等設定
- mysqlのenvironment:セクションにデータベース名・ユーザー名・パスワードを設定する。
- MYSQL_ROOT_PASSWORD変数にMySQLのrootユーザーのパスワードを設定する。(デフォルトではepgstationになっている)
- ユーザー名、データベース名、ユーザーパスワードはepgstationとしておくのが無難。
各コンテナにタイムゾーン・ロケールを設定する
services:
mirakurun:
environment:
TZ: "Asia/Tokyo"
LANG: ja_JP.UTF-8
LC_ALL: ja_JP.UTF-8
mysql:
environment:
TZ: "Asia/Tokyo"
LANG: ja_JP.UTF-8
LC_ALL: ja_JP.UTF-8
epgstation:
environment:
TZ: "Asia/Tokyo"
LANG: ja_JP.UTF-8
LC_ALL: ja_JP.UTF-8
Mirakurun、MYSQL、EPGStationの各コンテナの確実な連携
epgstation:
environment:
TZ: "Asia/Tokyo"
LANG: ja_JP.UTF-8
LC_ALL: ja_JP.UTF-8
HOST: "0.0.0.0"
PORT: "8888"
REMOTE_MIRAKURUN_URI: "http://mirakurun:40772"
DB_HOST: "mysql"
DB_USER: "epgstation"
DB_PASSWORD: "epgstation"
DB_NAME: "epgstation"
その他の各種設定
・docker-compose.ymlファイルの先頭に"version:"行があれば、不要なので削除する。
・各コンテナはDockerfileでビルドするので、各コンテナサービスの build セクションにmy.Dockerfileを指定する。
・各サービスの"image:"行は削除する。
#version: '3.7'
services:
mirakurun:
# image: chinachu/mirakurun
build:
context: "./mirakurun"
dockerfile: "my.Dockerfile"
mysql:
# image: mariadb:10.5
build:
context: "./mysql"
dockerfile: "my.Dockerfile"
epgstation:
build:
context: "./epgstation"
dockerfile: "my.Dockerfile"
作成した docker-compose.yml の全体
~/docker/docker-mirakurun-epgstation/docker-compose.yml
services:
mirakurun:
build:
context: "./mirakurun"
dockerfile: "my.Dockerfile"
cap_add:
- SYS_ADMIN
- SYS_NICE
ports:
- "40772:40772"
- "9229:9229"
volumes:
- ./mirakurun/conf:/app-config
- ./mirakurun/data:/app-data
- ./mirakurun/crontab:/var/spool/cron/crontabs
- /var/usbhdd01/video/mirakurun:/app-recorded
environment:
TZ: "Asia/Tokyo"
LANG: ja_JP.UTF-8
LC_ALL: ja_JP.UTF-8
devices:
- /dev/bus:/dev/bus
- /dev/dvb:/dev/dvb
restart: always
logging:
driver: json-file
options:
max-file: "1"
max-size: 10m
mysql:
build:
context: "./mysql"
dockerfile: "my.Dockerfile"
volumes:
- mysql-db:/var/lib/mysql
- /home/tv-xu2404/mysql-share:/tmp
- ./mysql/crontab:/var/spool/cron/crontabs
- ./mysql/my.cnf:/etc/mysql/conf.d
environment:
MYSQL_USER: epgstation
MYSQL_PASSWORD: epgstation
MYSQL_ROOT_PASSWORD: MYSQLROOTPW # 任意のmysql rootパスワード
MYSQL_DATABASE: epgstation
TZ: "Asia/Tokyo"
LANG: ja_JP.UTF-8
LC_ALL: ja_JP.UTF-8
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --performance-schema=false --expire_logs_days=1
restart: always
logging:
options:
max-size: "10m"
max-file: "3"
epgstation:
build:
context: "./epgstation"
dockerfile: "my.Dockerfile"
volumes:
- ./epgstation/config:/app/config
- ./epgstation/data:/app/data
- ./epgstation/logs:/app/logs
- ./epgstation/crontab:/var/spool/cron/crontabs
- /var/usbhdd01/video/epgstation250928/video:/app/recorded
- /var/usbhdd01/video/epgstation250928/thumbnail:/app/thumbnail
environment:
TZ: "Asia/Tokyo"
LANG: ja_JP.UTF-8
LC_ALL: ja_JP.UTF-8
HOST: "0.0.0.0"
PORT: "8888"
REMOTE_MIRAKURUN_URI: "http://mirakurun:40772"
DB_HOST: "mysql"
DB_USER: "epgstation"
DB_PASSWORD: "epgstation"
DB_NAME: "epgstation"
depends_on:
- mirakurun
- mysql
ports:
- "8888:8888"
- "8889:8889"
restart: always
volumes:
mysql-db:
driver: local
mirakurunをSETUPする。
$ docker compose run --rm -e SETUP=true mirakurun
Mirakurunの tuners.yml は自動作成されるので、作業不要。
Mirakurun用チャンネル情報ファイルを作成する
$ cd ~/docker/docker-mirakurun-epgstation/mirakurun/conf
$ sudo cp channels.yml channels.yml.original
手動でチャンネル設定する場合
参考 mirakurun BSCSチャンネル設定(2025/09/01現在) · GitHub
下記の"神戸チャンネル フォーマット"の内容で ~/docker/docker-mirakurun-epgstation/mirakurun/conf/channels.yml を作成する。
~/docker/docker-mirakurun-epgstation/mirakurun/conf/ 内のファイルのオーナーはrootユーザーになっているので、root権限で編集する。
神戸チャンネル フォーマット 広島チャンネル フォーマット
参照先:Mirakurun : チャンネル設定データ - rokkonet
自動チャンネル設定する場合
地デジ チャンネルスキャン
(mirakurunコンテナが稼働した状態で、Dockerコンテナ内ではなくホスト上で)
$ curl -X PUT "http://localhost:40772/api/config/channels/scan?type=GR&setDisabledOnAdd=false&refresh=true"
BS チャンネルスキャン
(mirakurunコンテナが稼働した状態で、Dockerコンテナ内ではなくホスト上で)
$ curl -X PUT "http://localhost:40772/api/config/channels/scan?type=BS&setDisabledOnAdd=false&refresh=true"
BSを自動チャンネル設定したら1日経過しても番組表が歯抜け状態となったが、mirakurunのGUIのconfigでrestartしたら直った。
EPGStationの設定を行う
最低限の[オリジナルの]config.ymlでTV録画システム起動を確認する
$ cp ~/docker/docker-mirakurun-epgstation/epgstation/config/config.yml ~/docker/docker-mirakurun-epgstation/epgstation/config/config.yml.original
最低限のconfig.yml: ~/docker/docker-mirakurun-epgstation/epgstation/config/config.yml
port: 8888
mirakurunPath: http://mirakurun:40772/
dbtype: mysql
mysql:
host: mysql
port: 3306
user: epgstation
password: epgstation
database: epgstation
epgUpdateIntervalTime: 10
conflictPriority: 1
recPriority: 2
recordedFormat: '%YEAR%年%MONTH%月%DAY%日%HOUR%時%MIN%分%SEC%秒-%TITLE%'
recordedFileExtension: .m2ts
recorded:
- name: recorded
path: '%ROOT%/recorded'
thumbnail: '%ROOT%/thumbnail'
thumbnailSize: 480x270
thumbnailPosition: 5
ffmpeg: /usr/local/bin/ffmpeg
ffprobe: /usr/local/bin/ffprobe
encodeProcessNum: 4
concurrentEncodeNum: 1
encode:
- name: H.264
cmd: '%NODE% %ROOT%/config/enc.js'
suffix: .mp4
rate: 4.0
urlscheme:
m2ts:
ios: vlc-x-callback://x-callback-url/stream?url=PROTOCOL%3A%2F%2FADDRESS
android: intent://ADDRESS#Intent;action=android.intent.action.VIEW;type=video/*;scheme=PROTOCOL;end
video:
ios: infuse://x-callback-url/play?url=PROTOCOL://ADDRESS
android: intent://ADDRESS#Intent;action=android.intent.action.VIEW;type=video/*;scheme=PROTOCOL;end
download:
ios: vlc-x-callback://x-callback-url/download?url=PROTOCOL%3A%2F%2FADDRESS&filename=FILENAME
stream:
live:
ts:
m2ts:
- name: 720p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2
-c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1'
- name: 480p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2
-c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1'
- name: 無変換
m2tsll:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -f mpegts -analyzeduration 500000 -i pipe:0 -map 0 -c:s copy -c:d
copy -ignore_unknown -fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 1
-threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -flags +cgop -vf yadif,scale=-2:720
-b:v 3000k -preset veryfast -y -f mpegts pipe:1'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -f mpegts -analyzeduration 500000 -i pipe:0 -map 0 -c:s copy -c:d
copy -ignore_unknown -fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 1
-threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -flags +cgop -vf yadif,scale=-2:480
-b:v 1500k -preset veryfast -y -f mpegts pipe:1'
webm:
- name: 720p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac
2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f
webm pipe:1'
- name: 480p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac
2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f
webm pipe:1'
mp4:
- name: 720p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2
-c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
- name: 480p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2
-c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
hls:
- name: 720p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast
-flags +loop-global_header %OUTPUT%'
- name: 480p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast
-flags +loop-global_header %OUTPUT%'
recorded:
ts:
webm:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2
-c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f
webm pipe:1'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 128k -ac 2
-c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f
webm pipe:1'
mp4:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v
libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v
libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
hls:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast
-flags +loop-global_header %OUTPUT%'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast
-flags +loop-global_header %OUTPUT%'
encoded:
webm:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 3 -c:a libvorbis -ar 48000 -b:a
192k -ac 2 -c:v libvpx-vp9 -vf scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y
-f webm pipe:1'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 3 -c:a libvorbis -ar 48000 -b:a
128k -ac 2 -c:v libvpx-vp9 -vf scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y
-f webm pipe:1'
mp4:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac
2 -c:v libx264 -vf scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac
2 -c:v libx264 -vf scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
hls:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf scale=-2:720 -b:v 3000k -preset veryfast -flags
+loop-global_header %OUTPUT%'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf scale=-2:480 -b:v 3000k -preset veryfast -flags
+loop-global_header %OUTPUT%'
Dockerコンテナを起動する。
$ cd ~/docker/docker-mirakurun-epgstation
$ docker compose build --no-cache --pull
$ docker compose up
ブラウザで"http://localhost:40772"にアクセスしてMirakurunサーバーへの接続を確認する。
ブラウザで"http://localhost:8888"にアクセスしてEPGStationサーバーへの接続を確認する。
コマンドラインの出力を確認する。
ffmpegの稼働を確認する。
"docker compose up"コマンドを入力したコマンドライン端末はそのままにして、別のシェルコマンドライン端末を起動する。
次のコマンドを実行する。
$ cd ~/docker/docker-mirakurun-epgstation
$ docker exec -it $(docker ps | grep docker-mirakurun-epgstation-epgstation | grep -o '^[^ ]*') bash # epgstationコンテナ内に入る
# which ffmpeg # ffmpegコマンドの有無とコマンドパスを確認する
# ffmpeg -version # ffmpegコマンドを実行できることを確認する
# exit # epgstationコンテナから出る
$ exit # シェルコマンドライン端末を終了する
MirakurunでNHK BS101チャンネルを視聴する。
VLCメディアプレーヤーで再生するなら、「ネットワークストリームを開く」メニューに次のURLを指定する。
http://MIRAKURUN-SERVER:40772/api/channels/BS/BS15_0/services/101/stream
ブラウザでEPGStationサーバーに接続し、放映中画面でライブ視聴ができることを確認する。
"docker compose up"コマンドを実行中のコマンドライン端末でキーボードから"Ctrl-c"を入力し、dockerコンテナを終了する。
dockerコンテナをデーモン起動する。
$ cd ~/docker/docker-mirakurun-epgstation
$ docker compose up -d
EPGStationで録画する。
番組表が取得されるまでしばらく待機する。
EPGStationで"TS"形式の録画と"H.264"形式の録画を予約し、録画結果を確認する。
config.ymlをカスタマイズする
~/docker/docker-mirakurun-epgstation/epgstation/config/config.yml に下記の修正(mysqlの文字コード指定、録画ファイル名フォーマット)を行う。
$ diff -u config.yml.original config.yml
--- config.yml.original 2024-05-03 11:40:10.068198955 +0900
+++ config.yml 2024-05-03 11:52:43.442341934 +0900
@@ -14,13 +14,14 @@
user: epgstation
password: epgstation
database: epgstation
+ charset: utf8mb4
epgUpdateIntervalTime: 10
conflictPriority: 1
recPriority: 2
-recordedFormat: '%YEAR%年%MONTH%月%DAY%日%HOUR%時%MIN%分%SEC%秒-%TITLE%'
+recordedFormat: '%SHORTYEAR%%MONTH%%DAY%%HOUR%%MIN%%TYPE%%CH%-%SID%-%CHNAME%-%TITLE%'
recordedFileExtension: .m2ts
recorded:
- name: recorded
H.264エンコード設定増設
次の3モードを追加する。
- 音声欠落を防ぐため、冒頭4秒間をカットして H.264にエンコードする設定
- NHK BSドキュメンタリー H.264エンコード設定
- NHK19時ニュース H.264エンコード設定
次の参照先にしたがって、設定する。
参照先 EPGStation : エンコードモード追加 - rokkonet
作成したconfig.yml
port: 8888
mirakurunPath: http://mirakurun:40772/
# dbtype: sqlite
# sqlite:
# extensions:
# - '/hoge/regexp.dylib'
# regexp: true
dbtype: mysql
mysql:
host: mysql
port: 3306
user: epgstation
password: epgstation
database: epgstation
charset: utf8mb4
epgUpdateIntervalTime: 10
conflictPriority: 1
recPriority: 2
#recordedFormat: '%YEAR%年%MONTH%月%DAY%日%HOUR%時%MIN%分%SEC%秒-%TITLE%'
recordedFormat: '%SHORTYEAR%%MONTH%%DAY%%HOUR%%MIN%%TYPE%%CH%-%SID%-%CHNAME%-%TITLE%'
recordedFileExtension: .m2ts
recorded:
- name: recorded
path: '%ROOT%/recorded'
thumbnail: '%ROOT%/thumbnail'
thumbnailSize: 480x270
thumbnailPosition: 5
ffmpeg: /usr/local/bin/ffmpeg
ffprobe: /usr/local/bin/ffprobe
encodeProcessNum: 4
concurrentEncodeNum: 1
encode:
- name: H.264-cut4secs
cmd: '%NODE% %ROOT%/config/enc-cut4secs.js'
suffix: .mp4
rate: 4.0
- name: H.264-nhk_bs_docu-cut4secs
cmd: '%NODE% %ROOT%/config/enc-bs_docu-cut4secs.js'
suffix: .mp4
rate: 4.0
- name: H.264-nhk_news-cut4secs
cmd: '%NODE% %ROOT%/config/enc-nhk_news-cut4secs.js'
suffix: .mp4
rate: 4.0
- name: H.264
cmd: '%NODE% %ROOT%/config/enc.js'
suffix: .mp4
rate: 4.0
urlscheme:
m2ts:
ios: vlc-x-callback://x-callback-url/stream?url=PROTOCOL%3A%2F%2FADDRESS
android: intent://ADDRESS#Intent;action=android.intent.action.VIEW;type=video/*;scheme=PROTOCOL;end
video:
ios: infuse://x-callback-url/play?url=PROTOCOL://ADDRESS
android: intent://ADDRESS#Intent;action=android.intent.action.VIEW;type=video/*;scheme=PROTOCOL;end
download:
ios: vlc-x-callback://x-callback-url/download?url=PROTOCOL%3A%2F%2FADDRESS&filename=FILENAME
stream:
live:
ts:
m2ts:
- name: 720p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2
-c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1'
- name: 480p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2
-c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1'
- name: 無変換
m2tsll:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -f mpegts -analyzeduration 500000 -i pipe:0 -map 0 -c:s copy -c:d
copy -ignore_unknown -fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 1
-threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -flags +cgop -vf yadif,scale=-2:720
-b:v 3000k -preset veryfast -y -f mpegts pipe:1'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -f mpegts -analyzeduration 500000 -i pipe:0 -map 0 -c:s copy -c:d
copy -ignore_unknown -fflags nobuffer -flags low_delay -max_delay 250000 -max_interleave_delta 1
-threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -flags +cgop -vf yadif,scale=-2:480
-b:v 1500k -preset veryfast -y -f mpegts pipe:1'
webm:
- name: 720p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac
2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f
webm pipe:1'
- name: 480p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac
2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f
webm pipe:1'
mp4:
- name: 720p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2
-c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
- name: 480p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2
-c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
hls:
- name: 720p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast
-flags +loop-global_header %OUTPUT%'
- name: 480p
cmd:
'%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast
-flags +loop-global_header %OUTPUT%'
recorded:
ts:
webm:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2
-c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f
webm pipe:1'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 128k -ac 2
-c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f
webm pipe:1'
mp4:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v
libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v
libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
hls:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast
-flags +loop-global_header %OUTPUT%'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -i pipe:0 -sn -map 0 -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast
-flags +loop-global_header %OUTPUT%'
encoded:
webm:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 3 -c:a libvorbis -ar 48000 -b:a
192k -ac 2 -c:v libvpx-vp9 -vf scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y
-f webm pipe:1'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 3 -c:a libvorbis -ar 48000 -b:a
128k -ac 2 -c:v libvpx-vp9 -vf scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y
-f webm pipe:1'
mp4:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac
2 -c:v libx264 -vf scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac
2 -c:v libx264 -vf scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune
fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4
pipe:1'
hls:
- name: 720p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf scale=-2:720 -b:v 3000k -preset veryfast -flags
+loop-global_header %OUTPUT%'
- name: 480p
cmd:
'%FFMPEG% -dual_mono_mode main -ss %SS% -i %INPUT% -sn -threads 0 -ignore_unknown
-max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1
-hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -hls_flags delete_segments -c:a
aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf scale=-2:480 -b:v 3000k -preset veryfast -flags
+loop-global_header %OUTPUT%'
TV録画システム起動
稼働中の TV録画システムを終了する。
$ cd ~/docker/docker-mirakurun-epgstation
$ docker compose down
TV録画システムを再ビルドする
$ docker compose build --no-cache
ホスト共有ディレクトリ以外のコンテナ内のデータは、失われる。
TV録画システムを起動する。
・ブラウザの設定でキャッシュを削除する。
・TV録画システムを起動する。
$ docker compose up -d
・TVシステム起動後、ブラウザでMirakurun・EPGStationのページを表示し、"Ctrl + Shift + R"でハードリロードする。
(設定を変更した時は、ブラウザのキャッシュを削除し、ブラウザのページを"Ctrl + Shift + R"でハードリロードする)
Mirakurun、EPGStation各コンテナ内ディレクトリとホストのディレクトリの共用設定反映を確認する。
Mirakurunコンテナ内のcron自動起動設定
次のページにしたがって、cron自動起動を設定する。
Docker版mirakurun:vim・ less・cron・ps組み込み、locale・タイムゾーン設定とcronの自動起動設定 - rokkonet
mirakutunコンテナ内で"crontab -e"を実行し、コマンド記述部の上部に次の変数設定を記述する。
PATH=/app-data/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # 適当に検索パスを増やす
LANG=ja_JP.UTF-8
LC_ALL=ja_JP.UTF-8
cronで適当なコマンドを実行してcronの稼働、時間設定(JSTかUTCか)を確認する。
例)下記cron設定で、cronの稼働、時間設定、共有ディレクトリの確認ができる。
39 21 * * * /usr/bin/touch /app-recorded/"$(date)"
MySQL設定ファイル作成
MySQL接続のパスワードを不要にする。
次の内容の"~/docker/docker-mirakurun-epgstation/mysql/my.cnf/50-client.cnf"ファイルを作成する。
(ファイル名は、拡張子が.cnfであれば何でもよい)
[client]
user=epgstation
password=epgstation
host=localhost
ファイル属性を設定する
$ sudo chown 999:999 ~/docker/docker-mirakurun-epgstation/mysql/my.cnf/50-client.cnf # mysqlコンテナ内のmysqlユーザーID999に合わせる
$ sudo chmod 600 ~/docker/docker-mirakurun-epgstation/mysql/my.cnf/50-client.cnf
MySQLコンテナのcronのロケール設定
MySQLコンテナ内で"crontab -e"を実行し、コマンド記述部の上部に次の変数設定を記述する。
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # 適当に検索パスを増やす
LANG=ja_JP.UTF-8
LC_ALL=ja_JP.UTF-8
EPGStationの録画データのテキストファイル保存
MySQLコンテナ内のcron用のシェルスクリプトを作成する
ホストにて次のコマンドでMySQLコンテナに入る。
$ docker exec -it $(docker ps | grep 'mysql' | awk '{print $1}') bash
/usr/local/bin/saveEpgstationDataAsText.sh を次の内容で作成する。
スクリプト中のSHAREはホストと共有のディレクトリとする。この記事では"/tmp"ディレクトリ。
スクリプト中のUSERNAMEとDATABASENAMEは、この記事ではepgstation。
参考: EPGStationの録画データをテキストファイルに保存する - rokkonet
#!/usr/bin/env sh
# save epgstation-recorded-data in mysql to text-file.
if [ -f SHARE/epgstation-recorded-information.txt ]; then
mv SHARE/epgstation-recorded-information.txt SHARE/epgstation-recorded-information-prev.txt
fi
mysql -u USERNAME DATABASENAME -B -e "SELECT video_file.id, video_file.parentDirectoryName, video_file.filePath, video_file.type, video_file.name, video_file.size, video_file.recordedId, recorded.startAt, recorded.endAt, recorded.name, recorded.description, recorded.extended FROM video_file LEFT OUTER JOIN recorded ON video_file.recordedId = recorded.id;" > SHARE/epgstation-recorded-information.txt
exit 0
ファイルに実行属性を与える。
# chmod 744 /usr/local/bin/saveEpgstationDataAsText.sh
cron設定する
ホストにて次のコマンドでMySQLコンテナに入る。
$ docker exec -it $(docker ps | grep 'mysql' | awk '{print $1}') bash
"crontab -e"コマンドで次の設定を記述する。
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=ja_JP.UTF-8
LC_ALL=ja_JP.UTF-8
# m h dom mon dow command
1 3 * * * /usr/local/bin/saveEpgstationDataAsText.sh
トラブル等でのログの確認
$ su - tv
$ docker logs docker-mirakurun-epgstation-epgstation-1 # docker-mirakurun、、、の途中でTabキーを押せば補完される
$ docker compose logs -f mirakurun
$ docker compose logs -f epgstation
$ docker compose logs -f mysql
稼働しているTV録画システムの終了と再起動
録画ファイル・サムネイルファイル・mysql内の情報(予約情報・録画情報等)は削除されない。
$ cd ~/docker/docker-mirakurun-epgstation
## 稼働状況確認
$ docker ps
## コンテナ内データが削除されない終了
$ docker compose down
## コンテナ内データが削除される終了
## mysql内の情報(予約情報・録画情報等)等、コンテナ内のデータは削除される
## 録画ファイル・サムネイルファイルはホストとの共有ディレクトリに保存していない限り削除される
$ docker compose down -v
## 既存コンテナの起動
$ docker compose up -d
Docker内ソフトの設定を変更した時は、ブラウザのキャッシュを削除し、ブラウザのページを"Ctrl + Shift + R"でハードリロードする。
## キャッシュを利用せずにホスト内の既存コンテナイメージからビルド
$ docker compose build --no-cache
## キャッシュを効かせてホスト内の既存コンテナイメージからビルド
$ docker compose build
## コンテナをビルドして起動
$ docker compose up --build -d
上記コマンド実行後、ブラウザのキャッシュを削除し、ブラウザのページを"Ctrl + Shift + R"でハードリロードする。
## コンテナイメージをダウンロードしキャッシュを使わずビルド
$ docker compose build --no-cache --pull
## コンテナイメージをダウンロードしキャッシュを効かせてビルド
$ docker compose build --pull
"docker compose down"コマンドについて
docker compose down
Composeファイルで定義されたサービスを停止し、関連するコンテナを削除するが、ボリューム(データ)は削除されない。
つまり、ボリュームデータは残る。
docker compose down -v
Composeファイルで定義されたサービスを停止し、関連するコンテナを削除するだけでなく、ボリューム(データ)も削除する。
つまり、ボリュームデータも一緒に削除される。
ボリュームデータを保持して再利用したい場合は、"docker compose down"コマンドを使用し、ボリュームデータも削除したい場合は、"docker compose down -v"コマンドを使用する。
ホストとの共有ディレクトリ内のデータは削除されない。
設定変更手順
Dockerコンテナ内のソフトの設定変更の反映
(1)Dockerコンテナを停止する
$ docker compose down
(2)Dockerコンテナを起動する
$ docker compose up -d
(3)ブラウザのキャッシュを削除する
(4)操作するブラウザのページを"Ctrl + Shift + R"でハードリロードする
その他
参考ページ Docker Composeにおける各種ファイルの変更時の反映 #docker-compose - Qiita
docker-compose.ymlを修正する場合
要注意
mysql内の情報(予約情報・録画情報等)等、コンテナ内のデータは削除される。
録画ファイル・サムネイルファイルはホスト共有ディレクトリに保存していない限り削除される。
手順
"--pull"オプションを使用すると、Composeがビルドプロセスの一部としてイメージをプルするように指示する。つまり、ローカルにそのイメージが存在しない場合でも、常に最新のイメージを取得してビルドする。これにより、常に最新の状態でアプリケーションをビルドおよび実行できる。
EPGStationコンテナの停止
$ cd ~/docker/docker-mirakurun-epgstation
$ docker compose kill epgstation
$ docker compose rm -f epgstation
"docker compose kill"コマンドは、Composeで定義されたサービスのコンテナを強制的に停止するが、ボリュームデータを削除しない。このコマンドは単にコンテナを停止するだけであり、ボリュームデータには影響を与えない。
"docker compose rm -f"コマンドは、Composeファイルで定義されたサービスのコンテナを強制的に削除する。このコマンドを実行すると、実行中のコンテナを強制的に停止し、その後削除する。ボリュームデータは削除されない。つまり、関連するコンテナが削除されるが、ボリュームデータは残る。
epgstation以外でのmysqlの利用
tvユーザでmysqlコンテナに入ってmysqlを利用する。
(tvユーザでログインする)
$ su - tv
(mysqlコンテナIDを確認する)
$ docker ps
(mysqlコンテナに入る)
$ docker exec -it MYSQLCONTAINERID /bin/bash
(mysqlクライアントを起動する)
# mysql -u USER -p DATABASE
コンテナ外とのデータ共有
docker-compose.ymlに"- /home/tv-USER/mysql-share:/tmp"を記述したので、コンテナ内の"/tmp"ディレクトリがホストの"/home/tv-USER/mysql-share"と共有される。
mirakurunのログ取得(コンテナのログ収録)
$ docker logs MIRAKURUN-CONTAINER-ID
TV番組録画、ストリーミング再生
https://rasumus.hatenablog.com/entry/2025/01/11/234619