diff --git a/DeleteSamples.py b/DeleteSamples.py old mode 100755 new mode 100644 index ed114785..4386af29 --- a/DeleteSamples.py +++ b/DeleteSamples.py @@ -29,9 +29,9 @@ ### NZBGET POST-PROCESSING SCRIPT ### ############################################################################## - import os import sys +from nzbtomedia.nzbToMediaConfig import config def is_sample(filePath, inputName, maxSampleSize, SampleIDs): @@ -53,25 +53,18 @@ def is_sample(filePath, inputName, maxSampleSize, SampleIDs): if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5] < '11.0': print "Script triggered from NZBGet (11.0 or later)." - # NZBGet argv: all passed as environment variables. - # Exit codes used by NZBGet - POSTPROCESS_PARCHECK=92 - POSTPROCESS_SUCCESS=93 - POSTPROCESS_ERROR=94 - POSTPROCESS_NONE=95 - # Check nzbget.conf options status = 0 if os.environ['NZBOP_UNPACK'] != 'yes': print "Please enable option \"Unpack\" in nzbget configuration file, exiting." - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) # Check par status if os.environ['NZBPP_PARSTATUS'] == '3': print "Par-check successful, but Par-repair disabled, exiting." print "Please check your Par-repair settings for future downloads." - sys.exit(POSTPROCESS_NONE) + sys.exit(config.NZBGET_POSTPROCESS_NONE) if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4': print "Par-repair failed, setting status \"failed\"." @@ -102,7 +95,7 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 # All checks done, now launching the script. if status == 1: - sys.exit(POSTPROCESS_NONE) + sys.exit(config.NZBGET_POSTPROCESS_NONE) mediaContainer = os.environ['NZBPO_MEDIAEXTENSIONS'].split(',') SampleIDs = os.environ['NZBPO_SAMPLEIDS'].split(',') @@ -119,8 +112,8 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 os.unlink(filePath) except: print "Error: unable to delete file", filePath - sys.exit(POSTPROCESS_ERROR) - sys.exit(POSTPROCESS_SUCCESS) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_SUCCESS) else: print "This script can only be called from NZBGet (11.0 or later)." diff --git a/ResetDateTime.py b/ResetDateTime.py old mode 100755 new mode 100644 index 24ec2e1e..20ac62ca --- a/ResetDateTime.py +++ b/ResetDateTime.py @@ -13,33 +13,27 @@ ### NZBGET POST-PROCESSING SCRIPT ### ############################################################################## -import os -import sys - # NZBGet V11+ # Check if the script is called from nzbget 11.0 or later +import os +import sys +from nzbtomedia.nzbToMediaConfig import config + if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5] < '11.0': print "Script triggered from NZBGet (11.0 or later)." - # NZBGet argv: all passed as environment variables. - # Exit codes used by NZBGet - POSTPROCESS_PARCHECK=92 - POSTPROCESS_SUCCESS=93 - POSTPROCESS_ERROR=94 - POSTPROCESS_NONE=95 - # Check nzbget.conf options status = 0 if os.environ['NZBOP_UNPACK'] != 'yes': print "Please enable option \"Unpack\" in nzbget configuration file, exiting." - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) # Check par status if os.environ['NZBPP_PARSTATUS'] == '3': print "Par-check successful, but Par-repair disabled, exiting." print "Please check your Par-repair settings for future downloads." - sys.exit(POSTPROCESS_NONE) + sys.exit(config.NZBGET_POSTPROCESS_NONE) if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4': print "Par-repair failed, setting status \"failed\"." @@ -70,7 +64,7 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 # All checks done, now launching the script. if status == 1: - sys.exit(POSTPROCESS_NONE) + sys.exit(config.NZBGET_POSTPROCESS_NONE) directory = os.path.normpath(os.environ['NZBPP_DIRECTORY']) for dirpath, dirnames, filenames in os.walk(directory): @@ -82,8 +76,8 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 continue except: print "Error: unable to reset time for file", file - sys.exit(POSTPROCESS_ERROR) - sys.exit(POSTPROCESS_SUCCESS) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_SUCCESS) else: print "This script can only be called from NZBGet (11.0 or later)." diff --git a/TorrentToMedia.py b/TorrentToMedia.py index 3b91515d..4a3ea7ca 100755 --- a/TorrentToMedia.py +++ b/TorrentToMedia.py @@ -1,24 +1,25 @@ #!/usr/bin/env python - -#System imports -import logging import datetime +import logging +import os +import re +import sys +import shutil from subprocess import Popen - -# Custom imports -import autoProcess.migratecfg as migratecfg -import extractor.extractor as extractor -import autoProcess.autoProcessComics as autoProcessComics -import autoProcess.autoProcessGames as autoProcessGames -import autoProcess.autoProcessMusic as autoProcessMusic -import autoProcess.autoProcessMovie as autoProcessMovie -import autoProcess.autoProcessTV as autoProcessTV -from autoProcess.nzbToMediaEnv import * -from autoProcess.nzbToMediaUtil import * -from autoProcess.autoSickBeardFork import autoFork -from utorrent.client import UTorrentClient -from transmissionrpc.client import Client as TransmissionClient -from synchronousdeluge.client import DelugeClient +from nzbtomedia.autoProcess.autoProcessComics import autoProcessComics +from nzbtomedia.autoProcess.autoProcessGames import autoProcessGames +from nzbtomedia.autoProcess.autoProcessMovie import autoProcessMovie +from nzbtomedia.autoProcess.autoProcessMusic import autoProcessMusic +from nzbtomedia.autoProcess.autoProcessTV import autoProcessTV +from nzbtomedia.extractor import extractor +from nzbtomedia.migratecfg import migratecfg +from nzbtomedia.nzbToMediaAutoFork import autoFork +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import category_search, safeName, is_sample, copy_link, WakeUp, parse_args, flatten, \ + nzbtomedia_configure_logging +from nzbtomedia.synchronousdeluge.client import DelugeClient +from nzbtomedia.utorrent.client import UTorrentClient +from nzbtomedia.transmissionrpc.client import Client as TransmissionClient def main(inputDirectory, inputName, inputCategory, inputHash, inputID): @@ -31,6 +32,14 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): extractionSuccess = False copy_list = [] useLink = useLink_in + file = None + + delugeClient = "" + utorrentClass = "" + TransmissionClass = "" + + # init autoFork + fork, fork_params = autoFork(inputCategory) Logger.debug("MAIN: Received Directory: %s | Name: %s | Category: %s", inputDirectory, inputName, inputCategory) @@ -38,15 +47,14 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): Logger.debug("MAIN: Determined Directory: %s | Name: %s | Category: %s", inputDirectory, inputName, inputCategory) - sbFork, sbParams = autoFork() - - if inputCategory in sbCategory and sbFork in SICKBEARD_TORRENT and Torrent_ForceLink != 1: - Logger.info("MAIN: Calling SickBeard's %s branch to post-process: %s",sbFork ,inputName) - result = autoProcessTV.processEpisode(inputDirectory, inputName, int(0)) - if result == 1: - Logger.info("MAIN: A problem was reported in the autoProcess* script.") - Logger.info("MAIN: All done.") - sys.exit() + if inputCategory in sbCategory: + if fork in config.SICKBEARD_TORRENT and Torrent_ForceLink != 1: + Logger.info("MAIN: Calling SickBeard's %s branch to post-process: %s",fork ,inputName) + result = autoProcessTV().processEpisode(inputDirectory, inputName, 0) + if result != 0: + Logger.info("MAIN: A problem was reported in the autoProcess* script.") + Logger.info("MAIN: All done.") + sys.exit() outputDestination = "" for category in categories: @@ -63,7 +71,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): continue if outputDestination == "": if inputCategory == "": - inputCategory = "UNCAT" + inputCategory = "UNCAT" if os.path.basename(inputDirectory) == inputName and os.path.isdir(inputDirectory): Logger.info("MAIN: Download is a directory") outputDestination = os.path.normpath(os.path.join(outputDirectory, inputCategory, safeName(inputName))) @@ -79,7 +87,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): processOnly.extend(user_script_categories) # Adds all categories to be processed by userscript. if not inputCategory in processOnly: - Logger.info("MAIN: No processing to be done for category: %s. Exiting", inputCategory) + Logger.info("MAIN: No processing to be done for category: %s. Exiting", inputCategory) Logger.info("MAIN: All done.") sys.exit() @@ -91,14 +99,14 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): utorrentClass = UTorrentClient(uTorrentWEBui, uTorrentUSR, uTorrentPWD) except: Logger.exception("MAIN: Failed to connect to uTorrent") - utorrentClass = "" + if clientAgent == 'transmission': try: Logger.debug("MAIN: Connecting to %s: http://%s:%s", clientAgent, TransmissionHost, TransmissionPort) TransmissionClass = TransmissionClient(TransmissionHost, TransmissionPort, TransmissionUSR, TransmissionPWD) except: Logger.exception("MAIN: Failed to connect to Transmission") - TransmissionClass = "" + if clientAgent == 'deluge': try: Logger.debug("MAIN: Connecting to %s: http://%s:%s", clientAgent, DelugeHost, DelugePort) @@ -106,17 +114,16 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): delugeClient.connect(host = DelugeHost, port = DelugePort, username = DelugeUSR, password = DelugePWD) except: Logger.exception("MAIN: Failed to connect to deluge") - delugeClient = "" # if we are using links with uTorrent it means we need to pause it in order to access the files Logger.debug("MAIN: Stoping torrent %s in %s while processing", inputName, clientAgent) - if clientAgent == 'utorrent' and utorrentClass != "": + if clientAgent == 'utorrent' and utorrentClass != "": utorrentClass.stop(inputHash) if clientAgent == 'transmission' and TransmissionClass !="": TransmissionClass.stop_torrent(inputID) if clientAgent == 'deluge' and delugeClient != "": delugeClient.core.pause_torrent([inputID]) - time.sleep(5) # Give Torrent client some time to catch up with the change + datetime.time.sleep(5) # Give Torrent client some time to catch up with the change Logger.debug("MAIN: Scanning files in directory: %s", inputDirectory) @@ -125,9 +132,9 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): if useLink in ['sym','move']: # These don't work for HeadPhones. useLink = 'no' # default to copy. - if inputCategory in sbCategory and sbFork in SICKBEARD_TORRENT: # Don't flatten when sending to SICKBEARD_TORRENT + if inputCategory in sbCategory and fork in config.SICKBEARD_TORRENT: # Don't flatten when sending to SICKBEARD_TORRENT noFlatten.extend(sbCategory) - + outputDestinationMaster = outputDestination # Save the original, so we can change this within the loop below, and reset afterwards. now = datetime.datetime.now() for dirpath, dirnames, filenames in os.walk(inputDirectory): @@ -147,7 +154,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): targetDirectory = os.path.join(outputDestination, file) if root == 1: - if foundFile == int(0): + if foundFile == int(0): Logger.debug("MAIN: Looking for %s in: %s", inputName, file) if (safeName(inputName) in safeName(file)) or (safeName(fileName) in safeName(inputName)): #pass # This file does match the Torrent name @@ -167,7 +174,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): else: continue # This file has not been recently moved or created, skip it - if inputCategory in sbCategory and sbFork in SICKBEARD_TORRENT: # We want to link every file. + if inputCategory in sbCategory and fork in config.SICKBEARD_TORRENT: # We want to link every file. Logger.info("MAIN: Found file %s in %s", fileExtension, filePath) try: copy_link(filePath, targetDirectory, useLink, outputDestination) @@ -208,13 +215,13 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): if re.search(r'\d+', os.path.splitext(fileName)[1]) and os.path.dirname(filePath) in extracted_folder and not any(item in os.path.splitext(fileName)[1] for item in ['.720p','.1080p','.x264']): part = int(re.search(r'\d+', os.path.splitext(fileName)[1]).group()) if part == 1: # we only want to extract the primary part. - Logger.debug("MAIN: Found primary part of a multi-part archive %s. Extracting", file) + Logger.debug("MAIN: Found primary part of a multi-part archive %s. Extracting", file) else: Logger.debug("MAIN: Found part %s of a multi-part archive %s. Ignoring", part, file) continue Logger.info("MAIN: Found compressed archive %s for file %s", fileExtension, filePath) try: - if inputCategory in hpCategory: # HP needs to scan the same dir as passed to downloader. + if inputCategory in hpCategory: # HP needs to scan the same dir as passed to downloader. extractor.extract(filePath, inputDirectory) else: extractor.extract(filePath, outputDestination) @@ -233,11 +240,11 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): continue outputDestination = outputDestinationMaster # Reset here. - if not inputCategory in noFlatten: #don't flatten hp in case multi cd albums, and we need to copy this back later. + if not inputCategory in noFlatten: #don't flatten hp in case multi cd albums, and we need to copy this back later. flatten(outputDestination) # Now check if movie files exist in destination: - if inputCategory in cpsCategory + sbCategory and not (inputCategory in sbCategory and sbFork in SICKBEARD_TORRENT): + if inputCategory in cpsCategory + sbCategory and not (inputCategory in sbCategory and fork in config.SICKBEARD_TORRENT): for dirpath, dirnames, filenames in os.walk(outputDestination): for file in filenames: filePath = os.path.join(dirpath, file) @@ -257,7 +264,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): else: Logger.debug("MAIN: Found %s media files in output. %s were found in input", str(video2), str(video)) - if inputCategory in sbCategory and sbFork in SICKBEARD_TORRENT: + if inputCategory in sbCategory and fork in config.SICKBEARD_TORRENT: if len(copy_list) > 0: Logger.debug("MAIN: Found and linked %s files", str(len(copy_list))) status = int(0) @@ -274,22 +281,23 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): Logger.error("MAIN: Something failed! Please check logs. Exiting") sys.exit(-1) + result = 0 if inputCategory in cpsCategory: Logger.info("MAIN: Calling CouchPotatoServer to post-process: %s", inputName) download_id = inputHash - result = autoProcessMovie.process(outputDestination, inputName, status, clientAgent, download_id, inputCategory) + result = autoProcessMovie().process(outputDestination, inputName, status, clientAgent, download_id, inputCategory) elif inputCategory in sbCategory: Logger.info("MAIN: Calling Sick-Beard to post-process: %s", inputName) - result = autoProcessTV.processEpisode(outputDestination, inputName, status, clientAgent, inputCategory) + result = autoProcessTV().processEpisode(outputDestination, inputName, status, clientAgent, inputCategory) elif inputCategory in hpCategory: Logger.info("MAIN: Calling HeadPhones to post-process: %s", inputName) - result = autoProcessMusic.process(inputDirectory, inputName, status, inputCategory) + result = autoProcessMusic().process(inputDirectory, inputName, status, clientAgent, inputCategory) elif inputCategory in mlCategory: Logger.info("MAIN: Calling Mylar to post-process: %s", inputName) - result = autoProcessComics.processEpisode(outputDestination, inputName, status, inputCategory) + result = autoProcessComics().processEpisode(outputDestination, inputName, status, clientAgent, inputCategory) elif inputCategory in gzCategory: Logger.info("MAIN: Calling Gamez to post-process: %s", inputName) - result = autoProcessGames.process(outputDestination, inputName, status, inputCategory) + result = autoProcessGames().process(outputDestination, inputName, status, clientAgent, inputCategory) if result == 1: Logger.info("MAIN: A problem was reported in the autoProcess* script. If torrent was paused we will resume seeding") @@ -334,7 +342,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): TransmissionClass.start_torrent(inputID) if clientAgent == 'deluge' and delugeClient != "": delugeClient.core.resume_torrent([inputID]) - time.sleep(5) + datetime.time.sleep(5) #cleanup if inputCategory in processCategories and result == 0 and os.path.isdir(outputDestination): num_files_new = int(0) @@ -346,7 +354,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): if fileExtension in mediaContainer or fileExtension in metaContainer: num_files_new = num_files_new + 1 file_list.append(file) - if num_files_new == int(0) or forceClean == 1: + if num_files_new == int(0) or forceClean == 1: Logger.info("All files have been processed. Cleaning outputDirectory %s", outputDestination) shutil.rmtree(outputDestination) else: @@ -411,11 +419,10 @@ def external_script(outputDestination,torrentName,torrentLabel): result = int(1) final_result = final_result + result - time.sleep(user_delay) + datetime.time.sleep(user_delay) num_files_new = int(0) for dirpath, dirnames, filenames in os.walk(outputDestination): for file in filenames: - filePath = os.path.join(dirpath, file) fileName, fileExtension = os.path.splitext(file) @@ -426,31 +433,24 @@ def external_script(outputDestination,torrentName,torrentLabel): Logger.info("All files have been processed. Cleaning outputDirectory %s", outputDestination) shutil.rmtree(outputDestination) elif user_script_clean == int(1) and num_files_new != int(0): - Logger.info("%s files were processed, but %s still remain. outputDirectory will not be cleaned.", num_files, num_files_new) + Logger.info("%s files were processed, but %s still remain. outputDirectory will not be cleaned.", num_files, num_files_new) return final_result if __name__ == "__main__": + # run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. + if migratecfg().migrate(): + nzbtomedia_configure_logging(config.LOG_FILE) + Logger = logging.getLogger(__name__) + Logger.info("====================") # Seperate old from new log + Logger.info("TorrentToMedia %s", config.NZBTOMEDIA_VERSION) - #check to migrate old cfg before trying to load. - if os.path.isfile(os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg.sample")): - migratecfg.migrate() - - # Logging - nzbtomedia_configure_logging(LOG_FILE) - Logger = logging.getLogger(__name__) - - Logger.info("====================") # Seperate old from new log - Logger.info("TorrentToMedia %s", VERSION) + Logger.info("MAIN: Loading config from %s", config.CONFIG_FILE) + else: + sys.exit(-1) WakeUp() - if not config(): - Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?") - sys.exit(-1) - - # CONFIG FILE - Logger.info("MAIN: Loading config from %s", CONFIG_FILE) - # EXAMPLE VALUES: + # EXAMPLE VALUES: clientAgent = config().get("Torrent", "clientAgent") # utorrent | deluge | transmission | rtorrent | other useLink_in = config().get("Torrent", "useLink") # no | hard | sym outputDirectory = config().get("Torrent", "outputDirectory") # /abs/path/to/complete/ @@ -470,19 +470,20 @@ if __name__ == "__main__": DelugePort = config().get("Torrent", "DelugePort") # 8084 DelugeUSR = config().get("Torrent", "DelugeUSR") # mysecretusr DelugePWD = config().get("Torrent", "DelugePWD") # mysecretpwr - + deleteOriginal = int(config().get("Torrent", "deleteOriginal")) # 0 forceClean = int(config().get("Torrent", "forceClean")) # 0 - + compressedContainer = (config().get("Extensions", "compressedExtensions")).split(',') # .zip,.rar,.7z mediaContainer = (config().get("Extensions", "mediaExtensions")).split(',') # .mkv,.avi,.divx metaContainer = (config().get("Extensions", "metaExtensions")).split(',') # .nfo,.sub,.srt minSampleSize = int(config().get("Extensions", "minSampleSize")) # 200 (in MB) SampleIDs = (config().get("Extensions", "SampleIDs")).split(',') # sample,-s. - + + Torrent_ForceLink = int(config().get("SickBeard", "Torrent_ForceLink")) # 1 + cpsCategory = (config().get("CouchPotato", "cpsCategory")).split(',') # movie sbCategory = (config().get("SickBeard", "sbCategory")).split(',') # tv - Torrent_ForceLink = int(config().get("SickBeard", "Torrent_ForceLink")) # 1 hpCategory = (config().get("HeadPhones", "hpCategory")).split(',') # music mlCategory = (config().get("Mylar", "mlCategory")).split(',') # comics gzCategory = (config().get("Gamez", "gzCategory")).split(',') # games @@ -493,7 +494,7 @@ if __name__ == "__main__": categories.extend(gzCategory) user_script_categories = config().get("UserScript", "user_script_categories").split(',') # NONE - if not "NONE" in user_script_categories: + if not "NONE" in user_script_categories: user_script_mediaExtensions = (config().get("UserScript", "user_script_mediaExtensions")).split(',') user_script = config().get("UserScript", "user_script_path") user_script_param = (config().get("UserScript", "user_script_param")).split(',') @@ -501,18 +502,18 @@ if __name__ == "__main__": user_script_clean = int(config().get("UserScript", "user_script_clean")) user_delay = int(config().get("UserScript", "delay")) user_script_runOnce = int(config().get("UserScript", "user_script_runOnce")) - + transcode = int(config().get("Transcoder", "transcode")) - n = 0 + n = 0 for arg in sys.argv: Logger.debug("arg %s is: %s", n, arg) n = n+1 - try: - inputDirectory, inputName, inputCategory, inputHash, inputID = parse_args(clientAgent) - except: + if not len(sys.argv) > 1: Logger.exception("MAIN: There was a problem loading variables") sys.exit(-1) + # process torrent + inputDirectory, inputName, inputCategory, inputHash, inputID = parse_args(clientAgent) main(inputDirectory, inputName, inputCategory, inputHash, inputID) diff --git a/autoProcess/Transcoder.py b/autoProcess/Transcoder.py deleted file mode 100644 index db34c8c3..00000000 --- a/autoProcess/Transcoder.py +++ /dev/null @@ -1,143 +0,0 @@ -import sys -import logging -import errno -from subprocess import call - -from nzbToMediaConfig import * - - -Logger = logging.getLogger() - -def Transcode_directory(dirName): - - if os.name == 'nt': - ffmpeg = os.path.join(os.path.dirname(sys.argv[0]), 'ffmpeg\\bin\\ffmpeg.exe') # note, will need to package in this dir. - useNiceness = False - if not os.path.isfile(ffmpeg): # problem - Logger.error("ffmpeg not found. ffmpeg needs to be located at: %s", ffmpeg) - Logger.info("Cannot transcode files in folder %s", dirName) - return 1 # failure - else: - if call(['which', 'ffmpeg']) != 0: - res = call([os.path.join(os.path.dirname(sys.argv[0]),'getffmpeg.sh')]) - if res or call(['which', 'ffmpeg']) != 0: # did not install or ffmpeg still not found. - Logger.error("Failed to install ffmpeg. Please install manually") - Logger.info("Cannot transcode files in folder %s", dirName) - return 1 # failure - else: - ffmpeg = 'ffmpeg' - else: - ffmpeg = 'ffmpeg' - useNiceness = True - - Logger.info("Loading config from %s", CONFIG_FILE) - - if not config(): - Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?") - return 1 # failure - - mediaContainer = (config().get("Extensions", "mediaExtensions")).split(',') - duplicate = int(config().get("Transcoder", "duplicate")) - ignoreExtensions = (config().get("Transcoder", "ignoreExtensions")).split(',') - outputVideoExtension = config().get("Transcoder", "outputVideoExtension").strip() - outputVideoCodec = config().get("Transcoder", "outputVideoCodec").strip() - outputVideoPreset = config().get("Transcoder", "outputVideoPreset").strip() - outputVideoFramerate = config().get("Transcoder", "outputVideoFramerate").strip() - outputVideoBitrate = config().get("Transcoder", "outputVideoBitrate").strip() - outputAudioCodec = config().get("Transcoder", "outputAudioCodec").strip() - outputAudioBitrate = config().get("Transcoder", "outputAudioBitrate").strip() - outputSubtitleCodec = config().get("Transcoder", "outputSubtitleCodec").strip() - outputFastStart = int(config().get("Transcoder", "outputFastStart")) - outputQualityPercent = int(config().get("Transcoder", "outputQualityPercent")) - if useNiceness: - niceness = int(config().get("Transcoder", "niceness")) - - map(lambda ext: ext.strip(), mediaContainer) - map(lambda ext: ext.strip(), ignoreExtensions) - - Logger.info("Checking for files to be transcoded") - final_result = 0 # initialize as successful - for dirpath, dirnames, filenames in os.walk(dirName): - for file in filenames: - filePath = os.path.join(dirpath, file) - name, ext = os.path.splitext(filePath) - if ext in mediaContainer: # If the file is a video file - if ext in ignoreExtensions: - Logger.info("No need to transcode video type %s", ext) - continue - if ext == outputVideoExtension: # we need to change the name to prevent overwriting itself. - outputVideoExtension = '-transcoded' + outputVideoExtension # adds '-transcoded.ext' - newfilePath = os.path.normpath(name + outputVideoExtension) - - command = [ffmpeg, '-loglevel', 'warning', '-i', filePath, '-map', '0'] # -map 0 takes all input streams - - if useNiceness: - command = ['nice', '-%d' % niceness] + command - - if len(outputVideoCodec) > 0: - command.append('-c:v') - command.append(outputVideoCodec) - if outputVideoCodec == 'libx264' and outputVideoPreset: - command.append('-preset') - command.append(outputVideoPreset) - else: - command.append('-c:v') - command.append('copy') - if len(outputVideoFramerate) > 0: - command.append('-r') - command.append(str(outputVideoFramerate)) - if len(outputVideoBitrate) > 0: - command.append('-b:v') - command.append(str(outputVideoBitrate)) - if len(outputAudioCodec) > 0: - command.append('-c:a') - command.append(outputAudioCodec) - if outputAudioCodec == 'aac': # Allow users to use the experimental AAC codec that's built into recent versions of ffmpeg - command.append('-strict') - command.append('-2') - else: - command.append('-c:a') - command.append('copy') - if len(outputAudioBitrate) > 0: - command.append('-b:a') - command.append(str(outputAudioBitrate)) - if outputFastStart > 0: - command.append('-movflags') - command.append('+faststart') - if outputQualityPercent > 0: - command.append('-q:a') - command.append(str(outputQualityPercent)) - if len(outputSubtitleCodec) > 0: # Not every subtitle codec can be used for every video container format! - command.append('-c:s') - command.append(outputSubtitleCodec) # http://en.wikibooks.org/wiki/FFMPEG_An_Intermediate_Guide/subtitle_options - else: - command.append('-sn') # Don't copy the subtitles over - command.append(newfilePath) - - try: # Try to remove the file that we're transcoding to just in case. (ffmpeg will return an error if it already exists for some reason) - os.remove(newfilePath) - except OSError, e: - if e.errno != errno.ENOENT: # Ignore the error if it's just telling us that the file doesn't exist - Logger.debug("Error when removing transcoding target: %s", e) - except Exception, e: - Logger.debug("Error when removing transcoding target: %s", e) - - Logger.info("Transcoding video: %s", file) - cmd = "" - for item in command: - cmd = cmd + " " + item - Logger.debug("calling command:%s", cmd) - result = 1 # set result to failed in case call fails. - try: - result = call(command) - except: - Logger.exception("Transcoding of video %s has failed", filePath) - if result == 0: - Logger.info("Transcoding of video %s to %s succeeded", filePath, newfilePath) - if duplicate == 0: # we get rid of the original file - os.unlink(filePath) - else: - Logger.error("Transcoding of video %s to %s failed", filePath, newfilePath) - # this will be 0 (successful) it all are successful, else will return a positive integer for failure. - final_result = final_result + result - return final_result diff --git a/autoProcess/autoProcessComics.py b/autoProcess/autoProcessComics.py deleted file mode 100644 index f0cc2f82..00000000 --- a/autoProcess/autoProcessComics.py +++ /dev/null @@ -1,96 +0,0 @@ -import urllib -import logging - -from nzbToMediaEnv import * -from nzbToMediaUtil import * - - -Logger = logging.getLogger() -socket.setdefaulttimeout(int(TimeOut)) #initialize socket timeout. - -class AuthURLOpener(urllib.FancyURLopener): - def __init__(self, user, pw): - self.username = user - self.password = pw - self.numTries = 0 - urllib.FancyURLopener.__init__(self) - - def prompt_user_passwd(self, host, realm): - if self.numTries == 0: - self.numTries = 1 - return (self.username, self.password) - else: - return ('', '') - - def openit(self, url): - self.numTries = 0 - return urllib.FancyURLopener.open(self, url) - - -def processEpisode(dirName, nzbName=None, status=0, inputCategory=None): - - - - Logger.info("Loading config from %s", CONFIG_FILE) - - if not config(): - Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?") - return 1 # failure - - - - section = "Mylar" - if inputCategory != None and config().has_section(inputCategory): - section = inputCategory - host = config().get(section, "host") - port = config().get(section, "port") - username = config().get(section, "username") - password = config().get(section, "password") - try: - ssl = int(config().get(section, "ssl")) - except (config.NoOptionError, ValueError): - ssl = 0 - - try: - web_root = config().get(section, "web_root") - except config.NoOptionError: - web_root = "" - - try: - watch_dir = config().get(section, "watch_dir") - except config.NoOptionError: - watch_dir = "" - params = {} - - nzbName, dirName = convert_to_ascii(nzbName, dirName) - - if dirName == "Manual Run" and watch_dir != "": - dirName = watch_dir - - params['nzb_folder'] = dirName - if nzbName != None: - params['nzb_name'] = nzbName - - myOpener = AuthURLOpener(username, password) - - if ssl: - protocol = "https://" - else: - protocol = "http://" - - url = protocol + host + ":" + port + web_root + "/post_process?" + urllib.urlencode(params) - - Logger.debug("Opening URL: %s", url) - - try: - urlObj = myOpener.openit(url) - except: - Logger.exception("Unable to open URL") - return 1 # failure - - result = urlObj.readlines() - for line in result: - Logger.info("%s", line) - - time.sleep(60) #wait 1 minute for now... need to see just what gets logged and how long it takes to process - return 0 # Success diff --git a/autoProcess/autoProcessGames.py b/autoProcess/autoProcessGames.py deleted file mode 100644 index f0779fa7..00000000 --- a/autoProcess/autoProcessGames.py +++ /dev/null @@ -1,75 +0,0 @@ -import urllib -import json -import logging - -from nzbToMediaEnv import * -from nzbToMediaUtil import * - - -Logger = logging.getLogger() -socket.setdefaulttimeout(int(TimeOut)) #initialize socket timeout. - -def process(dirName, nzbName=None, status=0, inputCategory=None): - - status = int(status) - - - Logger.info("Loading config from %s", CONFIG_FILE) - - if not config(): - Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?") - return 1 # failure - - - - section = "Gamez" - if inputCategory != None and config().has_section(inputCategory): - section = inputCategory - - host = config().get(section, "host") - port = config().get(section, "port") - apikey = config().get(section, "apikey") - - try: - ssl = int(config().get(section, "ssl")) - except (config.NoOptionError, ValueError): - ssl = 0 - - try: - web_root = config().get(section, "web_root") - except config.NoOptionError: - web_root = "" - - if ssl: - protocol = "https://" - else: - protocol = "http://" - - nzbName, dirName = convert_to_ascii(nzbName, dirName) - - baseURL = protocol + host + ":" + port + web_root + "/api?api_key=" + apikey + "&mode=" - - fields = nzbName.split("-") - gamezID = fields[0].replace("[","").replace("]","").replace(" ","") - downloadStatus = 'Wanted' - if status == 0: - downloadStatus = 'Downloaded' - - url = baseURL + "UPDATEREQUESTEDSTATUS&db_id=" + gamezID + "&status=" + downloadStatus - - Logger.debug("Opening URL: %s", url) - - try: - urlObj = urllib.urlopen(url) - except: - Logger.exception("Unable to open URL") - return 1 # failure - - result = json.load(urlObj) - Logger.info("Gamez returned %s", result) - if result['success']: - Logger.info("Status for %s has been set to %s in Gamez", gamezID, downloadStatus) - return 0 # Success - else: - Logger.error("Status for %s has NOT been updated in Gamez", gamezID) - return 1 # failure diff --git a/autoProcess/autoProcessMovie.py b/autoProcess/autoProcessMovie.py deleted file mode 100644 index f74d9385..00000000 --- a/autoProcess/autoProcessMovie.py +++ /dev/null @@ -1,325 +0,0 @@ -import urllib -import datetime -import json -import logging - -import Transcoder -from nzbToMediaEnv import * -from nzbToMediaUtil import * -from nzbToMediaSceneExceptions import process_all_exceptions - - -Logger = logging.getLogger() -socket.setdefaulttimeout(int(TimeOut)) #initialize socket timeout. - -def get_imdb(nzbName, dirName): - - imdbid = "" - - a = nzbName.find('.cp(') + 4 #search for .cptt( in nzbName - b = nzbName[a:].find(')') + a - if a > 3: # a == 3 if not exist - imdbid = nzbName[a:b] - - if imdbid: - Logger.info("Found movie id %s in name", imdbid) - return imdbid - - a = dirName.find('.cp(') + 4 #search for .cptt( in dirname - b = dirName[a:].find(')') + a - if a > 3: # a == 3 if not exist - imdbid = dirName[a:b] - - if imdbid: - Logger.info("Found movie id %s in directory", imdbid) - return imdbid - - else: - Logger.debug("Could not find an imdb id in directory or name") - return "" - -def get_movie_info(baseURL, imdbid, download_id): - - movie_id = "" - movie_status = None - release_status = None - if not imdbid and not download_id: - return movie_id, imdbid, download_id, movie_status, release_status - - releaselist = [] - movieid = [] - moviestatus = [] - library = [] - release = [] - offset = int(0) - while True: - url = baseURL + "media.list/?status=active&release_status=snatched&limit_offset=50," + str(offset) - - Logger.debug("Opening URL: %s", url) - - try: - urlObj = urllib.urlopen(url) - except: - Logger.exception("Unable to open URL") - break - - movieid2 = [] - library2 = [] - release2 = [] - moviestatus2 = [] - try: - result = json.load(urlObj) - movieid2 = [item["_id"] for item in result["movies"]] - for item in result["movies"]: - if "identifier" in item: - library2.append(item["identifier"]) - else: - library2.append(item["identifiers"]["imdb"]) - release2 = [item["releases"] for item in result["movies"]] - moviestatus2 = [item["status"] for item in result["movies"]] - except: - Logger.exception("Unable to parse json data for movies") - break - - movieid.extend(movieid2) - moviestatus.extend(moviestatus2) - library.extend(library2) - release.extend(release2) - if len(movieid2) < int(50): # finished parsing list of movies. Time to break. - break - offset = offset + 50 - - result = None # reset - for index in range(len(movieid)): - releaselist1 = [item for item in release[index] if item["status"] == "snatched" and "download_info" in item] - if download_id: - releaselist = [item for item in releaselist1 if item["download_info"]["id"].lower() == download_id.lower()] - else: - releaselist = releaselist1 - - if imdbid and library[index] == imdbid: - movie_id = str(movieid[index]) - movie_status = str(moviestatus[index]) - Logger.info("Found movie id %s with status %s in CPS database for movie %s", movie_id, movie_status, imdbid) - if not download_id and len(releaselist) == 1: - download_id = releaselist[0]["download_info"]["id"] - - elif not imdbid and download_id and len(releaselist) > 0: - movie_id = str(movieid[index]) - movie_status = str(moviestatus[index]) - imdbid = str(library[index]) - Logger.info("Found movie id %s and imdb %s with status %s in CPS database via download_id %s", movie_id, imdbid, movie_status, download_id) - - else: - continue - - if len(releaselist) == 1: - release_status = releaselist[0]["status"] - Logger.debug("Found a single release with download_id: %s. Release status is: %s", download_id, release_status) - - break - - if not movie_id: - Logger.exception("Could not parse database results to determine imdbid or movie id") - - return movie_id, imdbid, download_id, movie_status, release_status - -def get_status(baseURL, movie_id, download_id): - result = None - movie_status = None - release_status = None - if not movie_id: - return movie_status, release_status - - Logger.debug("Looking for status of movie: %s", movie_id) - url = baseURL + "media.get/?id=" + str(movie_id) - Logger.debug("Opening URL: %s", url) - - try: - urlObj = urllib.urlopen(url) - except: - Logger.exception("Unable to open URL") - return None, None - try: - result = json.load(urlObj) - movie_status = str(result["media"]["status"]) - Logger.debug("This movie is marked as status %s in CouchPotatoServer", movie_status) - except: - Logger.exception("Could not find a status for this movie") - - try: - if len(result["media"]["releases"]) == 1 and result["media"]["releases"][0]["status"] == "done": - release_status = result["media"]["releases"][0]["status"] - else: - release_status_list = [item["status"] for item in result["media"]["releases"] if "download_info" in item and item["download_info"]["id"].lower() == download_id.lower()] - if len(release_status_list) == 1: - release_status = release_status_list[0] - Logger.debug("This release is marked as status %s in CouchPotatoServer", release_status) - except: # index out of range/doesn't exist? - Logger.exception("Could not find a status for this release") - - return movie_status, release_status - -def process(dirName, nzbName=None, status=0, clientAgent = "manual", download_id = "", inputCategory=None): - - status = int(status) - - Logger.info("Loading config from %s", CONFIG_FILE) - - if not config(): - Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?") - return 1 # failure - - section = "CouchPotato" - if inputCategory != None and config().has_section(inputCategory): - section = inputCategory - - host = config().get(section, "host") - port = config().get(section, "port") - apikey = config().get(section, "apikey") - delay = float(config().get(section, "delay")) - method = config().get(section, "method") - delete_failed = int(config().get(section, "delete_failed")) - wait_for = int(config().get(section, "wait_for")) - try: - TimePerGiB = int(config().get(section, "TimePerGiB")) - except (config.NoOptionError, ValueError): - TimePerGiB = 60 # note, if using Network to transfer on 100Mbit LAN, expect ~ 600 MB/minute. - try: - ssl = int(config().get(section, "ssl")) - except (config.NoOptionError, ValueError): - ssl = 0 - try: - web_root = config().get(section, "web_root") - except config.NoOptionError: - web_root = "" - try: - transcode = int(config().get("Transcoder", "transcode")) - except (config.NoOptionError, ValueError): - transcode = 0 - try: - remoteCPS = int(config().get(section, "remoteCPS")) - except (config.NoOptionError, ValueError): - remoteCPS = 0 - - nzbName = str(nzbName) # make sure it is a string - - imdbid = get_imdb(nzbName, dirName) - - if ssl: - protocol = "https://" - else: - protocol = "http://" - # don't delay when we are calling this script manually. - if nzbName == "Manual Run": - delay = 0 - - baseURL = protocol + host + ":" + port + web_root + "/api/" + apikey + "/" - - movie_id, imdbid, download_id, initial_status, initial_release_status = get_movie_info(baseURL, imdbid, download_id) # get the CPS database movie id for this movie. - - process_all_exceptions(nzbName.lower(), dirName) - nzbName, dirName = convert_to_ascii(nzbName, dirName) - - if status == 0: - if transcode == 1: - result = Transcoder.Transcode_directory(dirName) - if result == 0: - Logger.debug("Transcoding succeeded for files in %s", dirName) - else: - Logger.warning("Transcoding failed for files in %s", dirName) - - if method == "manage": - command = "manage.update" - else: - command = "renamer.scan" - if clientAgent != "manual" and download_id != None: - if remoteCPS == 1: - command = command + "/?downloader=" + clientAgent + "&download_id=" + download_id - else: - command = command + "/?media_folder=" + urllib.quote(dirName) + "&downloader=" + clientAgent + "&download_id=" + download_id - - dirSize = getDirectorySize(dirName) # get total directory size to calculate needed processing time. - TimeOut2 = int(TimePerGiB) * dirSize # Couchpotato needs to complete all moving and renaming before returning the status. - TimeOut2 += 60 # Add an extra minute for over-head/processing/metadata. - socket.setdefaulttimeout(int(TimeOut2)) #initialize socket timeout. We may now be able to remove the delays from the wait_for section below? If true, this should exit on first loop. - - url = baseURL + command - - Logger.info("Waiting for %s seconds to allow CPS to process newly extracted files", str(delay)) - - time.sleep(delay) - - Logger.debug("Opening URL: %s", url) - - try: - urlObj = urllib.urlopen(url) - except: - Logger.exception("Unable to open URL") - return 1 # failure - - result = json.load(urlObj) - Logger.info("CouchPotatoServer returned %s", result) - if result['success']: - Logger.info("%s scan started on CouchPotatoServer for %s", method, nzbName) - else: - Logger.error("%s scan has NOT started on CouchPotatoServer for %s. Exiting", method, nzbName) - return 1 # failure - - else: - Logger.info("Download of %s has failed.", nzbName) - Logger.info("Trying to re-cue the next highest ranked release") - - if not movie_id: - Logger.warning("Cound not find a movie in the database for release %s", nzbName) - Logger.warning("Please manually ignore this release and refresh the wanted movie") - Logger.error("Exiting autoProcessMovie script") - return 1 # failure - - url = baseURL + "movie.searcher.try_next/?media_id=" + movie_id - - Logger.debug("Opening URL: %s", url) - - try: - urlObj = urllib.urlopen(url) - except: - Logger.exception("Unable to open URL") - return 1 # failure - - result = urlObj.readlines() - for line in result: - Logger.info("%s", line) - - Logger.info("Movie %s set to try the next best release on CouchPotatoServer", movie_id) - if delete_failed and not dirName in ['sys.argv[0]','/','']: - Logger.info("Deleting failed files and folder %s", dirName) - try: - shutil.rmtree(dirName) - except: - Logger.exception("Unable to delete folder %s", dirName) - return 0 # success - - if nzbName == "Manual Run": - return 0 # success - if not download_id: - return 1 # just to be sure TorrentToMedia doesn't start deleting files as we havent verified changed status. - - # we will now check to see if CPS has finished renaming before returning to TorrentToMedia and unpausing. - socket.setdefaulttimeout(int(TimeOut)) #initialize socket timeout. - - release_status = None - start = datetime.datetime.now() # set time for timeout - pause_for = int(wait_for) * 10 # keep this so we only ever have 6 complete loops. This may not be necessary now? - while (datetime.datetime.now() - start) < datetime.timedelta(minutes=wait_for): # only wait 2 (default) minutes, then return. - movie_status, release_status = get_status(baseURL, movie_id, download_id) # get the current status fo this movie. - if movie_status and initial_status and movie_status != initial_status: # Something has changed. CPS must have processed this movie. - Logger.info("SUCCESS: This movie is now marked as status %s in CouchPotatoServer", movie_status) - return 0 # success - time.sleep(pause_for) # Just stop this looping infinitely and hogging resources for 2 minutes ;) - else: - if release_status and initial_release_status and release_status != initial_release_status: # Something has changed. CPS must have processed this movie. - Logger.info("SUCCESS: This release is now marked as status %s in CouchPotatoServer", release_status) - return 0 # success - else: # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resule seeding now. - Logger.warning("The movie does not appear to have changed status after %s minutes. Please check CouchPotato Logs", wait_for) - return 1 # failure diff --git a/autoProcess/autoProcessMusic.py b/autoProcess/autoProcessMusic.py deleted file mode 100644 index eb55e427..00000000 --- a/autoProcess/autoProcessMusic.py +++ /dev/null @@ -1,103 +0,0 @@ -import urllib -import datetime -import logging - -from nzbToMediaEnv import * -from nzbToMediaUtil import * - - -Logger = logging.getLogger() - -def process(dirName, nzbName=None, status=0, clientAgent="manual", inputCategory=None): - - status = int(status) - - Logger.info("Loading config from %s", CONFIG_FILE) - - if not config(): - Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?") - return 1 # failure - - section = "HeadPhones" - if inputCategory != None and config().has_section(inputCategory): - section = inputCategory - - host = config().get(section, "host") - port = config().get(section, "port") - apikey = config().get(section, "apikey") - delay = float(config().get(section, "delay")) - - try: - ssl = int(config().get(section, "ssl")) - except (config.NoOptionError, ValueError): - ssl = 0 - try: - web_root = config().get(section, "web_root") - except config.NoOptionError: - web_root = "" - try: - TimePerGiB = int(config().get(section, "TimePerGiB")) - except (config.NoOptionError, ValueError): - TimePerGiB = 60 # note, if using Network to transfer on 100Mbit LAN, expect ~ 600 MB/minute. - if ssl: - protocol = "https://" - else: - protocol = "http://" - # don't delay when we are calling this script manually. - if clientAgent == "manual": - delay = 0 - - nzbName, dirName = convert_to_ascii(nzbName, dirName) - - dirSize = getDirectorySize(dirName) # get total directory size to calculate needed processing time. - TimeOut = int(TimePerGiB) * dirSize # HeadPhones needs to complete all moving/transcoding and renaming before returning the status. - TimeOut += 60 # Add an extra minute for over-head/processing/metadata. - socket.setdefaulttimeout(int(TimeOut)) #initialize socket timeout. - - params = {} - params['apikey'] = apikey - params['cmd'] = "forceProcess" - params['dir'] = dirName - - baseURL = protocol + host + ":" + port + web_root + "/api?" + urllib.urlencode(params) - - if status == 0: - - url = baseURL - - Logger.info("Waiting for %s seconds to allow HeadPhones to process newly extracted files", str(delay)) - - time.sleep(delay) - - Logger.debug("Opening URL: %s", url) - - try: - urlObj = urllib.urlopen(url) - except: - Logger.exception("Unable to open URL") - return 1 # failure - - result = urlObj.readlines() - Logger.info("HeadPhones returned %s", result) - if result[0] == "OK": - Logger.info("Post-processing started on HeadPhones for %s", nzbName) - else: - Logger.error("Post-processing has NOT started on HeadPhones for %s. Exiting", nzbName) - return 1 # failure - else: - Logger.info("The download failed. Nothing to process") - return 0 # Success (as far as this script is concerned) - - if nzbName == "Manual Run": - return 0 # success - - # we will now wait 1 minutes for this album to be processed before returning to TorrentToMedia and unpausing. - ## Hopefully we can use a "getHistory" check in here to confirm processing complete... - start = datetime.datetime.now() # set time for timeout - while (datetime.datetime.now() - start) < datetime.timedelta(minutes=1): # only wait 2 minutes, then return to TorrentToMedia - time.sleep(20) # Just stop this looping infinitely and hogging resources for 2 minutes ;) - else: # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resume seeding now. - Logger.info("This album should have completed processing. Please check HeadPhones Logs") - # Logger.warning("The album does not appear to have changed status after 2 minutes. Please check HeadPhones Logs") - # return 1 # failure - return 0 # success for now. diff --git a/autoProcess/autoProcessTV.py b/autoProcess/autoProcessTV.py deleted file mode 100644 index 2cb3a3c7..00000000 --- a/autoProcess/autoProcessTV.py +++ /dev/null @@ -1,216 +0,0 @@ -import urllib -import logging -import copy - -import Transcoder -from nzbToMediaSceneExceptions import process_all_exceptions -from autoProcess.autoSickBeardFork import autoFork -from nzbToMediaEnv import * -from nzbToMediaUtil import * - -Logger = logging.getLogger() - -class AuthURLOpener(urllib.FancyURLopener): - def __init__(self, user, pw): - self.username = user - self.password = pw - self.numTries = 0 - urllib.FancyURLopener.__init__(self) - - def prompt_user_passwd(self, host, realm): - if self.numTries == 0: - self.numTries = 1 - return (self.username, self.password) - else: - return ('', '') - - def openit(self, url): - self.numTries = 0 - try: - return urllib.FancyURLopener.open(self, url) - except: - raise IOError("Unable to open URL") - -def delete(dirName): - Logger.info("Deleting failed files and folder %s", dirName) - try: - shutil.rmtree(dirName, True) - except: - Logger.exception("Unable to delete folder %s", dirName) - - -def processEpisode(dirName, nzbName=None, failed=False, clientAgent = "manual", inputCategory=None): - - status = int(failed) - - Logger.info("Loading config from %s", CONFIG_FILE) - - if not config(): - Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?") - return 1 # failure - - section = "SickBeard" - if inputCategory != None and config().has_section(inputCategory): - section = inputCategory - - host = config().get(section, "host") - port = config().get(section, "port") - username = config().get(section, "username") - password = config().get(section, "password") - - try: - ssl = int(config().get(section, "ssl")) - except (config.NoOptionError, ValueError): - ssl = 0 - try: - web_root = config().get(section, "web_root") - except config.NoOptionError: - web_root = "" - try: - watch_dir = config().get(section, "watch_dir") - except config.NoOptionError: - watch_dir = "" - try: - transcode = int(config().get("Transcoder", "transcode")) - except (config.NoOptionError, ValueError): - transcode = 0 - try: - delete_failed = int(config().get(section, "delete_failed")) - except (config.NoOptionError, ValueError): - delete_failed = 0 - try: - delay = float(config().get(section, "delay")) - except (config.NoOptionError, ValueError): - delay = 0 - try: - TimePerGiB = int(config().get(section, "TimePerGiB")) - except (config.NoOptionError, ValueError): - TimePerGiB = 60 # note, if using Network to transfer on 100Mbit LAN, expect ~ 600 MB/minute. - try: - SampleIDs = (config().get("Extensions", "SampleIDs")).split(',') - except (config.NoOptionError, ValueError): - SampleIDs = ['sample','-s.'] - try: - nzbExtractionBy = config().get(section, "nzbExtractionBy") - except (config.NoOptionError, ValueError): - nzbExtractionBy = "Downloader" - try: - process_method = config().get(section, "process_method") - except config.NoOptionError: - process_method = None - - mediaContainer = (config().get("Extensions", "mediaExtensions")).split(',') - minSampleSize = int(config().get("Extensions", "minSampleSize")) - - if not os.path.isdir(dirName) and os.path.isfile(dirName): # If the input directory is a file, assume single file download and split dir/name. - dirName = os.path.split(os.path.normpath(dirName))[0] - - SpecificPath = os.path.join(dirName, str(nzbName)) - cleanName = os.path.splitext(SpecificPath) - if cleanName[1] == ".nzb": - SpecificPath = cleanName[0] - if os.path.isdir(SpecificPath): - dirName = SpecificPath - - # auto-detect fork type - fork, params = autoFork() - - if fork not in SICKBEARD_TORRENT or (clientAgent in ['nzbget','sabnzbd'] and nzbExtractionBy != "Destination"): - if nzbName: - process_all_exceptions(nzbName.lower(), dirName) - nzbName, dirName = convert_to_ascii(nzbName, dirName) - - # Now check if tv files exist in destination. Eventually extraction may be done here if nzbExtractionBy == TorrentToMedia - video = int(0) - for dirpath, dirnames, filenames in os.walk(dirName): - for file in filenames: - filePath = os.path.join(dirpath, file) - fileExtension = os.path.splitext(file)[1] - if fileExtension in mediaContainer: # If the file is a video file - if is_sample(filePath, nzbName, minSampleSize, SampleIDs): - Logger.debug("Removing sample file: %s", filePath) - os.unlink(filePath) # remove samples - else: - video = video + 1 - if video > 0: # Check that a video exists. if not, assume failed. - flatten(dirName) # to make sure SickBeard can find the video (not in sub-folder) - elif clientAgent == "manual": - Logger.warning("No media files found in directory %s to manually process.", dirName) - return 0 # Success (as far as this script is concerned) - else: - Logger.warning("No media files found in directory %s. Processing this as a failed download", dirName) - status = int(1) - failed = True - - dirSize = getDirectorySize(dirName) # get total directory size to calculate needed processing time. - TimeOut = int(TimePerGiB) * dirSize # SickBeard needs to complete all moving and renaming before returning the log sequence via url. - TimeOut += 60 # Add an extra minute for over-head/processing/metadata. - socket.setdefaulttimeout(int(TimeOut)) #initialize socket timeout. - - # configure SB params to pass - params['quiet'] = 1 - if nzbName is not None: - params['nzbName'] = nzbName - - for param in copy.copy(params): - if param == "failed": - params[param] = failed - - if param in ["dirName", "dir"]: - params[param] = dirName - - if param == "process_method": - if process_method: - params[param] = process_method - else: - del params[param] - - # delete any unused params so we don't pass them to SB by mistake - [params.pop(k) for k,v in params.items() if v is None] - - if status == 0: - Logger.info("The download succeeded. Sending process request to SickBeard's %s branch", fork) - elif fork in SICKBEARD_FAILED: - Logger.info("The download failed. Sending 'failed' process request to SickBeard's %s branch", fork) - else: - Logger.info("The download failed. SickBeard's %s branch does not handle failed downloads. Nothing to process", fork) - if delete_failed and os.path.isdir(dirName) and not dirName in ['sys.argv[0]','/','']: - Logger.info("Deleting directory: %s", dirName) - delete(dirName) - return 0 # Success (as far as this script is concerned) - - if status == 0 and transcode == 1: # only transcode successful downlaods - result = Transcoder.Transcode_directory(dirName) - if result == 0: - Logger.debug("Transcoding succeeded for files in %s", dirName) - else: - Logger.warning("Transcoding failed for files in %s", dirName) - - myOpener = AuthURLOpener(username, password) - - if ssl: - protocol = "https://" - else: - protocol = "http://" - - url = protocol + host + ":" + port + web_root + "/home/postprocess/processEpisode?" + urllib.urlencode(params) - - if clientAgent == "manual":delay = 0 - Logger.info("Waiting for %s seconds to allow SB to process newly extracted files", str(delay)) - - time.sleep(delay) - - Logger.debug("Opening URL: %s", url) - - try: - urlObj = myOpener.openit(url) - except: - Logger.exception("Unable to open URL") - return 1 # failure - - result = urlObj.readlines() - for line in result: - Logger.info("%s", line.rstrip()) - if status != 0 and delete_failed and not dirName in ['sys.argv[0]','/','']: - delete(dirName) - return 0 # Success diff --git a/autoProcess/migratecfg.py b/autoProcess/migratecfg.py deleted file mode 100644 index 9dc8c7c8..00000000 --- a/autoProcess/migratecfg.py +++ /dev/null @@ -1,227 +0,0 @@ -from nzbToMediaConfig import * - -def migrate(): - categories = [] - confignew = config(SAMPLE_CONFIG_FILE) - configold = config(CONFIG_FILE) - - section = "CouchPotato" - for option, value in configold.items(section) or config(MOVIE_CONFIG_FILE).items(section): - if option == "category": # change this old format - option = "cpsCategory" - if option == "outputDirectory": # move this to new location format - value = os.path.split(os.path.normpath(value))[0] - confignew.set("Torrent", option, value) - continue - if option in ["username", "password" ]: # these are no-longer needed. - continue - if option == "cpsCategory": - categories.extend(value.split(',')) - confignew.set(section, option, value) - - section = "SickBeard" - for option, value in configold.items(section) or config(TV_CONFIG_FILE).items(section): - if option == "category": # change this old format - option = "sbCategory" - if option == "wait_for": # remove old format - continue - if option == "failed_fork": # change this old format - option = "fork" - if value not in ["default", "failed", "failed-torrent", "auto"]: - value = "auto" - if option == "fork" and value not in ["default", "failed", "failed-torrent", "auto"]: - value = "auto" - if option == "outputDirectory": # move this to new location format - value = os.path.split(os.path.normpath(value))[0] - confignew.set("Torrent", option, value) - continue - if option == "sbCategory": - categories.extend(value.split(',')) - confignew.set(section, option, value) - - for section in configold.sections(): - try: - for option, value in configold.items(section): - if section == "HeadPhones": - if option in ["username", "password" ]: - continue - if option == "hpCategory": - categories.extend(value.split(',')) - confignew.set(section, option, value) - - if section == "Mylar": - if option in "mlCategory": - categories.extend(value.split(',')) - confignew.set(section, option, value) - - if section == "Gamez": - if option in ["username", "password" ]: # these are no-longer needed. - continue - if option == "gzCategory": - categories.extend(value.split(',')) - confignew.set(section, option, value) - - if section == "Torrent": - if option in ["compressedExtensions", "mediaExtensions", "metaExtensions", "minSampleSize"]: - section = "Extensions" # these were moved - if option == "useLink": # Sym links supported now as well. - if isinstance(value, int): - num_value = int(value) - if num_value == 1: - value = "hard" - else: - value = "no" - confignew.set(section, option, value) - - if section == "Extensions": - confignew.set(section, option, value) - - if section == "Transcoder": - confignew.set(section, option, value) - - if section == "WakeOnLan": - confignew.set(section, option, value) - - if section == "UserScript": - confignew.set(section, option, value) - - if section == "ASCII": - confignew.set(section, option, value) - - if section == "passwords": - confignew.set(section, option, value) - - if section == "loggers": - confignew.set(section, option, value) - - if section == "handlers": - confignew.set(section, option, value) - - if section == "formatters": - confignew.set(section, option, value) - - if section == "logger_root": - confignew.set(section, option, value) - - if section == "handler_console": - confignew.set(section, option, value) - - if section == "formatter_generic": - confignew.set(section, option, value) - except config.InterpolationMissingOptionError: - pass - - for section in categories: - try: - if configold.items(section): - confignew.add_section(section) - - for option, value in configold.items(section): - confignew.set(section, option, value) - except config.NoSectionError: - continue - - # create a backup of our old config - if os.path.isfile(CONFIG_FILE): - cfgbak_name = CONFIG_FILE + ".old" - if os.path.isfile(cfgbak_name): # remove older backups - os.unlink(cfgbak_name) - os.rename(CONFIG_FILE, cfgbak_name) - - # writing our configuration file to 'autoProcessMedia.cfg' - with open(CONFIG_FILE, 'wb') as configFile: - confignew.write(configFile) - -def addnzbget(): - confignew = config() - section = "CouchPotato" - envKeys = ['CATEGORY', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'DELAY', 'METHOD', 'DELETE_FAILED', 'REMOTECPS', 'WAIT_FOR', 'TIMEPERGIB'] - cfgKeys = ['cpsCategory', 'apikey', 'host', 'port', 'ssl', 'web_root', 'delay', 'method', 'delete_failed', 'remoteCPS', 'wait_for', 'TimePerGiB'] - for index in range(len(envKeys)): - key = 'NZBPO_CPS' + envKeys[index] - if os.environ.has_key(key): - option = cfgKeys[index] - value = os.environ[key] - confignew.set(section, option, value) - - - section = "SickBeard" - envKeys = ['CATEGORY', 'HOST', 'PORT', 'USERNAME', 'PASSWORD', 'SSL', 'WEB_ROOT', 'WATCH_DIR', 'FORK', 'DELETE_FAILED', 'DELAY', 'TIMEPERGIB', 'PROCESS_METHOD'] - cfgKeys = ['sbCategory', 'host', 'port', 'username', 'password', 'ssl', 'web_root', 'watch_dir', 'fork', 'delete_failed', 'delay', 'TimePerGiB', 'process_method'] - for index in range(len(envKeys)): - key = 'NZBPO_SB' + envKeys[index] - if os.environ.has_key(key): - option = cfgKeys[index] - value = os.environ[key] - confignew.set(section, option, value) - - section = "HeadPhones" - envKeys = ['CATEGORY', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'DELAY', 'TIMEPERGIB'] - cfgKeys = ['hpCategory', 'apikey', 'host', 'port', 'ssl', 'web_root', 'delay', 'TimePerGiB'] - for index in range(len(envKeys)): - key = 'NZBPO_HP' + envKeys[index] - if os.environ.has_key(key): - option = cfgKeys[index] - value = os.environ[key] - confignew.set(section, option, value) - - section = "Mylar" - envKeys = ['CATEGORY', 'HOST', 'PORT', 'USERNAME', 'PASSWORD', 'SSL', 'WEB_ROOT'] - cfgKeys = ['mlCategory', 'host', 'port', 'username', 'password', 'ssl', 'web_root'] - for index in range(len(envKeys)): - key = 'NZBPO_MY' + envKeys[index] - if os.environ.has_key(key): - option = cfgKeys[index] - value = os.environ[key] - confignew.set(section, option, value) - - section = "Gamez" - envKeys = ['CATEGORY', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT'] - cfgKeys = ['gzCategory', 'apikey', 'host', 'port', 'ssl', 'web_root'] - for index in range(len(envKeys)): - key = 'NZBPO_GZ' + envKeys[index] - if os.environ.has_key(key): - option = cfgKeys[index] - value = os.environ[key] - confignew.set(section, option, value) - - section = "Extensions" - envKeys = ['COMPRESSEDEXTENSIONS', 'MEDIAEXTENSIONS', 'METAEXTENSIONS'] - cfgKeys = ['compressedExtensions', 'mediaExtensions', 'metaExtensions'] - for index in range(len(envKeys)): - key = 'NZBPO_' + envKeys[index] - if os.environ.has_key(key): - option = cfgKeys[index] - value = os.environ[key] - confignew.set(section, option, value) - - section = "Transcoder" - envKeys = ['TRANSCODE', 'DUPLICATE', 'IGNOREEXTENSIONS', 'OUTPUTVIDEOEXTENSION', 'OUTPUTVIDEOCODEC', 'OUTPUTVIDEOPRESET', 'OUTPUTVIDEOFRAMERATE', 'OUTPUTVIDEOBITRATE', 'OUTPUTAUDIOCODEC', 'OUTPUTAUDIOBITRATE', 'OUTPUTSUBTITLECODEC'] - cfgKeys = ['transcode', 'duplicate', 'ignoreExtensions', 'outputVideoExtension', 'outputVideoCodec', 'outputVideoPreset', 'outputVideoFramerate', 'outputVideoBitrate', 'outputAudioCodec', 'outputAudioBitrate', 'outputSubtitleCodec'] - for index in range(len(envKeys)): - key = 'NZBPO_' + envKeys[index] - if os.environ.has_key(key): - option = cfgKeys[index] - value = os.environ[key] - confignew.set(section, option, value) - - section = "WakeOnLan" - envKeys = ['WAKE', 'HOST', 'PORT', 'MAC'] - cfgKeys = ['wake', 'host', 'port', 'mac'] - for index in range(len(envKeys)): - key = 'NZBPO_WOL' + envKeys[index] - if os.environ.has_key(key): - option = cfgKeys[index] - value = os.environ[key] - confignew.set(section, option, value) - - # create a backup of our old config - if os.path.isfile(CONFIG_FILE): - cfgbak_name = CONFIG_FILE + ".old" - if os.path.isfile(cfgbak_name): # remove older backups - os.unlink(cfgbak_name) - os.rename(CONFIG_FILE, cfgbak_name) - - # writing our configuration file to 'autoProcessMedia.cfg' - with open(CONFIG_FILE, 'wb') as configFile: - confignew.write(configFile) diff --git a/autoProcess/nzbToMediaEnv.py b/autoProcess/nzbToMediaEnv.py deleted file mode 100644 index 7846c595..00000000 --- a/autoProcess/nzbToMediaEnv.py +++ /dev/null @@ -1,24 +0,0 @@ -# Make things easy and less error prone by centralising all common values - -# Global Constants -VERSION = 'V9.3' -TimeOut = 60 - -# Constants pertinant to SabNzb -SABNZB_NO_OF_ARGUMENTS = 8 -SABNZB_0717_NO_OF_ARGUMENTS = 9 - -# Constants pertaining to SickBeard Branches: -fork_default = "default" -fork_failed = "failed" -fork_failed_torrent = "failed-torrent" - -forks = {} - -forks[fork_default] = {"dir": None, "method": None} -forks[fork_failed] = {"dirName": None, "failed": None} -forks[fork_failed_torrent] = {"dir": None, "failed": None, "process_method": None} - -SICKBEARD_FAILED = [fork_failed, fork_failed_torrent] -SICKBEARD_TORRENT = [fork_failed_torrent] - diff --git a/autoProcessMedia.cfg.sample b/autoProcessMedia.cfg.sample index 97731862..64904fba 100644 --- a/autoProcessMedia.cfg.sample +++ b/autoProcessMedia.cfg.sample @@ -13,13 +13,13 @@ ssl = 0 web_root = delay = 65 TimePerGiB = 60 +watch_dir = method = renamer delete_failed = 0 wait_for = 2 #### Set to 1 if CouchPotatoServer is running on a different server to your NZB client remoteCPS = 0 - [SickBeard] #### autoProcessing for TV Series #### sbCategory - category that gets called for post-processing with SB @@ -40,7 +40,6 @@ nzbExtractionBy = Downloader Torrent_ForceLink = 1 process_method = - [HeadPhones] #### autoProcessing for Music #### hpCategory - category that gets called for post-processing with HP @@ -53,7 +52,7 @@ ssl = 0 web_root = delay = 65 TimePerGiB = 60 - +watch_dir = [Mylar] #### autoProcessing for Comics @@ -68,7 +67,6 @@ web_root= ssl=0 watch_dir = - [Gamez] #### autoProcessing for Games #### gzCategory - category that gets called for post-processing with Gamez @@ -79,7 +77,7 @@ port = 8085 ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### ssl = 0 web_root = - +watch_dir = [Torrent] ###### clientAgent - Supported clients: utorrent, transmission, deluge, rtorrent, other diff --git a/nzbToCouchPotato.py b/nzbToCouchPotato.py index 728ffdfe..566e650c 100755 --- a/nzbToCouchPotato.py +++ b/nzbToCouchPotato.py @@ -121,25 +121,32 @@ ### NZBGET POST-PROCESSING SCRIPT ### ############################################################################## +# Exit codes used by NZBGet import logging +import os +import sys +from nzbtomedia.autoProcess.autoProcessMovie import autoProcessMovie +from nzbtomedia.migratecfg import migratecfg +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import nzbtomedia_configure_logging, WakeUp, get_dirnames -import autoProcess.migratecfg as migratecfg -import autoProcess.autoProcessMovie as autoProcessMovie -from autoProcess.nzbToMediaEnv import * -from autoProcess.nzbToMediaUtil import * +# run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. +if migratecfg().migrate(): + # check to write settings from nzbGet UI to autoProcessMedia.cfg. + if os.environ.has_key('NZBOP_SCRIPTDIR'): + migratecfg().addnzbget() -#check to migrate old cfg before trying to load. -if os.path.isfile(os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg.sample")): - migratecfg.migrate() -# check to write settings from nzbGet UI to autoProcessMedia.cfg. -if os.environ.has_key('NZBOP_SCRIPTDIR'): - migratecfg.addnzbget() + nzbtomedia_configure_logging(config.LOG_FILE) + Logger = logging.getLogger(__name__) + Logger.info("====================") # Seperate old from new log + Logger.info("nzbToCouchPotato %s", config.NZBTOMEDIA_VERSION) -nzbtomedia_configure_logging(LOG_FILE) -Logger = logging.getLogger(__name__) + Logger.info("MAIN: Loading config from %s", config.CONFIG_FILE) +else: + sys.exit(-1) -Logger.info("====================") # Seperate old from new log -Logger.info("nzbToCouchPotato %s", VERSION) +# couchpotato category +cpsCategory = (config().get("CouchPotato", "cpsCategory")).split(',') # movie WakeUp() @@ -150,24 +157,19 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 # NZBGet argv: all passed as environment variables. clientAgent = "nzbget" - # Exit codes used by NZBGet - POSTPROCESS_PARCHECK=92 - POSTPROCESS_SUCCESS=93 - POSTPROCESS_ERROR=94 - POSTPROCESS_NONE=95 # Check nzbget.conf options status = 0 if os.environ['NZBOP_UNPACK'] != 'yes': Logger.error("MAIN: Please enable option \"Unpack\" in nzbget configuration file, exiting") - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) # Check par status if os.environ['NZBPP_PARSTATUS'] == '3': Logger.warning("MAIN: Par-check successful, but Par-repair disabled, exiting") Logger.info("MAIN: Please check your Par-repair settings for future downloads.") - sys.exit(POSTPROCESS_NONE) + sys.exit(config.NZBGET_POSTPROCESS_NONE) if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4': Logger.warning("MAIN: Par-repair failed, setting status \"failed\"") @@ -200,9 +202,9 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 if os.environ.has_key('NZBPR_COUCHPOTATO'): download_id = os.environ['NZBPR_COUCHPOTATO'] Logger.info("MAIN: Script triggered from NZBGet, starting autoProcessMovie...") - result = autoProcessMovie.process(os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBNAME'], status, clientAgent, download_id) + result = autoProcessMovie().process(os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBNAME'], status, clientAgent, download_id) # SABnzbd Pre 0.7.17 -elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: +elif len(sys.argv) == config.SABNZB_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -213,9 +215,9 @@ elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: # 7 Status of post processing. 0 = OK, 1=failed verification, 2=failed unpack, 3=1+2 Logger.info("MAIN: Script triggered from SABnzbd, starting autoProcessMovie...") clientAgent = "sabnzbd" - result = autoProcessMovie.process(sys.argv[1], sys.argv[2], sys.argv[7], clientAgent) + result = autoProcessMovie().process(sys.argv[1], sys.argv[2], sys.argv[7], clientAgent) # SABnzbd 0.7.17+ -elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: +elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -227,18 +229,23 @@ elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: # 8 Failure URL Logger.info("MAIN: Script triggered from SABnzbd 0.7.17+, starting autoProcessMovie...") clientAgent = "sabnzbd" - result = autoProcessMovie.process(sys.argv[1], sys.argv[2], sys.argv[7], clientAgent) + result = autoProcessMovie().process(sys.argv[1], sys.argv[2], sys.argv[7], clientAgent) else: + result = 0 + Logger.warn("MAIN: Invalid number of arguments received from client.") Logger.info("MAIN: Running autoProcessMovie as a manual run...") - clientAgent = "manual" - result = autoProcessMovie.process('Manual Run', 'Manual Run', 0, clientAgent) + + for dirName in get_dirnames("CouchPotato", cpsCategory[0]): + Logger.info("MAIN: Calling CouchPotato to post-process: %s", dirName) + result = autoProcessMovie().process(dirName, dirName, 0) + if result != 0: break if result == 0: Logger.info("MAIN: The autoProcessMovie script completed successfully.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_SUCCESS) + sys.exit(config.NZBGET_POSTPROCESS_SUCCESS) else: Logger.info("MAIN: A problem was reported in the autoProcessMovie script.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) diff --git a/nzbToGamez.py b/nzbToGamez.py index 42791970..54130ed8 100755 --- a/nzbToGamez.py +++ b/nzbToGamez.py @@ -57,25 +57,33 @@ ### NZBGET POST-PROCESSING SCRIPT ### ############################################################################## + +# Exit codes used by NZBGet import logging +import os +import sys +from nzbtomedia.autoProcess.autoProcessGames import autoProcessGames +from nzbtomedia.migratecfg import migratecfg +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import WakeUp, nzbtomedia_configure_logging, get_dirnames -import autoProcess.migratecfg as migratecfg -import autoProcess.autoProcessGames as autoProcessGames -from autoProcess.nzbToMediaEnv import * -from autoProcess.nzbToMediaUtil import * +# run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. +if migratecfg().migrate(): + # check to write settings from nzbGet UI to autoProcessMedia.cfg. + if os.environ.has_key('NZBOP_SCRIPTDIR'): + migratecfg().addnzbget() -#check to migrate old cfg before trying to load. -if os.path.isfile(os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg.sample")): - migratecfg.migrate() -# check to write settings from nzbGet UI to autoProcessMedia.cfg. -if os.environ.has_key('NZBOP_SCRIPTDIR'): - migratecfg.addnzbget() + nzbtomedia_configure_logging(config.LOG_FILE) + Logger = logging.getLogger(__name__) + Logger.info("====================") # Seperate old from new log + Logger.info("nzbToGamez %s", config.NZBTOMEDIA_VERSION) -nzbtomedia_configure_logging(LOG_FILE) -Logger = logging.getLogger(__name__) + Logger.info("MAIN: Loading config from %s", config.CONFIG_FILE) +else: + sys.exit(-1) -Logger.info("====================") # Seperate old from new log -Logger.info("nzbToGamez %s", VERSION) +# gamez category +gzCategory = (config().get("Gamez", "gzCategory")).split(',') # gamez WakeUp() @@ -84,25 +92,18 @@ WakeUp() if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5] < '11.0': Logger.info("MAIN: Script triggered from NZBGet (11.0 or later).") - # NZBGet argv: all passed as environment variables. - # Exit codes used by NZBGet - POSTPROCESS_PARCHECK=92 - POSTPROCESS_SUCCESS=93 - POSTPROCESS_ERROR=94 - POSTPROCESS_NONE=95 - # Check nzbget.conf options status = 0 if os.environ['NZBOP_UNPACK'] != 'yes': Logger.error("MAIN: Please enable option \"Unpack\" in nzbget configuration file, exiting") - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) # Check par status if os.environ['NZBPP_PARSTATUS'] == '3': Logger.warning("MAIN: Par-check successful, but Par-repair disabled, exiting") Logger.info("MAIN: Please check your Par-repair settings for future downloads.") - sys.exit(POSTPROCESS_NONE) + sys.exit(config.NZBGET_POSTPROCESS_NONE) if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4': Logger.warning("MAIN: Par-repair failed, setting status \"failed\"") @@ -132,9 +133,9 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 # All checks done, now launching the script. Logger.info("MAIN: Script triggered from NZBGet, starting autoProcessGames...") - result = autoProcessGames.process(os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBNAME'], status) + result = autoProcessGames().process(os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBNAME'], status) # SABnzbd Pre 0.7.17 -elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: +elif len(sys.argv) == config.SABNZB_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -144,9 +145,9 @@ elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: # 6 Group that the NZB was posted in e.g. alt.binaries.x # 7 Status of post processing. 0 = OK, 1=failed verification, 2=failed unpack, 3=1+2 Logger.info("MAIN: Script triggered from SABnzbd, starting autoProcessGames...") - result = autoProcessGames.process(sys.argv[1], sys.argv[3], sys.argv[7]) + result = autoProcessGames().process(sys.argv[1], sys.argv[3], sys.argv[7]) # SABnzbd 0.7.17+ -elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: +elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -157,16 +158,22 @@ elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: # 7 Status of post processing. 0 = OK, 1=failed verification, 2=failed unpack, 3=1+2 # 8 Failure URL Logger.info("MAIN: Script triggered from SABnzbd 0.7.17+, starting autoProcessGames...") - result = autoProcessGames.process(sys.argv[1], sys.argv[3], sys.argv[7]) + result = autoProcessGames().process(sys.argv[1], sys.argv[3], sys.argv[7]) else: + result = 0 Logger.warn("MAIN: Invalid number of arguments received from client. Exiting") - sys.exit(1) + Logger.info("MAIN: Running autoProcessGames as a manual run...") + + for dirName in get_dirnames("Gamez", gzCategory[0]): + Logger.info("MAIN: Calling Gamez to post-process: %s", dirName) + result = autoProcessGames().process(dirName, dirName, 0) + if result != 0: break if result == 0: Logger.info("MAIN: The autoProcessGames script completed successfully.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_SUCCESS) + sys.exit(config.NZBGET_POSTPROCESS_SUCCESS) else: Logger.info("MAIN: A problem was reported in the autoProcessGames script.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) diff --git a/nzbToHeadPhones.py b/nzbToHeadPhones.py index 403e7179..c31a2f37 100755 --- a/nzbToHeadPhones.py +++ b/nzbToHeadPhones.py @@ -67,33 +67,32 @@ ### NZBGET POST-PROCESSING SCRIPT ### ############################################################################## -import logging - -import autoProcess.migratecfg as migratecfg -import autoProcess.autoProcessMusic as autoProcessMusic -from autoProcess.nzbToMediaEnv import * -from autoProcess.nzbToMediaUtil import * - # NZBGet argv: all passed as environment variables. # Exit codes used by NZBGet -POSTPROCESS_PARCHECK = 92 -POSTPROCESS_SUCCESS = 93 -POSTPROCESS_ERROR = 94 -POSTPROCESS_NONE = 95 +import os +import sys +import logging +from nzbtomedia.autoProcess.autoProcessMusic import autoProcessMusic +from nzbtomedia.migratecfg import migratecfg +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import get_dirnames, WakeUp, nzbtomedia_configure_logging +# run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. +if migratecfg().migrate(): + # check to write settings from nzbGet UI to autoProcessMedia.cfg. + if os.environ.has_key('NZBOP_SCRIPTDIR'): + migratecfg().addnzbget() -#check to migrate old cfg before trying to load. -if os.path.isfile(os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg.sample")): - migratecfg.migrate() -# check to write settings from nzbGet UI to autoProcessMedia.cfg. -if os.environ.has_key('NZBOP_SCRIPTDIR'): - migratecfg.addnzbget() + nzbtomedia_configure_logging(config.LOG_FILE) + Logger = logging.getLogger(__name__) + Logger.info("====================") # Seperate old from new log + Logger.info("nzbToHeadPhones %s", config.NZBTOMEDIA_VERSION) -nzbtomedia_configure_logging(LOG_FILE) -Logger = logging.getLogger(__name__) - -Logger.info("====================") # Seperate old from new log -Logger.info("nzbToHeadPhones %s", VERSION) + Logger.info("MAIN: Loading config from %s", config.CONFIG_FILE) +else: + sys.exit(-1) +# headphones category +hpCategory = (config().get("HeadPhones", "hpCategory")).split(',') # music WakeUp() @@ -107,13 +106,13 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 if os.environ['NZBOP_UNPACK'] != 'yes': Logger.error("MAIN: Please enable option \"Unpack\" in nzbget configuration file, exiting") - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) # Check par status if os.environ['NZBPP_PARSTATUS'] == '3': Logger.warning("MAIN: Par-check successful, but Par-repair disabled, exiting") Logger.info("MAIN: Please check your Par-repair settings for future downloads.") - sys.exit(POSTPROCESS_NONE) + sys.exit(config.NZBGET_POSTPROCESS_NONE) if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4': Logger.warning("MAIN: Par-repair failed, setting status \"failed\"") @@ -143,9 +142,9 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 # All checks done, now launching the script. Logger.info("MAIN: Script triggered from NZBGet, starting autoProcessMusic...") - result = autoProcessMusic.process(os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBNAME'], status) + result = autoProcessMusic().process(os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBNAME'], status) # SABnzbd Pre 0.7.17 -elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: +elif len(sys.argv) == config.SABNZB_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -155,9 +154,9 @@ elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: # 6 Group that the NZB was posted in e.g. alt.binaries.x # 7 Status of post processing. 0 = OK, 1=failed verification, 2=failed unpack, 3=1+2 Logger.info("MAIN: Script triggered from SABnzbd, starting autoProcessMusic...") - result = autoProcessMusic.process(sys.argv[1], sys.argv[2], sys.argv[7]) + result = autoProcessMusic().process(sys.argv[1], sys.argv[2], sys.argv[7]) # SABnzbd 0.7.17+ -elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: +elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -168,24 +167,23 @@ elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: # 7 Status of post processing. 0 = OK, 1=failed verification, 2=failed unpack, 3=1+2 # 8 Failue URL Logger.info("MAIN: Script triggered from SABnzbd 0.7.17+, starting autoProcessMusic...") - result = autoProcessMusic.process(sys.argv[1], sys.argv[2], sys.argv[7]) + result = autoProcessMusic().process(sys.argv[1], sys.argv[2], sys.argv[7]) else: result = 0 - hpCategory = (config().get("HeadPhones", "hpCategory")).split(',') # music - dirNames = get_dirnames("SickBeard", hpCategory[0]) Logger.warn("MAIN: Invalid number of arguments received from client.") Logger.info("MAIN: Running autoProcessMusic as a manual run...") - for dirName in dirNames: + for dirName in get_dirnames("HeadPhones", hpCategory[0]): Logger.info("MAIN: Calling Headphones to post-process: %s", dirName) - result = result = autoProcessMusic.process(dirName, dirName, 0) + result = result = autoProcessMusic().process(dirName, dirName, 0) if result != 0: break + if result == 0: Logger.info("MAIN: The autoProcessMusic script completed successfully.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_SUCCESS) + sys.exit(config.NZBGET_POSTPROCESS_SUCCESS) else: Logger.info("MAIN: A problem was reported in the autoProcessMusic script.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) diff --git a/nzbToMedia.py b/nzbToMedia.py index 1b29dbaf..4554c6a2 100755 --- a/nzbToMedia.py +++ b/nzbToMedia.py @@ -73,7 +73,7 @@ # SickBeard script category. # # category that gets called for post-processing with SickBeard. -#sbCategory=tv +#config().sbCategory=tv # SickBeard host. #sbhost=localhost @@ -271,54 +271,101 @@ ### NZBGET POST-PROCESSING SCRIPT ### ############################################################################## -import shutil +import os +import sys import logging +from nzbtomedia.autoProcess.autoProcessComics import autoProcessComics +from nzbtomedia.autoProcess.autoProcessGames import autoProcessGames +from nzbtomedia.autoProcess.autoProcessMovie import autoProcessMovie +from nzbtomedia.autoProcess.autoProcessMusic import autoProcessMusic +from nzbtomedia.autoProcess.autoProcessTV import autoProcessTV +from nzbtomedia.migratecfg import migratecfg +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import nzbtomedia_configure_logging, WakeUp, get_dirnames -import autoProcess.autoProcessComics as autoProcessComics -import autoProcess.autoProcessGames as autoProcessGames -import autoProcess.autoProcessMusic as autoProcessMusic -import autoProcess.autoProcessMovie as autoProcessMovie -import autoProcess.autoProcessTV as autoProcessTV -import autoProcess.migratecfg as migratecfg -from autoProcess.nzbToMediaEnv import * -from autoProcess.nzbToMediaUtil import * - -# Exit codes used by NZBGet -POSTPROCESS_PARCHECK = 92 -POSTPROCESS_SUCCESS = 93 -POSTPROCESS_ERROR = 94 -POSTPROCESS_NONE = 95 +# post-processing +def process(nzbDir, inputName=None, status=0, clientAgent='manual', download_id=None, inputCategory=None): + if inputCategory in cpsCategory: + if isinstance(nzbDir, list): + for dirName in nzbDir: + Logger.info("MAIN: Calling CouchPotatoServer to post-process: %s", inputName) + result = autoProcessMovie().process(dirName, dirName, status, clientAgent, download_id, inputCategory) + if result != 0: + return result + else: + Logger.info("MAIN: Calling CouchPotatoServer to post-process: %s", inputName) + return autoProcessMovie().process(nzbDir, inputName, status, clientAgent, download_id, inputCategory) + elif inputCategory in sbCategory: + if isinstance(nzbDir, list): + for dirName in nzbDir: + Logger.info("MAIN: Calling Sick-Beard to post-process: %s", inputName) + result = autoProcessTV().processEpisode(dirName, dirName, status, clientAgent, inputCategory) + if result !=0: + return result + else: + Logger.info("MAIN: Calling Sick-Beard to post-process: %s", inputName) + return autoProcessTV().processEpisode(nzbDir, inputName, status, clientAgent, inputCategory) + elif inputCategory in hpCategory: + if isinstance(nzbDir, list): + for dirName in nzbDir: + Logger.info("MAIN: Calling Headphones to post-process: %s", dirName) + result = autoProcessMusic().process(dirName, dirName, status, clientAgent, inputCategory) + if result != 0: + return result + else: + Logger.info("MAIN: Calling HeadPhones to post-process: %s", inputName) + return autoProcessMusic().process(nzbDir, inputName, status, clientAgent, inputCategory) + elif inputCategory in mlCategory: + if isinstance(nzbDir, list): + for dirName in nzbDir: + Logger.info("MAIN: Calling Mylar to post-process: %s", dirName) + result = autoProcessComics().processEpisode(dirName, dirName, status, clientAgent, inputCategory) + if result != 0: + return result + else: + Logger.info("MAIN: Calling Mylar to post-process: %s", inputName) + return autoProcessComics().processEpisode(nzbDir, inputName, status, clientAgent, inputCategory) + elif inputCategory in gzCategory: + if isinstance(nzbDir, list): + for dirName in nzbDir: + Logger.info("MAIN: Calling Gamez to post-process: %s", dirName) + result = autoProcessGames().process(dirName, dirName, status, clientAgent, inputCategory) + if result != 0: + return result + else: + Logger.info("MAIN: Calling Gamez to post-process: %s", inputName) + return autoProcessGames().process(nzbDir, inputName, status, clientAgent, inputCategory) + else: + Logger.warning("MAIN: The download category %s does not match any category defined in autoProcessMedia.cfg. Exiting.", inputCategory) + return -1 +######################################################################################################################## # run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. -if config(SAMPLE_CONFIG_FILE): - migratecfg.migrate() -elif config(): - shutil.copyfile(CONFIG_FILE, SAMPLE_CONFIG_FILE) - migratecfg.migrate() +if migratecfg().migrate(): + # check to write settings from nzbGet UI to autoProcessMedia.cfg. + if os.environ.has_key('NZBOP_SCRIPTDIR'): + migratecfg().addnzbget() -# check to write settings from nzbGet UI to autoProcessMedia.cfg. -if config() and os.environ.has_key('NZBOP_SCRIPTDIR'): - migratecfg.addnzbget() + nzbtomedia_configure_logging(config.LOG_FILE) + Logger = logging.getLogger(__name__) + Logger.info("====================") # Seperate old from new log + Logger.info("nzbToMedia %s", config.NZBTOMEDIA_VERSION) -nzbtomedia_configure_logging(LOG_FILE) -Logger = logging.getLogger(__name__) + Logger.info("MAIN: Loading config from %s", config.CONFIG_FILE) +else: + sys.exit(-1) -Logger.info("====================") # Seperate old from new log -Logger.info("nzbToMedia %s", VERSION) +# setup categories +cpsCategory = (config().get("CouchPotato", "cpsCategory")).split(',') or [] +sbCategory = (config().get("SickBeard", "sbCategory")).split(',') or [] +hpCategory = (config().get("HeadPhones", "hpCategory")).split(',') or [] +mlCategory = (config().get("Mylar", "mlCategory")).split(',') or [] +gzCategory = (config().get("Gamez", "gzCategory")).split(',') or [] WakeUp() -if not config(): - Logger.error("MAIN: You need an autoProcessMedia.cfg file - did you rename and edit the .sample?") - sys.exit(-1) - -Logger.info("MAIN: Loading config from %s", CONFIG_FILE) - -cpsCategory = (config().get("CouchPotato", "cpsCategory")).split(',') # movie -sbCategory = (config().get("SickBeard", "sbCategory")).split(',') # tv -hpCategory = (config().get("HeadPhones", "hpCategory")).split(',') # music -mlCategory = (config().get("Mylar", "mlCategory")).split(',') # comics -gzCategory = (config().get("Gamez", "gzCategory")).split(',') # games +# Post-Processing Result +result = 0 # NZBGet V11+ # Check if the script is called from nzbget 11.0 or later @@ -333,13 +380,13 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 if os.environ['NZBOP_UNPACK'] != 'yes': Logger.error("MAIN: Please enable option \"Unpack\" in nzbget configuration file, exiting") - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) # Check par status if os.environ['NZBPP_PARSTATUS'] == '3': Logger.warning("MAIN: Par-check successful, but Par-repair disabled, exiting") Logger.info("MAIN: Please check your Par-repair settings for future downloads.") - sys.exit(POSTPROCESS_NONE) + sys.exit(config.NZBGET_POSTPROCESS_NONE) if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4': Logger.warning("MAIN: Par-repair failed, setting status \"failed\"") @@ -369,11 +416,11 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 # All checks done, now launching the script. download_id = "" - if os.environ.has_key('NZBPR_COUCHPOTATO'): - download_id = os.environ['NZBPR_COUCHPOTATO'] - nzbDir, inputName, inputCategory = (os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBFILENAME'], os.environ['NZBPP_CATEGORY']) + if os.environ.has_key('NZBPR_COUCHPOTATO'):download_id = os.environ['NZBPR_COUCHPOTATO'] + result = process(os.environ['NZBPP_DIRECTORY'], inputName=os.environ['NZBPP_NZBFILENAME'], clientAgent = "nzbget", inputCategory=os.environ['NZBPP_CATEGORY']) + if result != 0: Logger.info("MAIN: A problem was reported in the autoProcess* script.") # SABnzbd Pre 0.7.17 -elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: +elif len(sys.argv) == config.SABNZB_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -383,10 +430,10 @@ elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: # 6 Group that the NZB was posted in e.g. alt.binaries.x # 7 Status of post processing. 0 = OK, 1=failed verification, 2=failed unpack, 3=1+2 Logger.info("MAIN: Script triggered from SABnzbd") - clientAgent = "sabnzbd" - nzbDir, inputName, status, inputCategory, download_id = (sys.argv[1], sys.argv[2], sys.argv[7], sys.argv[5], '') + result = process(sys.argv[1], inputName=sys.argv[2], status=sys.argv[7], inputCategory=sys.argv[5], clientAgent = "sabnzbd", download_id='') + if result != 0: Logger.info("MAIN: A problem was reported in the autoProcess* script.") # SABnzbd 0.7.17+ -elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: +elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -397,61 +444,37 @@ elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: # 7 Status of post processing. 0 = OK, 1=failed verification, 2=failed unpack, 3=1+2 # 8 Failure URL Logger.info("MAIN: Script triggered from SABnzbd 0.7.17+") - clientAgent = "sabnzbd" - nzbDir, inputName, status, inputCategory, download_id = (sys.argv[1], sys.argv[2], sys.argv[7], sys.argv[5], '') -else: # only CPS and SB supports this manual run for now. - clientAgent = "manual" + result = process(sys.argv[1], inputName=sys.argv[2], status=sys.argv[7], inputCategory=sys.argv[5], clientAgent = "sabnzbd", download_id='') + if result != 0:Logger.info("MAIN: A problem was reported in the autoProcess* script.") +else: + # only CPS and SB supports this manual run for now. Logger.warn("MAIN: Invalid number of arguments received from client.") Logger.info("MAIN: Running autoProcessMovie as a manual run...") - nzbDir, inputName, status, inputCategory, download_id = ('Manual Run', 'Manual Run', 0, cpsCategory[0], '') + if process(get_dirnames("CouchPotato", cpsCategory[0]), inputName=get_dirnames("CouchPotato", cpsCategory[0]), status=0, inputCategory=cpsCategory[0], clientAgent = "manual", download_id='') != 0: + Logger.info("MAIN: A problem was reported in the autoProcessMovie script.") Logger.info("MAIN: Running autoProcessTV as a manual run...") - dirNames = get_dirnames("SickBeard", sbCategory[0]) - nzbDir, inputName, status, inputCategory, = (dirNames, dirNames, 0, sbCategory[0]) + if process(get_dirnames("SickBeard", sbCategory[0]), inputName=get_dirnames("SickBeard", sbCategory[0]), status=0, clientAgent = "manual", inputCategory=sbCategory[0]) != 0: + Logger.info("MAIN: A problem was reported in the autoProcessTV script.") Logger.info("MAIN: Running autoProcessMusic as a manual run...") - dirNames = get_dirnames("HeadPhones", hpCategory[0]) - nzbDir, inputName, status, inputCategory = (dirNames, dirNames, 0, sbCategory[0]) + if process(get_dirnames("HeadPhones", hpCategory[0]), inputName=get_dirnames("HeadPhones", hpCategory[0]), status=0, clientAgent = "manual", inputCategory=hpCategory[0]) != 0: + Logger.info("MAIN: A problem was reported in the autoProcessMusic script.") -if inputCategory in cpsCategory: - Logger.info("MAIN: Calling CouchPotatoServer to post-process: %s", inputName) - result = autoProcessMovie.process(nzbDir, inputName, status, clientAgent, download_id, inputCategory) -elif inputCategory in sbCategory: - result = 0 - if isinstance(nzbDir, list): - for dirName in nzbDir: - Logger.info("MAIN: Calling Sick-Beard to post-process: %s", inputName) - result = autoProcessTV.processEpisode(dirName, dirName, status, clientAgent, inputCategory) - if result !=0:break - else: - Logger.info("MAIN: Calling Sick-Beard to post-process: %s", inputName) - result = autoProcessTV.processEpisode(nzbDir, inputName, status, clientAgent, inputCategory) -elif inputCategory in hpCategory: - result = 0 - if isinstance(nzbDir, list): - for dirName in nzbDir: - Logger.info("MAIN: Calling Headphones to post-process: %s", dirName) - result = autoProcessMusic.process(dirName, dirName, status, clientAgent, inputCategory) - if result != 0: break - else: - Logger.info("MAIN: Calling HeadPhones to post-process: %s", inputName) - result = autoProcessMusic.process(nzbDir, inputName, status, clientAgent, inputCategory) -elif inputCategory in mlCategory: - Logger.info("MAIN: Calling Mylar to post-process: %s", inputName) - result = autoProcessComics.processEpisode(nzbDir, inputName, status, inputCategory) -elif inputCategory in gzCategory: - Logger.info("MAIN: Calling Gamez to post-process: %s", inputName) - result = autoProcessGames.process(nzbDir, inputName, status, inputCategory) -else: - Logger.warning("MAIN: The download category %s does not match any category defined in autoProcessMedia.cfg. Exiting.", inputCategory) - sys.exit(POSTPROCESS_ERROR) + Logger.info("MAIN: Running autoProcessComics as a manual run...") + if process(get_dirnames("Mylar", mlCategory[0]), inputName=get_dirnames("Mylar", mlCategory[0]), status=0,clientAgent="manual", inputCategory=mlCategory[0]) != 0: + Logger.info("MAIN: A problem was reported in the autoProcessComics script.") + + Logger.info("MAIN: Running autoProcessGames as a manual run...") + if process(get_dirnames("Gamez", gzCategory[0]), inputName=get_dirnames("Gamez", gzCategory[0]), status=0,clientAgent="manual", inputCategory=gzCategory[0]) != 0: + Logger.info("MAIN: A problem was reported in the autoProcessGames script.") if result == 0: - Logger.info("MAIN: The autoProcess* script completed successfully.") + Logger.info("MAIN: The nzbToMedia script completed successfully.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_SUCCESS) + sys.exit(config.NZBGET_POSTPROCESS_SUCCESS) else: - Logger.info("MAIN: A problem was reported in the autoProcess* script.") + Logger.info("MAIN: A problem was reported in the nzbToMedia script.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_ERROR) \ No newline at end of file + sys.exit(config.NZBGET_POSTPROCESS_ERROR) \ No newline at end of file diff --git a/nzbToMediaConfig.py b/nzbToMediaConfig.py deleted file mode 100644 index 6a45cf2a..00000000 --- a/nzbToMediaConfig.py +++ /dev/null @@ -1,38 +0,0 @@ -import os -import ConfigParser - -# init paths -MY_FULLNAME = os.path.normpath(os.path.abspath(__file__)) -MY_NAME = os.path.basename(MY_FULLNAME) -PROG_DIR = os.path.dirname(MY_FULLNAME) - -# init config file names -CONFIG_FILE = os.path.join(PROG_DIR, "autoProcessMedia.cfg") -SAMPLE_CONFIG_FILE = os.path.join(PROG_DIR, "autoProcessMedia.cfg.sample") -MOVIE_CONFIG_FILE = os.path.join(PROG_DIR, "autoProcessMovie.cfg") -TV_CONFIG_FILE = os.path.join(PROG_DIR, "autoProcessTv.cfg") -LOG_FILE = os.path.join(PROG_DIR, "postprocess.log") - -class config(object): - - # link error handling classes - Error = ConfigParser.Error - NoSectionError = ConfigParser.NoSectionError - NoOptionError = ConfigParser.NoOptionError - DuplicateSectionError = ConfigParser.DuplicateSectionError - InterpolationError = ConfigParser.InterpolationError - InterpolationMissingOptionError = ConfigParser.InterpolationMissingOptionError - InterpolationSyntaxError = ConfigParser.InterpolationSyntaxError - InterpolationDepthError = ConfigParser.InterpolationDepthError - ParsingError = ConfigParser.ParsingError - MissingSectionHeaderError = ConfigParser.MissingSectionHeaderError - - def __new__(cls, *file): - if not file: - file = CONFIG_FILE - - # load config - config = ConfigParser.ConfigParser() - config.optionxform = str - if config.read(file): - return config \ No newline at end of file diff --git a/nzbToMylar.py b/nzbToMylar.py index 0d470235..7632a180 100755 --- a/nzbToMylar.py +++ b/nzbToMylar.py @@ -60,25 +60,32 @@ ### NZBGET POST-PROCESSING SCRIPT ### ############################################################################## +# Exit codes used by NZBGet import logging +import os +import sys +from nzbtomedia.autoProcess.autoProcessComics import autoProcessComics +from nzbtomedia.migratecfg import migratecfg +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import nzbtomedia_configure_logging, WakeUp, get_dirnames -import autoProcess.migratecfg as migratecfg -import autoProcess.autoProcessComics as autoProcessComics -from autoProcess.nzbToMediaEnv import * -from autoProcess.nzbToMediaUtil import * +# run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. +if migratecfg().migrate(): + # check to write settings from nzbGet UI to autoProcessMedia.cfg. + if os.environ.has_key('NZBOP_SCRIPTDIR'): + migratecfg().addnzbget() -#check to migrate old cfg before trying to load. -if os.path.isfile(os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg.sample")): - migratecfg.migrate() -# check to write settings from nzbGet UI to autoProcessMedia.cfg. -if os.environ.has_key('NZBOP_SCRIPTDIR'): - migratecfg.addnzbget() + nzbtomedia_configure_logging(config.LOG_FILE) + Logger = logging.getLogger(__name__) + Logger.info("====================") # Seperate old from new log + Logger.info("nzbToMylar %s", config.NZBTOMEDIA_VERSION) -nzbtomedia_configure_logging(LOG_FILE) -Logger = logging.getLogger(__name__) + Logger.info("MAIN: Loading config from %s", config.CONFIG_FILE) +else: + sys.exit(-1) -Logger.info("====================") # Seperate old from new log -Logger.info("nzbToMylar %s", VERSION) +# mylar category +mlCategory = (config().get("Mylar", "mlCategory")).split(',') # tv WakeUp() @@ -87,25 +94,18 @@ WakeUp() if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5] < '11.0': Logger.info("MAIN: Script triggered from NZBGet (11.0 or later).") - # NZBGet argv: all passed as environment variables. - # Exit codes used by NZBGet - POSTPROCESS_PARCHECK=92 - POSTPROCESS_SUCCESS=93 - POSTPROCESS_ERROR=94 - POSTPROCESS_NONE=95 - # Check nzbget.conf options status = 0 if os.environ['NZBOP_UNPACK'] != 'yes': Logger.error("MAIN: Please enable option \"Unpack\" in nzbget configuration file, exiting") - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) # Check par status if os.environ['NZBPP_PARSTATUS'] == '3': Logger.warning("MAIN: Par-check successful, but Par-repair disabled, exiting") Logger.info("MAIN: Please check your Par-repair settings for future downloads.") - sys.exit(POSTPROCESS_NONE) + sys.exit(config.NZBGET_POSTPROCESS_NONE) if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4': Logger.warning("MAIN: Par-repair failed, setting status \"failed\"") @@ -135,9 +135,9 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 # All checks done, now launching the script. Logger.info("MAIN: Script triggered from NZBGet, starting autoProcessComics...") - result = autoProcessComics.processEpisode(os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBNAME'], status) + result = autoProcessComics().processEpisode(os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBNAME'], status) # SABnzbd Pre 0.7.17 -elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: +elif len(sys.argv) == config.SABNZB_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -147,9 +147,9 @@ elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: # 6 Group that the NZB was posted in e.g. alt.binaries.x # 7 Status of post processing. 0 = OK, 1=failed verification, 2=failed unpack, 3=1+2 Logger.info("MAIN: Script triggered from SABnzbd, starting autoProcessComics...") - result = autoProcessComics.processEpisode(sys.argv[1], sys.argv[3], sys.argv[7]) + result = autoProcessComics().processEpisode(sys.argv[1], sys.argv[3], sys.argv[7]) # SABnzbd 0.7.17+ -elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: +elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -160,17 +160,23 @@ elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: # 7 Status of post processing. 0 = OK, 1=failed verification, 2=failed unpack, 3=1+2 # 8 Failure URL Logger.info("MAIN: Script triggered from SABnzbd 0.7.17+, starting autoProcessComics...") - result = autoProcessComics.processEpisode(sys.argv[1], sys.argv[3], sys.argv[7]) + result = autoProcessComics().processEpisode(sys.argv[1], sys.argv[3], sys.argv[7]) else: + result = 0 + Logger.warn("MAIN: Invalid number of arguments received from client.") Logger.info("MAIN: Running autoProcessComics as a manual run...") - result = autoProcessComics.processEpisode('Manual Run', 'Manual Run', 0) + + for dirName in get_dirnames("Mylar", mlCategory[0]): + Logger.info("MAIN: Calling Mylar to post-process: %s", dirName) + result = autoProcessComics().processEpisode(dirName, dirName, 0) + if result != 0: break if result == 0: Logger.info("MAIN: The autoProcessComics script completed successfully.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_SUCCESS) + sys.exit(config.NZBGET_POSTPROCESS_SUCCESS) else: Logger.info("MAIN: A problem was reported in the autoProcessComics script.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) diff --git a/nzbToSickBeard.py b/nzbToSickBeard.py index 1db1ed7f..d487fffa 100755 --- a/nzbToSickBeard.py +++ b/nzbToSickBeard.py @@ -123,33 +123,31 @@ ### NZBGET POST-PROCESSING SCRIPT ### ############################################################################## - +import os +import sys import logging +from nzbtomedia.autoProcess.autoProcessTV import autoProcessTV +from nzbtomedia.migratecfg import migratecfg +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import nzbtomedia_configure_logging, WakeUp, get_dirnames -import autoProcess.migratecfg as migratecfg -import autoProcess.autoProcessTV as autoProcessTV -from autoProcess.nzbToMediaEnv import * -from autoProcess.nzbToMediaUtil import * +# run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. +if migratecfg().migrate(): + # check to write settings from nzbGet UI to autoProcessMedia.cfg. + if os.environ.has_key('NZBOP_SCRIPTDIR'): + migratecfg().addnzbget() -# NZBGet argv: all passed as environment variables. -# Exit codes used by NZBGet -POSTPROCESS_PARCHECK = 92 -POSTPROCESS_SUCCESS = 93 -POSTPROCESS_ERROR = 94 -POSTPROCESS_NONE = 95 + nzbtomedia_configure_logging(config.LOG_FILE) + Logger = logging.getLogger(__name__) + Logger.info("====================") # Seperate old from new log + Logger.info("nzbToSickBeard %s", config.NZBTOMEDIA_VERSION) -#check to migrate old cfg before trying to load. -if os.path.isfile(os.path.join(os.path.dirname(sys.argv[0]), "autoProcessMedia.cfg.sample")): - migratecfg.migrate() -# check to write settings from nzbGet UI to autoProcessMedia.cfg. -if os.environ.has_key('NZBOP_SCRIPTDIR'): - migratecfg.addnzbget() + Logger.info("MAIN: Loading config from %s", config.CONFIG_FILE) +else: + sys.exit(-1) -nzbtomedia_configure_logging(LOG_FILE) -Logger = logging.getLogger(__name__) - -Logger.info("====================") # Seperate old from new log -Logger.info("nzbToSickBeard %s", VERSION) +# sickbeard category +sbCategory = (config().get("SickBeard", "sbCategory")).split(',') # tv WakeUp() @@ -163,13 +161,13 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 if os.environ['NZBOP_UNPACK'] != 'yes': Logger.error("MAIN: Please enable option \"Unpack\" in nzbget configuration file, exiting") - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) # Check par status if os.environ['NZBPP_PARSTATUS'] == '3': Logger.warning("MAIN: Par-check successful, but Par-repair disabled, exiting") Logger.info("MAIN: Please check your Par-repair settings for future downloads.") - sys.exit(POSTPROCESS_NONE) + sys.exit(config.NZBGET_POSTPROCESS_NONE) if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4': Logger.warning("MAIN: Par-repair failed, setting status \"failed\"") @@ -200,9 +198,9 @@ if os.environ.has_key('NZBOP_SCRIPTDIR') and not os.environ['NZBOP_VERSION'][0:5 # All checks done, now launching the script. Logger.info("MAIN: Script triggered from NZBGet, starting autoProcessTV...") clientAgent = "nzbget" - result = autoProcessTV.processEpisode(os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBFILENAME'], status, clientAgent, os.environ['NZBPP_CATEGORY']) + result = autoProcessTV().processEpisode(os.environ['NZBPP_DIRECTORY'], os.environ['NZBPP_NZBFILENAME'], status, clientAgent, os.environ['NZBPP_CATEGORY']) # SABnzbd Pre 0.7.17 -elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: +elif len(sys.argv) == config.SABNZB_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -213,9 +211,9 @@ elif len(sys.argv) == SABNZB_NO_OF_ARGUMENTS: # 7 Status of post processing. 0 = OK, 1=failed verification, 2=failed unpack, 3=1+2 Logger.info("MAIN: Script triggered from SABnzbd, starting autoProcessTV...") clientAgent = "sabnzbd" - result = autoProcessTV.processEpisode(sys.argv[1], sys.argv[2], sys.argv[7], clientAgent, sys.argv[5]) + result = autoProcessTV().processEpisode(sys.argv[1], sys.argv[2], sys.argv[7], clientAgent, sys.argv[5]) # SABnzbd 0.7.17+ -elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: +elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: # SABnzbd argv: # 1 The final directory of the job (full path) # 2 The original name of the NZB file @@ -227,24 +225,23 @@ elif len(sys.argv) >= SABNZB_0717_NO_OF_ARGUMENTS: # 8 Failure URL Logger.info("MAIN: Script triggered from SABnzbd 0.7.17+, starting autoProcessTV...") clientAgent = "sabnzbd" - result = autoProcessTV.processEpisode(sys.argv[1], sys.argv[2], sys.argv[7], clientAgent, sys.argv[5]) + result = autoProcessTV().processEpisode(sys.argv[1], sys.argv[2], sys.argv[7], clientAgent, sys.argv[5]) else: result = 0 - sbCategory = (config().get("SickBeard", "sbCategory")).split(',') # tv - dirNames = get_dirnames("SickBeard", sbCategory[0]) Logger.debug("MAIN: Invalid number of arguments received from client.") Logger.info("MAIN: Running autoProcessTV as a manual run...") - for dirName in dirNames: + for dirName in get_dirnames("SickBeard", sbCategory[0]): Logger.info("MAIN: Calling Sick-Beard to post-process: %s", dirName) - result = autoProcessTV.processEpisode(dirName, dirName, 0) + result = autoProcessTV().processEpisode(dirName, dirName, 0) if result != 0: break + if result == 0: Logger.info("MAIN: The autoProcessTV script completed successfully.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_SUCCESS) + sys.exit(config.NZBGET_POSTPROCESS_SUCCESS) else: Logger.info("MAIN: A problem was reported in the autoProcessTV script.") if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 - sys.exit(POSTPROCESS_ERROR) + sys.exit(config.NZBGET_POSTPROCESS_ERROR) diff --git a/nzbtomedia/Transcoder.py b/nzbtomedia/Transcoder.py new file mode 100644 index 00000000..13494e73 --- /dev/null +++ b/nzbtomedia/Transcoder.py @@ -0,0 +1,144 @@ +import errno +import logging +import os +import sys +from subprocess import call +from nzbtomedia.nzbToMediaConfig import config + + +class Transcoder: + def Transcode_directory(self, dirName): + Logger = logging.getLogger() + + if os.name == 'nt': + ffmpeg = os.path.join(os.path.dirname(sys.argv[0]), 'ffmpeg\\bin\\ffmpeg.exe') # note, will need to package in this dir. + useNiceness = False + if not os.path.isfile(ffmpeg): # problem + Logger.error("ffmpeg not found. ffmpeg needs to be located at: %s", ffmpeg) + Logger.info("Cannot transcode files in folder %s", dirName) + return 1 # failure + else: + if call(['which', 'ffmpeg']) != 0: + res = call([os.path.join(os.path.dirname(sys.argv[0]),'getffmpeg.sh')]) + if res or call(['which', 'ffmpeg']) != 0: # did not install or ffmpeg still not found. + Logger.error("Failed to install ffmpeg. Please install manually") + Logger.info("Cannot transcode files in folder %s", dirName) + return 1 # failure + else: + ffmpeg = 'ffmpeg' + else: + ffmpeg = 'ffmpeg' + useNiceness = True + + Logger.info("Loading config from %s", config.CONFIG_FILE) + + if not config(): + Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?") + return 1 # failure + + mediaContainer = (config().get("Extensions", "mediaExtensions")).split(',') + duplicate = int(config().get("Transcoder", "duplicate")) + ignoreExtensions = (config().get("Transcoder", "ignoreExtensions")).split(',') + outputVideoExtension = config().get("Transcoder", "outputVideoExtension").strip() + outputVideoCodec = config().get("Transcoder", "outputVideoCodec").strip() + outputVideoPreset = config().get("Transcoder", "outputVideoPreset").strip() + outputVideoFramerate = config().get("Transcoder", "outputVideoFramerate").strip() + outputVideoBitrate = config().get("Transcoder", "outputVideoBitrate").strip() + outputAudioCodec = config().get("Transcoder", "outputAudioCodec").strip() + outputAudioBitrate = config().get("Transcoder", "outputAudioBitrate").strip() + outputSubtitleCodec = config().get("Transcoder", "outputSubtitleCodec").strip() + outputFastStart = int(config().get("Transcoder", "outputFastStart")) + outputQualityPercent = int(config().get("Transcoder", "outputQualityPercent")) + + niceness = None + if useNiceness:niceness = int(config().get("Transcoder", "niceness")) + + map(lambda ext: ext.strip(), mediaContainer) + map(lambda ext: ext.strip(), ignoreExtensions) + + Logger.info("Checking for files to be transcoded") + final_result = 0 # initialize as successful + for dirpath, dirnames, filenames in os.walk(dirName): + for file in filenames: + filePath = os.path.join(dirpath, file) + name, ext = os.path.splitext(filePath) + if ext in mediaContainer: # If the file is a video file + if ext in ignoreExtensions: + Logger.info("No need to transcode video type %s", ext) + continue + if ext == outputVideoExtension: # we need to change the name to prevent overwriting itself. + outputVideoExtension = '-transcoded' + outputVideoExtension # adds '-transcoded.ext' + newfilePath = os.path.normpath(name + outputVideoExtension) + + command = [ffmpeg, '-loglevel', 'warning', '-i', filePath, '-map', '0'] # -map 0 takes all input streams + + if useNiceness: + command = ['nice', '-%d' % niceness] + command + + if len(outputVideoCodec) > 0: + command.append('-c:v') + command.append(outputVideoCodec) + if outputVideoCodec == 'libx264' and outputVideoPreset: + command.append('-preset') + command.append(outputVideoPreset) + else: + command.append('-c:v') + command.append('copy') + if len(outputVideoFramerate) > 0: + command.append('-r') + command.append(str(outputVideoFramerate)) + if len(outputVideoBitrate) > 0: + command.append('-b:v') + command.append(str(outputVideoBitrate)) + if len(outputAudioCodec) > 0: + command.append('-c:a') + command.append(outputAudioCodec) + if outputAudioCodec == 'aac': # Allow users to use the experimental AAC codec that's built into recent versions of ffmpeg + command.append('-strict') + command.append('-2') + else: + command.append('-c:a') + command.append('copy') + if len(outputAudioBitrate) > 0: + command.append('-b:a') + command.append(str(outputAudioBitrate)) + if outputFastStart > 0: + command.append('-movflags') + command.append('+faststart') + if outputQualityPercent > 0: + command.append('-q:a') + command.append(str(outputQualityPercent)) + if len(outputSubtitleCodec) > 0: # Not every subtitle codec can be used for every video container format! + command.append('-c:s') + command.append(outputSubtitleCodec) # http://en.wikibooks.org/wiki/FFMPEG_An_Intermediate_Guide/subtitle_options + else: + command.append('-sn') # Don't copy the subtitles over + command.append(newfilePath) + + try: # Try to remove the file that we're transcoding to just in case. (ffmpeg will return an error if it already exists for some reason) + os.remove(newfilePath) + except OSError, e: + if e.errno != errno.ENOENT: # Ignore the error if it's just telling us that the file doesn't exist + Logger.debug("Error when removing transcoding target: %s", e) + except Exception, e: + Logger.debug("Error when removing transcoding target: %s", e) + + Logger.info("Transcoding video: %s", file) + cmd = "" + for item in command: + cmd = cmd + " " + item + Logger.debug("calling command:%s", cmd) + result = 1 # set result to failed in case call fails. + try: + result = call(command) + except: + Logger.exception("Transcoding of video %s has failed", filePath) + if result == 0: + Logger.info("Transcoding of video %s to %s succeeded", filePath, newfilePath) + if duplicate == 0: # we get rid of the original file + os.unlink(filePath) + else: + Logger.error("Transcoding of video %s to %s failed", filePath, newfilePath) + # this will be 0 (successful) it all are successful, else will return a positive integer for failure. + final_result = final_result + result + return final_result diff --git a/autoProcess/__init__.py b/nzbtomedia/__init__.py similarity index 100% rename from autoProcess/__init__.py rename to nzbtomedia/__init__.py diff --git a/extractor/__init__.py b/nzbtomedia/autoProcess/__init__.py similarity index 100% rename from extractor/__init__.py rename to nzbtomedia/autoProcess/__init__.py diff --git a/nzbtomedia/autoProcess/autoProcessComics.py b/nzbtomedia/autoProcess/autoProcessComics.py new file mode 100644 index 00000000..353a85ec --- /dev/null +++ b/nzbtomedia/autoProcess/autoProcessComics.py @@ -0,0 +1,72 @@ +import logging +import urllib +import requests +import socket +import time +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import convert_to_ascii + +Logger = logging.getLogger() + +class autoProcessComics: + def processEpisode(self, dirName, nzbName=None, status=0, clientAgent='manual', inputCategory=None): + if dirName is None: + Logger.error("No directory was given!") + return 1 # failure + + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. + + Logger.info("Loading config from %s", config.CONFIG_FILE) + + section = "Mylar" + if inputCategory != None and config().has_section(inputCategory): + section = inputCategory + host = config().get(section, "host") + port = config().get(section, "port") + username = config().get(section, "username") + password = config().get(section, "password") + try: + ssl = int(config().get(section, "ssl")) + except (config.NoOptionError, ValueError): + ssl = 0 + + try: + web_root = config().get(section, "web_root") + except config.NoOptionError: + web_root = "" + + try: + watch_dir = config().get(section, "watch_dir") + except config.NoOptionError: + watch_dir = "" + params = {} + + nzbName, dirName = convert_to_ascii(nzbName, dirName) + + if dirName == "Manual Run" and watch_dir != "": + dirName = watch_dir + + params['nzb_folder'] = dirName + if nzbName != None: + params['nzb_name'] = nzbName + + if ssl: + protocol = "https://" + else: + protocol = "http://" + + url = protocol + host + ":" + port + web_root + "/post_process?" + urllib.urlencode(params) + + Logger.debug("Opening URL: %s", url) + + try: + r = requests.get(url, auth=(username, password)) + except requests.ConnectionError: + Logger.exception("Unable to open URL") + return 1 # failure + + if r.ok: + Logger.info("%s", r.content) + + time.sleep(60) #wait 1 minute for now... need to see just what gets logged and how long it takes to process + return 0 # Success diff --git a/nzbtomedia/autoProcess/autoProcessGames.py b/nzbtomedia/autoProcess/autoProcessGames.py new file mode 100644 index 00000000..966852c1 --- /dev/null +++ b/nzbtomedia/autoProcess/autoProcessGames.py @@ -0,0 +1,72 @@ +import json +import logging +import socket +import requests +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import convert_to_ascii + +Logger = logging.getLogger() + +class autoProcessGames: + def process(self, dirName, nzbName=None, status=0, clientAgent='manual', inputCategory=None): + if dirName is None: + Logger.error("No directory was given!") + return 1 # failure + + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. + + Logger.info("Loading config from %s", config.CONFIG_FILE) + + status = int(status) + + section = "Gamez" + if inputCategory != None and config().has_section(inputCategory): + section = inputCategory + + host = config().get(section, "host") + port = config().get(section, "port") + apikey = config().get(section, "apikey") + + try: + ssl = int(config().get(section, "ssl")) + except (config.NoOptionError, ValueError): + ssl = 0 + + try: + web_root = config().get(section, "web_root") + except config.NoOptionError: + web_root = "" + + if ssl: + protocol = "https://" + else: + protocol = "http://" + + nzbName, dirName = convert_to_ascii(nzbName, dirName) + + baseURL = protocol + host + ":" + port + web_root + "/api?api_key=" + apikey + "&mode=" + + fields = nzbName.split("-") + gamezID = fields[0].replace("[","").replace("]","").replace(" ","") + downloadStatus = 'Wanted' + if status == 0: + downloadStatus = 'Downloaded' + + url = baseURL + "UPDATEREQUESTEDSTATUS&db_id=" + gamezID + "&status=" + downloadStatus + + Logger.debug("Opening URL: %s", url) + + try: + r = requests.get(url) + except requests.ConnectionError: + Logger.exception("Unable to open URL") + return 1 # failure + + result = json.load(r.content) + Logger.info("Gamez returned %s", result) + if result['success']: + Logger.info("Status for %s has been set to %s in Gamez", gamezID, downloadStatus) + return 0 # Success + else: + Logger.error("Status for %s has NOT been updated in Gamez", gamezID) + return 1 # failure diff --git a/nzbtomedia/autoProcess/autoProcessMovie.py b/nzbtomedia/autoProcess/autoProcessMovie.py new file mode 100644 index 00000000..eda0b998 --- /dev/null +++ b/nzbtomedia/autoProcess/autoProcessMovie.py @@ -0,0 +1,324 @@ +import time +import datetime +import logging +import socket +import urllib +import requests +import shutil +import json +from nzbtomedia.Transcoder import Transcoder +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaSceneExceptions import process_all_exceptions +from nzbtomedia.nzbToMediaUtil import getDirectorySize, convert_to_ascii + +Logger = logging.getLogger() + +class autoProcessMovie: + def get_imdb(self, nzbName, dirName): + imdbid = "" + + a = nzbName.find('.cp(') + 4 #search for .cptt( in nzbName + b = nzbName[a:].find(')') + a + if a > 3: # a == 3 if not exist + imdbid = nzbName[a:b] + + if imdbid: + Logger.info("Found movie id %s in name", imdbid) + return imdbid + + a = dirName.find('.cp(') + 4 #search for .cptt( in dirname + b = dirName[a:].find(')') + a + if a > 3: # a == 3 if not exist + imdbid = dirName[a:b] + + if imdbid: + Logger.info("Found movie id %s in directory", imdbid) + return imdbid + + else: + Logger.debug("Could not find an imdb id in directory or name") + return "" + + def get_movie_info(self, baseURL, imdbid, download_id): + + movie_id = "" + movie_status = None + release_status = None + if not imdbid and not download_id: + return movie_id, imdbid, download_id, movie_status, release_status + + releaselist = [] + movieid = [] + moviestatus = [] + library = [] + release = [] + offset = int(0) + while True: + url = baseURL + "media.list/?status=active&release_status=snatched&limit_offset=50," + str(offset) + + Logger.debug("Opening URL: %s", url) + + try: + r = requests.get(url) + except requests.ConnectionError: + Logger.exception("Unable to open URL") + break + + movieid2 = [] + library2 = [] + release2 = [] + moviestatus2 = [] + try: + result = json.load(r.content) + movieid2 = [item["_id"] for item in result["movies"]] + for item in result["movies"]: + if "identifier" in item: + library2.append(item["identifier"]) + else: + library2.append(item["identifiers"]["imdb"]) + release2 = [item["releases"] for item in result["movies"]] + moviestatus2 = [item["status"] for item in result["movies"]] + except: + Logger.exception("Unable to parse json data for movies") + break + + movieid.extend(movieid2) + moviestatus.extend(moviestatus2) + library.extend(library2) + release.extend(release2) + if len(movieid2) < int(50): # finished parsing list of movies. Time to break. + break + offset = offset + 50 + + result = None # reset + for index in range(len(movieid)): + releaselist1 = [item for item in release[index] if item["status"] == "snatched" and "download_info" in item] + if download_id: + releaselist = [item for item in releaselist1 if item["download_info"]["id"].lower() == download_id.lower()] + else: + releaselist = releaselist1 + + if imdbid and library[index] == imdbid: + movie_id = str(movieid[index]) + movie_status = str(moviestatus[index]) + Logger.info("Found movie id %s with status %s in CPS database for movie %s", movie_id, movie_status, imdbid) + if not download_id and len(releaselist) == 1: + download_id = releaselist[0]["download_info"]["id"] + + elif not imdbid and download_id and len(releaselist) > 0: + movie_id = str(movieid[index]) + movie_status = str(moviestatus[index]) + imdbid = str(library[index]) + Logger.info("Found movie id %s and imdb %s with status %s in CPS database via download_id %s", movie_id, imdbid, movie_status, download_id) + + else: + continue + + if len(releaselist) == 1: + release_status = releaselist[0]["status"] + Logger.debug("Found a single release with download_id: %s. Release status is: %s", download_id, release_status) + + break + + if not movie_id: + Logger.exception("Could not parse database results to determine imdbid or movie id") + + return movie_id, imdbid, download_id, movie_status, release_status + + def get_status(self, baseURL, movie_id, download_id): + result = None + movie_status = None + release_status = None + if not movie_id: + return movie_status, release_status + + Logger.debug("Looking for status of movie: %s", movie_id) + url = baseURL + "media.get/?id=" + str(movie_id) + Logger.debug("Opening URL: %s", url) + + try: + r = requests.get(url) + except requests.ConnectionError: + Logger.exception("Unable to open URL") + return None, None + + try: + result = json.load(r.content) + movie_status = str(result["media"]["status"]) + Logger.debug("This movie is marked as status %s in CouchPotatoServer", movie_status) + except: + Logger.exception("Could not find a status for this movie") + + try: + if len(result["media"]["releases"]) == 1 and result["media"]["releases"][0]["status"] == "done": + release_status = result["media"]["releases"][0]["status"] + else: + release_status_list = [item["status"] for item in result["media"]["releases"] if "download_info" in item and item["download_info"]["id"].lower() == download_id.lower()] + if len(release_status_list) == 1: + release_status = release_status_list[0] + Logger.debug("This release is marked as status %s in CouchPotatoServer", release_status) + except: # index out of range/doesn't exist? + Logger.exception("Could not find a status for this release") + + return movie_status, release_status + + def process(self, dirName, nzbName=None, status=0, clientAgent = "manual", download_id = "", inputCategory=None): + if dirName is None: + Logger.error("No directory was given!") + return 1 # failure + + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. + Logger.info("Loading config from %s", config.CONFIG_FILE) + + status = int(status) + + section = "CouchPotato" + if inputCategory != None and config().has_section(inputCategory): + section = inputCategory + + host = config().get(section, "host") + port = config().get(section, "port") + apikey = config().get(section, "apikey") + delay = float(config().get(section, "delay")) + method = config().get(section, "method") + delete_failed = int(config().get(section, "delete_failed")) + wait_for = int(config().get(section, "wait_for")) + try: + TimePerGiB = int(config().get(section, "TimePerGiB")) + except (config.NoOptionError, ValueError): + TimePerGiB = 60 # note, if using Network to transfer on 100Mbit LAN, expect ~ 600 MB/minute. + try: + ssl = int(config().get(section, "ssl")) + except (config.NoOptionError, ValueError): + ssl = 0 + try: + web_root = config().get(section, "web_root") + except config.NoOptionError: + web_root = "" + try: + transcode = int(config().get("Transcoder", "transcode")) + except (config.NoOptionError, ValueError): + transcode = 0 + try: + remoteCPS = int(config().get(section, "remoteCPS")) + except (config.NoOptionError, ValueError): + remoteCPS = 0 + + nzbName = str(nzbName) # make sure it is a string + + imdbid = self.get_imdb(nzbName, dirName) + + if ssl: + protocol = "https://" + else: + protocol = "http://" + # don't delay when we are calling this script manually. + if clientAgent == "manual": + delay = 0 + + baseURL = protocol + host + ":" + port + web_root + "/api/" + apikey + "/" + + movie_id, imdbid, download_id, initial_status, initial_release_status = self.get_movie_info(baseURL, imdbid, download_id) # get the CPS database movie id for this movie. + + process_all_exceptions(nzbName.lower(), dirName) + nzbName, dirName = convert_to_ascii(nzbName, dirName) + + if status == 0: + if transcode == 1: + result = Transcoder().Transcode_directory(dirName) + if result == 0: + Logger.debug("Transcoding succeeded for files in %s", dirName) + else: + Logger.warning("Transcoding failed for files in %s", dirName) + + if method == "manage": + command = "manage.update" + else: + command = "renamer.scan" + if clientAgent != "manual" and download_id != None: + if remoteCPS == 1: + command = command + "/?downloader=" + clientAgent + "&download_id=" + download_id + else: + command = command + "/?media_folder=" + urllib.quote(dirName) + "&downloader=" + clientAgent + "&download_id=" + download_id + + dirSize = getDirectorySize(dirName) # get total directory size to calculate needed processing time. + TIME_OUT2 = int(TimePerGiB) * dirSize # Couchpotato needs to complete all moving and renaming before returning the status. + TIME_OUT2 += 60 # Add an extra minute for over-head/processing/metadata. + socket.setdefaulttimeout(int(TIME_OUT2)) #initialize socket timeout. We may now be able to remove the delays from the wait_for section below? If true, this should exit on first loop. + + url = baseURL + command + + Logger.info("Waiting for %s seconds to allow CPS to process newly extracted files", str(delay)) + + time.sleep(delay) + + Logger.debug("Opening URL: %s", url) + + try: + r = requests.get(url) + except requests.ConnectionError: + Logger.exception("Unable to open URL") + return 1 # failure + + result = json.load(r.content) + Logger.info("CouchPotatoServer returned %s", result) + if result['success']: + Logger.info("%s scan started on CouchPotatoServer for %s", method, nzbName) + else: + Logger.error("%s scan has NOT started on CouchPotatoServer for %s. Exiting", method, nzbName) + return 1 # failure + + else: + Logger.info("Download of %s has failed.", nzbName) + Logger.info("Trying to re-cue the next highest ranked release") + + if not movie_id: + Logger.warning("Cound not find a movie in the database for release %s", nzbName) + Logger.warning("Please manually ignore this release and refresh the wanted movie") + Logger.error("Exiting autoProcessMovie script") + return 1 # failure + + url = baseURL + "movie.searcher.try_next/?media_id=" + movie_id + + Logger.debug("Opening URL: %s", url) + + try: + r = requests.get(url) + except requests.ConnectionError: + Logger.exception("Unable to open URL") + return 1 # failure + + Logger.info("%s", r.content) + Logger.info("Movie %s set to try the next best release on CouchPotatoServer", movie_id) + if delete_failed and not dirName in ['sys.argv[0]','/','']: + Logger.info("Deleting failed files and folder %s", dirName) + try: + shutil.rmtree(dirName) + except: + Logger.exception("Unable to delete folder %s", dirName) + return 0 # success + + if clientAgent == "manual": + return 0 # success + if not download_id: + return 1 # just to be sure TorrentToMedia doesn't start deleting files as we havent verified changed status. + + # we will now check to see if CPS has finished renaming before returning to TorrentToMedia and unpausing. + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. + + release_status = None + start = datetime.datetime.now() # set time for timeout + pause_for = int(wait_for) * 10 # keep this so we only ever have 6 complete loops. This may not be necessary now? + while (datetime.datetime.now() - start) < datetime.timedelta(minutes=wait_for): # only wait 2 (default) minutes, then return. + movie_status, release_status = self.get_status(baseURL, movie_id, download_id) # get the current status fo this movie. + if movie_status and initial_status and movie_status != initial_status: # Something has changed. CPS must have processed this movie. + Logger.info("SUCCESS: This movie is now marked as status %s in CouchPotatoServer", movie_status) + return 0 # success + datetime.time.sleep(pause_for) # Just stop this looping infinitely and hogging resources for 2 minutes ;) + else: + if release_status and initial_release_status and release_status != initial_release_status: # Something has changed. CPS must have processed this movie. + Logger.info("SUCCESS: This release is now marked as status %s in CouchPotatoServer", release_status) + return 0 # success + else: # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resule seeding now. + Logger.warning("The movie does not appear to have changed status after %s minutes. Please check CouchPotato Logs", wait_for) + return 1 # failure diff --git a/nzbtomedia/autoProcess/autoProcessMusic.py b/nzbtomedia/autoProcess/autoProcessMusic.py new file mode 100644 index 00000000..e002dad3 --- /dev/null +++ b/nzbtomedia/autoProcess/autoProcessMusic.py @@ -0,0 +1,100 @@ +import datetime +import logging +import socket +import requests +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import convert_to_ascii, getDirectorySize + +Logger = logging.getLogger() + +class autoProcessMusic: + def process(self, dirName, nzbName=None, status=0, clientAgent="manual", inputCategory=None): + if dirName is None: + Logger.error("No directory was given!") + return 1 # failure + + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. + + Logger.info("Loading config from %s", config.CONFIG_FILE) + + status = int(status) + + section = "HeadPhones" + if inputCategory != None and config().has_section(inputCategory): + section = inputCategory + + host = config().get(section, "host") + port = config().get(section, "port") + apikey = config().get(section, "apikey") + delay = float(config().get(section, "delay")) + + try: + ssl = int(config().get(section, "ssl")) + except (config.NoOptionError, ValueError): + ssl = 0 + try: + web_root = config().get(section, "web_root") + except config.NoOptionError: + web_root = "" + try: + TimePerGiB = int(config().get(section, "TimePerGiB")) + except (config.NoOptionError, ValueError): + TimePerGiB = 60 # note, if using Network to transfer on 100Mbit LAN, expect ~ 600 MB/minute. + if ssl: + protocol = "https://" + else: + protocol = "http://" + # don't delay when we are calling this script manually. + if clientAgent == "manual": + delay = 0 + + nzbName, dirName = convert_to_ascii(nzbName, dirName) + + dirSize = getDirectorySize(dirName) # get total directory size to calculate needed processing time. + TIME_OUT = int(TimePerGiB) * dirSize # HeadPhones needs to complete all moving/transcoding and renaming before returning the status. + TIME_OUT += 60 # Add an extra minute for over-head/processing/metadata. + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. + + baseURL = protocol + host + ":" + port + web_root + "/api?apikey=" + apikey + "&cmd=" + + if status == 0: + command = "forceProcess" + + url = baseURL + command + + Logger.info("Waiting for %s seconds to allow HeadPhones to process newly extracted files", str(delay)) + + datetime.time.sleep(delay) + + Logger.debug("Opening URL: %s", url) + + try: + r = requests.get(url) + except requests.ConnectionError: + Logger.exception("Unable to open URL") + return 1 # failure + + Logger.info("HeadPhones returned %s", r.content) + if r.content[0] == "OK": + Logger.info("%s started on HeadPhones for %s", command, nzbName) + else: + Logger.error("%s has NOT started on HeadPhones for %s. Exiting", command, nzbName) + return 1 # failure + + else: + Logger.info("The download failed. Nothing to process") + return 0 # Success (as far as this script is concerned) + + if nzbName == "Manual Run": + return 0 # success + + # we will now wait 1 minutes for this album to be processed before returning to TorrentToMedia and unpausing. + ## Hopefully we can use a "getHistory" check in here to confirm processing complete... + start = datetime.datetime.now() # set time for timeout + while (datetime.datetime.now() - start) < datetime.timedelta(minutes=1): # only wait 2 minutes, then return to TorrentToMedia + datetime.time.sleep(20) # Just stop this looping infinitely and hogging resources for 2 minutes ;) + else: # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resume seeding now. + Logger.info("This album should have completed processing. Please check HeadPhones Logs") + # Logger.warning("The album does not appear to have changed status after 2 minutes. Please check HeadPhones Logs") + # return 1 # failure + return 0 # success for now. diff --git a/nzbtomedia/autoProcess/autoProcessTV.py b/nzbtomedia/autoProcess/autoProcessTV.py new file mode 100644 index 00000000..d10f9a86 --- /dev/null +++ b/nzbtomedia/autoProcess/autoProcessTV.py @@ -0,0 +1,188 @@ +import copy +import logging +import os +import socket +import urllib +import requests +import time +from nzbtomedia.Transcoder import Transcoder +from nzbtomedia.nzbToMediaAutoFork import autoFork +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaSceneExceptions import process_all_exceptions +from nzbtomedia.nzbToMediaUtil import convert_to_ascii, is_sample, flatten, getDirectorySize, delete + +Logger = logging.getLogger() + +class autoProcessTV: + def processEpisode(self, dirName, nzbName=None, failed=False, clientAgent = "manual", inputCategory=None): + if dirName is None: + Logger.error("No directory was given!") + return 1 # failure + + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. + + Logger.info("Loading config from %s", config.CONFIG_FILE) + + status = int(failed) + + section = "SickBeard" + if inputCategory != None and config().has_section(inputCategory): + section = inputCategory + + host = config().get(section, "host") + port = config().get(section, "port") + username = config().get(section, "username") + password = config().get(section, "password") + + try: + ssl = int(config().get(section, "ssl")) + except (config.NoOptionError, ValueError): + ssl = 0 + try: + web_root = config().get(section, "web_root") + except config.NoOptionError: + web_root = "" + try: + watch_dir = config().get(section, "watch_dir") + except config.NoOptionError: + watch_dir = "" + try: + transcode = int(config().get("Transcoder", "transcode")) + except (config.NoOptionError, ValueError): + transcode = 0 + try: + delete_failed = int(config().get(section, "delete_failed")) + except (config.NoOptionError, ValueError): + delete_failed = 0 + try: + delay = float(config().get(section, "delay")) + except (config.NoOptionError, ValueError): + delay = 0 + try: + TimePerGiB = int(config().get(section, "TimePerGiB")) + except (config.NoOptionError, ValueError): + TimePerGiB = 60 # note, if using Network to transfer on 100Mbit LAN, expect ~ 600 MB/minute. + try: + SampleIDs = (config().get("Extensions", "SampleIDs")).split(',') + except (config.NoOptionError, ValueError): + SampleIDs = ['sample','-s.'] + try: + nzbExtractionBy = config().get(section, "nzbExtractionBy") + except (config.NoOptionError, ValueError): + nzbExtractionBy = "Downloader" + try: + process_method = config().get(section, "process_method") + except config.NoOptionError: + process_method = None + + mediaContainer = (config().get("Extensions", "mediaExtensions")).split(',') + minSampleSize = int(config().get("Extensions", "minSampleSize")) + + if not os.path.isdir(dirName) and os.path.isfile(dirName): # If the input directory is a file, assume single file download and split dir/name. + dirName = os.path.split(os.path.normpath(dirName))[0] + + SpecificPath = os.path.join(dirName, str(nzbName)) + cleanName = os.path.splitext(SpecificPath) + if cleanName[1] == ".nzb": + SpecificPath = cleanName[0] + if os.path.isdir(SpecificPath): + dirName = SpecificPath + + # auto-detect fork type + fork, params = autoFork(section) + + if fork not in config.SICKBEARD_TORRENT or (clientAgent in ['nzbget','sabnzbd'] and nzbExtractionBy != "Destination"): + if nzbName: + process_all_exceptions(nzbName.lower(), dirName) + nzbName, dirName = convert_to_ascii(nzbName, dirName) + + # Now check if tv files exist in destination. Eventually extraction may be done here if nzbExtractionBy == TorrentToMedia + video = int(0) + for dirpath, dirnames, filenames in os.walk(dirName): + for file in filenames: + filePath = os.path.join(dirpath, file) + fileExtension = os.path.splitext(file)[1] + if fileExtension in mediaContainer: # If the file is a video file + if is_sample(filePath, nzbName, minSampleSize, SampleIDs): + Logger.debug("Removing sample file: %s", filePath) + os.unlink(filePath) # remove samples + else: + video = video + 1 + if video > 0: # Check that a video exists. if not, assume failed. + flatten(dirName) # to make sure SickBeard can find the video (not in sub-folder) + elif clientAgent == "manual": + Logger.warning("No media files found in directory %s to manually process.", dirName) + return 0 # Success (as far as this script is concerned) + else: + Logger.warning("No media files found in directory %s. Processing this as a failed download", dirName) + status = int(1) + failed = True + + dirSize = getDirectorySize(dirName) # get total directory size to calculate needed processing time. + TIME_OUT = int(TimePerGiB) * dirSize # SickBeard needs to complete all moving and renaming before returning the log sequence via url. + TIME_OUT += 60 # Add an extra minute for over-head/processing/metadata. + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. + + # configure SB params to pass + params['quiet'] = 1 + if nzbName is not None: + params['nzbName'] = nzbName + + for param in copy.copy(params): + if param == "failed": + params[param] = failed + + if param in ["dirName", "dir"]: + params[param] = dirName + + if param == "process_method": + if process_method: + params[param] = process_method + else: + del params[param] + + # delete any unused params so we don't pass them to SB by mistake + [params.pop(k) for k,v in params.items() if v is None] + + if status == 0: + Logger.info("The download succeeded. Sending process request to SickBeard's %s branch", fork) + elif fork in config.SICKBEARD_FAILED: + Logger.info("The download failed. Sending 'failed' process request to SickBeard's %s branch", fork) + else: + Logger.info("The download failed. SickBeard's %s branch does not handle failed downloads. Nothing to process", fork) + if delete_failed and os.path.isdir(dirName) and not dirName in ['sys.argv[0]','/','']: + Logger.info("Deleting directory: %s", dirName) + delete(dirName) + return 0 # Success (as far as this script is concerned) + + if status == 0 and transcode == 1: # only transcode successful downlaods + result = Transcoder().Transcode_directory(dirName) + if result == 0: + Logger.debug("Transcoding succeeded for files in %s", dirName) + else: + Logger.warning("Transcoding failed for files in %s", dirName) + + if ssl: + protocol = "https://" + else: + protocol = "http://" + + url = protocol + host + ":" + port + web_root + "/home/postprocess/processEpisode?" + urllib.urlencode(params) + + if clientAgent == "manual":delay = 0 + Logger.info("Waiting for %s seconds to allow SB to process newly extracted files", str(delay)) + + time.sleep(delay) + + Logger.debug("Opening URL: %s", url) + + try: + r = requests.get(url, auth=(username, password)) + except requests.ConnectionError: + Logger.exception("Unable to open URL") + return 1 # failure + + Logger.info("%s", r.content) + if status != 0 and delete_failed and not dirName in ['sys.argv[0]','/','']: + delete(dirName) + return 0 # Success diff --git a/linktastic/__init__.py b/nzbtomedia/extractor/__init__.py similarity index 100% rename from linktastic/__init__.py rename to nzbtomedia/extractor/__init__.py diff --git a/extractor/bin/chp.exe b/nzbtomedia/extractor/bin/chp.exe similarity index 100% rename from extractor/bin/chp.exe rename to nzbtomedia/extractor/bin/chp.exe diff --git a/extractor/bin/x64/7z.dll b/nzbtomedia/extractor/bin/x64/7z.dll similarity index 100% rename from extractor/bin/x64/7z.dll rename to nzbtomedia/extractor/bin/x64/7z.dll diff --git a/extractor/bin/x64/7z.exe b/nzbtomedia/extractor/bin/x64/7z.exe similarity index 100% rename from extractor/bin/x64/7z.exe rename to nzbtomedia/extractor/bin/x64/7z.exe diff --git a/extractor/bin/x64/license.txt b/nzbtomedia/extractor/bin/x64/license.txt similarity index 100% rename from extractor/bin/x64/license.txt rename to nzbtomedia/extractor/bin/x64/license.txt diff --git a/extractor/bin/x86/7z.dll b/nzbtomedia/extractor/bin/x86/7z.dll similarity index 100% rename from extractor/bin/x86/7z.dll rename to nzbtomedia/extractor/bin/x86/7z.dll diff --git a/extractor/bin/x86/7z.exe b/nzbtomedia/extractor/bin/x86/7z.exe similarity index 100% rename from extractor/bin/x86/7z.exe rename to nzbtomedia/extractor/bin/x86/7z.exe diff --git a/extractor/bin/x86/license.txt b/nzbtomedia/extractor/bin/x86/license.txt similarity index 100% rename from extractor/bin/x86/license.txt rename to nzbtomedia/extractor/bin/x86/license.txt diff --git a/extractor/extractor.py b/nzbtomedia/extractor/extractor.py similarity index 97% rename from extractor/extractor.py rename to nzbtomedia/extractor/extractor.py index 8402cab8..d621abcc 100644 --- a/extractor/extractor.py +++ b/nzbtomedia/extractor/extractor.py @@ -1,9 +1,9 @@ import sys import logging - -from nzbToMediaConfig import * from subprocess import call, Popen -from autoProcess.nzbToMediaUtil import create_destination + +from nzbtomedia.nzbToMediaConfig import * +from nzbtomedia.nzbToMediaUtil import create_destination Logger = logging.getLogger() @@ -111,7 +111,7 @@ def extract(filePath, outputDestination): # Create outputDestination folder create_destination(outputDestination) - Logger.info("MAIN: Loading config from %s", CONFIG_FILE) + Logger.info("MAIN: Loading config from %s", config.CONFIG_FILE) passwordsfile = config().get("passwords", "PassWordFile") if passwordsfile != "" and os.path.isfile(os.path.normpath(passwordsfile)): diff --git a/linktastic/.gitignore b/nzbtomedia/linktastic/.gitignore similarity index 100% rename from linktastic/.gitignore rename to nzbtomedia/linktastic/.gitignore diff --git a/linktastic/README.txt b/nzbtomedia/linktastic/README.txt similarity index 100% rename from linktastic/README.txt rename to nzbtomedia/linktastic/README.txt diff --git a/utorrent/__init__.py b/nzbtomedia/linktastic/__init__.py similarity index 100% rename from utorrent/__init__.py rename to nzbtomedia/linktastic/__init__.py diff --git a/linktastic/linktastic.py b/nzbtomedia/linktastic/linktastic.py similarity index 100% rename from linktastic/linktastic.py rename to nzbtomedia/linktastic/linktastic.py diff --git a/linktastic/setup.py b/nzbtomedia/linktastic/setup.py similarity index 100% rename from linktastic/setup.py rename to nzbtomedia/linktastic/setup.py diff --git a/nzbtomedia/migratecfg.py b/nzbtomedia/migratecfg.py new file mode 100644 index 00000000..2f1daf06 --- /dev/null +++ b/nzbtomedia/migratecfg.py @@ -0,0 +1,244 @@ +import os +import shutil +from nzbtomedia.nzbToMediaConfig import config + +class migratecfg: + def migrate(self): + categories = [] + + # check for autoProcessMedia.cfg and autoProcessMedia.cfg.sample and if they don't exist return and fail + if not config() and not config(config.SAMPLE_CONFIG_FILE): + return False + + # check for autoProcessMedia.cfg and create if it does not exist + if not config(config.CONFIG_FILE): + shutil.copyfile(config.SAMPLE_CONFIG_FILE, config.CONFIG_FILE) + configold = config(config.CONFIG_FILE) + + # check for autoProcessMedia.cfg.sample and create if it does not exist + if not config(config.SAMPLE_CONFIG_FILE): + shutil.copyfile(config.CONFIG_FILE, config.SAMPLE_CONFIG_FILE) + confignew = config(config.SAMPLE_CONFIG_FILE) + + section = "CouchPotato" + for option, value in configold.items(section) or config(config.MOVIE_CONFIG_FILE).items(section): + if option == "category": # change this old format + option = "cpsCategory" + if option == "outputDirectory": # move this to new location format + value = os.path.split(os.path.normpath(value))[0] + confignew.set("Torrent", option, value) + continue + if option in ["username", "password" ]: # these are no-longer needed. + continue + if option == "cpsCategory": + categories.extend(value.split(',')) + confignew.set(section, option, value) + + section = "SickBeard" + for option, value in configold.items(section) or config(config.TV_CONFIG_FILE).items(section): + if option == "category": # change this old format + option = "sbCategory" + if option == "wait_for": # remove old format + continue + if option == "failed_fork": # change this old format + option = "fork" + if value not in ["default", "failed", "failed-torrent", "auto"]: + value = "auto" + if option == "fork" and value not in ["default", "failed", "failed-torrent", "auto"]: + value = "auto" + if option == "outputDirectory": # move this to new location format + value = os.path.split(os.path.normpath(value))[0] + confignew.set("Torrent", option, value) + continue + if option == "sbCategory": + categories.extend(value.split(',')) + confignew.set(section, option, value) + + for section in configold.sections(): + try: + for option, value in configold.items(section): + if section == "HeadPhones": + if option in ["username", "password" ]: + continue + if option == "hpCategory": + categories.extend(value.split(',')) + confignew.set(section, option, value) + + if section == "Mylar": + if option in "mlCategory": + categories.extend(value.split(',')) + confignew.set(section, option, value) + + if section == "Gamez": + if option in ["username", "password" ]: # these are no-longer needed. + continue + if option == "gzCategory": + categories.extend(value.split(',')) + confignew.set(section, option, value) + + if section == "Torrent": + if option in ["compressedExtensions", "mediaExtensions", "metaExtensions", "minSampleSize"]: + section = "Extensions" # these were moved + if option == "useLink": # Sym links supported now as well. + if isinstance(value, int): + num_value = int(value) + if num_value == 1: + value = "hard" + else: + value = "no" + confignew.set(section, option, value) + + if section == "Extensions": + confignew.set(section, option, value) + + if section == "Transcoder": + confignew.set(section, option, value) + + if section == "WakeOnLan": + confignew.set(section, option, value) + + if section == "UserScript": + confignew.set(section, option, value) + + if section == "ASCII": + confignew.set(section, option, value) + + if section == "passwords": + confignew.set(section, option, value) + + if section == "loggers": + confignew.set(section, option, value) + + if section == "handlers": + confignew.set(section, option, value) + + if section == "formatters": + confignew.set(section, option, value) + + if section == "logger_root": + confignew.set(section, option, value) + + if section == "handler_console": + confignew.set(section, option, value) + + if section == "formatter_generic": + confignew.set(section, option, value) + except config.InterpolationMissingOptionError: + pass + + for section in categories: + try: + if configold.items(section): + confignew.add_section(section) + + for option, value in configold.items(section): + confignew.set(section, option, value) + except config.NoSectionError: + continue + + # create a backup of our old config + if os.path.isfile(config.CONFIG_FILE): + cfgbak_name = config.CONFIG_FILE + ".old" + if os.path.isfile(cfgbak_name): # remove older backups + os.unlink(cfgbak_name) + os.rename(config.CONFIG_FILE, cfgbak_name) + + # writing our configuration file to 'autoProcessMedia.cfg' + with open(config.CONFIG_FILE, 'wb') as configFile: + confignew.write(configFile) + + return True + + def addnzbget(self): + confignew = config() + section = "CouchPotato" + envKeys = ['CATEGORY', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'DELAY', 'METHOD', 'DELETE_FAILED', 'REMOTECPS', 'WAIT_FOR', 'TIMEPERGIB'] + cfgKeys = ['cpsCategory', 'apikey', 'host', 'port', 'ssl', 'web_root', 'delay', 'method', 'delete_failed', 'remoteCPS', 'wait_for', 'TimePerGiB'] + for index in range(len(envKeys)): + key = 'NZBPO_CPS' + envKeys[index] + if os.environ.has_key(key): + option = cfgKeys[index] + value = os.environ[key] + confignew.set(section, option, value) + + + section = "SickBeard" + envKeys = ['CATEGORY', 'HOST', 'PORT', 'USERNAME', 'PASSWORD', 'SSL', 'WEB_ROOT', 'WATCH_DIR', 'FORK', 'DELETE_FAILED', 'DELAY', 'TIMEPERGIB', 'PROCESS_METHOD'] + cfgKeys = ['sbCategory', 'host', 'port', 'username', 'password', 'ssl', 'web_root', 'watch_dir', 'fork', 'delete_failed', 'delay', 'TimePerGiB', 'process_method'] + for index in range(len(envKeys)): + key = 'NZBPO_SB' + envKeys[index] + if os.environ.has_key(key): + option = cfgKeys[index] + value = os.environ[key] + confignew.set(section, option, value) + + section = "HeadPhones" + envKeys = ['CATEGORY', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'DELAY', 'TIMEPERGIB'] + cfgKeys = ['hpCategory', 'apikey', 'host', 'port', 'ssl', 'web_root', 'delay', 'TimePerGiB'] + for index in range(len(envKeys)): + key = 'NZBPO_HP' + envKeys[index] + if os.environ.has_key(key): + option = cfgKeys[index] + value = os.environ[key] + confignew.set(section, option, value) + + section = "Mylar" + envKeys = ['CATEGORY', 'HOST', 'PORT', 'USERNAME', 'PASSWORD', 'SSL', 'WEB_ROOT'] + cfgKeys = ['mlCategory', 'host', 'port', 'username', 'password', 'ssl', 'web_root'] + for index in range(len(envKeys)): + key = 'NZBPO_MY' + envKeys[index] + if os.environ.has_key(key): + option = cfgKeys[index] + value = os.environ[key] + confignew.set(section, option, value) + + section = "Gamez" + envKeys = ['CATEGORY', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT'] + cfgKeys = ['gzCategory', 'apikey', 'host', 'port', 'ssl', 'web_root'] + for index in range(len(envKeys)): + key = 'NZBPO_GZ' + envKeys[index] + if os.environ.has_key(key): + option = cfgKeys[index] + value = os.environ[key] + confignew.set(section, option, value) + + section = "Extensions" + envKeys = ['COMPRESSEDEXTENSIONS', 'MEDIAEXTENSIONS', 'METAEXTENSIONS'] + cfgKeys = ['compressedExtensions', 'mediaExtensions', 'metaExtensions'] + for index in range(len(envKeys)): + key = 'NZBPO_' + envKeys[index] + if os.environ.has_key(key): + option = cfgKeys[index] + value = os.environ[key] + confignew.set(section, option, value) + + section = "Transcoder" + envKeys = ['TRANSCODE', 'DUPLICATE', 'IGNOREEXTENSIONS', 'OUTPUTVIDEOEXTENSION', 'OUTPUTVIDEOCODEC', 'OUTPUTVIDEOPRESET', 'OUTPUTVIDEOFRAMERATE', 'OUTPUTVIDEOBITRATE', 'OUTPUTAUDIOCODEC', 'OUTPUTAUDIOBITRATE', 'OUTPUTSUBTITLECODEC'] + cfgKeys = ['transcode', 'duplicate', 'ignoreExtensions', 'outputVideoExtension', 'outputVideoCodec', 'outputVideoPreset', 'outputVideoFramerate', 'outputVideoBitrate', 'outputAudioCodec', 'outputAudioBitrate', 'outputSubtitleCodec'] + for index in range(len(envKeys)): + key = 'NZBPO_' + envKeys[index] + if os.environ.has_key(key): + option = cfgKeys[index] + value = os.environ[key] + confignew.set(section, option, value) + + section = "WakeOnLan" + envKeys = ['WAKE', 'HOST', 'PORT', 'MAC'] + cfgKeys = ['wake', 'host', 'port', 'mac'] + for index in range(len(envKeys)): + key = 'NZBPO_WOL' + envKeys[index] + if os.environ.has_key(key): + option = cfgKeys[index] + value = os.environ[key] + confignew.set(section, option, value) + + # create a backup of our old config + if os.path.isfile(config.CONFIG_FILE): + cfgbak_name = config.CONFIG_FILE + ".old" + if os.path.isfile(cfgbak_name): # remove older backups + os.unlink(cfgbak_name) + os.rename(config.CONFIG_FILE, cfgbak_name) + + # writing our configuration file to 'autoProcessMedia.cfg' + with open(config.CONFIG_FILE, 'wb') as configFile: + confignew.write(configFile) \ No newline at end of file diff --git a/autoProcess/autoSickBeardFork.py b/nzbtomedia/nzbToMediaAutoFork.py similarity index 56% rename from autoProcess/autoSickBeardFork.py rename to nzbtomedia/nzbToMediaAutoFork.py index c1aef3c9..5d5e621d 100644 --- a/autoProcess/autoSickBeardFork.py +++ b/nzbtomedia/nzbToMediaAutoFork.py @@ -1,33 +1,13 @@ -import urllib import logging +import urllib +import requests -from nzbToMediaConfig import * -from autoProcess.nzbToMediaEnv import * +from nzbToMediaConfig import config -Logger = logging.getLogger() - -class AuthURLOpener(urllib.FancyURLopener): - def __init__(self, user, pw): - self.username = user - self.password = pw - self.numTries = 0 - urllib.FancyURLopener.__init__(self) - - def prompt_user_passwd(self, host, realm): - if self.numTries == 0: - self.numTries = 1 - return (self.username, self.password) - else: - return ('', '') - - def openit(self, url): - self.numTries = 0 - return urllib.FancyURLopener.open(self, url) - -def autoFork(): +def autoFork(section): + Logger = logging.getLogger() # config settings - section = "SickBeard" host = config().get(section, "host") port = config().get(section, "port") username = config().get(section, "username") @@ -44,12 +24,10 @@ def autoFork(): web_root = "" try: - fork = forks.items()[forks.keys().index(config().get(section, "fork"))] + fork = config.FORKS.items()[config.FORKS.keys().index(config().get(section, "fork"))] except: fork = "auto" - myOpener = AuthURLOpener(username, password) - if ssl: protocol = "https://" else: @@ -58,17 +36,17 @@ def autoFork(): detected = False if fork == "auto": Logger.info("Attempting to auto-detect SickBeard fork") - for fork in sorted(forks.iteritems()): + for fork in sorted(config.FORKS.iteritems()): url = protocol + host + ":" + port + web_root + "/home/postprocess/processEpisode?" + urllib.urlencode(fork[1]) # attempting to auto-detect fork try: - urlObj = myOpener.openit(url) - except IOError, e: + r = requests.get(url, auth=(username, password)) + except requests.ConnectionError: Logger.info("Could not connect to SickBeard to perform auto-fork detection!") break - if urlObj.getcode() == 200: + if r.ok: detected = True break @@ -76,7 +54,7 @@ def autoFork(): Logger.info("SickBeard fork auto-detection successful ...") else: Logger.info("SickBeard fork auto-detection failed") - fork = forks.items()[forks.keys().index(fork_default)] + fork = config.FORKS.items()[config.FORKS.keys().index(config.FORK_DEFAULT)] Logger.info("SickBeard fork set to %s", fork[0]) return fork[0], fork[1] \ No newline at end of file diff --git a/nzbtomedia/nzbToMediaConfig.py b/nzbtomedia/nzbToMediaConfig.py new file mode 100644 index 00000000..81826df7 --- /dev/null +++ b/nzbtomedia/nzbToMediaConfig.py @@ -0,0 +1,61 @@ +import os +import ConfigParser + +class config(object): + # constants for nzbtomedia + NZBTOMEDIA_VERSION = 'V9.3' + NZBTOMEDIA_TIMEOUT = 60 + + # Constants pertinant to SabNzb + SABNZB_NO_OF_ARGUMENTS = 8 + SABNZB_0717_NO_OF_ARGUMENTS = 9 + + # Constants pertaining to SickBeard Branches: + FORKS = {} + FORK_DEFAULT = "default" + FORK_FAILED = "failed" + FORK_FAILED_TORRENT = "failed-torrent" + FORKS[FORK_DEFAULT] = {"dir": None, "method": None} + FORKS[FORK_FAILED] = {"dirName": None, "failed": None} + FORKS[FORK_FAILED_TORRENT] = {"dir": None, "failed": None, "process_method": None} + SICKBEARD_FAILED = [FORK_FAILED, FORK_FAILED_TORRENT] + SICKBEARD_TORRENT = [FORK_FAILED_TORRENT] + + # NZBGet Exit Codes + NZBGET_POSTPROCESS_PARCHECK = 92 + NZBGET_POSTPROCESS_SUCCESS = 93 + NZBGET_POSTPROCESS_ERROR = 94 + NZBGET_POSTPROCESS_NONE = 95 + + # config files + PROGRAM_DIR = os.path.dirname(os.path.normpath(os.path.abspath(__file__))) + CONFIG_FILE = os.path.join(PROGRAM_DIR, "../autoProcessMedia.cfg") + SAMPLE_CONFIG_FILE = os.path.join(PROGRAM_DIR, "../autoProcessMedia.cfg.sample") + MOVIE_CONFIG_FILE = os.path.join(PROGRAM_DIR, "autoProcessMovie.cfg") + TV_CONFIG_FILE = os.path.join(PROGRAM_DIR, "autoProcessTv.cfg") + LOG_FILE = os.path.join(PROGRAM_DIR, "../postprocess.log") + + # config error handling classes + Error = ConfigParser.Error + NoSectionError = ConfigParser.NoSectionError + NoOptionError = ConfigParser.NoOptionError + DuplicateSectionError = ConfigParser.DuplicateSectionError + InterpolationError = ConfigParser.InterpolationError + InterpolationMissingOptionError = ConfigParser.InterpolationMissingOptionError + InterpolationSyntaxError = ConfigParser.InterpolationSyntaxError + InterpolationDepthError = ConfigParser.InterpolationDepthError + ParsingError = ConfigParser.ParsingError + MissingSectionHeaderError = ConfigParser.MissingSectionHeaderError + + def __new__(cls, *file): + if not file: + file = cls.CONFIG_FILE + return cls.loadConfig(file) + + @staticmethod + def loadConfig(file): + # load config + config = ConfigParser.ConfigParser() + config.optionxform = str + if config.read(file): + return config \ No newline at end of file diff --git a/autoProcess/nzbToMediaSceneExceptions.py b/nzbtomedia/nzbToMediaSceneExceptions.py similarity index 91% rename from autoProcess/nzbToMediaSceneExceptions.py rename to nzbtomedia/nzbToMediaSceneExceptions.py index b05e2b93..f899210e 100644 --- a/autoProcess/nzbToMediaSceneExceptions.py +++ b/nzbtomedia/nzbToMediaSceneExceptions.py @@ -1,26 +1,19 @@ -# System imports import os import logging - -# Custom imports -from nzbToMediaUtil import iterate_media_files - +from nzbtomedia.nzbToMediaUtil import iterate_media_files Logger = logging.getLogger() - def process_all_exceptions(name, dirname): for group, exception in __customgroups__.items(): if not (group in name or group in dirname): continue process_exception(exception, name, dirname) - def process_exception(exception, name, dirname): for parentDir, filename in iterate_media_files(dirname): exception(filename, parentDir) - def process_qoq(filename, dirname): Logger.debug("Reversing the file name for a QoQ release %s", filename) head, fileExtension = os.path.splitext(os.path.basename(filename)) diff --git a/autoProcess/nzbToMediaUtil.py b/nzbtomedia/nzbToMediaUtil.py similarity index 97% rename from autoProcess/nzbToMediaUtil.py rename to nzbtomedia/nzbToMediaUtil.py index e849e3a8..95a7110e 100644 --- a/autoProcess/nzbToMediaUtil.py +++ b/nzbtomedia/nzbToMediaUtil.py @@ -1,15 +1,17 @@ +import os +import re +import socket +import struct +import shutil +import sys +import time +import requests import logging import logging.config -import re -import sys -import shutil -import struct -import socket -import time - -import linktastic.linktastic as linktastic -from nzbToMediaConfig import * +import logging.handlers +from nzbtomedia.linktastic import linktastic +from nzbtomedia.nzbToMediaConfig import config Logger = logging.getLogger() @@ -30,8 +32,8 @@ def safeName(name): def nzbtomedia_configure_logging(logfile=None): if not logfile: - logfile = LOG_FILE - logging.config.fileConfig(CONFIG_FILE) + logfile = config.LOG_FILE + logging.config.fileConfig(config.CONFIG_FILE) fileHandler = logging.handlers.RotatingFileHandler(logfile, mode='a', maxBytes=1048576, backupCount=1, encoding='utf-8', delay=True) fileHandler.formatter = logging.Formatter('%(asctime)s|%(levelname)-7.7s %(message)s', '%H:%M:%S') fileHandler.level = logging.DEBUG @@ -315,7 +317,6 @@ def WakeOnLan(ethernet_address): ss.sendto(msg, ('', 9)) ss.close() - #Test Connection function def TestCon(host, port): try: @@ -324,7 +325,6 @@ def TestCon(host, port): except: return "Down" - def WakeUp(): if not config(): Logger.error("You need an autoProcessMedia.config() file - did you rename and edit the .sample?") @@ -333,7 +333,7 @@ def WakeUp(): wake = int(config().get("WakeOnLan", "wake")) if wake == 0: # just return if we don't need to wake anything. return - Logger.info("Loading WakeOnLan config from %s", CONFIG_FILE) + Logger.info("Loading WakeOnLan config from %s", config.CONFIG_FILE) config().get("WakeOnLan", "host") host = config().get("WakeOnLan", "host") port = int(config().get("WakeOnLan", "port")) @@ -440,21 +440,16 @@ def parse_transmission(args): inputID = os.getenv('TR_TORRENT_ID') return inputDirectory, inputName, inputCategory, inputHash, inputID - -__ARG_PARSERS__ = { +def parse_args(clientAgent): + clients = { 'other': parse_other, 'rtorrent': parse_rtorrent, 'utorrent': parse_utorrent, 'deluge': parse_deluge, 'transmission': parse_transmission, -} + } - -def parse_args(clientAgent): - parseFunc = __ARG_PARSERS__.get(clientAgent, None) - if not parseFunc: - raise RuntimeError("Could not find client-agent") - return parseFunc(sys.argv) + return clients[clientAgent](sys.argv) def get_dirnames(section, category): try: @@ -467,7 +462,7 @@ def get_dirnames(section, category): outputDirectory = "" # set dirName - dirNames = None + dirNames = [] if watch_dir != "": if os.path.exists(watch_dir): dirNames = [os.path.join(watch_dir, o) for o in os.listdir(watch_dir) if @@ -477,4 +472,16 @@ def get_dirnames(section, category): dirNames = [os.path.join(outputDirectory, o) for o in os.listdir(outputDirectory) if os.path.isdir(os.path.join(outputDirectory, o))] - return dirNames \ No newline at end of file + return dirNames + +def delete(dirName): + Logger.info("Deleting failed files and folder %s", dirName) + try: + shutil.rmtree(dirName, True) + except: + Logger.exception("Unable to delete folder %s", dirName) + +def getURL(url, username, password): + r = requests.get(url, auth=(username, password)) + return r + diff --git a/synchronousdeluge/__init__.py b/nzbtomedia/synchronousdeluge/__init__.py similarity index 81% rename from synchronousdeluge/__init__.py rename to nzbtomedia/synchronousdeluge/__init__.py index bf5b20fe..f711e847 100644 --- a/synchronousdeluge/__init__.py +++ b/nzbtomedia/synchronousdeluge/__init__.py @@ -19,6 +19,5 @@ __title__ = "synchronous-deluge" __version__ = "0.1" __author__ = "Christian Dale" -from synchronousdeluge.client import DelugeClient -from synchronousdeluge.exceptions import DelugeRPCError +from nzbtomedia.synchronousdeluge.exceptions import DelugeRPCError diff --git a/synchronousdeluge/client.py b/nzbtomedia/synchronousdeluge/client.py similarity index 96% rename from synchronousdeluge/client.py rename to nzbtomedia/synchronousdeluge/client.py index 394b6767..f35663e4 100644 --- a/synchronousdeluge/client.py +++ b/nzbtomedia/synchronousdeluge/client.py @@ -1,11 +1,11 @@ import os import platform + from collections import defaultdict from itertools import imap - -from synchronousdeluge.exceptions import DelugeRPCError -from synchronousdeluge.protocol import DelugeRPCRequest, DelugeRPCResponse -from synchronousdeluge.transfer import DelugeTransfer +from exceptions import DelugeRPCError +from protocol import DelugeRPCRequest, DelugeRPCResponse +from transfer import DelugeTransfer __all__ = ["DelugeClient"] diff --git a/synchronousdeluge/exceptions.py b/nzbtomedia/synchronousdeluge/exceptions.py similarity index 100% rename from synchronousdeluge/exceptions.py rename to nzbtomedia/synchronousdeluge/exceptions.py diff --git a/synchronousdeluge/protocol.py b/nzbtomedia/synchronousdeluge/protocol.py similarity index 100% rename from synchronousdeluge/protocol.py rename to nzbtomedia/synchronousdeluge/protocol.py diff --git a/synchronousdeluge/rencode.py b/nzbtomedia/synchronousdeluge/rencode.py similarity index 100% rename from synchronousdeluge/rencode.py rename to nzbtomedia/synchronousdeluge/rencode.py diff --git a/synchronousdeluge/transfer.py b/nzbtomedia/synchronousdeluge/transfer.py similarity index 96% rename from synchronousdeluge/transfer.py rename to nzbtomedia/synchronousdeluge/transfer.py index 979ffb16..0e4763f8 100644 --- a/synchronousdeluge/transfer.py +++ b/nzbtomedia/synchronousdeluge/transfer.py @@ -3,7 +3,7 @@ import struct import socket import ssl -from synchronousdeluge import rencode +from nzbtomedia.synchronousdeluge import rencode __all__ = ["DelugeTransfer"] diff --git a/nzbtomedia/transmissionrpc/__init__.py b/nzbtomedia/transmissionrpc/__init__.py new file mode 100644 index 00000000..b781e390 --- /dev/null +++ b/nzbtomedia/transmissionrpc/__init__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2008-2013 Erik Svensson +# Licensed under the MIT license. + +from nzbtomedia.transmissionrpc.constants import DEFAULT_PORT, DEFAULT_TIMEOUT, PRIORITY, RATIO_LIMIT, LOGGER +from nzbtomedia.transmissionrpc.error import TransmissionError, HTTPHandlerError +from nzbtomedia.transmissionrpc.httphandler import HTTPHandler, DefaultHTTPHandler +from nzbtomedia.transmissionrpc.torrent import Torrent +from nzbtomedia.transmissionrpc.session import Session +from nzbtomedia.transmissionrpc.client import Client +from nzbtomedia.transmissionrpc.utils import add_stdout_logger, add_file_logger + +__author__ = 'Erik Svensson ' +__version_major__ = 0 +__version_minor__ = 11 +__version__ = '{0}.{1}'.format(__version_major__, __version_minor__) +__copyright__ = 'Copyright (c) 2008-2013 Erik Svensson' +__license__ = 'MIT' diff --git a/transmissionrpc/client.py b/nzbtomedia/transmissionrpc/client.py similarity index 98% rename from transmissionrpc/client.py rename to nzbtomedia/transmissionrpc/client.py index 436006b9..e60be85c 100644 --- a/transmissionrpc/client.py +++ b/nzbtomedia/transmissionrpc/client.py @@ -10,12 +10,12 @@ import os import base64 import json -from transmissionrpc.constants import DEFAULT_PORT, DEFAULT_TIMEOUT -from transmissionrpc.error import TransmissionError, HTTPHandlerError -from transmissionrpc.utils import LOGGER, get_arguments, make_rpc_name, argument_value_convert, rpc_bool -from transmissionrpc.httphandler import DefaultHTTPHandler -from transmissionrpc.torrent import Torrent -from transmissionrpc.session import Session +from nzbtomedia.transmissionrpc.constants import DEFAULT_PORT, DEFAULT_TIMEOUT +from nzbtomedia.transmissionrpc.error import TransmissionError, HTTPHandlerError +from nzbtomedia.transmissionrpc.utils import LOGGER, get_arguments, make_rpc_name, argument_value_convert, rpc_bool +from nzbtomedia.transmissionrpc.httphandler import DefaultHTTPHandler +from nzbtomedia.transmissionrpc.torrent import Torrent +from nzbtomedia.transmissionrpc.session import Session from six import PY3, integer_types, string_types, iteritems diff --git a/transmissionrpc/constants.py b/nzbtomedia/transmissionrpc/constants.py similarity index 99% rename from transmissionrpc/constants.py rename to nzbtomedia/transmissionrpc/constants.py index 8c706b34..37a26d89 100644 --- a/transmissionrpc/constants.py +++ b/nzbtomedia/transmissionrpc/constants.py @@ -4,7 +4,7 @@ import logging -from six import iteritems +from nzbtomedia.transmissionrpc.six import iteritems LOGGER = logging.getLogger('transmissionrpc') diff --git a/transmissionrpc/error.py b/nzbtomedia/transmissionrpc/error.py similarity index 96% rename from transmissionrpc/error.py rename to nzbtomedia/transmissionrpc/error.py index d4971175..22be143c 100644 --- a/transmissionrpc/error.py +++ b/nzbtomedia/transmissionrpc/error.py @@ -2,7 +2,7 @@ # Copyright (c) 2008-2013 Erik Svensson # Licensed under the MIT license. -from six import string_types, integer_types +from nzbtomedia.transmissionrpc.six import string_types, integer_types class TransmissionError(Exception): """ diff --git a/transmissionrpc/httphandler.py b/nzbtomedia/transmissionrpc/httphandler.py similarity index 98% rename from transmissionrpc/httphandler.py rename to nzbtomedia/transmissionrpc/httphandler.py index 3fdcee6c..a999a1c8 100644 --- a/transmissionrpc/httphandler.py +++ b/nzbtomedia/transmissionrpc/httphandler.py @@ -4,7 +4,7 @@ import sys -from transmissionrpc.error import HTTPHandlerError +from nzbtomedia.transmissionrpc.error import HTTPHandlerError from six import PY3 if PY3: diff --git a/transmissionrpc/session.py b/nzbtomedia/transmissionrpc/session.py similarity index 96% rename from transmissionrpc/session.py rename to nzbtomedia/transmissionrpc/session.py index eb01ce15..e5d04bff 100644 --- a/transmissionrpc/session.py +++ b/nzbtomedia/transmissionrpc/session.py @@ -2,9 +2,9 @@ # Copyright (c) 2008-2013 Erik Svensson # Licensed under the MIT license. -from transmissionrpc.utils import Field +from nzbtomedia.transmissionrpc.utils import Field -from six import iteritems, integer_types +from nzbtomedia.transmissionrpc.six import iteritems, integer_types class Session(object): """ diff --git a/transmissionrpc/six.py b/nzbtomedia/transmissionrpc/six.py similarity index 100% rename from transmissionrpc/six.py rename to nzbtomedia/transmissionrpc/six.py diff --git a/transmissionrpc/torrent.py b/nzbtomedia/transmissionrpc/torrent.py similarity index 99% rename from transmissionrpc/torrent.py rename to nzbtomedia/transmissionrpc/torrent.py index 4d7d3d64..42c30b29 100644 --- a/transmissionrpc/torrent.py +++ b/nzbtomedia/transmissionrpc/torrent.py @@ -5,8 +5,8 @@ import sys import datetime -from transmissionrpc.constants import PRIORITY, RATIO_LIMIT, IDLE_LIMIT -from transmissionrpc.utils import Field, format_timedelta +from nzbtomedia.transmissionrpc.constants import PRIORITY, RATIO_LIMIT, IDLE_LIMIT +from nzbtomedia.transmissionrpc.utils import Field, format_timedelta from six import integer_types, string_types, text_type, iteritems diff --git a/transmissionrpc/utils.py b/nzbtomedia/transmissionrpc/utils.py similarity index 97% rename from transmissionrpc/utils.py rename to nzbtomedia/transmissionrpc/utils.py index 40653213..d67a3d06 100644 --- a/transmissionrpc/utils.py +++ b/nzbtomedia/transmissionrpc/utils.py @@ -2,16 +2,12 @@ # Copyright (c) 2008-2013 Erik Svensson # Licensed under the MIT license. -import socket -import datetime -import logging +import socket, datetime, logging, constants from collections import namedtuple +from constants import LOGGER -import transmissionrpc.constants as constants -from transmissionrpc.constants import LOGGER from six import string_types, iteritems - UNITS = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB'] def format_size(size): diff --git a/nzbtomedia/utorrent/__init__.py b/nzbtomedia/utorrent/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/utorrent/client.py b/nzbtomedia/utorrent/client.py similarity index 98% rename from utorrent/client.py rename to nzbtomedia/utorrent/client.py index ca9d83e5..da92c967 100644 --- a/utorrent/client.py +++ b/nzbtomedia/utorrent/client.py @@ -10,7 +10,7 @@ try: except ImportError: import simplejson as json -from upload import MultiPartForm +from nzbtomedia.utorrent.upload import MultiPartForm class UTorrentClient(object): diff --git a/utorrent/upload.py b/nzbtomedia/utorrent/upload.py similarity index 100% rename from utorrent/upload.py rename to nzbtomedia/utorrent/upload.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..1f47cffe --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +__author__ = 'Justin' diff --git a/tests/test_autofork.py b/tests/test_autofork.py index c9fb55c0..a0d1611c 100644 --- a/tests/test_autofork.py +++ b/tests/test_autofork.py @@ -1,6 +1,3 @@ -from autoProcess.nzbToMediaUtil import * -from autoProcess.autoSickBeardFork import autoFork -nzbtomedia_configure_logging(LOG_FILE) - +from nzbtomedia import * fork, params = autoFork() print fork, params \ No newline at end of file diff --git a/transmissionrpc/__init__.py b/transmissionrpc/__init__.py deleted file mode 100644 index ef4ad49c..00000000 --- a/transmissionrpc/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (c) 2008-2013 Erik Svensson -# Licensed under the MIT license. - -from transmissionrpc.constants import DEFAULT_PORT, DEFAULT_TIMEOUT, PRIORITY, RATIO_LIMIT, LOGGER -from transmissionrpc.error import TransmissionError, HTTPHandlerError -from transmissionrpc.httphandler import HTTPHandler, DefaultHTTPHandler -from transmissionrpc.torrent import Torrent -from transmissionrpc.session import Session -from transmissionrpc.client import Client -from transmissionrpc.utils import add_stdout_logger, add_file_logger - -__author__ = 'Erik Svensson ' -__version_major__ = 0 -__version_minor__ = 11 -__version__ = '{0}.{1}'.format(__version_major__, __version_minor__) -__copyright__ = 'Copyright (c) 2008-2013 Erik Svensson' -__license__ = 'MIT'