diff --git a/TVEncoder.py b/TVEncoder.py index 251095f..ab01972 100644 --- a/TVEncoder.py +++ b/TVEncoder.py @@ -9,7 +9,7 @@ import sys import getopt from libfilemanager import FileManager from libsettings import Settings -from libhandbrake import Encoder +import libhandbrake from libtvdatasource import TVData from collections import namedtuple @@ -106,8 +106,9 @@ def main(argv): print "File {0} already exists. Cannot process." \ .format(show.outputFile) else: - encoder = Encoder(settings.HandbrakeCommand()) - result = encoder.Encode(show.inputFile, show.outputFile) + result = libhandbrake.encode(settings.handbrakecommand(), + show.inputFile, + show.outputFile) # TODO do something with the result filemanager.performpostencodefileoperations( show.inputFile, show.outputFile) diff --git a/libhandbrake.py b/libhandbrake.py index 571a951..0e865f7 100644 --- a/libhandbrake.py +++ b/libhandbrake.py @@ -7,37 +7,30 @@ Created on Fri Jul 5 14:11:00 2013 Library to interface with handbrake to encode video files """ -import logging import subprocess -#============================================================================== -# 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'] -#============================================================================== -class Encoder: - def __init__(self, handbrakeCommand): - self.handbrakeCommand = handbrakeCommand - - def Encode(self, input, output, waitForCompletion=True, logger=None): - self.handbrakeCommand[3] = input - self.handbrakeCommand[5] = output +def encode(handbrakecommand, inputfile, outputfile, waitforcompletion=True, + logger=None): + """ + Encode inputfile and save the result to outputfile. handbrakecommand is + a list of strings containing the arguments to handbrakecli. + """ - if logger: - logger.debug("Handbrake command is: {0}".format(self.handbrakeCommand)) + handbrakecommand[3] = inputfile + handbrakecommand[5] = outputfile - process = subprocess.Popen(self.handbrakeCommand) - - if waitForCompletion: - process.wait() - - if logger is not None: - logger.info("Handbrake completed with return code {0}".format(process.returncode)) - return process.returncode - - return None - \ No newline at end of file + if logger: + logger.debug("Handbrake command is: {0}".format(handbrakecommand)) + + process = subprocess.Popen(handbrakecommand) + + if waitforcompletion: + process.wait() + + if logger is not None: + logger.info("Handbrake completed with return code {0}".format( + process.returncode)) + return process.returncode + + return None diff --git a/libmythtv.py b/libmythtv.py index 8d10a38..0036b08 100644 --- a/libmythtv.py +++ b/libmythtv.py @@ -8,25 +8,46 @@ Created on Fri Jul 5 14:10:47 2013 import MySQLdb as mdb from libtvshow import TVShow + class MythTV: + """ + Contains methods used for interacting with mythtv + """ + def __init__(self, settings): self.settings = settings - - def RetrieveEpisodeData(self, inputFile): - con = mdb.connect(self.settings.MythTVAddress(), self.settings.MythTVUser(), self.settings.MythTVPassword(), self.settings.MythTVDatabase()) - + + def retrieveepisodedata(self, inputfile): + """ + Retrieve the data that mythtv knows about the recorded file. + """ + con = mdb.connect(self.settings.MythTVAddress(), + self.settings.MythTVUser(), + self.settings.MythTVPassword(), + self.settings.MythTVDatabase()) + with con: cur = con.cursor(mdb.cursors.DictCursor) - cur.execute("select episode, season, title, subtitle, description from mythconverg.recorded where basename = '{0}'".format(inputFile)) + 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 - \ No newline at end of file + + return TVShow(result['episode'], result['season'], + result['title'], result['subtitle'], + result['description']) + + def fixmythtvepisodename(self, showname, episodetitle): + """ + Look for any prefixes listed in the configuration file. If there are + any and the episide title starts with the prefix, remove the prefix + from the episode title. The searching is done in the order that the + prefixes are listed in the configuration file. + """ + + for prefix in self.settings.GetShowMythTVEpisodePrefix(showname): + if episodetitle.lower().startswith(prefix.lower()): + return episodetitle[len(prefix):] + + #didn't find anything so return the episode title + return episodetitle diff --git a/libsettings.py b/libsettings.py index b8da13f..21394aa 100644 --- a/libsettings.py +++ b/libsettings.py @@ -7,111 +7,122 @@ Created on Fri Jul 5 20:14:15 2013 from configobj import ConfigObj -class ShowSettings: - def __init__(self, name, inputDirectory, outputDirectory): - self.name = name - self.inputDirectory = inputDirectory - self.outputDirectory = outputDirectory + +#============================================================================== +# class ShowSettings: +# """ +# Container for the settings for a show +# """ +# +# def __init__(self, name, inputdirectory, outputdirectory): +# self.name = name +# self.inputdirectory = inputdirectory +# self.outputdirectory = outputdirectory +#============================================================================== class Settings: - def __init__(self, settingsFile): - self.__config = ConfigObj(settingsFile) - - def TVRecordingDirectory(self): + """ + Accessor for the configuration file + """ + + def __init__(self, settingsfile): + self.__config = ConfigObj(settingsfile) + + def tvrecordingdirectory(self): return self.__config["TVRecordings"] - def HandbrakeCommand(self): + def handbrakecommand(self): return self.__config["HandbrakeCommand"] - - def MythTVAddress(self): - return self.__config["MythTV"]["address"] - - def MythTVUser(self): - return self.__config["MythTV"]["user"] - def MythTVPassword(self): + 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): + def mythtvdatabase(self): return self.__config["MythTV"]["database"] - - def SickbeardAddress(self): + + def sickbeardaddress(self): return self.__config["Sickbeard"]["address"] - - def SickbeardPort(self): + + def sickbeardport(self): return int(self.__config["Sickbeard"]["port"]) - def SickbeardAPIKey(self): + def sickbeardapikey(self): return self.__config["Sickbeard"]["APIKey"] - - def UnknownDirectory(self): + + def unknowndirectory(self): return self.__config["Shows"]["UnknownInput"] - - def GetShowNames(self, includeAlias=False): + + def getshownames(self, includealias=False): shows = self.__config["Shows"].sections result = shows[:] - if includeAlias: + 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) + + def getshowinputdirectory(self, showname): + show = self.__getshowsubsection(showname) if show is None: return "" else: return show["InputDirectory"] - def GetShowUnknownDirectory(self, showName): - show = self.__GetShowSubsection(showName) + def getshowunknowndirectory(self, showname): + show = self.__getshowsubsection(showname) if show is None: return "" else: return show["UnknownDirectory"] - - def GetShowOutputDirectory(self, showName): - show = self.__GetShowSubsection(showName) + + 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) + + 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) + + 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) + def getshowsickbearsepisodeprefix(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: + + 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 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 \ No newline at end of file + + return None diff --git a/libsickbeard.py b/libsickbeard.py index 994fd55..b8dd583 100644 --- a/libsickbeard.py +++ b/libsickbeard.py @@ -5,22 +5,23 @@ Created on Fri Jul 5 14:10:37 2013 @author: shanef """ -from libtvshow import TVShow import json from urllib import urlopen from fuzzywuzzy import fuzz from operator import itemgetter + class Sickbeard: def __init__(self, settings): self.__settings = settings self.__address = settings.SickbeardAddress() self.__port = settings.SickbeardPort() self.__apikey = settings.SickbeardAPIKey() - + 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): jsonurl = urlopen(self.__GetApiURL()+"?cmd=shows") result = json.loads(jsonurl.read()) @@ -33,25 +34,32 @@ class Sickbeard: shows = [] for show in result['data']: - shows.append((show, fuzz.partial_ratio(showName.lower(), result['data'][show]['show_name'].lower()))) - + shows.append((show, fuzz.partial_ratio(showName.lower(), + result['data'][show] + ['show_name'].lower()))) + shows = sorted(shows, key=itemgetter(1), reverse=True) - + if shows[0][1] > 85: return shows[0][0] - + def FindEpisodeByDescription(self, showId, season, episode, description): - jsonEpisodeUrl = urlopen("{0}?cmd=episode&tvdbid={1}&season={2}&episode={3}".format(self.__GetApiURL(), showId, season, episode)) - episodeResult = json.loads(jsonEpisodeUrl.read()) - - 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']) + jsonepisodeurl = urlopen("{0}?cmd=episode&tvdbid={1}&season={2}" + "&episode={3}".format(self.__GetApiURL(), + showId, season, episode)) + episoderesult = json.loads(jsonepisodeurl.read()) + + sickbearddescription = episoderesult['data']['description'] + + if fuzzystringcompare(sickbearddescription, description): + return (season, episode, episoderesult['data']['name']) return None - + def FindEpisodeName(self, showId, season, episode): - jsonurl = urlopen("{0}?cmd=episode&tvdbid={1}&season={2}&episode={3}".format(self.__GetApiURL(), showId, int(season), int(episode))) + jsonurl = urlopen("{0}?cmd=episode&tvdbid={1}&season={2}" + "&episode={3}".format(self.__GetApiURL(), showId, + int(season), int(episode))) result = json.loads(jsonurl.read()) if result['result'] == 'error': return "" @@ -59,20 +67,25 @@ class Sickbeard: return result['data']['name'] def FindEpisode(self, showId, name=None, description=None): - jsonurl = urlopen("{0}?cmd=show.seasons&tvdbid={1}".format(self.__GetApiURL(), showId)) + jsonurl = urlopen("{0}?cmd=show.seasons&tvdbid={1}".format( + self.__GetApiURL(), showId)) result = json.loads(jsonurl.read()) - + for season in result['data']: for episode in result['data'][season]: - if name is not None and fuzz.partial_ratio(name.lower(), result['data'][season][episode]['name'].lower()) > 90: - return (season, episode, result['data'][season][episode]['name']) + episodename = result['data'][season][episode]['name'] + if name is not None and fuzz.partial_ratio(name.lower(), + episodename) > 90: + return (season, episode, episodename) elif description is not None: - descriptionQueryResult = self.FindEpisodeByDescription(showId, season, episode, description) + descriptionQueryResult = \ + self.FindEpisodeByDescription(showId, season, + episode, description) if descriptionQueryResult is not None: return descriptionQueryResult - + return (0, 0, '') - + #============================================================================== # def GetEpisodeName(subtitle, showName): # if subtitle[:len(showName)].lower() == showName.lower(): @@ -80,11 +93,38 @@ class Sickbeard: # else: # return subtitle #============================================================================== - + def FixEpisodeTitle(self, showName, episodeTitle): - sickbeardPrefix = self.__settings.GetShowSickbeardEpisodePrefix(showName) + sickbeardPrefix = \ + self.__settings.GetShowSickbeardEpisodePrefix(showName) + if sickbeardPrefix != "": if not episodeTitle.lower.startswith(sickbeardPrefix.lower()): - return "{0} {1}".format(sickbeardPrefix.rstrip(), episodeTitle.lstrip()) - - return episodeTitle \ No newline at end of file + return "{0} {1}".format(sickbeardPrefix.rstrip(), + episodeTitle.lstrip()) + + return episodeTitle + + +def fuzzystringcompare(string1, string2, matchvalue=85, casesensitive=False): + """ + Compare two strings to see if they match it first does a straight + comparison. Secondly, it concatenates the longer string to the length of + the shorter one, and tries to compare them again. + """ + + if not casesensitive: + string1 = string1.lower() + string2 = string2.lower() + + if fuzz.ratio(string1, string2) > matchvalue: + return True + + if len(string1) > len(string2): + if fuzz.ratio(string1[:len(string2)], string2) > matchvalue: + return True + elif len(string2) > len(string1): + if fuzz.ratio(string1, string2[:len(string1)]) > matchvalue: + return True + + return False