Compare commits
No commits in common. "master" and "2.0" have entirely different histories.
16 changed files with 74 additions and 573 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
*.pyc
|
|
||||||
.spyderproject
|
|
||||||
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
SMTPServer = ""
|
|
||||||
SMTPUser = ""
|
|
||||||
SMTPPassword = ""
|
|
||||||
From = ""
|
|
||||||
To = ""
|
|
||||||
78
TVEncoder.py
78
TVEncoder.py
|
|
@ -10,14 +10,9 @@ import getopt
|
||||||
from libfilemanager import FileManager
|
from libfilemanager import FileManager
|
||||||
from libsettings import Settings
|
from libsettings import Settings
|
||||||
import libhandbrake
|
import libhandbrake
|
||||||
import libemail
|
|
||||||
from libtvdatasource import TVData
|
from libtvdatasource import TVData
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from termcolor import colored
|
from termcolor import colored
|
||||||
import logging
|
|
||||||
|
|
||||||
SETTINGS = "settings.cfg"
|
|
||||||
EMAIL_SETTINGS = "EmailSettings.cfg"
|
|
||||||
|
|
||||||
|
|
||||||
def showhelp():
|
def showhelp():
|
||||||
|
|
@ -31,7 +26,6 @@ def showhelp():
|
||||||
'files that will be processed without actually encoding them'
|
'files that will be processed without actually encoding them'
|
||||||
print 'TVEncoder.py -e - encode the files that have been processed'
|
print 'TVEncoder.py -e - encode the files that have been processed'
|
||||||
print 'TVEncoder.py -e -l - list the files that would be encoded'
|
print 'TVEncoder.py -e -l - list the files that would be encoded'
|
||||||
print 'TVEncoder.py -c - check the output directories for duplicates'
|
|
||||||
|
|
||||||
|
|
||||||
def print_shows(shows):
|
def print_shows(shows):
|
||||||
|
|
@ -75,11 +69,9 @@ def processarguments(options):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
inputoptions = namedtuple("inputoptions",
|
inputoptions = namedtuple("inputoptions",
|
||||||
"numfiles doencode readonly dolist "
|
"numfiles doencode readonly dolist")
|
||||||
"checkduplicates")
|
|
||||||
|
|
||||||
inputoptions.readonly = False
|
inputoptions.readonly = False
|
||||||
inputoptions.checkduplicates = False
|
|
||||||
|
|
||||||
for opt, arg in options:
|
for opt, arg in options:
|
||||||
if opt == '-h':
|
if opt == '-h':
|
||||||
|
|
@ -93,8 +85,6 @@ def processarguments(options):
|
||||||
inputoptions.numfiles = arg
|
inputoptions.numfiles = arg
|
||||||
elif opt == "-l":
|
elif opt == "-l":
|
||||||
inputoptions.readonly = True
|
inputoptions.readonly = True
|
||||||
elif opt == "-c":
|
|
||||||
inputoptions.checkduplicates = True
|
|
||||||
|
|
||||||
return inputoptions
|
return inputoptions
|
||||||
|
|
||||||
|
|
@ -104,25 +94,15 @@ def main(argv):
|
||||||
The main program for TVEncoder.
|
The main program for TVEncoder.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
opts, _ = getopt.getopt(argv, "hlpecn:")
|
opts, args = getopt.getopt(argv, "hlpen:")
|
||||||
except getopt.GetoptError:
|
except getopt.GetoptError:
|
||||||
showhelp()
|
showhelp()
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
inputoptions = processarguments(opts)
|
inputoptions = processarguments(opts)
|
||||||
|
|
||||||
settings = Settings(SETTINGS)
|
settings = Settings("settings.cfg")
|
||||||
filemanager = FileManager(settings)
|
filemanager = FileManager(settings)
|
||||||
|
|
||||||
if inputoptions.checkduplicates:
|
|
||||||
print "Searching for duplicates..."
|
|
||||||
duplicates = filemanager.checkexistingduplicates()
|
|
||||||
if duplicates:
|
|
||||||
for duplicate in duplicates:
|
|
||||||
print duplicate
|
|
||||||
else:
|
|
||||||
print "No duplicates found."
|
|
||||||
return
|
|
||||||
|
|
||||||
if inputoptions.readonly:
|
if inputoptions.readonly:
|
||||||
if inputoptions.doencode:
|
if inputoptions.doencode:
|
||||||
#Generate the list of files that would be encoded
|
#Generate the list of files that would be encoded
|
||||||
|
|
@ -136,69 +116,25 @@ def main(argv):
|
||||||
else:
|
else:
|
||||||
if inputoptions.doencode:
|
if inputoptions.doencode:
|
||||||
#Encode the files and move them to their final destination
|
#Encode the files and move them to their final destination
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
|
||||||
generallogger = createlogger("general", settings.generallogfile(),
|
|
||||||
logging.DEBUG)
|
|
||||||
actionlogger = createlogger("action", settings.actionlogfile(),
|
|
||||||
logging.INFO)
|
|
||||||
|
|
||||||
showdata = filemanager.getencodingfiles(inputoptions.readonly)
|
showdata = filemanager.getencodingfiles(inputoptions.readonly)
|
||||||
generallogger.info("There are {0} files to process."
|
|
||||||
.format(len(showdata)))
|
|
||||||
for show in showdata:
|
|
||||||
generallogger.info("========================================")
|
|
||||||
generallogger.info("Processing {0} of {1}, {2}".format(
|
|
||||||
showdata.index(show) + 1, len(showdata), str(show)))
|
|
||||||
|
|
||||||
|
for show in showdata:
|
||||||
if filemanager.checkfileexists(show.outputfile):
|
if filemanager.checkfileexists(show.outputfile):
|
||||||
message = "File {0} already exists. Cannot process." \
|
print "File {0} already exists. Cannot process." \
|
||||||
.format(show.outputfile)
|
.format(show.outputfile)
|
||||||
generallogger.warning(message)
|
|
||||||
actionlogger.warning(message)
|
|
||||||
else:
|
else:
|
||||||
result = libhandbrake.encode(settings.handbrakecommand(),
|
result = libhandbrake.encode(settings.handbrakecommand(),
|
||||||
show.inputfile,
|
show.inputfile,
|
||||||
show.outputfile)
|
show.outputfile)
|
||||||
|
# TODO do something with the result
|
||||||
generallogger.info("Encode finished with result: {0}"
|
|
||||||
.format(result))
|
|
||||||
filemanager.performpostencodefileoperations(
|
filemanager.performpostencodefileoperations(
|
||||||
show.inputfile, show.outputfile)
|
show.inputfile, show.outputfile)
|
||||||
|
|
||||||
if filemanager.checkduplicates(show.outputfile):
|
|
||||||
actionlogger.info("There is an existing video file"
|
|
||||||
"present for {0}"
|
|
||||||
.format(show.outputfile))
|
|
||||||
|
|
||||||
generallogger.info("Processing finished.")
|
|
||||||
generallogger.info("==========================="
|
|
||||||
"=============\n\n")
|
|
||||||
|
|
||||||
libemail.sendemail(EMAIL_SETTINGS, "Encoding Complete",
|
|
||||||
"Finished encoding {0} shows."
|
|
||||||
.format(len(showdata)))
|
|
||||||
else:
|
else:
|
||||||
# Process files for encoding
|
# Process files for encoding
|
||||||
shows = filemanager.getfilestoprepare(inputoptions.numfiles)
|
shows = filemanager.getfilestoprepare(inputoptions.numfiles)
|
||||||
print "Preparing {0} files".format(len(shows))
|
|
||||||
tvdata = TVData(settings)
|
tvdata = TVData(settings)
|
||||||
tvdata.prepareepisodes(shows)
|
tvdata.prepareepisodes(shows)
|
||||||
|
|
||||||
|
|
||||||
def createlogger(name, filename, level):
|
|
||||||
"""
|
|
||||||
Create a logger named <name> that will write to the file <filename>
|
|
||||||
"""
|
|
||||||
|
|
||||||
logger = logging.getLogger(name)
|
|
||||||
handler = logging.FileHandler(filename, mode='w')
|
|
||||||
formatter = logging.Formatter('%(asctime)s %(message)s')
|
|
||||||
handler.setFormatter(formatter)
|
|
||||||
handler.setLevel(level)
|
|
||||||
logger.addHandler(handler)
|
|
||||||
return logger
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main(sys.argv[1:])
|
main(sys.argv[1:])
|
||||||
|
|
|
||||||
32
libemail.py
32
libemail.py
|
|
@ -1,32 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Created on Sat Jul 20 20:48:10 2013
|
|
||||||
|
|
||||||
@author: shanef
|
|
||||||
"""
|
|
||||||
|
|
||||||
from libsettings import EmailSettings
|
|
||||||
|
|
||||||
import smtplib
|
|
||||||
from email.mime.text import MIMEText
|
|
||||||
|
|
||||||
|
|
||||||
def sendemail(settingsfilename, subject, body):
|
|
||||||
"""
|
|
||||||
Send an email using the settings defined in settingsfilename
|
|
||||||
"""
|
|
||||||
|
|
||||||
settings = EmailSettings(settingsfilename)
|
|
||||||
|
|
||||||
msg = MIMEText(body, "plain")
|
|
||||||
msg["Subject"] = subject
|
|
||||||
msg["From"] = settings.getfromaddress()
|
|
||||||
msg["To"] = settings.gettoaddress()
|
|
||||||
|
|
||||||
smtp = smtplib.SMTP(settings.getsmtpserver())
|
|
||||||
smtp.ehlo()
|
|
||||||
smtp.starttls()
|
|
||||||
smtp.login(settings.getsmtpuser(), settings.getsmtppassword())
|
|
||||||
smtp.sendmail(settings.getfromaddress(), [settings.gettoaddress()],
|
|
||||||
msg.as_string())
|
|
||||||
smtp.quit()
|
|
||||||
|
|
@ -35,14 +35,9 @@ class EncodeData:
|
||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
if checkfileexists(self.outputfile, False):
|
if os.path.exists(self.outputfile):
|
||||||
errors.append("FILE_EXISTS")
|
errors.append("FILE_EXISTS")
|
||||||
|
|
||||||
if self.outputfile[-5:-4] == "_":
|
|
||||||
tempoutfile = self.outputfile[:-5] + self.outputfile[-4:]
|
|
||||||
if checkfileexists(tempoutfile, False):
|
|
||||||
errors.append("FILE_EXISTS")
|
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -112,62 +107,13 @@ class FileManager:
|
||||||
#will reach here if there were less than numberofFiles found
|
#will reach here if there were less than numberofFiles found
|
||||||
return showstoprocess
|
return showstoprocess
|
||||||
|
|
||||||
def checkexistingduplicates(self):
|
|
||||||
"""
|
|
||||||
Check the existing files in the output directories for duplicate
|
|
||||||
files, typically in different formats
|
|
||||||
"""
|
|
||||||
|
|
||||||
duplicates = []
|
|
||||||
for show in self.__settings.getshownames():
|
|
||||||
outputdir = self.__settings.getshowoutputdirectory(show)
|
|
||||||
|
|
||||||
for rootdir, dirnames, filenames in os.walk(outputdir):
|
|
||||||
for fle in filenames:
|
|
||||||
filename = os.path.join(rootdir, fle)
|
|
||||||
if os.path.splitext(fle)[1].lower() in [".avi", ".mpg", ".mpeg",
|
|
||||||
"mp4", ".mkv"]:
|
|
||||||
if self.checkduplicates(filename):
|
|
||||||
duplicates.append(filename)
|
|
||||||
|
|
||||||
return sorted(duplicates)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def checkduplicates(filename):
|
def checkfileexists(filename):
|
||||||
"""
|
|
||||||
Check to see if there are any other video files existing for the
|
|
||||||
episode
|
|
||||||
"""
|
|
||||||
|
|
||||||
dirname = os.path.dirname(filename)
|
|
||||||
filename = os.path.basename(filename)
|
|
||||||
fileseasonepisode = filename[:6]
|
|
||||||
fileextension = os.path.splitext(filename)[1]
|
|
||||||
|
|
||||||
for _, _, filenames in os.walk(dirname):
|
|
||||||
for show in filenames:
|
|
||||||
extension = os.path.splitext(show)[1]
|
|
||||||
if (extension.lower() in [".avi", ".mpg", ".mpeg", "mp4", ".mkv"] and
|
|
||||||
show[:6] == fileseasonepisode
|
|
||||||
and fileextension != extension):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def checkfileexists(filename, casesensitive=True):
|
|
||||||
"""
|
"""
|
||||||
Check to see if a file currently exists
|
Check to see if a file currently exists
|
||||||
"""
|
"""
|
||||||
if casesensitive:
|
|
||||||
return os.path.exists(filename)
|
|
||||||
else:
|
|
||||||
filename = os.path.basename(filename)
|
|
||||||
for dirfile in os.listdir(os.path.dirname(filename)):
|
|
||||||
if (filename.lower() == dirfile.lower()):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
return os.path.exists(filename)
|
||||||
|
|
||||||
def __getinputfilestoencode(self):
|
def __getinputfilestoencode(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -177,7 +123,7 @@ class FileManager:
|
||||||
filelist = []
|
filelist = []
|
||||||
|
|
||||||
for show in self.__settings.getshownames():
|
for show in self.__settings.getshownames():
|
||||||
for dirpath, _, filenames in os.walk(
|
for dirpath, dirnames, filenames in os.walk(
|
||||||
self.__settings.getshowinputdirectory(show)):
|
self.__settings.getshowinputdirectory(show)):
|
||||||
for inputfile in filenames:
|
for inputfile in filenames:
|
||||||
if inputfile.endswith(".mpg"):
|
if inputfile.endswith(".mpg"):
|
||||||
|
|
@ -222,23 +168,3 @@ def findseason(path, filename, readonly):
|
||||||
os.makedirs(seasonpath)
|
os.makedirs(seasonpath)
|
||||||
|
|
||||||
return seasonpath
|
return seasonpath
|
||||||
|
|
||||||
|
|
||||||
def checkfileexists(filename, casesensitive=True):
|
|
||||||
"""
|
|
||||||
Check to see if a file currently exists
|
|
||||||
"""
|
|
||||||
dirname = os.path.dirname(filename)
|
|
||||||
|
|
||||||
if casesensitive:
|
|
||||||
return os.path.exists(filename)
|
|
||||||
else:
|
|
||||||
if not os.path.exists(dirname):
|
|
||||||
return False
|
|
||||||
|
|
||||||
basename = os.path.basename(filename)
|
|
||||||
for dirfile in os.listdir(dirname):
|
|
||||||
if (basename.lower() == dirfile.lower()):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,19 @@ Created on Fri Jul 5 20:14:15 2013
|
||||||
from configobj import ConfigObj
|
from configobj import ConfigObj
|
||||||
|
|
||||||
|
|
||||||
|
#==============================================================================
|
||||||
|
# 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:
|
class Settings:
|
||||||
"""
|
"""
|
||||||
Accessor for the configuration file
|
Accessor for the configuration file
|
||||||
|
|
@ -34,27 +47,6 @@ class Settings:
|
||||||
|
|
||||||
return self.__config["HandbrakeCommand"]
|
return self.__config["HandbrakeCommand"]
|
||||||
|
|
||||||
def illegalcharacters(self):
|
|
||||||
"""
|
|
||||||
Get a list of illegal characters for filenames
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__config["IllegalCharacters"]
|
|
||||||
|
|
||||||
def generallogfile(self):
|
|
||||||
"""
|
|
||||||
Get the filename to save general log messages to
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__config["Logging"]["General"]
|
|
||||||
|
|
||||||
def actionlogfile(self):
|
|
||||||
"""
|
|
||||||
Get the filename to save the action log messages to
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__config["Logging"]["Action"]
|
|
||||||
|
|
||||||
def mythtvaddress(self):
|
def mythtvaddress(self):
|
||||||
"""
|
"""
|
||||||
Get the MythTV/address setting
|
Get the MythTV/address setting
|
||||||
|
|
@ -214,9 +206,11 @@ class Settings:
|
||||||
else:
|
else:
|
||||||
return show["SickbeardPrefix"]
|
return show["SickbeardPrefix"]
|
||||||
|
|
||||||
|
# TODO check if this is actually doing anything. it seems like it
|
||||||
|
# just returns what is input
|
||||||
def getshow(self, showname):
|
def getshow(self, showname):
|
||||||
"""
|
"""
|
||||||
Get the name of the show, showname.
|
Get the InputDirectory setting for the show, showname.
|
||||||
"""
|
"""
|
||||||
showsection = self.__getshowsubsection(showname)
|
showsection = self.__getshowsubsection(showname)
|
||||||
if showsection is None:
|
if showsection is None:
|
||||||
|
|
@ -237,51 +231,3 @@ class Settings:
|
||||||
return self.__config["Shows"][show]
|
return self.__config["Shows"][show]
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class EmailSettings:
|
|
||||||
"""
|
|
||||||
Accessor for the email configuration file
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, settingsfile):
|
|
||||||
"""
|
|
||||||
Initialise settingsfile as a configobj
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.__config = ConfigObj(settingsfile)
|
|
||||||
|
|
||||||
def getsmtpserver(self):
|
|
||||||
"""
|
|
||||||
Get the address of the smtp server
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__config["SMTPServer"]
|
|
||||||
|
|
||||||
def getsmtpuser(self):
|
|
||||||
"""
|
|
||||||
Get the username for the smtp server
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__config["SMTPUser"]
|
|
||||||
|
|
||||||
def getsmtppassword(self):
|
|
||||||
"""
|
|
||||||
Get the username for the smtp server
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__config["SMTPPassword"]
|
|
||||||
|
|
||||||
def getfromaddress(self):
|
|
||||||
"""
|
|
||||||
Get the from address for emails
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__config["From"]
|
|
||||||
|
|
||||||
def gettoaddress(self):
|
|
||||||
"""
|
|
||||||
Get the to address for emails
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self.__config["To"]
|
|
||||||
|
|
|
||||||
|
|
@ -67,14 +67,13 @@ class Sickbeard:
|
||||||
|
|
||||||
jsonurl = urlopen("{0}?cmd=show.seasons&tvdbid={1}".format(
|
jsonurl = urlopen("{0}?cmd=show.seasons&tvdbid={1}".format(
|
||||||
self.__getapiurl(), showid))
|
self.__getapiurl(), showid))
|
||||||
|
|
||||||
result = json.loads(jsonurl.read())
|
result = json.loads(jsonurl.read())
|
||||||
|
|
||||||
for season in result['data']:
|
for season in result['data']:
|
||||||
for episode in result['data'][season]:
|
for episode in result['data'][season]:
|
||||||
episodename = result['data'][season][episode]['name']
|
episodename = result['data'][season][episode]['name']
|
||||||
if name is not None and fuzz.ratio(name.lower(),
|
if name is not None and fuzz.partial_ratio(name.lower(),
|
||||||
episodename.lower()) > 85:
|
episodename) > 90:
|
||||||
return (season, episode, episodename)
|
return (season, episode, episodename)
|
||||||
elif description is not None:
|
elif description is not None:
|
||||||
descriptionqueryresult = \
|
descriptionqueryresult = \
|
||||||
|
|
@ -85,6 +84,14 @@ class Sickbeard:
|
||||||
|
|
||||||
return (0, 0, '')
|
return (0, 0, '')
|
||||||
|
|
||||||
|
#==============================================================================
|
||||||
|
# def GetEpisodeName(subtitle, showName):
|
||||||
|
# if subtitle[:len(showName)].lower() == showName.lower():
|
||||||
|
# return subtitle[len(showName + ' and the '):]
|
||||||
|
# else:
|
||||||
|
# return subtitle
|
||||||
|
#==============================================================================
|
||||||
|
|
||||||
def fixepisodetitle(self, showname, episodetitle):
|
def fixepisodetitle(self, showname, episodetitle):
|
||||||
"""
|
"""
|
||||||
Check to see if there is a prefix specified for the show. If there is,
|
Check to see if there is a prefix specified for the show. If there is,
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,8 @@ class TVData:
|
||||||
seasonfolder = "Season {0}".format(show.season)
|
seasonfolder = "Season {0}".format(show.season)
|
||||||
season = "S{0}".format(show.season)
|
season = "S{0}".format(show.season)
|
||||||
episode = "E{0}".format(show.episode)
|
episode = "E{0}".format(show.episode)
|
||||||
renamedfile = self.getoutputfilename(season, episode,
|
renamedfile = "{0}{1} - {2} - SD TV_.mpg".format(season, episode,
|
||||||
show.subtitle)
|
show.subtitle)
|
||||||
|
|
||||||
directory = self.getdirectory(show.title, seasonfolder,
|
directory = self.getdirectory(show.title, seasonfolder,
|
||||||
season, episode)
|
season, episode)
|
||||||
|
|
@ -102,17 +102,20 @@ class TVData:
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getoutputfilename(self, season, episode, name):
|
#==============================================================================
|
||||||
"""
|
# def __determinetargetfilename(directory, filename, inputfilename):
|
||||||
Get the output filename, and remove any illegal characters
|
# """
|
||||||
"""
|
# Determine the filename for the input file. If the path does not
|
||||||
|
# exist, it is created.
|
||||||
filename = "{0}{1} - {2} - SD TV_.mpg".format(season, episode, name)
|
# """
|
||||||
|
#
|
||||||
for illegalcharacter in self.__settings.illegalcharacters():
|
# inputdir = os.path.join(directory, inputfilename[:-4])
|
||||||
filename = filename.replace(illegalcharacter, "")
|
#
|
||||||
|
# if not os.path.exists(inputdir):
|
||||||
return filename
|
# os.makedirs(inputdir)
|
||||||
|
#
|
||||||
|
# return os.path.join(inputdir, filename)
|
||||||
|
#==============================================================================
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def processepisode(inputfile, outputfile):
|
def processepisode(inputfile, outputfile):
|
||||||
|
|
@ -134,11 +137,4 @@ class TVData:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for showdata in showsdata:
|
for showdata in showsdata:
|
||||||
print "========================================"
|
|
||||||
print "Copying {0} to {1}".format(showdata.inputfile,
|
|
||||||
showdata.outputfile)
|
|
||||||
|
|
||||||
self.processepisode(showdata.inputfile, showdata.outputfile)
|
self.processepisode(showdata.inputfile, showdata.outputfile)
|
||||||
|
|
||||||
print "Finished copy"
|
|
||||||
print "========================================\n\n"
|
|
||||||
|
|
|
||||||
3
pep8.sh
3
pep8.sh
|
|
@ -1,3 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
pep8 libemail.py TVEncoder.py libfilemanager.py libhandbrake.py libmythtv.py libsettings.py libsickbeard.py libtvdatasource.py libtvshow.py
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
pylint TVEncoder.py libfilemanager.py libhandbrake.py libmythtv.py libsettings.py libsickbeard.py libtvdatasource.py libtvshow.py libemail.py
|
|
||||||
52
settings.cfg
52
settings.cfg
|
|
@ -1,10 +1,5 @@
|
||||||
TVRecordings = "/Volumes/TV Recordings/"
|
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"
|
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"
|
||||||
IllegalCharacters = "?", ":"
|
|
||||||
|
|
||||||
[ "Logging" ]
|
|
||||||
General = "logs/encoding.log"
|
|
||||||
Action = "logs/needsaction.log"
|
|
||||||
|
|
||||||
[ "MythTV" ]
|
[ "MythTV" ]
|
||||||
address = 192.168.0.2
|
address = 192.168.0.2
|
||||||
|
|
@ -18,55 +13,46 @@ IllegalCharacters = "?", ":"
|
||||||
APIKey = 3678177136222bf5002be209220ccb20
|
APIKey = 3678177136222bf5002be209220ccb20
|
||||||
|
|
||||||
[ "Shows" ]
|
[ "Shows" ]
|
||||||
VideoProcessingDir = "/srv/storage2/files/VideoProcessing/"
|
UnknownInput = "/srv/storage2/files/VideoProcessing/Unknown/"
|
||||||
KidsTVDir = "/srv/storage2/videos/Kids/TV/"
|
|
||||||
UnknownInput = "%(VideoProcessingDir)sUnknown/"
|
|
||||||
[[ "Thomas the Tank Engine & Friends" ]]
|
[[ "Thomas the Tank Engine & Friends" ]]
|
||||||
InputDirectory = "%(VideoProcessingDir)sThomas/"
|
InputDirectory = "/srv/storage2/files/VideoProcessing/Thomas/Input/"
|
||||||
UnknownDirectory = "%(UnknownInput)sThomas/"
|
UnknownDirectory = "/srv/storage2/files/VideoProcessing/Unknown/Thomas/"
|
||||||
OutputDirectory = "%(KidsTVDir)sThomas The Tank Engine & Friends/"
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/Thomas The Tank Engine & Friends/"
|
||||||
alias = "Thomas and Friends",
|
alias = "Thomas and Friends",
|
||||||
MythTvEpisodePrefix = ,
|
MythTvEpisodePrefix = ,
|
||||||
SickbeardPrefix = ""
|
SickbeardPrefix = ""
|
||||||
[[ "Chuggington" ]]
|
[[ "Chuggington" ]]
|
||||||
InputDirectory = "%(VideoProcessingDir)sChuggington/"
|
InputDirectory = "/srv/storage2/files/VideoProcessing/Chuggington/Input/"
|
||||||
UnknownDirectory = "%(UnknownInput)sChuggington/"
|
UnknownDirectory = "/srv/storage2/files/VideoProcessing/Unknown/Chuggington/"
|
||||||
OutputDirectory = "%(KidsTVDir)sChuggington/"
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/Chuggington/"
|
||||||
alias = ,
|
alias = ,
|
||||||
MythTvEpisodePrefix = ,
|
MythTvEpisodePrefix = ,
|
||||||
SickbeardPrefix = ""
|
SickbeardPrefix = ""
|
||||||
[[ "Mike the Knight" ]]
|
[[ "Mike the Knight" ]]
|
||||||
InputDirectory = "%(VideoProcessingDir)sMikeTheKnight/"
|
InputDirectory = "/srv/storage2/files/VideoProcessing/MikeTheKnight/Input/"
|
||||||
UnknownDirectory = "%(UnknownInput)sMikeTheKnight/"
|
UnknownDirectory = "/srv/storage2/files/VideoProcessing/Unknown/MikeTheKnight/"
|
||||||
OutputDirectory = "%(KidsTVDir)sMike the Knight/"
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/Mike the Knight/"
|
||||||
alias = ,
|
alias = ,
|
||||||
MythTvEpisodePrefix = "Mike the Knight and the ", Mike the Knight and "
|
MythTvEpisodePrefix = "Mike the Knight and the ", Mike the Knight and "
|
||||||
SickbeardPrefix = ""
|
SickbeardPrefix = ""
|
||||||
[[ "Octonauts" ]]
|
[[ "Octonauts" ]]
|
||||||
InputDirectory = "%(VideoProcessingDir)sOctonauts/"
|
InputDirectory = "/srv/storage2/files/VideoProcessing/Octonauts/Input/"
|
||||||
UnknownDirectory = "%(UnknownInput)sOctonauts/"
|
UnknownDirectory = "/srv/storage2/files/VideoProcessing/Unknown/Octonauts/"
|
||||||
OutputDirectory = "%(KidsTVDir)sOctonauts/"
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/Octonauts/"
|
||||||
alias = "The Octonauts",
|
alias = "The Octonauts",
|
||||||
MythTvEpisodePrefix = "The Octonauts and ",
|
MythTvEpisodePrefix = "The Octonauts and ",
|
||||||
SickbeardPrefix = "The"
|
SickbeardPrefix = "The"
|
||||||
[[ "In the Night Garden" ]]
|
[[ "In the Night Garden" ]]
|
||||||
InputDirectory = "%(VideoProcessingDir)sInTheNightGarden/"
|
InputDirectory = "/srv/storage2/files/VideoProcessing/InTheNightGarden/Input/"
|
||||||
UnknownDirectory = "%(UnknownInput)sInTheNightGarden/"
|
UnknownDirectory = "/srv/storage2/files/VideoProcessing/Unknown/InTheNightGarden/"
|
||||||
OutputDirectory = "%(KidsTVDir)sIn The Night Garden/"
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/In The Night Garden/"
|
||||||
alias = ,
|
alias = ,
|
||||||
MythTvEpisodePrefix = ,
|
MythTvEpisodePrefix = ,
|
||||||
SickbeardPrefix = ""
|
SickbeardPrefix = ""
|
||||||
[[ "Raa Raa! The Noisy Lion" ]]
|
[[ "Raa Raa! The Noisy Lion" ]]
|
||||||
InputDirectory = "%(VideoProcessingDir)sRaaRaa/"
|
InputDirectory = "/srv/storage2/files/VideoProcessing/RaaRaa/Input/"
|
||||||
UnknownDirectory = "%(UnknownInput)sRaaRaa/"
|
UnknownDirectory = "/srv/storage2/files/VideoProcessing/Unknown/RaaRaa/"
|
||||||
OutputDirectory = "%(KidsTVDir)sRaa Raa the Noisy Lion/"
|
OutputDirectory = "/srv/storage2/videos/Kids/TV/Raa Raa the Noisy Lion/"
|
||||||
alias = ,
|
|
||||||
MythTvEpisodePrefix = ,
|
|
||||||
SickbeardPrefix = ""
|
|
||||||
[[ "Fireman Sam" ]]
|
|
||||||
InputDirectory = "%(VideoProcessingDir)sFiremanSam/"
|
|
||||||
UnknownDirectory = "%(UnknownInput)sFiremanSam/"
|
|
||||||
OutputDirectory = "%(KidsTVDir)sFireman Sam/"
|
|
||||||
alias = ,
|
alias = ,
|
||||||
MythTvEpisodePrefix = ,
|
MythTvEpisodePrefix = ,
|
||||||
SickbeardPrefix = ""
|
SickbeardPrefix = ""
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Created on Sat Jul 13 20:37:47 2013
|
|
||||||
|
|
||||||
@author: shanef
|
|
||||||
"""
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
sys.path.insert(0, parentdir)
|
|
||||||
import TVEncoder
|
|
||||||
|
|
||||||
|
|
||||||
class TVEncoderTest(unittest.TestCase):
|
|
||||||
def test_processarguments_encodereadonly(self):
|
|
||||||
args = []
|
|
||||||
args.append(('-e', ''))
|
|
||||||
args.append(('-l', ''))
|
|
||||||
result = TVEncoder.processarguments(args)
|
|
||||||
|
|
||||||
self.assertTrue(result.doencode)
|
|
||||||
self.assertTrue(result.readonly)
|
|
||||||
|
|
||||||
def test_processarguments_encodereadonlyreverse(self):
|
|
||||||
args = []
|
|
||||||
args.append(('-l', ''))
|
|
||||||
args.append(('-e', ''))
|
|
||||||
result = TVEncoder.processarguments(args)
|
|
||||||
|
|
||||||
self.assertTrue(result.doencode)
|
|
||||||
self.assertTrue(result.readonly)
|
|
||||||
|
|
||||||
def test_processarguments_encode(self):
|
|
||||||
args = []
|
|
||||||
args.append(('-e', ''))
|
|
||||||
result = TVEncoder.processarguments(args)
|
|
||||||
|
|
||||||
self.assertTrue(result.doencode)
|
|
||||||
self.assertFalse(result.readonly)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(TVEncoderTest)
|
|
||||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Created on Fri Jul 19 23:31:16 2013
|
|
||||||
|
|
||||||
@author: shanef
|
|
||||||
"""
|
|
||||||
|
|
||||||
from minimock import Mock, mock
|
|
||||||
import unittest
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
sys.path.insert(0, parentdir)
|
|
||||||
import libemail
|
|
||||||
from libsettings import EmailSettings
|
|
||||||
import smtplib
|
|
||||||
|
|
||||||
|
|
||||||
class libemailtest(unittest.TestCase):
|
|
||||||
def test_SendEmail(self):
|
|
||||||
mock("EmailSettings.getfromaddress", returns="from@email.com")
|
|
||||||
mock("EmailSettings.gettoaddress", returns="to@email.com")
|
|
||||||
mock("EmailSettings.getsmtpserver", returns="smtp.test")
|
|
||||||
mock("EmailSettings.getsmtpuser", returns="user")
|
|
||||||
mock("EmailSettings.getsmtppassword", returns="password")
|
|
||||||
smtplib.SMTP = Mock('smtplib.SMTP')
|
|
||||||
smtplib.SMTP.mock_returns = Mock('smtp_connection')
|
|
||||||
|
|
||||||
libemail.sendemail("test", "subject", "body")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(libemailtest)
|
|
||||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
|
||||||
|
|
@ -8,11 +8,9 @@ Created on Fri Jul 5 14:12:26 2013
|
||||||
import unittest
|
import unittest
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import minimock
|
|
||||||
from minimock import mock, Mock
|
|
||||||
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
sys.path.insert(0, parentdir)
|
sys.path.insert(0, parentdir)
|
||||||
from libfilemanager import EncodeData, FileManager
|
from libfilemanager import EncodeData
|
||||||
|
|
||||||
|
|
||||||
class libfilemanagertest(unittest.TestCase):
|
class libfilemanagertest(unittest.TestCase):
|
||||||
|
|
@ -26,92 +24,6 @@ class libfilemanagertest(unittest.TestCase):
|
||||||
"{2}\n".format(showname, inputname, outputname)
|
"{2}\n".format(showname, inputname, outputname)
|
||||||
self.assertEqual(result, expected)
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
def test_EncodeDataCheckProblemsFileExists(self):
|
|
||||||
showname = "test show"
|
|
||||||
inputname = "test input"
|
|
||||||
outputname = "test_output.mkv"
|
|
||||||
data = EncodeData(showname, inputname, outputname)
|
|
||||||
mock("os.path.exists", returns=True)
|
|
||||||
|
|
||||||
result = data.checkproblems()
|
|
||||||
|
|
||||||
self.assertIn("FILE_EXISTS", result)
|
|
||||||
minimock.restore()
|
|
||||||
|
|
||||||
def test_EncodeDataCheckProblemsFile_Exists(self):
|
|
||||||
showname = "test show"
|
|
||||||
inputname = "test input"
|
|
||||||
outputname = "test_output_.mkv"
|
|
||||||
data = EncodeData(showname, inputname, outputname)
|
|
||||||
mock("os.path.exists", returns_iter=[False, True])
|
|
||||||
result = data.checkproblems()
|
|
||||||
self.assertIn("FILE_EXISTS", result)
|
|
||||||
minimock.restore()
|
|
||||||
|
|
||||||
def test_checkfileexistscaseinsensitive(self):
|
|
||||||
settings = Mock('libsettings.Settings')
|
|
||||||
filemanager = FileManager(settings)
|
|
||||||
|
|
||||||
mock("os.listdir", returns=["filename.test"])
|
|
||||||
|
|
||||||
result = filemanager.checkfileexists("/path/to/fiLename.test", False)
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
minimock.restore()
|
|
||||||
|
|
||||||
def test_checkduplicateavi(self):
|
|
||||||
settings = Mock('libsettings.Settings')
|
|
||||||
filemanager = FileManager(settings)
|
|
||||||
|
|
||||||
os.walk = dummywalk
|
|
||||||
|
|
||||||
result = filemanager.checkduplicates("/path/to/S03E14 - Test - SD TV.mkv")
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
minimock.restore()
|
|
||||||
|
|
||||||
def test_checkduplicatethomas(self):
|
|
||||||
settings = Mock('libsettings.Settings')
|
|
||||||
filemanager = FileManager(settings)
|
|
||||||
|
|
||||||
os.walk = thomaswalk
|
|
||||||
|
|
||||||
result = filemanager.checkduplicates("/path/to/S12E05 - Henry Gets It Wrong - SD TV.mkv")
|
|
||||||
|
|
||||||
self.assertTrue(result)
|
|
||||||
minimock.restore()
|
|
||||||
|
|
||||||
def test_checkduplicatenomatch(self):
|
|
||||||
settings = Mock('libsettings.Settings')
|
|
||||||
filemanager = FileManager(settings)
|
|
||||||
|
|
||||||
os.walk = dummywalk
|
|
||||||
|
|
||||||
result = filemanager.checkduplicates("/path/to/S03E13 - Test - SD TV.mkv")
|
|
||||||
|
|
||||||
self.assertFalse(result)
|
|
||||||
minimock.restore()
|
|
||||||
|
|
||||||
def test_checkduplicatesameextension(self):
|
|
||||||
settings = Mock('libsettings.Settings')
|
|
||||||
filemanager = FileManager(settings)
|
|
||||||
|
|
||||||
os.walk = dummywalk
|
|
||||||
|
|
||||||
result = filemanager.checkduplicates("/path/to/S03E14 - Test - SD TV.avi")
|
|
||||||
|
|
||||||
self.assertFalse(result)
|
|
||||||
minimock.restore()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def dummywalk(arg):
|
|
||||||
return [("/path/to/", [], ["S03E14 - Test - SD TV.avi"])]
|
|
||||||
|
|
||||||
def thomaswalk(arg):
|
|
||||||
return [(("/path/to/", [], ["S12E05 - Henry Gets It Wrong - Unknown.AVI"]))]
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(libfilemanagertest)
|
suite = unittest.TestLoader().loadTestsFromTestCase(libfilemanagertest)
|
||||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
unittest.TextTestRunner(verbosity=2).run(suite)
|
||||||
minimock.restore()
|
|
||||||
|
|
@ -4,48 +4,3 @@ Created on Fri Jul 5 14:12:38 2013
|
||||||
|
|
||||||
@author: shanef
|
@author: shanef
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
|
||||||
from minimock import Mock
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
sys.path.insert(0, parentdir)
|
|
||||||
import libsickbeard
|
|
||||||
import urllib
|
|
||||||
|
|
||||||
|
|
||||||
class SickbeardTest(unittest.TestCase):
|
|
||||||
def test_findepisodeCloseSubtitle(self):
|
|
||||||
settings = Mock('libsettings.Settings')
|
|
||||||
settings.sickbeardaddress.mock_returns = "test"
|
|
||||||
settings.sickbeardport.mock_returns = "123"
|
|
||||||
settings.sickbeardapikey.mock_returns = "test"
|
|
||||||
|
|
||||||
urllib.urlopen = dummy_urlopen
|
|
||||||
|
|
||||||
sickbeard = libsickbeard.Sickbeard(settings)
|
|
||||||
|
|
||||||
result = sickbeard.findepisode("78949", "Splish, Splash, Splosh")
|
|
||||||
|
|
||||||
self.assertEqual("13", result[0])
|
|
||||||
self.assertEqual("15", result[1])
|
|
||||||
self.assertEqual("Splish, Splash, Splosh!", result[2])
|
|
||||||
|
|
||||||
|
|
||||||
def dummy_urlopen(arg):
|
|
||||||
class TmpClass:
|
|
||||||
def read(arg):
|
|
||||||
jsonresult = '{ "data": {"13": { "15": { "airdate": "2010-02-12", ' \
|
|
||||||
'"name": "Splish, Splash, Splosh!", "quality": "N/A", ' \
|
|
||||||
'"status": "Wanted" } } }, "message": "", ' \
|
|
||||||
'"result": "success" }'
|
|
||||||
|
|
||||||
return jsonresult
|
|
||||||
|
|
||||||
return TmpClass()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(SickbeardTest)
|
|
||||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Created on Thu Jul 18 23:13:15 2013
|
|
||||||
|
|
||||||
@author: shanef
|
|
||||||
"""
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
from minimock import Mock
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
sys.path.insert(0, parentdir)
|
|
||||||
import libtvdatasource
|
|
||||||
|
|
||||||
|
|
||||||
class tvdatasourceTest(unittest.TestCase):
|
|
||||||
def test_GetOutputFilenameNoIllegals(self):
|
|
||||||
result = self._dooutputfilenametest("S01", "E02", "test name", "")
|
|
||||||
self.assertEqual(result, "S01E02 - test name - SD TV_.mpg")
|
|
||||||
|
|
||||||
def test_GetOutputFilenameOneIllegals(self):
|
|
||||||
result = self._dooutputfilenametest("S01", "E02", "test name?", "?")
|
|
||||||
self.assertEqual(result, "S01E02 - test name - SD TV_.mpg")
|
|
||||||
|
|
||||||
def test_GetOutputFilenameTwoIllegals(self):
|
|
||||||
result = self._dooutputfilenametest("S01", "E02", "tes>t name?", ["?", ">"])
|
|
||||||
self.assertEqual(result, "S01E02 - test name - SD TV_.mpg")
|
|
||||||
|
|
||||||
def _dooutputfilenametest(self, season, episode, name, illegals):
|
|
||||||
settings = Mock('libsettings.Settings')
|
|
||||||
settings.illegalcharacters.mock_returns = illegals
|
|
||||||
tvdatasource = libtvdatasource.TVData(settings)
|
|
||||||
return tvdatasource.getoutputfilename(season, episode, name)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(tvdatasourceTest)
|
|
||||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue