rokkonet

PC・Androidソフトウェア・アプリの開発・使い方に関するメモ

EPGStation : エンコードモード追加

2026 Nov. 10.
2026 Apr. 06.
2025 Mar. 16.
2025 Feb. 24.

以下の記事はEPGStation v2のもの。
EPGStation v3では、hoge.js(の冒頭)の require を import に書き換える。
出典: docker-mirakurun-epgstation/docs/migration.md at v3 · l3tnun/docker-mirakurun-epgstation · GitHub

音声欠落対策H.264エンコード設定

音声欠落を防ぐため、冒頭4秒間をカットして H.264にエンコードする設定を追加する設定

ストリームを指定しない。
通常の番組はこれで対応できる。
NHK総合19時ニュース、NHK BS世界のドキュメンタリーはこれでは音声が欠ける。

参考
EPGStationで使うFFmpeg 4.2.4のオプション設定を考える – Simple Life in the digital age

https://rasumus.hatenablog.com/entry/2020/05/30/221853

(1) エンコードスクリプトを作成する
次の内容で ${HOME}/docker/docker-mirakurun-epgstation/epgstation/config/enc-cut4secs.js をファイル属性644で作成する。

// 2025 Mar. 02.
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']);

// 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}/docker/docker-mirakurun-epgstation/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


NHK BS 世界のドキュメンタリー H.264エンコード設定

参考 https://rasumus.hatenablog.com/entry/2020/05/30/221853

第1音声ストリームに日本語、第2音声ストリームに英語が入った音声多重番組のトランスコード

(1) エンコードスクリプトを作成する
次の内容で ${HOME}/docker/docker-mirakurun-epgstation/epgstation/config/enc-bs_docu-cut4secs.js をファイル属性644で作成する。

// 2025 Mar. 08.
// NHK BS 世界のドキュメンタリー向けH.264トランスコード コード。
// 第1音声ストリームに日本語音声、第2音声ストリームに英語音声が入った動画をトランスコードする。
// ビデオは第1ビデオストリームをトランスコードする。
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
];

// input 設定
Array.prototype.push.apply(args,['-i', input]);

Array.prototype.push.apply(args,[
    '-movflags', 'faststart',
    '-preset', preset,
    '-f', 'mp4',
    '-aspect', '16:9',
    '-c:v', codec,
    '-crf', crf,
    '-map', '0:v:0',
    '-max_muxing_queue_size', maxMuxingQueueSize
]);

// video filter 設定
let videoFilter = 'yadif';
if (videoHeight > 720) {
    videoFilter += ',scale=-2:720';
}
Array.prototype.push.apply(args, ['-vf', videoFilter]);

// 音声ストリームをマップ
Array.prototype.push.apply(args, [
    '-map', '0:a:0',
    '-map', '0:a:1',
    '-metadata:s:a:0', 'title=Japanese',
    '-metadata:s:a:0', 'language=jpn',
    '-metadata:s:a:1', 'title=English',
    '-metadata:s:a:1', 'language=eng'
]);

// 音声コード関連
Array.prototype.push.apply(args, [
    '-c:a', 'aac',
    '-ar', '48000',
    '-ab', audioBitrate,
    '-ac', '2'
]);

