EPGStation での録画ルール。
最初のうちは TS ファイルも残すルールで運用していたが、エンコード処理が問題がないので TS ファイルを自動削除するようにした。
さて、ポリシー変更以前に設定したルールについても、TSファイルを自動削除するように変更したい。GUI でチマチマやるのではなく、どうしたら自動化できるかな?
環境
- Version of EPGStation: 2.6.20
- Version of Mirakurun: 3.9.0-rc.2
- OS:Ubuntu Linux 20.04
- Architecture: x64
「PLEX PX-Q3PE4 で docker-mirakurun-epgstation を使いたい」
https://qiita.com/nanbuwks/items/640ee4405e1fdd2ca497
こちらで構築したものです。
WebAPI
こういった処理は EPGStation では WebAPI を使って処理するらしい。
WebAPIのドキュメントはどこかな?
こちらによると、
EPGStation が提供する WebAPI は express-openapi によって提供される 、OpenAPI (Swagger) 準拠の RESTful API です
利用可能な全ての API は Swagger UI 上で確認可能です
http://:/api/debug
早速URLをブラウザで見てみると以下のように確認できた。
WebAPI が反応するかチェック
まずは WebAPI のアクセスができるかどうかチェック。
「archlinuxを定期的に再起動する(録画中ならやめる)」
https://qiita.com/hirmr/items/9c63bc7672032c5bf050
で使っているテクをそのまま使い、curl で録画中かどうかのチェックを行いました。
$ curl http://192.168.42.100:8888/api/recording?isHalfWidth=true
返ってきた返事
{"records":[{"id":6139,"channelId":400101,"startAt":1674367800000,"endAt":1674370800000,"name":"BS世界のドキュメンタリー「マミー・フット!おばあちゃんはサッカー選手」[二][字][再]","isRecording":true,"isEncoding":false,"isProtected":false,"ruleId":62,"programId":40010127876,"description":"シニア女性たちによるフランス対南アフリカのサッカー特別試合。珍しい取り組みの舞台裏に密着。言葉や文化が異なっても、仲間とともに人生を楽しむ気持ちは変わらない。","extended":"◇番組内容\nシニア女性たちによるフランス対南アフリカのサッカー特別試合。その舞台裏に密着する。フランスのメンバーはほとんどがサッカー経験なしだが新しいことへの挑戦に張り切る。一方の南アフリカチームは女性がショートパンツでサッカーをすることへの偏見をはねのけて練習に励んできた。試合本番。言葉や文化の違いを超えて、仲間とともに人生を楽しむ気持ちを共有する。 原題:MAMIES FOOT(フランス 2020年)\n◇制作\n~2020年 フランス Old Stories Production/PV Senioriales Production制作~","rawExtended":{"番組内容":"シニア女性たちによるフランス対南アフリカのサッカー特別試合。その舞台裏に密着する。フランスのメンバーはほとんどがサッカー経験なしだが新しいことへの挑戦に張り切る。一方の南アフリカチームは女性がショートパンツでサッカーをすることへの偏見をはねのけて練習に励んできた。試合本番。言葉や文化の違いを超えて、仲間とともに人生を楽しむ気持ちを共有する。 原題:MAMIES FOOT(フランス 2020年)","制作":"~2020年 フランス Old Stories Production/PV Senioriales Production制作~"},"genre1":8,"subGenre1":7,"genre2":0,"subGenre2":2,"genre3":0,"subGenre3":5,"videoType":"mpeg2","videoResolution":"1080i","videoStreamContent":1,"videoComponentType":179,"audioSamplingRate":48000,"audioComponentType":3,"thumbnails":[],"videoFiles":[{"id":10632,"name":"TS","filename":"2023年01月22日15時10分00秒-BS世界のドキュメンタリー「マミー・フット!おばあちゃんはサッカー選手」[二][字][再].m2ts","type":"ts","size":0}]}],"total":1}
返事が返ってきたので WebAPI へのアクセスは問題無いようです。
ルール情報を取得してみる
http://<サーバアドレス>/api/rules でルール情報を取得することができます。
パラメータ | ||
---|---|---|
offset | オフセット | Default:0 |
limit | リミット | Default:24 |
type | 予約情報取得タイプ | Available values : all, normal, conflict, skip, overlap |
keyword | キーワード |
ということで、適当にルール3つをリクエスト
$ curl http://192.168.42.100:8888/api/rules?offset=10\&limit=3\&type="all"\&keyword=""
とすると、
{"rules":[{"id":11,"isTimeSpecification":false,"searchOption":{"keyCS":false,"keyRegExp":false,"name":true,"description":true,"extended":false,"ignoreKeyCS":false,"ignoreKeyRegExp":false,"ignoreName":false,"ignoreDescription":false,"ignoreExtended":false,"GR":false,"BS":false,"CS":false,"SKY":false,"isFree":false,"keyword":"ガリレオ","genres":[{"genre":3,"subGenre":0}],"times":[{"week":127}]},"reserveOption":{"enable":true,"allowEndLack":true,"avoidDuplicate":false},"encodeOption":{"mode1":"H.264","encodeParentDirectoryName1":"recorded","isDeleteOriginalAfterEncode":true},"reservesCnt":0},{"id":12,"isTimeSpecification":false,"searchOption":{"keyCS":false,"keyRegExp":false,"name":true,"description":true,"extended":false,"ignoreKeyCS":false,"ignoreKeyRegExp":false,"ignoreName":false,"ignoreDescription":false,"ignoreExtended":false,"GR":false,"BS":false,"CS":false,"SKY":false,"isFree":false,"keyword":"NHKスペシャル","genres":[{"genre":8,"subGenre":0}],"times":[{"week":127}]},"reserveOption":{"enable":true,"allowEndLack":true,"avoidDuplicate":false},"encodeOption":{"mode1":"H.264","encodeParentDirectoryName1":"recorded","isDeleteOriginalAfterEncode":true},"reservesCnt":6},{"id":13,"isTimeSpecification":false,"searchOption":{"keyCS":false,"keyRegExp":false,"name":true,"description":true,"extended":false,"ignoreKeyCS":false,"ignoreKeyRegExp":false,"ignoreName":false,"ignoreDescription":false,"ignoreExtended":false,"GR":false,"BS":false,"CS":false,"SKY":false,"isFree":false,"keyword":"はたらく魔王さま","genres":[{"genre":7,"subGenre":0}],"times":[{"week":127}]},"reserveOption":{"enable":true,"allowEndLack":true,"avoidDuplicate":false},"encodeOption":{"mode1":"H.264","encodeParentDirectoryName1":"recorded","isDeleteOriginalAfterEncode":true},"reservesCnt":0}],"total":185}
取得できました
python で同様に取得してみます。requests モジュールを使いました。
import requests
import json
url = "http://192.168.42.100:8888/api/rules?offset=1&limit=1&type=all&keyword="
response = requests.get(url)
jsonData = response.json()
for jsonObj in jsonData["rules"]:
jsonObj["encodeOption"]={"mode1":"H.264","encodeParentDirectoryName1":"recorded","isDeleteOriginalAfterEncode":"False"}
print(json.dumps(jsonObj,indent=4))
print(jsonObj["encodeOption"]["isDeleteOriginalAfterEncode"])
この python がうまく動いたので、ルールを修正した JSON に直すようにしたのが以下です。
import requests
import json
url = "http://192.168.42.100:8888/api/rules?offset=1&limit=100&type=all&keyword="
response = requests.get(url)
jsonData = response.json()
for jsonObj in jsonData["rules"]:
if ("encodeOption" not in jsonObj):
print("no encodeOption:",jsonObj["id"])
jsonObj["encodeOption"]={"mode1":"H.264","encodeParentDirectoryName1":"recorded","isDeleteOriginalAfterEncode":True}
if (True != jsonObj["encodeOption"]["isDeleteOriginalAfterEncode"]):
print("isDeleteOriginalAfterEncode is not True:",jsonObj["id"])
jsonObj["encodeOption"]["isDeleteOriginalAfterEncode"]=True
# print(json.dumps(jsonObj,indent=4))
print(jsonObj["encodeOption"]["isDeleteOriginalAfterEncode"])
この修正した JSON を登録するようにすればいいですね。
予約修正
先程は GET メソッドで JSON を取得しましたが、それを修正した JSON は PUT メソッドを使って登録する必要があります。ルール修正のAPIが少し難しかったので、先に予約修正のAPIを curl でテストしてみました。以下の curl は、先の http://<hostname>:<port>/api/debug
画面にて Try it out
を選ぶと生成することができます。
予約を取得
$ curl -X 'GET' 'http://192.168.42.100:8888/api/reserves/7444?isHalfWidth=false' -H 'accept: application/json'
{"id":7444,"isSkip":false,"isConflict":false,"isOverlap":false,"allowEndLack":true,"isTimeSpecified":false,"isDeleteOriginalAfterEncode":false,"channelId":3273601024,"startAt":1674986400000,"endAt":1674988200000,"name":"NHKニュース7[二][字]","programId":327360102426083,"description":"「確かなニュース、いつでも どこでも」 きょうの日本、世界の今 一歩先へ、一歩深く テレビでもスマホでも このニュースを届けたい","extended":"◇番組内容\n「確かなニュース、いつでも どこでも」 きょうの日本、世界の今 一歩先へ、一歩深く テレビでもスマホでも このニュースを届けたい\n◇出演者\n【キャスター】高井正智,川﨑理加,深川仁志,【気象キャスター】向笠康二郎","rawExtended":{"番組内容":"「確かなニュース、いつでも どこでも」 きょうの日本、世界の今 一歩先へ、一歩深く テレビでもスマホでも このニュースを届けたい","出演者":"【キャスター】高井正智,川﨑理加,深川仁志,【気象キャスター】向笠康二郎"},"genre1":0,"subGenre1":0,"genre2":0,"subGenre2":1,"genre3":1,"subGenre3":0,"videoType":"mpeg2","videoResolution":"1080i","videoStreamContent":1,"videoComponentType....
これのうち、allowEndLack さえ含まれていれば、変更データは一部分だけでOKでした。以下は元々の録画予約に含まれていない encodeOption を追加したコマンドです。
$ curl -X 'PUT' 'http://192.168.42.100:8888/api/reserves/7444' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{ "allowEndLack": true, "encodeOption": {"mode1": "H.264","encodeParentDirectoryName1": "recorded","isDeleteOriginalAfterEncode": true}}'
返事は以下のように返ってきました。
{"code":201,"message":"ok"}
ルール修正
ルール修正については、修正する一部だけで試したらエラーとなり、けっこうしっかりデータを作っておかないといけない感じです。基本的に取得したルールのJSONデータを書き換えて戻すようにしています。
curl でテスト
ルール取得
$ curl -X 'GET' 'http://192.168.42.100:8888/api/rules/16' -H 'accept: application/json'
{"id":16,"isTimeSpecification":false,"searchOption":{"keyCS":false,"keyRegExp":false,"name":true,"description":true,"extended":false,"ignoreKeyCS":false,"ignoreKeyRegExp":false,"ignoreName":false,"ignoreDescription":false,"ignoreExtended":false,"GR":false,"BS":false,"CS":false,"SKY":false,"isFree":false,"keyword":"ベストヒットUSA ","channelIds":[400151],"genres":[{"genre":4,"subGenre":1}],"times":[{"week":127}]},"reserveOption":{"enable":true,"allowEndLack":true,"avoidDuplicate":false}}n
ルールに encodeOption を加えて書き換え
$ curl -X 'PUT' 'http://192.168.42.100:8888/api/rules/16' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"id":16,"isTimeSpecification":false,"searchOption":{"keyCS":false,"keyRegExp":false,"name":true,"description":true,"extended":false,"ignoreKeyCS":false,"ignoreKeyRegExp":false,"ignoreName":false,"ignoreDescription":false,"ignoreExtended":false,"GR":false,"BS":false,"CS":false,"SKY":false,"isFree":false,"keyword":"ベストヒットUSA ","channelIds":[400151],"genres":[{"genre":4,"subGenre":1}],"times":[{"week":127}]},"reserveOption":{"enable":true,"allowEndLack":true,"avoidDuplicate":false},"encodeOption":{"mode1":"H.264","encodeParentDirectoryName1":"recorded","isDeleteOriginalAfterEncode":true}}'
返事
{"code":200}
Pythonプログラム
requests モジュールでは JSON の PUT がうまくいかなかったので、 urllib.request を使っています。
urllib.request が標準モジュールであることと、エラーメッセージがわかりやすかったので今後もこっちのほうがいいかな。
#import requests
import urllib.request
import json
# example json data={"id":16,"isTimeSpecification":False,"searchOption":{"keyCS":False,"keyRegExp":False,"name":True,"description":True,"extended":False,"ignoreKeyCS":False,"ignoreKeyRegExp":False,"ignoreName":False,"ignoreDescription":False,"ignoreExtended":False,"GR":False,"BS":False,"CS":False,"SKY":False,"isFree":False,"keyword":"ベストヒットUSA ","channelIds":[400151],"genres":[{"genre":4,"subGenre":1}],"times":[{"week":127}]},"reserveOption":{"enable":True,"allowEndLack":True,"avoidDuplicate":False},"encodeOption":{"mode1":"H.264","encodeParentDirectoryName1":"recorded","isDeleteOriginalAfterEncode":True}}
# limit を適宜変更のこと
urlget = "http://192.168.42.100:8888/api/rules?offset=0&limit=1000&type=all&keyword="
urlput = "http://192.168.42.100:8888/api/rules/"
# ルール一覧を得る
response = urllib.request.urlopen(urlget)
jsonData = json.load(response)
# ルールごとにループ
for jsonObj in jsonData["rules"]:
# encodeOption が指定されていなかった場合
if ("encodeOption" not in jsonObj):
print("no encodeOption:",jsonObj["id"])
# encodeOption を子要素と共に追加
jsonObj["encodeOption"]={"mode1":"H.264","encodeParentDirectoryName1":"recorded","isDeleteOriginalAfterEncode":True}
# 変更したルールを変更登録
url=urlput+str(jsonObj["id"])
headers = {"Content-Type": "application/json"}
# print (json.dumps(s))
res=urllib.request.Request(url,json.dumps(jsonObj).encode(),headers,method="PUT")
with urllib.request.urlopen(res) as f:
pass
print(f.status,end="")
if (200==f.status):
print(" OK")
else:
print(" Error")
print(f.reason)
print(json.dumps(res.json()))
# encodeOption が指定されているがisDeleteOriginarlAfterEncode が True でなかった場合
if (True != jsonObj["encodeOption"]["isDeleteOriginalAfterEncode"]):
print("isDeleteOriginalAfterEncode is not True:",jsonObj["id"])
# True に変更
jsonObj["encodeOption"]["isDeleteOriginalAfterEncode"]=True
# 変更したルールを変更登録
url=urlput+str(jsonObj["id"])
headers = {"Content-Type": "application/json"}
# print (json.dumps(s))
res=urllib.request.Request(url,json.dumps(jsonObj).encode(),headers,method="PUT")
with urllib.request.urlopen(res) as f:
pass
print(f.status,end="")
if (200==f.status):
print(" OK")
else:
print(" Error")
print(f.reason)
print(json.dumps(res.json()))
ちょっと手間取ったところとして、jsonObj は Python 内部では辞書型で持っているのですが、それをjson.dumps()で文字列に変えて更に encode() でバイト文字列にする必要がありました。
そのうえ、辞書型での Bool 値と json の Bool 値の表記が異なって ( True/true , False/false ) いるのをそらなかったので、最初戸惑ってしまいました。
実行
$ python3 apitest.py
no encodeOption: 35
200 OK
no encodeOption: 40
200 OK
no encodeOption: 41
200 OK
no encodeOption: 42
200 OK
isDeleteOriginalAfterEncode is not True: 44
200 OK
isDeleteOriginalAfterEncode is not True: 45
200 OK
no encodeOption: 46
.
.
.
isDeleteOriginalAfterEncode is not True: 139
200 OK
no encodeOption: 143
200 OK
isDeleteOriginalAfterEncode is not True: 173
200 OK
うまくいきました。
録画ルール変更後の予約の扱い
録画ルールを変更しても、録画ルールから生成された予約が約一週間先まであります。録画ルールを変更する前に生成されたこの予約について、録画ルールを変更したら予約の内容はどうなるのでしょうか?
GUIで確かめたら、録画ルールを変更する以前に生成された予約の内容は、変更が反映されてました。予約も変更が必要かな? と思ってましたがそれは必要ないということになります。