added settings file
This commit is contained in:
33
TVEncoder.py
33
TVEncoder.py
@@ -7,12 +7,12 @@ Created on Fri Jul 5 14:14:22 2013
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import getopt
|
import getopt
|
||||||
import libfilemanager
|
from libfilemanager import FileManager
|
||||||
from libsettings import Settings
|
from libsettings import Settings
|
||||||
from libhandbrake import Encoder
|
from libhandbrake import Encoder
|
||||||
import libtvdatasource
|
import libtvdatasource
|
||||||
|
|
||||||
TVRECORDINGSDIR = "/Volumes/TV Recordings/"
|
#TVRECORDINGSDIR = "/Volumes/TV Recordings/"
|
||||||
#TVRECORDINGSDIR = "/srv/storage2/videos/TVRecordings/" # TODO move this to settings
|
#TVRECORDINGSDIR = "/srv/storage2/videos/TVRecordings/" # TODO move this to settings
|
||||||
|
|
||||||
def ShowHelp():
|
def ShowHelp():
|
||||||
@@ -55,37 +55,42 @@ def main(argv):
|
|||||||
readOnly = True
|
readOnly = True
|
||||||
doList = True
|
doList = True
|
||||||
|
|
||||||
showSettings = Settings("settings.xml") # TODO call actual settings file
|
settings = Settings("settings.cfg")
|
||||||
|
|
||||||
if readOnly and doList:
|
if readOnly and doList:
|
||||||
if doEncode:
|
if doEncode:
|
||||||
#Generate the list of files that would be encoded
|
#Generate the list of files that would be encoded
|
||||||
showData = libfilemanager.GetEncodingFiles(showSettings, readOnly)
|
fileManager = FileManager(settings)
|
||||||
|
showData = fileManager.GetEncodingFiles(readOnly)
|
||||||
PrintShowsToEncode(showData)
|
PrintShowsToEncode(showData)
|
||||||
else:
|
else:
|
||||||
# Generate the list of files to process
|
# Generate the list of files to process
|
||||||
tempShowList = ["Thomas and Friends", "Thomas the Tank Engine & Friends",
|
# tempShowList = ["Thomas and Friends", "Thomas the Tank Engine & Friends",
|
||||||
"Chuggington", "Mike the Knight", "Octonauts",
|
# "Chuggington", "Mike the Knight", "Octonauts",
|
||||||
"The Octonauts", "In the Night Garden",
|
# "The Octonauts", "In the Night Garden",
|
||||||
"Raa Raa! The Noisy Lion"] # TODO get from settings
|
# "Raa Raa! The Noisy Lion"] # TODO get from settings
|
||||||
shows = libfilemanager.GetFilesToPrepare(TVRECORDINGSDIR, numFiles, tempShowList)
|
fileManager = FileManager(settings)
|
||||||
|
shows = fileManager.GetFilesToPrepare(numFiles)
|
||||||
print "num results: {0}".format(len(shows))
|
print "num results: {0}".format(len(shows))
|
||||||
PrintShowsToPrepare(shows)
|
PrintShowsToPrepare(shows)
|
||||||
else:
|
else:
|
||||||
if doEncode:
|
if doEncode:
|
||||||
#Encode the files and move them to their final destination
|
#Encode the files and move them to their final destination
|
||||||
showData = libfilemanager.GetEncodingFiles(shows, readOnly)
|
fileManager = FileManager(settings)
|
||||||
|
showData = fileManager.GetEncodingFiles(readOnly)
|
||||||
|
|
||||||
for show in showData:
|
for show in showData:
|
||||||
if libfilemanager.CheckFileExists(show.outputFile):
|
if fileManager.CheckFileExists(show.outputFile):
|
||||||
print "File {0} already exists. Cannot process.".format(show.outputFile)
|
print "File {0} already exists. Cannot process.".format(show.outputFile)
|
||||||
else:
|
else:
|
||||||
result = Encoder.Encode(show.inputFile, show.outputFile)
|
encoder = Encoder(settings.HandbrakeCommand)
|
||||||
|
result = encoder.Encode(show.inputFile, show.outputFile)
|
||||||
|
|
||||||
libfilemanager.PerformPostEncodeFileOperations(show.inputFile, show.outputFile)
|
fileManager.PerformPostEncodeFileOperations(show.inputFile, show.outputFile)
|
||||||
else:
|
else:
|
||||||
# TODO Process files for encoding
|
# TODO Process files for encoding
|
||||||
shows = libfilemanager.GetFilesToPrepare(TVRECORDINGSDIR, numFiles, shows)
|
fileManager = FileManager(settings)
|
||||||
|
shows = fileManager.GetFilesToPrepare(numFiles)
|
||||||
libtvdatasource.PrepareEpisodes(shows)
|
libtvdatasource.PrepareEpisodes(shows)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ Created on Fri Jul 5 14:11:31 2013
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
import libtvdatasource as TVData
|
from libtvdatasource import TVData
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
#move this to settings
|
#move this to settings
|
||||||
TVRECORDINGSDIR = "/srv/storage2/videos/TVRecordings/"
|
#TVRECORDINGSDIR = "/srv/storage2/videos/TVRecordings/"
|
||||||
|
|
||||||
class EncodeData:
|
class EncodeData:
|
||||||
inputFile = ''
|
inputFile = ''
|
||||||
@@ -21,80 +21,85 @@ class EncodeData:
|
|||||||
def ToString(self):
|
def ToString(self):
|
||||||
return "Input: {0}/tOutput: {2}".format(self.inputFile, self.outputFile)
|
return "Input: {0}/tOutput: {2}".format(self.inputFile, self.outputFile)
|
||||||
|
|
||||||
|
class FileManager:
|
||||||
|
def __init__(self, settings):
|
||||||
|
self.settings = settings
|
||||||
|
|
||||||
def __GetInputFilesToEncode(shows):
|
def __GetInputFilesToEncode(self):
|
||||||
fileList = []
|
fileList = []
|
||||||
|
|
||||||
for show in shows:
|
for show in self.settings.GetShowNames():
|
||||||
for r,d,f in os.walk(show.inputDirectory):
|
for r,d,f in os.walk(show.GetShowInputDirectory(show)):
|
||||||
for files in f:
|
for files in f:
|
||||||
if files.endswith(".mpg"):
|
if files.endswith(".mpg"):
|
||||||
data = EncodeData()
|
data = EncodeData()
|
||||||
data.show = show
|
data.show = show
|
||||||
data.inputFile = os.path.join(r,files)
|
data.inputFile = os.path.join(r,files)
|
||||||
fileList.append(data)
|
fileList.append(data)
|
||||||
|
|
||||||
return fileList
|
return fileList
|
||||||
|
|
||||||
def __FindSeason(path, fileName, readOnly):
|
def __FindSeason(self, path, fileName, readOnly):
|
||||||
season = "Season {0}".format(fileName[1:3])
|
season = "Season {0}".format(fileName[1:3])
|
||||||
seasonPath = os.path.join(path, season)
|
seasonPath = os.path.join(path, season)
|
||||||
|
|
||||||
if not readOnly:
|
if not readOnly:
|
||||||
if not os.path.exists(seasonPath):
|
if not os.path.exists(seasonPath):
|
||||||
os.makedirs(seasonPath)
|
os.makedirs(seasonPath)
|
||||||
|
|
||||||
return seasonPath
|
return seasonPath
|
||||||
|
|
||||||
def __GetEncodeOutputFile(showData, readOnly):
|
def __GetEncodeOutputFile(self, inputFile, showName, readOnly):
|
||||||
inFile = os.path.basename(showData.inputFile)
|
inFile = os.path.basename(inputFile)
|
||||||
outFilename = inFile[:-3]+"mkv"
|
outFilename = inFile[:-3]+"mkv"
|
||||||
outPath = __FindSeason(showData.show.outputDirectory, outFilename)
|
outPath = self.__FindSeason(self.settings.GetShowOutputFile(showName), outFilename)
|
||||||
showData.outputFile = os.path.join(outPath, outFilename)
|
return os.path.join(outPath, outFilename)
|
||||||
|
|
||||||
return showData
|
def GetEncodingFiles(self, readOnly=True):
|
||||||
|
showsData = self.__GetInputFilesToEncode(self.settings.GetShowNames())
|
||||||
|
for showData in showsData:
|
||||||
|
showData.outputFile = self.__GetEncodeOutputFile(showData.inputFile, showData.name, readOnly)
|
||||||
|
|
||||||
def GetEncodingFiles(shows, readOnly=True):
|
return showsData
|
||||||
showsData = __GetInputFilesToEncode(shows)
|
|
||||||
for showData in showsData:
|
|
||||||
showsData = __GetEncodeOutputFile(showData, readOnly)
|
|
||||||
|
|
||||||
return showsData
|
def CheckFileExists(self, file):
|
||||||
|
return os.path.isfile(file)
|
||||||
|
|
||||||
def CheckFileExists(file):
|
def __GetRecordingFile(self, fileName):
|
||||||
return os.path.isfile(file)
|
return os.path.join(self.settings.TVRecordingDirectory, os.path.dirname(fileName).split("/")[-1] + ".mpg")
|
||||||
|
|
||||||
def __GetRecordingFile(fileName):
|
def PerformPostEncodeFileOperations(self, inputFileName, outputFileName):
|
||||||
return os.path.join(TVRECORDINGSDIR, os.path.dirname(fileName).split("/")[-1] + ".mpg")
|
shutil.rmtree(os.path.dirname(inputFileName))
|
||||||
|
|
||||||
def PerformPostEncodeFileOperations(inputFileName, outputFileName):
|
linkAddress = self.__GetRecordingFile(inputFileName)
|
||||||
shutil.rmtree(os.path.dirname(inputFileName))
|
|
||||||
|
|
||||||
linkAddress = __GetRecordingFile(inputFileName)
|
os.remove(linkAddress)
|
||||||
|
|
||||||
os.remove(linkAddress)
|
os.symlink(outputFileName, linkAddress)
|
||||||
|
|
||||||
os.symlink(outputFileName, linkAddress)
|
def GetFilesToPrepare(self, numberofFiles):
|
||||||
|
path = self.settings.TVRecordingDirectory()
|
||||||
|
files = glob.glob("{0}*.mpg".format(path))
|
||||||
|
files = sorted(files, key=os.path.getctime)
|
||||||
|
files = filter(lambda file: not os.path.islink(file), files)
|
||||||
|
|
||||||
def GetFilesToPrepare(path, numberofFiles, shows):
|
#files is now a list of unprocessed files, but contains shows other than those we are interested in
|
||||||
files = glob.glob("{0}*.mpg".format(path))
|
|
||||||
files = sorted(files, key=os.path.getctime)
|
|
||||||
files = filter(lambda file: not os.path.islink(file), files)
|
|
||||||
|
|
||||||
#files is now a list of unprocessed files, but contains shows other than those we are interested in
|
showsToProcess = []
|
||||||
|
i = 0
|
||||||
|
print "Found {0} potential files".format(len(files))
|
||||||
|
|
||||||
showsToProcess = []
|
tvData = TVData(self.settings)
|
||||||
i = 0
|
|
||||||
print "Found {0} potential files".format(len(files))
|
|
||||||
for file in files:
|
|
||||||
# TODO get these from settings
|
|
||||||
#if TVData.CheckTitleIsInList('localhost', 'script', 'script', 'mythconverg', file):
|
|
||||||
showData = TVData.RetrieveEpisodeData('192.168.0.2', 'script', 'script', 'mythconverg', file, shows, '192.168.0.2', '8081', '3678177136222bf5002be209220ccb20') # TODO all these settings need to move to settings
|
|
||||||
if showData:
|
|
||||||
showsToProcess.append(showData)
|
|
||||||
i = i + 1
|
|
||||||
if i == int(numberofFiles):
|
|
||||||
return showsToProcess
|
|
||||||
|
|
||||||
return showsToProcess #will reach here if there were less than numberofFiles found
|
for file in files:
|
||||||
|
# TODO get these from settings
|
||||||
|
#if TVData.CheckTitleIsInList('localhost', 'script', 'script', 'mythconverg', file):
|
||||||
|
showData = tvData.RetrieveEpisodeData(file)
|
||||||
|
if showData:
|
||||||
|
showsToProcess.append(showData)
|
||||||
|
i = i + 1
|
||||||
|
if i == int(numberofFiles):
|
||||||
|
return showsToProcess
|
||||||
|
|
||||||
|
return showsToProcess #will reach here if there were less than numberofFiles found
|
||||||
|
|
||||||
@@ -10,20 +10,25 @@ Library to interface with handbrake to encode video files
|
|||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
HANDBRAKECOMMAND = ['HandBrakeCLI', '--verbose', '-i',
|
#==============================================================================
|
||||||
"SUBSTITUTE WITH INPUT FILE", '-o',
|
# HANDBRAKECOMMAND = ['HandBrakeCLI', '--verbose', '-i',
|
||||||
"SUBSTITUDE WITH OUTPUT FILE", '-f', 'mkv', '-e', 'x264',
|
# "SUBSTITUTE WITH INPUT FILE", '-o',
|
||||||
'-x264-preset', 'slower', '-x264-tune', 'animation', '-q',
|
# "SUBSTITUDE WITH OUTPUT FILE", '-f', 'mkv', '-e', 'x264',
|
||||||
'20', '--loose-anamorphic', '--decomb', '--detelecine',
|
# '-x264-preset', 'slower', '-x264-tune', 'animation', '-q',
|
||||||
'--denoise="2:1:2:3"', '--deblock']
|
# '20', '--loose-anamorphic', '--decomb', '--detelecine',
|
||||||
|
# '--denoise="2:1:2:3"', '--deblock']
|
||||||
|
#==============================================================================
|
||||||
|
|
||||||
class Encoder:
|
class Encoder:
|
||||||
def Encode(input, output, waitForCompletion=True, logger=None):
|
def __init__(self, handbrakeCommand):
|
||||||
HANDBRAKECOMMAND[3] = input
|
self.handbrakeCommand = handbrakeCommand
|
||||||
HANDBRAKECOMMAND[5] = output
|
|
||||||
|
|
||||||
logger.debug("Handbrake command is: {0}".format(HANDBRAKECOMMAND))
|
def Encode(self, input, output, waitForCompletion=True, logger=None):
|
||||||
process = subprocess.Popen(HANDBRAKECOMMAND)
|
self.handbrakeCommand[3] = input
|
||||||
|
self.handbrakeCommand[5] = output
|
||||||
|
|
||||||
|
logger.debug("Handbrake command is: {0}".format(self.handbrakeCommand))
|
||||||
|
process = subprocess.Popen(self.handbrakeCommand)
|
||||||
|
|
||||||
if waitForCompletion:
|
if waitForCompletion:
|
||||||
process.wait()
|
process.wait()
|
||||||
|
|||||||
27
libmythtv.py
27
libmythtv.py
@@ -8,14 +8,25 @@ Created on Fri Jul 5 14:10:47 2013
|
|||||||
import MySQLdb as mdb
|
import MySQLdb as mdb
|
||||||
from libtvshow import TVShow
|
from libtvshow import TVShow
|
||||||
|
|
||||||
def RetrieveEpisodeData(serverAddress, user, password, database, inputFile):
|
class MythTV:
|
||||||
con = mdb.connect(serverAddress, user, password, database)
|
def __init__(self, settings):
|
||||||
|
self.settings = settings
|
||||||
|
|
||||||
with con:
|
def RetrieveEpisodeData(self, inputFile):
|
||||||
cur = con.cursor(mdb.cursors.DictCursor)
|
con = mdb.connect(self.settings.MythTVAddress(), self.settings.MythTVUser(), self.settings.MythTVPassword(), self.settings.MythTVDatabase())
|
||||||
cur.execute("select episode, season, title, subtitle, description from mythconverg.recorded where basename = '{0}'".format(inputFile))
|
|
||||||
result = cur.fetchone()
|
|
||||||
#print result
|
|
||||||
|
|
||||||
return TVShow(result['episode'], result['season'], result['title'], result['subtitle'], result['description'])
|
with con:
|
||||||
|
cur = con.cursor(mdb.cursors.DictCursor)
|
||||||
|
cur.execute("select episode, season, title, subtitle, description from mythconverg.recorded where basename = '{0}'".format(inputFile))
|
||||||
|
result = cur.fetchone()
|
||||||
|
#print result
|
||||||
|
|
||||||
|
return TVShow(result['episode'], result['season'], result['title'], result['subtitle'], result['description'])
|
||||||
|
|
||||||
|
def FixMythTVEpisodeName(self, showName, episodeTitle):
|
||||||
|
for prefix in self.settings.GetShowMythTVEpisodePrefix(showName):
|
||||||
|
if episodeTitle.lower().startswith(prefix.lower()):
|
||||||
|
return episodeTitle[len(prefix):]
|
||||||
|
|
||||||
|
return episodeTitle #didn't find anything so return the episode title
|
||||||
|
|
||||||
101
libsettings.py
101
libsettings.py
@@ -5,7 +5,7 @@ Created on Fri Jul 5 20:14:15 2013
|
|||||||
@author: shanef
|
@author: shanef
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from xml.etree import ElementTree
|
from configobj import ConfigObj
|
||||||
|
|
||||||
class ShowSettings:
|
class ShowSettings:
|
||||||
def __init__(self, name, inputDirectory, outputDirectory):
|
def __init__(self, name, inputDirectory, outputDirectory):
|
||||||
@@ -13,15 +13,98 @@ class ShowSettings:
|
|||||||
self.inputDirectory = inputDirectory
|
self.inputDirectory = inputDirectory
|
||||||
self.outputDirectory = outputDirectory
|
self.outputDirectory = outputDirectory
|
||||||
|
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
def __init__(self, settingsFile):
|
def __init__(self, settingsFile):
|
||||||
self.shows = self.LoadSettings(settingsFile)
|
self.__config = ConfigObj(settingsFile)
|
||||||
|
|
||||||
def LoadSettings(self, source):
|
def TVRecordingDirectory(self):
|
||||||
shows = []
|
return self.__config["TVRecordings"]
|
||||||
settingsXml = ElementTree.parse(source).getroot()
|
|
||||||
|
|
||||||
for show in settingsXml.findall('show'):
|
def HandbrakeCommand(self):
|
||||||
newShow = ShowSettings(show[0].text, show[1].text, show[2].text)
|
return self.__config["HandbrakeCommand"]
|
||||||
shows.append(newShow)
|
|
||||||
return shows
|
def MythTVAddress(self):
|
||||||
|
return self.__config["MythTV"]["address"]
|
||||||
|
|
||||||
|
def MythTVUser(self):
|
||||||
|
return self.__config["MythTV"]["user"]
|
||||||
|
|
||||||
|
def MythTVPassword(self):
|
||||||
|
return self.__config["MythTV"]["password"]
|
||||||
|
|
||||||
|
def MythTVDatabase(self):
|
||||||
|
return self.__config["MythTV"]["database"]
|
||||||
|
|
||||||
|
def SickbeardAddress(self):
|
||||||
|
return self.__config["Sickbeard"]["address"]
|
||||||
|
|
||||||
|
def SickbeardPort(self):
|
||||||
|
return int(self.__config["Sickbeard"]["port"])
|
||||||
|
|
||||||
|
def SickbeardAPIKey(self):
|
||||||
|
return self.__config["Sickbeard"]["APIKey"]
|
||||||
|
|
||||||
|
def UnknownDirectory(self):
|
||||||
|
return self.__config["Shows"]["UnknownInput"]
|
||||||
|
|
||||||
|
def GetShowNames(self, includeAlias=False):
|
||||||
|
shows = self.__config["Shows"].sections
|
||||||
|
result = shows[:]
|
||||||
|
if includeAlias:
|
||||||
|
for show in shows:
|
||||||
|
for alias in self.__config["Shows"][show]["alias"]:
|
||||||
|
result.append(alias)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def GetShowInputDirectory(self, showName):
|
||||||
|
show = self.__GetShowSubsection(showName)
|
||||||
|
if show is None:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return show["InputDirectory"]
|
||||||
|
|
||||||
|
def GetShowOutputDirectory(self, showName):
|
||||||
|
show = self.__GetShowSubsection(showName)
|
||||||
|
if show is None:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return show["OutputDirectory"]
|
||||||
|
|
||||||
|
def GetShowAlias(self, showName):
|
||||||
|
show = self.__GetShowSubsection(showName)
|
||||||
|
if show is None:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return show["alias"]
|
||||||
|
|
||||||
|
def GetShowMythTVEpisodePrefix(self, showName):
|
||||||
|
show = self.__GetShowSubsection(showName)
|
||||||
|
if show is None:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return show["MythTvEpisodePrefix"]
|
||||||
|
|
||||||
|
def GetShowSickbeardEpisodePrefix(self, showName):
|
||||||
|
show = self.__GetShowSubsection(showName)
|
||||||
|
if show is None:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
return show["SickbeardPrefix"]
|
||||||
|
|
||||||
|
def GetShow(self, showName):
|
||||||
|
showSection = self.__GetShowSubsection(showName)
|
||||||
|
if showSection is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return showSection.name
|
||||||
|
|
||||||
|
def __GetShowSubsection(self, showName):
|
||||||
|
if showName in self.GetShowNames():
|
||||||
|
return self.__config["Shows"][showName]
|
||||||
|
else: # check liases
|
||||||
|
for show in self.GetShowNames():
|
||||||
|
if showName in self.__config["Shows"][show]["alias"]:
|
||||||
|
return self.__config["Shows"][show]
|
||||||
|
|
||||||
|
return None
|
||||||
@@ -12,13 +12,14 @@ from fuzzywuzzy import fuzz
|
|||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
class Sickbeard:
|
class Sickbeard:
|
||||||
def __init__(self, address, port, apikey):
|
def __init__(self, settings):
|
||||||
self.address = address
|
self.__settings = settings
|
||||||
self.port = port
|
self.__address = settings.SickbeardAddress()
|
||||||
self.apikey = apikey
|
self.__port = settings.SickbeardPort()
|
||||||
|
self.__apikey = settings.SickbeardAPIKey()
|
||||||
|
|
||||||
def __GetApiURL(self):
|
def __GetApiURL(self):
|
||||||
return "http://{0}:{1}/api/{2}/".format(self.address, self.port, self.apikey)
|
return "http://{0}:{1}/api/{2}/".format(self.__address, self.__port, self.__apikey)
|
||||||
|
|
||||||
def FindShowId(self, showName):
|
def FindShowId(self, showName):
|
||||||
jsonurl = urlopen(self.__GetApiURL()+"?cmd=shows")
|
jsonurl = urlopen(self.__GetApiURL()+"?cmd=shows")
|
||||||
@@ -43,7 +44,8 @@ class Sickbeard:
|
|||||||
jsonEpisodeUrl = urlopen("{0}?cmd=episode&tvdbid={1}&season={2}&episode={3}".format(self.__GetApiURL(), showId, season, episode))
|
jsonEpisodeUrl = urlopen("{0}?cmd=episode&tvdbid={1}&season={2}&episode={3}".format(self.__GetApiURL(), showId, season, episode))
|
||||||
episodeResult = json.loads(jsonEpisodeUrl.read())
|
episodeResult = json.loads(jsonEpisodeUrl.read())
|
||||||
|
|
||||||
if fuzz.ratio(episodeResult['data']['description'].lower(), description.lower()) > 85:
|
sickbeardDescription = episodeResult['data']['description']
|
||||||
|
if fuzz.ratio(sickbeardDescription.lower(), description.lower()) > 85 or fuzz.ratio(sickbeardDescription.lower()[:len(description)], description.lower()) > 85 or fuzz.ratio(sickbeardDescription.lower(), description.lower()[:len(sickbeardDescription)]) > 85:
|
||||||
return (season, episode, episodeResult['data']['name'])
|
return (season, episode, episodeResult['data']['name'])
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@@ -54,8 +56,8 @@ class Sickbeard:
|
|||||||
|
|
||||||
for season in result['data']:
|
for season in result['data']:
|
||||||
for episode in result['data'][season]:
|
for episode in result['data'][season]:
|
||||||
if name is not None and name.lower() == result['data'][season][episode]['name'].lower():
|
if name is not None and fuzz.partial_ratio(name.lower(), result['data'][season][episode]['name'].lower()) > 90:
|
||||||
return (season, episode, name)
|
return (season, episode, result['data'][season][episode]['name'])
|
||||||
elif description is not None:
|
elif description is not None:
|
||||||
descriptionQueryResult = self.FindEpisodeByDescription(showId, season, episode, description)
|
descriptionQueryResult = self.FindEpisodeByDescription(showId, season, episode, description)
|
||||||
if descriptionQueryResult is not None:
|
if descriptionQueryResult is not None:
|
||||||
@@ -63,8 +65,18 @@ class Sickbeard:
|
|||||||
|
|
||||||
return (0, 0, '')
|
return (0, 0, '')
|
||||||
|
|
||||||
def GetEpisodeName(subtitle, showName):
|
#==============================================================================
|
||||||
if subtitle[:len(showName)].lower() == showName.lower():
|
# def GetEpisodeName(subtitle, showName):
|
||||||
return subtitle[len(showName + ' and the '):]
|
# if subtitle[:len(showName)].lower() == showName.lower():
|
||||||
else:
|
# return subtitle[len(showName + ' and the '):]
|
||||||
return subtitle
|
# else:
|
||||||
|
# return subtitle
|
||||||
|
#==============================================================================
|
||||||
|
|
||||||
|
def FixEpisodeTitle(self, showName, episodeTitle):
|
||||||
|
sickbeardPrefix = self.__settings.GetShowSickbeardEpisodePrefix(showName)
|
||||||
|
if sickbeardPrefix != "":
|
||||||
|
if not episodeTitle.lower.startswith(sickbeardPrefix.lower()):
|
||||||
|
return "{0} {1}".format(sickbeardPrefix.rstrip(), episodeTitle.lstrip())
|
||||||
|
|
||||||
|
return episodeTitle
|
||||||
@@ -5,116 +5,131 @@ Created on Fri Jul 5 14:42:47 2013
|
|||||||
@author: shanef
|
@author: shanef
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import libmythtv as MythTV
|
from libmythtv import MythTV
|
||||||
from libsickbeard import Sickbeard
|
from libsickbeard import Sickbeard
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
# TODO Move these to settings
|
# TODO Move these to settings
|
||||||
PROCESSDIR="/srv/storage2/files/VideoProcessing/"
|
#PROCESSDIR="/srv/storage2/files/VideoProcessing/"
|
||||||
THOMAS="Thomas"
|
#THOMAS="Thomas"
|
||||||
CHUGGINGTON="Chuggington"
|
#CHUGGINGTON="Chuggington"
|
||||||
MIKE="MikeTheKnight"
|
#MIKE="MikeTheKnight"
|
||||||
OCTONAUTS="Octonauts"
|
#OCTONAUTS="Octonauts"
|
||||||
NIGHTGARDEN="InTheNightGarden"
|
#NIGHTGARDEN="InTheNightGarden"
|
||||||
RAARAA="RaaRaa"
|
#RAARAA="RaaRaa"
|
||||||
INPUTDIR="Input"
|
#INPUTDIR="Input"
|
||||||
|
|
||||||
def FixEpisodeSeasonNumber(number):
|
class TVData:
|
||||||
if len(number) == 1:
|
def __init__(self, settings):
|
||||||
return "0{0}".format(number)
|
self.settings = settings
|
||||||
else:
|
|
||||||
return number
|
|
||||||
|
|
||||||
def GetDirectory(title, season):
|
def FixEpisodeSeasonNumber(self, number):
|
||||||
directory = ""
|
if len(number) == 1:
|
||||||
if title == "Thomas and Friends" or title == "Thomas the Tank Engine & Friends":
|
return "0{0}".format(number)
|
||||||
directory = THOMAS
|
else:
|
||||||
elif title == "Chuggington":
|
return number
|
||||||
directory = CHUGGINGTON
|
|
||||||
elif title == "Mike the Knight":
|
|
||||||
directory = MIKE
|
|
||||||
elif title == "Octonauts" or title == "The Octonauts":
|
|
||||||
directory = OCTONAUTS
|
|
||||||
elif title == "In the Night Garden":
|
|
||||||
directory = NIGHTGARDEN
|
|
||||||
elif title == "Raa Raa! The Noisy Lion":
|
|
||||||
directory = RAARAA
|
|
||||||
else:
|
|
||||||
print "Didn't match"
|
|
||||||
|
|
||||||
return os.path.join(PROCESSDIR, directory, INPUTDIR, season)
|
def GetDirectory(self, title, season):
|
||||||
|
show = self.settings.GetShow(title)
|
||||||
|
if not show or show == "":
|
||||||
|
print "Couldn't find show for {0}".format(title)
|
||||||
|
return self.settings.UnknownDirectory()
|
||||||
|
else:
|
||||||
|
return os.path.join(self.settings.GetShowInputDirectory(show), season)
|
||||||
|
#==============================================================================
|
||||||
|
# if title == "Thomas and Friends" or title == "Thomas the Tank Engine & Friends":
|
||||||
|
# directory = THOMAS
|
||||||
|
# elif title == "Chuggington":
|
||||||
|
# directory = CHUGGINGTON
|
||||||
|
# elif title == "Mike the Knight":
|
||||||
|
# directory = MIKE
|
||||||
|
# elif title == "Octonauts" or title == "The Octonauts":
|
||||||
|
# directory = OCTONAUTS
|
||||||
|
# elif title == "In the Night Garden":
|
||||||
|
# directory = NIGHTGARDEN
|
||||||
|
# elif title == "Raa Raa! The Noisy Lion":
|
||||||
|
# directory = RAARAA
|
||||||
|
# else:
|
||||||
|
# print "Didn't match"
|
||||||
|
#==============================================================================
|
||||||
|
|
||||||
def RetrieveEpisodeData(serverAddress, user, password, database, inputFile, showsToProcess, sickbeardAddress, sickbeardPort, sickbeardAPIKey):
|
# return os.path.join(PROCESSDIR, directory, INPUTDIR, season)
|
||||||
file = os.path.basename(inputFile)
|
|
||||||
show = MythTV.RetrieveEpisodeData(serverAddress, user, password, database, file)
|
|
||||||
|
|
||||||
if show.title and show.title in showsToProcess:
|
def RetrieveEpisodeData(self, inputFile):
|
||||||
if show.subtitle:
|
file = os.path.basename(inputFile)
|
||||||
show.subtitle = GetEpisodeName(show.subtitle, show.title)
|
|
||||||
|
|
||||||
if (show.season == "0" or show.episode == "0"):
|
mythTv = MythTV(self.settings)
|
||||||
sickbeard = Sickbeard(sickbeardAddress, sickbeardPort, sickbeardAPIKey)
|
show = mythTv.RetrieveEpisodeData(file)
|
||||||
showId = sickbeard.FindShowId(show.title)
|
|
||||||
|
|
||||||
result = sickbeard.FindEpisode(showId, show.subtitle, show.description)
|
showsToProcess = self.settings.GetShowNames(True)
|
||||||
show.season = str(result[0])
|
|
||||||
show.episode = str(result[1])
|
|
||||||
show.subtitle = result[2]
|
|
||||||
|
|
||||||
if show.season != "0" and show.episode != "0":
|
if show.title and show.title in showsToProcess:
|
||||||
show.season = FixEpisodeSeasonNumber(show.season)
|
show.title = self.settings.GetShow(show.title)
|
||||||
show.episode = FixEpisodeSeasonNumber(show.episode)
|
|
||||||
|
|
||||||
seasonFolder = "Season {0}".format(show.season)
|
if (show.season == "0" or show.episode == "0"):
|
||||||
season = "S{0}".format(show.season)
|
sickbeard = Sickbeard(self.settings)
|
||||||
episode = "E{0}".format(show.episode)
|
showId = sickbeard.FindShowId(show.title)
|
||||||
renamedFile = "{0}{1} - {2} - SD TV_.mpg".format(season, episode, show.subtitle)
|
|
||||||
|
|
||||||
directory = GetDirectory(show.title, seasonFolder)
|
if show.subtitle is not None and show.subtitle:
|
||||||
|
show.subtitle = mythTv.FixMythTVEpisodeName(show.title, show.subtitle)
|
||||||
|
show.subtitle = sickbeard.FixEpisodeTitle(show.title, show.subtitle)
|
||||||
|
|
||||||
show.outputFile = os.path.join(directory, file[:-4], renamedFile)
|
result = sickbeard.FindEpisode(showId, show.subtitle, show.description)
|
||||||
show.inputFile = inputFile
|
show.season = str(result[0])
|
||||||
|
show.episode = str(result[1])
|
||||||
|
show.subtitle = result[2]
|
||||||
|
|
||||||
return show
|
if show.season != "0" and show.episode != "0":
|
||||||
else:
|
show.season = self.FixEpisodeSeasonNumber(show.season)
|
||||||
return None
|
show.episode = self.FixEpisodeSeasonNumber(show.episode)
|
||||||
|
|
||||||
def CheckTitleIsInList(serverAddress, user, password, database, inputFile):
|
seasonFolder = "Season {0}".format(show.season)
|
||||||
"""Check that inputFile is a recording of a show that is to be processed."""
|
season = "S{0}".format(show.season)
|
||||||
file = os.path.basename(inputFile)
|
episode = "E{0}".format(show.episode)
|
||||||
show = MythTV.RetrieveEpisodeData('localhost', 'script', 'script', 'mythconverg', file)
|
renamedFile = "{0}{1} - {2} - SD TV_.mpg".format(season, episode, show.subtitle)
|
||||||
|
|
||||||
# TODO get this from settings
|
directory = self.GetDirectory(show.title, seasonFolder)
|
||||||
if show.title in ["Thomas and Friends", "Thomas the Tank Engine & Friends",
|
|
||||||
"Chuggington", "Mike the Knight", "Octonauts",
|
|
||||||
"The Octonauts", "In the Night Garden",
|
|
||||||
"Raa Raa! The Noisy Lion"]:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def DetermineTargetFilename(directory, filename, inputFilename):
|
show.outputFile = os.path.join(directory, file[:-4], renamedFile)
|
||||||
dir = os.path.join(directory, inputFilename[:-4])
|
show.inputFile = inputFile
|
||||||
|
|
||||||
if not os.path.exists(dir):
|
return show
|
||||||
os.makedirs(dir)
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
return os.path.join(dir, filename)
|
#==============================================================================
|
||||||
|
# def CheckTitleIsInList(serverAddress, user, password, database, inputFile):
|
||||||
|
# """Check that inputFile is a recording of a show that is to be processed."""
|
||||||
|
# file = os.path.basename(inputFile)
|
||||||
|
# show = MythTV.RetrieveEpisodeData('localhost', 'script', 'script', 'mythconverg', file)
|
||||||
|
#
|
||||||
|
# # TODO get this from settings
|
||||||
|
# if show.title in ["Thomas and Friends", "Thomas the Tank Engine & Friends",
|
||||||
|
# "Chuggington", "Mike the Knight", "Octonauts",
|
||||||
|
# "The Octonauts", "In the Night Garden",
|
||||||
|
# "Raa Raa! The Noisy Lion"]:
|
||||||
|
# return True
|
||||||
|
# else:
|
||||||
|
# return False
|
||||||
|
#==============================================================================
|
||||||
|
|
||||||
def GetEpisodeName(subtitle, showName):
|
def DetermineTargetFilename(directory, filename, inputFilename):
|
||||||
if subtitle[:len(showName)].lower() == showName.lower():
|
dir = os.path.join(directory, inputFilename[:-4])
|
||||||
return subtitle[len(showName + ' and the '):]
|
|
||||||
else:
|
|
||||||
return subtitle
|
|
||||||
|
|
||||||
def ProcessEpisode(inputFile, outputFile):
|
if not os.path.exists(dir):
|
||||||
outputdir = os.path.dirname(outputFile)
|
os.makedirs(dir)
|
||||||
if not os.path.exists(outputdir):
|
|
||||||
os.makedirs(outputdir)
|
|
||||||
|
|
||||||
shutil.move(inputFile, outputFile)
|
return os.path.join(dir, filename)
|
||||||
|
|
||||||
def PrepareEpisodes(showsData):
|
|
||||||
for showData in showsData:
|
def ProcessEpisode(inputFile, outputFile):
|
||||||
ProcessEpisode(showData.inputFile, showData.outputFile)
|
outputdir = os.path.dirname(outputFile)
|
||||||
|
if not os.path.exists(outputdir):
|
||||||
|
os.makedirs(outputdir)
|
||||||
|
|
||||||
|
shutil.move(inputFile, outputFile)
|
||||||
|
|
||||||
|
def PrepareEpisodes(self, showsData):
|
||||||
|
for showData in showsData:
|
||||||
|
self.ProcessEpisode(showData.inputFile, showData.outputFile)
|
||||||
52
settings.cfg
Normal file
52
settings.cfg
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
TVRecordings = "/Volumes/TV Recordings/"
|
||||||
|
HandbrakeCommand = "HandBrakeCLI", "--verbose", "-i", "SUBSTITUTE WITH INPUT FILE", "-o", "SUBSTITUDE WITH OUTPUT FILE", "-f", "mkv", "-e", "x264", "-x264-preset", "slower", "-x264-tune", "animation", "-q", "20", "--loose-anamorphic", "--decomb", "--detelecine", '--denoise="2:1:2:3"', "--deblock"
|
||||||
|
|
||||||
|
[ "MythTV" ]
|
||||||
|
address = 192.168.0.2
|
||||||
|
user = script
|
||||||
|
password = script
|
||||||
|
database = mythconverg
|
||||||
|
|
||||||
|
[ "Sickbeard" ]
|
||||||
|
address = 192.168.0.2
|
||||||
|
port = 8081
|
||||||
|
APIKey = 3678177136222bf5002be209220ccb20
|
||||||
|
|
||||||
|
[ "Shows" ]
|
||||||
|
UnknownInput = "/srv/storage2/files/VideoProcessing/Unknown/"
|
||||||
|
[[ "Thomas the Tank Engine & Friends" ]]
|
||||||
|
InputDirectory = "/srv/storage2/files/VideoProcessing/Thomas/Input/"
|
||||||
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/Thomas The Tank Engine & Friends/"
|
||||||
|
alias = "Thomas and Friends",
|
||||||
|
MythTvEpisodePrefix = ,
|
||||||
|
SickbeardPrefix = ""
|
||||||
|
[[ "Chuggington" ]]
|
||||||
|
InputDirectory = "/srv/storage2/files/VideoProcessing/Chuggington/Input/"
|
||||||
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/Chuggington/"
|
||||||
|
alias = ,
|
||||||
|
MythTvEpisodePrefix = ,
|
||||||
|
SickbeardPrefix = ""
|
||||||
|
[[ "Mike the Knight" ]]
|
||||||
|
InputDirectory = "/srv/storage2/files/VideoProcessing/MikeTheKnight/Input/"
|
||||||
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/Mike the Knight/"
|
||||||
|
alias = ,
|
||||||
|
MythTvEpisodePrefix = "Mike the Knight and the ", Mike the Knight and "
|
||||||
|
SickbeardPrefix = ""
|
||||||
|
[[ "Octonauts" ]]
|
||||||
|
InputDirectory = "/srv/storage2/files/VideoProcessing/Octonauts/Input/"
|
||||||
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/Octonauts/"
|
||||||
|
alias = "The Octonauts",
|
||||||
|
MythTvEpisodePrefix = "The Octonauts and ",
|
||||||
|
SickbeardPrefix = "The "
|
||||||
|
[[ "In the Night Garden" ]]
|
||||||
|
InputDirectory = "/srv/storage2/files/VideoProcessing/InTheNightGarden/Input/"
|
||||||
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/In The Night Garden/"
|
||||||
|
alias = ,
|
||||||
|
MythTvEpisodePrefix = ,
|
||||||
|
SickbeardPrefix = ""
|
||||||
|
[[ "Raa Raa! The Noisy Lion" ]]
|
||||||
|
InputDirectory = "/srv/storage2/files/VideoProcessing/RaaRaa/Input/"
|
||||||
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/Raa Raa the Noisy Lion/"
|
||||||
|
alias = ,
|
||||||
|
MythTvEpisodePrefix = ,
|
||||||
|
SickbeardPrefix = ""
|
||||||
Reference in New Issue
Block a user