Linuxで録画予約を自動化するスクリプト書いた

2013年10月21日 Linux, スクリプト関連

2013/11/13 追記 :
recdgen.shを更新しました。iepg.listに特番の番号を放置した時、受信できない放送局の番組に番号がそのまま引き継がれて正常に録画ができなくなる可能性があったので、ch.listに登録の無い局に出会った時に該当番号を削除する処理を追加。
blog記事中のスクリプトは更新済みです。

2013/10/25 追記 :
recdgen.shに録画情報のチェック機能を追加しました。
翌週の放送がないときは録画しない、すでに放送された番組のデータが残っていたら最新のものに差し替える、録画情報がおかしい時は録画予約に反映しないなど。
その他、細かく修正を行なっています。詳細な変更点はgithubで確認してください。
blog記事中のスクリプトは更新済みです。

2013/10/24 追記 :
recdgen.sh、rectv.shを更新しました。
recdgen.shの変更点は、設定方法の変更とreadmeに記載されていた挙動とずれていた部分の修正。
rectv.shの変更点は、設定方法の変更です。recdgen.sh、rectv.shともにディレクトリの設定を変更しなくても実行権限をつけるだけでそれなりに動くようになりました。rectv.shのhddの設定は必要です。
blog記事中のスクリプトは更新済みです。

2013/10/23 追記 :
recdgen.shを更新しました。
変更点は、エラー処理の追加、無駄な処理の削除、iepg.listの末尾のアイテムを取りこぼす可能性があった処理の修正、問題箇所がふわっとわかるかもしれないエラーログ出力の追加です。
記事中のスクリプトは更新済みです。

PT3で録画サーバを構築して1年とちょっと。
これまでなんとなく手入力でcrontabに録画予約を登録していたんだけども、いい加減面倒になってきたので、この際だからと思って録画予約を自動化するスクリプトを書いてみたよ。
LinuxMint13で動くよ!!Shellscriptだよ!!!
これに関しては既存のソフトウェアなんかもたくさん書かれていて車輪の再発明もいいところなんだけど、既存のものはSQLを使ってたりして事前の準備が面倒すぎるので、お勉強のついで。

スクリプト2つと設定ファイル3つで動くよ!LAMPなしでいけちゃうよ!!やったね!!

スクリプトのダウンロードはgithub(右側 Download ZIP)ここ(rectv.zip)から

使い方はZIPファイルの中のReadme読んでください・・・
一応必要十分な情報は盛りこんであるはずだから。
なんというかReadme書ききったらもう気力が残ってない。マニュアルとか苦行すぎるw

あとこれはかなりどうでも良い事なんだけども、
recdgen.shのcrontabのjob登録のしかたがかなり乱暴なので、気になるならは自分で直してね。
そのままでも不都合なければそのままでも動くけども。

それからrecdgen.shの実行前には必ず crontab -l > filename してね。

やらないでcrontab飛んだー!!とか言われても知らんがなwwwwwwwwwwwとしか言えないから。
ちゃんと注意書きしたからね。

それからこれかなり大事な部分、
録画に失敗しても責任取らないし取れないから事前に十分な動作テストを行なってから使ってください。

一応スクリプトすぐ読めるように置いときます。

recdgen.sh

