Ubuntu26.04でLXDコンテナにKonomiTVセットアップ

これまでも何度か紹介してきたKonomiTVセットアップですが、途中部分も簡略化したので、一度、こちらにまとめました。

ホストにチューナードライバ適用(ホスト側)

OS:Ubuntu 26.04
TVチューナー:DTV02A-1T1S-U

まずはホスト側にチューナードライバを適用します。Secure Boot環境の場合、ドライバインストール時に確認画面が表示されるので、こちらの記事を参考に設定。

mkdir -p ~/dtv && cd ~/dtv
DRIVER_VERSION=$(curl -s https://api.github.com/repos/tsukumijima/px4_drv/releases/latest | grep '"tag_name"' | sed 's/.*"v\([^"]*\)".*/\1/')
DRIVER_DEB="px4-drv-dkms_${DRIVER_VERSION}_all.deb"
DRIVER_URL="https://github.com/tsukumijima/px4_drv/releases/download/v${DRIVER_VERSION}/${DRIVER_DEB}"
curl -L -o "${DRIVER_DEB}" "${DRIVER_URL}"
chmod 644 "${DRIVER_DEB}"
sudo apt install -y "./${DRIVER_DEB}"
sudo modprobe -r px4_drv; sudo modprobe px4_drv
lsmod | grep px4
sudo dmesg | grep -i "px4_drv version"

コンテナ作成、Tailscaleセットアップ、チューナーパススルー(ホスト側)

Ubuntu26.04ベースのコンテナ作成、/opt/lxd-dataをコンテナにマウント、Tailscaleセットアップ、チューナーのパススルーまで行います。途中で2回ほどスナップショットも作成出来ます。
まだLXDをインストールしていない場合は、こちらを参考にインストールしてから実行します。

#!/bin/bash
set -euo pipefail

MOUNT_PATH="/opt/lxd-data"

# ============================================================
# ユーティリティ
# ============================================================
ask_yn() {
    # ask_yn "質問文"  -> 0=Yes, 1=No
    local prompt="$1"
    while true; do
        read -rp "${prompt} [y/N]: " ans
        case "${ans,,}" in
            y|yes) return 0 ;;
            n|no|"") return 1 ;;
            *) echo "  y または n で答えてください。" ;;
        esac
    done
}

# ============================================================
# 1. コンテナ名の入力
# ============================================================
read -rp "作成するコンテナ名を入力してください [konomitv]: " CONTAINER
CONTAINER="${CONTAINER:-konomitv}"
echo "  コンテナ名: ${CONTAINER}"

# ============================================================
# 2. Tailscale authkey の入力
# ============================================================
echo ""
if ask_yn "Tailscale の authkey がありますか?"; then
    read -rsp "authkey を入力してください(tskeyから入力。入力は非表示): " TS_AUTHKEY
    echo ""
    USE_TS_AUTHKEY=true
else
    USE_TS_AUTHKEY=false
fi

# ============================================================
# 3. コンテナ作成・マウント・ID マッピング
# ============================================================
echo ""
echo "=== コンテナ '${CONTAINER}' を作成 ==="
lxc launch ubuntu:26.04 "$CONTAINER"

echo ""
echo "=== ${MOUNT_PATH} の確認・作成 ==="
if [ ! -d "$MOUNT_PATH" ]; then
    sudo mkdir -p "$MOUNT_PATH"
    if [ ! -d "$MOUNT_PATH" ]; then
        echo "エラー: ${MOUNT_PATH} の作成に失敗しました"
        exit 1
    fi
    echo "  ${MOUNT_PATH} を作成しました"
else
    echo "  ${MOUNT_PATH} は既に存在します"
fi

# ------------------------------------------------------------
# 録画フォルダ /opt/lxd-data/tv の作成とアクセス権設定
#
# install_dtv.sh がコンテナ内からバインドマウントで参照するため、
# ここでホスト側に作成しておく。
#   - UID 1000 / GID 1000 を所有者に設定(コンテナ内の ubuntu ユーザーと一致)
#   - 755 でグループ・他ユーザーにも読み取り・実行を許可する
# ------------------------------------------------------------
TV_DIR="${MOUNT_PATH}/tv"
echo ""
echo "=== 録画フォルダ ${TV_DIR} の確認・作成 ==="
if [ ! -d "$TV_DIR" ]; then
    sudo mkdir -p "$TV_DIR"
    echo "  ${TV_DIR} を作成しました"
else
    echo "  ${TV_DIR} は既に存在します"
