Skip to content

Instantly share code, notes, and snippets.

@uru2
Last active June 5, 2024 05:06
Show Gist options
  • Save uru2/7f738d864c2789b35c35e6bb7be9d0cb to your computer and use it in GitHub Desktop.
Save uru2/7f738d864c2789b35c35e6bb7be9d0cb to your computer and use it in GitHub Desktop.
docker mirakcコンテナーを利用したmirakc用チャンネルスキャン
#!/bin/sh
# mirakc channel scan (using mirakc docker container image)
# by uru (https://twitter.com/uru_2)
#
# require:
# docker
# jq
set -eu
export LANG=C.UTF-8
readonly EXTRACT_SID="${EXTRACT_SID:-0}"
readonly OUTPUT_FILE='mirakc_channels.yml'
# use container image
# https://hub.docker.com/r/mirakc/mirakc/tags
readonly CONTAINER_IMAGE='docker.io/mirakc/mirakc:latest'
#readonly CONTAINER_IMAGE='cust_image_mirakc_alpine'
# tuner device mapping for container
# if empty setting, then skip channel scan
# see: https://docs.docker.com/engine/reference/commandline/run/#add-host-device-to-container---device
readonly DEVICE_MAP_GR='/dev/px4video2:/dev/px4video2'
readonly DEVICE_MAP_BS='/dev/px4video0:/dev/px4video0'
readonly DEVICE_MAP_CS='/dev/px4video0:/dev/px4video0'
#readonly DEVICE_MAP_GR='/dev/dvb:/dev/dvb'
# record command template
# must be ts stream output to stdout
# if empty setting, then skip channel scan
# <channel> : channel
readonly RECORD_COMMAND_GR='recpt1 --device /dev/px4video2 <channel> 10 -'
readonly RECORD_COMMAND_BS='recpt1 --device /dev/px4video0 --lnb 15 <channel> 20 -'
readonly RECORD_COMMAND_CS='recpt1 --device /dev/px4video0 --lnb 15 <channel> 10 -'
#readonly RECORD_COMMAND_GR='dvbv5-zap -a 0 -c /usr/local/etc/dvbv5/channels/isdb/dvbv5_channels_isdbt.conf -s -r -P <channel> -t 10 -o -'
# scan target channels: GR
CHANNELS_GR="$(cat << EOT
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
C13
C14
C15
C16
C17
C18
C19
C20
C21
C22
C23
C24
C25
C26
C27
C28
C29
C30
C31
C32
C33
C34
C35
C36
C37
C38
C39
C40
C41
C42
C43
C44
C45
C46
C47
C48
C49
C50
C51
C52
C53
C54
C55
C56
C57
C58
C59
C60
C61
C62
C63
EOT
)"
readonly CHANNELS_GR=$(echo "${CHANNELS_GR}" | grep -e '^[^#]')
# scan target channels: BS
CHANNELS_BS="$(cat << EOT
BS01_0
BS01_1
BS01_2
BS01_3
#BS01_4
#BS01_5
#BS01_6
#BS01_7
BS03_0
BS03_1
BS03_2
BS03_3
#BS03_4
#BS03_5
#BS03_6
#BS03_7
BS05_0
BS05_1
BS05_2
BS05_3
#BS05_4
#BS05_5
#BS05_6
#BS05_7
#BS07_0
#BS07_1
#BS07_2
#BS07_3
#BS07_4
#BS07_5
#BS07_6
#BS07_7
BS09_0
BS09_1
BS09_2
BS09_3
#BS09_4
#BS09_5
#BS09_6
#BS09_7
BS11_0
BS11_1
BS11_2
BS11_3
#BS11_4
#BS11_5
#BS11_6
#BS11_7
BS13_0
BS13_1
BS13_2
BS13_3
#BS13_4
#BS13_5
#BS13_6
#BS13_7
BS15_0
BS15_1
BS15_2
BS15_3
#BS15_4
#BS15_5
#BS15_6
#BS15_7
#BS17_0
#BS17_1
#BS17_2
#BS17_3
#BS17_4
#BS17_5
#BS17_6
#BS17_7
BS19_0
BS19_1
BS19_2
BS19_3
#BS19_4
#BS19_5
#BS19_6
#BS19_7
BS21_0
BS21_1
BS21_2
BS21_3
#BS21_4
#BS21_5
#BS21_6
#BS21_7
BS23_0
BS23_1
BS23_2
BS23_3
#BS23_4
#BS23_5
#BS23_6
#BS23_7
EOT
)"
readonly CHANNELS_BS=$(echo "${CHANNELS_BS}" | grep -e '^[^#]')
# scan target channels: CS
CHANNELS_CS="$(cat << EOT
CS2
CS4
CS6
CS8
CS10
CS12
CS14
CS16
CS18
CS20
CS22
CS24
EOT
)"
readonly CHANNELS_CS=$(echo "${CHANNELS_CS}" | grep -e '^[^#]')
# find require tools
if [ ! "$(which docker)" ]; then
echo 'require docker' >&2
return 1
fi
if [ ! "$(which jq)" ]; then
echo 'require jq' >&2
return 1
fi
all_lists=''
# scan GR
if [ -n "${DEVICE_MAP_GR}" ] && [ -n "${RECORD_COMMAND_GR}" ]; then
list=''
type='GR'
channels="${CHANNELS_GR}"
cmd_base="${RECORD_COMMAND_GR}"
dev_map="${DEVICE_MAP_GR}"
for ch in ${channels}; do
echo "[type: ${type}, channel: ${ch}]" >&2
# generate record command
rec_cmd="$(echo "${cmd_base}" | sed -e "s/<channel>/${ch}/")"
# execute command
json=$(docker run --rm "--device=${dev_map}" --entrypoint= -it "${CONTAINER_IMAGE}" sh -c "${rec_cmd} 2> /dev/null | /usr/local/bin/mirakc-arib scan-services 2> /dev/null" \
| jq -M -c || printf '')
if [ -z "${json}" ]; then
continue
fi
# extract .name (first service only)
sname=$(echo "${json}" | jq -M -r '.[0] | .name')
# extract all service .sid
sid=$(echo "${json}" | jq -M -r '.[] | .sid' | jq -M -s . | jq -M -r 'join(",")')
list=$(printf '%s\n%s\t%s\t%s\t%s' "${list}" "${type}" "${ch}" "${sname}" "${sid}" | sed '/^$/d')
done
# append all lists
if [ -n "${list}" ]; then
all_lists=$(printf '%s\n%s' "${all_lists}" "${list}" | sed '/^$/d')
fi
fi
# scan BS
if [ -n "${DEVICE_MAP_BS}" ] && [ -n "${RECORD_COMMAND_BS}" ]; then
list=''
type='BS'
channels="${CHANNELS_BS}"
cmd_base="${RECORD_COMMAND_BS}"
dev_map="${DEVICE_MAP_BS}"
for ch in ${channels}; do
echo "[type: ${type}, channel: ${ch}]" >&2
# generate record command
rec_cmd="$(echo "${cmd_base}" | sed -e "s/<channel>/${ch}/")"
# execute command
json=$(docker run --rm "--device=${dev_map}" --entrypoint= -it "${CONTAINER_IMAGE}" sh -c "${rec_cmd} 2> /dev/null | /usr/local/bin/mirakc-arib scan-services 2> /dev/null" \
| jq -M -c || printf '')
if [ -z "${json}" ]; then
continue
fi
# extract .name (first service only)
sname=$(echo "${json}" | jq -M -r '.[0] | .name')
# extract all service .sid
sid=$(echo "${json}" | jq -M -r '.[] | .sid' | jq -M -s . | jq -M -r 'join(",")')
# duplicate sid skip
# (may return first slot(=slot 0) information, if slot not used)
append='1'
if [ -n "${list}" ]; then
for line in ${list}; do
line_sid=$(echo "${line}" | cut -f 4)
if [ "${line_sid}" = "${sid}" ]; then
append='0'
break
fi
done
fi
if [ "${append}" = '0' ]; then
continue
fi
list=$(printf '%s\n%s\t%s\t%s\t%s' "${list}" "${type}" "${ch}" "${sname}" "${sid}" | sed '/^$/d')
done
# append all lists
if [ -n "${list}" ]; then
all_lists=$(printf '%s\n%s' "${all_lists}" "${list}" | sed '/^$/d')
fi
fi
# scan CS
if [ -n "${DEVICE_MAP_CS}" ] && [ -n "${RECORD_COMMAND_CS}" ]; then
list=''
type='CS'
channels="${CHANNELS_CS}"
cmd_base="${RECORD_COMMAND_CS}"
dev_map="${DEVICE_MAP_CS}"
for ch in ${channels}; do
echo "[type: ${type}, channel: ${ch}]" >&2
# generate record command
rec_cmd="$(echo "${cmd_base}" | sed -e "s/<channel>/${ch}/")"
# execute command
json=$(docker run --rm "--device=${dev_map}" --entrypoint= -it "${CONTAINER_IMAGE}" sh -c "${rec_cmd} 2> /dev/null | /usr/local/bin/mirakc-arib scan-services 2> /dev/null" \
| jq -M -c || printf '')
if [ -z "${json}" ]; then
continue
fi
if [ "${EXTRACT_SID}" = "1" ]; then
# each all services
for i in $(awk "BEGIN { for (i = 0; i < $(echo "${json}" | jq -M -r 'length'); i++) { print i } }"); do
service_json=$(echo "${json}" | jq -M -c ".[${i}]")
# extract .name
sname=$(echo "${service_json}" | jq -M -r '.name')
# extract .sid
sid=$(echo "${service_json}" | jq -M -r '.sid')
list=$(printf '%s\n%s\t%s\t%s\t%s' "${list}" "${type}" "${ch}" "${sname}" "${sid}" | sed '/^$/d')
done
else
# service name = channel
sname="${ch}"
# extract all service .sid
sid=$(echo "${json}" | jq -M -r '.[] | .sid' | jq -M -s . | jq -M -r 'join(",")')
list=$(printf '%s\n%s\t%s\t%s\t%s' "${list}" "${type}" "${ch}" "${sname}" "${sid}" | sed '/^$/d')
fi
done
# append all lists
if [ -n "${list}" ]; then
all_lists=$(printf '%s\n%s' "${all_lists}" "${list}" | sed '/^$/d')
fi
fi
# generate mirakc channels configuration
# see: https://github.com/mirakc/mirakc/blob/release/docs/config.md#channels
if [ -n "${all_lists}" ]; then
echo 'channels:' > "${OUTPUT_FILE}"
echo "${all_lists}" | awk -F "\t" -v "EXTRACT_SID=${EXTRACT_SID}" '
{
printf(" - name: '\''%s'\''\n", $3);
printf(" type: '\''%s'\''\n", $1);
printf(" channel: '\''%s'\''\n", $2);
printf(" extra-args: '\'''\''\n");
if (EXTRACT_SID == "1") {
printf(" services: [%s]\n", $4);
}
printf(" disabled: false\n");
printf("\n");
}' >> "${OUTPUT_FILE}"
fi
echo "channel scan finished, output to ${OUTPUT_FILE}" >&2
return 0
@uru2
Copy link
Author