// 出力ファイル設定
Array.prototype.push.apply(args,[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-bs_docu-cut4secs.js によるエンコード設定を組み込む
${HOME}/docker/docker-mirakurun-epgstation/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

   #### enc-bs_docu-cut4secs.js によるエンコード設定 ####
    - name: H.264-nhk_bs_docu-cut4secs
      cmd: '%NODE% %ROOT%/config/enc-bs_docu-cut4secs.js'
      suffix: .mp4
      rate: 4.0



NHKニュース( 日英2ヵ国語) H.264エンコード設定


第1音声ストリームに日本語と英語が入ったDual Mono Modeの音声多重番組を2つの音声ストリームにトランスコード





次の音声オプションを適用するように下記のenc-nhk_news-2audio_streams-cut5secs.js記事を訂正すること。

ffmpeg \
 -filter_complex "[0:a:0]pan=mono|c0=c0[jp];[0:a:0]pan=mono|c0=c1[en]" \
 -map "[jp]" -c:a:0 aac -b:a:0 128k -ac:a:0 1 -metadata:s:a:0 title="Japanese" -metadata:s:a:0 language=jpn \
 -map "[en]" -c:a:1 aac -b:a:1 128k -ac:a:1 1 -metadata:s:a:1 title="English" -metadata:s:a:1 language=eng \
 -ar 48000 \





(1) エンコードスクリプトを作成する
次の内容で ${HOME}/docker/docker-mirakurun-epgstation/epgstation/config/enc-nhk_news-2audio_streams-cut5secs.js をファイル属性644で作成する。

// 2025 Mar. 15.
// 第1ビデオストリーム、第1音声ストリームをトランスコードする。
// 第1音声ストリームはDual Mono Modeで日本語と英語が入っている。
// 変換後の第1音声ストリームに日本語、第2音声ストリームに英語が入る。

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', '5', '-y'];

// input 設定
Array.prototype.push.apply(args,['-i', input]);

Array.prototype.push.apply(args, ['-analyzeduration', analyzedurationSize, '-probesize', probesizeSize]);

// メタ情報
Array.prototype.push.apply(args,['-movflags', 'faststart']);

Array.prototype.push.apply(args,['-ignore_unknown']);

// コーデック等
Array.prototype.push.apply(args,[
    '-preset', preset,
    '-crf', crf,
    '-f', 'mp4']);

// ビデオストリームをマップ
Array.prototype.push.apply(args, ['-map', '0:v:0', '-max_muxing_queue_size', maxMuxingQueueSize]);

// ビデオコード関連
Array.prototype.push.apply(args, ['-aspect', '16:9', '-c:v', codec]);

// video filter 設定
let videoFilter = 'yadif';
if (videoHeight > 720) {
    videoFilter += ',scale=-2:720';
}
Array.prototype.push.apply(args, ['-vf', videoFilter]);

// 音声ストリームをマップ
Array.prototype.push.apply(args, ['-map', '0:a:0', '-map', '0:a:0', '-metadata:s:a:0', 'title=Japanese', '-metadata:s:a:0', 'language=jpn', '-metadata:s:a:1', 'title=English', '-metadata:s:a:1', 'language=eng']);

// 音声コード関連
Array.prototype.push.apply(args, ['-c:a:0', 'aac', '-c:a:1', 'aac', '-ar', '48000', '-ab', audioBitrate, '-ac', '2' ]);

// 出力先
Array.prototype.push.apply(args,[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-nhk_news-2audio_streams-cut5secs.js によるエンコード設定を組み込む
${HOME}/docker/docker-mirakurun-epgstation/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

   #### enc-bs_docu-cut4secs.js によるエンコード設定 ####
    - name: H.264-nhk_bs_docu-cut4secs
      cmd: '%NODE% %ROOT%/config/enc-bs_docu-cut4secs.js'
      suffix: .mp4
      rate: 4.0

   #### enc-nhk_news-cut4secs.js によるエンコード設定 ####
    - name: H.264-nhk_news-cut4secs
      cmd: '%NODE% %ROOT%/config/enc-nhk_news-cut4secs.js'
      suffix: .mp4
      rate: 4.0



(参考)デフォルトの ${HOME}/docker/docker-mirakurun-epgstation/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');
});


TV録画システム構築:PT2 TVチューナー & Docker版Mirakurun & Docker版MySQL & Docker版EPGStation (Xubuntu 24.04 , Debian 13 )

2026 Nov. 10.
2026 Sep. 19.
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カードリーダ、録画ファイル保存用ストレージを接続する。

この記事では、録画ファイル保存ストレージのパーティションを /dev/sdb1 とし、マウントポイントを /var/bigdata/02 とし、録画ファイル保存ディレクトリを /var/bigdata/02/video/epgstationYYMMDD とする。

$ sudo mkdir -p /var/bigdata/02
$ sudo chmod 755 /var/bigdata
$ sudo chmod 755 /var/bigdata/02


録画ファイル保存ストレージをマウントする設定を /etc/fstab に記述し、システムを再起動する。

/dev/sdb1 /var/bigdata/02 ext4 defaults 0 2


マウント状況を確認する。

$ mount | grep /var/bigdata/02


録画ファイル保存ディレクトリを作成する。
コンテナと共有するディレクトリの属性は 777 にする。

$ sudo mkdir -p /var/bigdata/02/video/epgstationYYMMDD/video
$ sudo mkdir /var/bigdata/02/video/epgstationYYMMDD/thumbnail
$ sudo chmod 755 /var/bigdata/02/video
$ sudo chmod 755 /var/bigdata/02/video/epgstationYYMMDD
$ sudo chmod 777 /var/bigdata/02/video/epgstationYYMMDD/video
$ sudo chmod 777 /var/bigdata/02/video/epgstationYYMMDD/thumbnail


TV録画・再生のユーザーとして tv ユーザー(ユーザー名は任意)を作成する。

$ sudo useradd -d /home/TVDIR -m -s /bin/bash -u USERID tv
$ sudo passwd tv


/etc/group ファイルを編集して、tvユーザーを他の一般ユーザーと同じように各グループに所属させる。
特に、sudoグループには必ず所属させる。

システムからログアウト、もしくはシステムを再起動する。

tvユーザーでログインする。


PT2アンテナ端子配置

  S1 BS (PCケース上蓋側)
  T1 地上
  S2 BS
  T2 地上 (マザーボード側)

ロケール、タイムゾーンを設定する

$ sudo apt update
$ sudo update-locale LANG=ja_JP.UTF-8
$ sudo timedatectl set-timezone Asia/Tokyo


時刻サーバーに同期させる


debian 13、ubuntu 24..04
次のリンク記事にしたがって設定する。
https://rasumus.hatenablog.com/entry/2026/09/14/072340

パッケージがインストールされていたら下記でもよい。

# /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 update && 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.


dvb-tools(TV受信コマンドdvbv5-zap)をインストール

$ 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


/etc/group ファイルを編集して、tvユーザーをdockerグループに所属させる。

/etc/groupの修正を反映するために、システム再起動もしくは再ログインする。
tvユーザーで再ログイン後、tvユーザーのdockerグループ所属を確認する。

$ groups tv
tv : tv adm cdrom sudo dip plugdev users lpadmin lxd docker


tvユーザーのホームディレクトリ内にdockerディレクトリを作成する

$ su - tv
$ mkdir ~/docker


Docker版mirakurun-epgstationをインストールする

「 GitHub - l3tnun/docker-mirakurun-epgstation: Mirakurun + EPGStation on Docker · GitHub 」を利用するが、cron組み込みなどのカスタマイズをするので、そこに書かれているインストール手順は実行しない。
下記の各コマンドを実行する。

$ cd ~/docker
$ git clone -b v3 https://github.com/l3tnun/docker-mirakurun-epgstation.git
$ cd 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. 共通ベースイメージ
########################################
ARG BASE_IMAGE=l3tnun/epgstation:master-debian


########################################
# 2. Build Stage: FFmpeg をコンパイル
########################################
FROM ${BASE_IMAGE} AS builder

ARG FFMPEGVERSION=7.0.1

ENV FFMPEGVERSION=${FFMPEGVERSION}

RUN set -eux; \
    apt-get update; \
    apt-get install -y --no-install-recommends \
      build-essential \
      gcc \
      g++ \
      make \
      git \
      automake \
      autoconf \
      curl \
      wget \
      pkg-config \
      yasm \
      nasm \
      texinfo \
      zlib1g-dev \
      ca-certificates \
      libx264-dev \
      libmp3lame-dev \
      libopus-dev \
      libvpx-dev \
      libass-dev \
      libfreetype6-dev \
      libtheora-dev \
      libtool \
      libva-dev \
      libvdpau-dev \
      libvorbis-dev \
      libnuma-dev \
      libaribb24-dev; \
    \
    mkdir -p /tmp/ffmpeg_sources; \
    cd /tmp/ffmpeg_sources; \
    curl -fsSL "https://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-libaribb24 \
      --disable-debug \
      --disable-doc; \
    \
    make -j"$(nproc)"; \
    make install; \
    \
    # ビルド時に必要な共有ライブラリを記録
    ldd /usr/local/bin/ffmpeg \
      | awk '/=> \// {print $3} /^[[:space:]]*\// {print $1}' \
      | sort -u > /tmp/ffmpeg-shared-libs; \
    \
    # 共有ライブラリを提供するDebianパッケージを特定
    while IFS= read -r lib; do \
      real_lib="$(readlink -f "$lib")"; \
      owner="$(dpkg-query -S "$real_lib" 2>/dev/null | head -n 1 || true)"; \
      if [ -z "$owner" ]; then \
        echo "共有ライブラリの所有パッケージを特定できません: $real_lib" >&2; \
        exit 1; \
      fi; \
      printf '%s\n' "$owner" \
        | sed -E 's/: .*//' \
        | sed -E 's/:.*//'; \
    done < /tmp/ffmpeg-shared-libs \
      | sort -u > /tmp/ffmpeg-runtime-packages; \
    \
    test -s /tmp/ffmpeg-runtime-packages; \
    \
    rm -rf /var/lib/apt/lists/* /tmp/ffmpeg_sources


########################################
# 3. Runtime Stage
########################################
FROM ${BASE_IMAGE}

ENV LANG=ja_JP.UTF-8 \
    TZ=Asia/Tokyo \
    DEBIAN_FRONTEND=noninteractive

# FFmpegの実行時依存パッケージ一覧
COPY --from=builder /tmp/ffmpeg-runtime-packages \
    /tmp/ffmpeg-runtime-packages

# ビルドしたFFmpegをコピー
COPY --from=builder /usr/local /usr/local

RUN set -eux; \
    apt-get update; \
    \
    # FFmpeg実行時に必要な共有ライブラリを導入
    xargs -r apt-get install -y --no-install-recommends \
      < /tmp/ffmpeg-runtime-packages; \
    \
    # その他の実行環境
    apt-get install -y --no-install-recommends \
      cron \
      locales \
      tzdata \
      procps \
      vim \
      less; \
    \
    # ライブラリ検索パスを設定
    echo "/usr/local/lib" > /etc/ld.so.conf.d/local-ffmpeg.conf; \
    ldconfig; \
    \
    # FFmpegの共有ライブラリ確認
    ldd /usr/local/bin/ffmpeg | tee /tmp/ffmpeg-ldd; \
    if grep -q "not found" /tmp/ffmpeg-ldd; then \
      echo "FFmpegの共有ライブラリが不足しています" >&2; \
      exit 1; \
    fi; \
    \
    # FFmpegの起動確認
    /usr/local/bin/ffmpeg -version; \
    \
    # x265への依存がないことを確認
    if readelf -d /usr/local/bin/ffmpeg | grep -q 'libx265'; then \
      echo "FFmpegにx265への依存があります" >&2; \
      exit 1; \
    fi; \
    \
    # 日本語ロケール設定
    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; \
    \
    # cronログ
    touch /var/log/cron.log; \
    chmod 0644 /var/log/cron.log; \
    \
    rm -f /tmp/ffmpeg-runtime-packages /tmp/ffmpeg-ldd; \
    apt-get clean; \
    rm -rf /var/lib/apt/lists/*


########################################
# 4. Entrypoint
########################################
COPY entrypoint.sh /entrypoint.sh

RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]


******************************
(旧my.Dockerfile。EPGStationがv3になった頃から下記ではffmpegエンコードができなくなった)

########################################
# 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"]

******************************

epgstationのcrontabディレクトリ作成

ホストのtvユーザーで、

$ mkdir ~/docker/docker-mirakurun-epgstation/epgstation/crontab
$ chmod 777 ~/docker/docker-mirakurun-epgstation/epgstation/crontab


ホストに共有ディレクトリを作成する。

Mirakurun
$ mkdir ~/docker/docker-mirakurun-epgstation/mirakurun/crontab  # コンテナのcron設定を保管する場所
$ chmod 777 ~/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 777 ~/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 777 ~/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


EPGStation v2からv3に伴う変更点は下記リンクページの「3. docker-compose.yml を更新する」にあり。
docker-mirakurun-epgstation/docs/migration.md at v3 · l3tnun/docker-mirakurun-epgstation · GitHub

~/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設定
* "- ./epgstation/thumbnail:/app/thumbnail"の:(コロン)の前は録画サムネイルファイル保存ディレクトリのパスにする。
* "- ./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:セクションにデータベース名・ユーザー名・パスワードを設定する。
  • ユーザー名、データベース名、ユーザーパスワードはepgstationとしておくのが無難。
      MYSQL_USER: epgstation
      MYSQL_PASSWORD: epgstation
      MYSQL_DATABASE: epgstation
  • MYSQL_ROOT_PASSWORD変数にMySQLのrootユーザーのパスワードを設定する。(デフォルトでは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の各コンテナの確実な連携

Docker Compose環境でのホスト名について

Docker Compose環境では、同じDockerネットワーク内に存在するコンテナ同士は、コンテナサービス名をホスト名として名前解決できるようになる。
そのため、コンテナ間の通信にはサービス名を使用する。
EPGStationのコンテナから見て、Mirakurunのコンテナは mirakurun というサービス名で稼働している。
Dockerコンテナにおける localhost はコンテナ自身を指す。
もし "http://localhost:40772" と指定してしまうと、EPGStationコンテナ自身の中でポート 40772 を探してしまうため、Mirakurunと通信ができずエラーになってしまう。

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する。

$ cd ~/docker/docker-mirakurun-epgstation
$ docker compose run --rm -e SETUP=true mirakurun


Mirakurunの tuners.yml は ~/docker/docker-mirakurun-epgstation/mirakurun/conf/ に自動作成されるので、作業不要。



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内の情報(予約情報・録画情報等)等、コンテナ内のデータは削除される。
録画ファイル・サムネイルファイルはホスト共有ディレクトリに保存していない限り削除される。

手順
  • コンテナを終了・ボリュームを削除する。
    $ cd ~/docker/docker-mirakurun-epgstation
    $ docker compose down -v

  • 設定変更作業を行う。

  • コンテナを起動する。
    $ docker compose up -d

    ブラウザのキャッシュを削除し、ブラウザのページを"Ctrl + Shift + R"でハードリロードする。

    Dockerfileを修正する場合

    コンテナを再構築して、再起動する。

    要注意
    mysql内の情報(予約情報・録画情報等)等、コンテナ内のデータは削除される。
    録画ファイル・サムネイルファイルはコンテナ外に保存していない限り削除される。

    手順
  • コンテナを終了・ボリュームを削除する。
    $ cd ~/docker/docker-mirakurun-epgstation
    $ docker compose down -v

  • 設定変更作業を行う。

  • イメージ取得・ビルド・コンテナ起動を行う。
    $ docker compose build --pull
    $ docker compose up -d
    ブラウザのキャッシュを削除し、ブラウザのページを"Ctrl + Shift + R"でハードリロードする。

"--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ファイルで定義されたサービスのコンテナを強制的に削除する。このコマンドを実行すると、実行中のコンテナを強制的に停止し、その後削除する。ボリュームデータは削除されない。つまり、関連するコンテナが削除されるが、ボリュームデータは残る。

コンテナの完全削除

$ cd ~/docker/docker-mirakurun-epgstation
$ docker compose down --volumes
$ docker image prune -a
$ docker system prune -a --volumes


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

ICカードリーダーライタSCR3310-NTTComをxubuntuにインストール

2026 Nov. 08.
2026 Sep. 15.
2026 Mar. 01.
2024 Jan. 03.
2023 Dec. 31.

ICカードリーダー接続をPCが認識していることを確認

$ lsusb
Bus 001 Device 002: ID 04e6:511a SCM Microsystems, Inc. SCR3310-NTTCom USB SmartCard Reader


カードリーダー用ソフトをインストール

参考ページ 録画サーバーOS更新

$ sudo apt update && sudo apt install pcscd pcsc-tools libpcsclite-dev
$ systemctl status pcscd.socket

(期待される出力例)
● pcscd.socket - PC/SC Smart Card Daemon Activation Socket
     Loaded: loaded (/lib/systemd/system/pcscd.socket; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2023-10-29 10:49:13 JST; 18s ago
   Triggers: ● pcscd.service
     Listen: /run/pcscd/pcscd.comm (Stream)
     CGroup: /system.slice/pcscd.socket

 (pcscdが動作していなかったら)
  $ sudo systemctl restart pcscd.socket

カードリーダーにカードの裏面を上にしてB-CASカードを挿入し、動作確認する。
$ pcsc_scan
 次の出力があれば成功
  Japanese Chijou Digital B-CAS Card (pay TV)


トラブル対応

pcsc_scanコマンド実行に失敗し、次のエラーとなったら
$ pcsc_scan
PC/SC device scanner
V 1.7.3 (c) 2001-2024, Ludovic Rousseau <ludovic.rousseau@free.fr>
SCardEstablishContext: Access denied.

/etc/default/pcscd ファイルに次の1行を記述し、pcscd.serviceを再起動する。
PCSCD_ARGS="--disable-polkit"

サービス再起動と確認

$ sudo systemctl restart pcscd.service
$ systemctl status pcscd.service
$ pcsc_scan


下記状況となった時に、ICカードリーダーを接続するUSB端子を変更したら、正常に動作した。
$ pcsc_scan
PC/SC device scanner
V 1.7.4 (c) 2001-2026, Ludovic Rousseau <ludovic.rousseau@free.fr>
Using reader plug'n play mechanism
Scanning present readers...
Waiting for the first reader...   


debian 13、xubuntu 26.04 : 自動時刻合わせ設定

2026 Nov. 08.
2026 Sep. 14.

時刻のズレの自動修正設定。

時刻同期の状態確認(NTPサービスが有効になっているか確認する)

$ timedatectl status
               Local time: 金 2026-09-11 19:43:18 JST
           Universal time: 金 2026-09-11 10:43:18 UTC
                 RTC time: 金 2026-09-11 19:43:18
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: no
              NTP service: n/a
          RTC in local TZ: yes

自動化設定ができている時の出力は次となる。
NTP service: active
System clock synchronized: yes
RTC in local TZ: no


NTPによる時刻自動同期の有効化作業

システムクロックを同期するためのバックエンドサービスの稼働状況確認

$ sudo timedatectl set-ntp true
Failed to set ntp: NTP not supported 

システムクロックを同期するためのバックエンドサービス(systemd-timesyncd など)がシステムにインストールされていないか、有効化されていない。

必要なパッケージをインストールし、サービスを有効化する。

$ sudo apt update
$ sudo apt install systemd-timesyncd


自動同期サービスを有効にして起動する。

$ sudo systemctl enable --now systemd-timesyncd


systemd-timesyncdがactive (running) になっていることを確認する。

$ sudo systemctl status systemd-timesyncd


timedatectl を使って同期を有効にする。

$ sudo timedatectl set-ntp true


設定が正しく反映されたかを以下のコマンドで確認する。

$ timedatectl status
Local time: 金 2026-09-11 19:55:12 JST
Universal time: 金 2026-09-11 10:55:12 UTC
RTC time: 金 2026-09-11 19:47:47
Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
NTP service: active
RTC in local TZ: yes 

System clock synchronized: yes および NTP service: active となっており、自動時刻同期が正常に機能していた。
一方、"RTC in local TZ: yes" となっているのでハードウェア時計(RTC)をローカル時間(日本時間)として扱っている。
LinuxシステムではRTCをUTC(協定世界時)に設定することが標準的で、ここが yes のままだと、将来的にOS間のデュアルブートなどで時刻のズレが生じる原因になることがある。
標準的な UTC に修正する。

$ sudo timedatectl set-local-rtc 0


確認。

 $ timedatectl status

ubuntu系linuxインストール

2026 Nov. 08.
2026 Sep. 22.
2026 May 03.
2026 Feb. 25.
2025 Nov. 03.
2025 Oct. 12.
2025 Sep. 15.
2025 Aug. 30.
2025 Feb. 08.
2024 Sep. 24.
2024 May. 01.
2024 Apr. 28.
2023 May 03.
2022 Sep. 10.
2022 Feb. 08.
2021 May 19.
2021 Apr. 24.
2021 Mar. 29.
2021 Feb. 27.
2021 Jan. 31.
2020 Oct. 17.
2020 Sep. 26.
2020 Aug. 15.
2019 Oct. 14.
2019 Jan. 04.
2018 Dec. 01.
2018 Nov. 04.
2018 Oct. 14.
2018 Aug. 13.
 
前提

PCの基本設定機構はレガシーBIOSではなくUEFIとする。

起動ドライブはレガシーMBRタイプではなくGPTタイプとする。

インストールUSBメモリの準備

下記リンクの記事を参考にして、Balena-Etcherでインストール用のUSBメモリを作成する。

Balena-Etcherはパーティション構造を自動判別し、イメージのセクターをそのまま書き込む。近年の一般的なLinuxディストリビューション(Ubuntu, Debian, Fedoraなど)の公式ISOはハイブリッドISO(UEFI bootとLegacy BIOS bootの両方のブートローダを内包した構造)になっているため、どちらのPC環境でもそのまま起動できるよう自動処理される。

 
ストレージの準備
GPTタイプの起動ディスクを用意する。
下記の記事を参考にして、起動ディスクのパーティション(EFI System Partition / ESPパーティション)を準備する。
 
インストール先の/home内のユーザーディレクトリ名が既存ディレクトリ名と重ならないようにする。
 
PCをUEFIドライブからbootさせる設定
PC基本設定 -> Boot -> Boot Drive Priority -> 1st Boot Device -> UEFI Hard Disk : Ubuntu
PC基本設定 -> Boot -> UEFI Hard Disk Drive -> 1st Boot Device -> Ubuntu
 
インストール
USBメモリ/DVDからlinuxディストリビューションをインストールする。
PCのbootドライブ設定とUEFI Disk Drive設定はUEFIタイプとする。

 
インストール時にセットするユーザーにはUIDを指定できないので、ユーザー名は仮のものとして適当なものにする。
 
 

インストールメディアをLegacy BIOSモードで読み込むべきか、UEFIモードで読み込むべきかを決める手順。

(1)GParted等でLinuxをライブ起動する。
(2)インストール先ストレージがUEFIモードとなっているか、BIOSモードとなっているか、次のコマンドで確認する。
    $ sudo parted /dev/sda print
      「Partition Table: gpt」ならUEFIモード。
      「Partition Table: msdos」ならBIOSモード。
(3)ブートモードがUEFIモードとなっているか、BIOSモードとなっているか、次のコマンドで確認する。
    $ [ -d /sys/firmware/efi ] && echo "UEFIモード" || echo "BIOSモード"
(4)PCのBIOS設定/UEFI設定/ブートドライブ設定等で、ブートモードをインストール先ストレージのモードと一致させる。

 
 
UEFIシステム・GPTドライブでのディスクパーティションについて
300MB程度のEFI System Partition (ESP)がディスクに存在していなければ、vfatで作成・フォーマットする。
既にESPが存在していれば、再フォーマットせず、必ずそのまま残しておく。
通常はシステムが自動で処理するが、Linuxインストール作業時に指定可能な時はESPパーティションのマウントポイントを /boot/efi とする。
 
 
video card対応
nvidia video chipならば次のリンクを参照する。
  (nvidia-driver-390とか)
 
/etc/fstab設定
フィールド書式
file-system  dir  type  options  dump  pass
 
passフィールドについて
起動時にfsckがチェックする順番。0,1または2を設定できる。
1 はチェックの優先度が一番高い。ルートファイルシステム(/)には1を指定する。
2 はその他のローカルファイルシステムに指定する。
0 のファイルシステムはチェックされない。スワップ、仮想ファイルシステム、ネットワークファイルシステム、リムーバブルメディアなどに指定する。
 
 NFSファイルシステムのマウント設定
 
 ntfsファイルシステムのマウント設定
 
ユーザを追加・設定
最初のユーザーを登録し、所属するグループはインストール時のユーザーと同じにする。
ユーザーのパスワード設定を行う。
 
起動時NumLock設定
 
Xfceパネルに「通知プラグイン」を追加

パネルの何もない場所を右クリックし、「パネル」>「パネルの設定」を開く。「アイテム」タブの「+」ボタンを押し、「通知プラグイン (Notification Plugin)」を追加すると、いつでも履歴にアクセスできるようになる。

 
Xfce2 マウスフォーカス設定
設定 -> ウィンドウマネージャー ->
フォーカス -> フォーカスで前面に出す ->
「ウィンドウがフォーカスを取得した場合自動的に前面に出す」のチェックを外す。
 
設定 -> ウィンドウマネージャー ->
フォーカス -> クリックで前面に出す ->
「アプリケーションウィンドウ内でクリックした場合前面に出す」のチェックを外す。
 
Firefoxは、「ツールバーをカスタマイズ」で「タイトルバーを表示する」設定にしないとXubuntuデスクトップ設定に従わない。
 
画面解像度変更
 
ユーザーのumask設定 umask 0022
セキュリティ性の高い"umask 0077"としたユーザーでビルドしたプログラムをシステムにインストールすると、システム上のディレクトリ・ファイルをrootユーザー以外が読み込めない恐れがあるので、"umask 0022"がよい。
~/.profileファイルに書き込んでおく。
 
ログイン時設定ファイル読み込みの仕組み確認
 
パス設定
 
固定IPアドレス設定
 
/etc/hostsを設定する。

/etc/hosts修正のシステムへの反映は即時になされる。

下記コマンドでキャッシュのクリアをしておく。

$ sudo resolvectl flush-caches

 

TCP Wrapperは使用されていないので /etc/hosts.deny /etc/hosts.allow の設定は不要

 


時刻合わせ
 

buildツールのインストール

$ sudo apt update && sudo apt install build-essential
 
 
 
FirefoxでのGeminiのチャットページ画面で上下スクロールバーが表示されるようにする。(Firefoxの「隠し設定」でスクロールバーを強制する)
  • FirefoxのURLバーに about:config と入力してEnterキーを押す。

  • 注意画面が出るが、「危険を承知で続行」を選択する。

  • 検索窓に widget.non-native-theme.scrollbar.style と入力する。

  • 右側の鉛筆アイコンをクリックして、値を 4 に書き換えてチェックマーク(保存)を押す。(0がデフォルト)

    • 4はシステム標準(Linux/GTK)のスタイルを強制する設定。

  • ページを再読み込み(F5)して確認する。

 
wake-on-lan設定
 
 
nfsクライアントインストール
参照先:NFSクライアント設定 - rokkonet
 
nfsサーバーインストール
参照先: nfs server 
 
sshサーバーインストール 鍵生成・配置
 
ルーター設定 外部からのsshパケットをsshサーバーホストに転送させる
 
 

OpenVPNインストール

 参照先
  OpenVPNインストール ルーティング方式 Easy-RSA3利用、TLS認証あり版 - rokkonet

  OpenVPNのインストールとセットアップからインターネット接続までのガイドブック - Qiita

 

LAN外からのopenvpnクライアントパケットがホストに転送されるようにルーターを設定する。

 

 
sambaインストール
 
 
TV録画・視聴システム

 

TVストリーム分離ツール tssplitter_liteインストール(ffmpegでできるので不要)
  

( pt2・recpt1インストール ) Mirakurun + EPGStationなら不要

( epgrec_unaインストール  ) Mirakurun + EPGStationなら不要
 
 
( TV録画ファイル定期圧縮 epgrec版)
 
( TV録画番組内容ファイル定期作成 epgrec版)
 
 
データベースシステムをインストール
  ( 旧版  mysqlインストール )
  
rubyインストール
  
 
bitbucket利用対応
gitインストール
  $ sudo apt update && sudo apt install git

bitbucket設定
  リポジトリディレクトリを置くディレクトリの作成
   $ mkdir ~/bitbucket

  SSH認証設定
 

 

 
anti-virusソフトインストール
 
プリンター・スキャナー インストール

mailインストール
 
javaインストール
 
sinatraインストール・設定
 
googleドライブ同期設定
・ローカルファイルとの同期

  grive2が扱いやすいが、google認証できない状況。
 
 ・googleドライブのマウント
 
mysqlデータ移行
 
mysqlデータベース定期バックアップ
 
他ファイルサーバーデータ移行
 
no-ipアップデートデーモンインストール
  
 
PT2テレビチューナーカード接続エラー定期メール通知
 
 
システムからのメールの保存量に制限を設定する
 
rootユーザーcron設定
一般ユーザーcron設定
 
( epgrecエラーログ定期メール通知 )
 

systemd機構の"systemctl enable HOGE.service"と"systemctl daemon-reload"の機能

2026 Nov. 05.

$ sudo systemctl enable [ --now ] HOGE.service

システム起動時(ブート時)にそのサービスが自動で立ち上がるよう設定する。
"--now"オプション:
「今すぐ(コマンドを実行したタイミングで)」そのサービスを起動する。
"--now"オプション無しで実行してもサービスはすぐに起動せず、別途 systemctl start を実行する必要がある。
しかし --now オプションを付与することで、「自動起動設定の有効化」と「即時起動」を1回のコマンドで同時に完了させることができる。

systemctl is-enabled HOGE.service

自動起動の有効・無効だけを確認できる。
出力結果:
enabled: 自動起動が有効に設定されている。
disabled: 自動起動が無効に設定されている。
static: この設定を持つユニットファイルではなく、他の仕組みで制御されている場合などに表示される。

$ sudo systemctl daemon-reload

systemdマネージャーに対し、ディスク上に保存されているユニットファイル(.service ファイルなど)の変更を再読み込みさせる。
/etc/systemd/system/HOGE.service などのファイルを直接編集・保存しても、systemdはその変更を自動では認識しない。
daemon-reload を実行することで、変更された設定ファイルをsystemdに再認識させる。
サービスファイルの内容を書き換えたときや新しくサービスファイルを自作して配置したときに実行する。
パッケージマネージャー経由でインストールした場合は、通常、パッケージのインストーラーが、インストールやアップデートの処理の中で自動的に daemon-reload や適切な有効化・起動処理を実行してくれるので、"systemctl daemon-reload"の実行は不要。

sambaインストール

2026 Nov. 04.

2026 Sep. 13.

2026 Mar. 17.
2025 Sep. 24.

2025 Aug. 29.

2024 Jan. 21.

2021 May 02.

2021 Apr. 30.

2021 Mar. 28.

2021 Jan. 31. 

2020 Sep. 28.

2020 Jan. 19.

2017 Feb. 11.

インストール

$ sudo apt update && sudo apt install samba
 

ポート開放

(複数ポートをまとめて設定可能)

$ sudo ufw enable

$ sudo ufw allow from YOUR.NETWORK.ADDRESS.0/24 to any app Samba

(例) sudo ufw allow from 192.168.1.0/24 to any app Samba

$ sudo ufw reload

 

(個別設定する場合)

$ sudo ufw enable

$ sudo ufw allow proto udp from YOUR.NETWORK.ADDRESS.0/24 to any port 137

$ sudo ufw allow proto udp from YOUR.NETWORK.ADDRESS.0/24 to any port 138

$ sudo ufw allow proto tcp from YOUR.NETWORK.ADDRESS.0/24 to any port 139

$ sudo ufw allow proto tcp from YOUR.NETWORK.ADDRESS.0/24 to any port 445

$ sudo ufw reload

 

(Chat GPT情報)

Sambaは通常、以下のポートを使用します。

    TCP 139: NetBIOSセッションサービス
    TCP 445: Microsoft-DSサービス
    UDP 137: NetBIOSネームサービス
    UDP 138: NetBIOSデータグラムサービス

これらのポートは、SambaがWindowsファイルおよびプリンタ共有を提供するために使用されます。ただし、特にセキュリティ上の理由から、TCP 445が最も一般的に使用されるポートです。したがって、多くの場合、SambaサーバーへのアクセスはTCP 445ポートを介して行われます。

ただし、ネットワーク環境や設定によっては、他のポートも使用されることがあります。特にUDP 137とUDP 138は、NetBIOSネームサービスとデータグラムサービスに関連しており、ネームリゾルバやブラウジングに使用されることがあります。

したがって、必要に応じてこれらのポートをファイアウォールやセキュリティグループで適切に設定することが重要です。ネットワーク構成によっては、TCP 445だけでなく、他のポートも許可する必要があるかもしれません。

 

OpenVPN経由での接続のためのポート開放

https://rasumus.hatenablog.com/entry/2018/05/26/103300

 

設定( /etc/samba/smb.conf)

Arch系のManjaro Linuxでは/etc/sambaは存在するものの、設定ファイルはなく、manjaro-settings-samba をインストールすると/etc/samba/smb.confが置かれる。

 

Debian、Ubuntuではsambaをインストールすると/etc/samba/smb.confが置かれる。

 

global設定

[global]
wide links = yes
unix extensions = no
security = user
map to guest = never
browseable = yes
load printers = no
disable spoolss = yes
 
## "disable netbios = yes"があれば無効化する。
# disable netbios = yes
 
 

homeディレクトリ公開

[homes]
   comment = Home Directories
   browseable = no
   guest ok = no
   read only = no
   create mask = 0644
   directory mask = 0755
   writable = yes
   valid users = %S

 

任意のディレクトリ公開

[SOME-DIR]
   path = /SOME/DIR
   browseable = yes
   read only = no
   writable = yes
   guest ok = no
   valid users = USER1,USER2
   create mask = 0644
   directory mask = 0755
   acl_xattr:ignore system acls = no
 
 
 
[ptint$] セクションと [printers] セクションは不要なので、すべてコメントアウトする。
 
 

設定メモ

browseable = no
 ファイラーに表示するには[global]セクションで browseable = yes とする
 
writable = yes
  読み書き・削除を可能にする
 

"guest ok = no"と"public = no"は同じなので。どちらかの指定でよい。

"guest ok= no"と"map to guest = never"は効果が重なるため、どちらかの指定でよい。

 

printer関連

sambaクライアントでsambaサーバーを通じて印刷を行わないなら、[ptint$] と [printers] の設定は不要。
 

シンボリックリンクの読み込み

[global]
wide links = yes
unix extensions = no
 

ユーザー 認証

[global]
security = user
map to guest = never
 
 

クライアント端末に公開ディレクトリを表示する

[global]
browseable = yes
 

プリンターをクライアントに表示しない

[global]
load printers = no
disable spoolss = yes

sambaクライアントからsambaサーバーを介したネットワークプリンタ利用をしない

[print$]セクションをすべてコメントアウトもしくは削除する。

システムのunix/linuxアカウントのパスワードとSambaユーザーアカウントのパスワードの同期

下記の設定であるが、sambaインストール時にデフォルト設定されていた。
 
(smb.conf設定)
unix password sync = yes
passwd program = /usr/bin/passwd %u
passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
 
上記3行の設定により、unix password syncパラメータを「yes」に設定することで、Sambaパスワードが変更されるタイミングでUNIXのパスワード変更コマンドを起動することができる。
 
 
smb.confの構文チェック
$ testparm
 
​オプションなしで testparm コマンドを実行した場合、カレントディレクトリの位置に関わらず、システム上のデフォルトのパスにある設定ファイル(通常は /etc/samba/smb.conf)を自動的に探し出して構文チェックを行う。
エラーが表示されず設定が正しく読み込まれていれば成功。
 
 

samba再起動(設定読込)

$ sudo systemctl restart smbd.service
$ sudo systemctl restart nmbd.service

 

unix/linuxユーザーの登録

( www.atmarkit.co.jp/ait/articles/0901/28/news153.html より)
$ sudo pdbedit -a USER  // パスワード登録も求められる。

 

パスワード変更

ログイン中のユーザーのパスワード変更
$ smbpasswd
  "unix password sync = yes" ならlinxu/unixシステムのユーザーパスワードも変更される。
 
他のユーザーのパスワード変更
$ smbpasswd USER
  "unix password sync = yes" ならlinxu/unixシステムのユーザーパスワードも変更される。

"guest ok ="の意味

Sambaサーバにアカウントを持たないユーザーがアクセスした場合に、それを特定のUNIXアカウント(ゲストアカウント)にマッピングしてアクセスを許可する設定。
yes : ゲストアカウントでのアクセスを許可する。public = yesとしても同じ。


"guest account ="の値で特定の UNIXアカウントに指定する。

"map to guest ="で、 Sambaユーザーとして存在しないユーザーがアクセスした場合にゲストアカウントとして扱う設定にする。
"map to guest =" の値
 never : 不正なパスワードによるユーザーのログイン要求を拒否する。
 bad User: 不正なパスワードによるユーザーのログイン要求を拒否するが、指定されたユーザーが存在しなかった場合はゲストログインとして扱う。この場合、guest accountで指定したユーザーとなる。
 Bad Password : 不正なパスワードによるユーザーのログイン要求はゲストユーザーとして扱う。この場合、guest accountで指定したユーザーとなる。

samba関連ポート

 
通信目的          samba側の待受ポート 接続元のポート
名前登録など        137/udp        137/udp
ブラウジングなど      138/udp        138/udp
ファイル / 印刷サービスなど 139/tcp         Hi/tcp
ファイル / 印刷サービスなど (Direct Hosting of SMB)
              445/tcp         Hi/tcp
 

137/udp と 138/udp は UDP のため、基本的に双方向に通過可能にする必要がありますが、それではセキュリティが低下してしまいます。

実は、この 2つが存在しない場合でも、139/tcp(もしくは 445/tcp)が通過できればファイル / 印刷サービスは提供できます。

ただし、139/tcp のみを通過可能にした場合は、ブラウジング機能が動作しないため、Samba マシンのアイコンは「ネットワークコンピュータ」上に表示されません。

TCP 139 NetBIOS

参考元 https://ja.play-and-more.com/5251-smb-port-what-is-port-445-port-139-used-for

    第4回 WindowsネットワークとNetBIOS:Windowsネットワークの基礎 - @IT

Windowsネットワークの基本的なプロトコル。

NetBIOS名を使用して互いの位置を特定し、識別します。 NetBIOS名は最大16文字で、通常はコンピュータ名とは別の名前です。

ドメイン、ワークグループ、システム名、アカウント情報など、あらゆる種類の情報はNetBIOS経由で入手できます。

 

再チェック! ファイル共有プロトコル「SMB」のためのセキュリティ対策 (2/2):山市良のうぃんどうず日記(83) - @IT より

TCP 137  NETBIOS Name Service(netbios-ns) 

138/UDP NETBIOS Datagram Service(netbios-dgm)
139/TCP NETBIOS Session Service(netbios-ssn)
445/TCP Direct Hosting of SMB(microsoft-ds)