19.09.2018, 16:59
Hallo zusammen,
da ich mit meinen verschiedenen easyVDR-Versionen immer wieder von eurem KowHow partizipiert habe,
möchte ich der Community auch mal was zur Verfügung stellen. (... hoffe, hier ist der richtige Platz dafür)
Da wir mittlerweile mehrere Smart-TV's im Haus verteilt haben, wollte ich die Aufnahmen für den WaF gut lesbar mit dem minidlna servieren.
Bei der Lösung, die mir Herr G. ausgespuckt hat, war mir die Einarbeitungszeit zu lange, daher habe ich mir letztes Wochenende quick & dirty ein Python (2) Script gebastelt.
- Geht bestimmt auch eleganter -
Voraussetzung:
Es darf nur eine *.TS Datei im Aufnahmeverzeichnis vorhanden sein. Also muss die max. Größe für die Aufnahmen im VDR entsprechend hoch eingestellt sein.
Das Script sollte bei einem Standard-easyVDR 3.x Setup OOTB laufen und macht folgendes:
- Verzeichnis für den minidlna-Server anlegen
- Durchlaufen der Aufnahme-Pfades
- Auslesen des Titel und Untertitel aus der VDR info Datei
- Im Zielverzeichnis für den minidlna-Server Unterverzeichnisse und Symlinks (zu 0001.ts) mit "schönen", langen Namen aus Titel und Untertitel anlegen
Mittels Cron-Job lasse ich es alle 10 Min. laufen.
Was nicht sauber geht:
Wenn z.B. die Symlinks im Verzeichnis /xxx/aufnahmen liegen und der minidlna auf dieses Verzeichnis schaut, kommt er anscheinend etwas durcheinenader und zeigt nach einem "Refresh" in den Cilents nur noch "Ordner Durchsuchen" an (Wo dann auch alles wieder zu finden ist).
Das liegt wahrscheinlich daran, dass das Script die Verzeichnis-Struktur bei jedem Durchlauf komplett neu erstellt und ist bei mir bisher nicht mehr aufgetreten, seit ich den minidlna auf das übergeordnete Verzeichnis schauen lasse, also: /xxx
Wenn der minidlna-Server erstmal dem Symlink gefolgt ist, macht es offensichtlich nichts aus, wenn man ihm den Symlink während des Streamens unter dem Hintern weg zieht, zumindest sind die Streams beim Testen nicht zusammengebrochen.
da ich mit meinen verschiedenen easyVDR-Versionen immer wieder von eurem KowHow partizipiert habe,
möchte ich der Community auch mal was zur Verfügung stellen. (... hoffe, hier ist der richtige Platz dafür)
Da wir mittlerweile mehrere Smart-TV's im Haus verteilt haben, wollte ich die Aufnahmen für den WaF gut lesbar mit dem minidlna servieren.
Bei der Lösung, die mir Herr G. ausgespuckt hat, war mir die Einarbeitungszeit zu lange, daher habe ich mir letztes Wochenende quick & dirty ein Python (2) Script gebastelt.
- Geht bestimmt auch eleganter -
Voraussetzung:
Es darf nur eine *.TS Datei im Aufnahmeverzeichnis vorhanden sein. Also muss die max. Größe für die Aufnahmen im VDR entsprechend hoch eingestellt sein.
Das Script sollte bei einem Standard-easyVDR 3.x Setup OOTB laufen und macht folgendes:
- Verzeichnis für den minidlna-Server anlegen
- Durchlaufen der Aufnahme-Pfades
- Auslesen des Titel und Untertitel aus der VDR info Datei
- Im Zielverzeichnis für den minidlna-Server Unterverzeichnisse und Symlinks (zu 0001.ts) mit "schönen", langen Namen aus Titel und Untertitel anlegen
Mittels Cron-Job lasse ich es alle 10 Min. laufen.
Was nicht sauber geht:
Wenn z.B. die Symlinks im Verzeichnis /xxx/aufnahmen liegen und der minidlna auf dieses Verzeichnis schaut, kommt er anscheinend etwas durcheinenader und zeigt nach einem "Refresh" in den Cilents nur noch "Ordner Durchsuchen" an (Wo dann auch alles wieder zu finden ist).
Das liegt wahrscheinlich daran, dass das Script die Verzeichnis-Struktur bei jedem Durchlauf komplett neu erstellt und ist bei mir bisher nicht mehr aufgetreten, seit ich den minidlna auf das übergeordnete Verzeichnis schauen lasse, also: /xxx
Wenn der minidlna-Server erstmal dem Symlink gefolgt ist, macht es offensichtlich nichts aus, wenn man ihm den Symlink während des Streamens unter dem Hintern weg zieht, zumindest sind die Streams beim Testen nicht zusammengebrochen.
Code:
#! /usr/bin/python
import sys
import os
import errno
import string
import shutil
strAppDir = os.path.dirname(os.path.realpath(__file__)) + "/"
strBaseDirRecordings = "/media/easyvdr01/video0"
strBaseDirDLNA = "/media/easyvdr01/dlnarecordings/aufnahmen"
strExtensionStream = "TS"
strExtensionRecFolder = "rec"
strArrFoldersExExclude = ["/media/easyvdr01/video0/ausgelagerteaufnahmen"]
strArrFoldersExExcludeTemp = []
strArrSubtitleNoSwap = ["Fernsehserie", "Fernsehfilm", "Moderation:"]
strReplaceTuples4UserFriendlyOut = [("_", " "),
("~", "-"),
("#2E", "."),
("#3A", ":"),
("#3F", "?"),
("/", "-"),
("\xc3\x9f", "ss")]
#\xc3\x9f = sZ
def check_dirsexist(strPath2Check):
if not os.path.exists(strPath2Check):
os.makedirs(strPath2Check)
return True
def cleanup_storage(strPath2Clean, boolWithSubdirs = False):
for dir_name, subdir_list, file_list in os.walk(strPath2Clean):
if boolWithSubdirs == False:
for filename in file_list:
os.remove(os.path.join(strPath2Clean, filename))
else:
for filename in file_list:
os.remove(os.path.join(dir_name, filename))
if dir_name <> strPath2Clean:
shutil.rmtree(dir_name)
return True
def walklevel(some_dir, level=1):
some_dir = some_dir.rstrip(os.path.sep)
assert os.path.isdir(some_dir)
num_sep = some_dir.count(os.path.sep)
for root, dirs, files in os.walk(some_dir):
yield root, dirs, files
num_sep_this = root.count(os.path.sep)
if num_sep + level <= num_sep_this:
del dirs[:]
def string_included(stringToSearchIn, ArrayWithSubStrings):
returnVal = False
for curStr in ArrayWithSubStrings:
if curStr in stringToSearchIn:
returnVal = True
break
return returnVal
def make_userfriend(dirnameInput, IsArray=False):
if IsArray == True:
dirnameOutput = []
for modThis in dirnameInput:
for stringTuples in strReplaceTuples4UserFriendlyOut:
replaceThis = stringTuples[0]
replaceWith = stringTuples[1]
modThis = modThis.replace(replaceThis, replaceWith)
dirnameOutput.append(modThis.replace(replaceThis, replaceWith))
else:
dirnameOutput = dirnameInput
for stringTuples in strReplaceTuples4UserFriendlyOut:
replaceThis = stringTuples[0]
replaceWith = stringTuples[1]
dirnameOutput = dirnameOutput.replace(replaceThis, replaceWith)
return dirnameOutput
def read_vdrinfo(strFileFullPath):
arrTemp = []
lnCount = 0
if os.path.exists(strFileFullPath) == True:
inputFile = open(strFileFullPath,'r')
strLines = [line.rstrip('\n') for line in inputFile]
inputFile.close()
for line in strLines:
lnCount = lnCount + 1
if line <> "":
if lnCount == 3:
strSplitLine = [lineA.rstrip(' ') for lineA in line]
if strSplitLine[0] == "T":
arrTemp.append(line.replace("T ", "", 1))
if lnCount == 4:
strSplitLine = [lineA.rstrip(' ') for lineA in line]
if strSplitLine[0] == "S":
arrTemp.append(line.replace("S ", "", 1))
return arrTemp
def create_symlink(strRecDir, strTargetDir, IsSerie=False, MultiRecs=False):
symlinkName = ""
for dir_name_src, subdir_list_src, file_list_src in walklevel(strRecDir):
file_list_src.sort()
if dir_name_src <> strRecDir:
if MultiRecs == True:
machNix = 1
symlinkName = ""
if os.path.splitext(dir_name_src)[1][1:] == strExtensionRecFolder:
arrInfo = make_userfriend(read_vdrinfo(os.path.join(dir_name_src, "info")), True)
# an letzter stelle des Namens kommt das aufnahmeverzeichnis (zur sicherheit, um eindeutigkeit zu behalten)
strDateOfRecording = os.path.splitext(os.path.basename(dir_name_src).replace(".rec", ""))[0]
if len(arrInfo) == 1:
symlinkName = arrInfo[0] + " " + strDateOfRecording
if len(arrInfo) == 2:
NoSwap = string_included(arrInfo[1], strArrSubtitleNoSwap)
if IsSerie == False:
symlinkName = arrInfo[0] + " (" + arrInfo[1] + ") " + strDateOfRecording
else:
if NoSwap == False:
symlinkName = arrInfo[1] + " (" + arrInfo[0] + ") " + strDateOfRecording
else:
symlinkName = arrInfo[0] + " (" + arrInfo[1] + ") " + strDateOfRecording
if len(symlinkName) >0:
symlinkName = symlinkName + ".ts"
try:
os.unlink(os.path.join(strTargetDir, symlinkName))
except OSError, e:
machNix = 1
try:
os.symlink(os.path.join(dir_name_src, "00001.ts"), os.path.join(strTargetDir, symlinkName))
except OSError, e:
print "LINK Error ", e.errno
machNix = 1
def GetRecDirs(strFindInDir):
NumOfDirs = 0
ArrRecDirs =[]
SubDirString = ""
for PathNameRecordings, SubDirListRecordings, FileListRecordings in walklevel(strFindInDir):
SubDirListRecordings.sort()
for SubDir in SubDirListRecordings:
if os.path.splitext(SubDir)[1][1:] == strExtensionRecFolder:
NumOfDirs = NumOfDirs + 1
SubDirString = os.path.join(SubDirString, SubDir)
else:
SubDirString = os.path.join(SubDirString, SubDir)
NumOfDirs = NumOfDirs + 1
ArrRecDirs.append(SubDirString)
return ArrRecDirs
def GetRecDirs2(strFindInDir):
NumOfDirs = 0
ArrRecDirs =[]
SubDirString = ""
for PathNameRecordings, SubDirListRecordings, FileListRecordings in walklevel(strFindInDir):
SubDirListRecordings.sort()
for SubDir in SubDirListRecordings:
if os.path.splitext(SubDir)[1][1:] == strExtensionRecFolder:
NumOfDirs = NumOfDirs + 1
else:
NumOfDirs = NumOfDirs + 1
ArrRecDirs.append(SubDir)
return ArrRecDirs
def CountSubDirs(strCountInDir):
NumSubDirs = 0
NumRecDirs = 0
for PathNameRecordings, SubDirListRecordings, FileListRecordings in walklevel(strCountInDir):
for SubDir in SubDirListRecordings:
if os.path.splitext(SubDirListRecordings[0])[1][1:] == strExtensionRecFolder:
NumRecDirs = NumRecDirs + 1
else:
NumSubDirs = NumSubDirs + 1
return NumSubDirs, NumRecDirs, len(FileListRecordings)
def WalkRecordDirs(strSourceDir, strTargetDir, IsSeriesDir=False, SpecialTreatment=False):
for PathNameRecordings, SubDirListRecordings, FileListRecordings in walklevel(strSourceDir):
SubDirListRecordings.sort()
if PathNameRecordings <> strSourceDir:
if not string_included(PathNameRecordings,strArrFoldersExExclude):
if not string_included(PathNameRecordings,strArrFoldersExExcludeTemp):
strDirTarg = os.path.join(strTargetDir, make_userfriend(os.path.basename(PathNameRecordings)))
NumSubDirs, NumRecDirs, NumFiles = CountSubDirs(PathNameRecordings)
if NumSubDirs == 0 and NumRecDirs == 1 and NumFiles > 1:
#aufnahme!, symlink erzeugen
create_symlink(PathNameRecordings, strTargetDir, IsSeriesDir)
elif NumSubDirs == NumRecDirs and NumFiles == 0:
#serien-verzeichnis!, weiter suchen
if SpecialTreatment == True:
if NumSubDirs == 1 and NumRecDirs == 1 and NumFiles == 0:
#aufnahme!, symlink erzeugen
RecDirs = GetRecDirs(PathNameRecordings)
#print "RecDirs ", IsSeriesDir, strTargetDir
if len(RecDirs) == 1:
create_symlink(os.path.join(PathNameRecordings, RecDirs[0]), strTargetDir, IsSeriesDir)
if NumSubDirs == 1 and NumRecDirs > 1 and NumFiles == 0:
#mehrere aufnahmen!, symlink erzeugen
print " ", PathNameRecordings
RecDirs = GetRecDirs(PathNameRecordings)
print "RecDirs ", IsSeriesDir, strTargetDir
if len(RecDirs) == 1:
create_symlink(os.path.join(PathNameRecordings, RecDirs[0]), strTargetDir, IsSeriesDir, True)
if NumSubDirs > 1 and NumRecDirs > 1 and NumFiles == 0:
#mehrere aufnahmen, mehrere Unterverzeichnisse!, symlinks erzeugen
RecDirs = GetRecDirs2(PathNameRecordings)
for RecSubDir in RecDirs:
create_symlink(os.path.join(PathNameRecordings, RecSubDir), strTargetDir, IsSeriesDir, True)
else:
check_dirsexist(strDirTarg)
WalkRecordDirs(PathNameRecordings, strDirTarg, True)
elif NumSubDirs == 1 and NumRecDirs > 1 and NumFiles == 0:
#mehrere aufnahmen!, symlink erzeugen
#print "spezial-behandlung!!!"
if SpecialTreatment == True:
if NumSubDirs == 1 and NumRecDirs > 1 and NumFiles == 0:
#mehrere aufnahmen!, symlink erzeugen
RecDirs = GetRecDirs(PathNameRecordings)
if len(RecDirs) == 1:
create_symlink(os.path.join(PathNameRecordings, RecDirs[0]), strTargetDir)
elif NumSubDirs > 0 and NumRecDirs == 0 and NumFiles == 0:
#serien-verzeichnis spezielle behandlung!, weiter suchen
check_dirsexist(strDirTarg)
WalkRecordDirs(PathNameRecordings, strDirTarg, True, True)
check_dirsexist(strBaseDirDLNA)
cleanup_storage(strBaseDirDLNA, True)
WalkRecordDirs(strBaseDirRecordings, strBaseDirDLNA)