Weil ich mich noch mal weiter mit der Thematik befasst habe, dachte ich, ich schreibe direkt mal ein kleines HowTo, was vielleicht angepinnt werden kann, damit andere Nutzer von meinen Erfahrungen profitieren. Sollte ich an irgendeiner Stelle etwas zu unpräzise oder falsch erklären, dann korrigiere ich das gerne :). Da je nach Installationsweise die Dateipfade unterschiedlich sein können, gebe ich die immer nur relativ an. In den Skripten müssen die Dateipfade immer auf die eigene Situation angepasst werden.
Disclaimer
Benutzung auf eigene Gefahr! Eigentlich kann nichts schlimmes passieren, ausser dass ihr euer [definition='1','0']log[/definition] Verzeichnis zumüllt, wenn ihr das Skript nicht richtig anpasst, aber sicher ist sicher ;).
Das Problem
Ihr habt einen TVHeadend-Server und aus welchen Gründen auch immer, habt ihr den TVHeadend-Server neu installiert oder seid vielleicht auf eine Dockerinstallation gwechselt. Nachdem ihr alles eingerichtet habt, stellt ihr fest, die ganzen alten Aufnahmen, die vielleicht noch in /recordings waren oder die ihr dorthin zurückgesüpielt habt, tauchen nicht mehr unter Aufnahmen auf. TVHeadend bietet leider keine direkte Möglichkeit die Aufnahmen wieder zu integrieren. Wenn ihr die Aufnahmen nicht so in Kodi einbinden wollt, zeige ich euch jetzt zwei Wege, wie ihr eure Aufnahmen in eine neue TVHeadend installation integriert bekommt.
Hintergrund
Wie funktioniert das mit den Aufnahmen in TVHeadend? Wenn ihr eine Aufnahme plant, dann wird im Configordner von TVHeadend im Verzeichnis dvr/[definition='1','0']log[/definition]/ eine JSON erzeugt, mit jeder Menge Infos aus dem EPG und zur Aufnahme. Diese Datei enthällt auch den Speicherort und den Dateinamen der Aufnahme und ist der Schlüssel dazu, dass ein Video bei TVHeadend als Aufnahme auftaucht. Es reicht allerdings nicht einfach diese Datei in das Verzeichnis der neuen Installation zu kopieren. Da passiert genau gar nichts, weil TVHeandend diesen Ordner anscheinend in keiner Art und Weise überwacht oder scannt.
Die Lösung
Man kann über eine API per URL Aufnahmen in TVHeadend planen. Der Clou ist, man kann auch Aufnahmen in der Vergangenheit planen und diese API nutzen, um für Videos, die in einem Verzeichnis liegen zugehörige Dateien in dvr/[definition='1','0']log[/definition]/ von TVHeadend anlegen zu lassen. Das wurde im TVHeadend-Forum diskutiert und die hier vorgestellten Lösungen basieren auf Anpassungen von einem Skript des Users ullix tv https://tvheadend.org/boards/5/topic…3#message-29113.
Beide Lösungen sind in Pyhton geschrieben und sollten sowohl mit Python 2.7, als auch Python 3 funktionieren.
Lösung 1
Solltet ihr noch die alte config haben, dann könnt ihr die erste Lösung nutzen, die, soweit ich das überschaue, vom Resultat her absolut identisch ist, zu der Situation vorher in eurer alten Installation. Besser kanns nicht gehen :).
1. Speichert eure alten Logs in einen Ordner /storage/log-backup/ ab.
2. Überprüft, ob der Speicherort in den Dateien richtig ist. Bei einer nativen Installation steht da zum Beispiel als Verzeichnispfad /storage/recordings/..., aber wenn ihr eine Dockerinstallation habt, steht dort als Pfad nur /recordings/... Solltet ihr von der einen zur anderen Installationsart wechseln, dann müsst ihr das entsprechend in den Dateien anpassen.
3. Speichert einfach den Code zum Beispiel im Ordner /storage unter dem Dateinamen tvh_log_import.py ab.
4. Passt die api_url an, indem ihr euren TVHeadend-Benutzernamen, -Passwort und die IP Adresse des Servers eintragt.
4. Verbindet euch per SSH mit eurem Kodirechner und führt die Datei aus mit
5. Fertig :).
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#This script has the purpose to import old TVHeadend recordings in a new TVHeadend installation, when old logs exist. Old logs have to be in a folder given under logdir and filename in the logfile have to match files to be imported. This is adapted from the following skript:
#https://tvheadend.org/boards/5/topics/28252?r=29113#message-29113 by user ullix tv.
#Variables have to be adapted to personal situation.
import json, urllib, time, datetime, subprocess, os
#Input variables
logdir = "/storage/log-backup/"
api_url = "http://user:password@IP:9981/api/dvr/entry/create?conf="
#Functions
def importLog([definition='1','0']log[/definition], url):
"""Takes existing json [definition='1','0']log[/definition] file and sends a recording timer to the server."""
f = open([definition='1','0']log[/definition],"r")
mask = f.read()
new_mask = json.loads(mask)
api_string = url + json.dumps(new_mask)
filehandle = urllib.urlopen(api_string)
print "Server Answer:", filehandle.read()
#Iterating through [definition='1','0']log[/definition] files
files = os.listdir(logdir)
for [definition='1','0']log[/definition] in files:
importLog(logdir+[definition='1','0']log[/definition], api_url)
Alles anzeigen
Lösung 2
Solltet ihr nichts mehr außer euren Aufnahmen haben, dann könnt ihr die zweite Variante nutzen. Das Skript geht einfach euren Aufnahme Ordner durch und erzeugt aus den Informationen aus dem Dateinahmen eine sehr leere JSON. Zum erkennen, um was es geht, reicht das aber allemal und ihr könnt eure Aufnahmen wieder wie vorher abspielen. Das Skript geht davon aus, dass in eurem /recordings Ordner für jeden Film oder Serie ein Unterordner besteht. Falls das bei euch nicht der Fall ist, passt entweder die Ordnerstruktur an oder das Skript, je nachdem, was euch leichter von der Hand geht. Außerdem erwartet das Skript, dass eure Dateien am Anfang des Dateinamens einen Zeitstempel der Form YYYY-MM-DDTHH-MM haben. Hier gilt fast das gleiche wie zuvor. Solltet ihr keinen Zeitstempel haben oder das Ändern des Skriptes oder der Dateinamen ist euch zu aufwendig, dann nutzt das Skript einen Fallbackmodus und nutzt den Zeitstempel der cdate.
1. Speichert einfach den Code zum Beispiel im Ordner /storage unter dem Dateinamen tvh_rec_import.py ab.
2. Passt die api_url an, indem ihr euren TVHeadend-Benutzernamen, -Passwort und die IP Adresse des Servers eintragt.
3. Verbindet euch per SSH mit eurem Kodirechner und führt die Datei aus mit
4. Fertig :).
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#This script has the purpose to import old TVHeadend recordings in a new TVHeadend installation, when no old logs exist. It scans a folder with TVHeadend recordings and sets for each file a recording timer in TVHeadend. This is adapted from the following skript:
#https://tvheadend.org/boards/5/topics/28252?r=29113#message-29113 by user ullix tv.
#The storage folder is expected to have subfolders for each movie or series. My recordings have a filename scheme of "YYYY-MM-DDTHH-MM-xxx.ts" because I had %FT%R in the beginning of recording string. Variables have to be adapted to personal situation and scripts need either to be adapted or filenames to be renamed.
import json, urllib, time, datetime, subprocess, os
#Input variables
recdir = "/storage/recordings/"
api_url = "http://user:password@IP:9981/api/dvr/entry/create?conf="
mask = """{
"enabled": true,
"start": 1000,
"stop": 2000,
"channelname": "Imported",
"title": {
"ger": "my title"
},
"comment": "added by tvh_rec_import.py",
"files": [
{
"filename": "/full/path/to/videofile.ts"
}
]
}"""
mask = mask.replace("\n", "") # remove the line feeds
#Functions
def filedate2num(filepath):
"""Convert filename that starts with 'YYYY-MM-DDTHH-MM' to a unix timestamp; use cdate, i.e. last inode change time not creation, on error"""
try:
dt = int(time.mktime(datetime.datetime.strptime(filepath.split("/")[-1][0:15], "%Y-%m-%dT%H-%M").timetuple()))
except:
print "ERROR in filestr2num: file name doesn't start with 'YYYY-MM-DDTHH-MM.ts'. Use Inode Change Time instead."
dt = int(os.stat(filepath).st_ctime)
return dt
def videoDuration(video_file_path):
"""Get video duration in sec from a ffprobe call, using json output"""
#command is: ffprobe -loglevel quiet -print_format json -show_format /full/path/to/videofile
command = ["ffprobe", "-loglevel", "quiet", "-print_format", "json", "-show_format", video_file_path]
pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, err = pipe.communicate()
js = json.loads(out)
return int(float(js['format']['duration']) + 1.)
def importRecord(filepath, mask, url):
"""Creates a json file with the information from video file and sends a recording timer to the server."""
video_start = filedate2num(filepath)
new_mask = json.loads(mask)
new_mask['files'][0]['filename'] = filepath
new_mask['title']['ger'] = filepath.split("/")[-1][:-3]
new_mask['start'] = video_start
new_mask['stop'] = video_start + videoDuration(filepath)
print "New File Info: \n", json.dumps(new_mask, sort_keys = True, indent = 4)
api_string = url + json.dumps(new_mask)
filehandle = urllib.urlopen(api_string)
print "Server Answer:", filehandle.read()
#Iterating through recordings folder
directories = os.listdir(recdir)
for folder in directories:
for root, dirs, files in os.walk(recdir+folder):
for filename in files:
importRecord(recdir+folder+"/"+filename, mask, api_url)
Alles anzeigen
Update 26.08.2020:
Beim Debugging eines Problems von Nutzer Friedhofsblond ist mir aufgefallen, dass die ursprüngliche Version meines Skripts in Lösung 2 an einer Stelle ein Spezialfall für mich war.
Ursprünglich stand dort in der Erzeugung des json-Files:
Dabei sorgt [8:] dafür, dass das führende /storage entfernt wird. Dies habe ich in meiner Installation entfernt, weil ich TVH im Docker laufen habe und der /recordings Ordner direkt im Docker gemountet wird.
Für den vlt. üblicheren Fall der nativen Installation steht nun im Skript korrekterweise:
Solltet ihr auch Docker benutzen, dann könnt ihr die ursprüngliche Variante benutzen und solltet die Zahl entsprechend der Anzahl der führenden Zeichen anpassen. Zum Beispiel /mydisk/recordings benötigt dann [7:].