テレビ録画メディアサーバー構築入門(第9回)
使用法
ここで構築した「録画メディアサーバー」の特徴は、EPGStation で予約録画して(中間作業を完全自動化して)Jellyfin で視聴するというものです。
予約設定はEPGStationの「ルール」で細かく指定します。
ルール設定
最初に「ルール」に複数のスロットを作っておくと便利です。
まずは「検索」
http://localhost:8888/#/search
から適当に「検索」して、最下部の「追加」を押すと、「ルール」に追加されます。
追加された項目の、左にあるスイッチをオフにする。
おなじ作業を5回繰り返して、ルールのスロットを5つ作成する。
一番上のスロットには、最優先の番組を登録する。時間的に重複しないことが確実であれば、複数の番組をまとめて登録が可能です。これには、「正規表現」を選択して、「キーワード」に番組名を OR記号 | でつないで並べれば良い。
例:番組名1|番組名2|番組名3
ジャンルや放送局、最小の長さ(分)などで指定することも可能です。
あるいは、キーワードを設定せずに、ジャンルを選び、除外キーワードを設定する。例:名前に [再] を含む番組を除外
キーワードが複数あるなら、上のようにOR記号 |で項目を加えていく。
同様にして、優先度の低い番組を下のスロットに追加していきます。
たとえば、「映画」や「ドラマ」は、「ジャンル」よりまとめて登録できますが、時間的に一部重複するかたち(裏番組)で、複数の放送局が同時放送される場合があります。
こうした場合、「キーワード」や「放送局」で区別して、別のスロットに登録することで、録画の優先順位を指定できます。
個人的には、キーワード(芸人)やジャンル(アニメ)で「ざっくり」検索して、ヒットした結果から、不要な番組を手動でシラミツブシに「除外」していく方法を、便利に使っています。
サムネ画像
第7回で動画ファイル名から番組名を抽出したことで、同じ番組がフォルダにまとめられることになりました。
しかし、フォルダのイメージ画像が設定されていないため、Jellyfinの番組一覧表示が殺風景なものになっています。この問題は、動画からサムネ画像folder.jpgを作成して、各フォルダに配置すれば解決します。対象としては、最新の動画を使用することにします。さらに、親フォルダである、メディアルート media の画像もあわせてアップデートします。
まずその前に、Jellyfinはファイル名に基づき、登録されたオンラインデータベースを検索しに行きます。とりあえず、オンラインアクセスしないように設定します。
ダッシュボード
ライブラリ
ライブラリ
番組
ライブラリを管理
メタデータダウンローダーの項目すべてチェックを外す
インターネットからメタデータを自動的に再取得:しない
TheMovieDb, The Open Movie Database のチェックを外す
update_thumbs.sh
作業フォルダ~/workに作成
(追記:実はこれ、後で使わなくなる。第12回・13回参照)
#!/bin/bash
MEDIA_ROOT="$HOME/media"
latest_file=""
latest_time=0
latest_dir=""
for show_dir in "$MEDIA_ROOT"/*; do
[ -d "$show_dir" ] || continue
# そのディレクトリ内で最新の動画ファイルを探す
latest_episode=$(find "$show_dir" -type f \( -iname "*.mkv" -o -iname "*.mp4" -o -iname "*.avi" \) \
-printf "%T@ %p\n" | sort -nr | head -n1 | cut -d' ' -f2-)
if [ -n "$latest_episode" ]; then
if [ ! -f "$show_dir/folder.jpg" ]; then
echo "Generating thumbnail in $show_dir from: $latest_episode"
ffmpeg -y -ss 00:00:05 -i "$latest_episode" -frames:v 1 -q:v 2 "$show_dir/folder.jpg"
fi
# 全体で最も新しいファイルかをチェック
file_time=$(stat -c %Y "$latest_episode")
if [ "$file_time" -ge "$latest_time" ]; then
latest_time=$file_time
latest_file="$latest_episode"
fi
else
echo "No video files found in: $show_dir"
fi
done
# 全体で最新の動画から生成したサムネールを MEDIA_ROOT にコピー
if [ -n "$latest_file" ]; then
echo "Also copying thumbnail of latest video globally: $latest_file"
temp_thumb="/tmp/latest_folder.jpg"
ffmpeg -y -ss 00:00:05 -i "$latest_file" -frames:v 1 -q:v 2 "$temp_thumb"
cp "$temp_thumb" "$MEDIA_ROOT/folder.jpg"
rm -f "$temp_thumb"
else
echo "No video files found in any show directories."
fichmod +x update_thumbs.sh
./update_thumbs.sh空フォルダの削除
視聴後の動画を手動で削除することがあります。動画がなくとも、親フォルダは残るため、番組一覧には、クリックしても再生エラーとなる残骸だけが残されます。
過去に作成したものの、もはや動画mp4を含まないフォルダを自動で削除するスクリプトを用意します。
remove_empty_dirs.sh
作業フォルダ~/workに作成
#!/bin/bash
MEDIA_ROOT="$HOME/media"
# 再帰的にディレクトリを検査する関数
check_and_remove_dir() {
local dir="$1"
# ディレクトリ内のサブディレクトリについて再帰的にチェック
for sub_dir in "$dir"/*/; do
if [ -d "$sub_dir" ]; then
check_and_remove_dir "$sub_dir"
fi
done
# サブディレクトリのチェックが完了したら、現在のディレクトリに .mp4 ファイルがないか確認
mp4_files=$(find "$dir" -type f -name "*.mp4")
if [ -z "$mp4_files" ]; then
# サブディレクトリにも .mp4 ファイルが存在しない場合のみ削除
sub_dirs_with_mp4=false
for sub_dir in "$dir"/*/; do
if [ -d "$sub_dir" ]; then
mp4_in_sub_dir=$(find "$sub_dir" -type f -name "*.mp4")
if [ -n "$mp4_in_sub_dir" ]; then
sub_dirs_with_mp4=true
break
fi
fi
done
if ! $sub_dirs_with_mp4; then
echo "Deleting directory: $dir"
rm -rf "$dir"
fi
fi
}
# 再帰的にチェックと削除実行
check_and_remove_dir "$MEDIA_ROOT"処理済み動画の削除
これまで EPGStation の録画済み動画には、手を加えない方針できました。しかし、ある程度の期間、問題なく運用できてくると、サイズが大きい元のm2tsファイルを削除する必要が出てきます。できれば、自動でやりたい。
1週間以上前の古い動画をデータベースから削除するスクリプトが次のとおりです。
deleteold.py
#!/usr/bin/env python3
import requests
import json
from datetime import datetime, timedelta
# 録画サーバのURLとAPIエンドポイント
BASE_URL = 'http://localhost:8888/api'
RECORDED_ENDPOINT = '/recorded?isHalfWidth=false&offset=0&limit=1000'
# APIヘッダー
headers = {
'accept': 'application/json',
}
def get_recorded_programs():
"""録画済みの番組情報を取得"""
response = requests.get(BASE_URL + RECORDED_ENDPOINT, headers=headers)
if response.status_code == 200:
return response.json()['records']
else:
print(f"Failed to fetch recorded programs: {response.status_code}")
return []
def delete_recorded_program(program_id):
"""指定したIDの録画済み番組を削除"""
url = f"{BASE_URL}/recorded/{program_id}"
response = requests.delete(url, headers=headers)
if response.status_code == 200:
print(f"Program {program_id} deleted successfully.")
else:
print(f"Failed to delete program {program_id}: {response.status_code}")
def main():
recorded_programs = get_recorded_programs()
# 現在の日時と最古保存日時を取得
now = datetime.now()
# datetime_delete = now - timedelta(days=30) #1ヶ月前
datetime_delete = now - timedelta(days=7) #1週間
for record in recorded_programs:
program_id = record['id']
start_at = record.get('startAt', None)
if start_at is not None:
# UNIXタイムスタンプをdatetimeオブジェクトに変換
start_datetime = datetime.fromtimestamp(start_at / 1000)
# 古いもののみ削除する
if start_datetime < datetime_delete:
delete_recorded_program(program_id)
if __name__ == '__main__':
main()保存領域圧迫の最大の要因は、m2ts動画ファイルです。正常に処理した後は、適切に削除(または移動)していかないとシステムが崩壊します。ディスク容量が枯渇してきたら、削除間隔を1週間 timedelta(days=7) から1日 days=1 に変更する必要が生じるでしょう。
ファイル削除は、細心の注意を要する作業です。確実に動作するか手動操作で確認しましょう。
enc01.sh
以上3つを 適切なタイミングで実行します。update_thumbs.shは、録画m2tsをmp4に編集するスクリプトenc01.sh の最後で実行します。(つまり、また、enc01.shを置き換える。)
#!/bin/bash
SOURCEDIR="$HOME/docker-mirakurun-epgstation/recorded/"
WORKDIR="$HOME/work/"
OUTDIR="$HOME/media/"
NHK1="GR20"
NHK2="GR13"
encoded=false
while IFS= read -r FILE;
do
cd $SOURCEDIR
if [ -f "$FILE" ]; then
FILENAME=${FILE%.*}
GRSTRING=`echo $FILENAME | sed -n 's/.*\(GR[0-9][0-9]\).*/\1/p'`
cd $WORKDIR
if [ -z $GRSTRING ] || [ $GRSTRING = $NHK1 ] || [ $GRSTRING = $NHK2 ]; then
# NHKならば
./enc0.sh $SOURCEDIR/"$FILE" ${FILENAME}.mp4
else
# NHK以外
./enc1.sh $SOURCEDIR/"$FILE" ${FILENAME}.mp4
fi
if [ -f ${FILENAME}.mp4 ] ; then
./mvjf.sh ${FILENAME}.mp4 $OUTDIR
else
echo ERROR: mp4 not created
fi
./processed.py "$FILE"
encoded=true
fi
done < <($WORKDIR/toprocess.py)
$encoded && $WORKDIR/update_thumbs.shenc01.sh はencode.sh から呼び出されます。encode.shは、録画状態を監視する意味でも、頻繁に実行します。
一方で、remove_empty_dirs.shとdeleteold.py は、そこまで頻繁に実行する必要はありませんので、それぞれ定時(毎時0分と朝5時0分)に実行します。(追記:remove_empty_dirs.shは必須ではありません。Jellyfinの「番組」タブから手動で「シリーズを削除」できます。)
crontab -e#0 5 * * * $HOME/work/enc01.sh
*/4 * * * * $HOME/work/encode.sh >> $HOME/work/encode.log 2>&1
0 * * * * $HOME/work/remove_empty_dirs.sh >> $HOME/work/encode.log 2>&1 #不要?
0 5 * * * $HOME/work/deleteold.py >> $HOME/work/encode.log 2>&1
ここまで自動化をすすめると、録画予約から視聴まで、すべての操作をスマホだけで完結させることができるようになりました。
自家版ネットフリックスのような、自分だけのテレビ録画メディアサーバー環境が完成しました。
http://100.x.y.z:8888/ から録画予約し、http://100.x.y.z:8096/ から視聴します。100.x.y.zはサーバーのアドレスです(第2回、第3回、第6回)。



コメント