diff --git a/TorrentToMedia.py b/TorrentToMedia.py index 0165d3e7..4cfbb0cb 100755 --- a/TorrentToMedia.py +++ b/TorrentToMedia.py @@ -20,7 +20,7 @@ from nzbtomedia.extractor import extractor 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 + nzbtomedia_configure_logging, get_dirnames from nzbtomedia.synchronousdeluge.client import DelugeClient from nzbtomedia.utorrent.client import UTorrentClient from nzbtomedia.transmissionrpc.client import Client as TransmissionClient @@ -48,19 +48,16 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): Logger.debug("MAIN: Determined Directory: %s | Name: %s | Category: %s", inputDirectory, inputName, inputCategory) - if inputCategory in sections["SickBeard"]: - fork, fork_params = autoFork("SickBeard", inputCategory) - Torrent_NoLink = int(config()["SickBeard"][inputCategory]["Torrent_NoLink"]) # 0 - if fork in config.SICKBEARD_TORRENT and Torrent_NoLink == 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() + if config.issubsection(inputCategory,["SickBeard","NzbDrone"]): + Logger.info("MAIN: Calling autoProcessTV to post-process: %s",inputName) + result = autoProcessTV().processEpisode(inputDirectory, inputName, 0, clientAgent=clientAgent, inputCategory=inputCategory) + if result != 0: + Logger.info("MAIN: A problem was reported in the autoProcessTV script.") + Logger.info("MAIN: All done.") + sys.exit() outputDestination = "" - for section, category in sections.items(): + for category in categories: if category == inputCategory: if os.path.basename(inputDirectory) == inputName and os.path.isdir(inputDirectory): Logger.info("MAIN: Download is a directory") @@ -72,6 +69,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): break else: continue + if outputDestination == "": if inputCategory == "": inputCategory = "UNCAT" @@ -83,7 +81,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): outputDestination = os.path.normpath(os.path.join(outputDirectory, inputCategory, os.path.splitext(safeName(inputName))[0])) Logger.info("MAIN: Output directory set to: %s", outputDestination) - processOnly = list(chain.from_iterable(sections.values())) + processOnly = list(chain.from_iterable(subsections.values())) if not "NONE" in user_script_categories: # if None, we only process the 5 listed. if "ALL" in user_script_categories: # All defined categories processOnly = categories @@ -130,14 +128,14 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): Logger.debug("MAIN: Scanning files in directory: %s", inputDirectory) - noFlatten.extend(list(chain.from_iterable(config.get_sections(["HeadPhones"]).values()))) # Make sure we preserve folder structure for HeadPhones. + if config.issubsection(inputCategory, "HeadPhones"): + noFlatten.extend(list(chain.from_iterable(config()[section].sections))) # Make sure we preserve folder structure for HeadPhones. 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): Logger.debug("MAIN: Found %s files in %s", str(len(filenames)), dirpath) for file in filenames: - filePath = os.path.join(dirpath, file) fileName, fileExtension = os.path.splitext(file) if inputCategory in noFlatten: @@ -172,7 +170,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): continue # This file has not been recently moved or created, skip it if fileExtension in mediaContainer: # If the file is a video file - if is_sample(filePath, inputName, minSampleSize, SampleIDs) and not inputCategory in config.get_sections(["HeadPhones"]).values(): # Ignore samples + if is_sample(filePath, inputName, minSampleSize, SampleIDs) and not config.issubsection(inputCategory, ["HeadPhones"]): # Ignore samples Logger.info("MAIN: Ignoring sample file: %s ", filePath) continue else: @@ -208,7 +206,7 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): except: Logger.exception("MAIN: Extraction failed for: %s", file) continue - elif not inputCategory in list(chain.from_iterable(config.get_sections(['CouchPotato','SickBeard']).values())): #process all for non-video categories. + elif not config.issubsection(inputCategory,['CouchPotato','SickBeard','NzbDrone']): #process all for non-video categories. Logger.info("MAIN: Found file %s for category %s", filePath, inputCategory) copy_link(filePath, targetDirectory, useLink, outputDestination) copy_list.append([filePath, os.path.join(outputDestination, file)]) @@ -221,8 +219,8 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): 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 list(chain.from_iterable(config.get_sections(['CouchPotato','SickBeard']).values())): + # Now check if video files exist in destination: + if config.issubsection(inputCategory,["SickBeard","NzbDrone"]): for dirpath, dirnames, filenames in os.walk(outputDestination): for file in filenames: filePath = os.path.join(dirpath, file) @@ -242,12 +240,12 @@ 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)) - processCategories = list(chain.from_iterable(sections.values())) + processCategories = list(chain.from_iterable(subsections.values())) if (inputCategory in user_script_categories and not "NONE" in user_script_categories) or ("ALL" in user_script_categories and not inputCategory in processCategories): Logger.info("MAIN: Processing user script %s.", user_script) result = external_script(outputDestination,inputName,inputCategory) - elif status == int(0) or (inputCategory in list(chain.from_iterable(config.get_sections(['HeadPhones','Mylar','Gamez']).values()))): # if movies linked/extracted or for other categories. + elif status == int(0) or (config.issubsection(inputCategory,['HeadPhones','Mylar','Gamez'])): # if movies linked/extracted or for other categories. Logger.debug("MAIN: Calling autoProcess script for successful download.") status = int(0) # hp, my, gz don't support failed. else: @@ -255,21 +253,24 @@ def main(inputDirectory, inputName, inputCategory, inputHash, inputID): sys.exit(-1) result = 0 - if inputCategory in sections['CouchPotato'].values(): - Logger.info("MAIN: Calling CouchPotatoServer to post-process: %s", inputName) + if config.issubsection(inputCategory,['CouchPotato']): + Logger.info("MAIN: Calling CouchPotato:" + inputCategory + " to post-process: %s", inputName) download_id = inputHash result = autoProcessMovie().process(outputDestination, inputName, status, clientAgent, download_id, inputCategory) - elif inputCategory in sections['SickBeard'].values(): - Logger.info("MAIN: Calling Sick-Beard to post-process: %s", inputName) + elif config.issubsection(inputCategory,['SickBeard']): + Logger.info("MAIN: Calling Sick-Beard:" + inputCategory + " to post-process: %s", inputName) result = autoProcessTV().processEpisode(outputDestination, inputName, status, clientAgent, inputCategory) - elif inputCategory in sections['HeadPhones'].values(): - Logger.info("MAIN: Calling HeadPhones to post-process: %s", inputName) + elif config.issubsection(inputCategory,['NzbDrone']): + Logger.info("MAIN: Calling NzbDrone:" + inputCategory + " to post-process: %s", inputName) + result = autoProcessTV().processEpisode(outputDestination, inputName, status, clientAgent, inputCategory) + elif config.issubsection(inputCategory,['HeadPhones']): + Logger.info("MAIN: Calling HeadPhones:" + inputCategory + " to post-process: %s", inputName) result = autoProcessMusic().process(inputDirectory, inputName, status, clientAgent, inputCategory) - elif inputCategory in sections['Mylar'].values(): - Logger.info("MAIN: Calling Mylar to post-process: %s", inputName) + elif config.issubsection(inputCategory,['Mylar']): + Logger.info("MAIN: Calling Mylar:" + inputCategory + " to post-process: %s", inputName) result = autoProcessComics().processEpisode(outputDestination, inputName, status, clientAgent, inputCategory) - elif inputCategory in sections['Gamez'].values(): - Logger.info("MAIN: Calling Gamez to post-process: %s", inputName) + elif config.issubsection(inputCategory,['Gamez']): + Logger.info("MAIN: Calling Gamez:" + inputCategory + " to post-process: %s", inputName) result = autoProcessGames().process(outputDestination, inputName, status, clientAgent, inputCategory) if result == 1: @@ -434,8 +435,8 @@ if __name__ == "__main__": minSampleSize = int(config()["Extensions"]["minSampleSize"]) # 200 (in MB) SampleIDs = (config()["Extensions"]["SampleIDs"]) # sample,-s. - sections = config.get_sections(["CouchPotato", "SickBeard", "HeadPhones", "Mylar", "Gamez"]) - categories += list(chain.from_iterable(sections.values())) + subsections = config.get_subsections(["CouchPotato", "SickBeard", "NzbDrone", "HeadPhones", "Mylar", "Gamez"]) + categories += list(chain.from_iterable(subsections.values())) user_script_categories = config()["UserScript"]["user_script_categories"] # NONE if not "NONE" in user_script_categories: @@ -460,4 +461,13 @@ if __name__ == "__main__": Logger.exception("MAIN: There was a problem loading variables") sys.exit(-1) - main(inputDirectory, inputName, inputCategory, inputHash, inputID) + # check if this is a manual run + if inputDirectory is None: + for section, subsection in subsections.iteritems(): + for category in subsection: + dirNames = get_dirnames(section, category) + Logger.info("MAIN: TorrentToMedia running %s:%s as a manual run...", section, category) + for dirName in dirNames: + main(dirName, os.path.basename(dirName), category, inputHash, inputID) + else: + main(inputDirectory, inputName, inputCategory, inputHash, inputID) diff --git a/autoProcessMedia.cfg.sample b/autoProcessMedia.cfg.sample index e761ddbe..47963470 100644 --- a/autoProcessMedia.cfg.sample +++ b/autoProcessMedia.cfg.sample @@ -5,6 +5,7 @@ #### autoProcessing for Movies #### movie - category that gets called for post-processing with CPS [[movie]] + enabled = 0 apikey = host = localhost port = 5050 @@ -24,6 +25,7 @@ #### autoProcessing for TV Series #### tv - category that gets called for post-processing with SB [[tv]] + enabled = 0 host = localhost port = 8081 username = @@ -40,10 +42,30 @@ Torrent_NoLink = 0 process_method = +[NzbDrone] + #### autoProcessing for TV Series + #### ndCategory - category that gets called for post-processing with NzbDrone + [[tv]] + enabled = 0 + host = localhost + port = 8989 + username = + password = + ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### + web_root = + ssl = 0 + delay = 0 + TimePerGiB = 60 + watch_dir = + delete_failed = 0 + nzbExtractionBy = Downloader + Torrent_NoLink = 0 + [HeadPhones] #### autoProcessing for Music #### music - category that gets called for post-processing with HP [[music]] + enabled = 0 apikey = host = localhost port = 8181 @@ -58,6 +80,7 @@ #### autoProcessing for Comics #### comics - category that gets called for post-processing with Mylar [[comics]] + enabled = 0 host = localhost port= 8090 username= @@ -71,6 +94,7 @@ #### autoProcessing for Games #### games - category that gets called for post-processing with Gamez [[games]] + enabled = 0 apikey = host = localhost port = 8085 @@ -172,4 +196,29 @@ [passwords] # enter the full path to a text file containing passwords to be used for extraction attempts. # In the passwords file, every password should be on a new line - PassWordFile = \ No newline at end of file + PassWordFile = + +# Logging configuration +[loggers] + keys = root + +[handlers] + keys = console + +[formatters] + keys = generic + +[logger_root] + level = NOTSET + handlers = console + qualname = + +[handler_console] + class = StreamHandler + args = (sys.stdout,) + level = INFO + formatter = generic + +[formatter_generic] + format = %(asctime)s|%(levelname)-7.7s %(message)s + datefmt = %H:%M:%S \ No newline at end of file diff --git a/logging.cfg.sample b/logging.cfg.sample new file mode 100644 index 00000000..13e08a5a --- /dev/null +++ b/logging.cfg.sample @@ -0,0 +1,23 @@ +[loggers] +keys = root + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = NOTSET +handlers = console +qualname = + +[handler_console] +class = StreamHandler +args = (sys.stdout,) +level = INFO +formatter = generic + +[formatter_generic] +format = %(asctime)s|%(levelname)-7.7s %(message)s +datefmt = %H:%M:%S \ No newline at end of file diff --git a/nzbToCouchPotato.py b/nzbToCouchPotato.py index 616f149e..cf2a84e1 100755 --- a/nzbToCouchPotato.py +++ b/nzbToCouchPotato.py @@ -147,9 +147,6 @@ if config.migrate(): else: sys.exit(-1) -# setup sections and categories -sections = config.get_sections(["CouchPotato"]) - WakeUp() # NZBGet V11+ @@ -235,16 +232,20 @@ elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: else: result = 0 - Logger.warn("MAIN: Invalid number of arguments received from client.") - Logger.info("MAIN: Running autoProcessMovie as a manual run...") + # init sub-sections + subsections = config.get_subsections(["CouchPotato"]) - for section, categories in sections.items(): - for category in categories: + Logger.warn("MAIN: Invalid number of arguments received from client.") + for section, subsection in subsections.items(): + for category in subsection: dirNames = get_dirnames(section, category) for dirName in dirNames: - Logger.info("MAIN: Calling " + section + ":" + category + " to post-process: %s", dirName) - results = autoProcessMovie().process(dirName, dirName, 0, inputCategory=category) - if results != 0:result = results + Logger.info("MAIN: nzbToCouchPotato running %s:%s as a manual run...", section, subsection) + results = autoProcessMovie(dirName, inputName=os.path.basename(dirName), status=0, clientAgent="manual", + inputCategory=category) + if results != 0: + result = results + Logger.info("MAIN: A problem was reported when trying to manually run %s:%s.", section, subsection) if result == 0: Logger.info("MAIN: The autoProcessMovie script completed successfully.") diff --git a/nzbToGamez.py b/nzbToGamez.py index 38d4e1e8..83529335 100755 --- a/nzbToGamez.py +++ b/nzbToGamez.py @@ -83,7 +83,7 @@ else: sys.exit(-1) # gamez category -sections = config.get_sections(['Gamez']) +sections = config.get_subsections(['Gamez']) WakeUp() @@ -162,16 +162,19 @@ elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: else: result = 0 - Logger.warn("MAIN: Invalid number of arguments received from client. Exiting") - Logger.info("MAIN: Running autoProcessGames as a manual run...") + # init sub-sections + subsections = config.get_subsections(["Gamez"]) - for section, categories in sections.items(): - for category in categories: + Logger.warn("MAIN: Invalid number of arguments received from client.") + for section, subsection in subsections.items(): + for category in subsection: dirNames = get_dirnames(section, category) for dirName in dirNames: - Logger.info("MAIN: Calling " + section + ":" + category + " to post-process: %s", dirName) - results = autoProcessGames().process(dirName, dirName, 0, inputCategory=category) - if results != 0:result = results + Logger.info("MAIN: nzbToGamez running %s:%s as a manual run...", section, category) + results = autoProcessGames(dirName, inputName=os.path.basename(dirName), status=0, clientAgent = "manual", inputCategory=category) + if results != 0: + result = results + Logger.info("MAIN: A problem was reported when trying to manually run %s:%s.", section, category) if result == 0: Logger.info("MAIN: The autoProcessGames script completed successfully.") diff --git a/nzbToHeadPhones.py b/nzbToHeadPhones.py index 1e3b7234..cafd2d1c 100755 --- a/nzbToHeadPhones.py +++ b/nzbToHeadPhones.py @@ -95,9 +95,6 @@ if config.migrate(): else: sys.exit(-1) -# headphones category -sections = config.get_sections(["HeadPhones"]) - WakeUp() # NZBGet V11+ @@ -175,16 +172,20 @@ elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: else: result = 0 - Logger.warn("MAIN: Invalid number of arguments received from client.") - Logger.info("MAIN: Running autoProcessMusic as a manual run...") + # init sub-sections + subsections = config.get_subsections(["HeadPhones"]) - for section, categories in sections.items(): - for category in categories: + Logger.warn("MAIN: Invalid number of arguments received from client.") + for section, subsection in subsections.items(): + for category in subsection: dirNames = get_dirnames(section, category) for dirName in dirNames: - Logger.info("MAIN: Calling " + section + ":" + category + " to post-process: %s", dirName) - results = autoProcessMusic().process(dirName, dirName, 0, inputCategory=category) - if results != 0:result = results + Logger.info("MAIN: nzbToHeadPhones running %s:%s as a manual run...", section, subsection) + results = autoProcessMusic(dirName, inputName=os.path.basename(dirName), status=0, clientAgent="manual", + inputCategory=category) + if results != 0: + result = results + Logger.info("MAIN: A problem was reported when trying to manually run %s:%s.", section, subsection) if result == 0: Logger.info("MAIN: The autoProcessMusic script completed successfully.") diff --git a/nzbToMedia.py b/nzbToMedia.py index bcb918fb..108e20ef 100755 --- a/nzbToMedia.py +++ b/nzbToMedia.py @@ -9,7 +9,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib' ############################################################################## ### NZBGET POST-PROCESSING SCRIPT ### -# Post-Process to CouchPotato, SickBeard, Mylar, Gamez, HeadPhones. +# Post-Process to CouchPotato, SickBeard, NzbDrone, Mylar, Gamez, HeadPhones. # # This script sends the download to your automated media management servers. # @@ -88,7 +88,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib' #sbport=8081 # SickBeard username. -#sbusername= +#sbusername= # SickBeard password. #sbpassword= @@ -133,6 +133,35 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib' # set this to move, copy, hardlin, symlink as appropriate if you want to over-ride SB defaults. Leave blank to use SB default. #sbprocess_method= +## NzbDrone + +# NzbDrone script category. +# +# category that gets called for post-processing with NzbDrone. +#ndCategory=tv + +# NzbDrone host. +#ndHost=localhost + +# NzbDrone port. +#ndPort=8989 + +# NzbDrone API key. +#ndAPIKey= + +# NzbDrone uses SSL (0, 1). +# +# Set to 1 if using SSL, else set to 0. +#ndSSL=0 + +# NzbDrone web root. +# +# set this if using a reverse proxy. +#ndWebRoot= + +# Prefer NzbDrone if categories clash (0, 1). +#ndPrefer=0 + ## HeadPhones # HeadPhones script category. @@ -183,7 +212,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib' #myport=8090 # Mylar username. -#myusername= +#myusername= # Mylar password. #mypassword= @@ -245,7 +274,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib' # ignore extensions # -# list of extensions that won't be transcoded. +# list of extensions that won't be transcoded. #ignoreExtensions=.avi,.mkv # ffmpeg output settings. @@ -287,58 +316,24 @@ from nzbtomedia.nzbToMediaUtil import nzbtomedia_configure_logging, WakeUp, get_ # post-processing def process(nzbDir, inputName=None, status=0, clientAgent='manual', download_id=None, inputCategory=None): - if inputCategory in sections["CouchPotato"]: - 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 sections["SickBeard"]: - 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 sections["HeadPhones"]: - 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 sections["Mylar"]: - 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 sections["Gamez"]: - 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) + + if section in ["CouchPotato"]: + Logger.info("MAIN: Calling CouchPotatoServer to post-process: %s", inputName) + return autoProcessMovie().process(nzbDir, inputName, status, clientAgent, download_id, inputCategory) + elif section in ["SickBeard", "NzbDrone"]: + Logger.info("MAIN: Calling Sick-Beard to post-process: %s", inputName) + return autoProcessTV().processEpisode(nzbDir, inputName, status, clientAgent, inputCategory) + elif section in ["HeadPhones"]: + Logger.info("MAIN: Calling HeadPhones to post-process: %s", inputName) + return autoProcessMusic().process(nzbDir, inputName, status, clientAgent, inputCategory) + elif section in ["Mylar"]: + Logger.info("MAIN: Calling Mylar to post-process: %s", inputName) + return autoProcessComics().processEpisode(nzbDir, inputName, status, clientAgent, inputCategory) + elif section in ["Gamez"]: + 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) + Logger.warning("MAIN: We could not find the section %s with a download category of %s in your autoProcessMedia.cfg. Exiting.", section, inputCategory) return -1 ######################################################################################################################## @@ -360,9 +355,6 @@ else: print("Unable to find " + config.CONFIG_FILE + " or " + config.SAMPLE_CONFIG_FILE) sys.exit(-1) -# setup sections and categories -sections = config.get_sections(["CouchPotato","SickBeard","HeadPhones","Mylar","Gamez"]) - WakeUp() # Post-Processing Result @@ -450,15 +442,20 @@ elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: else: result = 0 + # init sub-sections + subsections = config.get_subsections(["CouchPotato", "SickBeard", "NzbDrone", "HeadPhones", "Mylar", "Gamez"]) + Logger.warn("MAIN: Invalid number of arguments received from client.") - for section, categories in sections.items(): - for category in categories: + for section, subsection in subsections.items(): + for category in subsection: dirNames = get_dirnames(section, category) - Logger.info("MAIN: Running " + section + ":" + category + " as a manual run...") - results = process(dirNames, inputName=dirNames, status=0, inputCategory=category, clientAgent = "manual") - if results != 0: - result = results - Logger.info("MAIN: A problem was reported when trying to manually run " + section + ":" + category + ".") + for dirName in dirNames: + Logger.info("MAIN: nzbToMedia running %s:%s as a manual run...", section, subsection) + results = process(dirName, inputName=os.path.basename(dirName), status=0, clientAgent="manual", + inputCategory=category) + if results != 0: + result = results + Logger.info("MAIN: A problem was reported when trying to manually run %s:%s.", section, subsection) if result == 0: Logger.info("MAIN: The nzbToMedia script completed successfully.") diff --git a/nzbToMylar.py b/nzbToMylar.py index d130d5b9..552446c1 100755 --- a/nzbToMylar.py +++ b/nzbToMylar.py @@ -87,9 +87,6 @@ if config.migrate(): else: sys.exit(-1) -# mylar category -sections = config.get_sections(["Mylar"]) - WakeUp() # NZBGet V11+ @@ -167,16 +164,20 @@ elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: else: result = 0 - Logger.warn("MAIN: Invalid number of arguments received from client.") - Logger.info("MAIN: Running autoProcessComics as a manual run...") + # init sub-sections + subsections = config.get_subsections(["Mylar"]) - for section, categories in sections.items(): - for category in categories: + Logger.warn("MAIN: Invalid number of arguments received from client.") + for section, subsection in subsections.items(): + for category in subsection: dirNames = get_dirnames(section, category) for dirName in dirNames: - Logger.info("MAIN: Calling " + section + ":" + category + " to post-process: %s", dirName) - results = autoProcessComics().processEpisode(dirName, dirName, 0, inputCategory=category) - if results != 0:result = results + Logger.info("MAIN: nzbToMylar running %s:%s as a manual run...", section, subsection) + results = autoProcessComics(dirName, inputName=os.path.basename(dirName), status=0, clientAgent="manual", + inputCategory=category) + if results != 0: + result = results + Logger.info("MAIN: A problem was reported when trying to manually run %s:%s.", section, subsection) if result == 0: Logger.info("MAIN: The autoProcessComics script completed successfully.") diff --git a/nzbToNzbDrone.py b/nzbToNzbDrone.py new file mode 100755 index 00000000..14fd4277 --- /dev/null +++ b/nzbToNzbDrone.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python + +# adds lib directory to system path +import os +import sys +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'lib'))) + +# +############################################################################## +### NZBGET POST-PROCESSING SCRIPT ### + +# Post-Process to NzbDrone. +# +# This script sends the download to your automated media management servers. +# +# NOTE: This script requires Python to be installed on your system. + +############################################################################## +### OPTIONS ### + +## NzbDrone + +# NzbDrone script category. +# +# category that gets called for post-processing with NzbDrone. +#ndCategory=tv + +# NzbDrone host. +#ndHost=localhost + +# NzbDrone port. +#ndPort=8989 + +# NzbDrone API key. +#ndAPIKey= + +# NzbDrone uses SSL (0, 1). +# +# Set to 1 if using SSL, else set to 0. +#ndSSL=0 + +# NzbDrone web root. +# +# set this if using a reverse proxy. +#ndWebRoot= + +## Extensions + +# Media Extensions +# +# This is a list of media extensions that are used to verify that the download does contain valid media. +#mediaExtensions=.mkv,.avi,.divx,.xvid,.mov,.wmv,.mp4,.mpg,.mpeg,.vob,.iso + +## Transcoder + +# Transcode (0, 1). +# +# set to 1 to transcode, otherwise set to 0. +#transcode=0 + +# create a duplicate, or replace the original (0, 1). +# +# set to 1 to cretae a new file or 0 to replace the original +#duplicate=1 + +# ignore extensions +# +# list of extensions that won't be transcoded. +#ignoreExtensions=.avi,.mkv + +# ffmpeg output settings. +#outputVideoExtension=.mp4 +#outputVideoCodec=libx264 +#outputVideoPreset=medium +#outputVideoFramerate=24 +#outputVideoBitrate=800k +#outputAudioCodec=libmp3lame +#outputAudioBitrate=128k +#outputSubtitleCodec= + +## WakeOnLan + +# use WOL (0, 1). +# +# set to 1 to send WOL broadcast to the mac and test the server (e.g. xbmc) on the host and port specified. +#wolwake=0 + +# WOL MAC +# +# enter the mac address of the system to be woken. +#wolmac=00:01:2e:2D:64:e1 + +# Set the Host and Port of a server to verify system has woken. +#wolhost=192.168.1.37 +#wolport=80 + +### NZBGET POST-PROCESSING SCRIPT ### +############################################################################## +import logging +from nzbtomedia.autoProcess.autoProcessTV import autoProcessTV +from nzbtomedia.nzbToMediaConfig import config +from nzbtomedia.nzbToMediaUtil import nzbtomedia_configure_logging, WakeUp, get_dirnames + +# run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. +if config.migrate(): + # check to write settings from nzbGet UI to autoProcessMedia.cfg. + if os.environ.has_key('NZBOP_SCRIPTDIR'): + config.addnzbget() + + nzbtomedia_configure_logging(config.LOG_FILE) + Logger = logging.getLogger(__name__) + Logger.info("====================") # Seperate old from new log + Logger.info("nzbToNzbDrone %s", config.NZBTOMEDIA_VERSION) + + Logger.info("MAIN: Loading config from %s", config.CONFIG_FILE) +else: + sys.exit(-1) + +WakeUp() + +# NZBGet V11+ +# Check if the script is called from nzbget 11.0 or later +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).") + + # 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(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(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\"") + status = 1 + + # Check unpack status + if os.environ['NZBPP_UNPACKSTATUS'] == '1': + Logger.warning("MAIN: Unpack failed, setting status \"failed\"") + status = 1 + + if os.environ['NZBPP_UNPACKSTATUS'] == '0' and os.environ['NZBPP_PARSTATUS'] == '0': + # Unpack was skipped due to nzb-file properties or due to errors during par-check + + if os.environ['NZBPP_HEALTH'] < 1000: + Logger.warning("MAIN: Download health is compromised and Par-check/repair disabled or no .par2 files found. Setting status \"failed\"") + Logger.info("MAIN: Please check your Par-check/repair settings for future downloads.") + status = 1 + + else: + Logger.info("MAIN: Par-check/repair disabled or no .par2 files found, and Unpack not required. Health is ok so handle as though download successful") + Logger.info("MAIN: Please check your Par-check/repair settings for future downloads.") + + # Check if destination directory exists (important for reprocessing of history items) + if not os.path.isdir(os.environ['NZBPP_DIRECTORY']): + Logger.error("MAIN: Nothing to post-process: destination directory %s doesn't exist. Setting status \"failed\"", os.environ['NZBPP_DIRECTORY']) + status = 1 + + # 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']) +# SABnzbd Pre 0.7.17 +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 + # 3 Clean version of the job name (no path info and ".nzb" removed) + # 4 Indexer's report number (if supported) + # 5 User-defined category + # 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 autoProcessTV...") + clientAgent = "sabnzbd" + result = autoProcessTV().processEpisode(sys.argv[1], sys.argv[2], sys.argv[7], clientAgent, sys.argv[5]) +# SABnzbd 0.7.17+ +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 + # 3 Clean version of the job name (no path info and ".nzb" removed) + # 4 Indexer's report number (if supported) + # 5 User-defined category + # 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 + # 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]) +else: + result = 0 + + # init sub-sections + subsections = config.get_subsections(["CouchPotato", "SickBeard", "NzbDrone", "HeadPhones", "Mylar", "Gamez"]) + + Logger.warn("MAIN: Invalid number of arguments received from client.") + for section, subsection in subsections.items(): + for category in subsection: + dirNames = get_dirnames(section, category) + for dirName in dirNames: + Logger.info("MAIN: nzbToNzbDrone running %s:%s as a manual run...", section, subsection) + results = autoProcessTV(dirName, inputName=os.path.basename(dirName), status=0, clientAgent="manual", + inputCategory=category) + if results != 0: + result = results + Logger.info("MAIN: A problem was reported when trying to manually run %s:%s.", section, subsection) + +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(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(config.NZBGET_POSTPROCESS_ERROR) diff --git a/nzbToSickBeard.py b/nzbToSickBeard.py index dff4cf24..85c3b1a7 100755 --- a/nzbToSickBeard.py +++ b/nzbToSickBeard.py @@ -149,9 +149,6 @@ if config.migrate(): else: sys.exit(-1) -# sickbeard category -sections = config.get_sections(["SickBeard"]) - WakeUp() # NZBGet V11+ @@ -232,16 +229,20 @@ elif len(sys.argv) >= config.SABNZB_0717_NO_OF_ARGUMENTS: else: result = 0 - Logger.debug("MAIN: Invalid number of arguments received from client.") - Logger.info("MAIN: Running autoProcessTV as a manual run...") + # init sub-sections + subsections = config.get_subsections(["SickBeard", "NzbDrone"]) - for section, categories in sections.items(): - for category in categories: + Logger.warn("MAIN: Invalid number of arguments received from client.") + for section, subsection in subsections.items(): + for category in subsection: dirNames = get_dirnames(section, category) for dirName in dirNames: - Logger.info("MAIN: Calling " + section + ":" + category + " to post-process: %s", dirName) - results = autoProcessTV().processEpisode(dirName, dirName, 0, inputCategory=category) - if results != 0:result = results + Logger.info("MAIN: nzbTo%s running %s:%s as a manual run...", section, section, subsection) + results = autoProcessTV(dirName, inputName=os.path.basename(dirName), status=0, clientAgent="manual", + inputCategory=category) + if results != 0: + result = results + Logger.info("MAIN: A problem was reported when trying to manually run %s:%s.", section, subsection) if result == 0: Logger.info("MAIN: The autoProcessTV script completed successfully.") diff --git a/nzbtomedia/autoProcess/autoProcessComics.py b/nzbtomedia/autoProcess/autoProcessComics.py index e5f52aa4..e18999c4 100644 --- a/nzbtomedia/autoProcess/autoProcessComics.py +++ b/nzbtomedia/autoProcess/autoProcessComics.py @@ -14,11 +14,22 @@ class autoProcessComics: Logger.error("No directory was given!") return 1 # failure + # auto-detect correct section + section = [x for x in config.issubsection(inputCategory) if config()[x][inputCategory]['enabled'] == 1] + if len(section) > 1: + Logger.error( + "MAIN: You can't have multiple sub-sections with the same name enabled, fix your autoProcessMedia.cfg file.") + return 1 + elif len(section) == 0: + Logger.error( + "MAIN: We were unable to find a processor for category %s that was enabled, please check your autoProcessMedia.cfg file.", inputCategory) + return 1 + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. Logger.info("Loading config from %s", config.CONFIG_FILE) - section = "Mylar" + host = config()[section][inputCategory]["host"] port = config()[section][inputCategory]["port"] username = config()[section][inputCategory]["username"] diff --git a/nzbtomedia/autoProcess/autoProcessGames.py b/nzbtomedia/autoProcess/autoProcessGames.py index bb202481..be49daf4 100644 --- a/nzbtomedia/autoProcess/autoProcessGames.py +++ b/nzbtomedia/autoProcess/autoProcessGames.py @@ -13,13 +13,24 @@ class autoProcessGames: Logger.error("No directory was given!") return 1 # failure + # auto-detect correct section + section = [x for x in config.issubsection(inputCategory) if config()[x][inputCategory]['enabled'] == 1] + if len(section) > 1: + Logger.error( + "MAIN: You can't have multiple sub-sections with the same name enabled, fix your autoProcessMedia.cfg file.") + return 1 + elif len(section) == 0: + Logger.error( + "MAIN: We were unable to find a processor for category %s that was enabled, please check your autoProcessMedia.cfg file.", inputCategory) + return 1 + + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. Logger.info("Loading config from %s", config.CONFIG_FILE) status = int(status) - section = "Gamez" host = config()[section][inputCategory]["host"] port = config()[section][inputCategory]["port"] apikey = config()[section][inputCategory]["apikey"] diff --git a/nzbtomedia/autoProcess/autoProcessMovie.py b/nzbtomedia/autoProcess/autoProcessMovie.py index 186f9456..ea3cac60 100644 --- a/nzbtomedia/autoProcess/autoProcessMovie.py +++ b/nzbtomedia/autoProcess/autoProcessMovie.py @@ -165,12 +165,22 @@ class autoProcessMovie: Logger.error("No directory was given!") return 1 # failure + # auto-detect correct section + section = [x for x in config.issubsection(inputCategory) if config()[x][inputCategory]['enabled'] == 1] + if len(section) > 1: + Logger.error( + "MAIN: You can't have multiple sub-sections with the same name enabled, fix your autoProcessMedia.cfg file.") + return 1 + elif len(section) == 0: + Logger.error( + "MAIN: We were unable to find a processor for category %s that was enabled, please check your autoProcessMedia.cfg file.", inputCategory) + return 1 + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. Logger.info("Loading config from %s", config.CONFIG_FILE) status = int(status) - section = "CouchPotato" host = config()[section][inputCategory]["host"] port = config()[section][inputCategory]["port"] apikey = config()[section][inputCategory]["apikey"] @@ -178,6 +188,7 @@ class autoProcessMovie: method = config()[section][inputCategory]["method"] delete_failed = int(config()[section][inputCategory]["delete_failed"]) wait_for = int(config()[section][inputCategory]["wait_for"]) + try: TimePerGiB = int(config()[section][inputCategory]["TimePerGiB"]) except: diff --git a/nzbtomedia/autoProcess/autoProcessMusic.py b/nzbtomedia/autoProcess/autoProcessMusic.py index 9ea60b08..7854ebf9 100644 --- a/nzbtomedia/autoProcess/autoProcessMusic.py +++ b/nzbtomedia/autoProcess/autoProcessMusic.py @@ -14,13 +14,23 @@ class autoProcessMusic: Logger.error("No directory was given!") return 1 # failure + # auto-detect correct section + section = [x for x in config.issubsection(inputCategory) if config()[x][inputCategory]['enabled'] == 1] + if len(section) > 1: + Logger.error( + "MAIN: You can't have multiple sub-sections with the same name enabled, fix your autoProcessMedia.cfg file.") + return 1 + elif len(section) == 0: + Logger.error( + "MAIN: We were unable to find a processor for category %s that was enabled, please check your autoProcessMedia.cfg file.", inputCategory) + return 1 + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. Logger.info("Loading config from %s", config.CONFIG_FILE) status = int(status) - section = "HeadPhones" host = config()[section][inputCategory]["host"] port = config()[section][inputCategory]["port"] apikey = config()[section][inputCategory]["apikey"] diff --git a/nzbtomedia/autoProcess/autoProcessTV.py b/nzbtomedia/autoProcess/autoProcessTV.py index 9d176f8b..df2adf1f 100644 --- a/nzbtomedia/autoProcess/autoProcessTV.py +++ b/nzbtomedia/autoProcess/autoProcessTV.py @@ -14,18 +14,34 @@ from nzbtomedia.nzbToMediaUtil import convert_to_ascii, is_sample, flatten, getD Logger = logging.getLogger() class autoProcessTV: - def processEpisode(self, dirName, nzbName=None, failed=False, clientAgent = "manual", inputCategory=None): + def processEpisode(self, dirName, nzbName=None, failed=False, clientAgent = "manual", section=None, inputCategory=None): if dirName is None: Logger.error("No directory was given!") return 1 # failure + # auto-detect correct section + section = [x for x in config.issubsection(inputCategory) if config()[x][inputCategory]['enabled'] == 1] + if len(section) > 1: + Logger.error( + "MAIN: You can't have multiple sub-sections with the same name enabled, fix your autoProcessMedia.cfg file.") + return 1 + elif len(section) == 0: + Logger.error( + "MAIN: We were unable to find a processor for category %s that was enabled, please check your autoProcessMedia.cfg file.", inputCategory) + return 1 + + fork, fork_params = autoFork(section, inputCategory) + Torrent_NoLink = int(config()[section][inputCategory]["Torrent_NoLink"]) # 0 + if not fork in config.SICKBEARD_TORRENT and not Torrent_NoLink == 1: + if clientAgent in ['utorrent', 'transmission', 'deluge']: + return 1 + socket.setdefaulttimeout(int(config.NZBTOMEDIA_TIMEOUT)) #initialize socket timeout. Logger.info("Loading config from %s", config.CONFIG_FILE) status = int(failed) - section = "SickBeard" host = config()[section][inputCategory]["host"] port = config()[section][inputCategory]["port"] username = config()[section][inputCategory]["username"] @@ -90,9 +106,6 @@ class autoProcessTV: if os.path.isdir(SpecificPath): dirName = SpecificPath - # auto-detect fork type - fork, params = autoFork(section, inputCategory) - if fork not in config.SICKBEARD_TORRENT or (clientAgent in ['nzbget','sabnzbd'] and nzbExtractionBy != "Destination"): if nzbName: process_all_exceptions(nzbName.lower(), dirName) diff --git a/nzbtomedia/nzbToMediaConfig.py b/nzbtomedia/nzbToMediaConfig.py index 9034af8b..0ea6aa8b 100644 --- a/nzbtomedia/nzbToMediaConfig.py +++ b/nzbtomedia/nzbToMediaConfig.py @@ -1,7 +1,8 @@ +import logging import os import shutil -from itertools import chain from lib import configobj +from itertools import chain class config(object): # constants for nzbtomedia @@ -37,157 +38,191 @@ class config(object): TV_CONFIG_FILE = os.path.join(PROGRAM_DIR, "autoProcessTv.cfg") LOG_FILE = os.path.join(PROGRAM_DIR, "postprocess.log") LOG_CONFIG = os.path.join(PROGRAM_DIR, "logging.cfg") + SAMPLE_LOG_CONFIG = os.path.join(PROGRAM_DIR, "logging.cfg.sample") def __new__(cls, *config_file): try: # load config if not config_file: - return configobj.ConfigObj(cls.CONFIG_FILE) + return configobj.ConfigObj(cls.CONFIG_FILE, interpolation=False) else: - return configobj.ConfigObj(*config_file) + return configobj.ConfigObj(*config_file, interpolation=False) except Exception, e: return @staticmethod - def get_sections(section): - sections = {} + def issubsection(subsection, sections=None): + if not sections: + sections = config.__get_sections(subsection) + if not isinstance(sections, list): + sections = [sections] + + results = set() + for section in sections: + if config()[section].has_key(subsection): + results.add(section) + return results if results.issubset(sections) else False + + @staticmethod + def __get_sections(subsections): # check and return categories if section does exist - if not isinstance(section, list): - section = [section] + if not isinstance(subsections, list): + subsections = [subsections] - for x in section: - if config().has_key(x): - sections.update({x: config()[x].sections}) - return sections + to_return = [] + for subsection in subsections: + for section in config().sections: + if config()[section].has_key(subsection): + to_return.append(section) + return to_return + + @staticmethod + def get_subsections(sections): + # check and return categories if section does exist + if not isinstance(sections, list): + sections = [sections] + + to_return = {} + for section in sections: + if section in config().sections: + for subsection in config()[section].sections: + if not isinstance(subsection, list): + subsection = [subsection] + to_return.update({section: subsection}) + return to_return @staticmethod def migrate(): - categories = {} - confignew = None - configold = None + global config_new, config_old + config_new = config_old = None try: # 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) - except:pass + config_old = config(config.CONFIG_FILE) + except: + pass try: # 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) - except:pass + config_new = config(config.SAMPLE_CONFIG_FILE) + except: + pass # 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) or not confignew or not configold: + if not config() and not config(config.SAMPLE_CONFIG_FILE) or not config_new or not config_old: return False - for section in configold.sections: - for option, value in configold[section].items(): - if section == "CouchPotato": - if option == "category": # change this old format - option = "cpsCategory" - if section == "SickBeard": - if option == "category": # change this old format - option = "sbCategory" - if option in ["cpsCategory","sbCategory","hpCategory","mlCategory","gzCategory"]: + + subsections = {} + # gather all new-style and old-style sub-sections + for newsection, newitems in config_new.iteritems(): + if config_new[newsection].sections: + subsections.update({newsection: config_new[newsection].sections}) + for section, items in config_old.iteritems(): + if config_old[section].sections: + subsections.update({section: config_old[section].sections}) + for option, value in config_old[section].items(): + if option in ["category", "cpsCategory", "sbCategory", "hpCategory", "mlCategory", "gzCategory"]: if not isinstance(value, list): value = [value] - categories.update({section: value}) + # add subsection + subsections.update({section: value}) + config_old[section].pop(option) continue - try: - for section in configold.sections: - subsection = None - if section in list(chain.from_iterable(categories.values())): - subsection = section - section = ''.join([k for k, v in categories.iteritems() if subsection in v]) - elif section in categories.keys(): - subsection = categories[section][0] + def cleanup_values(values, section): + for option, value in values.iteritems(): + if section in ['CouchPotato']: + if option == ['outputDirectory']: + config_new['Torrent'][option] = os.path.split(os.path.normpath(value))[0] + values.pop(option) + if section in ['CouchPotato', 'HeadPhones', 'Gamez']: + if option in ['username', 'password']: + values.pop(option) + if section in ["SickBeard", "NzbDrone"]: + if option == "wait_for": # remove old format + values.pop(option) + if option == "failed_fork": # change this old format + values['failed'] = 'auto' + values.pop(option) + if option == "Torrent_ForceLink": + values['Torrent_NoLink'] = value + values.pop(option) + if option == "outputDirectory": # move this to new location format + config_new['Torrent'][option] = os.path.split(os.path.normpath(value))[0] + values.pop(option) + if section in ["Torrent"]: + if option in ["compressedExtensions", "mediaExtensions", "metaExtensions", "minSampleSize"]: + config_new['Extensions'][option] = value + values.pop(option) + 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' + return values - # create subsection if it does not exist - if subsection and subsection not in confignew[section].sections: - confignew[section][subsection] = {} + def process_section(section, subsections=None): + if subsections: + for subsection in subsections: + if subsection in config_old.sections: + values = config_old[subsection] + if subsection not in config_new[section].sections: + config_new[section][subsection] = {} + for option, value in values.items(): + config_new[section][subsection][option] = value + elif subsection in config_old[section].sections: + values = config_old[section][subsection] + if subsection not in config_new[section].sections: + config_new[section][subsection] = {} + for option, value in values.items(): + config_new[section][subsection][option] = value + else: + values = config_old[section] + if section not in config_new.sections: + config_new[section] = {} + for option, value in values.items(): + config_new[section][option] = value - for option, value in configold[section].items(): - if section == "CouchPotato": - if option == "outputDirectory": # move this to new location format - value = os.path.split(os.path.normpath(value))[0] - confignew['Torrent'][option] = value - continue - if option in ["username", "password"]: # these are no-longer needed. - continue - if option in ["category","cpsCategory"]: - continue - - if section == "SickBeard": - if option == "wait_for": # remove old format - continue - if option == "failed_fork": # change this old format - option = "fork" - value = "auto" - if option == "Torrent_ForceLink": - continue - if option == "outputDirectory": # move this to new location format - value = os.path.split(os.path.normpath(value))[0] - confignew['Torrent'][option] = value - continue - if option in ["category", "sbCategory"]: - continue - - if section == "HeadPhones": - if option in ["username", "password" ]: - continue - if option == "hpCategory": - continue - - if section == "Mylar": - if option in "mlCategory": - continue - - if section == "Gamez": - if option in ["username", "password"]: # these are no-longer needed. - continue - if option == "gzCategory": - continue - - 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" - - if subsection: - confignew[section][subsection][option] = value - else: - confignew[section][option] = value - except:pass + # convert old-style categories to new-style sub-sections + for section in config_old.keys(): + subsection = None + if section in list(chain.from_iterable(subsections.values())): + subsection = section + section = ''.join([k for k,v in subsections.iteritems() if subsection in v]) + process_section(section, subsection) + #[[v.remove(c) for c in v if c in subsection] for k, v in subsections.items() if k == section] + elif section in subsections.keys(): + subsection = subsections[section] + process_section(section, subsection) + #[[v.remove(c) for c in v if c in subsection] for k,v in subsections.items() if k == section] + elif section in config_old.keys(): + process_section(section, subsection) # 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 + 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) + config_new.write(configFile) return True @staticmethod def addnzbget(): - confignew = config() + config_new = config() section = "CouchPotato" envCatKey = 'NZBPO_CPSCATEGORY' envKeys = ['APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'DELAY', 'METHOD', 'DELETE_FAILED', 'REMOTECPS', 'WAIT_FOR', 'TIMEPERGIB'] @@ -198,9 +233,9 @@ class config(object): if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] - if os.environ[envCatKey] not in confignew[section].sections: - confignew[section][os.environ[envCatKey]] = {} - confignew[section][os.environ[envCatKey]][option] = value + if os.environ[envCatKey] not in config_new[section].sections: + config_new[section][os.environ[envCatKey]] = {} + config_new[section][os.environ[envCatKey]][option] = value section = "SickBeard" envCatKey = 'NZBPO_SBCATEGORY' @@ -212,9 +247,9 @@ class config(object): if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] - if os.environ[envCatKey] not in confignew[section].sections: - confignew[section][os.environ[envCatKey]] = {} - confignew[section][os.environ[envCatKey]][option] = value + if os.environ[envCatKey] not in config_new[section].sections: + config_new[section][os.environ[envCatKey]] = {} + config_new[section][os.environ[envCatKey]][option] = value section = "HeadPhones" envCatKey = 'NZBPO_HPCATEGORY' @@ -226,9 +261,9 @@ class config(object): if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] - if os.environ[envCatKey] not in confignew[section].sections: - confignew[section][os.environ[envCatKey]] = {} - confignew[section][os.environ[envCatKey]][option] = value + if os.environ[envCatKey] not in config_new[section].sections: + config_new[section][os.environ[envCatKey]] = {} + config_new[section][os.environ[envCatKey]][option] = value section = "Mylar" envCatKey = 'NZBPO_MYCATEGORY' @@ -240,9 +275,9 @@ class config(object): if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] - if os.environ[envCatKey] not in confignew[section].sections: - confignew[section][os.environ[envCatKey]] = {} - confignew[section][os.environ[envCatKey]][option] = value + if os.environ[envCatKey] not in config_new[section].sections: + config_new[section][os.environ[envCatKey]] = {} + config_new[section][os.environ[envCatKey]][option] = value section = "Gamez" envCatKey = 'NZBPO_GZCATEGORY' @@ -254,9 +289,9 @@ class config(object): if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] - if os.environ[envCatKey] not in confignew[section].sections: - confignew[section][os.environ[envCatKey]] = {} - confignew[section][os.environ[envCatKey]][option] = value + if os.environ[envCatKey] not in config_new[section].sections: + config_new[section][os.environ[envCatKey]] = {} + config_new[section][os.environ[envCatKey]][option] = value section = "Extensions" envKeys = ['COMPRESSEDEXTENSIONS', 'MEDIAEXTENSIONS', 'METAEXTENSIONS'] @@ -266,7 +301,7 @@ class config(object): if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] - confignew[section][option] = value + config_new[section][option] = value section = "Transcoder" envKeys = ['TRANSCODE', 'DUPLICATE', 'IGNOREEXTENSIONS', 'OUTPUTVIDEOEXTENSION', 'OUTPUTVIDEOCODEC', 'OUTPUTVIDEOPRESET', 'OUTPUTVIDEOFRAMERATE', 'OUTPUTVIDEOBITRATE', 'OUTPUTAUDIOCODEC', 'OUTPUTAUDIOBITRATE', 'OUTPUTSUBTITLECODEC'] @@ -276,7 +311,7 @@ class config(object): if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] - confignew[section][option] = value + config_new[section][option] = value section = "WakeOnLan" envKeys = ['WAKE', 'HOST', 'PORT', 'MAC'] @@ -286,7 +321,7 @@ class config(object): if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] - confignew[section][option] = value + config_new[section][option] = value # create a backup of our old config if os.path.isfile(config.CONFIG_FILE): @@ -297,4 +332,4 @@ class config(object): # writing our configuration file to 'autoProcessMedia.cfg' with open(config.CONFIG_FILE, 'wb') as configFile: - confignew.write(configFile) \ No newline at end of file + config_new.write(configFile) \ No newline at end of file diff --git a/nzbtomedia/nzbToMediaUtil.py b/nzbtomedia/nzbToMediaUtil.py index 7abe2894..3c9f2263 100644 --- a/nzbtomedia/nzbToMediaUtil.py +++ b/nzbtomedia/nzbToMediaUtil.py @@ -51,6 +51,9 @@ def create_destination(outputDestination): sys.exit(-1) def category_search(inputDirectory, inputName, inputCategory, root, categories): + if inputDirectory is None: + return inputDirectory, inputName, inputCategory, root + if not os.path.isdir(inputDirectory) and os.path.isfile(inputDirectory): # If the input directory is a file, assume single file downlaod and split dir/name. inputDirectory,inputName = os.path.split(os.path.normpath(inputDirectory)) @@ -327,14 +330,13 @@ def TestCon(host, port): def WakeUp(): if not config(): - Logger.error("You need an autoProcessMedia.config() file - did you rename and edit the .sample?") + Logger.error("You need an autoProcessMedia.cfg file - did you rename and edit the .sample?") return wake = int(config()["WakeOnLan"]["wake"]) if wake == 0: # just return if we don't need to wake anything. return Logger.info("Loading WakeOnLan config from %s", config.CONFIG_FILE) - config()["WakeOnLan"]["host"] host = config()["WakeOnLan"]["host"] port = int(config()["WakeOnLan"]["port"]) mac = config()["WakeOnLan"]["mac"] @@ -376,6 +378,7 @@ def convert_to_ascii(nzbName, dirName): return nzbName, dirName def parse_other(args): + return os.path.normpath(args[1]), '', '', '', '' def parse_rtorrent(args): @@ -449,40 +452,49 @@ def parse_args(clientAgent): 'transmission': parse_transmission, } - return clients[clientAgent](sys.argv) + try: + return clients[clientAgent](sys.argv) + except:return None, None, None, None, None -def get_dirnames(section, inputCategory): +def get_dirnames(section, subsections=None): dirNames = [] - try: - watch_dir = config()[section][inputCategory]["watch_dir"] - if not os.path.exists(watch_dir): - watch_dir = "" - except: - watch_dir = "" + if subsections is None: + subsections = config.get_subsections(section).values() - try: - outputDirectory = os.path.join(config()["Torrent"]["outputDirectory"], inputCategory) - if not os.path.exists(watch_dir): - outputDirectory = "" - except: - outputDirectory = "" + if not isinstance(subsections, list): + subsections = [subsections] - if watch_dir != "": - dirNames.extend([os.path.join(watch_dir, o) for o in os.listdir(watch_dir) if - os.path.isdir(os.path.join(watch_dir, o))]) - if not dirNames: - Logger.warn("No Directories identified to Scan inside " + watch_dir) + for subsection in subsections: + try: + watch_dir = config()[section][subsection]["watch_dir"] + if not os.path.exists(watch_dir): + watch_dir = None + except: + watch_dir = None - if outputDirectory != "": - dirNames.extend([os.path.join(outputDirectory, o) for o in os.listdir(outputDirectory) if - os.path.isdir(os.path.join(outputDirectory, o))]) - if not dirNames: - Logger.warn("No Directories identified to Scan inside " + outputDirectory) + try: + outputDirectory = os.path.join(config()["Torrent"]["outputDirectory"], subsection) + if not os.path.exists(outputDirectory): + outputDirectory = None + except: + outputDirectory = None - if watch_dir == "" and outputDirectory == "": - Logger.warn("No watch_dir or outputDirectory setup to be Scanned, go fix you autoProcessMedia.cfg file.") + if watch_dir: + dirNames.extend([os.path.join(watch_dir, o) for o in os.listdir(watch_dir) if + os.path.isdir(os.path.join(watch_dir, o))]) + if not dirNames: + Logger.warn("%s:%s has no directories identified to scan inside %s", section, subsection, watch_dir) + + if outputDirectory: + dirNames.extend([os.path.join(outputDirectory, o) for o in os.listdir(outputDirectory) if + os.path.isdir(os.path.join(outputDirectory, o))]) + if not dirNames: + Logger.warn("%s:%s has no directories identified to scan inside %s", section, subsection, outputDirectory) + + if watch_dir is None and outputDirectory is None: + Logger.warn("%s:%s has no watch_dir or outputDirectory setup to be Scanned, go fix you autoProcessMedia.cfg file.", section, subsection) return dirNames