2024 Feb. 25.
2024 Jan. 06.
2023 Dec. 31.
非Docker版MySQLとすることで、MySQLを一般ユーザーが利用しやすいメリットあり。
ロケール、タイムゾーンを設定する
$ 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="行と"FallbackNTP="行を設定する。
(例)
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
(オプション)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=256M
USE_RSYNC=true
システムを再起動する。
$ sudo reboot
稼働確認
$ df -h | grep "log2ram" log2ram 256M 63M 194M 25% /var/log
次の状況となったら、/etc/log2ram.conf のSIZE値を大きくする。
$ journalctl -xeu log2ram.service log2ram.service: Failed with result 'exit-code'. ERROR: RAM disk for "/var/hdd.log/" too small. Can't sync.
PLEXチューナードライバをインストールする
次のサイトにしたがってインストールする。
PLEX PX-W3U4 TVチューナー ドライバをxubuntu 22.04にインストール - rokkonet
B-CASカードリーダーをインストールする
次のサイトにしたがってインストールする。
ICカードリーダライタSCR3310-NTTComをxubuntuにインストール - rokkonet
Docker (version 18.06.0 and higher), docker-compose (version 1.22.0 and higher)をインストールする
次のサイトにしたがってインストールする。
Docker、docker-composeをubuntuにインストール - rokkonet
Docker版のMirakurun、MySQLを運用する任意の一般ユーザーを決める(ここではtvユーザーとする)
tvユーザーをdockerグループ、sudoグループ、videoグループに所属させ、ログインしなおす
・所属グループ追加
$ sudo usermod -aG docker,sudo,video tv
・いったんログアウトし、tvユーザーで再度ログインする
dockerディレクトリを作成する
$ su - tv $ mkdir ~/docker
Docker版Mirakurunをインストールする
Mirakurunと共有するホスト側ディレクトリを作成する
$ sudo mkdir /opt/mirakurun $ cd /opt/mirakurun $ sudo mkdir run opt config data $ sudo chmod 755 /opt/mirakurun /opt/mirakurun/*
Docker版Mirakurunをダウンロードする
PLEXチューナー・recpt1コマンドを利用できるgithub.com/Chinachu/Mirakurunを利用する。
参考
【家】録画鯖のリプレース(その他 その他)by @由貴 - みんカラ
PLEX PX-Q3PE4 で docker-mirakurun-epgstation を使いたい #Docker - Qiita
【完全解説】LinuxとPX-W3U4でEPGStation v2を構築する方法(PX-Q3U4/W3PE4/Q3PE4) | ページ 4 | 小茂根の暮らし
https://github.com/Chinachu/Mirakurun にアクセスし、Codeタブ画面でブランチ・ドロップダウンをクリックしTagsタブをクリックし、最新バージョンもしくは最新rc版を確認する。現時点では 3.9.0-rc.4 もしくは 3.8.0。
git clone コマンドの"-b"オプションに最新タグを指定する。
$ su - tv $ cd ~/docker $ git clone https://github.com/Chinachu/Mirakurun -b 3.9.0-rc.4
MirakurunのDockerfileを作成する
参考
【家】録画鯖のリプレース(その他 その他)by @由貴 - みんカラ
PLEX PX-Q3PE4 で docker-mirakurun-epgstation を使いたい #Docker - Qiita
【完全解説】LinuxとPX-W3U4でEPGStation v2を構築する方法(PX-Q3U4/W3PE4/Q3PE4) | ページ 4 | 小茂根の暮らし
$ su - tv $ mv ~/docker/Mirakurun/docker/Dockerfile ~/docker/Mirakurun/docker/Dockerfile.original
~/docker/Mirakurun/docker/Dockerfile ファイルを次の内容にする。
(参考)マルチステートビルドDockerfile
Dockerのマルチステージビルドでimageを軽量化する
下記のDockerfileは recpt1とarib25をインストールするようになっている。
~/docker/Mirakurun/docker/Dockerfile
ARG ARCH= FROM ${ARCH}node:18.15.0-buster AS build WORKDIR /app ENV DOCKER=YES NODE_ENV=production ADD . . RUN apt-get update && \ apt-get upgrade -y && \ apt-get install -y --no-install-recommends build-essential && \ npm install --production=false && \ npm run build && \ npm install -g --unsafe-perm --production FROM ${ARCH}node:18.15.0-buster-slim WORKDIR /app ENV DEV="build-essential libtool autoconf git automake" RUN apt-get update && \ apt-get upgrade -y && \ apt-get install -y --no-install-recommends \ ca-certificates \ make \ gcc \ g++ \ pkg-config \ pcscd \ libpcsclite-dev \ libccid \ pcsc-tools \ $DEV && \ \ # arib25 \ apt install -y --no-install-recommends \ autoconf \ build-essential \ cmake \ curl \ git \ libssl-dev \ libtool \ libboost-all-dev \ pkg-config \ yasm && \ git clone https://github.com/stz2012/libarib25.git && \ cd libarib25 && \ cmake . && \ make && \ make install && \ ldconfig && \ \ # recpt1 \ git clone https://github.com/stz2012/recpt1 /tmp/recpt1 && \ cd /tmp/recpt1/recpt1 && \ ./autogen.sh && \ ./configure --enable-b25 && \ make && \ make install && \ rm -rf /tmp/recpt1 && \ \ apt-get -y remove $DEV && \ apt-get autoremove -y && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* COPY --from=build /usr/local/lib/node_modules/mirakurun /app CMD ["./docker/container-init.sh"] EXPOSE 40772 9229
docker-compose.ymlを作成する
参考
【家】録画鯖のリプレース(その他 その他)by @由貴 - みんカラ
PLEX PX-Q3PE4 で docker-mirakurun-epgstation を使いたい #Docker - Qiita
$ su - tv $ cd ~/docker/Mirakurun/docker $ mv docker-compose.yml docker-compose.yml.original
次の内容で ~/docker/Mirakurun/docker/docker-compose.yml を作成する。
imageには、先に"git clone https://github.com/Chinachu/Mirakurun -b 3.9.0-rc.4"コマンドの -bオプションで指定した"3.9.0-rc.4"に合ったものを https://hub.docker.com/r/chinachu/mirakurun/tags の中で見つけて記述する。
~/docker/Mirakurun/docker/docker-compose.yml
services: mirakurun: container_name: mirakurun-3.9.0-rc.4 build: # context: Mirakurun context: ../ dockerfile: docker/Dockerfile # image: chinachu/mirakurun:3.9.0-rc.4 image: chinachu/mirakurun:amd64-3.9.0-rc.4 cap_add: - SYS_ADMIN - SYS_NICE ports: - "40772:40772" - "9229:9229" environment: TZ: "Asia/Tokyo" # DOCKER_NETWORK: host # network_mode: host devices: - /dev/px4video0:/dev/px4video0 - /dev/px4video1:/dev/px4video1 - /dev/px4video2:/dev/px4video2 - /dev/px4video3:/dev/px4video3 - /dev/bus:/dev/bus volumes: # ** CAUTION ** # (default) `/usr/local/mirakurun/*` has been moved to `/opt/mirakurun/*` # try: # sudo mv -vf /usr/local/mirakurun /opt/mirakurun # sudo mkdir -p /opt/mirakurun/run /opt/mirakurun/opt /opt/mirakurun/config /opt/mirakurun/data # you can change to any location if required. - type: bind source: /opt/mirakurun/run/ target: /var/run/ - type: bind source: /opt/mirakurun/opt/ target: /opt/ - type: bind source: /opt/mirakurun/config/ target: /app-config/ - type: bind source: /opt/mirakurun/data/ target: /app-data/ restart: always logging: driver: json-file options: max-file: "1" max-size: 10m
tuners.yml, channels.ymlを作成する
$ su - tv $ cd ~/docker/Mirakurun/config $ mv tuners.yml tuners.yml.original $ mv channels.yml channels.yml.original
チューナー情報ファイル作成
次の内容で ~/docker/Mirakurun/config/tuners.yml を作成する。
参考 【完全解説】LinuxとPX-W3U4でEPGStation v2を構築する方法(PX-Q3U4/W3PE4/Q3PE4) | ページ 5 | 小茂根の暮らし
~/docker/Mirakurun/config/tuners.yml
- name: PX-W3U4_S1 types: - BS - CS command: recpt1 --device /dev/px4video0 <channel> - - decoder: arib-b25-stream-test isDisabled: false - name: PX-W3U4_S2 types: - BS - CS command: recpt1 --device /dev/px4video1 <channel> - - decoder: arib-b25-stream-test isDisabled: false - name: PX-W3U4_T1 types: - GR command: recpt1 --device /dev/px4video2 <channel> - - decoder: arib-b25-stream-test isDisabled: false - name: PX-W3U4_T2 types: - GR command: recpt1 --device /dev/px4video3 <channel> - - decoder: arib-b25-stream-test isDisabled: false
チャンネル情報ファイル作成
参考 mirakurun BSCSチャンネル設定(2023/04/19現在) · GitHub
次の内容で ~/docker/Mirakurun/config/channels.yml を作成する。
神戸チャンネル フォーマット
(見ないチャンネルには "isDisabled: true"行を書き込む)
~/docker/Mirakurun/config/channels.yml
- name: NHK総合 type: GR channel: '22' isDisabled: false - name: NHKEテレ type: GR channel: '13' isDisabled: false - name: サンテレビ type: GR channel: '26' isDisabled: false - name: MBS毎日放送 type: GR channel: '16' isDisabled: false - name: ABCテレビ type: GR channel: '15' isDisabled: false - name: テレビ大阪 type: GR channel: '18' isDisabled: false - name: 関西テレビ type: GR channel: '17' isDisabled: false - name: 読売テレビ type: GR channel: '14' isDisabled: false - name: J:COMテレビ type: GR channel: '19' isDisabled: false - name: J:COMチャンネル type: GR channel: '24' isDisabled: false - name: NHK BS1 type: BS channel: BS15_0 serviceId: 101 - name: NHK BSプレミアム type: BS channel: BS03_1 serviceId: 103 - name: BS日テレ type: BS channel: BS13_0 serviceId: 141 - name: BS朝日 type: BS channel: BS01_0 serviceId: 151 - name: BS-TBS type: BS channel: BS01_1 serviceId: 161 - name: BSテレ東 type: BS channel: BS01_2 serviceId: 171 - name: BSフジ type: BS channel: BS13_1 serviceId: 181 - name: WOWOWプライム type: BS channel: BS03_0 serviceId: 191 isDisabled: true - name: WOWOWライブ type: BS channel: BS05_0 serviceId: 192 isDisabled: true - name: WOWOWシネマ type: BS channel: BS05_1 serviceId: 193 isDisabled: true - name: スター・チャンネル1 type: BS channel: BS09_1 serviceId: 200 isDisabled: true - name: スター・チャンネル2 type: BS channel: BS15_1 serviceId: 201 isDisabled: true - name: スター・チャンネル3 type: BS channel: BS15_1 serviceId: 202 isDisabled: true - name: BS11 type: BS channel: BS09_0 serviceId: 211 - name: TwellV type: BS channel: BS09_2 serviceId: 222 - name: 放送大学 BS1 type: BS channel: BS11_0 serviceId: 231 - name: 放送大学 BS2 type: BS channel: BS11_0 serviceId: 232 - name: グリーンチャンネル type: BS channel: BS21_2 serviceId: 234 isDisabled: true - name: BSアニマックス type: BS channel: BS13_2 serviceId: 236 isDisabled: true - name: J SPORTS 1 type: BS channel: BS19_1 serviceId: 242 isDisabled: true - name: J SPORTS 2 type: BS channel: BS19_2 serviceId: 243 isDisabled: true - name: J SPORTS 3 type: BS channel: BS19_3 serviceId: 244 isDisabled: true - name: J SPORTS 4 type: BS channel: BS19_0 serviceId: 245 isDisabled: true - name: BS釣りビジョン type: BS channel: BS11_1 serviceId: 251 isDisabled: true - name: WOWOWプラス type: BS channel: BS21_0 serviceId: 252 isDisabled: true - name: 日本映画専門チャンネル type: BS channel: BS21_1 serviceId: 255 isDisabled: true - name: ディズニー・チャンネル type: BS channel: BS23_0 serviceId: 256 isDisabled: true - name: BS松竹東急 type: BS channel: BS23_3 serviceId: 260 - name: BSJapanext type: BS channel: BS23_2 serviceId: 263 - name: BSよしもと type: BS channel: BS23_1 serviceId: 265
dockerデーモンの稼働を確認する
$ systemctl status docker.service (docker.serviceが稼働していなければ) $ sudo systemctl start docker.service $ systemctl status docker.service
pcscdを停止させる
Mirakurunではpcscdは稼働させない
$ sudo systemctl stop pcscd.socket $ sudo systemctl disable pcscd.socket (確認) $ systemctl status pcscd.socket
Mirakurunコンテナを作成する
$ su - tv $ cd ~/docker/Mirakurun/docker $ docker-compose -f ./docker-compose.yml pull $ docker-compose -f ./docker-compose.yml build --no-cache かなり時間がかかる
初回セットアップを行う
$ su - tv $ cd ~/docker/Mirakurun/docker $ docker-compose -f ./docker-compose.yml run --rm -e SETUP=true mirakurun
チューナー情報ファイルを確認する
~/docker/Mirakurun/config/tuners.yml が先に作成した内容であることを確認する。
チャンネル設定ファイルを確認する
~/docker/Mirakurun/config/channels.yml が先に作成した内容であることを確認する。
Mirakurunコンテナを起動する
$ su - tv $ cd ~/docker/Mirakurun/docker $ docker-compose -f ./docker-compose.yml up -d
Mirakurunの稼働を確認する
$ curl -o - http://<MirakurunURL>:<Port>/api/version 通常は curl -o - http://localhost:40772/api/version => {"current":"xxxx","latest":"xxxx"}
あるいは、ブラウザから http://MY/MIRAKURUN/IP/ADDRESS:40772 にアクセスする。
PC起動時のMirakurun起動について
docker-compose.ymlに"restart: always"を記述しているので、PC起動時にMirakurunが自動起動する。
(参考)Mirakurunでの手動録画
$ su - tv (コンテナID確認) $ docker ps (シェルモードでMirakurunコンテナに入る) $ docker exec -it MIRAKURUNcontainerID /bin/bash (ホスト(Xubuntu)と共有のテンポラリディレクトリ作成) # mkdir /app-data/tmp (地デジ22チャンネルを15秒間録画しホストの/opt/mirakurun/data/に保存) # recpt1 --b25 --strip --sid hd 22 15 /app-data/tmp/tmp22ch.ts (NHK BS1を15秒間録画しホストの/opt/mirakurun/data/に保存) # recpt1 --b25 --strip --sid hd BS15_0 15 /app-data/tmp/tmpBS1ch.ts (Mirakurunコンテナから出る) # exit (録画ファイル確認) $ ls /opt/mirakurun/data/tmp/*.ts /opt/mirakurun/data/tmp/tmp22ch.ts /opt/mirakurun/data/tmp/tmpBS1ch.ts
ポート開放
40772番ポートをLAN内に開放する
(例)
アドレス確認 $ ip a | grep '192.168.' inet 192.168.6.3/24 brd 192.168.6.255 scope global noprefixroute ens33 $ sudo ufw enable $ sudo ufw allow proto tcp from 192.168.6.0/24 to any port 40772 $ sudo ufw allow proto udp from 192.168.6.0/24 to any port 40772 openVPNでLAN外からのアクセスを許可する場合 $ sudo ufw allow proto tcp from 10.8.0.0/24 to any port 40772 $ sudo ufw allow proto udp from 10.8.0.0/24 to any port 40772 設定読み込み $ sudo ufw reload
(参考)Mirakurunの停止
稼働しているコンテナを停止する。
$ su - tv $ cd ~/docker/Mirakurun/docker $ docker-compose -f ./docker-compose.yml down
MySQLをインストールする
mariaDBをインストールする
次のサイトにしたがってインストールする。
MariaDBをubuntuにインストール - rokkonet
mariaDBをEPGStation向けに設定する
出典 https://github.com/y-hashida/Memo_Mirakurun-and-EPGStation
データベースとユーザーを作成し、大量発生するバイナリログの保管期間を1日にする
$ sudo mysql > CREATE DATABASE epgstation CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; > GRANT ALL ON epgstation.* TO epgstation@localhost IDENTIFIED BY 'epgstation'; > GRANT ALL ON epgstation.* TO epgstation@127.0.0.1 IDENTIFIED BY 'epgstation'; > GRANT ALL ON epgstation.* TO epgstation@MY.EPGSTATION.IP.ADDRESS IDENTIFIED BY 'epgstation'; > SET GLOBAL expire_logs_days = 1; > exit
EPGStationをインストールする
gccのインストール
$ gcc --version (インストールされていなければ) $ sudo apt update && sudo apt install build-essential
Node.jsのインストール
$ node --version
インストールされていなければ次のサイトにしたがってインストールする。
github.com/l3tnun/EPGStationでの動作環境記載
Node.js : ^14.6.0 || ^16.6.1 || ^18.16.1
バージョン20でEPGStationが稼働した。
インストールガイド -> 最新のNode.jsのubuntuへのインストール - rokkonet
FFMPEGのインストール
$ ffmpeg -version (インストールされていなければ) $ sudo apt update && sudo apt install ffmpeg
pythonのインストール
$ python --version
インストールされていなければ、EPGStationを稼働させるユーザー(tvとした)でまずpyenvをインストールし、その後、pythonをインストールする。
出典 ubuntu 20.04 / 18.04 に pyenv をインストール
$ su - tv $ sudo apt update && sudo apt install \ build-essential libssl-dev zlib1g-dev \ libbz2-dev libreadline-dev libsqlite3-dev curl llvm \ libncursesw5-dev tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \ libopencv-dev git $ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
~/.profile に下記を記述する。
export PYENV_ROOT="${HOME}/.pyenv" export PATH="${PYENV_ROOT}/bin:${PATH}" eval "$(pyenv init --path)"
~/.profile を読み込む。
$ source ~/.profile
pyenvがインストールされていることを確認する
$ pyenv -v
インストールできるpythonの一覧を出力する
$ pyenv install --list
適当なバージョンのpythonをインストールする
$ pyenv install 3.9.4 (確認) $ pyenv versions
グローバル空間での利用に設定する
(インストールしたユーザー空間でのグローバル。他ユーザーからは利用できない)
$ pyenv global 3.9.4 (確認) $ python -V
Mirakurunの稼働確認
$ curl -o - http://<MirakurunURL>:<Port>/api/version 通常は curl -o - http://localhost:40772/api/version => {"current":"xxxx","latest":"xxxx"} 稼働していなければ $ cd ~/docker/Mirakurun/docker $ docker-compose -f ./docker-compose.yml up -d
MySQLの稼働確認
$ systemctl status mysql.service 稼働していなければ $ sudo systemctl start mysql.service
録画ファイル保管場所と録画サムネイル画像ファイル保管場所を作成する
EPGStationをWindows上のVMware Workstation PlayerのXubuntuにインストールし、録画ファイル保管場所をWindows上のストレージとする時は、Windows上の録画ファイル保管ストレージをVMwareとの共有フォルダとする。
$ sudo mkdir /MY/RECORDED/FILE/DIR $ sudo mkdir /MY/RECORDED/FILE/DIR/thums $ sudo chmod 777 /MY/RECORDED/FILE/DIR /MY/RECORDED/FILE/DIR/thums
EPGStationをインストールする
出典 EPGStation/doc/linux-setup.md at master · l3tnun/EPGStation · GitHub
$ su - tv $ cd ~/ $ git clone https://github.com/l3tnun/EPGStation.git $ cd EPGStation $ npm run all-install $ npm run build $ cd config $ cp config.yml.template config.yml $ cp operatorLogConfig.sample.yml operatorLogConfig.yml $ cp epgUpdaterLogConfig.sample.yml epgUpdaterLogConfig.yml $ cp serviceLogConfig.sample.yml serviceLogConfig.yml $ cp enc.js.template enc.js
~/EPGStation/config/config.ymlを修正する
(修正概要)
unix socket接続できなかったので、
unix socket接続設定を削除
40772ポートIP接続を設定
mysql利用に変更
録画ファイル名規則を変更
録画ファイル保存ディレクトリを変更
録画サムネイル画像保存ディレクトリを変更
マニュアル EPGStation/doc/conf-manual.md at master · l3tnun/EPGStation · GitHub
~/EPGStation/config/config.yml
# mirakurunPath: http+unix://%2Fvar%2Frun%2Fmirakurun.sock/ mirakurunPath: http://localhost:40772 # dbtype: sqlite # sqlite: # extensions: # - '/hoge/regexp.dylib' # regexp: true dbtype: mysql mysql: host: 127.0.0.1 port: 3306 user: epgstation password: epgstation database: epgstation charset: utf8mb4 recordedFormat: '%SHORTYEAR%%MONTH%%DAY%%HOUR%%MIN%%TYPE%%CH%-%SID%-%CHNAME%-%TITLE%' recorded: - name: recorded ## ブラウザ上に表示される保存場所名 path: '/MY/RECORDED/FILE/DIR' ## 保存ディレクトリのフルパス thumbnail: '/MY/RECORDED/FILE/DIR/thums' #ffmpeg: /usr/local/bin/ffmpeg ffmpeg: /usr/bin/ffmpeg #ffprobe: /usr/local/bin/ffprobe ffprobe: /usr/bin/ffprobe
H.264エンコード設定増設
音声欠落を防ぐため、冒頭4秒間をカットして H.264にエンコードする設定を追加する
参考 副音声付きTV録画tsファイルのmp4へのトランスコード - rokkonet
(1) エンコードスクリプトを作成する
次の内容で ${HOME}/EPGStation/config/enc-cut4secs.js をファイル属性644で作成する。
const spawn = require('child_process').spawn; const ffmpeg = process.env.FFMPEG; const input = process.env.INPUT; const output = process.env.OUTPUT; const analyzedurationSize = '10M'; // Mirakurun の設定に応じて変更すること const probesizeSize = '32M'; // Mirakurun の設定に応じて変更すること const maxMuxingQueueSize = 1024; const dualMonoMode = 'main'; const videoHeight = parseInt(process.env.VIDEORESOLUTION, 10); const isDualMono = parseInt(process.env.AUDIOCOMPONENTTYPE, 10) == 2; const audioBitrate = videoHeight > 720 ? '192k' : '128k'; const preset = 'veryfast'; const codec = 'libx264'; const crf = 23; const args = ['-ss', '4', '-y', '-analyzeduration', analyzedurationSize, '-probesize', probesizeSize]; // dual mono 設定 if (isDualMono) { Array.prototype.push.apply(args, ['-dual_mono_mode', dualMonoMode]); } // input 設定 Array.prototype.push.apply(args,['-i', input]); // メタ情報を先頭に置く Array.prototype.push.apply(args,['-movflags', 'faststart']); // 字幕データを含めたストリームをすべてマップ // Array.prototype.push.apply(args, ['-map', '0', '-ignore_unknown', '-max_muxing_queue_size', maxMuxingQueueSize, '-sn']); // video filter 設定 let videoFilter = 'yadif'; if (videoHeight > 720) { videoFilter += ',scale=-2:720' } Array.prototype.push.apply(args, ['-vf', videoFilter]); // その他設定 Array.prototype.push.apply(args,[ '-preset', preset, '-aspect', '16:9', '-c:v', codec, '-crf', crf, '-f', 'mp4', '-c:a', 'aac', '-ar', '48000', '-ab', audioBitrate, '-ac', '2', output ]); let str = ''; for (let i of args) { str += ` ${ i }` } console.error(str); const child = spawn(ffmpeg, args); child.stderr.on('data', (data) => { console.error(String(data)); }); child.on('error', (err) => { console.error(err); throw new Error(err); }); process.on('SIGINT', () => { child.kill('SIGINT'); });
(2) EPGStationに enc-cut4secs.js によるエンコード設定を組み込む
${HOME}/EPGStation/config/config.yml のencodeブロックに設定を記述する。
"- name:"で始め、変換コマンドjsファイル・拡張子・録画後タイムアウト時間(秒)を指定する。
設定例
encode: #### デフォルトの設定 #### - name: H.264 cmd: '%NODE% %ROOT%/config/enc.js' suffix: .mp4 rate: 4.0 #### enc-cut4secs.js によるエンコード設定 #### - name: H.264-cut4secs cmd: '%NODE% %ROOT%/config/enc-cut4secs.js' suffix: .mp4 rate: 4.0
(参考)デフォルトの ${HOME}/EPGStation/config/enc.js'
const spawn = require('child_process').spawn; const ffmpeg = process.env.FFMPEG; const input = process.env.INPUT; const output = process.env.OUTPUT; const analyzedurationSize = '10M'; // Mirakurun の設定に応じて変更すること const probesizeSize = '32M'; // Mirakurun の設定に応じて変更すること const maxMuxingQueueSize = 1024; const dualMonoMode = 'main'; const videoHeight = parseInt(process.env.VIDEORESOLUTION, 10); const isDualMono = parseInt(process.env.AUDIOCOMPONENTTYPE, 10) == 2; const audioBitrate = videoHeight > 720 ? '192k' : '128k'; const preset = 'veryfast'; const codec = 'libx264'; const crf = 23; const args = ['-y', '-analyzeduration', analyzedurationSize, '-probesize', probesizeSize]; // dual mono 設定 if (isDualMono) { Array.prototype.push.apply(args, ['-dual_mono_mode', dualMonoMode]); } // input 設定 Array.prototype.push.apply(args,['-i', input]); // メタ情報を先頭に置く Array.prototype.push.apply(args,['-movflags', 'faststart']); // 字幕データを含めたストリームをすべてマップ // Array.prototype.push.apply(args, ['-map', '0', '-ignore_unknown', '-max_muxing_queue_size', maxMuxingQueueSize, '-sn']); // video filter 設定 let videoFilter = 'yadif'; if (videoHeight > 720) { videoFilter += ',scale=-2:720' } Array.prototype.push.apply(args, ['-vf', videoFilter]); // その他設定 Array.prototype.push.apply(args,[ '-preset', preset, '-aspect', '16:9', '-c:v', codec, '-crf', crf, '-f', 'mp4', '-c:a', 'aac', '-ar', '48000', '-ab', audioBitrate, '-ac', '2', output ]); let str = ''; for (let i of args) { str += ` ${ i }` } console.error(str); const child = spawn(ffmpeg, args); child.stderr.on('data', (data) => { console.error(String(data)); }); child.on('error', (err) => { console.error(err); throw new Error(err); }); process.on('SIGINT', () => { child.kill('SIGINT'); });
ポート開放
8888番ポートをLAN内に開放する
(例)
$ sudo ufw enable $ sudo ufw allow proto tcp from MY.NET.ADDRESS..0/24 to any port 8888 $ sudo ufw allow proto udp from MY.NET.ADDRESS..0/24 to any port 8888 openVPNでLAN外からのアクセスを許可する場合 $ sudo ufw allow proto tcp from 10.8.0.0/24 to any port 8888 $ sudo ufw allow proto udp from 10.8.0.0/24 to any port 8888 設定読み込み $ sudo ufw reload
初回起動
$ cd ~/EPGStation $ sudo npm install pm2 -g $ sudo pm2 startup (次の出力が出る) ##### ここから ##### [PM2] Freeze a process list on reboot via: $ pm2 save [PM2] Remove init script via: $ pm2 unstartup systemd ##### ここまで ##### $ pm2 start dist/index.js --name "epgstation" $ pm2 save
上記コマンド実行時の画面出力内容
+++ ここから +++
$ sudo npm install pm2 -g /usr/local/bin/pm2 -> /usr/local/lib/node_modules/pm2/bin/pm2 /usr/local/bin/pm2-dev -> /usr/local/lib/node_modules/pm2/bin/pm2-dev /usr/local/bin/pm2-docker -> /usr/local/lib/node_modules/pm2/bin/pm2-docker /usr/local/bin/pm2-runtime -> /usr/local/lib/node_modules/pm2/bin/pm2-runtime npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.3.1 (node_modules/pm2/node_modules/chokidar/node_modules/fsevents): npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"}) + pm2@4.5.6 added 175 packages from 194 contributors in 15.996s $ sudo pm2 startup Runtime Edition PM2 is a Production Process Manager for Node.js applications with a built-in Load Balancer. Start and Daemonize any application: $ pm2 start app.js Load Balance 4 instances of api.js: $ pm2 start api.js -i 4 Monitor in production: $ pm2 monitor Make pm2 auto-boot at server restart: $ pm2 startup To go further checkout: http://pm2.io/ ------------- [PM2] Init System found: systemd ----------------------------------------------------------- PM2 detected systemd but you precised ubuntu Please verify that your choice is indeed your init system If you arent sure, just run : pm2 startup ----------------------------------------------------------- Platform ubuntu Template [Unit] Description=PM2 process manager Documentation=https://pm2.keymetrics.io/ After=network.target [Service] Type=forking User=root LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin Environment=PM2_HOME=/root/.pm2 PIDFile=/root/.pm2/pm2.pid Restart=on-failure ExecStart=/usr/local/lib/node_modules/pm2/bin/pm2 resurrect ExecReload=/usr/local/lib/node_modules/pm2/bin/pm2 reload all ExecStop=/usr/local/lib/node_modules/pm2/bin/pm2 kill [Install] WantedBy=multi-user.target Target path /etc/systemd/system/pm2-root.service Command list [ 'systemctl enable pm2-root' ] [PM2] Writing init configuration in /etc/systemd/system/pm2-root.service [PM2] Making script booting at startup... [PM2] [-] Executing: systemctl enable pm2-root... Created symlink /etc/systemd/system/multi-user.target.wants/pm2-root.service → /etc/systemd/system/pm2-root.service. [PM2] [v] Command successfully executed. +---------------------------------------+ [PM2] Freeze a process list on reboot via: $ pm2 save [PM2] Remove init script via: $ pm2 unstartup systemd $ pm2 start dist/index.js --name "epgstation" Runtime Edition PM2 is a Production Process Manager for Node.js applications with a built-in Load Balancer. Start and Daemonize any application: $ pm2 start app.js Load Balance 4 instances of api.js: $ pm2 start api.js -i 4 Monitor in production: $ pm2 monitor Make pm2 auto-boot at server restart: $ pm2 startup To go further checkout: http://pm2.io/ ------------- [PM2] Spawning PM2 daemon with pm2_home=/HOME/.pm2 [PM2] PM2 Successfully daemonized [PM2] Starting /HOME/EPGStation/dist/index.js in fork_mode (1 instance) [PM2] Done. ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐ │ id │ name │ mode │ ↺ │ status │ cpu │ memory │ ├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤ │ 0 │ epgstation │ fork │ 0 │ online │ 0% │ 21.8mb │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘ $ pm2 save [PM2] Saving current process list... [PM2] Successfully saved in /HOME/.pm2/dump.pm2
+++ ここまで +++
EPGStationの稼働を http://EPGSTATION.HOST.IP.ADDRESS:8888 を開いて確認する。
あるいは、"curl -o - http://EPGSTATION.HOST.IP.ADDRESS:8888"コマンドで出力があることを確認する。
異常があれば、 ${HOME}/.pm2/logs/epgstation-error.log ファイルを確認する。
システム起動時に、Mirakurun、MySQLの起動後にEPGStationが自動起動するように設定する
/etc/systemd/system/epgstation.serviceを作成する。
/etc/systemd/system/epgstation.service
[Unit] Description=EPGStation Requires=docker.service After=docker.service mysql.service Wants=mysql.service [Service] Type=simple User=tv Group=tv WorkingDirectory=/home/tv/EPGStation ExecStart=npm start [Install] WantedBy=multi-user.target
systemdにepgstation.serviceをロードする。
$ sudo systemctl daemon-reload
EPGStation自動起動を設定する。
$ sudo systemctl enable epgstation.service
pm2で起動し稼働しているEPGStationを終了する
$ su - tv $ pm2 stop epgstation
"pm2 save"コマンドでセットされたEPGStation自動起動を解除する
$ su - tv $ pm2 unstartup
システムを再起動してEPGStationの自動起動を確認する
$ sudo reboot
Mirakurun、MySQLの起動に無関係にEPGStationを起動する方法(非推奨)
出典 https://qiita.com/ikemura23/items/68fb61b16c6752daa7e8 $ su - tv $ cd ~/EPGStation $ pm2 stop epgstation $ pm2 start dist/index.js --name "epgstation" --update-env $ pm2 startup ## 画面出力された指示にしたがって、画面のコマンドをコピーする 上記でコピーしたコマンドを実行する $ sudo env PATH=$PATH:/usr/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u tv --hp ${HOME} "pm2 save"コマンドを実行すると、次回システム起動時にEPGStationが自動起動する $ pm2 save システムを再起動してEPGStationの自動起動を確認 $ sudo reboot
稼働確認
ブラウザで http://EPGSTATION.HOST.IP.ADDRESS:8888 を開いて確認する。
あるいは、"curl -o - http://EPGSTATION.HOST.IP.ADDRESS:8888"コマンドで出力があることを確認する。
・pm2コマンド起動している場合のpm2コマンドでの確認
$ su - tv $ pm2 status
・mysqlのデータベーステーブルを確認
$ mysql -u epgstation -p epgstation > show tables; > select * from channel; > select * from program; > exit
(参考)ステータス表示
$ su - tv $ pm2 show epgstation
(参考)systemdでMirakurun、MySQLの起動後に自動起動したEPGStation の終了
$ sudo systemctl stop epgstation.service
(参考)pm2コマンドで起動した EPGStation の終了
$ su - tv $ pm2 stop epgstation
(参考)"pm2 save"コマンドで設定したEPGStation自動起動の解除
$ su - tv $ pm2 unstartup
(参考)npmコマンドによるEPGStation起動(次回システム起動時に自動起動はしない)
$ su - tv $ npm start
(参考)npmコマンドで起動したEPGStationの終了
$ su - tv $ npm stop
ログ保管場所
${HOME}/EPGStation/logs/
${HOME}/.pm2/logs/epgstation-out.log
${HOME}/.pm2/logs/epgstation-error.log
ログファイルについて
GitHub - l3tnun/EPGStation: Mirakurun を使用した録画管理ソフト
config.yml詳細マニュアル
EPGStation/doc/conf-manual.md at master · l3tnun/EPGStation · GitHub
(参考)EPGStationのアンインストール
出典 EPGStationのインストール - にゃののん日記
$ su - tv $ pm2 delete epgstation ## PM2に登録されているEPGStationを削除 $ pm2 save ## PM2の現在の状態を保存 $ pm2 kill ## PM2を停止 $ sudo systemctl stop pm2-xxxxxxxx ## 現在のユーザ(xxxxxxxxをユーザ名に置き換える)でのPM2の自動起動を停止 $ sudo systemctl disable pm2-xxxxxxxx ## 現在のユーザでのPM2の無効化 $ sudo rm -f /etc/systemd/system/pm2-xxxxxxxx.service ## 設定を削除 $ rm -rf ~/.pm2 ## PM2の設定保存ディレクトリを削除
(参考)mysqlのテーブル構造
> show tables; +----------------------------+ | Tables_in_epgstation | +----------------------------+ | channel | | drop_log_file | | migrations | | program | | recorded | | recorded_history | | recorded_tag | | recorded_tags_recorded_tag | | reserve | | rule | | thumbnail | | video_file | +----------------------------+
> show columns from program; +----------------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------------+--------------+------+-----+---------+-------+ | id | bigint(20) | NO | PRI | NULL | | | updateTime | bigint(20) | NO | | NULL | | | channelId | bigint(20) | NO | | NULL | | | eventId | bigint(20) | NO | | NULL | | | serviceId | int(11) | NO | | NULL | | | networkId | int(11) | NO | | NULL | | | startAt | bigint(20) | NO | | NULL | | | endAt | bigint(20) | NO | | NULL | | | startHour | int(11) | NO | | NULL | | | week | int(11) | NO | | NULL | | | duration | int(11) | NO | | NULL | | | isFree | tinyint(4) | NO | | NULL | | | name | text | NO | | NULL | | | halfWidthName | text | NO | | NULL | | | shortName | text | NO | | NULL | | | description | text | YES | | NULL | | | halfWidthDescription | text | YES | | NULL | | | extended | text | YES | | NULL | | | halfWidthExtended | text | YES | | NULL | | | genre1 | int(11) | YES | | NULL | | | subGenre1 | int(11) | YES | | NULL | | | genre2 | int(11) | YES | | NULL | | | subGenre2 | int(11) | YES | | NULL | | | genre3 | int(11) | YES | | NULL | | | subGenre3 | int(11) | YES | | NULL | | | channelType | varchar(255) | NO | | NULL | | | channel | varchar(255) | NO | | NULL | | | videoType | text | YES | | NULL | | | videoResolution | text | YES | | NULL | | | videoStreamContent | int(11) | YES | | NULL | | | videoComponentType | int(11) | YES | | NULL | | | audioSamplingRate | int(11) | YES | | NULL | | | audioComponentType | int(11) | YES | | NULL | | +----------------------+--------------+------+-----+---------+-------+
> show columns from recorded; +----------------------+------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------------------+------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | reserveId | int(11) | YES | | NULL | | | ruleId | int(11) | YES | | NULL | | | programId | bigint(20) | YES | | NULL | | | channelId | bigint(20) | NO | | NULL | | | isProtected | tinyint(4) | NO | | 0 | | | startAt | bigint(20) | NO | | NULL | | | endAt | bigint(20) | NO | | NULL | | | duration | int(11) | NO | | NULL | | | name | text | NO | | NULL | | | halfWidthName | text | NO | | NULL | | | description | text | YES | | NULL | | | halfWidthDescription | text | YES | | NULL | | | extended | text | YES | | NULL | | | halfWidthExtended | text | YES | | NULL | | | genre1 | int(11) | YES | | NULL | | | subGenre1 | int(11) | YES | | NULL | | | genre2 | int(11) | YES | | NULL | | | subGenre2 | int(11) | YES | | NULL | | | genre3 | int(11) | YES | | NULL | | | subGenre3 | int(11) | YES | | NULL | | | videoType | text | YES | | NULL | | | videoResolution | text | YES | | NULL | | | videoStreamContent | int(11) | YES | | NULL | | | videoComponentType | int(11) | YES | | NULL | | | audioSamplingRate | int(11) | YES | | NULL | | | audioComponentType | int(11) | YES | | NULL | | | isRecording | tinyint(4) | NO | | NULL | | | dropLogFileId | int(11) | YES | UNI | NULL | | +----------------------+------------+------+-----+---------+----------------+ id: video_fileテーブルのrecordedIdと同じ値 startAt, endAt: 単位がミリ秒のunix time値 NHK総合神戸のchannelIdは"3208043008"
> show columns from reserve; +-----------------------------+------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------------------------+------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | updateTime | bigint(20) | NO | | NULL | | | ruleId | int(11) | YES | | NULL | | | ruleUpdateCnt | int(11) | YES | | NULL | | | isSkip | tinyint(4) | NO | | 0 | | | isConflict | tinyint(4) | NO | | 0 | | | allowEndLack | tinyint(4) | NO | | 0 | | | tags | text | YES | | NULL | | | isOverlap | tinyint(4) | NO | | 0 | | | isIgnoreOverlap | tinyint(4) | NO | | 0 | | | isTimeSpecified | tinyint(4) | NO | | 0 | | | parentDirectoryName | text | YES | | NULL | | | directory | text | YES | | NULL | | | recordedFormat | text | YES | | NULL | | | encodeMode1 | text | YES | | NULL | | | encodeParentDirectoryName1 | text | YES | | NULL | | | encodeDirectory1 | text | YES | | NULL | | | encodeMode2 | text | YES | | NULL | | | encodeParentDirectoryName2 | text | YES | | NULL | | | encodeDirectory2 | text | YES | | NULL | | | encodeMode3 | text | YES | | NULL | | | encodeParentDirectoryName3 | text | YES | | NULL | | | encodeDirectory3 | text | YES | | NULL | | | isDeleteOriginalAfterEncode | tinyint(4) | NO | | 0 | | | programId | bigint(20) | YES | | NULL | | | programUpdateTime | bigint(20) | YES | | NULL | | | channelId | bigint(20) | NO | | NULL | | | channel | text | NO | | NULL | | | channelType | text | NO | | NULL | | | startAt | bigint(20) | NO | | NULL | | | endAt | bigint(20) | NO | | NULL | | | name | text | YES | | NULL | | | halfWidthName | text | YES | | NULL | | | shortName | text | YES | | NULL | | | description | text | YES | | NULL | | | halfWidthDescription | text | YES | | NULL | | | extended | text | YES | | NULL | | | halfWidthExtended | text | YES | | NULL | | | genre1 | int(11) | YES | | NULL | | | subGenre1 | int(11) | YES | | NULL | | | genre2 | int(11) | YES | | NULL | | | subGenre2 | int(11) | YES | | NULL | | | genre3 | int(11) | YES | | NULL | | | subGenre3 | int(11) | YES | | NULL | | | videoType | text | YES | | NULL | | | videoResolution | text | YES | | NULL | | | videoStreamContent | int(11) | YES | | NULL | | | videoComponentType | int(11) | YES | | NULL | | | audioSamplingRate | int(11) | YES | | NULL | | | audioComponentType | int(11) | YES | | NULL | | +-----------------------------+------------+------+-----+---------+----------------+
> show columns from video_file; +---------------------+------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------------+------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | parentDirectoryName | text | NO | | NULL | | | filePath | text | NO | | NULL | | | type | text | NO | | NULL | | | name | text | NO | | NULL | | | size | bigint(20) | NO | | 0 | | | recordedId | int(11) | NO | MUL | NULL | | +---------------------+------------+------+-----+---------+----------------+ recordedId:recordedテーブルのidと同じ値
(参考)録画ファイル情報取得例
(例1)mysqlのデータから抽出
mysql > 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 ;
(例2)config.ymlからの録画ファイル保存ディレクトリ取得 & mysqlデータ抽出
# visudo epgstationUser ALL=(root) NOPASSWD: /usr/bin/mysql $ su - epgstationUser $ ConfigFile="${HOME}/EPGStation/config/config.yml" $ ParentDir=$(cat "$ConfigFile" | grep -P '^[ \t]*path') $ ParentDir=${ParentDir#*\'} $ ParentDir=${ParentDir%\'*} $ ParentDir=${ParentDir%/} $ DestDir="DIR/TO/SAVE/RECORDED-FILE-LIST" $ DestFileName="FILE-NAME-OF-RECORDED-FILE-LIST" $ DbName=DATABE-NAME-OF-EPGSTATION-IN-MYSQL $ sed "s:${ParentDir}\t*:${ParentDir}/:" > "${DestDir}/${DestFileName}" <(echo "select video_file.id, '${ParentDir}' as parentDirPath, 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" | sudo /usr/bin/mysql -D ${DbName})
(例3)指定するchannelIdとstartAtに合致するレコードをrecordedテーブルとvideo_fileテーブルから削除するsql文
DELETE recorded, video_file FROM recorded INNER JOIN video_file ON recorded.id = video_file.recordedId WHERE recorded.channelId = 指定するchannelId AND recorded.startAt = 指定するstartAt;
(参考)録画ファイル保存ディレクトリ
録画ファイル保存ディレクトリは、mysqlデータベースには"recorded"と記録されており、パスを取得できない。
録画ファイル保存ディレクトリパスは ~/EPGStation/config/config.yml内のrecorded: path: 'PARENT/DIR'を参照する。
(参考)録画ファイル情報テキストファイル保存スクリプト
スクリプト保管場所
https://bitbucket.org/arsmus/shell-script-public/src/master/audio-video/save_record-file-information-epgstation.sh
(参考)録画ファイル保存ディレクトリの変更について
~/EPGStation/config/config.yml内のrecorded: path: 'PARENT/DIR'を変更すると録画ファイル保存ディレクトリが変更される。
保存ディレクトリ変更前の録画ファイルは http://localhost:8888/ からは再生できなくなる。