#!/bin/bash
# ディレクトリ設定
#usrdir="/home/`/usr/bin/whoami`/"
usrdir="`/usr/bin/dirname ${0}`/"
stgfile=${usrdir}recstg/
reclist=/tmp/
# エラー処理
pusherrmsg () {
  errtime=`date "+%Y/%m/%d %H:%M:%S"`
  case ${1} in
    1 ) echo "${errtime} : ディレクトリの設定が間違っているようです。末尾にスラッシュがあるか確認してください。" >> /tmp/recdgen_err.log && exit 1 ;;
    2 ) echo "${errtime} : ファイルの取得に失敗しました。iepg.list または ネットワークを確認してください。" ;;
    3 ) echo "${errtime} : 取得データに異常があります。iepg.listを確認してください。" ;;
    4 ) echo "${errtime} : 予約情報の生成に失敗したようです。設定ファイル、ディレクトリ設定、ネットワークの状態を確認してください。" ;;
    5 ) echo "${errtime} : 番組情報が存在しないため ${3} をリストから削除しました。放送が終了したか、存在しない番組です。" ;;
    6 ) echo "${errtime} : 受信できない番組です。 ${3} をリストから削除しました。" ;;
  esac >> /tmp/recdgen_err.log
  if [ -z "${3}" ]
  then
    rm -f ${2}iepg/*.* ${2}rec/*.*
    exit 1
  else
# 偽データ
    echo "MXテレビ" 1970 01 01 09:00 09:30 "無効タイトル"
  fi
}
iepgex () {
  cat "${1}iepg/iepg.php?PID=${2}"  | iconv -f cp932 -t utf-8 | grep -e "year" -e "month" -e "date" -e "start" -e "end" -e "program-title" -e "station" | sed -e "s/[a-z]*-|[a-z]*: |r|n|<|>//g" -e "s/ | /_/g"
}
getiepg () {
  sleep 2 && /usr/bin/wget -P "${1}iepg/" http://cal.syoboi.jp/iepg.php?PID=${2} || pusherrmsg 2 ${1}
}
lsupdate () {
  local lsd=${1}iepg.list
  case ${3} in
    del ) local iepgnum=`cat ${lsd} | sed -e "s/${2}//" -e "s/^$//"` ;;
    upd ) local iepgnum=`cat ${lsd} | sed -e "s/${2}/$((${2}+1))/"` ;;
  esac
  echo ${iepgnum} | sed -e "s/r|n//g" -e "s/ /n/g" > ${stgfile}iepg.list
}
# ディレクトリ設定チェック
ckstg=( "${usrdir}" "${stgfile}" "${reclist}" )
for (( i = 0; i < ${#ckstg[@]}; i++ ))
{
  echo ${ckstg[i]} | grep /$ || pusherrmsg 1
}
# 作業ディレクトリ
if [ ! -d "${reclist}rec" ]
then
  mkdir "${reclist}rec"
fi
if [ ! -d "${reclist}iepg" ]
then
  mkdir "${reclist}iepg"
fi
# ファイル取得
for (( i = 0; i < `cat "${stgfile}iepg.list" | wc -w`; i++ ))
{
  pgid+=( `cat "${stgfile}iepg.list" | head -$(( ${i} +1 )) | tail -1 | sed -e "s/r|n//g"` )
  getiepg ${reclist} ${pgid[i]}
# ファイル処理
  unset data dt tm len nxtm sp
  data=(`iepgex "${reclist}" "${pgid[i]}"`)
  while :
  do
    if [ "${data[1]}" -lt "1971" ]
    then
# 番組存在しない
      unset data
      data=( `pusherrmsg 5 ${reclist} ${pgid[i]}` )
      ngid+=( ${pgid[i]} )
      sp="nodata"
      break
    elif [ "${data[1]}${data[2]}${data[3]}" -lt `date +%Y%m%d` ]
    then
# データ古い時
      unset data
      lsupdate ${stgfile} ${pgid[i]} upd
      rm "${reclist}iepg/iepg.php?PID=${pgid[i]}"
      pgid[i]=$(( ${pgid[i]} + 1 ))
      getiepg ${reclist} ${pgid[i]}
      data=(`iepgex "${reclist}" "${pgid[i]}"`)
    else
      break
    fi
  done
# 休止確認
  nxtm=( `date -d "`date +%Y%m%d`" +%s` - `date -d "${data[1]}${data[2]}${data[3]}" +%s` )
  nxtm=`echo $(( $(( ${nxtm[@]} )) / 86400 )) | grep ^- | sed -e "s/^-//"`
  if [ -n "${nxtm}" ]
  then
    if [ "7" -le "${nxtm}" ]
    then
      sp="# "
    fi
  fi
  for (( j = 0; j < ${#data[@]}; j++ ))
  {
    if [ -z "${data[j]}" ]
    then
      pusherrmsg 3 ${reclist}
    fi
    case ${j} in
      0 ) ch=( `cat "${stgfile}ch.list" | grep ${data[j]}` ) ;;
      [4,5] ) tm+=( `date -d ${data[j]} "+%-H %-M"` ) ;;
      6 ) ttl=${data[j]} ;;
      * ) dt+=${data[j]} ;;
    esac
  }
  if [ -z "${ch[1]}" ]
  then
# 放送局遠い
    ngid+=( ${pgid[i]} )
    sp="nodata"
    pusherrmsg 6 ${reclist} ${pgid[i]}
  fi
  wk=`date -d ${dt} "+%w"`
# 開始終了時刻確認
  st=$(( $(( ${tm[0]} * 60 )) + ${tm[1]} ))
  if [ ${st} -eq 0 ]
  then
      ed=$(( $(( ${tm[2]} * 60 )) + ${tm[3]} ))
  else
    case ${tm[2]} in
      0 ) ed=$(( $(( 24 * 60 )) + ${tm[3]} )) ;;
      * ) ed=$(( $(( ${tm[2]} * 60 )) + ${tm[3]} )) ;;
    esac
  fi
# 録画時間確認
  len=$(( ${ed} - ${st} - 1 ))
  if [ ${len} -lt 9 ]
  then
    len=$(( ${ed} - ${st} + 2 ))
    if [ ${st} -eq 0 ]
    then
      tm[0]=23
      tm[1]=$(( 6${tm[1]} - 1 ))
    else
      tm[1]=$(( ${tm[1]} - 1 ))
    fi
  fi
# 個別job生成
  case ${sp} in
    nodata ) : > ${reclist}rec/rec${pgid[i]}.list ;;
    * ) echo  ${sp}${tm[1]} ${tm[0]} '*' '*' ${wk} "${usrdir}rectv.sh" ${ch[1]} ${len} ""${ttl}"" ${pgid[i]} > ${reclist}rec/rec${pgid[i]}.list ;;
  esac
}
for (( i = 0; i < ${#ngid[@]}; i++ ))
{
  lsupdate ${stgfile} ${ngid[i]} del
}
# 個別job生成確認
ckjobdata=`cat ${reclist}rec/*.*`
if [ -z "${ckjobdata}" ]
then
  pusherrmsg 4 ${reclist}
else
# job生成
  cat ${reclist}rec/*.* "${stgfile}routine.list" | /usr/bin/sort -k 5 > "${reclist}rec.list"
fi
# crontab登録
/usr/bin/crontab "${reclist}rec.list"
# 作業ファイル削除
rm ${reclist}iepg/*.* ${reclist}rec/*.*

rec、iepgディレクトリがなかったらrec、iepgディレクトリを作って、
iepg.listの内容を元にしょぼいカレンダーからiepgファイルを取得、
iepgファイルから抜き出したデータを処理して、処理済みデータとroutine.listを結合。
cronjobを書きだして登録。という流れのスクリプト。
一応ZIPにサンプルのch.list入れといたけど地域ごとに違ったりするので自分で作ってね。
iepg.listとch.list無いとただcrontabを吹き飛ばすだけの楽しいいたずらスクリプトになってしまうので気を付けたほうがいいよ。
エラーが出たらとりあえずログを/tmp/以下に保存して止まるようになったよ。

これで録画予約は完了。
後は録画が実行されるのを祈って待つだけ。

rectv.sh

#!/bin/bash
# $1 -- ch_num
# $2 -- rec_min
# $3 -- title
#stgfile="/home/`/usr/bin/whoami`/rectv/stgdir/"
stgfile="`/usr/bin/dirname ${0}`/recstg/"
# hdd-id
d1="hdd-id01"
d2="hdd-id02"
g="grep"
dt=`date +%y%m%d%H%M%S`
mt=`echo $(( 60 * ${2} ))`
case "${1}" in
  "103" | "910" ) sid=${1} ;;
  * ) sid=hd ;;
esac
flag=`cat "${stgfile}drive.list"`
case ${flag} in
  ${d1} ) ;;
  ${d2} ) d2=${d1}
  d1=${flag} ;;
  * ) flag=${d1} ;;
esac
if [ ! -d /media/${d1} ]
then
  d1=${d2}
  d2=${flag}
fi
u="9[6-9]%|100%"
dck=`df -h | $g ${d1} | $g ${u} | wc -l`
case ${dck} in
	1 ) df -h | $g ${d2} | $g ${u} && exit
	dr=${d2} ;;
	* ) dr=${d1} ;;
esac
cd /media/${dr}/recdir/ || exit
/usr/local/bin/recpt1 --b25 --strip --sid ${sid} ${1} ${mt} ${1}_${3}_${dt}.ts
echo "${dr}" > "${stgfile}drive.list"

実行部分。
録画用HDDが存在するか、残量が必要なだけあるかを確認して録画を実行、
ランダム秒スリープ後、iepg.listを更新。という流れ。

これで相互にデータを共有しながら手作業無しで録画予約が行われる。
容量の許す限り指定番組を録り続ける。

やったね!!録画サーバにとってのオペレーターの存在価値がほぼゼロになったよ!!!

コメントは受け付けていません。