uru2 commented Aug 24, 2022

mirakcは基本的にdockerなどのコンテナー実行を推奨しているのでそのイメージを使ってチャンネルスキャンファイルを出力するようにした
実行ディレクトリに mirakc_channels.yml を生成するのでこの内容を組み込む
なおこの設定では実行には25分ぐらいかかる

必要であれば下記の設定を変更すること
チューナーであればmirakcやMirakurunの設定、コンテナーイメージやデバイスマップ指定はdockerで利用する指定と同じ

  • CONTAINER_IMAGE : 利用するコンテナーイメージ
    • カスタムイメージの場合は mirakc/mirakc から派生させたものとすること
  • DEVICE_MAP_GR : 地上波用録画デバイスマップ
  • DEVICE_MAP_BS : BS波用録画デバイスマップ
  • DEVICE_MAP_CS : CS波用録画デバイスマップ
    • dvbデバイスなら /dev/dvb:/dev/dvb だけでよい
  • RECORD_COMMAND_GR : 地上波録画コマンド
  • RECORD_COMMAND_BS : BS波録画コマンド
  • RECORD_COMMAND_CS : CS波録画コマンド
    • パイプで処理するためストリームはstdoutに流すこと
    • 録画秒に関してBSはチャンネル情報取得に遅くて17秒程度かかることがあるので念のため20秒ぐらいは余裕を持たせること
  • CHANNELS_GR : 地上波スキャンチャンネル
  • CHANNELS_BS : BS波スキャンチャンネル
  • CHANNELS_CS : CS波スキャンチャンネル
    • あらかじめチャンネルがわかっているのであれば削除してもよい
    • 空行、先頭が # であればスキップする