fi
sudo chown 1000:1000 "$TV_DIR"
sudo chmod 755 "$TV_DIR"
echo "  所有者: 1000:1000  パーミッション: 755"

echo ""
echo "=== ホストの ${MOUNT_PATH} をコンテナにマウント ==="
lxc config device add "$CONTAINER" opt-lxd-data disk source="$MOUNT_PATH" path="$MOUNT_PATH"

echo ""
echo "=== ID マッピング設定 ==="
lxc config set "$CONTAINER" raw.idmap "both 1000 1000"

echo ""
echo "=== コンテナを再起動 ==="
lxc restart "$CONTAINER"

# ============================================================
# 4. コンテナ内セットアップ(apt / Tailscale)
# ============================================================
echo ""
echo "=== コンテナ '${CONTAINER}' 内のセットアップを開始 ==="

lxc exec "${CONTAINER}" -- bash -euo pipefail << 'INNER'
echo "==> apt update"
apt update

echo "==> apt upgrade"
apt upgrade -y

echo "==> curl インストール"
apt install -y curl

echo "==> Tailscale インストール"
curl -fsSL https://tailscale.com/install.sh | sh

echo "==> セットアップ完了"
INNER

echo ""
echo "=== Tailscale を起動 ==="
if [ "$USE_TS_AUTHKEY" = true ]; then
    lxc exec "${CONTAINER}" -- tailscale up --authkey="${TS_AUTHKEY}"
else
    lxc exec "${CONTAINER}" -- tailscale up
fi

# ============================================================
# 5. TailscaleOK スナップショット
# ============================================================
echo ""
if ask_yn "スナップショット 'TailscaleOK' を作成しますか?"; then
    echo "=== コンテナを停止中 ==="
    lxc stop "${CONTAINER}"
    echo "=== スナップショット 'TailscaleOK' を作成中 ==="
    lxc snapshot "${CONTAINER}" TailscaleOK
    echo "  スナップショット 'TailscaleOK' を作成しました"
    echo "=== コンテナを起動中 ==="
    lxc start "${CONTAINER}"
fi

# ============================================================
# 6. USB チューナーパススルー
# ============================================================
echo ""
if ask_yn "USB チューナーをコンテナにパススルーしますか?"; then

    # --- USB デバイス(vendorid / productid)---
    echo ""
    echo "=== USB チューナーを検出中 ==="
    LSUSB_LINE=$(lsusb | grep -i "ISDBT2056" || true)
    if [ -z "$LSUSB_LINE" ]; then
        echo "エラー: ISDBT2056 デバイスが見つかりません。接続を確認してください。"
        exit 1
    fi
    echo "  検出: $LSUSB_LINE"

    IDS=$(echo "$LSUSB_LINE" | grep -oP 'ID \K[0-9a-fA-F]{4}:[0-9a-fA-F]{4}')
    VENDOR_ID=$(echo "$IDS" | cut -d: -f1)
    PRODUCT_ID=$(echo "$IDS" | cut -d: -f2)
    echo "  vendorid : $VENDOR_ID"
    echo "  productid: $PRODUCT_ID"

    if lxc config device show "$CONTAINER" | grep -q "usb-tuner"; then
        echo "  usb-tuner は登録済みのため上書きします"
        lxc config device remove "$CONTAINER" usb-tuner
    fi
    lxc config device add "$CONTAINER" usb-tuner usb \
        vendorid="$VENDOR_ID" \
        productid="$PRODUCT_ID"
    echo "  usb-tuner を追加しました"

    # --- /dev/bus/usb パススルー ---
    echo ""
    echo "=== USB バスデバイスノードを検出中 ==="
    BUS_NUM=$(echo "$LSUSB_LINE" | grep -oP 'Bus \K[0-9]+')
    DEV_NUM=$(echo "$LSUSB_LINE" | grep -oP 'Device \K[0-9]+')

    if [ -n "$BUS_NUM" ] && [ -n "$DEV_NUM" ]; then
        USB_NODE="/dev/bus/usb/$(printf '%03d' "$BUS_NUM")/$(printf '%03d' "$DEV_NUM")"
        if [ -e "$USB_NODE" ]; then
            echo "  検出: $USB_NODE"
            NAME="usb-bus-node"
            if lxc config device show "$CONTAINER" | grep -q "^${NAME}:"; then
                lxc config device remove "$CONTAINER" "$NAME"
            fi
            lxc config device add "$CONTAINER" "$NAME" unix-char \
                source="$USB_NODE" path="$USB_NODE"
            echo "  $NAME を追加しました ($USB_NODE)"
        else
            echo "  警告: $USB_NODE が存在しません。スキップします。"
        fi
    else
        echo "  警告: バス/デバイス番号を特定できませんでした。スキップします。"
    fi

    # --- isdb2056videoN デバイス ---
    echo ""
    echo "=== isdb2056video デバイスを検出中 ==="
    ISDB_DEVS=$(ls /dev/isdb2056video* 2>/dev/null || true)
    if [ -z "$ISDB_DEVS" ]; then
        echo "  警告: /dev/isdb2056video* が見つかりません。スキップします。"
    else
        IDX=0
        for DEV in $ISDB_DEVS; do
            NAME="isdb2056-${IDX}"
            echo "  追加: $DEV ($NAME)"
            if lxc config device show "$CONTAINER" | grep -q "^${NAME}:"; then
                lxc config device remove "$CONTAINER" "$NAME"
            fi
            lxc config device add "$CONTAINER" "$NAME" unix-char \
                source="$DEV" path="$DEV"
            IDX=$(( IDX + 1 ))
        done
    fi

    # --- DVB デバイス ---
    echo ""
    echo "=== DVB デバイスを検出中 ==="
    DVB_DEVS=$(find /dev/dvb -type c 2>/dev/null || true)
    if [ -z "$DVB_DEVS" ]; then
        echo "  INFO: DVB デバイスなし。スキップします。"
    else
        for DEV in $DVB_DEVS; do
            NAME="dvb-$(echo "$DEV" | sed 's|/dev/dvb/||; s|/|-|g')"
            echo "  追加: $DEV ($NAME)"
            if lxc config device show "$CONTAINER" | grep -q "^${NAME}:"; then
                lxc config device remove "$CONTAINER" "$NAME"
            fi
            lxc config device add "$CONTAINER" "$NAME" unix-char \
                source="$DEV" path="$DEV"
        done
    fi

    echo ""
    echo "=== 登録済みデバイス一覧 (コンテナ: $CONTAINER) ==="
    lxc config device show "$CONTAINER"

    # ============================================================
    # 7. コンテナ内チューナー確認
    # ============================================================
    echo ""
    if ask_yn "コンテナ内でチューナーデバイスを確認しますか?"; then
        echo ""
        echo "=== コンテナ内チューナー確認 ==="
        lxc exec "${CONTAINER}" -- bash -euo pipefail << 'CHECK'
EXIT_CODE=0

echo "=== isdb2056video デバイス確認 ==="
ISDB_DEVS=$(ls /dev/isdb2056video* 2>/dev/null || true)
if [ -z "$ISDB_DEVS" ]; then
    echo "  NG: /dev/isdb2056video* が見つかりません"
    EXIT_CODE=1
else
    for DEV in $ISDB_DEVS; do
        echo "  OK: $DEV"
    done
fi

echo ""
echo "=== USB バスデバイスノード確認 ==="
FOUND_USB=$(find /dev/bus/usb -type c 2>/dev/null | head -1 || true)
if [ -n "$FOUND_USB" ]; then
    echo "  OK: $(find /dev/bus/usb -type c 2>/dev/null | tr '\n' ' ')"
else
    echo "  INFO: /dev/bus/usb ノードなし(コンテナ環境では省略可)"
fi

echo ""
echo "=== DVB デバイス確認 ==="
DVB_DEVS=$(find /dev/dvb -type c 2>/dev/null || true)
if [ -z "$DVB_DEVS" ]; then
    echo "  INFO: DVB デバイスなし(この機種では不要)"
else
    for DEV in $DVB_DEVS; do
        echo "  OK: $DEV"
    done
fi

echo ""
if [ "$EXIT_CODE" -eq 0 ]; then
    echo "=== 結果: すべてのデバイスが確認できました ✓ ==="
else
    echo "=== 結果: 一部のデバイスが見つかりません ✗ ==="
fi
exit "$EXIT_CODE"
CHECK
    fi

    # ============================================================
    # 8. TunerOK スナップショット
    # ============================================================
    echo ""
    if ask_yn "スナップショット 'TunerOK' を作成しますか?"; then
        echo "=== コンテナを停止中 ==="
        lxc stop "${CONTAINER}"
        echo "=== スナップショット 'TunerOK' を作成中 ==="
        lxc snapshot "${CONTAINER}" TunerOK
        echo "  スナップショット 'TunerOK' を作成しました"
        echo "=== コンテナを起動中 ==="
        lxc start "${CONTAINER}"
    fi

fi  # USBパススルー end

# ============================================================
# 完了・コンテナに入る
# ============================================================
echo ""
echo "=== セットアップ完了。コンテナ '${CONTAINER}' に接続します ==="
lxc exec "${CONTAINER}" -- bash

Mirakurun、EDCB、KonomiTVセットアップ(コンテナ内)

下記をコピーして貼り付ければOK。問題なければソフトのインストール自体は10分くらいで完了するはず。最後にEPGの取得も開始しているので、EPGの取得完了まで待つなら、さらに20分くらい放置していれば、番組情報まで取得出来ているはず。

#!/bin/bash
# =============================================================
# DTV環境セットアップスクリプト
# 対応環境: Ubuntu Desktop / LXDコンテナ (Ubuntu 26.04)
# 実行方法: sudo bash install_dtv.sh
# =============================================================
set -e

# ------------------------------------------------------------
# root 権限チェック
# ------------------------------------------------------------
if [ "$(id -u)" -ne 0 ]; then
    echo "エラー: このスクリプトは root で実行してください。"
    echo "  sudo bash $0"
    exit 1
fi

# ------------------------------------------------------------
# 実行環境の判定(LXDコンテナか通常のホストか)
# ------------------------------------------------------------
IS_LXD=false
if systemd-detect-virt --container 2>/dev/null | grep -qi lxc; then
    IS_LXD=true
fi
echo "実行環境: $([ "$IS_LXD" = true ] && echo 'LXDコンテナ' || echo 'Ubuntu Desktop/VM')"

# ------------------------------------------------------------
# スクリプト実行ユーザーとホームディレクトリの取得
# sudo 経由の場合は SUDO_USER を優先する
# ------------------------------------------------------------
REAL_USER="${SUDO_USER:-$(logname 2>/dev/null || id -un)}"
REAL_HOME=$(getent passwd "$REAL_USER" | cut -d: -f6)
DTV_DIR="$REAL_HOME/dtv"
echo "作業ユーザー: $REAL_USER  ホーム: $REAL_HOME"

# ============================================================
# 1/9: B-CAS キーの入力
# ============================================================
echo "=== 1/9: キー設定 ==="
echo "キーの内容を貼り付けてください(入力後、Enter を 2 回押すと確定します):"
BCAS_CONTENT=$(sed '/^$/q')

# ============================================================
# 2/9: 依存パッケージのインストール
# ============================================================
echo "=== 2/9: 依存パッケージをインストール中 ==="
apt update
apt install -y \
    autoconf automake cmake libtool libpcsclite-dev \
    git build-essential pkg-config curl wget \
    libclang-dev libdvbv5-dev libudev-dev \
    nodejs npm ffmpeg liblua5.2-dev lua-zlib g++ make gcc

# Node.js 18 を nvm 経由でインストール
# システムの nodejs は古い場合があるため nvm で固定バージョンを使用する
export NVM_DIR="/root/.nvm"
if [ ! -d "$NVM_DIR" ]; then
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
fi
source "$NVM_DIR/nvm.sh"
nvm install 18
nvm use 18
nvm alias default 18
NODE18_BIN=$(dirname "$(nvm which 18)")
export PATH="$NODE18_BIN:$PATH"
echo "Node.js バージョン確認: $(node -v)  npm: $(npm -v)"

# pm2 はプロセス管理に使用(KonomiTV の起動管理)
npm install -g pm2 || true

# ============================================================
# 3/9: TVチューナードライバのセットアップ
# ============================================================
echo "=== 3/9: ドライバをセットアップ中 ==="
mkdir -p "$DTV_DIR" && cd "$DTV_DIR"

echo "デバイスパーミッションを設定中..."
if [ "$IS_LXD" = true ]; then
    # LXDコンテナ内では udev が動作しないため chmod で直接設定する
    chmod 666 /dev/isdb2056video* 2>/dev/null && echo "isdb2056: OK" || echo "isdb2056: デバイスなし"
    chmod 666 /dev/px4video*      2>/dev/null && echo "px4video: OK"  || echo "px4video: デバイスなし"
else
    # ホスト環境では udev ルールを使用してデバイスの恒久的な権限設定を行う
    tee /etc/udev/rules.d/99-dtv.rules > /dev/null <<'UDEV'
SUBSYSTEM=="usb", ATTRS{idVendor}=="0511", MODE="0666"
KERNEL=="isdb2056video*", MODE="0666", GROUP="video"
KERNEL=="px4video*",      MODE="0666", GROUP="video"
UDEV
    udevadm control --reload-rules
    udevadm trigger
    sleep 2
    chmod 666 /dev/isdb2056video* 2>/dev/null && echo "isdb2056: OK" || echo "isdb2056: デバイスなし"
    chmod 666 /dev/px4video*      2>/dev/null && echo "px4video: OK"  || echo "px4video: デバイスなし"
    # ユーザーを video グループに追加(再ログイン後に有効)
    usermod -aG video "$REAL_USER" || true
fi

# チューナーが見つからない場合は警告を表示して継続する
if ! ls /dev/isdb2056video* /dev/px4video* 2>/dev/null | grep -q .; then
    echo "警告: TVチューナーデバイスが見つかりません。"
    if [ "$IS_LXD" = true ]; then
        echo "  LXDのプロファイルでデバイスパススルーが設定されているか確認してください。"
        echo "  例: lxc config device add <container> isdb2056video0 unix-char path=/dev/isdb2056video0"
    else
        echo "  チューナーが正しく接続・認識されているか確認してください。"
    fi
fi

# ============================================================
# 4/9: 復号ライブラリ (libyakisoba / libsobacas) のビルド
# ============================================================
echo "=== 4/9: 復号ライブラリのビルド ==="
cd "$DTV_DIR"
for repo in libyakisoba libsobacas; do
    [ ! -d "$repo" ] && git clone "https://github.com/tsunoda14/${repo}.git"
    cd "$repo"
    autoreconf -i
    mkdir -p build && cd build
    # libyakisoba のみ --sysconfdir を指定する(設定ファイルの配置先)
    [ "$repo" = "libyakisoba" ] && ../configure --sysconfdir=/usr/local/etc || ../configure
    make -j"$(nproc)"
    make install
    cd "$DTV_DIR"
done
# 共有ライブラリのキャッシュを更新
ldconfig

# ============================================================
# 5/9: Rust / recisdb のビルド
# ============================================================
echo "=== 5/9: Rust と recisdb のビルド ==="
export CARGO_HOME="/root/.cargo"
export RUSTUP_HOME="/root/.rustup"
if ! command -v cargo &>/dev/null; then
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
fi
source "$CARGO_HOME/env" 2>/dev/null || export PATH="$CARGO_HOME/bin:$PATH"

# libsobacas の pkg-config ファイルを手動作成(Cargo ビルドで参照される)
mkdir -p /usr/local/lib/pkgconfig
tee /usr/local/lib/pkgconfig/libsobacas.pc > /dev/null <<'EOF'
prefix=/usr/local
libdir=/usr/local/lib
includedir=/usr/include
Name: libsobacas
Description: PCSC compatible ECM decoder library
Version: 0.0.0
Libs: -L${libdir} -lsobacas
Cflags: -I${includedir}/PCSC
EOF

cd "$DTV_DIR"
[ ! -d recisdb-rs ] && git clone --recursive https://github.com/kazuki0824/recisdb-rs.git
cd recisdb-rs
# b25-sys の依存ライブラリを pcsclite から libsobacas に差し替える
sed -i 's/pcsclite/sobacas/g' b25-sys/build.rs
cargo build -F dvb --release
cp target/release/recisdb /usr/local/bin/
# B-CAS キーを所定のパスに保存
mkdir -p /usr/local/etc
echo "$BCAS_CONTENT" | tee /usr/local/etc/bcas_keys > /dev/null

# ============================================================
# 6/9: チャンネルスキャン・Mirakurun 設定
# ============================================================
echo "=== 6/9: チャンネルスキャンと Mirakurun 設定 ==="
wget -q https://github.com/tsukumijima/ISDBScanner/releases/download/v1.3.3/isdb-scanner \
    -O /usr/local/bin/isdb-scanner
chmod +x /usr/local/bin/isdb-scanner

npm install -g \
    --unsafe-perm \
    --foreground-scripts \
    --production \
    --ignore-engines \
    mirakurun@3.9.0-rc.4

# 初回起動で設定ディレクトリを生成させてから一旦停止する
mkdir -p /usr/local/etc/mirakurun
mirakurun start || true
sleep 5
mirakurun stop  || true

# スキャン済みチャンネルが存在しない場合のみスキャンを実行する
mkdir -p "$DTV_DIR/scanned"
if [ -z "$(ls -A "$DTV_DIR/scanned/" 2>/dev/null)" ]; then
    isdb-scanner "$DTV_DIR/scanned/"
fi

if [ ! -f "$DTV_DIR/scanned/Mirakurun/channels.yml" ]; then
    echo "エラー: チャンネルスキャンが完了しませんでした。"
    echo "デバイスのパススルー設定を確認してから再実行してください。"
    exit 1
fi

# スキャン結果を Mirakurun の設定ディレクトリに配置する
cp -a "$DTV_DIR/scanned/Mirakurun/channels.yml" /usr/local/etc/mirakurun/channels.yml
cp -a "$DTV_DIR/scanned/Mirakurun/tuners.yml"   /usr/local/etc/mirakurun/tuners.yml
chown -R root:root /usr/local/etc/mirakurun/
mirakurun start

# ============================================================
# 7/9: EDCB セットアップ
# ============================================================
echo "=== 7/9: EDCB セットアップ ==="
cd "$DTV_DIR"
[ ! -d EDCB ] && git clone https://github.com/xtne6f/EDCB
cd EDCB/Document/Unix
make -j"$(nproc)"
make install
make extra
make install_extra

mkdir -p /var/local/edcb
chown -R "$REAL_USER:$REAL_USER" /var/local/edcb
make setup_ini

# EDCB Material WebUI(EDCB の Web 管理画面)を配置する
cd "$DTV_DIR"
[ ! -d EDCB_Material_WebUI ] && git clone https://github.com/EMWUI/EDCB_Material_WebUI
cp -r EDCB_Material_WebUI/HttpPublic /var/local/edcb/
cp -r EDCB_Material_WebUI/Setting    /var/local/edcb/
# EpgData フォルダ作成のために所有者を再設定する
chown -R "$REAL_USER:$REAL_USER" /var/local/edcb

# BonDriver_LinuxMirakc: EDCB が Mirakurun を BonDriver 経由で使うためのドライバ
[ ! -d BonDriver_LinuxMirakc ] && \
    git clone https://github.com/matching/BonDriver_LinuxMirakc.git --recurse-submodules
cd BonDriver_LinuxMirakc
make -j"$(nproc)"
cp BonDriver_LinuxMirakc.so     /usr/local/lib/edcb/
cp BonDriver_LinuxMirakc.so.ini_sample /usr/local/lib/edcb/BonDriver_LinuxMirakc.so.ini

# スキャン結果から EDCB 用チャンネル設定ファイルをコピーする
cp "$DTV_DIR/scanned/EDCB-Wine/ChSet5.txt" /var/local/edcb/Setting/
cp "$DTV_DIR/scanned/EDCB-Wine/BonDriver_mirakc(BonDriver_mirakc).ChSet4.txt" \
   '/var/local/edcb/Setting/BonDriver_LinuxMirakc(LinuxMirakc).ChSet4.txt'

# WebUI の設定変更(設定画面のアクセスを許可)
sed -i 's/^ALLOW_SETTING=.*/ALLOW_SETTING=true/' /var/local/edcb/HttpPublic/legacy/util.lua

# ------------------------------------------------------------
# 録画フォルダのセットアップ
# ホスト側のマウントポイント /opt/lxd-data/tv を
# /var/local/edcb/HttpPublic/video にバインドマウントする
#
# /opt/lxd-data はホストが所有するディレクトリのため、
# root でも直接 mkdir できない場合がある。
# 存在しない場合は警告を表示して処理を継続する。
# ------------------------------------------------------------
RECORD_SRC="/opt/lxd-data/tv"
RECORD_DST="/var/local/edcb/HttpPublic/video"
echo "録画フォルダをセットアップ中: $RECORD_SRC -> $RECORD_DST"

# 録画先ディレクトリ(コンテナ内側)は必ず作成する
mkdir -p "$RECORD_DST"

# ソース側(ホストマウントポイント)は存在する場合のみ処理する
if [ -d "$RECORD_SRC" ]; then
    if grep -q "$RECORD_DST" /etc/fstab; then
        echo "fstab: $RECORD_DST は既に登録済みのためスキップします"
    else
        echo "$RECORD_SRC $RECORD_DST none bind 0 0" >> /etc/fstab
        echo "fstab: $RECORD_DST を登録しました"
    fi

    if mountpoint -q "$RECORD_DST"; then
        echo "バインドマウント: $RECORD_DST は既にマウント済みです"
    else
        mount --bind "$RECORD_SRC" "$RECORD_DST"
        echo "バインドマウント: $RECORD_DST をマウントしました"
    fi
else
    echo "警告: $RECORD_SRC が存在しないためバインドマウントをスキップします。"
    echo "  ホスト側でディレクトリを作成してから手動でマウントしてください。"
    echo "  例(ホスト側): sudo mkdir -p $RECORD_SRC"
    echo "  例(コンテナ内): sudo mount --bind $RECORD_SRC $RECORD_DST"
fi

# 録画先の所有者を実行ユーザーに設定する(EDCB からの書き込みを可能にする)
chown -R "$REAL_USER:$REAL_USER" "$RECORD_DST" 2>/dev/null || true

# ------------------------------------------------------------
# 接続されているチューナー数を自動検出して設定に反映する
# デバイスが見つからない場合は tuners.yml の定義数を代用する
# ------------------------------------------------------------
ISDB_DEV_COUNT=$(ls /dev/isdb2056video* 2>/dev/null | wc -l)
PX4_DEV_COUNT=$(ls /dev/px4video*       2>/dev/null | wc -l)
if [ "$ISDB_DEV_COUNT" -gt 0 ]; then
    TUNER_COUNT=$ISDB_DEV_COUNT
elif [ "$PX4_DEV_COUNT" -gt 0 ]; then
    # PX-W3U4 等は 4 デバイスで 1 チューナー扱いのため 4 で割る
    TUNER_COUNT=$(( PX4_DEV_COUNT / 4 ))
    [ "$TUNER_COUNT" -eq 0 ] && TUNER_COUNT=1
else
    TUNER_COUNT=$(grep -c '^ *- name:' /usr/local/etc/mirakurun/tuners.yml 2>/dev/null || echo 1)
    [ "$TUNER_COUNT" -eq 0 ] && TUNER_COUNT=1
fi
echo "検出チューナー数: ${TUNER_COUNT}"

# EpgTimerSrv.ini: EDCB 本体の動作設定
tee /var/local/edcb/EpgTimerSrv.ini > /dev/null <<EOT
[SET]
EnableHttpSrv=1
EnableTCPSrv=1
RecEndMode=0
Data=1
; ローカルおよびプライベートネットワーク全域からのアクセスを許可する
HttpAccessControlList=+127.0.0.0/8,+10.0.0.0/8,+172.16.0.0/12,+192.168.0.0/16,+169.254.0.0/16,+100.64.0.0/10
[TunerNum]
BonDriver_LinuxMirakc(LinuxMirakc).so=${TUNER_COUNT}
[BonDriver_LinuxMirakc.so]
Count=${TUNER_COUNT}
GetEpg=1
EPGCount=0
Priority=0
EOT

# Common.ini: 録画先フォルダの設定
tee /var/local/edcb/Common.ini > /dev/null <<'EOT'
[SET]
RecFolderPath0=/var/local/edcb/HttpPublic/video
RecFolderNum=1
EOT

# systemd サービスとして EDCB を登録・起動する
tee /etc/systemd/system/edcb.service > /dev/null <<EOT
[Unit]
Description=EpgTimerSrv
After=network-online.target
[Service]
Type=simple
User=$REAL_USER
ExecStart=/usr/local/bin/EpgTimerSrv
Restart=always
[Install]
WantedBy=default.target
EOT
systemctl daemon-reload
systemctl enable edcb
systemctl start edcb

# ============================================================
# 8/9: KonomiTV インストール
# ============================================================
echo "=== 8/9: KonomiTV インストール ==="
cd "$DTV_DIR"
curl -LO https://github.com/tsukumijima/KonomiTV/releases/download/v0.13.0/KonomiTV-Installer.elf
chmod +x KonomiTV-Installer.elf

apt install -y expect

# expect を使ってインストーラの対話入力を自動化する
expect << 'EXPECT_EOF'
set timeout 300
log_file /tmp/konomi_install.log

spawn ./KonomiTV-Installer.elf

# 01. インストール/アップデート/アンインストール選択
expect -re {\[1/2/3/4/5\].*:} { send "1\r" }

# 02. インストール先フォルダ
expect -re {フォルダのパス:} { send "/opt/KonomiTV\r" }

# 03. バックエンド選択(デフォルト EDCB のまま空 Enter)
expect -re {\[EDCB/Mirakurun\].*:} { send "\r" }

# 04. EDCB TCP API URL
expect -re {TCP API の URL:} { send "tcp://127.0.0.1:4510/\r" }

# 05. エンコーダー選択
expect -re {\[FFmpeg.*\].*:} { send "FFmpeg\r" }

# 06. 録画フォルダ(1つ目)
expect -re {録画フォルダのパス:} { send "/var/local/edcb/HttpPublic/video\r" }

# 06. 録画フォルダ(2つ目 = 空 Enter で終了)
expect -re {録画フォルダのパス:} { send "\r" }

# 07. キャプチャ画像フォルダ(1つ目)
expect -re {キャプチャ画像の保存先フォルダのパス:} { send "/var/local/edcb/HttpPublic/video\r" }

# 07. キャプチャ画像フォルダ(2つ目 = 空 Enter で終了)
expect -re {キャプチャ画像の保存先フォルダのパス:} { send "\r" }

# インストール完了まで待機
expect eof
EXPECT_EOF

# config.yaml の always_receive_tv_from_mirakurun を有効化して再起動する
KONOMI_CONFIG=$(find /opt/KonomiTV -name "config.yaml" 2>/dev/null | head -1)
if [ -z "$KONOMI_CONFIG" ]; then
    echo "警告: KonomiTV の config.yaml が見つかりませんでした。"
else
    echo "KonomiTV config.yaml を更新中: $KONOMI_CONFIG"
    sed -i 's/always_receive_tv_from_mirakurun: false/always_receive_tv_from_mirakurun: true/' "$KONOMI_CONFIG"
    pm2 restart KonomiTV 2>/dev/null || true
fi

# ============================================================
# 9/9: EPG 取得開始(バックグラウンド)
# ============================================================
echo ""
echo "=== 9/9: 全セットアップ完了後 EPG 取得を開始 ==="
(
    echo "EDCBの起動を待機中..."
    for i in $(seq 1 60); do
        if curl -sf "http://127.0.0.1:5510/legacy/index.html" -o /dev/null 2>/dev/null; then
            echo "EDCB: 起動確認 (${i}秒)"
            break
        fi
        sleep 1
    done
    sleep 5

    echo "EPG取得リクエストを送信中..."
    # CSRF トークンを取得してから EPG 取得をリクエストする
    CTOK=$(curl -s http://127.0.0.1:5510/legacy/index.html \
        | grep -o 'name="ctok" value="[^"]*"' | head -1 \
        | grep -o 'value="[^"]*"' | cut -d'"' -f2)
    RESULT=$(curl -s -X POST "http://127.0.0.1:5510/legacy/index.html" \
        -H "Content-Type: application/x-www-form-urlencoded" \
        -d "ctok=${CTOK}&epgcap=y" \
        | grep -o 'id="result">[^<]*')
    if echo "$RESULT" | grep -q "開始しました"; then
        echo "EPG受信: 開始しました"
    else
        echo "警告: EPG取得リクエストの応答: $RESULT"
    fi
) >> /var/log/dtv_epg_start.log 2>&1 &

CONTAINER_NAME=$(hostname)

echo "EPG受信をバックグラウンドで開始しました"
echo "進捗ログ: tail -f /var/log/dtv_epg_start.log"
echo ""
echo "=== EPG取得状況の確認 ==="
ls /var/local/edcb/Setting/EpgData 2>/dev/null || echo "(EPGデータはまだ取得中です。数分後に再確認してください)"
echo ""
echo "============================================================"
echo " セットアップ完了"
echo "============================================================"
echo " EDCB Web:   http://${CONTAINER_NAME}:5510/"
echo " EPG確認:     ls /var/local/edcb/Setting/EpgData"
echo " EPGログ:     tail -f /var/log/dtv_epg_start.log"
echo " EDCB再起動:  systemctl restart edcb"
echo "============================================================"

インストール後のEPG取得状況確認など(コンテナ内)

番組表データを取得中なので、下記でEPG取得状況を確認。tmpファイルが無くなればEPGの取得完了。COPY

ls /var/local/edcb/Setting/EpgData

1チューナー環境で先にKonomiTVの動作確認を行いたいなら、チューナーがEPG受信中なので下記でEDCBを再起動してからKonomiTVで動作確認を。COPY

systemctl restart edcb

なお、KonomiTVセットアップ時には下記を自動入力しているので、変更箇所があるならKonomiTV起動後にアカウント登録をして、サーバ設定で変更します。

Enter
/opt/KonomiTV
Enter
tcp://127.0.0.1:4510/
FFmpeg
/var/local/edcb/HttpPublic/video
Enter
/var/local/edcb/HttpPublic/video
Enter

GPUパススルーする場合

セットアップ完了後、GPUをパスするーするならこちらの記事を参考に。

タイトルとURLをコピーしました