Replaced The TV Recording System To EDCB

Raspberry PiでEpgStationで運用していた録画サーバーをEDCBへ移行した。

Background

元々Raspberry Pi 4でEpgStationを運用していた。チューナーはUSBのトングルタイプを利用。
これが如何せん不安定で、度々録画できなくなる。
一度録画できなくなると、USBを抜き差ししたり、再起動したり、色々しないと安定しなくて、結構な時間を取られていた。

で、実は手元にPT3という安定感抜群のチューナーが何個か転がっていたので、それを再利用したいという気持ちが強くなってきた。
しかしこのチューナーはPCI Expressというインターフェイスなので、新たにサーバーを組まないといけなく腰が重かったのだが、地デジ自体がいつまで続くのか分からないなと思うようになり、この度サーバーを組み立てて、PT3を利用して録画サーバーを組むことにした。

これ、人生で何回目だろうか。
お金以外にもスペース等の問題もあるのだが、小さいPCケースを利用するということで、家庭内稟議は何とか通すことに成功した。

別に録画してまで見たい番組がそれほどあるのかと言われると、それ程ない。
が、理屈ではないのだ。
そろそろ年齢も良い年になってきたので、出来ない理由を並べるのではなく、やりたいことを先延ばしにしたくないという気持ちが強くなってきたのかもしれない。

折角一から作成するので、色々調べて、ハードウェアとソフトウェア共に自分のやってみたい構成でサーバーを組んでみようと思った。

Structure

ざっと以下のような構成になった。

Hardware

もう割り切って録画用サーバーとしてファンレス&省エネのマザーボードを選んだ。
それ意外は、適当に。

Software

EpgStationがメンテナンスが停止してしまっていたので、色々入れ替えてみた。
普通に安定して使えている。
先人たちの努力に感謝。

Recorded Files Organization

自分の場合、基本的に録画されたファイルはSamba経由で直接ファイルを参照できれば良いと思っているので、録画ファイルのファイル構成は、番組ごとにまとまっていて欲しい。
ということで、以下のような簡単なluaスクリプトを書いた。

-- PostRecEnd.lua
-- xtne6f版EDCB 録画後実行スクリプト

-- =============================
-- 関数定義
-- =============================
local function sanitizeDirName(name)
    return name:gsub(' ', '-')
        :gsub('[%*%?<>|:;&%(%)%[%]{}!"`%$#~\\/]', function(c)
            local map = {
                ['*']='*', ['?']='?', ['<']='<', ['>']='>', ['|']='|',
                [':']=':', [';']=';', ['&']='&', ['(']='(', [')']=')',
                ['[']='[', [']']=']', ['{']='{', ['}']='}', ['!']='!',
                ['"']='-', ["'"]='-', ['`']='-', ['$']='$', ['#']='#',
                ['~']='~', ['\\']='¥', ['/']='/'
            }
            return map[c] or c
        end)
end

local function debug(msg, mode)
    mode = mode or 'a'
    local f = io.open('/var/local/edcb/PostRecEndDebug.txt', mode)
    if f then
        f:write(msg .. '\n')
        f:close()
    end
end

-- =============================
-- メイン処理
-- =============================

-- デバッグ: env内容
debug('=== ' .. os.date('%Y-%m-%d %H:%M:%S') .. ' ===', 'w')
if env then
    for k, v in pairs(env) do
        debug(string.format('env.%s = %s', k, tostring(v)))
    end
end

-- 録画情報取得
local ri = edcb.GetRecFileInfoBasic(env.RecInfoID)
if not ri or ri.recFilePath == '' then
    debug('Error: No RecInfo')
    return
end

debug('FilePath: ' .. ri.recFilePath)

-- chown
edcb.os.execute('chown {{ mirakc_edcb.edcb.file_owner_uid }}:{{ mirakc_edcb.edcb.file_owner_gid }} "' .. ri.recFilePath .. '"')

-- AddKey処理
local addKey = env.AddKey or ''
if addKey ~= '' then
    -- パス生成
    local baseDir, fileName = ri.recFilePath:match('(.+)/([^/]+)$')
    local dirName = sanitizeDirName(addKey)
    local targetDir = baseDir .. '/' .. dirName
    local newPath = targetDir .. '/' .. fileName

    debug('AddKey: ' .. addKey .. ' -> ' .. dirName)

    -- ディレクトリ作成と移動
    edcb.os.execute('mkdir -p "' .. targetDir .. '" && chown {{ mirakc_edcb.edcb.file_owner_uid }}:{{ mirakc_edcb.edcb.file_owner_gid }} "' .. targetDir .. '"')

    if edcb.os.rename(ri.recFilePath, newPath) then
        -- 関連ファイル
        edcb.os.rename(ri.recFilePath .. '.program.txt', newPath .. '.program.txt')
        edcb.os.rename(ri.recFilePath .. '.err', newPath .. '.err')
        -- DB更新
        edcb.ChgPathRecFileInfo(ri.id, newPath)
        debug('Moved: ' .. newPath)
    else
        debug('Failed to move')
    end
end

動きとしては、

  • ファイル名にSambaやLinuxが苦手な文字があったら全角に変換orダッシュへ
  • キーワードごとにディレクトリを自動作成
  • 録画後、キーワードディレクトリに移動

一応、API経由でファイルパスを変更しているので、録画結果の一覧からも引き続き操作可能

自分の場合は、これで満足。

Conclusion

PT3がめっちゃ安定していることもあり、移行前とは快適性が雲泥の差だ。
それぞれのソフトウェアもDockerイメージでまとめて、docker composeで稼働させるようにしているので、アップデートは基本イメージを差し替えるだけで良いのも楽。
これはEpgStationの時が楽だったので、真似させてもらっている。

当分は、この構成で続けられたらいいな。