前に作った scan_ch_mirak.sh との相違点

  • dockerjq のみホスト側に用意すればよい
  • mirakc用のみでMirakurun用設定は出力しない (Mirakurun向けは形式似てるから自分でなんとかして)
  • epgdumpはもはや不要
  • 利用チャンネルがわかっているのであればスキャンしたいチャンネルを編集できるようにした
  • recpt1を使っているのであればBSのチャンネル再編でも困ることはないはず (※)

※recpt1とBSチャンネル再編について
recpt1ではBSチャンネル指定が BS{物理チャンネル}_{スロット番号:0-7} という形式になっておりrecpt1側がパースしてデバイスに対してリクエストを行っている
理論上 BS01_0, BS01_1, ..., BS01_7, ..., BS23_7 まで全スキャンすれば漏れはなくなるはず
ただ現状1チャンネルを最大4スロットまでしか利用していないので、デフォルトでの指定も各チャンネル4スロット分までとしている
なおBSチャンネル再編の際にrecpt1が更新されるが、これは--helpでの表示とサービスID指定録画の影響だけなので、BS??_?形式での指定ではプログラムの更新をする必要はない

@uru2
Copy link
Author

uru2 commented Sep 2, 2022

mirakc側でサービスをスキャンするので利用可能なチャンネルのみ出力するよう変更
CSは名称=チャンネルとする

なお環境変数に EXTRACT_SID=1 を指定して実行すると初期リビジョンと同じ動作を行う (GR,BSは各チャンネルのSIDを展開、CSは各SIDごとチャンネル生成)

@uru2
Copy link
Author

uru2 commented Sep 3, 2022

PX-MLT8PEで使ってみてわかったが、px4_drvのオプション options px4_drv discard_null_packets=Y を使うとBS03_2スキャンでrecpt1が指定秒数を過ぎても終了しない不具合?を確認

px4_drvとPX-MLT8PE(PX-MLT5PEも?)でスキャンする際にはこれを無効にする必要あり

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment