def get_nzoid(inputName): nzoid = None logger.debug("Searching for nzoid from SAbnzbd ...") baseURL = "http://%s:%s/api" % (nzbtomedia.SABNZBDHOST, nzbtomedia.SABNZBDPORT) url = baseURL params = {} params['apikey'] = nzbtomedia.SABNZBDAPIKEY params['mode'] = "queue" params['output'] = 'json' try: r = requests.get(url, params=params, verify=False) except requests.ConnectionError: logger.error("Unable to open URL") return nzoid # failure try: result = r.json() cleanName = os.path.splitext(os.path.split(inputName)[1])[0] for slot in result['queue']['slots']: if slot['filename'] in [inputName, cleanName]: nzoid = slot['nzo_id'] logger.debug("Found nzoid: %s" % nzoid) break except: logger.warning("Data from SABnzbd could not be parsed") return nzoid
def get_dirnames(section, subsections=None): dirNames = [] if subsections is None: subsections = nzbtomedia.SUBSECTIONS[section].sections if not isinstance(subsections, list): subsections = [subsections] for subsection in subsections: try: watch_dir = nzbtomedia.CFG[section][subsection]["watch_dir"] if not os.path.exists(watch_dir): watch_dir = None except: watch_dir = None try: outputDirectory = os.path.join(nzbtomedia.OUTPUTDIRECTORY, subsection) if not os.path.exists(outputDirectory): outputDirectory = None except: outputDirectory = None if watch_dir: # search for single files and move them into there own folder for post-processing for mediafile in listMediaFiles(watch_dir): parentDir = os.path.dirname(mediafile) if parentDir == watch_dir: p = os.path.join(parentDir, (os.path.splitext(os.path.splitext(mediafile)[0])[0])) if not os.path.exists(p): os.mkdir(p) shutil.move(mediafile, p) 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 outputDirectory: # search for single files and move them into there own folder for post-processing for mediafile in listMediaFiles(outputDirectory): parentDir = os.path.dirname(mediafile) if parentDir == outputDirectory: p = os.path.join(parentDir, (os.path.splitext(os.path.splitext(mediafile)[0])[0])) if not os.path.exists(p): os.mkdir(p) shutil.move(mediafile, p) 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.warning("%s:%s has no directories identified for post-processing" % (section, subsection)) return list(set(dirNames))
def rmReadOnly(filename): if os.path.isfile(filename): #check first the read-only attribute file_attribute = os.stat(filename)[0] if (not file_attribute & stat.S_IWRITE): # File is read-only, so make it writeable logger.debug('Read only mode on file ' + filename + ' Will try to make it writeable') try: os.chmod(filename, stat.S_IWRITE) except: logger.warning('Cannot change permissions of ' + filename, logger.WARNING)
def pause_torrent(clientAgent, inputHash, inputID, inputName): logger.debug("Stopping torrent %s in %s while processing" % (inputName, clientAgent)) try: if clientAgent == 'utorrent' and nzbtomedia.TORRENT_CLASS != "": nzbtomedia.TORRENT_CLASS.stop(inputHash) if clientAgent == 'transmission' and nzbtomedia.TORRENT_CLASS != "": nzbtomedia.TORRENT_CLASS.stop_torrent(inputID) if clientAgent == 'deluge' and nzbtomedia.TORRENT_CLASS != "": nzbtomedia.TORRENT_CLASS.core.pause_torrent([inputID]) time.sleep(5) except: logger.warning("Failed to stop torrent %s in %s" % (inputName, clientAgent))
def resume_torrent(clientAgent, inputHash, inputID, inputName): logger.debug("Starting torrent %s in %s" % (inputName, clientAgent)) try: if clientAgent == 'utorrent' and nzbtomedia.TORRENT_CLASS != "": nzbtomedia.TORRENT_CLASS.start(inputHash) if clientAgent == 'transmission' and nzbtomedia.TORRENT_CLASS != "": nzbtomedia.TORRENT_CLASS.start_torrent(inputID) if clientAgent == 'deluge' and nzbtomedia.TORRENT_CLASS != "": nzbtomedia.TORRENT_CLASS.core.resume_torrent([inputID]) time.sleep(5) except: logger.warning("Failed to start torrent %s in %s" % (inputName, clientAgent))
def copy_link(src, targetLink, useLink): logger.info("MEDIAFILE: [%s]" % (os.path.basename(targetLink)), 'COPYLINK') logger.info("SOURCE FOLDER: [%s]" % (os.path.dirname(src)), 'COPYLINK') logger.info("TARGET FOLDER: [%s]" % (os.path.dirname(targetLink)), 'COPYLINK') if src != targetLink and os.path.exists(targetLink): logger.info( "MEDIAFILE already exists in the TARGET folder, skipping ...", 'COPYLINK') return True elif src == targetLink and os.path.isfile(targetLink) and os.path.isfile( src): logger.info("SOURCE AND TARGET files are the same, skipping ...", 'COPYLINK') return True elif src == os.path.dirname(targetLink): logger.info("SOURCE AND TARGET folders are the same, skipping ...", 'COPYLINK') return True makeDir(os.path.dirname(targetLink)) try: if useLink == 'dir': logger.info("Directory linking SOURCE FOLDER -> TARGET FOLDER", 'COPYLINK') linktastic.dirlink(src, targetLink) return True if useLink == 'junction': logger.info( "Directory junction linking SOURCE FOLDER -> TARGET FOLDER", 'COPYLINK') linktastic.dirlink(src, targetLink) return True elif useLink == "hard": logger.info("Hard linking SOURCE MEDIAFILE -> TARGET FOLDER", 'COPYLINK') linktastic.link(src, targetLink) return True elif useLink == "sym": logger.info("Sym linking SOURCE MEDIAFILE -> TARGET FOLDER", 'COPYLINK') shutil.move(src, targetLink) linktastic.symlink(targetLink, src) return True elif useLink == "move": logger.info("Moving SOURCE MEDIAFILE -> TARGET FOLDER", 'COPYLINK') shutil.move(src, targetLink) return True except Exception, e: logger.warning("Error: %s, copying instead ... " % (e), 'COPYLINK')
def main(args): # Initialize the config nzbtomedia.initialize() # clientAgent for Torrents clientAgent = nzbtomedia.TORRENT_CLIENTAGENT logger.info("#########################################################") logger.info("## ..::[%s]::.. CLIENT:%s ## STARTING" % (args[0], clientAgent)) logger.info("#########################################################") # debug command line options logger.debug("Options passed into TorrentToMedia: %s" % (args)) # Post-Processing Result result = 0 try: inputDirectory, inputName, inputCategory, inputHash, inputID = parse_args(clientAgent, args) except: logger.error("There was a problem loading variables") return -1 if inputDirectory and inputName and inputHash and inputID: result = processTorrent(inputDirectory, inputName, inputCategory, inputHash, inputID, clientAgent) else: # Perform Manual Run logger.warning("Invalid number of arguments received from client, Switching to manual run mode ...") # Loop and auto-process clientAgent = 'manual' for section, subsection in nzbtomedia.SUBSECTIONS.items(): for category in subsection: if nzbtomedia.CFG[section][category].isenabled(): dirNames = get_dirnames(section, category) for dirName in dirNames: logger.info("Running %s:%s as a manual run for folder %s ..." % (section, category, dirName)) results = processTorrent(dirName, os.path.basename(dirName), category, inputHash, inputID, clientAgent) if results != 0: result = results logger.error("A problem was reported when trying to manually run %s:%s." % (section, category)) else: logger.warning("%s:%s is DISABLED, you can enable this in autoProcessMedia.cfg ..." % (section, category)) if result == 0: logger.info("The %s script completed successfully." % (args[0])) else: logger.error("A problem was reported in the %s script." % (args[0])) sys.exit(result)
def replace_filename(filename, dirname, name): head, fileExtension = os.path.splitext(os.path.basename(filename)) if media_pattern.search(os.path.basename(dirname).replace(' ','.')) is not None: newname = os.path.basename(dirname).replace(' ', '.') logger.debug("Replacing file name %s with directory name %s" % (head, newname), "EXCEPTION") elif media_pattern.search(name.replace(' ','.').lower()) is not None: newname = name.replace(' ', '.') logger.debug("Replacing file name %s with download name %s" % (head, newname), "EXCEPTION") else: logger.warning("No name replacement determined for %s" % (head), "EXCEPTION") return newfile = newname + fileExtension newfilePath = os.path.join(dirname, newfile) return newfilePath
def find_imdbid(dirName, inputName): imdbid = None logger.info('Attemping imdbID lookup for %s' % (inputName)) # find imdbid in dirName logger.info('Searching folder and file names for imdbID ...') m = re.search('(tt\d{7})', dirName + inputName) if m: imdbid = m.group(1) logger.info("Found imdbID [%s]" % imdbid) return imdbid logger.info('Searching IMDB for imdbID ...') guess = guessit.guess_movie_info(inputName) if guess: # Movie Title title = None if 'title' in guess: title = guess['title'] # Movie Year year = None if 'year' in guess: year = guess['year'] url = "http://www.omdbapi.com" logger.debug("Opening URL: %s" % url) try: r = requests.get(url, params={'y': year, 't': title}, verify=False) except requests.ConnectionError: logger.error("Unable to open URL %s" % url) return results = r.json() try: imdbid = results['imdbID'] except: pass if imdbid: logger.info("Found imdbID [%s]" % imdbid) return imdbid logger.warning('Unable to find a imdbID for %s' % (inputName))
def find_imdbid(dirName, inputName): imdbid = None logger.info('Attemping imdbID lookup for %s' % (inputName)) # find imdbid in dirName logger.info('Searching folder and file names for imdbID ...') m = re.search('(tt\d{7})', dirName+inputName) if m: imdbid = m.group(1) logger.info("Found imdbID [%s]" % imdbid) return imdbid logger.info('Searching IMDB for imdbID ...') guess = guessit.guess_movie_info(inputName) if guess: # Movie Title title = None if 'title' in guess: title = guess['title'] # Movie Year year = None if 'year' in guess: year = guess['year'] url = "http://www.omdbapi.com" logger.debug("Opening URL: %s" % url) try: r = requests.get(url, params={'y': year, 't': title}, verify=False) except requests.ConnectionError: logger.error("Unable to open URL %s" % url) return results = r.json() try: imdbid = results['imdbID'] except: pass if imdbid: logger.info("Found imdbID [%s]" % imdbid) return imdbid logger.warning('Unable to find a imdbID for %s' % (inputName))
def remove_torrent(clientAgent, inputHash, inputID, inputName): if nzbtomedia.DELETE_ORIGINAL == 1 or nzbtomedia.USELINK == 'move': logger.debug("Deleting torrent %s from %s" % (inputName, clientAgent)) try: if clientAgent == 'utorrent' and nzbtomedia.TORRENT_CLASS != "": nzbtomedia.TORRENT_CLASS.removedata(inputHash) nzbtomedia.TORRENT_CLASS.remove(inputHash) if clientAgent == 'transmission' and nzbtomedia.TORRENT_CLASS != "": nzbtomedia.TORRENT_CLASS.remove_torrent(inputID, True) if clientAgent == 'deluge' and nzbtomedia.TORRENT_CLASS != "": nzbtomedia.TORRENT_CLASS.core.remove_torrent(inputID, True) time.sleep(5) except: logger.warning("Failed to delete torrent %s in %s" % (inputName, clientAgent)) else: resume_torrent(clientAgent, inputHash, inputID, inputName)
def WakeUp(): host = nzbtomedia.CFG["WakeOnLan"]["host"] port = int(nzbtomedia.CFG["WakeOnLan"]["port"]) mac = nzbtomedia.CFG["WakeOnLan"]["mac"] i = 1 while TestCon(host, port) == "Down" and i < 4: logger.info(("Sending WakeOnLan Magic Packet for mac: %s" % (mac))) WakeOnLan(mac) time.sleep(20) i = i + 1 if TestCon(host, port) == "Down": # final check. logger.warning("System with mac: %s has not woken after 3 attempts. Continuing with the rest of the script." % ( mac)) else: logger.info("System with mac: %s has been woken. Continuing with the rest of the script." % (mac))
def replace_filename(filename, dirname, name): head, fileExtension = os.path.splitext(os.path.basename(filename)) if media_pattern.search(os.path.basename(dirname)) is not None: newname = os.path.basename(dirname) logger.debug("Replacing file name %s with directory name %s" % (head, newname), "EXCEPTION") elif media_pattern.search(name) is not None: newname = name logger.debug("Replacing file name %s with download name %s" % (head, newname), "EXCEPTION") else: logger.warning("No name replacement determined for %s" % (head), "EXCEPTION") return newfile = newname + fileExtension newfilePath = os.path.join(dirname, newfile) try: os.rename(filename, newfilePath) except Exception,e: logger.error("Unable to rename file due to: %s" % (str(e)), "EXCEPTION")
def replace_filename(filename, dirname, name): head, fileExtension = os.path.splitext(os.path.basename(filename)) if media_pattern.search(os.path.basename(dirname).replace( ' ', '.')) is not None: newname = os.path.basename(dirname).replace(' ', '.') logger.debug( "Replacing file name %s with directory name %s" % (head, newname), "EXCEPTION") elif media_pattern.search(name.replace(' ', '.').lower()) is not None: newname = name.replace(' ', '.') logger.debug( "Replacing file name %s with download name %s" % (head, newname), "EXCEPTION") else: logger.warning("No name replacement determined for %s" % (head), "EXCEPTION") newname = name newfile = newname + fileExtension newfilePath = os.path.join(dirname, newfile) return newfilePath
def copy_link(src, targetLink, useLink): logger.info("MEDIAFILE: [%s]" % (os.path.basename(targetLink)), 'COPYLINK') logger.info("SOURCE FOLDER: [%s]" % (os.path.dirname(src)), 'COPYLINK') logger.info("TARGET FOLDER: [%s]" % (os.path.dirname(targetLink)), 'COPYLINK') if src != targetLink and os.path.exists(targetLink): logger.info("MEDIAFILE already exists in the TARGET folder, skipping ...", 'COPYLINK') return True elif src == targetLink and os.path.isfile(targetLink) and os.path.isfile(src): logger.info("SOURCE AND TARGET files are the same, skipping ...", 'COPYLINK') return True elif src == os.path.dirname(targetLink): logger.info("SOURCE AND TARGET folders are the same, skipping ...", 'COPYLINK') return True makeDir(os.path.dirname(targetLink)) try: if useLink == 'dir': logger.info("Directory linking SOURCE FOLDER -> TARGET FOLDER", 'COPYLINK') linktastic.dirlink(src, targetLink) return True if useLink == 'junction': logger.info("Directory junction linking SOURCE FOLDER -> TARGET FOLDER", 'COPYLINK') linktastic.dirlink(src, targetLink) return True elif useLink == "hard": logger.info("Hard linking SOURCE MEDIAFILE -> TARGET FOLDER", 'COPYLINK') linktastic.link(src, targetLink) return True elif useLink == "sym": logger.info("Sym linking SOURCE MEDIAFILE -> TARGET FOLDER", 'COPYLINK') shutil.move(src, targetLink) linktastic.symlink(targetLink, src) return True elif useLink == "move": logger.info("Moving SOURCE MEDIAFILE -> TARGET FOLDER", 'COPYLINK') shutil.move(src, targetLink) return True except Exception, e: logger.warning("Error: %s, copying instead ... " % (e), 'COPYLINK')
def copy_link(filePath, targetDirectory, useLink, outputDestination): if os.path.isfile(targetDirectory): logger.info("COPYLINK: target file already exists. Nothing to be done") return True makeDir(outputDestination) if useLink == "hard": try: logger.info("COPYLINK: Hard linking %s to %s" % (filePath, targetDirectory)) linktastic.link(filePath, targetDirectory) except: logger.error("COPYLINK") if os.path.isfile(targetDirectory): logger.warning( "COPYLINK: Something went wrong in linktastic.link, but the destination file was created") else: logger.warning("COPYLINK: Something went wrong in linktastic.link, copying instead") logger.debug("COPYLINK: Copying %s to %s" % (filePath, targetDirectory)) shutil.copy(filePath, targetDirectory) elif useLink == "sym": try: logger.info("COPYLINK: Moving %s to %s before sym linking" % (filePath, targetDirectory)) shutil.move(filePath, targetDirectory) logger.info("COPYLINK: Sym linking %s to %s" % (targetDirectory, filePath)) linktastic.symlink(targetDirectory, filePath) except: logger.error("COPYLINK") if os.path.isfile(targetDirectory): logger.warning( "COPYLINK: Something went wrong in linktastic.link, but the destination file was created") else: logger.info("COPYLINK: Something went wrong in linktastic.link, copying instead") logger.debug("COPYLINK: Copying %s to %s" % (filePath, targetDirectory)) shutil.copy(filePath, targetDirectory) elif useLink == "move": logger.debug("Moving %s to %s" % (filePath, targetDirectory)) shutil.move(filePath, targetDirectory) else: logger.debug("Copying %s to %s" % (filePath, targetDirectory)) shutil.copy(filePath, targetDirectory) return True
def processEpisode(self, section, dirName, inputName=None, failed=False, clientAgent="manual", inputCategory=None): # auto-detect correct fork fork, fork_params = autoFork(section, inputCategory) # Check video files for corruption status = int(failed) for video in listMediaFiles(dirName): if not transcoder.isVideoGood(video): status = 1 host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] try: username = nzbtomedia.CFG[section][inputCategory]["username"] password = nzbtomedia.CFG[section][inputCategory]["password"] except: username = "" password = "" try: apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] except: apikey = "" try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: delete_failed = int( nzbtomedia.CFG[section][inputCategory]["delete_failed"]) except: delete_failed = 0 try: nzbExtractionBy = nzbtomedia.CFG[section][inputCategory][ "nzbExtractionBy"] except: nzbExtractionBy = "Downloader" try: process_method = nzbtomedia.CFG[section][inputCategory][ "process_method"] except: process_method = None try: remote_path = int( nzbtomedia.CFG[section][inputCategory]["remote_path"]) except: remote_path = 0 try: wait_for = int(nzbtomedia.CFG[section][inputCategory]["wait_for"]) except: wait_for = 2 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(inputName)) cleanName = os.path.splitext(SpecificPath) if cleanName[1] == ".nzb": SpecificPath = cleanName[0] if os.path.isdir(SpecificPath): dirName = SpecificPath if fork not in nzbtomedia.SICKBEARD_TORRENT or ( clientAgent in ['nzbget', 'sabnzbd'] and nzbExtractionBy != "Destination"): if inputName: process_all_exceptions(inputName.lower(), dirName) inputName, dirName = convert_to_ascii(inputName, dirName) # Now check if tv files exist in destination. Eventually extraction may be done here if nzbExtractionBy == TorrentToMedia if listMediaFiles( dirName ): # 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), section) 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), section) status = 1 failed = 1 # configure SB params to pass fork_params['quiet'] = 1 if inputName is not None: fork_params['nzbName'] = inputName for param in copy.copy(fork_params): if param == "failed": fork_params[param] = failed if param in ["dirName", "dir"]: fork_params[param] = dirName if remote_path: fork_params[param] = remoteDir(dirName) if param == "process_method": if process_method: fork_params[param] = process_method else: del fork_params[param] # delete any unused params so we don't pass them to SB by mistake [fork_params.pop(k) for k, v in fork_params.items() if v is None] if status == 0: logger.postprocess( "SUCCESS: The download succeeded, sending a post-process request", section) else: if fork in nzbtomedia.SICKBEARD_FAILED or section == "NzbDrone": logger.postprocess( "FAILED: The download failed. Sending 'failed' process request to %s branch" % (fork), section) else: logger.postprocess( "FAILED: The download failed. %s branch does not handle failed downloads. Nothing to process" % (fork), section) if delete_failed and os.path.isdir( dirName) and not os.path.dirname(dirName) == dirName: logger.postprocess( "Deleting failed files and folder %s" % (dirName), section) rmDir(dirName) return 0 # Success (as far as this script is concerned) if status == 0 and nzbtomedia.TRANSCODE == 1: # only transcode successful downlaods result = transcoder.Transcode_directory(dirName) if result == 0: logger.debug( "SUCCESS: Transcoding succeeded for files in %s" % (dirName), section) else: logger.warning( "FAILED: Transcoding failed for files in %s" % (dirName), section) if ssl: protocol = "https://" else: protocol = "http://" url = None if section == "SickBeard": url = "%s%s:%s%s/home/postprocess/processEpisode" % ( protocol, host, port, web_root) elif section == "NzbDrone": url = "%s%s:%s%s/api/command" % (protocol, host, port, web_root) url1 = "%s%s:%s%s/api/missing" % (protocol, host, port, web_root) headers = {"X-Api-Key": apikey} params = { 'sortKey': 'series.title', 'page': 1, 'pageSize': 1, 'sortDir': 'asc' } if remote_path: data = json.dumps({ "name": "DownloadedEpisodesScan", "path": remote_path }) else: data = json.dumps({ "name": "DownloadedEpisodesScan", "path": dirName }) logger.debug("Opening URL: %s" % (url), section) try: if section == "SickBeard": r = None r = requests.get(url, auth=(username, password), params=fork_params, stream=True, verify=False) elif section == "NzbDrone": start_numMissing = self.numMissing( url1, params, headers) # get current number of outstanding eppisodes. r = None r = requests.post(url, data=data, headers=headers, stream=True, verify=False) except requests.ConnectionError: logger.error("Unable to open URL: %s" % (url), section) return 1 # failure if not r.status_code in [ requests.codes.ok, requests.codes.created, requests.codes.accepted ]: logger.error("Server returned status %s" % (str(r.status_code)), section) return 1 Success = False Started = False for line in r.iter_lines(): if line: logger.postprocess("%s" % (line), section) if section == "SickBeard" and "Processing succeeded" in line: Success = True elif section == "NzbDrone" and "stateChangeTime" in line: Started = True if status != 0 and delete_failed and not os.path.dirname( dirName) == dirName: logger.postprocess( "Deleting failed files and folder %s" % (dirName), section) rmDir(dirName) if Success: return 0 elif section == "NzbDrone" and Started: n = 0 current_numMissing = start_numMissing while n < 6: # set up wait_for minutes of no change in numMissing. time.sleep(10 * wait_for) new_numMissing = self.numMissing(url1, params, headers) if new_numMissing == current_numMissing: # nothing processed since last call n += 1 else: n = 0 current_numMissing = new_numMissing # reset counter and start loop again with this many missing. if current_numMissing < start_numMissing: logger.debug( "The number of missing episodes changes from %s to %s and then remained the same for %s minutes. Consider this successful" % (str(start_numMissing), str(current_numMissing), str(wait_for)), section) return 0 else: # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resume seeding now. logger.warning( "The number of missing episodes: %s does not appear to have changed status after %s minutes, Please check your logs." % (str(start_numMissing), str(wait_for)), section) return 1 else: return 1 # We did not receive Success confirmation.
def main(args, section=None): # Initialize the config nzbtomedia.initialize(section) # clientAgent for NZBs clientAgent = nzbtomedia.NZB_CLIENTAGENT logger.info("#########################################################") logger.info("## ..::[%s]::.. ##" % os.path.basename(__file__)) logger.info("#########################################################") # debug command line options logger.debug("Options passed into nzbToMedia: %s" % args) # Post-Processing Result result = 0 status = 0 # NZBGet if os.environ.has_key('NZBOP_SCRIPTDIR'): # Check if the script is called from nzbget 11.0 or later if os.environ['NZBOP_VERSION'][0:5] < '11.0': logger.error("NZBGet Version %s is not supported. Please update NZBGet." %(str(os.environ['NZBOP_VERSION']))) sys.exit(nzbtomedia.NZBGET_POSTPROCESS_ERROR) logger.info("Script triggered from NZBGet Version %s." %(str(os.environ['NZBOP_VERSION']))) # Check if the script is called from nzbget 13.0 or later if os.environ.has_key('NZBPP_TOTALSTATUS'): if not os.environ['NZBPP_TOTALSTATUS'] == 'SUCCESS': logger.info("Download failed with status %s." %(os.environ['NZBPP_STATUS'])) status = 1 else: # Check par status if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4': logger.warning("Par-repair failed, setting status \"failed\"") status = 1 # Check unpack status if os.environ['NZBPP_UNPACKSTATUS'] == '1': logger.warning("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( "Download health is compromised and Par-check/repair disabled or no .par2 files found. Setting status \"failed\"") logger.info("Please check your Par-check/repair settings for future downloads.") status = 1 else: logger.info( "Par-check/repair disabled or no .par2 files found, and Unpack not required. Health is ok so handle as though download successful") logger.info("Please check your Par-check/repair settings for future downloads.") # Check for download_id to pass to CouchPotato download_id = "" if os.environ.has_key('NZBPR_COUCHPOTATO'): download_id = os.environ['NZBPR_COUCHPOTATO'] # All checks done, now launching the script. clientAgent = 'nzbget' result = process(os.environ['NZBPP_DIRECTORY'], inputName=os.environ['NZBPP_NZBNAME'], status=status, clientAgent=clientAgent, download_id=download_id, inputCategory=os.environ['NZBPP_CATEGORY']) # SABnzbd Pre 0.7.17 elif len(args) == nzbtomedia.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 clientAgent = 'sabnzbd' logger.info("Script triggered from SABnzbd") result = process(args[1], inputName=args[2], status=args[7], inputCategory=args[5], clientAgent=clientAgent, download_id='') # SABnzbd 0.7.17+ elif len(args) >= nzbtomedia.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 clientAgent = 'sabnzbd' logger.info("Script triggered from SABnzbd 0.7.17+") result = process(args[1], inputName=args[2], status=args[7], inputCategory=args[5], clientAgent=clientAgent, download_id='') else: # Perform Manual Post-Processing logger.warning("Invalid number of arguments received from client, Switching to manual run mode ...") for section, subsections in nzbtomedia.SECTIONS.items(): for subsection in subsections: for dirName in getDirs(section, subsection): logger.info("Starting manual run for %s:%s - Folder:%s" % (section, subsection, dirName)) logger.info("Checking database for download info for %s ..." % (os.path.basename(dirName))) nzbtomedia.DOWNLOADINFO = get_downloadInfo(os.path.basename(dirName), 0) if nzbtomedia.DOWNLOADINFO: logger.info( "Found download info for %s, setting variables now ..." % (os.path.basename(dirName))) else: logger.info( 'Unable to locate download info for %s, continuing to try and process this release ...' % ( os.path.basename(dirName)) ) try: clientAgent = str(nzbtomedia.DOWNLOADINFO[0]['client_agent']) except: clientAgent = 'manual' try: download_id = str(nzbtomedia.DOWNLOADINFO[0]['input_id']) except: download_id = None if clientAgent.lower() not in nzbtomedia.NZB_CLIENTS and clientAgent != 'manual': continue results = process(dirName, os.path.basename(dirName), 0, clientAgent=clientAgent, download_id=download_id, inputCategory=subsection) if results != 0: logger.error("A problem was reported when trying to perform a manual run for %s:%s." % ( section, subsection)) result = results if result == 0: logger.info("The %s script completed successfully." % args[0]) if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 del nzbtomedia.MYAPP return (nzbtomedia.NZBGET_POSTPROCESS_SUCCESS) else: logger.error("A problem was reported in the %s script." % args[0]) if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 del nzbtomedia.MYAPP return (nzbtomedia.NZBGET_POSTPROCESS_ERROR) del nzbtomedia.MYAPP return (result)
def main(args): # Initialize the config nzbtomedia.initialize() # clientAgent for Torrents clientAgent = nzbtomedia.TORRENT_CLIENTAGENT logger.info("#########################################################") logger.info("## ..::[%s]::.. ##" % os.path.basename(__file__)) logger.info("#########################################################") # debug command line options logger.debug("Options passed into TorrentToMedia: %s" % (args)) # Post-Processing Result result = 0 try: inputDirectory, inputName, inputCategory, inputHash, inputID = nzbtomedia.parse_args( clientAgent, args) except: logger.error("There was a problem loading variables") return -1 if inputDirectory and inputName and inputHash and inputID: result = processTorrent(inputDirectory, inputName, inputCategory, inputHash, inputID, clientAgent) else: # Perform Manual Post-Processing logger.warning( "Invalid number of arguments received from client, Switching to manual run mode ..." ) for section, subsections in nzbtomedia.SECTIONS.items(): for subsection in subsections: for dirName in nzbtomedia.getDirs(section, subsection): logger.info("Starting manual run for %s:%s - Folder:%s" % (section, subsection, dirName)) logger.info( "Checking database for download info for %s ..." % (os.path.basename(dirName))) nzbtomedia.DOWNLOADINFO = nzbtomedia.get_downloadInfo( os.path.basename(dirName), 0) if nzbtomedia.DOWNLOADINFO: logger.info( "Found download info for %s, setting variables now ..." % (os.path.basename(dirName))) else: logger.info( 'Unable to locate download info for %s, continuing to try and process this release ...' % (os.path.basename(dirName))) try: clientAgent = str( nzbtomedia.DOWNLOADINFO[0]['client_agent']) except: clientAgent = 'manual' try: inputHash = str( nzbtomedia.DOWNLOADINFO[0]['input_hash']) except: inputHash = None try: inputID = str(nzbtomedia.DOWNLOADINFO[0]['input_id']) except: inputID = None if clientAgent.lower( ) not in nzbtomedia.TORRENT_CLIENTS and clientAgent != 'manual': continue results = processTorrent(dirName, os.path.basename(dirName), subsection, inputHash, inputID, clientAgent) if results != 0: logger.error( "A problem was reported when trying to perform a manual run for %s:%s." % (section, subsection)) result = results if result == 0: logger.info("The %s script completed successfully." % (args[0])) else: logger.error("A problem was reported in the %s script." % (args[0])) return result
def process(self, section, dirName, inputName=None, status=0, clientAgent="manual", download_id="", inputCategory=None, failureLink=None): host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] method = nzbtomedia.CFG[section][inputCategory]["method"] delete_failed = int( nzbtomedia.CFG[section][inputCategory]["delete_failed"]) wait_for = int(nzbtomedia.CFG[section][inputCategory]["wait_for"]) try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: remote_path = int( nzbtomedia.CFG[section][inputCategory]["remote_path"]) except: remote_path = 0 try: extract = int(section[inputCategory]["extract"]) except: extract = 0 if ssl: protocol = "https://" else: protocol = "http://" baseURL = "%s%s:%s%s/api/%s" % (protocol, host, port, web_root, apikey) if not server_responding(baseURL): logger.error("Server did not respond. Exiting", section) return [ 1, "%s: Failed to post-process - %s did not respond." % (section, section) ] imdbid = find_imdbid(dirName, inputName) release = self.get_release(baseURL, imdbid, download_id) # pull info from release found if available release_id = None media_id = None downloader = None release_status_old = None if release: try: release_id = release.keys()[0] media_id = release[release_id]['media_id'] download_id = release[release_id]['download_info']['id'] downloader = release[release_id]['download_info']['downloader'] release_status_old = release[release_id]['status'] except: pass 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(inputName)) cleanName = os.path.splitext(SpecificPath) if cleanName[1] == ".nzb": SpecificPath = cleanName[0] if os.path.isdir(SpecificPath): dirName = SpecificPath process_all_exceptions(inputName, dirName) inputName, dirName = convert_to_ascii(inputName, dirName) if not listMediaFiles( dirName, media=True, audio=False, meta=False, archives=False) and listMediaFiles(dirName, media=False, audio=False, meta=False, archives=True) and extract: logger.debug('Checking for archives to extract in directory: %s' % (dirName)) nzbtomedia.extractFiles(dirName) inputName, dirName = convert_to_ascii(inputName, dirName) good_files = 0 num_files = 0 # Check video files for corruption status = int(status) for video in listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False): num_files += 1 if transcoder.isVideoGood(video, status): import_subs(video) good_files += 1 if num_files > 0 and good_files == num_files: if status: logger.info( "Status shown as failed from Downloader, but %s valid video files found. Setting as success." % (str(good_files)), section) status = 0 elif num_files > 0 and good_files < num_files: logger.info( "Status shown as success from Downloader, but corrupt video files found. Setting as failed.", section) if os.environ.has_key('NZBOP_VERSION') and os.environ[ 'NZBOP_VERSION'][0:5] >= '14.0': print('[NZB] MARK=BAD') if failureLink: failureLink = failureLink + '&corrupt=true' status = 1 elif clientAgent == "manual": logger.warning( "No media files found in directory %s to manually process." % (dirName), section) 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), section) status = 1 if status == 0: if nzbtomedia.TRANSCODE == 1: result, newDirName = transcoder.Transcode_directory(dirName) if result == 0: logger.debug( "Transcoding succeeded for files in %s" % (dirName), section) dirName = newDirName else: logger.error( "Transcoding failed for files in %s" % (dirName), section) return [ 1, "%s: Failed to post-process - Transcoding failed" % (section) ] for video in listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False): if not release and not ".cp(tt" in video and imdbid: videoName, videoExt = os.path.splitext(video) video2 = "%s.cp(%s)%s" % (videoName, imdbid, videoExt) logger.debug('Renaming: %s to: %s' % (video, video2)) os.rename(video, video2) params = {} if download_id: params['downloader'] = downloader or clientAgent params['download_id'] = download_id params['media_folder'] = dirName if remote_path: params['media_folder'] = remoteDir(dirName) if method == "manage": command = "/manage.update" params = {} else: command = "/renamer.scan" url = "%s%s" % (baseURL, command) logger.debug("Opening URL: %s with PARAMS: %s" % (url, params), section) logger.postprocess("Starting %s scan for %s" % (method, inputName), section) try: r = requests.get(url, params=params, verify=False) except requests.ConnectionError: logger.error("Unable to open URL", section) return [ 1, "%s: Failed to post-process - Unable to connect to %s" % (section, section) ] result = r.json() if not r.status_code in [ requests.codes.ok, requests.codes.created, requests.codes.accepted ]: logger.error( "Server returned status %s" % (str(r.status_code)), section) return [ 1, "%s: Failed to post-process - Server returned status %s" % (section, str(r.status_code)) ] elif result['success']: logger.postprocess( "SUCCESS: Finished %s scan for folder %s" % (method, dirName), section) if method == "manage": return [ 0, "%s: Successfully post-processed %s" % (section, inputName) ] else: logger.error( "FAILED: %s scan was unable to finish for folder %s. exiting!" % (method, dirName), section) return [ 1, "%s: Failed to post-process - Server did not return success" % (section) ] else: logger.postprocess("FAILED DOWNLOAD DETECTED FOR %s" % (inputName), section) if failureLink: reportNzb(failureLink, clientAgent) if delete_failed and os.path.isdir( dirName) and not os.path.dirname(dirName) == dirName: logger.postprocess( "Deleting failed files and folder %s" % dirName, section) rmDir(dirName) if not release_id and not media_id: logger.error( "Could not find a downloaded movie in the database matching %s, exiting!" % inputName, section) return [ 1, "%s: Failed to post-process - Failed download not found in %s" % (section, section) ] if release_id: logger.postprocess( "Setting failed release %s to ignored ..." % (inputName), section) url = baseURL + "/release.ignore" params = {'id': release_id} logger.debug("Opening URL: %s with PARAMS: %s" % (url, params), section) try: r = requests.get(url, params=params, verify=False) except requests.ConnectionError: logger.error("Unable to open URL %s" % (url), section) return [ 1, "%s: Failed to post-process - Unable to connect to %s" % (section, section) ] result = r.json() if not r.status_code in [ requests.codes.ok, requests.codes.created, requests.codes.accepted ]: logger.error( "Server returned status %s" % (str(r.status_code)), section) return [ 1, "%s: Failed to post-process - Server returned status %s" % (section, str(r.status_code)) ] elif result['success']: logger.postprocess( "SUCCESS: %s has been set to ignored ..." % (inputName), section) else: logger.warning( "FAILED: Unable to set %s to ignored!" % (inputName), section) return [ 1, "%s: Failed to post-process - Unable to set %s to ignored" % (section, inputName) ] logger.postprocess( "Trying to snatch the next highest ranked release.", section) url = "%s/movie.searcher.try_next" % (baseURL) logger.debug("Opening URL: %s" % (url), section) try: r = requests.get(url, params={'media_id': media_id}, verify=False) except requests.ConnectionError: logger.error("Unable to open URL %s" % (url), section) return [ 1, "%s: Failed to post-process - Unable to connect to %s" % (section, section) ] result = r.json() if not r.status_code in [ requests.codes.ok, requests.codes.created, requests.codes.accepted ]: logger.error( "Server returned status %s" % (str(r.status_code)), section) return [ 1, "%s: Failed to post-process - Server returned status %s" % (section, str(r.status_code)) ] elif result['success']: logger.postprocess( "SUCCESS: Snatched the next highest release ...", section) return [ 0, "%s: Successfully snatched next highest release" % (section) ] else: logger.postprocess( "SUCCESS: Unable to find a new release to snatch now. CP will keep searching!", section) return [ 0, "%s: No new release found now. %s will keep searching" % (section, section) ] # Added a releease that was not in the wanted list so confirm rename successful by finding this movie media.list. if not release: download_id = None # we don't want to filter new releases based on this. # we will now check to see if CPS has finished renaming before returning to TorrentToMedia and unpausing. timeout = time.time() + 60 * wait_for while (time.time() < timeout): # only wait 2 (default) minutes, then return. logger.postprocess( "Checking for status change, please stand by ...", section) release = self.get_release(baseURL, imdbid, download_id, release_id) if release: try: if release_id is None and release_status_old is None: # we didn't have a release before, but now we do. logger.postprocess( "SUCCESS: Movie %s has now been added to CouchPotato" % (imdbid), section) return [ 0, "%s: Successfully post-processed %s" % (section, inputName) ] release_status_new = release[release_id]['status'] if release_status_new != release_status_old: logger.postprocess( "SUCCESS: Release %s has now been marked with a status of [%s]" % (inputName, str(release_status_new).upper()), section) return [ 0, "%s: Successfully post-processed %s" % (section, inputName) ] except: pass if not os.path.isdir(dirName): logger.postprocess( "SUCCESS: Input Directory [%s] has been processed and removed" % (dirName), section) return [ 0, "%s: Successfully post-processed %s" % (section, inputName) ] elif not listMediaFiles( dirName, media=True, audio=False, meta=False, archives=True): logger.postprocess( "SUCCESS: Input Directory [%s] has no remaining media files. This has been fully processed." % (dirName), section) return [ 0, "%s: Successfully post-processed %s" % (section, inputName) ] # pause and let CouchPotatoServer catch its breath time.sleep(10 * wait_for) # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resule seeding now. logger.warning( "%s does not appear to have changed status after %s minutes, Please check your logs." % (inputName, wait_for), section) return [ 1, "%s: Failed to post-process - No change in status" % (section) ]
def addnzbget(): # load configs into memory CFG_NEW = config() try: if os.environ.has_key("NZBPO_NDCATEGORY") and os.environ.has_key("NZBPO_SBCATEGORY"): if os.environ("NZBPO_NDCATEGORY") == os.environ("NZBPO_SBCATEGORY"): logger.warning( "%s category is set for SickBeard and NzbDrone. Please check your config in NZBGet" % (os.environ("NZBPO_NDCATEGORY")) ) section = "Nzb" key = "NZBOP_DESTDIR" if os.environ.has_key(key): option = "default_downloadDirectory" value = os.environ[key] CFG_NEW[section][option] = value section = "General" envKeys = ["AUTO_UPDATE", "CHECK_MEDIA", "SAFE_MODE"] cfgKeys = ["auto_update", "check_media", "safe_mode"] for index in range(len(envKeys)): key = "NZBPO_" + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[section][option] = value section = "Network" envKeys = ["MOUNTPOINTS"] cfgKeys = ["mount_points"] for index in range(len(envKeys)): key = "NZBPO_" + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[section][option] = value section = "CouchPotato" envCatKey = "NZBPO_CPSCATEGORY" envKeys = [ "ENABLED", "APIKEY", "HOST", "PORT", "SSL", "WEB_ROOT", "METHOD", "DELETE_FAILED", "REMOTE_PATH", "WAIT_FOR", "WATCH_DIR", ] cfgKeys = [ "enabled", "apikey", "host", "port", "ssl", "web_root", "method", "delete_failed", "remote_path", "wait_for", "watch_dir", ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = "NZBPO_CPS" + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]["enabled"] = 1 section = "SickBeard" envCatKey = "NZBPO_SBCATEGORY" envKeys = [ "ENABLED", "HOST", "PORT", "USERNAME", "PASSWORD", "SSL", "WEB_ROOT", "WATCH_DIR", "FORK", "DELETE_FAILED", "TORRENT_NOLINK", "NZBEXTRACTIONBY", "REMOTE_PATH", ] cfgKeys = [ "enabled", "host", "port", "username", "password", "ssl", "web_root", "watch_dir", "fork", "delete_failed", "Torrent_NoLink", "nzbExtractionBy", "remote_path", ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = "NZBPO_SB" + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]["enabled"] = 1 if os.environ[envCatKey] in CFG_NEW["NzbDrone"].sections: CFG_NEW["NzbDrone"][envCatKey]["enabled"] = 0 section = "HeadPhones" envCatKey = "NZBPO_HPCATEGORY" envKeys = ["ENABLED", "APIKEY", "HOST", "PORT", "SSL", "WEB_ROOT", "WAIT_FOR", "WATCH_DIR", "REMOTE_PATH"] cfgKeys = ["enabled", "apikey", "host", "port", "ssl", "web_root", "wait_for", "watch_dir", "remote_path"] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = "NZBPO_HP" + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]["enabled"] = 1 section = "Mylar" envCatKey = "NZBPO_MYCATEGORY" envKeys = [ "ENABLED", "HOST", "PORT", "USERNAME", "PASSWORD", "APIKEY", "SSL", "WEB_ROOT", "WATCH_DIR", "REMOTE_PATH", ] cfgKeys = [ "enabled", "host", "port", "username", "password", "apikey", "ssl", "web_root", "watch_dir", "remote_path", ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = "NZBPO_MY" + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]["enabled"] = 1 section = "Gamez" envCatKey = "NZBPO_GZCATEGORY" envKeys = ["ENABLED", "APIKEY", "HOST", "PORT", "SSL", "WEB_ROOT", "WATCH_DIR", "LIBRARY", "REMOTE_PATH"] cfgKeys = ["enabled", "apikey", "host", "port", "ssl", "web_root", "watch_dir", "library", "remote_path"] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = "NZBPO_GZ" + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]["enabled"] = 1 section = "NzbDrone" envCatKey = "NZBPO_NDCATEGORY" envKeys = [ "ENABLED", "HOST", "APIKEY", "PORT", "SSL", "WEB_ROOT", "WATCH_DIR", "FORK", "DELETE_FAILED", "TORRENT_NOLINK", "NZBEXTRACTIONBY", "WAIT_FOR", "DELETE_FAILED", "REMOTE_PATH", ] cfgKeys = [ "enabled", "host", "apikey", "port", "ssl", "web_root", "watch_dir", "fork", "delete_failed", "Torrent_NoLink", "nzbExtractionBy", "wait_for", "delete_failed", "remote_path", ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = "NZBPO_ND" + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]["enabled"] = 1 if os.environ[envCatKey] in CFG_NEW["SickBeard"].sections: CFG_NEW["SickBeard"][envCatKey]["enabled"] = 0 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] CFG_NEW[section][option] = value section = "Transcoder" envKeys = [ "TRANSCODE", "DUPLICATE", "NICENESS", "IGNOREEXTENSIONS", "OUTPUTFASTSTART", "OUTPUTVIDEOPATH", "PROCESSOUTPUT", "AUDIOLANGUAGE", "ALLAUDIOLANGUAGES", "SUBLANGUAGES", "ALLSUBLANGUAGES", "EMBEDSUBS", "BURNINSUBTITLE", "EXTRACTSUBS", "EXTERNALSUBDIR", "OUTPUTDEFAULT", "OUTPUTVIDEOEXTENSION", "OUTPUTVIDEOCODEC", "VIDEOCODECALLOW", "OUTPUTVIDEOPRESET", "OUTPUTVIDEOFRAMERATE", "OUTPUTVIDEOBITRATE", "OUTPUTAUDIOCODEC", "AUDIOCODECALLOW", "OUTPUTAUDIOBITRATE", "OUTPUTQUALITYPERCENT", "GETSUBS", "OUTPUTAUDIOTRACK2CODEC", "AUDIOCODEC2ALLOW", "OUTPUTAUDIOTRACK2BITRATE", "OUTPUTAUDIOOTHERCODEC", "AUDIOOTHERCODECALLOW", "OUTPUTAUDIOOTHERBITRATE", "OUTPUTSUBTITLECODEC", ] cfgKeys = [ "transcode", "duplicate", "niceness", "ignoreExtensions", "outputFastStart", "outputVideoPath", "processOutput", "audioLanguage", "allAudioLanguages", "subLanguages", "allSubLanguages", "embedSubs", "burnInSubtitle", "extractSubs", "externalSubDir", "outputDefault", "outputVideoExtension", "outputVideoCodec", "VideoCodecAllow", "outputVideoPreset", "outputVideoFramerate", "outputVideoBitrate", "outputAudioCodec", "AudioCodecAllow", "outputAudioBitrate", "outputQualityPercent", "getSubs", "outputAudioTrack2Codec", "AudioCodec2Allow", "outputAudioTrack2Bitrate", "outputAudioOtherCodec", "AudioOtherCodecAllow", "outputAudioOtherBitrate", "outputSubtitleCodec", ] for index in range(len(envKeys)): key = "NZBPO_" + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[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] CFG_NEW[section][option] = value except Exception, e: logger.debug("Error %s when applying NZBGet config" % (e))
def initialize(section=None): global NZBGET_POSTPROCESS_ERROR, NZBGET_POSTPROCESS_NONE, NZBGET_POSTPROCESS_PARCHECK, NZBGET_POSTPROCESS_SUCCESS, \ NZBTOMEDIA_TIMEOUT, FORKS, FORK_DEFAULT, FORK_FAILED_TORRENT, FORK_FAILED, SICKBEARD_TORRENT, SICKBEARD_FAILED, \ NZBTOMEDIA_BRANCH, NZBTOMEDIA_VERSION, NEWEST_VERSION, NEWEST_VERSION_STRING, VERSION_NOTIFY, SYS_ARGV, CFG, \ SABNZB_NO_OF_ARGUMENTS, SABNZB_0717_NO_OF_ARGUMENTS, CATEGORIES, TORRENT_CLIENTAGENT, USELINK, OUTPUTDIRECTORY, NOFLATTEN, \ UTORRENTPWD, UTORRENTUSR, UTORRENTWEBUI, DELUGEHOST, DELUGEPORT, DELUGEUSR, DELUGEPWD, TRANSMISSIONHOST, TRANSMISSIONPORT, \ TRANSMISSIONPWD, TRANSMISSIONUSR, COMPRESSEDCONTAINER, MEDIACONTAINER, METACONTAINER, SECTIONS, USER_SCRIPT_CATEGORIES, \ __INITIALIZED__, AUTO_UPDATE, APP_FILENAME, USER_DELAY, APP_NAME, TRANSCODE, GIT_PATH, GIT_USER, \ GIT_BRANCH, GIT_REPO, SYS_ENCODING, NZB_CLIENTAGENT, SABNZBDHOST, SABNZBDPORT, SABNZBDAPIKEY, \ DUPLICATE, IGNOREEXTENSIONS, OUTPUTVIDEOEXTENSION, OUTPUTVIDEOCODEC, OUTPUTVIDEOPRESET, OUTPUTVIDEOFRAMERATE, LOG_DB, \ OUTPUTVIDEOBITRATE, OUTPUTAUDIOCODEC, OUTPUTAUDIOBITRATE, OUTPUTSUBTITLECODEC, OUTPUTFASTSTART, OUTPUTQUALITYPERCENT, \ NICENESS, LOG_DEBUG, FORCE_CLEAN, FFMPEG_PATH, FFMPEG, FFPROBE, AUDIOCONTAINER, EXTCONTAINER, TORRENT_CLASS, \ DELETE_ORIGINAL, PASSWORDSFILE, USER_DELAY, USER_SCRIPT, USER_SCRIPT_CLEAN, USER_SCRIPT_MEDIAEXTENSIONS, \ USER_SCRIPT_PARAM, USER_SCRIPT_RUNONCE, USER_SCRIPT_SUCCESSCODES, DOWNLOADINFO, CHECK_MEDIA, SAFE_MODE, \ TORRENT_DEFAULTDIR, NZB_DEFAULTDIR, REMOTEPATHS if __INITIALIZED__: return False try: locale.setlocale(locale.LC_ALL, "") SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): pass # For OSes that are poorly configured I'll just randomly force UTF-8 if not SYS_ENCODING or SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'): SYS_ENCODING = 'UTF-8' if not hasattr(sys, "setdefaultencoding"): reload(sys) try: # pylint: disable=E1101 # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(SYS_ENCODING) except: print 'Sorry, you MUST add the nzbToMedia folder to the PYTHONPATH environment variable' print 'or find another way to force Python to use ' + SYS_ENCODING + ' for string encoding.' if os.environ.has_key('NZBOP_SCRIPTDIR'): sys.exit(NZBGET_POSTPROCESS_ERROR) else: sys.exit(1) if not makeDir(LOG_DIR): print("!!! No log folder, logging to screen only!") # init logging logger.ntm_log_instance.initLogging() # run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. if not config.migrate(): logger.error("Unable to migrate config file %s, exiting ..." % (CONFIG_FILE)) if os.environ.has_key('NZBOP_SCRIPTDIR'): pass # We will try and read config from Environment. else: sys.exit(-1) # run migrate to convert NzbGet data from old cfg style to new cfg style if os.environ.has_key('NZBOP_SCRIPTDIR'): CFG = config.addnzbget() else: # load newly migrated config logger.info("Loading config from [%s]" % (CONFIG_FILE)) CFG = config() # Enable/Disable DEBUG Logging LOG_DEBUG = int(CFG['General']['log_debug']) LOG_DB = int(CFG['General']['log_db']) # initialize the main SB database nzbToMediaDB.upgradeDatabase(nzbToMediaDB.DBConnection(), mainDB.InitialSchema) # Set Version and GIT variables NZBTOMEDIA_VERSION = '9.3' VERSION_NOTIFY = int(CFG['General']['version_notify']) AUTO_UPDATE = int(CFG['General']['auto_update']) GIT_REPO = 'nzbToMedia' GIT_PATH = CFG['General']['git_path'] GIT_USER = CFG['General']['git_user'] or 'clinton-hall' GIT_BRANCH = CFG['General']['git_branch'] or 'master' FORCE_CLEAN = CFG["General"]["force_clean"] FFMPEG_PATH = CFG["General"]["ffmpeg_path"] CHECK_MEDIA = int(CFG["General"]["check_media"]) SAFE_MODE = int(CFG["General"]["safe_mode"]) # Check for updates via GitHUB if versionCheck.CheckVersion().check_for_new_version(): if AUTO_UPDATE == 1: logger.info("Auto-Updating nzbToMedia, Please wait ...") updated = versionCheck.CheckVersion().update() if updated: # restart nzbToMedia restart() else: logger.error( "Update wasn't successful, not restarting. Check your log for more information." ) # Set Current Version logger.info('nzbToMedia Version:' + NZBTOMEDIA_VERSION + ' Branch:' + GIT_BRANCH + ' (' + platform.system() + ' ' + platform.release() + ')') if int(CFG["WakeOnLan"]["wake"]) == 1: WakeUp() NZB_CLIENTAGENT = CFG["Nzb"]["clientAgent"] # sabnzbd SABNZBDHOST = CFG["Nzb"]["sabnzbd_host"] SABNZBDPORT = int(CFG["Nzb"]["sabnzbd_port"]) SABNZBDAPIKEY = CFG["Nzb"]["sabnzbd_apikey"] NZB_DEFAULTDIR = CFG["Nzb"]["default_downloadDirectory"] TORRENT_CLIENTAGENT = CFG["Torrent"][ "clientAgent"] # utorrent | deluge | transmission | rtorrent | other USELINK = CFG["Torrent"]["useLink"] # no | hard | sym OUTPUTDIRECTORY = CFG["Torrent"][ "outputDirectory"] # /abs/path/to/complete/ TORRENT_DEFAULTDIR = CFG["Torrent"]["default_downloadDirectory"] CATEGORIES = (CFG["Torrent"]["categories"] ) # music,music_videos,pictures,software NOFLATTEN = (CFG["Torrent"]["noFlatten"]) if isinstance(NOFLATTEN, str): NOFLATTEN = NOFLATTEN.split(',') DELETE_ORIGINAL = int(CFG["Torrent"]["deleteOriginal"]) UTORRENTWEBUI = CFG["Torrent"][ "uTorrentWEBui"] # http://localhost:8090/gui/ UTORRENTUSR = CFG["Torrent"]["uTorrentUSR"] # mysecretusr UTORRENTPWD = CFG["Torrent"]["uTorrentPWD"] # mysecretpwr TRANSMISSIONHOST = CFG["Torrent"]["TransmissionHost"] # localhost TRANSMISSIONPORT = int(CFG["Torrent"]["TransmissionPort"]) TRANSMISSIONUSR = CFG["Torrent"]["TransmissionUSR"] # mysecretusr TRANSMISSIONPWD = CFG["Torrent"]["TransmissionPWD"] # mysecretpwr DELUGEHOST = CFG["Torrent"]["DelugeHost"] # localhost DELUGEPORT = int(CFG["Torrent"]["DelugePort"]) # 8084 DELUGEUSR = CFG["Torrent"]["DelugeUSR"] # mysecretusr DELUGEPWD = CFG["Torrent"]["DelugePWD"] # mysecretpwr REMOTEPATHS = CFG["Network"]["mount_points"] or None if REMOTEPATHS: REMOTEPATHS = [ tuple(item.split(',')) for item in REMOTEPATHS.split('|') ] # /volume1/Public/,E:\|/volume2/share/,\\NAS\ COMPRESSEDCONTAINER = [ re.compile('.r\d{2}$', re.I), re.compile('.part\d+.rar$', re.I), re.compile('.rar$', re.I) ] COMPRESSEDCONTAINER += [ re.compile('%s$' % ext, re.I) for ext in CFG["Extensions"]["compressedExtensions"] ] MEDIACONTAINER = CFG["Extensions"]["mediaExtensions"] AUDIOCONTAINER = CFG["Extensions"]["audioExtensions"] METACONTAINER = CFG["Extensions"]["metaExtensions"] # .nfo,.sub,.srt if isinstance(COMPRESSEDCONTAINER, str): COMPRESSEDCONTAINER = COMPRESSEDCONTAINER.split(',') if isinstance(MEDIACONTAINER, str): MEDIACONTAINER = MEDIACONTAINER.split(',') if isinstance(AUDIOCONTAINER, str): AUDIOCONTAINER = AUDIOCONTAINER.split(',') if isinstance(METACONTAINER, str): METACONTAINER = METACONTAINER.split(',') TRANSCODE = int(CFG["Transcoder"]["transcode"]) DUPLICATE = int(CFG["Transcoder"]["duplicate"]) IGNOREEXTENSIONS = (CFG["Transcoder"]["ignoreExtensions"]) OUTPUTVIDEOEXTENSION = CFG["Transcoder"]["outputVideoExtension"].strip() OUTPUTVIDEOCODEC = CFG["Transcoder"]["outputVideoCodec"].strip() OUTPUTVIDEOPRESET = CFG["Transcoder"]["outputVideoPreset"].strip() OUTPUTVIDEOFRAMERATE = CFG["Transcoder"]["outputVideoFramerate"].strip() OUTPUTVIDEOBITRATE = CFG["Transcoder"]["outputVideoBitrate"].strip() OUTPUTAUDIOCODEC = CFG["Transcoder"]["outputAudioCodec"].strip() OUTPUTAUDIOBITRATE = CFG["Transcoder"]["outputAudioBitrate"].strip() OUTPUTSUBTITLECODEC = CFG["Transcoder"]["outputSubtitleCodec"].strip() OUTPUTFASTSTART = int(CFG["Transcoder"]["outputFastStart"]) OUTPUTQUALITYPERCENT = int(CFG["Transcoder"]["outputQualityPercent"]) NICENESS = int(CFG["Transcoder"]["niceness"]) PASSWORDSFILE = CFG["passwords"]["PassWordFile"] # Setup FFMPEG and FFPROBE locations if platform.system() == 'Windows': FFMPEG = os.path.join(FFMPEG_PATH, 'ffmpeg.exe') FFPROBE = os.path.join(FFMPEG_PATH, 'ffprobe.exe') if not (os.path.isfile(FFMPEG)): # problem FFMPEG = None logger.warning( "Failed to locate ffmpeg.exe, transcoding disabled!") logger.warning( "Install ffmpeg with x264 support to enable this feature ...") if not (os.path.isfile(FFPROBE)) and CHECK_MEDIA: # problem FFPROBE = None logger.warning( "Failed to locate ffprobe.exe, video corruption detection disabled!" ) logger.warning( "Install ffmpeg with x264 support to enable this feature ...") else: FFMPEG = subprocess.Popen( ['which', 'ffmpeg'], stdout=subprocess.PIPE).communicate()[0].strip() FFPROBE = subprocess.Popen( ['which', 'ffprobe'], stdout=subprocess.PIPE).communicate()[0].strip() if not FFMPEG: if os.access(os.path.join(FFMPEG_PATH, 'ffmpeg'), os.X_OK): FFMPEG = os.path.join(FFMPEG_PATH, 'ffmpeg') else: FFMPEG = None logger.warning( "Failed to locate ffmpeg, transcoding disabled!") logger.warning( "Install ffmpeg with x264 support to enable this feature ..." ) if not FFPROBE and CHECK_MEDIA: if os.access(os.path.join(FFMPEG_PATH, 'ffprobe'), os.X_OK): FFPROBE = os.path.join(FFMPEG_PATH, 'ffprobe') else: FFPROBE = None logger.warning( "Failed to locate ffprobe, video corruption detection disabled!" ) logger.warning( "Install ffmpeg with x264 support to enable this feature ..." ) if not CHECK_MEDIA: # allow users to bypass this. FFPROBE = None # userscript map(USER_SCRIPT_CATEGORIES.append, ([subsections[0] for subsections in CFG['UserScript'].items()])) # check for script-defied section and if None set to allow sections SECTIONS = CFG[tuple( x for x in CFG if CFG[x].sections and CFG[x].isenabled()) if not section else (section, )] map(CATEGORIES.extend, ([subsection.sections for section, subsection in SECTIONS.items()])) CATEGORIES = list(set(CATEGORIES)) # create torrent class TORRENT_CLASS = create_torrent_class(TORRENT_CLIENTAGENT) # finished initalizing return True
def main(args, section=None): # Initialize the config nzbtomedia.initialize(section) # clientAgent for NZBs clientAgent = nzbtomedia.NZB_CLIENTAGENT logger.info("#########################################################") logger.info("## ..::[%s]::.. ##" % os.path.basename(__file__)) logger.info("#########################################################") # debug command line options logger.debug("Options passed into nzbToMedia: %s" % args) # Post-Processing Result result = 0 status = 0 # 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("Script triggered from NZBGet (11.0 or later).") if os.environ['NZBOP_UNPACK'] != 'yes': logger.error( "Please enable option \"Unpack\" in nzbget configuration file, exiting" ) sys.exit(nzbtomedia.NZBGET_POSTPROCESS_ERROR) # Check par status if os.environ['NZBPP_PARSTATUS'] == '3': logger.warning( "Par-check successful, but Par-repair disabled, exiting") logger.info( "Please check your Par-repair settings for future downloads.") sys.exit(nzbtomedia.NZBGET_POSTPROCESS_NONE) if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ[ 'NZBPP_PARSTATUS'] == '4': logger.warning("Par-repair failed, setting status \"failed\"") status = 1 # Check unpack status if os.environ['NZBPP_UNPACKSTATUS'] == '1': logger.warning("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( "Download health is compromised and Par-check/repair disabled or no .par2 files found. Setting status \"failed\"" ) logger.info( "Please check your Par-check/repair settings for future downloads." ) status = 1 else: logger.info( "Par-check/repair disabled or no .par2 files found, and Unpack not required. Health is ok so handle as though download successful" ) logger.info( "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( "Nothing to post-process: destination directory %s doesn't exist. Setting status failed" % (os.environ['NZBPP_DIRECTORY'])) status = 1 # Check for download_id to pass to CouchPotato download_id = "" if os.environ.has_key('NZBPR_COUCHPOTATO'): download_id = os.environ['NZBPR_COUCHPOTATO'] # All checks done, now launching the script. clientAgent = 'nzbget' result = process(os.environ['NZBPP_DIRECTORY'], inputName=os.environ['NZBPP_NZBFILENAME'], status=status, clientAgent=clientAgent, download_id=download_id, inputCategory=os.environ['NZBPP_CATEGORY']) # SABnzbd Pre 0.7.17 elif len(args) == nzbtomedia.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 clientAgent = 'sabnzbd' logger.info("Script triggered from SABnzbd") result = process(args[1], inputName=args[2], status=args[7], inputCategory=args[5], clientAgent=clientAgent, download_id='') # SABnzbd 0.7.17+ elif len(args) >= nzbtomedia.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 clientAgent = 'sabnzbd' logger.info("Script triggered from SABnzbd 0.7.17+") result = process(args[1], inputName=args[2], status=args[7], inputCategory=args[5], clientAgent=clientAgent, download_id='') else: # Perform Manual Run logger.warning( "Invalid number of arguments received from client, Switching to manual run mode ..." ) # Loop and auto-process clientAgent = 'manual' for section, subsection in nzbtomedia.SUBSECTIONS.items(): for category in subsection: if nzbtomedia.CFG[section][category].isenabled(): dirNames = get_dirnames(section, category) for dirName in dirNames: logger.info( "Starting manual run for %s:%s - Folder:%s" % (section, category, dirName)) results = process(dirName, os.path.basename(dirName), 0, clientAgent=clientAgent, inputCategory=category) if results != 0: logger.error( "A problem was reported when trying to perform a manual run for %s:%s." % (section, category)) result = results else: logger.debug("nzbToMedia %s:%s is DISABLED" % (section, category)) if result == 0: logger.info("The %s script completed successfully." % args[0]) if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 sys.exit(nzbtomedia.NZBGET_POSTPROCESS_SUCCESS) else: logger.error("A problem was reported in the %s script." % args[0]) if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 sys.exit(nzbtomedia.NZBGET_POSTPROCESS_ERROR) sys.exit(result)
def main(args): # Initialize the config nzbtomedia.initialize() # clientAgent for Torrents clientAgent = nzbtomedia.TORRENT_CLIENTAGENT logger.info("#########################################################") logger.info("## ..::[%s]::.. ##" % os.path.basename(__file__)) logger.info("#########################################################") # debug command line options logger.debug("Options passed into TorrentToMedia: %s" % (args)) # Post-Processing Result result = [ 0, "" ] try: inputDirectory, inputName, inputCategory, inputHash, inputID = nzbtomedia.parse_args(clientAgent, args) except: logger.error("There was a problem loading variables") return -1 if inputDirectory and inputName and inputHash and inputID: result = processTorrent(inputDirectory, inputName, inputCategory, inputHash, inputID, clientAgent) else: # Perform Manual Post-Processing logger.warning("Invalid number of arguments received from client, Switching to manual run mode ...") for section, subsections in nzbtomedia.SECTIONS.items(): for subsection in subsections: for dirName in nzbtomedia.getDirs(section, subsection, link='hard'): logger.info("Starting manual run for %s:%s - Folder:%s" % (section, subsection, dirName)) logger.info("Checking database for download info for %s ..." % (os.path.basename(dirName))) nzbtomedia.DOWNLOADINFO = nzbtomedia.get_downloadInfo(os.path.basename(dirName), 0) if nzbtomedia.DOWNLOADINFO: logger.info( "Found download info for %s, setting variables now ..." % (os.path.basename(dirName))) else: logger.info( 'Unable to locate download info for %s, continuing to try and process this release ...' % ( os.path.basename(dirName)) ) try: clientAgent = str(nzbtomedia.DOWNLOADINFO[0]['client_agent']) except: clientAgent = 'manual' try: inputHash = str(nzbtomedia.DOWNLOADINFO[0]['input_hash']) except: inputHash = None try: inputID = str(nzbtomedia.DOWNLOADINFO[0]['input_id']) except: inputID = None if clientAgent.lower() not in nzbtomedia.TORRENT_CLIENTS and clientAgent != 'manual': continue try: dirName = dirName.encode(nzbtomedia.SYS_ENCODING) except: pass inputName = os.path.basename(dirName) try: inputName = inputName.encode(nzbtomedia.SYS_ENCODING) except: pass results = processTorrent(dirName, inputName, subsection, inputHash, inputID, clientAgent) if results[0] != 0: logger.error("A problem was reported when trying to perform a manual run for %s:%s." % ( section, subsection)) result = results if result[0] == 0: logger.info("The %s script completed successfully." % (args[0])) else: logger.error("A problem was reported in the %s script." % (args[0])) del nzbtomedia.MYAPP return result[0]
def process(self, section, dirName, inputName=None, status=0, clientAgent="manual", download_id="", inputCategory=None): # Check video files for corruption status = int(status) for video in listMediaFiles(dirName): if not transcoder.isVideoGood(video): status = 1 host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] method = nzbtomedia.CFG[section][inputCategory]["method"] delete_failed = int( nzbtomedia.CFG[section][inputCategory]["delete_failed"]) wait_for = int(nzbtomedia.CFG[section][inputCategory]["wait_for"]) try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: remote_path = int( nzbtomedia.CFG[section][inputCategory]["remote_path"]) except: remote_path = 0 if ssl: protocol = "https://" else: protocol = "http://" baseURL = "%s%s:%s%s/api/%s" % (protocol, host, port, web_root, apikey) imdbid = find_imdbid(dirName, inputName) release = self.get_release(baseURL, imdbid, download_id) # pull info from release found if available release_id = None media_id = None downloader = None release_status_old = None if release: try: release_id = release.keys()[0] media_id = release[release_id]['media_id'] download_id = release[release_id]['download_info']['id'] downloader = release[release_id]['download_info']['downloader'] release_status_old = release[release_id]['status'] except: pass process_all_exceptions(inputName.lower(), dirName) inputName, dirName = convert_to_ascii(inputName, dirName) if status == 0: if nzbtomedia.TRANSCODE == 1: result = transcoder.Transcode_directory(dirName) if result == 0: logger.debug( "Transcoding succeeded for files in %s" % (dirName), section) else: logger.warning( "Transcoding failed for files in %s" % (dirName), section) if method == "manage": command = "/manage.update" else: command = "/renamer.scan" params = {} if download_id: params['downloader'] = downloader or clientAgent params['download_id'] = download_id params['media_folder'] = dirName if remote_path: params['media_folder'] = remoteDir(dirName) url = "%s%s" % (baseURL, command) logger.debug("Opening URL: %s with PARAMS: %s" % (url, params), section) logger.postprocess("Starting %s scan for %s" % (method, inputName), section) try: r = requests.get(url, params=params, verify=False) except requests.ConnectionError: logger.error("Unable to open URL", section) return 1 # failure result = r.json() if not r.status_code in [ requests.codes.ok, requests.codes.created, requests.codes.accepted ]: logger.error( "Server returned status %s" % (str(r.status_code)), section) return 1 elif result['success']: logger.postprocess( "SUCCESS: Finished %s scan for folder %s" % (method, dirName), section) else: logger.error( "FAILED: %s scan was unable to finish for folder %s. exiting!" % (method, dirName), section) return 1 # failure # Added a releease that was not in the wanted list so no way to check status, exit without errors if not release: return 0 else: logger.postprocess("FAILED DOWNLOAD DETECTED FOR %s" % (inputName), section) if delete_failed and os.path.isdir( dirName) and not os.path.dirname(dirName) == dirName: logger.postprocess( "Deleting failed files and folder %s" % dirName, section) rmDir(dirName) if not download_id: logger.error( "Could not find a downloaded movie in the database matching %s, exiting!" % inputName, section) return 1 # failure logger.postprocess( "Setting failed release %s to ignored ..." % (inputName), section) url = baseURL + "/release.ignore" params = {'id': release_id} logger.debug("Opening URL: %s with PARAMS: %s" % (url, params), section) try: r = requests.get(url, params=params, verify=False) except requests.ConnectionError: logger.error("Unable to open URL %s" % (url), section) return 1 # failure result = r.json() if result['success']: logger.postprocess( "SUCCESS: %s has been set to ignored ..." % (inputName), section) else: logger.warning( "FAILED: Unable to set %s to ignored!" % (inputName), section) logger.postprocess( "Trying to snatch the next highest ranked release.", section) url = "%s/movie.searcher.try_next" % (baseURL) logger.debug("Opening URL: %s" % (url), section) try: r = requests.get(url, params={'media_id': media_id}) except requests.ConnectionError: logger.error("Unable to open URL %s" % (url), section) return 1 # failure result = r.json() if not r.status_code in [ requests.codes.ok, requests.codes.created, requests.codes.accepted ]: logger.error( "Server returned status %s" % (str(r.status_code)), section) return 1 elif result['success']: logger.postprocess( "SUCCESS: Snatched the next highest release ...", section) return 0 else: logger.postprocess( "FAILED: Unable to find a higher ranked release then %s to snatch!" % (inputName), section) return 1 # we will now check to see if CPS has finished renaming before returning to TorrentToMedia and unpausing. timeout = time.time() + 60 * wait_for while (time.time() < timeout): # only wait 2 (default) minutes, then return. logger.postprocess( "Checking for status change, please stand by ...", section) release = self.get_release(baseURL, imdbid, download_id, release_id) if release: try: release_status_new = release[release_id]['status'] if release_status_new != release_status_old: logger.postprocess( "SUCCESS: Release %s has now been marked with a status of [%s]" % (inputName, str(release_status_new).upper()), section) return 0 # success except: pass # pause and let CouchPotatoServer catch its breath time.sleep(10 * wait_for) # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resule seeding now. logger.warning( "%s does not appear to have changed status after %s minutes, Please check your logs." % (inputName, wait_for), section) return 1 # failure
def addnzbget(): # load configs into memory CFG_NEW = config() try: if os.environ.has_key('NZBPO_NDCATEGORY') and os.environ.has_key('NZBPO_SBCATEGORY'): if os.environ('NZBPO_NDCATEGORY') == os.environ('NZBPO_SBCATEGORY'): logger.warning("%s category is set for SickBeard and NzbDrone. Please check your config in NZBGet" % (os.environ('NZBPO_NDCATEGORY'))) section = "Nzb" key = 'NZBOP_DESTDIR' if os.environ.has_key(key): option = 'default_downloadDirectory' value = os.environ[key] CFG_NEW[section][option] = value section = "General" envKeys = ['AUTO_UPDATE', 'CHECK_MEDIA', 'SAFE_MODE'] cfgKeys = ['auto_update', 'check_media', 'safe_mode'] for index in range(len(envKeys)): key = 'NZBPO_' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[section][option] = value section = "Network" envKeys = ['MOUNTPOINTS'] cfgKeys = ['mount_points'] for index in range(len(envKeys)): key = 'NZBPO_' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[section][option] = value section = "CouchPotato" envCatKey = 'NZBPO_CPSCATEGORY' envKeys = ['ENABLED', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'METHOD', 'DELETE_FAILED', 'REMOTE_PATH', 'WAIT_FOR', 'WATCH_DIR'] cfgKeys = ['enabled', 'apikey', 'host', 'port', 'ssl', 'web_root', 'method', 'delete_failed', 'remote_path', 'wait_for', 'watch_dir'] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_CPS' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 section = "SickBeard" envCatKey = 'NZBPO_SBCATEGORY' envKeys = ['ENABLED', 'HOST', 'PORT', 'USERNAME', 'PASSWORD', 'SSL', 'WEB_ROOT', 'WATCH_DIR', 'FORK', 'DELETE_FAILED', 'TORRENT_NOLINK', 'NZBEXTRACTIONBY', 'REMOTE_PATH'] cfgKeys = ['enabled', 'host', 'port', 'username', 'password', 'ssl', 'web_root', 'watch_dir', 'fork', 'delete_failed', 'Torrent_NoLink', 'nzbExtractionBy', 'remote_path'] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_SB' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 if os.environ[envCatKey] in CFG_NEW['NzbDrone'].sections: CFG_NEW['NzbDrone'][envCatKey]['enabled'] = 0 section = "HeadPhones" envCatKey = 'NZBPO_HPCATEGORY' envKeys = ['ENABLED', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'WAIT_FOR', 'WATCH_DIR', 'REMOTE_PATH'] cfgKeys = ['enabled', 'apikey', 'host', 'port', 'ssl', 'web_root', 'wait_for', 'watch_dir', 'remote_path'] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_HP' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 section = "Mylar" envCatKey = 'NZBPO_MYCATEGORY' envKeys = ['ENABLED', 'HOST', 'PORT', 'USERNAME', 'PASSWORD', 'APIKEY', 'SSL', 'WEB_ROOT', 'WATCH_DIR', 'REMOTE_PATH'] cfgKeys = ['enabled', 'host', 'port', 'username', 'password', 'apikey', 'ssl', 'web_root', 'watch_dir', 'remote_path'] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_MY' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 section = "Gamez" envCatKey = 'NZBPO_GZCATEGORY' envKeys = ['ENABLED', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'WATCH_DIR', 'LIBRARY', 'REMOTE_PATH'] cfgKeys = ['enabled', 'apikey', 'host', 'port', 'ssl', 'web_root', 'watch_dir', 'library', 'remote_path'] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_GZ' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 section = "NzbDrone" envCatKey = 'NZBPO_NDCATEGORY' envKeys = ['ENABLED', 'HOST', 'APIKEY', 'PORT', 'SSL', 'WEB_ROOT', 'WATCH_DIR', 'FORK', 'DELETE_FAILED', 'TORRENT_NOLINK', 'NZBEXTRACTIONBY', 'WAIT_FOR', 'DELETE_FAILED', 'REMOTE_PATH'] cfgKeys = ['enabled', 'host', 'apikey', 'port', 'ssl', 'web_root', 'watch_dir', 'fork', 'delete_failed', 'Torrent_NoLink', 'nzbExtractionBy', 'wait_for', 'delete_failed', 'remote_path'] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_ND' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 if os.environ[envCatKey] in CFG_NEW['SickBeard'].sections: CFG_NEW['SickBeard'][envCatKey]['enabled'] = 0 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] CFG_NEW[section][option] = value section = "Posix" envKeys = ['NICENESS', 'IONICE_CLASS', 'IONICE_CLASSDATA'] cfgKeys = ['niceness', 'ionice_class', 'ionice_classdata'] for index in range(len(envKeys)): key = 'NZBPO_' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[section][option] = value section = "Transcoder" envKeys = ['TRANSCODE', 'DUPLICATE', 'IGNOREEXTENSIONS', 'OUTPUTFASTSTART', 'OUTPUTVIDEOPATH', 'PROCESSOUTPUT', 'AUDIOLANGUAGE', 'ALLAUDIOLANGUAGES', 'SUBLANGUAGES', 'ALLSUBLANGUAGES', 'EMBEDSUBS', 'BURNINSUBTITLE', 'EXTRACTSUBS', 'EXTERNALSUBDIR', 'OUTPUTDEFAULT', 'OUTPUTVIDEOEXTENSION', 'OUTPUTVIDEOCODEC', 'VIDEOCODECALLOW', 'OUTPUTVIDEOPRESET', 'OUTPUTVIDEOFRAMERATE', 'OUTPUTVIDEOBITRATE', 'OUTPUTAUDIOCODEC', 'AUDIOCODECALLOW', 'OUTPUTAUDIOBITRATE', 'OUTPUTQUALITYPERCENT', 'GETSUBS', 'OUTPUTAUDIOTRACK2CODEC', 'AUDIOCODEC2ALLOW', 'OUTPUTAUDIOTRACK2BITRATE', 'OUTPUTAUDIOOTHERCODEC', 'AUDIOOTHERCODECALLOW', 'OUTPUTAUDIOOTHERBITRATE', 'OUTPUTSUBTITLECODEC', 'OUTPUTAUDIOCHANNELS', 'OUTPUTAUDIOTRACK2CHANNELS', 'OUTPUTAUDIOOTHERCHANNELS'] cfgKeys = ['transcode', 'duplicate', 'ignoreExtensions', 'outputFastStart', 'outputVideoPath', 'processOutput', 'audioLanguage', 'allAudioLanguages', 'subLanguages', 'allSubLanguages', 'embedSubs', 'burnInSubtitle', 'extractSubs', 'externalSubDir', 'outputDefault', 'outputVideoExtension', 'outputVideoCodec', 'VideoCodecAllow', 'outputVideoPreset', 'outputVideoFramerate', 'outputVideoBitrate', 'outputAudioCodec', 'AudioCodecAllow', 'outputAudioBitrate', 'outputQualityPercent', 'getSubs', 'outputAudioTrack2Codec', 'AudioCodec2Allow', 'outputAudioTrack2Bitrate', 'outputAudioOtherCodec', 'AudioOtherCodecAllow', 'outputAudioOtherBitrate', 'outputSubtitleCodec', 'outputAudioChannels', 'outputAudioTrack2Channels', 'outputAudioOtherChannels'] for index in range(len(envKeys)): key = 'NZBPO_' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[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] CFG_NEW[section][option] = value section = "UserScript" envCatKey = 'NZBPO_USCATEGORY' envKeys = ['USER_SCRIPT_MEDIAEXTENSIONS', 'USER_SCRIPT_PATH', 'USER_SCRIPT_PARAM', 'USER_SCRIPT_RUNONCE', 'USER_SCRIPT_SUCCESSCODES', 'USER_SCRIPT_CLEAN', 'USDELAY', 'USREMOTE_PATH'] cfgKeys = ['user_script_mediaExtensions', 'user_script_path', 'user_script_param', 'user_script_runOnce', 'user_script_successCodes', 'user_script_clean', 'delay', 'remote_path'] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 except Exception, e: logger.debug("Error %s when applying NZBGet config" % (e))
def process(self, section, dirName, inputName=None, status=0, clientAgent="manual", download_id="", inputCategory=None, failureLink=None): host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] method = nzbtomedia.CFG[section][inputCategory]["method"] delete_failed = int(nzbtomedia.CFG[section][inputCategory]["delete_failed"]) wait_for = int(nzbtomedia.CFG[section][inputCategory]["wait_for"]) try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: remote_path = int(nzbtomedia.CFG[section][inputCategory]["remote_path"]) except: remote_path = 0 try: extract = int(section[inputCategory]["extract"]) except: extract = 0 if ssl: protocol = "https://" else: protocol = "http://" baseURL = "%s%s:%s%s/api/%s" % (protocol, host, port, web_root, apikey) if not server_responding(baseURL): logger.error("Server did not respond. Exiting", section) return [1, "%s: Failed to post-process - %s did not respond." % (section, section) ] imdbid = find_imdbid(dirName, inputName) release = self.get_release(baseURL, imdbid, download_id) # pull info from release found if available release_id = None media_id = None downloader = None release_status_old = None if release: try: release_id = release.keys()[0] media_id = release[release_id]['media_id'] download_id = release[release_id]['download_info']['id'] downloader = release[release_id]['download_info']['downloader'] release_status_old = release[release_id]['status'] except: pass 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(inputName)) cleanName = os.path.splitext(SpecificPath) if cleanName[1] == ".nzb": SpecificPath = cleanName[0] if os.path.isdir(SpecificPath): dirName = SpecificPath process_all_exceptions(inputName, dirName) inputName, dirName = convert_to_ascii(inputName, dirName) if not listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False) and listMediaFiles(dirName, media=False, audio=False, meta=False, archives=True) and extract: logger.debug('Checking for archives to extract in directory: %s' % (dirName)) nzbtomedia.extractFiles(dirName) inputName, dirName = convert_to_ascii(inputName, dirName) good_files = 0 num_files = 0 # Check video files for corruption status = int(status) for video in listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False): num_files += 1 if transcoder.isVideoGood(video, status): import_subs(video) good_files += 1 if not release and not ".cp(tt" in video and imdbid: videoName, videoExt = os.path.splitext(video) video2 = "%s.cp(%s)%s" % (videoName, imdbid, videoExt) logger.debug('Renaming: %s to: %s' % (video, video2)) os.rename(video, video2) if num_files > 0 and good_files == num_files: if status: logger.info("Status shown as failed from Downloader, but %s valid video files found. Setting as success." % (str(good_files)), section) status = 0 elif num_files > 0 and good_files < num_files: logger.info("Status shown as success from Downloader, but corrupt video files found. Setting as failed.", section) if os.environ.has_key('NZBOP_VERSION') and os.environ['NZBOP_VERSION'][0:5] >= '14.0': print('[NZB] MARK=BAD') if failureLink: failureLink = failureLink + '&corrupt=true' status = 1 elif clientAgent == "manual": logger.warning("No media files found in directory %s to manually process." % (dirName), section) 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), section) status = 1 if status == 0: if nzbtomedia.TRANSCODE == 1: result, newDirName = transcoder.Transcode_directory(dirName) if result == 0: logger.debug("Transcoding succeeded for files in %s" % (dirName), section) dirName = newDirName else: logger.error("Transcoding failed for files in %s" % (dirName), section) return [1, "%s: Failed to post-process - Transcoding failed" % (section) ] if method == "manage": command = "/manage.update" else: command = "/renamer.scan" params = {} if download_id: params['downloader'] = downloader or clientAgent params['download_id'] = download_id params['media_folder'] = dirName if remote_path: params['media_folder'] = remoteDir(dirName) url = "%s%s" % (baseURL, command) logger.debug("Opening URL: %s with PARAMS: %s" % (url, params), section) logger.postprocess("Starting %s scan for %s" % (method, inputName), section) try: r = requests.get(url, params=params, verify=False) except requests.ConnectionError: logger.error("Unable to open URL", section) return [1, "%s: Failed to post-process - Unable to connect to %s" % (section, section) ] result = r.json() if not r.status_code in [requests.codes.ok, requests.codes.created, requests.codes.accepted]: logger.error("Server returned status %s" % (str(r.status_code)), section) return [1, "%s: Failed to post-process - Server returned status %s" % (section, str(r.status_code)) ] elif result['success']: logger.postprocess("SUCCESS: Finished %s scan for folder %s" % (method, dirName), section) else: logger.error("FAILED: %s scan was unable to finish for folder %s. exiting!" % (method, dirName), section) return [1, "%s: Failed to post-process - Server did not return success" % (section) ] else: logger.postprocess("FAILED DOWNLOAD DETECTED FOR %s" % (inputName), section) if failureLink: reportNzb(failureLink, clientAgent) if delete_failed and os.path.isdir(dirName) and not os.path.dirname(dirName) == dirName: logger.postprocess("Deleting failed files and folder %s" % dirName, section) rmDir(dirName) if not release_id and not media_id: logger.error("Could not find a downloaded movie in the database matching %s, exiting!" % inputName, section) return [1, "%s: Failed to post-process - Failed download not found in %s" % (section, section) ] if release_id: logger.postprocess("Setting failed release %s to ignored ..." % (inputName), section) url = baseURL + "/release.ignore" params = {'id': release_id} logger.debug("Opening URL: %s with PARAMS: %s" % (url, params), section) try: r = requests.get(url, params=params, verify=False) except requests.ConnectionError: logger.error("Unable to open URL %s" % (url), section) return [1, "%s: Failed to post-process - Unable to connect to %s" % (section, section) ] result = r.json() if not r.status_code in [requests.codes.ok, requests.codes.created, requests.codes.accepted]: logger.error("Server returned status %s" % (str(r.status_code)), section) return [1, "%s: Failed to post-process - Server returned status %s" % (section, str(r.status_code)) ] elif result['success']: logger.postprocess("SUCCESS: %s has been set to ignored ..." % (inputName), section) else: logger.warning("FAILED: Unable to set %s to ignored!" % (inputName), section) return [1, "%s: Failed to post-process - Unable to set %s to ignored" % (section, inputName) ] logger.postprocess("Trying to snatch the next highest ranked release.", section) url = "%s/movie.searcher.try_next" % (baseURL) logger.debug("Opening URL: %s" % (url), section) try: r = requests.get(url, params={'media_id': media_id}) except requests.ConnectionError: logger.error("Unable to open URL %s" % (url), section) return [1, "%s: Failed to post-process - Unable to connect to %s" % (section, section) ] result = r.json() if not r.status_code in [requests.codes.ok, requests.codes.created, requests.codes.accepted]: logger.error("Server returned status %s" % (str(r.status_code)), section) return [1, "%s: Failed to post-process - Server returned status %s" % (section, str(r.status_code)) ] elif result['success']: logger.postprocess("SUCCESS: Snatched the next highest release ...", section) return [0, "%s: Successfully snatched next highest release" % (section) ] else: logger.postprocess("SUCCESS: Unable to find a new release to snatch now. CP will keep searching!", section) return [0, "%s: No new release found now. %s will keep searching" % (section, section) ] # Added a releease that was not in the wanted list so confirm rename successful by finding this movie media.list. if not release: download_id = None # we don't want to filter new releases based on this. # we will now check to see if CPS has finished renaming before returning to TorrentToMedia and unpausing. timeout = time.time() + 60 * wait_for while (time.time() < timeout): # only wait 2 (default) minutes, then return. logger.postprocess("Checking for status change, please stand by ...", section) release = self.get_release(baseURL, imdbid, download_id, release_id) if release: try: if release_id is None and release_status_old is None: # we didn't have a release before, but now we do. logger.postprocess("SUCCESS: Movie %s has now been added to CouchPotato" % (imdbid), section) return [0, "%s: Successfully post-processed %s" % (section, inputName) ] release_status_new = release[release_id]['status'] if release_status_new != release_status_old: logger.postprocess("SUCCESS: Release %s has now been marked with a status of [%s]" % ( inputName, str(release_status_new).upper()), section) return [0, "%s: Successfully post-processed %s" % (section, inputName) ] except: pass if not os.path.isdir(dirName): logger.postprocess("SUCCESS: Input Directory [%s] has been processed and removed" % ( dirName), section) return [0, "%s: Successfully post-processed %s" % (section, inputName) ] elif not listMediaFiles(dirName, media=True, audio=False, meta=False, archives=True): logger.postprocess("SUCCESS: Input Directory [%s] has no remaining media files. This has been fully processed." % ( dirName), section) return [0, "%s: Successfully post-processed %s" % (section, inputName) ] # pause and let CouchPotatoServer catch its breath time.sleep(10 * wait_for) # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resule seeding now. logger.warning( "%s does not appear to have changed status after %s minutes, Please check your logs." % (inputName, wait_for), section) return [1, "%s: Failed to post-process - No change in status" % (section) ]
def initialize(section=None): global NZBGET_POSTPROCESS_ERROR, NZBGET_POSTPROCESS_NONE, NZBGET_POSTPROCESS_PARCHECK, NZBGET_POSTPROCESS_SUCCESS, NZBTOMEDIA_TIMEOUT, FORKS, FORK_DEFAULT, FORK_FAILED_TORRENT, FORK_FAILED, SICKBEARD_TORRENT, SICKBEARD_FAILED, NZBTOMEDIA_BRANCH, NZBTOMEDIA_VERSION, NEWEST_VERSION, NEWEST_VERSION_STRING, VERSION_NOTIFY, SYS_ARGV, CFG, SABNZB_NO_OF_ARGUMENTS, SABNZB_0717_NO_OF_ARGUMENTS, CATEGORIES, TORRENT_CLIENTAGENT, USELINK, OUTPUTDIRECTORY, NOFLATTEN, UTORRENTPWD, UTORRENTUSR, UTORRENTWEBUI, DELUGEHOST, DELUGEPORT, DELUGEUSR, DELUGEPWD, TRANSMISSIONHOST, TRANSMISSIONPORT, TRANSMISSIONPWD, TRANSMISSIONUSR, COMPRESSEDCONTAINER, MEDIACONTAINER, METACONTAINER, SECTIONS, __INITIALIZED__, AUTO_UPDATE, APP_FILENAME, USER_DELAY, APP_NAME, TRANSCODE, DEFAULTS, GIT_PATH, GIT_USER, GIT_BRANCH, GIT_REPO, SYS_ENCODING, NZB_CLIENTAGENT, SABNZBDHOST, SABNZBDPORT, SABNZBDAPIKEY, DUPLICATE, IGNOREEXTENSIONS, VEXTENSION, OUTPUTVIDEOPATH, PROCESSOUTPUT, VCODEC, VCODEC_ALLOW, VPRESET, VFRAMERATE, LOG_DB, VBITRATE, VRESOLUTION, ALANGUAGE, AINCLUDE, ACODEC, ACODEC_ALLOW, ABITRATE, ACODEC2, ACODEC2_ALLOW, ABITRATE2, ACODEC3, ACODEC3_ALLOW, ABITRATE3, ALLOWSUBS, SEXTRACT, SEMBED, SLANGUAGES, SINCLUDE, SUBSDIR, SCODEC, OUTPUTFASTSTART, OUTPUTQUALITYPERCENT, BURN, GETSUBS, NICENESS, LOG_DEBUG, FORCE_CLEAN, FFMPEG_PATH, FFMPEG, FFPROBE, AUDIOCONTAINER, EXTCONTAINER, TORRENT_CLASS, DELETE_ORIGINAL, PASSWORDSFILE, USER_DELAY, USER_SCRIPT, USER_SCRIPT_CLEAN, USER_SCRIPT_MEDIAEXTENSIONS, USER_SCRIPT_PARAM, USER_SCRIPT_RUNONCE, USER_SCRIPT_SUCCESSCODES, DOWNLOADINFO, CHECK_MEDIA, SAFE_MODE, TORRENT_DEFAULTDIR, NZB_DEFAULTDIR, REMOTEPATHS, LOG_ENV if __INITIALIZED__: return False try: locale.setlocale(locale.LC_ALL, "") SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): pass # For OSes that are poorly configured I'll just randomly force UTF-8 if not SYS_ENCODING or SYS_ENCODING in ("ANSI_X3.4-1968", "US-ASCII", "ASCII"): SYS_ENCODING = "UTF-8" if not hasattr(sys, "setdefaultencoding"): reload(sys) try: # pylint: disable=E1101 # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(SYS_ENCODING) except: print "Sorry, you MUST add the nzbToMedia folder to the PYTHONPATH environment variable" print "or find another way to force Python to use " + SYS_ENCODING + " for string encoding." if os.environ.has_key("NZBOP_SCRIPTDIR"): sys.exit(NZBGET_POSTPROCESS_ERROR) else: sys.exit(1) if not makeDir(LOG_DIR): print ("!!! No log folder, logging to screen only!") # init logging logger.ntm_log_instance.initLogging() # run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. if not config.migrate(): logger.error("Unable to migrate config file %s, exiting ..." % (CONFIG_FILE)) if os.environ.has_key("NZBOP_SCRIPTDIR"): pass # We will try and read config from Environment. else: sys.exit(-1) # run migrate to convert NzbGet data from old cfg style to new cfg style if os.environ.has_key("NZBOP_SCRIPTDIR"): CFG = config.addnzbget() else: # load newly migrated config logger.info("Loading config from [%s]" % (CONFIG_FILE)) CFG = config() # Enable/Disable DEBUG Logging LOG_DEBUG = int(CFG["General"]["log_debug"]) LOG_DB = int(CFG["General"]["log_db"]) LOG_ENV = int(CFG["General"]["log_env"]) if LOG_ENV: for item in os.environ: logger.info("%s: %s" % (item, os.environ[item]), "ENVIRONMENT") # initialize the main SB database nzbToMediaDB.upgradeDatabase(nzbToMediaDB.DBConnection(), mainDB.InitialSchema) # Set Version and GIT variables NZBTOMEDIA_VERSION = "10.0" VERSION_NOTIFY = int(CFG["General"]["version_notify"]) AUTO_UPDATE = int(CFG["General"]["auto_update"]) GIT_REPO = "nzbToMedia" GIT_PATH = CFG["General"]["git_path"] GIT_USER = CFG["General"]["git_user"] or "clinton-hall" GIT_BRANCH = CFG["General"]["git_branch"] or "master" FORCE_CLEAN = CFG["General"]["force_clean"] FFMPEG_PATH = CFG["General"]["ffmpeg_path"] CHECK_MEDIA = int(CFG["General"]["check_media"]) SAFE_MODE = int(CFG["General"]["safe_mode"]) # Check for updates via GitHUB if versionCheck.CheckVersion().check_for_new_version(): if AUTO_UPDATE == 1: logger.info("Auto-Updating nzbToMedia, Please wait ...") updated = versionCheck.CheckVersion().update() if updated: # restart nzbToMedia restart() else: logger.error("Update wasn't successful, not restarting. Check your log for more information.") # Set Current Version logger.info( "nzbToMedia Version:" + NZBTOMEDIA_VERSION + " Branch:" + GIT_BRANCH + " (" + platform.system() + " " + platform.release() + ")" ) if int(CFG["WakeOnLan"]["wake"]) == 1: WakeUp() NZB_CLIENTAGENT = CFG["Nzb"]["clientAgent"] # sabnzbd SABNZBDHOST = CFG["Nzb"]["sabnzbd_host"] SABNZBDPORT = int(CFG["Nzb"]["sabnzbd_port"]) SABNZBDAPIKEY = CFG["Nzb"]["sabnzbd_apikey"] NZB_DEFAULTDIR = CFG["Nzb"]["default_downloadDirectory"] TORRENT_CLIENTAGENT = CFG["Torrent"]["clientAgent"] # utorrent | deluge | transmission | rtorrent | other USELINK = CFG["Torrent"]["useLink"] # no | hard | sym OUTPUTDIRECTORY = CFG["Torrent"]["outputDirectory"] # /abs/path/to/complete/ TORRENT_DEFAULTDIR = CFG["Torrent"]["default_downloadDirectory"] CATEGORIES = CFG["Torrent"]["categories"] # music,music_videos,pictures,software NOFLATTEN = CFG["Torrent"]["noFlatten"] if isinstance(NOFLATTEN, str): NOFLATTEN = NOFLATTEN.split(",") if isinstance(CATEGORIES, str): CATEGORIES = CATEGORIES.split(",") DELETE_ORIGINAL = int(CFG["Torrent"]["deleteOriginal"]) UTORRENTWEBUI = CFG["Torrent"]["uTorrentWEBui"] # http://localhost:8090/gui/ UTORRENTUSR = CFG["Torrent"]["uTorrentUSR"] # mysecretusr UTORRENTPWD = CFG["Torrent"]["uTorrentPWD"] # mysecretpwr TRANSMISSIONHOST = CFG["Torrent"]["TransmissionHost"] # localhost TRANSMISSIONPORT = int(CFG["Torrent"]["TransmissionPort"]) TRANSMISSIONUSR = CFG["Torrent"]["TransmissionUSR"] # mysecretusr TRANSMISSIONPWD = CFG["Torrent"]["TransmissionPWD"] # mysecretpwr DELUGEHOST = CFG["Torrent"]["DelugeHost"] # localhost DELUGEPORT = int(CFG["Torrent"]["DelugePort"]) # 8084 DELUGEUSR = CFG["Torrent"]["DelugeUSR"] # mysecretusr DELUGEPWD = CFG["Torrent"]["DelugePWD"] # mysecretpwr REMOTEPATHS = CFG["Network"]["mount_points"] or None if REMOTEPATHS: REMOTEPATHS = [ tuple(item.split(",")) for item in REMOTEPATHS.split("|") ] # /volume1/Public/,E:\|/volume2/share/,\\NAS\ COMPRESSEDCONTAINER = [re.compile(".r\d{2}$", re.I), re.compile(".part\d+.rar$", re.I), re.compile(".rar$", re.I)] COMPRESSEDCONTAINER += [re.compile("%s$" % ext, re.I) for ext in CFG["Extensions"]["compressedExtensions"]] MEDIACONTAINER = CFG["Extensions"]["mediaExtensions"] AUDIOCONTAINER = CFG["Extensions"]["audioExtensions"] METACONTAINER = CFG["Extensions"]["metaExtensions"] # .nfo,.sub,.srt if isinstance(COMPRESSEDCONTAINER, str): COMPRESSEDCONTAINER = COMPRESSEDCONTAINER.split(",") if isinstance(MEDIACONTAINER, str): MEDIACONTAINER = MEDIACONTAINER.split(",") if isinstance(AUDIOCONTAINER, str): AUDIOCONTAINER = AUDIOCONTAINER.split(",") if isinstance(METACONTAINER, str): METACONTAINER = METACONTAINER.split(",") GETSUBS = int(CFG["Transcoder"]["getSubs"]) TRANSCODE = int(CFG["Transcoder"]["transcode"]) DUPLICATE = int(CFG["Transcoder"]["duplicate"]) IGNOREEXTENSIONS = CFG["Transcoder"]["ignoreExtensions"] if isinstance(IGNOREEXTENSIONS, str): IGNOREEXTENSIONS = IGNOREEXTENSIONS.split(",") OUTPUTFASTSTART = int(CFG["Transcoder"]["outputFastStart"]) OUTPUTQUALITYPERCENT = int(CFG["Transcoder"]["outputQualityPercent"]) NICENESS = int(CFG["Transcoder"]["niceness"]) OUTPUTVIDEOPATH = CFG["Transcoder"]["outputVideoPath"] PROCESSOUTPUT = int(CFG["Transcoder"]["processOutput"]) ALANGUAGE = CFG["Transcoder"]["audioLanguage"] AINCLUDE = int(CFG["Transcoder"]["allAudioLanguages"]) SLANGUAGES = CFG["Transcoder"]["subLanguages"] if isinstance(SLANGUAGES, str): SLANGUAGES = SLANGUAGES.split(",") SINCLUDE = int(CFG["Transcoder"]["allSubLanguages"]) SEXTRACT = int(CFG["Transcoder"]["extractSubs"]) SEMBED = int(CFG["Transcoder"]["embedSubs"]) SUBSDIR = CFG["Transcoder"]["externalSubDir"] VEXTENSION = CFG["Transcoder"]["outputVideoExtension"].strip() VCODEC = CFG["Transcoder"]["outputVideoCodec"].strip() VCODEC_ALLOW = CFG["Transcoder"]["VideoCodecAllow"].strip() if isinstance(VCODEC_ALLOW, str): VCODEC_ALLOW = VCODEC_ALLOW.split(",") VPRESET = CFG["Transcoder"]["outputVideoPreset"].strip() VFRAMERATE = float(CFG["Transcoder"]["outputVideoFramerate"].strip()) VBITRATE = int((CFG["Transcoder"]["outputVideoBitrate"].strip()).replace("k", "000")) VRESOLUTION = CFG["Transcoder"]["outputVideoResolution"] ACODEC = CFG["Transcoder"]["outputAudioCodec"].strip() ACODEC_ALLOW = CFG["Transcoder"]["AudioCodecAllow"].strip() if isinstance(ACODEC_ALLOW, str): ACODEC_ALLOW = ACODEC_ALLOW.split(",") ABITRATE = int((CFG["Transcoder"]["outputAudioBitrate"].strip()).replace("k", "000")) ACODEC2 = CFG["Transcoder"]["outputAudioTrack2Codec"].strip() ACODEC2_ALLOW = CFG["Transcoder"]["AudioCodec2Allow"].strip() if isinstance(ACODEC2_ALLOW, str): ACODEC2_ALLOW = ACODEC2_ALLOW.split(",") ABITRATE2 = int((CFG["Transcoder"]["outputAudioTrack2Bitrate"].strip()).replace("k", "000")) ACODEC3 = CFG["Transcoder"]["outputAudioOtherCodec"].strip() ACODEC3_ALLOW = CFG["Transcoder"]["AudioOtherCodecAllow"].strip() if isinstance(ACODEC3_ALLOW, str): ACODEC3_ALLOW = ACODEC3_ALLOW.split(",") ABITRATE3 = int((CFG["Transcoder"]["outputAudioOtherBitrate"].strip()).replace("k", "000")) SCODEC = CFG["Transcoder"]["outputSubtitleCodec"].strip() BURN = int(CFG["Transcoder"]["burnInSubtitle"].strip()) DEFAULTS = CFG["Transcoder"]["outputDefault"].strip() allow_subs = [".mkv", ".mp4", ".m4v", "asf", "wma", "wmv"] codec_alias = { "libx264": ["libx264", "h264", "h.264", "AVC", "MPEG-4"], "libmp3lame": ["libmp3lame", "mp3"], "libfaac": ["libfaac", "aac", "faac"], } transcode_defaults = { "iPad": { "VEXTENSION": ".mp4", "VCODEC": "libx264", "VPRESET": None, "VFRAMERATE": None, "VBITRATE": None, "VRESOLUTION": None, "VCODEC_ALLOW": ["libx264", "h264", "h.264", "AVC", "avc", "mpeg4", "msmpeg4", "MPEG-4"], "ACODEC": "aac", "ACODEC_ALLOW": ["libfaac"], "ABITRATE": None, "ACODEC2": "ac3", "ACODEC2_ALLOW": ["ac3"], "ABITRATE2": None, "ACODEC3": None, "ACODEC3_ALLOW": [], "ABITRATE3": None, "SCODEC": "mov_text", }, "iPad-1080p": { "VEXTENSION": ".mp4", "VCODEC": "libx264", "VPRESET": None, "VFRAMERATE": None, "VBITRATE": None, "VRESOLUTION": "1920:1080", "VCODEC_ALLOW": ["libx264", "h264", "h.264", "AVC", "avc", "mpeg4", "msmpeg4", "MPEG-4"], "ACODEC": "aac", "ACODEC_ALLOW": ["libfaac"], "ABITRATE": None, "ACODEC2": "ac3", "ACODEC2_ALLOW": ["ac3"], "ABITRATE2": None, "ACODEC3": None, "ACODEC3_ALLOW": [], "ABITRATE3": None, "SCODEC": "mov_text", }, "iPad-720p": { "VEXTENSION": ".mp4", "VCODEC": "libx264", "VPRESET": None, "VFRAMERATE": None, "VBITRATE": None, "VRESOLUTION": "1280:720", "VCODEC_ALLOW": ["libx264", "h264", "h.264", "AVC", "avc", "mpeg4", "msmpeg4", "MPEG-4"], "ACODEC": "aac", "ACODEC_ALLOW": ["libfaac"], "ABITRATE": None, "ACODEC2": "ac3", "ACODEC2_ALLOW": ["ac3"], "ABITRATE2": None, "ACODEC3": None, "ACODEC3_ALLOW": [], "ABITRATE3": None, "SCODEC": "mov_text", }, "Apple-TV": { "VEXTENSION": ".mp4", "VCODEC": "libx264", "VPRESET": None, "VFRAMERATE": None, "VBITRATE": None, "VRESOLUTION": "1280:720", "VCODEC_ALLOW": ["libx264", "h264", "h.264", "AVC", "avc", "mpeg4", "msmpeg4", "MPEG-4"], "ACODEC": "ac3", "ACODEC_ALLOW": ["ac3"], "ABITRATE": None, "ACODEC2": "aac", "ACODEC2_ALLOW": ["libfaac"], "ABITRATE2": None, "ACODEC3": None, "ACODEC3_ALLOW": [], "ABITRATE3": None, "SCODEC": "mov_text", }, "iPod": { "VEXTENSION": ".mp4", "VCODEC": "libx264", "VPRESET": None, "VFRAMERATE": None, "VBITRATE": None, "VRESOLUTION": "1280:720", "VCODEC_ALLOW": ["libx264", "h264", "h.264", "AVC", "avc", "mpeg4", "msmpeg4", "MPEG-4"], "ACODEC": "aac", "ACODEC_ALLOW": ["libfaac"], "ABITRATE": 128000, "ACODEC2": None, "ACODEC2_ALLOW": [], "ABITRATE2": None, "ACODEC3": None, "ACODEC3_ALLOW": [], "ABITRATE3": None, "SCODEC": "mov_text", }, "iPhone": { "VEXTENSION": ".mp4", "VCODEC": "libx264", "VPRESET": None, "VFRAMERATE": None, "VBITRATE": None, "VRESOLUTION": "460:320", "VCODEC_ALLOW": ["libx264", "h264", "h.264", "AVC", "avc", "mpeg4", "msmpeg4", "MPEG-4"], "ACODEC": "aac", "ACODEC_ALLOW": ["libfaac"], "ABITRATE": 128000, "ACODEC2": None, "ACODEC2_ALLOW": [], "ABITRATE2": None, "ACODEC3": None, "ACODEC3_ALLOW": [], "ABITRATE3": None, "SCODEC": "mov_text", }, "PS3": { "VEXTENSION": ".mp4", "VCODEC": "libx264", "VPRESET": None, "VFRAMERATE": None, "VBITRATE": None, "VRESOLUTION": None, "VCODEC_ALLOW": ["libx264", "h264", "h.264", "AVC", "avc", "mpeg4", "msmpeg4", "MPEG-4"], "ACODEC": "ac3", "ACODEC_ALLOW": ["ac3"], "ABITRATE": None, "ACODEC2": "aac", "ACODEC2_ALLOW": ["libfaac"], "ABITRATE2": None, "ACODEC3": None, "ACODEC3_ALLOW": [], "ABITRATE3": None, "SCODEC": "mov_text", }, "Roku-480p": { "VEXTENSION": ".mp4", "VCODEC": "libx264", "VPRESET": None, "VFRAMERATE": None, "VBITRATE": None, "VRESOLUTION": None, "VCODEC_ALLOW": ["libx264", "h264", "h.264", "AVC", "avc", "mpeg4", "msmpeg4", "MPEG-4"], "ACODEC": "aac", "ACODEC_ALLOW": ["libfaac"], "ABITRATE": 128000, "ACODEC2": "ac3", "ACODEC2_ALLOW": ["ac3"], "ABITRATE2": None, "ACODEC3": None, "ACODEC3_ALLOW": [], "ABITRATE3": None, "SCODEC": "mov_text", }, "Roku-720p": { "VEXTENSION": ".mp4", "VCODEC": "libx264", "VPRESET": None, "VFRAMERATE": None, "VBITRATE": None, "VRESOLUTION": None, "VCODEC_ALLOW": ["libx264", "h264", "h.264", "AVC", "avc", "mpeg4", "msmpeg4", "MPEG-4"], "ACODEC": "aac", "ACODEC_ALLOW": ["libfaac"], "ABITRATE": 128000, "ACODEC2": "ac3", "ACODEC2_ALLOW": ["ac3"], "ABITRATE2": None, "ACODEC3": None, "ACODEC3_ALLOW": [], "ABITRATE3": None, "SCODEC": "mov_text", }, "Roku-1080p": { "VEXTENSION": ".mp4", "VCODEC": "libx264", "VPRESET": None, "VFRAMERATE": None, "VBITRATE": None, "VRESOLUTION": None, "VCODEC_ALLOW": ["libx264", "h264", "h.264", "AVC", "avc", "mpeg4", "msmpeg4", "MPEG-4"], "ACODEC": "aac", "ACODEC_ALLOW": ["libfaac"], "ABITRATE": 160000, "ACODEC2": "ac3", "ACODEC2_ALLOW": ["ac3"], "ABITRATE2": None, "ACODEC3": None, "ACODEC3_ALLOW": [], "ABITRATE3": None, "SCODEC": "mov_text", }, } if DEFAULTS and DEFAULTS in transcode_defaults: VEXTENSION = transcode_defaults[DEFAULTS]["VEXTENSION"] VCODEC = transcode_defaults[DEFAULTS]["VCODEC"] VPRESET = transcode_defaults[DEFAULTS]["VPRESET"] VFRAMERATE = transcode_defaults[DEFAULTS]["VFRAMERATE"] VBITRATE = transcode_defaults[DEFAULTS]["VBITRATE"] VRESOLUTION = transcode_defaults[DEFAULTS]["VRESOLUTION"] VCODEC_ALLOW = transcode_defaults[DEFAULTS]["VCODEC_ALLOW"] ACODEC = transcode_defaults[DEFAULTS]["ACODEC"] ACODEC_ALLOW = transcode_defaults[DEFAULTS]["ACODEC_ALLOW"] ABITRATE = transcode_defaults[DEFAULTS]["ABITRATE"] ACODEC2 = transcode_defaults[DEFAULTS]["ACODEC2"] ACODEC2_ALLOW = transcode_defaults[DEFAULTS]["ACODEC2_ALLOW"] ABITRATE2 = transcode_defaults[DEFAULTS]["ABITRATE2"] ACODEC3 = transcode_defaults[DEFAULTS]["ACODEC3"] ACODEC3_ALLOW = transcode_defaults[DEFAULTS]["ACODEC3_ALLOW"] ABITRATE3 = transcode_defaults[DEFAULTS]["ABITRATE3"] SCODEC = transcode_defaults[DEFAULTS]["SCODEC"] transcode_defaults = {} # clear memory if VEXTENSION in allow_subs: ALLOWSUBS = 1 if not VCODEC_ALLOW and VCODEC: VCODEC_ALLOW.extend([VCODEC]) for codec in VCODEC_ALLOW: if codec in codec_alias: extra = [item for item in codec_alias[codec] if item not in VCODEC_ALLOW] VCODEC_ALLOW.extend(extra) if not ACODEC_ALLOW and ACODEC: ACODEC_ALLOW.extend([ACODEC]) for codec in ACODEC_ALLOW: if codec in codec_alias: extra = [item for item in codec_alias[codec] if item not in ACODEC_ALLOW] ACODEC_ALLOW.extend(extra) if not ACODEC2_ALLOW and ACODEC2: ACODEC2_ALLOW.extend([ACODEC2]) for codec in ACODEC2_ALLOW: if codec in codec_alias: extra = [item for item in codec_alias[codec] if item not in ACODEC2_ALLOW] ACODEC2_ALLOW.extend(extra) if not ACODEC3_ALLOW and ACODEC3: ACODEC3_ALLOW.extend([ACODEC3]) for codec in ACODEC3_ALLOW: if codec in codec_alias: extra = [item for item in codec_alias[codec] if item not in ACODEC3_ALLOW] ACODEC3_ALLOW.extend(extra) codec_alias = {} # clear memory PASSWORDSFILE = CFG["passwords"]["PassWordFile"] # Setup FFMPEG and FFPROBE locations if platform.system() == "Windows": FFMPEG = os.path.join(FFMPEG_PATH, "ffmpeg.exe") FFPROBE = os.path.join(FFMPEG_PATH, "ffprobe.exe") if not (os.path.isfile(FFMPEG)): # problem FFMPEG = None logger.warning("Failed to locate ffmpeg.exe, transcoding disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") if not (os.path.isfile(FFPROBE)) and CHECK_MEDIA: # problem FFPROBE = None logger.warning("Failed to locate ffprobe.exe, video corruption detection disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") else: try: FFMPEG = subprocess.Popen(["which", "ffmpeg"], stdout=subprocess.PIPE).communicate()[0].strip() FFPROBE = subprocess.Popen(["which", "ffprobe"], stdout=subprocess.PIPE).communicate()[0].strip() except: if os.path.isfile(os.path.join(FFMPEG_PATH, "ffmpeg")): FFMPEG = os.path.join(FFMPEG_PATH, "ffmpeg") if os.path.isfile(os.path.join(FFMPEG_PATH, "ffprobe")): FFPROBE = os.path.join(FFMPEG_PATH, "ffprobe") if not FFMPEG: if os.access(os.path.join(FFMPEG_PATH, "ffmpeg"), os.X_OK): FFMPEG = os.path.join(FFMPEG_PATH, "ffmpeg") else: FFMPEG = None logger.warning("Failed to locate ffmpeg, transcoding disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") if not FFPROBE and CHECK_MEDIA: if os.access(os.path.join(FFMPEG_PATH, "ffprobe"), os.X_OK): FFPROBE = os.path.join(FFMPEG_PATH, "ffprobe") else: FFPROBE = None logger.warning("Failed to locate ffprobe, video corruption detection disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") if not CHECK_MEDIA: # allow users to bypass this. FFPROBE = None # check for script-defied section and if None set to allow sections SECTIONS = CFG[tuple(x for x in CFG if CFG[x].sections and CFG[x].isenabled()) if not section else (section,)] map(CATEGORIES.extend, ([subsection.sections for section, subsection in SECTIONS.items()])) CATEGORIES = list(set(CATEGORIES)) # create torrent class TORRENT_CLASS = create_torrent_class(TORRENT_CLIENTAGENT) # finished initalizing return True
class autoProcessTV: def command_complete(self, url, params, headers, section): r = None try: r = requests.get(url, params=params, headers=headers, stream=True, verify=False) except requests.ConnectionError: logger.error("Unable to open URL: %s" % (url1), section) return None if not r.status_code in [requests.codes.ok, requests.codes.created, requests.codes.accepted]: logger.error("Server returned status %s" % (str(r.status_code)), section) return None else: try: res = json.loads(r.content) return res['state'] except: logger.error("%s did not return expected json data." % section, section) return None def CDH(self, url2, headers): r = None try: r = requests.get(url2, params={}, headers=headers, stream=True, verify=False) except requests.ConnectionError: logger.error("Unable to open URL: %s" % (url2), section) return False if not r.status_code in [requests.codes.ok, requests.codes.created, requests.codes.accepted]: logger.error("Server returned status %s" % (str(r.status_code)), section) return False else: try: res = json.loads(r.content) return res["enableCompletedDownloadHandling"] except: return False def processEpisode(self, section, dirName, inputName=None, failed=False, clientAgent = "manual", download_id=None, inputCategory=None, failureLink=None): host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 if ssl: protocol = "https://" else: protocol = "http://" try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" if not server_responding("%s%s:%s%s" % (protocol,host,port,web_root)): logger.error("Server did not respond. Exiting", section) return [1, "%s: Failed to post-process - %s did not respond." % (section, section) ] # auto-detect correct fork fork, fork_params = autoFork(section, inputCategory) try: username = nzbtomedia.CFG[section][inputCategory]["username"] password = nzbtomedia.CFG[section][inputCategory]["password"] except: username = "" password = "" try: apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] except: apikey = "" try: delete_failed = int(nzbtomedia.CFG[section][inputCategory]["delete_failed"]) except: delete_failed = 0 try: nzbExtractionBy = nzbtomedia.CFG[section][inputCategory]["nzbExtractionBy"] except: nzbExtractionBy = "Downloader" try: process_method = nzbtomedia.CFG[section][inputCategory]["process_method"] except: process_method = None try: remote_path = int(nzbtomedia.CFG[section][inputCategory]["remote_path"]) except: remote_path = 0 try: wait_for = int(nzbtomedia.CFG[section][inputCategory]["wait_for"]) except: wait_for = 2 try: force = int(nzbtomedia.CFG[section][inputCategory]["force"]) except: force = 0 try: extract = int(section[inputCategory]["extract"]) except: extract = 0 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(inputName)) cleanName = os.path.splitext(SpecificPath) if cleanName[1] == ".nzb": SpecificPath = cleanName[0] if os.path.isdir(SpecificPath): dirName = SpecificPath # Attempt to create the directory if it doesn't exist and ignore any # error stating that it already exists. This fixes a bug where SickRage # won't process the directory because it doesn't exist. try: os.makedirs(dirName) # Attempt to create the directory except OSError, e: # Re-raise the error if it wasn't about the directory not existing if e.errno != errno.EEXIST: raise # Check video files for corruption status = int(failed) good_files = 0 num_files = 0 for video in listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False): num_files += 1 if transcoder.isVideoGood(video, status): good_files += 1 import_subs(video) if num_files > 0: if good_files == num_files and not status == 0: logger.info('Found Valid Videos. Setting status Success') status = 0 failed = 0 if good_files < num_files and status == 0: logger.info('Found corrupt videos. Setting status Failed') status = 1 failed = 1 if os.environ.has_key('NZBOP_VERSION') and os.environ['NZBOP_VERSION'][0:5] >= '14.0': print('[NZB] MARK=BAD') if failureLink: failureLink = failureLink + '&corrupt=true' elif clientAgent == "manual" and not listMediaFiles(dirName, media=True, audio=False, meta=False, archives=True): logger.warning("No media files found in directory %s to manually process." % (dirName), section) return [0, ""] # Success (as far as this script is concerned) if fork not in nzbtomedia.SICKBEARD_TORRENT or (clientAgent in ['nzbget','sabnzbd'] and nzbExtractionBy != "Destination"): if inputName: process_all_exceptions(inputName, dirName) inputName, dirName = convert_to_ascii(inputName, dirName) # Now check if tv files exist in destination. if listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False): # Check that a video exists. if not, assume failed. flatten(dirName) # to make sure SickBeard can find the video (not in sub-folder) elif listMediaFiles(dirName, media=False, audio=False, meta=False, archives=True) and extract: logger.debug('Checking for archives to extract in directory: %s' % (dirName)) nzbtomedia.extractFiles(dirName) inputName, dirName = convert_to_ascii(inputName, dirName) good_files = 0 num_files = 0 for video in listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False): num_files += 1 if transcoder.isVideoGood(video, status): good_files += 1 import_subs(video) if num_files > 0 and good_files == num_files: logger.info('Found Valid Videos. Setting status Success') status = 0 failed = 0 if listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False): # Check that a video exists. if not, assume failed. flatten(dirName) elif clientAgent == "manual": logger.warning("No media files found in directory %s to manually process." % (dirName), section) 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), section) status = 1 failed = 1 if status == 0 and nzbtomedia.TRANSCODE == 1: # only transcode successful downlaods result, newDirName = transcoder.Transcode_directory(dirName) if result == 0: logger.debug("SUCCESS: Transcoding succeeded for files in %s" % (dirName), section) dirName = newDirName else: logger.error("FAILED: Transcoding failed for files in %s" % (dirName), section) return [1, "%s: Failed to post-process - Transcoding failed" % (section) ] # configure SB params to pass fork_params['quiet'] = 1 if inputName is not None: fork_params['nzbName'] = inputName for param in copy.copy(fork_params): if param == "failed": fork_params[param] = failed if param in ["dirName", "dir"]: fork_params[param] = dirName if remote_path: fork_params[param] = remoteDir(dirName) if param == "process_method": if process_method: fork_params[param] = process_method else: del fork_params[param] if param == "force": if force: fork_params[param] = force else: del fork_params[param] # delete any unused params so we don't pass them to SB by mistake [fork_params.pop(k) for k,v in fork_params.items() if v is None] if status == 0: logger.postprocess("SUCCESS: The download succeeded, sending a post-process request", section) else: if failureLink: reportNzb(failureLink, clientAgent) if fork in nzbtomedia.SICKBEARD_FAILED: logger.postprocess("FAILED: The download failed. Sending 'failed' process request to %s branch" % (fork), section) elif section == "NzbDrone": logger.postprocess("FAILED: The download failed. Sending failed download to %s for CDH processing" % (fork), section) return [1, "%s: Downlaod Failed. Sending back to %s" % (section, section) ] # Return as failed to flag this in the downloader. else: logger.postprocess("FAILED: The download failed. %s branch does not handle failed downloads. Nothing to process" % (fork), section) if delete_failed and os.path.isdir(dirName) and not os.path.dirname(dirName) == dirName: logger.postprocess("Deleting failed files and folder %s" % (dirName), section) rmDir(dirName) return [1, "%s: Failed to post-process. %s does not support failed downloads" % (section, section) ] # Return as failed to flag this in the downloader. url = None if section == "SickBeard": url = "%s%s:%s%s/home/postprocess/processEpisode" % (protocol,host,port,web_root) elif section == "NzbDrone": url = "%s%s:%s%s/api/command" % (protocol, host, port, web_root) url2 = "%s%s:%s%s/api/config/downloadClient" % (protocol, host, port, web_root) headers = {"X-Api-Key": apikey} params = {'sortKey': 'series.title', 'page': 1, 'pageSize': 1, 'sortDir': 'asc'} if remote_path: logger.debug("remote_path: %s" % (remoteDir(dirName)),section) data = {"name": "DownloadedEpisodesScan", "path": remoteDir(dirName), "downloadClientId": download_id} else: logger.debug("path: %s" % (dirName),section) data = {"name": "DownloadedEpisodesScan", "path": dirName, "downloadClientId": download_id} if not download_id: data.pop("downloadClientId") data = json.dumps(data) try: if section == "SickBeard": logger.debug("Opening URL: %s with params: %s" % (url, str(fork_params)), section) r = None s = requests.Session() login = "******" % (protocol,host,port,web_root) login_params = {'username': username, 'password': password} s.post(login, data=login_params, stream=True, verify=False) r = s.get(url, auth=(username, password), params=fork_params, stream=True, verify=False) elif section == "NzbDrone": logger.debug("Opening URL: %s with data: %s" % (url, str(data)), section) r = None r = requests.post(url, data=data, headers=headers, stream=True, verify=False) except requests.ConnectionError: logger.error("Unable to open URL: %s" % (url), section) return [1, "%s: Failed to post-process - Unable to connect to %s" % (section, section) ] if not r.status_code in [requests.codes.ok, requests.codes.created, requests.codes.accepted]: logger.error("Server returned status %s" % (str(r.status_code)), section) return [1, "%s: Failed to post-process - Server returned status %s" % (section, str(r.status_code)) ] Success = False Started = False if section == "SickBeard": for line in r.iter_lines(): if line: logger.postprocess("%s" % (line), section) if "Processing succeeded" in line or "Successfully processed" in line: Success = True elif section == "NzbDrone": try: res = json.loads(r.content) scan_id = int(res['id']) logger.debug("Scan started with id: %s" % (str(scan_id)), section) Started = True except Exception as e: logger.warning("No scan id was returned due to: %s" % (e), section) scan_id = None Started = False if status != 0 and delete_failed and not os.path.dirname(dirName) == dirName: logger.postprocess("Deleting failed files and folder %s" % (dirName),section) rmDir(dirName) if Success: return [0, "%s: Successfully post-processed %s" % (section, inputName) ] elif section == "NzbDrone" and Started: n = 0 params = {} url = url + "/" + str(scan_id) while n < 6: # set up wait_for minutes to see if command completes.. time.sleep(10 * wait_for) command_status = self.command_complete(url, params, headers, section) if command_status and command_status in ['completed', 'failed']: break n += 1 if command_status: logger.debug("The Scan command return status: %s" % (command_status), section) if not os.path.exists(dirName): logger.debug("The directory %s has been removed. Renaming was successful." % (dirName), section) return [0, "%s: Successfully post-processed %s" % (section, inputName) ] elif command_status and command_status in ['completed']: logger.debug("The Scan command has completed successfully. Renaming was successful.", section) return [0, "%s: Successfully post-processed %s" % (section, inputName) ] elif command_status and command_status in ['failed']: logger.debug("The Scan command has failed. Renaming was not successful.", section) #return [1, "%s: Failed to post-process %s" % (section, inputName) ] if self.CDH(url2, headers): logger.debug("The Scan command did not return status completed, but complete Download Handling is enabled. Passing back to %s." % (section), section) return [status, "%s: Complete DownLoad Handling is enabled. Passing back to %s" % (section, section) ] else: logger.warning("The Scan command did not return a valid status. Renaming was not successful.", section) return [1, "%s: Failed to post-process %s" % (section, inputName) ] else: return [1, "%s: Failed to post-process - Returned log from %s was not as expected." % (section, section) ] # We did not receive Success confirmation.
def processEpisode(self, dirName, nzbName=None, failed=False, clientAgent = "manual", inputCategory=None): # auto-detect correct section section = nzbtomedia.CFG.findsection(inputCategory) if not section: logger.error( "We were unable to find a section for category %s, please check your autoProcessMedia.cfg file." % inputCategory) return 1 # auto-detect correct fork fork, fork_params = autoFork(inputCategory) status = int(failed) host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] username = nzbtomedia.CFG[section][inputCategory]["username"] password = nzbtomedia.CFG[section][inputCategory]["password"] try: apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] except: apikey = "" try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: delete_failed = int(nzbtomedia.CFG[section][inputCategory]["delete_failed"]) except: delete_failed = 0 try: nzbExtractionBy = nzbtomedia.CFG[section][inputCategory]["nzbExtractionBy"] except: nzbExtractionBy = "Downloader" try: process_method = nzbtomedia.CFG[section][inputCategory]["process_method"] except: process_method = None try: Torrent_NoLink = int(nzbtomedia.CFG[section][inputCategory]["Torrent_NoLink"]) except: Torrent_NoLink = 0 try: remote_path = nzbtomedia.CFG[section][inputCategory]["remote_path"] except: remote_path = None 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 if fork not in nzbtomedia.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 nzbtomedia.MEDIACONTAINER: # If the file is a video file if is_sample(filePath, nzbName, nzbtomedia.MINSAMPLESIZE, nzbtomedia.SAMPLEIDS): logger.debug("Removing sample file: %s" % (filePath), section) 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), section) 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), section) status = int(1) failed = True # configure SB params to pass fork_params['quiet'] = 1 if nzbName is not None: fork_params['nzbName'] = nzbName for param in copy.copy(fork_params): if param == "failed": fork_params[param] = failed if param in ["dirName", "dir"]: fork_params[param] = dirName if remote_path: dirName_new = os.path.join(remote_path, os.path.basename(dirName)).replace("\\", "/") fork_params[param] = dirName_new if param == "process_method": if fork in nzbtomedia.SICKBEARD_TORRENT and Torrent_NoLink == 1 and not clientAgent in ['nzbget','sabnzbd']: #use default SickBeard settings here. del fork_params[param] if process_method: fork_params[param] = process_method else: del fork_params[param] # delete any unused params so we don't pass them to SB by mistake [fork_params.pop(k) for k,v in fork_params.items() if v is None] if status == 0: logger.postprocess("SUCCESS: The download succeeded, sending a post-process request", section) else: if fork in nzbtomedia.SICKBEARD_FAILED: logger.postprocess("FAILED: The download failed. Sending 'failed' process request to %s branch" % (fork), section) else: logger.postprocess("FAILED: The download failed. %s branch does not handle failed downloads. Nothing to process" % (fork), section) if delete_failed and os.path.isdir(dirName) and not os.path.dirname(dirName) == dirName: logger.postprocess("Deleting failed files and folder %s" % (dirName), section) delete(dirName) return 0 # Success (as far as this script is concerned) if status == 0 and nzbtomedia.TRANSCODE == 1: # only transcode successful downlaods result = Transcoder().Transcode_directory(dirName) if result == 0: logger.debug("SUCCESS: Transcoding succeeded for files in %s" % (dirName), section) else: logger.warning("FAILED: Transcoding failed for files in %s" % (dirName), section) if ssl: protocol = "https://" else: protocol = "http://" url = None if section == "SickBeard": url = "%s%s:%s%s/home/postprocess/processEpisode" % (protocol,host,port,web_root) elif section == "NzbDrone": url = "%s%s:%s%s/api/command" % (protocol, host, port, web_root) logger.debug("Opening URL: %s" % (url),section) try: r = None if section == "SickBeard": r = requests.get(url, auth=(username, password), params=fork_params, stream=True) elif section == "NzbDrone": params = {"name": "DownloadedEpisodesScan", "path": dirName} headers = {"X-Api-Key": apikey} r = requests.get(url, params=params, headers=headers, stream=True) except requests.ConnectionError: logger.error("Unable to open URL: %s" % (url), section) return 1 # failure for line in r.iter_lines(): if line: logger.postprocess("%s" % (line), section) if status != 0 and delete_failed and not os.path.dirname(dirName) == dirName: logger.postprocess("Deleting failed files and folder %s" % (dirName),section) delete(dirName) return 0 # Success
def main(args, section=None): # Initialize the config nzbtomedia.initialize(section) # clientAgent for NZBs clientAgent = nzbtomedia.NZB_CLIENTAGENT logger.info("#########################################################") logger.info("## ..::[%s]::.. ##" % os.path.basename(__file__)) logger.info("#########################################################") # debug command line options logger.debug("Options passed into nzbToMedia: %s" % args) # Post-Processing Result result = 0 status = 0 # 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("Script triggered from NZBGet (11.0 or later).") if os.environ['NZBOP_UNPACK'] != 'yes': logger.error("Please enable option \"Unpack\" in nzbget configuration file, exiting") sys.exit(nzbtomedia.NZBGET_POSTPROCESS_ERROR) # Check par status if os.environ['NZBPP_PARSTATUS'] == '3': logger.warning("Par-check successful, but Par-repair disabled, exiting") logger.info("Please check your Par-repair settings for future downloads.") sys.exit(nzbtomedia.NZBGET_POSTPROCESS_NONE) if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ['NZBPP_PARSTATUS'] == '4': logger.warning("Par-repair failed, setting status \"failed\"") status = 1 # Check unpack status if os.environ['NZBPP_UNPACKSTATUS'] == '1': logger.warning("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("Download health is compromised and Par-check/repair disabled or no .par2 files found. Setting status \"failed\"") logger.info("Please check your Par-check/repair settings for future downloads.") status = 1 else: logger.info("Par-check/repair disabled or no .par2 files found, and Unpack not required. Health is ok so handle as though download successful") logger.info("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("Nothing to post-process: destination directory %s doesn't exist. Setting status failed" % (os.environ['NZBPP_DIRECTORY'])) status = 1 # Check for download_id to pass to CouchPotato download_id = "" if os.environ.has_key('NZBPR_COUCHPOTATO'): download_id = os.environ['NZBPR_COUCHPOTATO'] # All checks done, now launching the script. clientAgent = 'nzbget' result = process(os.environ['NZBPP_DIRECTORY'], inputName=os.environ['NZBPP_NZBFILENAME'], status=status, clientAgent=clientAgent, download_id=download_id, inputCategory=os.environ['NZBPP_CATEGORY']) # SABnzbd Pre 0.7.17 elif len(args) == nzbtomedia.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 clientAgent = 'sabnzbd' logger.info("Script triggered from SABnzbd") result = process(args[1], inputName=args[2], status=args[7], inputCategory=args[5], clientAgent=clientAgent, download_id='') # SABnzbd 0.7.17+ elif len(args) >= nzbtomedia.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 clientAgent = 'sabnzbd' logger.info("Script triggered from SABnzbd 0.7.17+") result = process(args[1], inputName=args[2], status=args[7], inputCategory=args[5], clientAgent=clientAgent, download_id='') else: # Perform Manual Run logger.warning("Invalid number of arguments received from client, Switching to manual run mode ...") # Loop and auto-process clientAgent = 'manual' for section, subsection in nzbtomedia.SUBSECTIONS.items(): for category in subsection: if nzbtomedia.CFG[section][category].isenabled(): dirNames = get_dirnames(section, category) for dirName in dirNames: logger.info("Starting manual run for %s:%s - Folder:%s" % (section, category, dirName)) results = process(dirName, os.path.basename(dirName), 0, clientAgent=clientAgent, inputCategory=category) if results != 0: logger.error("A problem was reported when trying to perform a manual run for %s:%s." % (section, category)) result = results else: logger.debug("nzbToMedia %s:%s is DISABLED" % (section, category)) if result == 0: logger.info("The %s script completed successfully." % args[0]) if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 sys.exit(nzbtomedia.NZBGET_POSTPROCESS_SUCCESS) else: logger.error("A problem was reported in the %s script." % args[0]) if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 sys.exit(nzbtomedia.NZBGET_POSTPROCESS_ERROR) sys.exit(result)
def processTorrent(inputDirectory, inputName, inputCategory, inputHash, inputID, clientAgent): status = 1 # 1 = failed | 0 = success root = 0 foundFile = 0 uniquePath = 1 if clientAgent != 'manual' and not nzbtomedia.DOWNLOADINFO: logger.debug('Adding TORRENT download info for directory %s to database' % (inputDirectory)) myDB = nzbToMediaDB.DBConnection() encoded, inputDirectory1 = CharReplace(inputDirectory) encoded, inputName1 = CharReplace(inputName) controlValueDict = {"input_directory": unicode(inputDirectory1)} newValueDict = {"input_name": unicode(inputName1), "input_hash": unicode(inputHash), "input_id": unicode(inputID), "client_agent": unicode(clientAgent), "status": 0, "last_update": datetime.date.today().toordinal() } myDB.upsert("downloads", newValueDict, controlValueDict) logger.debug("Received Directory: %s | Name: %s | Category: %s" % (inputDirectory, inputName, inputCategory)) inputDirectory, inputName, inputCategory, root = nzbtomedia.category_search(inputDirectory, inputName, inputCategory, root, nzbtomedia.CATEGORIES) # Confirm the category by parsing directory structure if inputCategory == "": inputCategory = "UNCAT" usercat = inputCategory try: inputName = inputName.encode(nzbtomedia.SYS_ENCODING) except: pass try: inputDirectory = inputDirectory.encode(nzbtomedia.SYS_ENCODING) except: pass logger.debug("Determined Directory: %s | Name: %s | Category: %s" % (inputDirectory, inputName, inputCategory)) # auto-detect section section = nzbtomedia.CFG.findsection(inputCategory).isenabled() if section is None: section = nzbtomedia.CFG.findsection("ALL").isenabled() if section is None: logger.error( 'Category:[%s] is not defined or is not enabled. Please rename it or ensure it is enabled for the appropriate section in your autoProcessMedia.cfg and try again.' % ( inputCategory)) return [-1, ""] else: usercat = "ALL" if len(section) > 1: logger.error( 'Category:[%s] is not unique, %s are using it. Please rename it or disable all other sections using the same category name in your autoProcessMedia.cfg and try again.' % ( usercat, section.keys())) return [-1, ""] if section: sectionName = section.keys()[0] logger.info('Auto-detected SECTION:%s' % (sectionName)) else: logger.error("Unable to locate a section with subsection:%s enabled in your autoProcessMedia.cfg, exiting!" % ( inputCategory)) return [-1, ""] try: Torrent_NoLink = int(section[usercat]["Torrent_NoLink"]) except: Torrent_NoLink = 0 try: extract = int(section[usercat]['extract']) except: extract = 0 try: uniquePath = int(section[usercat]["unique_path"]) except: uniquePath = 1 if clientAgent != 'manual': nzbtomedia.pause_torrent(clientAgent, inputHash, inputID, inputName) if uniquePath: outputDestination = os.path.normpath( nzbtomedia.os.path.join(nzbtomedia.OUTPUTDIRECTORY, inputCategory, nzbtomedia.sanitizeName(inputName))) else: outputDestination = os.path.normpath( nzbtomedia.os.path.join(nzbtomedia.OUTPUTDIRECTORY, inputCategory)) try: outputDestination = outputDestination.encode(nzbtomedia.SYS_ENCODING) except: pass logger.info("Output directory set to: %s" % (outputDestination)) if nzbtomedia.SAFE_MODE and outputDestination == nzbtomedia.TORRENT_DEFAULTDIR: logger.error( 'The output directory:[%s] is the Download Directory. Edit outputDirectory in autoProcessMedia.cfg. Exiting' % ( inputDirectory)) return [-1, ""] logger.debug("Scanning files in directory: %s" % (inputDirectory)) if sectionName == 'HeadPhones': nzbtomedia.NOFLATTEN.extend( inputCategory) # Make sure we preserve folder structure for HeadPhones. now = datetime.datetime.now() inputFiles = nzbtomedia.listMediaFiles(inputDirectory) logger.debug("Found %s files in %s" % (str(len(inputFiles)), inputDirectory)) for inputFile in inputFiles: filePath = os.path.dirname(inputFile) fileName, fileExt = os.path.splitext(os.path.basename(inputFile)) fullFileName = os.path.basename(inputFile) targetFile = nzbtomedia.os.path.join(outputDestination, fullFileName) if inputCategory in nzbtomedia.NOFLATTEN: if not os.path.basename(filePath) in outputDestination: targetFile = nzbtomedia.os.path.join( nzbtomedia.os.path.join(outputDestination, os.path.basename(filePath)), fullFileName) logger.debug( "Setting outputDestination to %s to preserve folder structure" % (os.path.dirname(targetFile))) try: targetFile = targetFile.encode(nzbtomedia.SYS_ENCODING) except: pass if root == 1: if not foundFile: logger.debug("Looking for %s in: %s" % (inputName, inputFile)) if (nzbtomedia.sanitizeName(inputName) in nzbtomedia.sanitizeName(inputFile)) or ( nzbtomedia.sanitizeName(fileName) in nzbtomedia.sanitizeName(inputName)): foundFile = True logger.debug("Found file %s that matches Torrent Name %s" % (fullFileName, inputName)) else: continue if root == 2: mtime_lapse = now - datetime.datetime.fromtimestamp(os.path.getmtime(inputFile)) ctime_lapse = now - datetime.datetime.fromtimestamp(os.path.getctime(inputFile)) if not foundFile: logger.debug("Looking for files with modified/created dates less than 5 minutes old.") if (mtime_lapse < datetime.timedelta(minutes=5)) or (ctime_lapse < datetime.timedelta(minutes=5)): foundFile = True logger.debug("Found file %s with date modifed/created less than 5 minutes ago." % (fullFileName)) else: continue # This file has not been recently moved or created, skip it if Torrent_NoLink == 0: try: nzbtomedia.copy_link(inputFile, targetFile, nzbtomedia.USELINK) nzbtomedia.rmReadOnly(targetFile) except: logger.error("Failed to link: %s to %s" % (inputFile, targetFile)) inputName, outputDestination = convert_to_ascii(inputName, outputDestination) if extract == 1: logger.debug('Checking for archives to extract in directory: %s' % (outputDestination)) nzbtomedia.extractFiles(outputDestination) if not inputCategory in nzbtomedia.NOFLATTEN: #don't flatten hp in case multi cd albums, and we need to copy this back later. nzbtomedia.flatten(outputDestination) # Now check if video files exist in destination: if sectionName in ["SickBeard", "NzbDrone", "CouchPotato"]: numVideos = len( nzbtomedia.listMediaFiles(outputDestination, media=True, audio=False, meta=False, archives=False)) if numVideos > 0: logger.info("Found %s media files in %s" % (numVideos, outputDestination)) status = 0 elif extract != 1: logger.info("Found no media files in %s. Sending to %s to process" % (outputDestination, sectionName)) status = 0 else: logger.warning("Found no media files in %s" % outputDestination) # Only these sections can handling failed downloads so make sure everything else gets through without the check for failed if not sectionName in ['CouchPotato', 'SickBeard', 'NzbDrone']: status = 0 logger.info("Calling %s:%s to post-process:%s" % (sectionName, usercat, inputName)) result = [ 0, "" ] if sectionName == 'UserScript': result = external_script(outputDestination, inputName, inputCategory, section[usercat]) elif sectionName == 'CouchPotato': result = nzbtomedia.autoProcessMovie().process(sectionName,outputDestination, inputName, status, clientAgent, inputHash, inputCategory) elif sectionName in ['SickBeard','NzbDrone']: result = nzbtomedia.autoProcessTV().processEpisode(sectionName,outputDestination, inputName, status, clientAgent, inputCategory) elif sectionName == 'HeadPhones': result = nzbtomedia.autoProcessMusic().process(sectionName,outputDestination, inputName, status, clientAgent, inputCategory) elif sectionName == 'Mylar': result = nzbtomedia.autoProcessComics().processEpisode(sectionName,outputDestination, inputName, status, clientAgent, inputCategory) elif sectionName == 'Gamez': result = nzbtomedia.autoProcessGames().process(sectionName,outputDestination, inputName, status, clientAgent, inputCategory) if result[0] != 0: if clientAgent != 'manual': logger.error( "A problem was reported in the autoProcess* script. If torrent was paused we will resume seeding") nzbtomedia.resume_torrent(clientAgent, inputHash, inputID, inputName) else: if clientAgent != 'manual': # update download status in our DB nzbtomedia.update_downloadInfoStatus(inputName, 1) # remove torrent nzbtomedia.remove_torrent(clientAgent, inputHash, inputID, inputName) if not sectionName == 'UserScript': # for user script, we assume this is cleaned by the script or option USER_SCRIPT_CLEAN # cleanup our processing folders of any misc unwanted files and empty directories nzbtomedia.cleanDir(outputDestination, sectionName, inputCategory) return result
def addnzbget(): # load configs into memory CFG_NEW = config() try: if os.environ.has_key('NZBPO_NDCATEGORY') and os.environ.has_key( 'NZBPO_SBCATEGORY'): if os.environ['NZBPO_NDCATEGORY'] == os.environ[ 'NZBPO_SBCATEGORY']: logger.warning( "%s category is set for SickBeard and NzbDrone. Please check your config in NZBGet" % (os.environ['NZBPO_NDCATEGORY'])) section = "Nzb" key = 'NZBOP_DESTDIR' if os.environ.has_key(key): option = 'default_downloadDirectory' value = os.environ[key] CFG_NEW[section][option] = value section = "General" envKeys = ['AUTO_UPDATE', 'CHECK_MEDIA', 'SAFE_MODE'] cfgKeys = ['auto_update', 'check_media', 'safe_mode'] for index in range(len(envKeys)): key = 'NZBPO_' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[section][option] = value section = "Network" envKeys = ['MOUNTPOINTS'] cfgKeys = ['mount_points'] for index in range(len(envKeys)): key = 'NZBPO_' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[section][option] = value section = "CouchPotato" envCatKey = 'NZBPO_CPSCATEGORY' envKeys = [ 'ENABLED', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'METHOD', 'DELETE_FAILED', 'REMOTE_PATH', 'WAIT_FOR', 'WATCH_DIR' ] cfgKeys = [ 'enabled', 'apikey', 'host', 'port', 'ssl', 'web_root', 'method', 'delete_failed', 'remote_path', 'wait_for', 'watch_dir' ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_CPS' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[ section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 section = "SickBeard" envCatKey = 'NZBPO_SBCATEGORY' envKeys = [ 'ENABLED', 'HOST', 'PORT', 'USERNAME', 'PASSWORD', 'SSL', 'WEB_ROOT', 'WATCH_DIR', 'FORK', 'DELETE_FAILED', 'TORRENT_NOLINK', 'NZBEXTRACTIONBY', 'REMOTE_PATH', 'PROCESS_METHOD' ] cfgKeys = [ 'enabled', 'host', 'port', 'username', 'password', 'ssl', 'web_root', 'watch_dir', 'fork', 'delete_failed', 'Torrent_NoLink', 'nzbExtractionBy', 'remote_path', 'process_method' ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_SB' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[ section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 if os.environ[envCatKey] in CFG_NEW['NzbDrone'].sections: CFG_NEW['NzbDrone'][envCatKey]['enabled'] = 0 section = "HeadPhones" envCatKey = 'NZBPO_HPCATEGORY' envKeys = [ 'ENABLED', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'WAIT_FOR', 'WATCH_DIR', 'REMOTE_PATH' ] cfgKeys = [ 'enabled', 'apikey', 'host', 'port', 'ssl', 'web_root', 'wait_for', 'watch_dir', 'remote_path' ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_HP' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[ section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 section = "Mylar" envCatKey = 'NZBPO_MYCATEGORY' envKeys = [ 'ENABLED', 'HOST', 'PORT', 'USERNAME', 'PASSWORD', 'APIKEY', 'SSL', 'WEB_ROOT', 'WATCH_DIR', 'REMOTE_PATH' ] cfgKeys = [ 'enabled', 'host', 'port', 'username', 'password', 'apikey', 'ssl', 'web_root', 'watch_dir', 'remote_path' ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_MY' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[ section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 section = "Gamez" envCatKey = 'NZBPO_GZCATEGORY' envKeys = [ 'ENABLED', 'APIKEY', 'HOST', 'PORT', 'SSL', 'WEB_ROOT', 'WATCH_DIR', 'LIBRARY', 'REMOTE_PATH' ] cfgKeys = [ 'enabled', 'apikey', 'host', 'port', 'ssl', 'web_root', 'watch_dir', 'library', 'remote_path' ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_GZ' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[ section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 section = "NzbDrone" envCatKey = 'NZBPO_NDCATEGORY' envKeys = [ 'ENABLED', 'HOST', 'APIKEY', 'PORT', 'SSL', 'WEB_ROOT', 'WATCH_DIR', 'FORK', 'DELETE_FAILED', 'TORRENT_NOLINK', 'NZBEXTRACTIONBY', 'WAIT_FOR', 'DELETE_FAILED', 'REMOTE_PATH' ] cfgKeys = [ 'enabled', 'host', 'apikey', 'port', 'ssl', 'web_root', 'watch_dir', 'fork', 'delete_failed', 'Torrent_NoLink', 'nzbExtractionBy', 'wait_for', 'delete_failed', 'remote_path' ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_ND' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[ section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 if os.environ[envCatKey] in CFG_NEW['SickBeard'].sections: CFG_NEW['SickBeard'][envCatKey]['enabled'] = 0 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] CFG_NEW[section][option] = value section = "Posix" envKeys = ['NICENESS', 'IONICE_CLASS', 'IONICE_CLASSDATA'] cfgKeys = ['niceness', 'ionice_class', 'ionice_classdata'] for index in range(len(envKeys)): key = 'NZBPO_' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[section][option] = value section = "Transcoder" envKeys = [ 'TRANSCODE', 'DUPLICATE', 'IGNOREEXTENSIONS', 'OUTPUTFASTSTART', 'OUTPUTVIDEOPATH', 'PROCESSOUTPUT', 'AUDIOLANGUAGE', 'ALLAUDIOLANGUAGES', 'SUBLANGUAGES', 'ALLSUBLANGUAGES', 'EMBEDSUBS', 'BURNINSUBTITLE', 'EXTRACTSUBS', 'EXTERNALSUBDIR', 'OUTPUTDEFAULT', 'OUTPUTVIDEOEXTENSION', 'OUTPUTVIDEOCODEC', 'VIDEOCODECALLOW', 'OUTPUTVIDEOPRESET', 'OUTPUTVIDEOFRAMERATE', 'OUTPUTVIDEOBITRATE', 'OUTPUTAUDIOCODEC', 'AUDIOCODECALLOW', 'OUTPUTAUDIOBITRATE', 'OUTPUTQUALITYPERCENT', 'GETSUBS', 'OUTPUTAUDIOTRACK2CODEC', 'AUDIOCODEC2ALLOW', 'OUTPUTAUDIOTRACK2BITRATE', 'OUTPUTAUDIOOTHERCODEC', 'AUDIOOTHERCODECALLOW', 'OUTPUTAUDIOOTHERBITRATE', 'OUTPUTSUBTITLECODEC', 'OUTPUTAUDIOCHANNELS', 'OUTPUTAUDIOTRACK2CHANNELS', 'OUTPUTAUDIOOTHERCHANNELS' ] cfgKeys = [ 'transcode', 'duplicate', 'ignoreExtensions', 'outputFastStart', 'outputVideoPath', 'processOutput', 'audioLanguage', 'allAudioLanguages', 'subLanguages', 'allSubLanguages', 'embedSubs', 'burnInSubtitle', 'extractSubs', 'externalSubDir', 'outputDefault', 'outputVideoExtension', 'outputVideoCodec', 'VideoCodecAllow', 'outputVideoPreset', 'outputVideoFramerate', 'outputVideoBitrate', 'outputAudioCodec', 'AudioCodecAllow', 'outputAudioBitrate', 'outputQualityPercent', 'getSubs', 'outputAudioTrack2Codec', 'AudioCodec2Allow', 'outputAudioTrack2Bitrate', 'outputAudioOtherCodec', 'AudioOtherCodecAllow', 'outputAudioOtherBitrate', 'outputSubtitleCodec', 'outputAudioChannels', 'outputAudioTrack2Channels', 'outputAudioOtherChannels' ] for index in range(len(envKeys)): key = 'NZBPO_' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] CFG_NEW[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] CFG_NEW[section][option] = value section = "UserScript" envCatKey = 'NZBPO_USCATEGORY' envKeys = [ 'USER_SCRIPT_MEDIAEXTENSIONS', 'USER_SCRIPT_PATH', 'USER_SCRIPT_PARAM', 'USER_SCRIPT_RUNONCE', 'USER_SCRIPT_SUCCESSCODES', 'USER_SCRIPT_CLEAN', 'USDELAY', 'USREMOTE_PATH' ] cfgKeys = [ 'user_script_mediaExtensions', 'user_script_path', 'user_script_param', 'user_script_runOnce', 'user_script_successCodes', 'user_script_clean', 'delay', 'remote_path' ] if os.environ.has_key(envCatKey): for index in range(len(envKeys)): key = 'NZBPO_' + envKeys[index] if os.environ.has_key(key): option = cfgKeys[index] value = os.environ[key] if os.environ[envCatKey] not in CFG_NEW[ section].sections: CFG_NEW[section][os.environ[envCatKey]] = {} CFG_NEW[section][os.environ[envCatKey]][option] = value CFG_NEW[section][os.environ[envCatKey]]['enabled'] = 1 except Exception, e: logger.debug("Error %s when applying NZBGet config" % (e))
def autoFork(section, inputCategory): # auto-detect correct section # config settings try: host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] except: host = None port = None try: username = nzbtomedia.CFG[section][inputCategory]["username"] password = nzbtomedia.CFG[section][inputCategory]["password"] except: username = None password = None try: apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] except: apikey = None try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: fork = nzbtomedia.FORKS.items()[nzbtomedia.FORKS.keys().index( nzbtomedia.CFG[section][inputCategory]["fork"])] except: fork = "auto" if ssl: protocol = "https://" else: protocol = "http://" detected = False if section == "NzbDrone": logger.info("Attempting to verify %s fork" % inputCategory) url = "%s%s:%s%s/api/rootfolder" % (protocol, host, port, web_root) headers = {"X-Api-Key": apikey} try: r = requests.get(url, headers=headers, stream=True, verify=False) except requests.ConnectionError: logger.warning("Could not connect to %s:%s to verify fork!" % (section, inputCategory)) if not r.ok: logger.warning( "Connection to %s:%s failed! Check your configuration" % (section, inputCategory)) fork = ['default', {}] elif fork == "auto": params = nzbtomedia.ALL_FORKS rem_params = [] logger.info("Attempting to auto-detect %s fork" % inputCategory) # define the order to test. Default must be first since the default fork doesn't reject parameters. # then in order of most unique parameters. url = "%s%s:%s%s/home/postprocess/" % (protocol, host, port, web_root) # attempting to auto-detect fork try: if username and password: s = requests.Session() login = "******" % (protocol, host, port, web_root) login_params = {'username': username, 'password': password} s.post(login, data=login_params, stream=True, verify=False) r = s.get(url, auth=(username, password), verify=False) else: r = requests.get(url, verify=False) except requests.ConnectionError: logger.info( "Could not connect to %s:%s to perform auto-fork detection!" % (section, inputCategory)) r = [] if r and r.ok: for param in params: if not 'name="%s"' % (param) in r.text: rem_params.append(param) for param in rem_params: params.pop(param) for fork in sorted(nzbtomedia.FORKS.iteritems(), reverse=False): if params == fork[1]: detected = True break if detected: logger.info("%s:%s fork auto-detection successful ..." % (section, inputCategory)) elif rem_params: logger.info("%s:%s fork auto-detection found custom params %s" % (section, inputCategory, params)) fork = ['custom', params] else: logger.info("%s:%s fork auto-detection failed" % (section, inputCategory)) fork = nzbtomedia.FORKS.items()[nzbtomedia.FORKS.keys().index( nzbtomedia.FORK_DEFAULT)] logger.info("%s:%s fork set to %s" % (section, inputCategory, fork[0])) return fork[0], fork[1]
def processEpisode(self, section, dirName, inputName=None, status=0, clientAgent='manual', inputCategory=None): if status != 0: logger.warning("FAILED DOWNLOAD DETECTED, nothing to process.",section) return 0 host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] username = nzbtomedia.CFG[section][inputCategory]["username"] password = nzbtomedia.CFG[section][inputCategory]["password"] try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: remote_path = int(nzbtomedia.CFG[section][inputCategory]["remote_path"]) except: remote_path = 0 inputName, dirName = convert_to_ascii(inputName, dirName) replaceExtensions(dirName) params = {} params['nzb_folder'] = dirName if remote_path: params['nzb_folder'] = remoteDir(dirName) if inputName != None: params['nzb_name'] = inputName if ssl: protocol = "https://" else: protocol = "http://" url = "%s%s:%s%s/post_process" % (protocol, host, port, web_root) success = False logger.debug("Opening URL: %s" % (url), section) try: r = requests.get(url, auth=(username, password), params=params, stream=True, verify=False) except requests.ConnectionError: logger.error("Unable to open URL", section) return 1 # failure for line in r.iter_lines(): if line: logger.postprocess("%s" % (line), section) if "Post Processing SUCCESSFULL!" in line: success = True if not r.status_code in [requests.codes.ok, requests.codes.created, requests.codes.accepted]: logger.error("Server returned status %s" % (str(r.status_code)), section) return 1 if success: logger.postprocess("SUCCESS: This issue has been processed successfully",section) return 0 else: logger.warning("The issue does not appear to have successfully processed. Please check your Logs",section) return 1 # failure
def autoFork(section, inputCategory): # auto-detect correct section # config settings try: host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] except: host = None port = None try: username = nzbtomedia.CFG[section][inputCategory]["username"] password = nzbtomedia.CFG[section][inputCategory]["password"] except: username = None password = None try: apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] except: apikey = None try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: fork = nzbtomedia.FORKS.items()[nzbtomedia.FORKS.keys().index(nzbtomedia.CFG[section][inputCategory]["fork"])] except: fork = "auto" if ssl: protocol = "https://" else: protocol = "http://" detected = False if section == "NzbDrone": logger.info("Attempting to verify %s fork" % inputCategory) url = "%s%s:%s%s/api/rootfolder" % (protocol,host,port,web_root) headers={"X-Api-Key": apikey} try: r = requests.get(url, headers=headers, stream=True, verify=False) except requests.ConnectionError: logger.warning("Could not connect to %s:%s to verify fork!" % (section, inputCategory)) if not r.ok: logger.warning("Connection to %s:%s failed! Check your configuration" % (section, inputCategory)) fork = ['default', {}] elif fork == "auto": params = nzbtomedia.ALL_FORKS rem_params = [] logger.info("Attempting to auto-detect %s fork" % inputCategory) # define the order to test. Default must be first since the default fork doesn't reject parameters. # then in order of most unique parameters. url = "%s%s:%s%s/home/postprocess/" % (protocol,host,port,web_root) # attempting to auto-detect fork try: if username and password: s = requests.Session() login = "******" % (protocol,host,port,web_root) login_params = {'username': username, 'password': password} s.post(login, data=login_params, stream=True, verify=False) r = s.get(url, auth=(username, password), verify=False) else: r = requests.get(url, verify=False) except requests.ConnectionError: logger.info("Could not connect to %s:%s to perform auto-fork detection!" % (section, inputCategory)) r = [] if r and r.ok: for param in params: if not 'name="%s"' %(param) in r.text: rem_params.append(param) for param in rem_params: params.pop(param) for fork in sorted(nzbtomedia.FORKS.iteritems(), reverse=False): if params == fork[1]: detected = True break if detected: logger.info("%s:%s fork auto-detection successful ..." % (section, inputCategory)) elif rem_params: logger.info("%s:%s fork auto-detection found custom params %s" % (section, inputCategory, params)) fork = ['custom', params] else: logger.info("%s:%s fork auto-detection failed" % (section, inputCategory)) fork = nzbtomedia.FORKS.items()[nzbtomedia.FORKS.keys().index(nzbtomedia.FORK_DEFAULT)] logger.info("%s:%s fork set to %s" % (section, inputCategory, fork[0])) return fork[0], fork[1]
def extract(filePath, outputDestination): # Using Windows if os.name == 'nt': if os_platform() == 'AMD64': platform = 'x64' else: platform = 'x86' if not os.path.dirname(sys.argv[0]): chplocation = os.path.normpath( os.path.join(os.getcwd(), 'nzbtomedia/extractor/bin/chp.exe')) sevenzipLocation = os.path.normpath( os.path.join( os.getcwd(), 'nzbtomedia/extractor/bin/' + platform + '/7z.exe')) else: chplocation = os.path.normpath( os.path.join(os.path.dirname(sys.argv[0]), 'nzbtomedia/extractor/bin/chp.exe')) sevenzipLocation = os.path.normpath( os.path.join( os.path.dirname(sys.argv[0]), 'nzbtomedia/extractor/bin/' + platform + '/7z.exe')) if not os.path.exists(sevenzipLocation): logger.error("EXTRACTOR: Could not find 7-zip, Exiting") return False else: if not os.path.exists(chplocation): cmd_7zip = [sevenzipLocation, "x", "-y"] else: cmd_7zip = [chplocation, sevenzipLocation, "x", "-y"] ext_7zip = [ ".rar", ".zip", ".tar.gz", "tgz", ".tar.bz2", ".tbz", ".tar.lzma", ".tlz", ".7z", ".xz" ] EXTRACT_COMMANDS = dict.fromkeys(ext_7zip, cmd_7zip) # Using unix else: required_cmds = [ "unrar", "unzip", "tar", "unxz", "unlzma", "7zr", "bunzip2" ] ## Possible future suport: # gunzip: gz (cmd will delete original archive) ## the following do not extract to dest dir # ".xz": ["xz", "-d --keep"], # ".lzma": ["xz", "-d --format=lzma --keep"], # ".bz2": ["bzip2", "-d --keep"], EXTRACT_COMMANDS = { ".rar": ["unrar", "x", "-o+", "-y"], ".tar": ["tar", "-xf"], ".zip": ["unzip"], ".tar.gz": ["tar", "-xzf"], ".tgz": ["tar", "-xzf"], ".tar.bz2": ["tar", "-xjf"], ".tbz": ["tar", "-xjf"], ".tar.lzma": ["tar", "--lzma", "-xf"], ".tlz": ["tar", "--lzma", "-xf"], ".tar.xz": ["tar", "--xz", "-xf"], ".txz": ["tar", "--xz", "-xf"], ".7z": ["7zr", "x"], } # Test command exists and if not, remove if not os.getenv('TR_TORRENT_DIR'): for cmd in required_cmds: if call( ['which', cmd]): #note, returns 0 if exists, or 1 if doesn't exist. for k, v in EXTRACT_COMMANDS.items(): if cmd in v[0]: logger.error( "EXTRACTOR: %s not found, disabling support for %s" % (cmd, k)) del EXTRACT_COMMANDS[k] else: logger.warning( "EXTRACTOR: Cannot determine which tool to use when called from Transmission" ) if not EXTRACT_COMMANDS: logger.warning( "EXTRACTOR: No archive extracting programs found, plugin will be disabled" ) ext = os.path.splitext(filePath) cmd = [] if ext[1] in (".gz", ".bz2", ".lzma"): # Check if this is a tar if os.path.splitext(ext[0])[1] == ".tar": cmd = EXTRACT_COMMANDS[".tar" + ext[1]] elif ext[1] in (".1", ".01", ".001") and os.path.splitext( ext[0])[1] in (".rar", ".zip", ".7z"): cmd = EXTRACT_COMMANDS[os.path.splitext(ext[0])[1]] else: if ext[1] in EXTRACT_COMMANDS: cmd = EXTRACT_COMMANDS[ext[1]] else: logger.debug("EXTRACTOR: Unknown file type: %s" % ext[1]) return False # Create outputDestination folder makeDir(outputDestination) passwordsfile = nzbtomedia.CFG["passwords"]["PassWordFile"] if passwordsfile != "" and os.path.isfile(os.path.normpath(passwordsfile)): passwords = [ line.strip() for line in open(os.path.normpath(passwordsfile)) ] else: passwords = [] logger.info("Extracting %s to %s" % (filePath, outputDestination)) logger.debug("Extracting %s %s %s" % (cmd, filePath, outputDestination)) pwd = os.getcwd() # Get our Present Working Directory os.chdir( outputDestination ) # Not all unpack commands accept full paths, so just extract into this directory try: # now works same for nt and *nix cmd.append(filePath) # add filePath to final cmd arg. cmd2 = cmd cmd2.append("-p-") # don't prompt for password. p = Popen(cmd2) # should extract files fine. res = p.wait() if ( res >= 0 and os.name == 'nt' ) or res == 0: # for windows chp returns process id if successful or -1*Error code. Linux returns 0 for successful. logger.info("EXTRACTOR: Extraction was successful for %s to %s" % (filePath, outputDestination)) elif len(passwords) > 0: logger.info("EXTRACTOR: Attempting to extract with passwords") pass_success = int(0) for password in passwords: if password == "": # if edited in windows or otherwise if blank lines. continue cmd2 = cmd #append password here. passcmd = "-p" + password cmd2.append(passcmd) p = Popen(cmd2) # should extract files fine. res = p.wait() if ( res >= 0 and os.name == 'nt' ) or res == 0: # for windows chp returns process id if successful or -1*Error code. Linux returns 0 for successful. logger.info( "EXTRACTOR: Extraction was successful for %s to %s using password: %s" % (filePath, outputDestination, password)) pass_success = int(1) break else: continue if pass_success == int(0): logger.error( "EXTRACTOR: Extraction failed for %s. 7zip result was %s" % (filePath, res)) except: logger.error( "EXTRACTOR: Extraction failed for %s. Could not call command %s" % (filePath, cmd)) os.chdir(pwd) # Go back to our Original Working Directory return True
def processTorrent(inputDirectory, inputName, inputCategory, inputHash, inputID, clientAgent): status = 1 # 1 = failed | 0 = success root = 0 foundFile = 0 if clientAgent != 'manual' and not nzbtomedia.DOWNLOADINFO: logger.debug( 'Adding TORRENT download info for directory %s to database' % (inputDirectory)) myDB = nzbToMediaDB.DBConnection() controlValueDict = {"input_directory": unicode(inputDirectory)} newValueDict = { "input_name": unicode(inputName), "input_hash": unicode(inputHash), "input_id": unicode(inputID), "client_agent": unicode(clientAgent), "status": 0, "last_update": datetime.date.today().toordinal() } myDB.upsert("downloads", newValueDict, controlValueDict) logger.debug("Received Directory: %s | Name: %s | Category: %s" % (inputDirectory, inputName, inputCategory)) inputDirectory, inputName, inputCategory, root = nzbtomedia.category_search( inputDirectory, inputName, inputCategory, root, nzbtomedia.CATEGORIES ) # Confirm the category by parsing directory structure logger.debug("Determined Directory: %s | Name: %s | Category: %s" % (inputDirectory, inputName, inputCategory)) # auto-detect section section = nzbtomedia.CFG.findsection(inputCategory).isenabled() if section is None: logger.error( 'Category:[%s] is not defined or is not enabled. Please rename it or ensure it is enabled for teh appropriate section in your autoProcessMedia.cfg and try again.' % (inputCategory)) return -1 if len(section) > 1: logger.error( 'Category:[%s] is not unique, %s are using it. Please rename it or disable all other sections using the same category name in your autoProcessMedia.cfg and try again.' % (inputCategory, section.keys())) return -1 if section: sectionName = section.keys()[0] logger.info('Auto-detected SECTION:%s' % (sectionName)) else: logger.error( "Unable to locate a section with subsection:%s enabled in your autoProcessMedia.cfg, exiting!" % (inputCategory)) return -1 try: Torrent_NoLink = int(section[inputCategory]["Torrent_NoLink"]) except: Torrent_NoLink = 0 try: extract = int(section[inputCategory]['extract']) except: extract = 0 if not "NONE" in nzbtomedia.USER_SCRIPT_CATEGORIES: try: nzbtomedia.USER_SCRIPT_MEDIAEXTENSIONS = ( nzbtomedia.CFG[sectionName][inputCategory] ["user_script_mediaExtensions"]) except: nzbtomedia.USER_SCRIPT_MEDIAEXTENSIONS = None try: nzbtomedia.USER_SCRIPT = nzbtomedia.CFG[sectionName][ inputCategory]["user_script_path"] except: nzbtomedia.USER_SCRIPT = None try: nzbtomedia.USER_SCRIPT_PARAM = ( nzbtomedia.CFG[sectionName][inputCategory]["user_script_param"] ) except: nzbtomedia.USER_SCRIPT_PARAM = None try: nzbtomedia.USER_SCRIPT_SUCCESSCODES = ( nzbtomedia.CFG[sectionName][inputCategory] ["user_script_successCodes"]) except: nzbtomedia.USER_SCRIPT_SUCCESSCODES = 0 try: nzbtomedia.USER_SCRIPT_CLEAN = int( nzbtomedia.CFG[sectionName][inputCategory] ["user_script_clean"]) except: nzbtomedia.USER_SCRIPT_CLEAN = 1 try: nzbtomedia.USER_SCRIPT_RUNONCE = int( nzbtomedia.CFG[sectionName][inputCategory] ["user_script_runOnce"]) except: nzbtomedia.USER_SCRIPT_RUNONCE = 1 if clientAgent != 'manual': nzbtomedia.pause_torrent(clientAgent, inputHash, inputID, inputName) processCategories = nzbtomedia.CATEGORIES processOnly = processCategories if inputCategory == "": inputCategory = "UNCAT" outputDestination = os.path.normpath( nzbtomedia.os.path.join(nzbtomedia.OUTPUTDIRECTORY, inputCategory, nzbtomedia.sanitizeName(inputName))) logger.info("Output directory set to: %s" % (outputDestination)) if nzbtomedia.SAFE_MODE and outputDestination == nzbtomedia.TORRENT_DEFAULTDIR: logger.error( 'The output directory:[%s] is the Download Directory. Edit outputDirectory in autoProcessMedia.cfg. Exiting' % (inputDirectory)) return -1 if not "NONE" in nzbtomedia.USER_SCRIPT_CATEGORIES: # if None, we only process the 5 listed. if "ALL" in nzbtomedia.USER_SCRIPT_CATEGORIES: # All defined categories processOnly = nzbtomedia.CATEGORIES processOnly.extend( nzbtomedia.USER_SCRIPT_CATEGORIES ) # Adds all categories to be processed by userscript. if not inputCategory in processOnly: logger.info("No processing to be done for category: %s. Exiting" % (inputCategory)) return logger.debug("Scanning files in directory: %s" % (inputDirectory)) if sectionName == 'HeadPhones': nzbtomedia.NOFLATTEN.extend( inputCategory ) # Make sure we preserve folder structure for HeadPhones. now = datetime.datetime.now() inputFiles = nzbtomedia.listMediaFiles(inputDirectory) logger.debug("Found %s files in %s" % (str(len(inputFiles)), inputDirectory)) for inputFile in inputFiles: filePath = os.path.dirname(inputFile) fileName, fileExt = os.path.splitext(os.path.basename(inputFile)) if fileExt in nzbtomedia.EXT_REPLACE: fullFileName = fileName + nzbtomedia.EXT_REPLACE[fileExt] else: fullFileName = os.path.basename(inputFile) targetFile = nzbtomedia.os.path.join(outputDestination, fullFileName) if inputCategory in nzbtomedia.NOFLATTEN: if not os.path.basename(filePath) in outputDestination: targetFile = nzbtomedia.os.path.join( nzbtomedia.os.path.join(outputDestination, os.path.basename(filePath)), fullFileName) logger.debug( "Setting outputDestination to %s to preserve folder structure" % (os.path.dirname(targetFile))) if root == 1: if not foundFile: logger.debug("Looking for %s in: %s" % (inputName, inputFile)) if (nzbtomedia.sanitizeName(inputName) in nzbtomedia.sanitizeName(inputFile)) or ( nzbtomedia.sanitizeName(fileName) in nzbtomedia.sanitizeName(inputName)): foundFile = True logger.debug("Found file %s that matches Torrent Name %s" % (fullFileName, inputName)) else: continue if root == 2: mtime_lapse = now - datetime.datetime.fromtimestamp( os.path.getmtime(inputFile)) ctime_lapse = now - datetime.datetime.fromtimestamp( os.path.getctime(inputFile)) if not foundFile: logger.debug( "Looking for files with modified/created dates less than 5 minutes old." ) if (mtime_lapse < datetime.timedelta(minutes=5)) or ( ctime_lapse < datetime.timedelta(minutes=5)): foundFile = True logger.debug( "Found file %s with date modifed/created less than 5 minutes ago." % (fullFileName)) else: continue # This file has not been recently moved or created, skip it if Torrent_NoLink == 0: try: nzbtomedia.copy_link(inputFile, targetFile, nzbtomedia.USELINK) nzbtomedia.rmReadOnly(targetFile) except: logger.error("Failed to link: %s to %s" % (inputFile, targetFile)) if not inputCategory in nzbtomedia.NOFLATTEN: #don't flatten hp in case multi cd albums, and we need to copy this back later. nzbtomedia.flatten(outputDestination) if extract == 1: logger.debug('Checking for archives to extract in directory: %s' % (outputDestination)) nzbtomedia.extractFiles(outputDestination) # Now check if video files exist in destination: if sectionName in ["SickBeard", "NzbDrone", "CouchPotato"]: numVideos = len( nzbtomedia.listMediaFiles(outputDestination, media=True, audio=False, meta=False, archives=False)) if numVideos > 0: logger.info("Found %s media files in %s" % (numVideos, outputDestination)) status = 0 elif extract != 1: logger.info( "Found no media files in %s. Sending to %s to process" % (outputDestination, sectionName)) status = 0 else: logger.warning("Found no media files in %s" % outputDestination) # Only these sections can handling failed downloads so make sure everything else gets through without the check for failed if not sectionName in ['CouchPotato', 'SickBeard', 'NzbDrone']: status = 0 result = 0 if (inputCategory in nzbtomedia.USER_SCRIPT_CATEGORIES and not "NONE" in nzbtomedia.USER_SCRIPT_CATEGORIES) or ( "ALL" in nzbtomedia.USER_SCRIPT_CATEGORIES and not inputCategory in processCategories): logger.info("Processing user script %s." % (nzbtomedia.USER_SCRIPT)) result = external_script(outputDestination, inputName, inputCategory) elif status != 0: logger.error("Something failed! Please check logs. Exiting") return status logger.info("Calling %s:%s to post-process:%s" % (sectionName, inputCategory, inputName)) if sectionName == 'CouchPotato': result = nzbtomedia.autoProcessMovie().process(sectionName, outputDestination, inputName, status, clientAgent, inputHash, inputCategory) elif sectionName in ['SickBeard', 'NzbDrone']: result = nzbtomedia.autoProcessTV().processEpisode( sectionName, outputDestination, inputName, status, clientAgent, inputCategory) elif sectionName == 'HeadPhones': result = nzbtomedia.autoProcessMusic().process(sectionName, outputDestination, inputName, status, clientAgent, inputCategory) elif sectionName == 'Mylar': result = nzbtomedia.autoProcessComics().processEpisode( sectionName, outputDestination, inputName, status, clientAgent, inputCategory) elif sectionName == 'Gamez': result = nzbtomedia.autoProcessGames().process(sectionName, outputDestination, inputName, status, clientAgent, inputCategory) if result != 0: if clientAgent != 'manual': logger.error( "A problem was reported in the autoProcess* script. If torrent was paused we will resume seeding" ) nzbtomedia.resume_torrent(clientAgent, inputHash, inputID, inputName) else: if clientAgent != 'manual': # update download status in our DB nzbtomedia.update_downloadInfoStatus(inputName, 1) # remove torrent nzbtomedia.remove_torrent(clientAgent, inputHash, inputID, inputName) # cleanup our processing folders of any misc unwanted files and empty directories nzbtomedia.cleanDir(outputDestination, sectionName, inputCategory) return result
def process(self, dirName, nzbName=None, status=0, clientAgent="manual", inputCategory=None): # auto-detect correct section section = nzbtomedia.CFG.findsection(inputCategory) if len(section) == 0: logger.error( "We were unable to find a section for category %s, please check your autoProcessMedia.cfg file." % (inputCategory)) return 1 status = int(status) host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] wait_for = int(nzbtomedia.CFG[section][inputCategory]["wait_for"]) try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: remote_path = nzbtomedia.CFG[section][inputCategory]["remote_path"] except: remote_path = None if ssl: protocol = "https://" else: protocol = "http://" nzbName, dirName = convert_to_ascii(nzbName, dirName) url = "%s%s:%s%s/api" % (protocol,host,port,web_root) if status == 0: params = {} params['apikey'] = apikey params['cmd'] = "forceProcess" params['dir'] = os.path.dirname(dirName) if remote_path: dirName_new = os.path.join(remote_path, os.path.basename(os.path.dirname(dirName))).replace("\\", "/") params['dir'] = dirName_new release_status = self.get_status(url, apikey, dirName) if release_status: if release_status not in ["unprocessed", "snatched"]: logger.warning("%s is marked with a status of %s, skipping ..." % (nzbName, release_status),section) return 0 else: logger.error("Could not find a status for %s" % (nzbName),section) return 1 logger.debug("Opening URL: %s" % (url),section) try: r = requests.get(url, params=params) except requests.ConnectionError: logger.error("Unable to open URL %s" % (url),section) return 1 # failure logger.debug("Result: %s" % (r.text),section) if r.text == "OK": logger.postprocess("SUCCESS: Post-Processing started for %s in folder %s ..." % (nzbName, dirName),section) else: logger.error("FAILED: Post-Processing has NOT started for %s in folder %s. exiting!" % (nzbName, dirName),section) return 1 # failure else: logger.warning("FAILED DOWNLOAD DETECTED", section) return 0 # Success (as far as this script is concerned) # we will now wait 1 minutes for this album to be processed before returning to TorrentToMedia and unpausing. timeout = time.time() + 60 * wait_for while (time.time() < timeout): # only wait 2 (default) minutes, then return. current_status = self.get_status(url, apikey, dirName) if current_status is not None and current_status != release_status: # Something has changed. CPS must have processed this movie. logger.postprocess("SUCCESS: This release is now marked as status [%s]" % (current_status),section) return 0 time.sleep(10 * wait_for) # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resule seeding now. logger.warning("The music album does not appear to have changed status after %s minutes. Please check your Logs" % (wait_for)) return 1 # failure
def main(args, section=None): # Initialize the config nzbtomedia.initialize(section) # clientAgent for NZBs clientAgent = nzbtomedia.NZB_CLIENTAGENT logger.info("#########################################################") logger.info("## ..::[%s]::.. ##" % os.path.basename(__file__)) logger.info("#########################################################") # debug command line options logger.debug("Options passed into nzbToMedia: %s" % args) # Post-Processing Result result = 0 status = 0 # NZBGet if os.environ.has_key('NZBOP_SCRIPTDIR'): # Check if the script is called from nzbget 11.0 or later if os.environ['NZBOP_VERSION'][0:5] < '11.0': logger.error( "NZBGet Version %s is not supported. Please update NZBGet." % (str(os.environ['NZBOP_VERSION']))) sys.exit(nzbtomedia.NZBGET_POSTPROCESS_ERROR) logger.info("Script triggered from NZBGet Version %s." % (str(os.environ['NZBOP_VERSION']))) # Check if the script is called from nzbget 13.0 or later if os.environ.has_key('NZBPP_TOTALSTATUS'): if not os.environ['NZBPP_TOTALSTATUS'] == 'SUCCESS': logger.info("Download failed with status %s." % (os.environ['NZBPP_STATUS'])) status = 1 else: # Check par status if os.environ['NZBPP_PARSTATUS'] == '1' or os.environ[ 'NZBPP_PARSTATUS'] == '4': logger.warning("Par-repair failed, setting status \"failed\"") status = 1 # Check unpack status if os.environ['NZBPP_UNPACKSTATUS'] == '1': logger.warning("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( "Download health is compromised and Par-check/repair disabled or no .par2 files found. Setting status \"failed\"" ) logger.info( "Please check your Par-check/repair settings for future downloads." ) status = 1 else: logger.info( "Par-check/repair disabled or no .par2 files found, and Unpack not required. Health is ok so handle as though download successful" ) logger.info( "Please check your Par-check/repair settings for future downloads." ) # Check for download_id to pass to CouchPotato download_id = "" if os.environ.has_key('NZBPR_COUCHPOTATO'): download_id = os.environ['NZBPR_COUCHPOTATO'] # All checks done, now launching the script. clientAgent = 'nzbget' result = process(os.environ['NZBPP_DIRECTORY'], inputName=os.environ['NZBPP_NZBNAME'], status=status, clientAgent=clientAgent, download_id=download_id, inputCategory=os.environ['NZBPP_CATEGORY']) # SABnzbd Pre 0.7.17 elif len(args) == nzbtomedia.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 clientAgent = 'sabnzbd' logger.info("Script triggered from SABnzbd") result = process(args[1], inputName=args[2], status=args[7], inputCategory=args[5], clientAgent=clientAgent, download_id='') # SABnzbd 0.7.17+ elif len(args) >= nzbtomedia.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 clientAgent = 'sabnzbd' logger.info("Script triggered from SABnzbd 0.7.17+") result = process(args[1], inputName=args[2], status=args[7], inputCategory=args[5], clientAgent=clientAgent, download_id='') else: # Perform Manual Post-Processing logger.warning( "Invalid number of arguments received from client, Switching to manual run mode ..." ) for section, subsections in nzbtomedia.SECTIONS.items(): for subsection in subsections: for dirName in getDirs(section, subsection): logger.info("Starting manual run for %s:%s - Folder:%s" % (section, subsection, dirName)) logger.info( "Checking database for download info for %s ..." % (os.path.basename(dirName))) nzbtomedia.DOWNLOADINFO = get_downloadInfo( os.path.basename(dirName), 0) if nzbtomedia.DOWNLOADINFO: logger.info( "Found download info for %s, setting variables now ..." % (os.path.basename(dirName))) else: logger.info( 'Unable to locate download info for %s, continuing to try and process this release ...' % (os.path.basename(dirName))) try: clientAgent = str( nzbtomedia.DOWNLOADINFO[0]['client_agent']) except: clientAgent = 'manual' try: download_id = str( nzbtomedia.DOWNLOADINFO[0]['input_id']) except: download_id = None if clientAgent.lower( ) not in nzbtomedia.NZB_CLIENTS and clientAgent != 'manual': continue results = process(dirName, os.path.basename(dirName), 0, clientAgent=clientAgent, download_id=download_id, inputCategory=subsection) if results != 0: logger.error( "A problem was reported when trying to perform a manual run for %s:%s." % (section, subsection)) result = results if result == 0: logger.info("The %s script completed successfully." % args[0]) if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 return (nzbtomedia.NZBGET_POSTPROCESS_SUCCESS) else: logger.error("A problem was reported in the %s script." % args[0]) if os.environ.has_key('NZBOP_SCRIPTDIR'): # return code for nzbget v11 return (nzbtomedia.NZBGET_POSTPROCESS_ERROR) return (result)
def initialize(section=None): global NZBGET_POSTPROCESS_ERROR, NZBGET_POSTPROCESS_NONE, NZBGET_POSTPROCESS_PARCHECK, NZBGET_POSTPROCESS_SUCCESS, \ NZBTOMEDIA_TIMEOUT, FORKS, FORK_DEFAULT, FORK_FAILED_TORRENT, FORK_FAILED, SICKBEARD_TORRENT, SICKBEARD_FAILED, \ NZBTOMEDIA_BRANCH, NZBTOMEDIA_VERSION, NEWEST_VERSION, NEWEST_VERSION_STRING, VERSION_NOTIFY, SYS_ARGV, CFG, \ SABNZB_NO_OF_ARGUMENTS, SABNZB_0717_NO_OF_ARGUMENTS, CATEGORIES, TORRENT_CLIENTAGENT, USELINK, OUTPUTDIRECTORY, NOFLATTEN, \ UTORRENTPWD, UTORRENTUSR, UTORRENTWEBUI, DELUGEHOST, DELUGEPORT, DELUGEUSR, DELUGEPWD, TRANSMISSIONHOST, TRANSMISSIONPORT, \ TRANSMISSIONPWD, TRANSMISSIONUSR, COMPRESSEDCONTAINER, MEDIACONTAINER, METACONTAINER, SECTIONS, USER_SCRIPT_CATEGORIES, \ __INITIALIZED__, AUTO_UPDATE, APP_FILENAME, USER_DELAY, APP_NAME, TRANSCODE, GIT_PATH, GIT_USER, \ GIT_BRANCH, GIT_REPO, SYS_ENCODING, NZB_CLIENTAGENT, SABNZBDHOST, SABNZBDPORT, SABNZBDAPIKEY, \ DUPLICATE, IGNOREEXTENSIONS, OUTPUTVIDEOEXTENSION, OUTPUTVIDEOCODEC, OUTPUTVIDEOPRESET, OUTPUTVIDEOFRAMERATE, LOG_DB, \ OUTPUTVIDEOBITRATE, OUTPUTAUDIOCODEC, OUTPUTAUDIOBITRATE, OUTPUTSUBTITLECODEC, OUTPUTFASTSTART, OUTPUTQUALITYPERCENT, \ NICENESS, LOG_DEBUG, FORCE_CLEAN, FFMPEG_PATH, FFMPEG, FFPROBE, AUDIOCONTAINER, EXTCONTAINER, TORRENT_CLASS, \ DELETE_ORIGINAL, PASSWORDSFILE, USER_DELAY, USER_SCRIPT, USER_SCRIPT_CLEAN, USER_SCRIPT_MEDIAEXTENSIONS, \ USER_SCRIPT_PARAM, USER_SCRIPT_RUNONCE, USER_SCRIPT_SUCCESSCODES, DOWNLOADINFO, EXT_REPLACE, CHECK_MEDIA, SAFE_MODE, \ TORRENT_DEFAULTDIR, NZB_DEFAULTDIR, REMOTEPATHS if __INITIALIZED__: return False try: locale.setlocale(locale.LC_ALL, "") SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): pass # For OSes that are poorly configured I'll just randomly force UTF-8 if not SYS_ENCODING or SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'): SYS_ENCODING = 'UTF-8' if not hasattr(sys, "setdefaultencoding"): reload(sys) try: # pylint: disable=E1101 # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(SYS_ENCODING) except: print 'Sorry, you MUST add the nzbToMedia folder to the PYTHONPATH environment variable' print 'or find another way to force Python to use ' + SYS_ENCODING + ' for string encoding.' if os.environ.has_key('NZBOP_SCRIPTDIR'): sys.exit(NZBGET_POSTPROCESS_ERROR) else: sys.exit(1) if not makeDir(LOG_DIR): print("!!! No log folder, logging to screen only!") # init logging logger.ntm_log_instance.initLogging() # run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. if not config.migrate(): logger.error("Unable to migrate config file %s, exiting ..." % (CONFIG_FILE)) if os.environ.has_key('NZBOP_SCRIPTDIR'): pass # We will try and read config from Environment. else: sys.exit(-1) # run migrate to convert NzbGet data from old cfg style to new cfg style if os.environ.has_key('NZBOP_SCRIPTDIR'): CFG = config.addnzbget() else: # load newly migrated config logger.info("Loading config from [%s]" % (CONFIG_FILE)) CFG = config() # Enable/Disable DEBUG Logging LOG_DEBUG = int(CFG['General']['log_debug']) LOG_DB = int(CFG['General']['log_db']) # initialize the main SB database nzbToMediaDB.upgradeDatabase(nzbToMediaDB.DBConnection(), mainDB.InitialSchema) # Set Version and GIT variables NZBTOMEDIA_VERSION = '9.3' VERSION_NOTIFY = int(CFG['General']['version_notify']) AUTO_UPDATE = int(CFG['General']['auto_update']) GIT_REPO = 'nzbToMedia' GIT_PATH = CFG['General']['git_path'] GIT_USER = CFG['General']['git_user'] or 'clinton-hall' GIT_BRANCH = CFG['General']['git_branch'] or 'master' FORCE_CLEAN = CFG["General"]["force_clean"] FFMPEG_PATH = CFG["General"]["ffmpeg_path"] CHECK_MEDIA = int(CFG["General"]["check_media"]) SAFE_MODE = int(CFG["General"]["safe_mode"]) # Check for updates via GitHUB if versionCheck.CheckVersion().check_for_new_version(): if AUTO_UPDATE == 1: logger.info("Auto-Updating nzbToMedia, Please wait ...") updated = versionCheck.CheckVersion().update() if updated: # restart nzbToMedia restart() else: logger.error("Update wasn't successful, not restarting. Check your log for more information.") # Set Current Version logger.info( 'nzbToMedia Version:' + NZBTOMEDIA_VERSION + ' Branch:' + GIT_BRANCH + ' (' + platform.system() + ' ' + platform.release() + ')') if int(CFG["WakeOnLan"]["wake"]) == 1: WakeUp() NZB_CLIENTAGENT = CFG["Nzb"]["clientAgent"] # sabnzbd SABNZBDHOST = CFG["Nzb"]["sabnzbd_host"] SABNZBDPORT = int(CFG["Nzb"]["sabnzbd_port"]) SABNZBDAPIKEY = CFG["Nzb"]["sabnzbd_apikey"] NZB_DEFAULTDIR = CFG["Nzb"]["default_downloadDirectory"] TORRENT_CLIENTAGENT = CFG["Torrent"]["clientAgent"] # utorrent | deluge | transmission | rtorrent | other USELINK = CFG["Torrent"]["useLink"] # no | hard | sym OUTPUTDIRECTORY = CFG["Torrent"]["outputDirectory"] # /abs/path/to/complete/ TORRENT_DEFAULTDIR = CFG["Torrent"]["default_downloadDirectory"] CATEGORIES = (CFG["Torrent"]["categories"]) # music,music_videos,pictures,software NOFLATTEN = (CFG["Torrent"]["noFlatten"]) if isinstance(NOFLATTEN, str): NOFLATTEN = NOFLATTEN.split(',') DELETE_ORIGINAL = int(CFG["Torrent"]["deleteOriginal"]) UTORRENTWEBUI = CFG["Torrent"]["uTorrentWEBui"] # http://localhost:8090/gui/ UTORRENTUSR = CFG["Torrent"]["uTorrentUSR"] # mysecretusr UTORRENTPWD = CFG["Torrent"]["uTorrentPWD"] # mysecretpwr TRANSMISSIONHOST = CFG["Torrent"]["TransmissionHost"] # localhost TRANSMISSIONPORT = int(CFG["Torrent"]["TransmissionPort"]) TRANSMISSIONUSR = CFG["Torrent"]["TransmissionUSR"] # mysecretusr TRANSMISSIONPWD = CFG["Torrent"]["TransmissionPWD"] # mysecretpwr DELUGEHOST = CFG["Torrent"]["DelugeHost"] # localhost DELUGEPORT = int(CFG["Torrent"]["DelugePort"]) # 8084 DELUGEUSR = CFG["Torrent"]["DelugeUSR"] # mysecretusr DELUGEPWD = CFG["Torrent"]["DelugePWD"] # mysecretpwr REMOTEPATHS = CFG["Network"]["mount_points"] or None if REMOTEPATHS: REMOTEPATHS = [ tuple(item.split(',')) for item in REMOTEPATHS.split('|') ] # /volume1/Public/,E:\|/volume2/share/,\\NAS\ COMPRESSEDCONTAINER = [re.compile('.r\d{2}$', re.I), re.compile('.part\d+.rar$', re.I), re.compile('.rar$', re.I)] COMPRESSEDCONTAINER += [re.compile('%s$' % ext, re.I) for ext in CFG["Extensions"]["compressedExtensions"]] EXT_REPLACE = {'.cbr':'.rar', '.cbz':'.zip'} # extensions used for comic books need to be replaced before we can extract. MEDIACONTAINER = CFG["Extensions"]["mediaExtensions"] AUDIOCONTAINER = CFG["Extensions"]["audioExtensions"] METACONTAINER = CFG["Extensions"]["metaExtensions"] # .nfo,.sub,.srt if isinstance(COMPRESSEDCONTAINER, str): COMPRESSEDCONTAINER = COMPRESSEDCONTAINER.split(',') if isinstance(MEDIACONTAINER, str): MEDIACONTAINER = MEDIACONTAINER.split(',') if isinstance(AUDIOCONTAINER, str): AUDIOCONTAINER = AUDIOCONTAINER.split(',') if isinstance(METACONTAINER, str): METACONTAINER = METACONTAINER.split(',') TRANSCODE = int(CFG["Transcoder"]["transcode"]) DUPLICATE = int(CFG["Transcoder"]["duplicate"]) IGNOREEXTENSIONS = (CFG["Transcoder"]["ignoreExtensions"]) OUTPUTVIDEOEXTENSION = CFG["Transcoder"]["outputVideoExtension"].strip() OUTPUTVIDEOCODEC = CFG["Transcoder"]["outputVideoCodec"].strip() OUTPUTVIDEOPRESET = CFG["Transcoder"]["outputVideoPreset"].strip() OUTPUTVIDEOFRAMERATE = CFG["Transcoder"]["outputVideoFramerate"].strip() OUTPUTVIDEOBITRATE = CFG["Transcoder"]["outputVideoBitrate"].strip() OUTPUTAUDIOCODEC = CFG["Transcoder"]["outputAudioCodec"].strip() OUTPUTAUDIOBITRATE = CFG["Transcoder"]["outputAudioBitrate"].strip() OUTPUTSUBTITLECODEC = CFG["Transcoder"]["outputSubtitleCodec"].strip() OUTPUTFASTSTART = int(CFG["Transcoder"]["outputFastStart"]) OUTPUTQUALITYPERCENT = int(CFG["Transcoder"]["outputQualityPercent"]) NICENESS = int(CFG["Transcoder"]["niceness"]) PASSWORDSFILE = CFG["passwords"]["PassWordFile"] # Setup FFMPEG and FFPROBE locations if platform.system() == 'Windows': FFMPEG = os.path.join(FFMPEG_PATH, 'ffmpeg.exe') FFPROBE = os.path.join(FFMPEG_PATH, 'ffprobe.exe') if not (os.path.isfile(FFMPEG)): # problem FFMPEG = None logger.warning("Failed to locate ffmpeg.exe, transcoding disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") if not (os.path.isfile(FFPROBE)) and CHECK_MEDIA: # problem FFPROBE = None logger.warning("Failed to locate ffprobe.exe, video corruption detection disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") else: FFMPEG = subprocess.Popen(['which', 'ffmpeg'], stdout=subprocess.PIPE).communicate()[0].strip() FFPROBE = subprocess.Popen(['which', 'ffprobe'], stdout=subprocess.PIPE).communicate()[0].strip() if not FFMPEG: if os.access(os.path.join(FFMPEG_PATH, 'ffmpeg'), os.X_OK): FFMPEG = os.path.join(FFMPEG_PATH, 'ffmpeg') else: FFMPEG = None logger.warning("Failed to locate ffmpeg, transcoding disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") if not FFPROBE and CHECK_MEDIA: if os.access(os.path.join(FFMPEG_PATH, 'ffprobe'), os.X_OK): FFPROBE = os.path.join(FFMPEG_PATH, 'ffprobe') else: FFPROBE = None logger.warning("Failed to locate ffprobe, video corruption detection disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") if not CHECK_MEDIA: # allow users to bypass this. FFPROBE = None # userscript map(USER_SCRIPT_CATEGORIES.append, ([subsections[0] for subsections in CFG['UserScript'].items()])) # check for script-defied section and if None set to allow sections SECTIONS = CFG[tuple(x for x in CFG if CFG[x].sections and CFG[x].isenabled()) if not section else (section,)] map(CATEGORIES.extend,([subsection.sections for section,subsection in SECTIONS.items()])) CATEGORIES = list(set(CATEGORIES)) # create torrent class TORRENT_CLASS = create_torrent_class(TORRENT_CLIENTAGENT) # finished initalizing return True
def find_imdbid(dirName, inputName): imdbid = None logger.info('Attemping imdbID lookup for %s' % (inputName)) # find imdbid in dirName logger.info('Searching folder and file names for imdbID ...') m = re.search('(tt\d{7})', dirName+inputName) if m: imdbid = m.group(1) logger.info("Found imdbID [%s]" % imdbid) return imdbid if os.path.isdir(dirName): for file in os.listdir(dirName): m = re.search('(tt\d{7})', file) if m: imdbid = m.group(1) logger.info("Found imdbID [%s] via file name" % imdbid) return imdbid if os.environ.has_key('NZBPR__DNZB_MOREINFO'): dnzb_more_info=os.environ.get('NZBPR__DNZB_MOREINFO', '') if dnzb_more_info != '': regex = re.compile(r'^http://www.imdb.com/title/(tt[0-9]+)/$', re.IGNORECASE) m = regex.match(dnzb_more_info) if m: imdbid = m.group(1) logger.info("Found imdbID [%s] from DNZB-MoreInfo" % imdbid) return imdbid logger.info('Searching IMDB for imdbID ...') guess = guessit.guess_movie_info(inputName) if guess: # Movie Title title = None if 'title' in guess: title = guess['title'] # Movie Year year = None if 'year' in guess: year = guess['year'] url = "http://www.omdbapi.com" logger.debug("Opening URL: %s" % url) try: r = requests.get(url, params={'y': year, 't': title}, verify=False) except requests.ConnectionError: logger.error("Unable to open URL %s" % url) return results = r.json() try: imdbid = results['imdbID'] except: pass if imdbid: logger.info("Found imdbID [%s]" % imdbid) return imdbid logger.warning('Unable to find a imdbID for %s' % (inputName))
def process(self, section, dirName, inputName=None, status=0, clientAgent="manual", inputCategory=None): status = int(status) host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] wait_for = int(nzbtomedia.CFG[section][inputCategory]["wait_for"]) try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: remote_path = int(nzbtomedia.CFG[section][inputCategory]["remote_path"]) except: remote_path = 0 if ssl: protocol = "https://" else: protocol = "http://" 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(inputName)) cleanName = os.path.splitext(SpecificPath) if cleanName[1] == ".nzb": SpecificPath = cleanName[0] if os.path.isdir(SpecificPath): dirName = SpecificPath process_all_exceptions(inputName.lower(), dirName) inputName, dirName = convert_to_ascii(inputName, dirName) if not listMediaFiles(dirName, media=False, audio=True, meta=False, archives=False) and listMediaFiles(dirName, media=False, audio=False, meta=False, archives=True): logger.debug('Checking for archives to extract in directory: %s' % (dirName)) nzbtomedia.extractFiles(dirName) inputName, dirName = convert_to_ascii(inputName, dirName) if listMediaFiles(dirName, media=False, audio=True, meta=False, archives=False) and status: logger.info("Status shown as failed from Downloader, but %s valid video files found. Setting as successful." % (str(good_files)), section) status = 0 url = "%s%s:%s%s/api" % (protocol,host,port,web_root) if status == 0: params = {} params['apikey'] = apikey params['cmd'] = "forceProcess" params['dir'] = os.path.dirname(dirName) if remote_path: params['dir'] = remoteDir(dirName) release_status = self.get_status(url, apikey, dirName) if not release_status: logger.error("Could not find a status for %s, is it in the wanted list ?" % (inputName),section) logger.debug("Opening URL: %s with PARAMS: %s" % (url, params), section) try: r = requests.get(url, params=params, verify=False) except requests.ConnectionError: logger.error("Unable to open URL %s" % (url) ,section) return 1 # failure logger.debug("Result: %s" % (r.text),section) if not r.status_code in [requests.codes.ok, requests.codes.created, requests.codes.accepted]: logger.error("Server returned status %s" % (str(r.status_code)), section) return 1 elif r.text == "OK": logger.postprocess("SUCCESS: Post-Processing started for %s in folder %s ..." % (inputName, dirName),section) else: logger.error("FAILED: Post-Processing has NOT started for %s in folder %s. exiting!" % (inputName, dirName),section) return 1 # failure else: logger.warning("FAILED DOWNLOAD DETECTED", section) return 0 # Success (as far as this script is concerned) # we will now wait for this album to be processed before returning to TorrentToMedia and unpausing. timeout = time.time() + 60 * wait_for while (time.time() < timeout): current_status = self.get_status(url, apikey, dirName) if current_status is not None and current_status != release_status: # Something has changed. CPS must have processed this movie. logger.postprocess("SUCCESS: This release is now marked as status [%s]" % (current_status),section) return 0 if not os.path.isdir(dirName): logger.postprocess("SUCCESS: The input directory %s has been removed Processing must have finished." % (dirName),section) return 0 time.sleep(10 * wait_for) # The status hasn't changed. uTorrent can resume seeding now. logger.warning("The music album does not appear to have changed status after %s minutes. Please check your Logs" % (wait_for),section) return 1 # failure
def processEpisode(self, section, dirName, inputName=None, status=0, clientAgent='manual', inputCategory=None): if int(status) != 0: logger.warning("FAILED DOWNLOAD DETECTED, nothing to process.",section) return [1, "%s: Failed to post-process. %s does not support failed downloads" % (section, section) ] host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] username = nzbtomedia.CFG[section][inputCategory]["username"] password = nzbtomedia.CFG[section][inputCategory]["password"] try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: remote_path = int(nzbtomedia.CFG[section][inputCategory]["remote_path"]) except: remote_path = 0 if ssl: protocol = "https://" else: protocol = "http://" url = "%s%s:%s%s/post_process" % (protocol, host, port, web_root) if not server_responding(url): logger.error("Server did not respond. Exiting", section) return [1, "%s: Failed to post-process - %s did not respond." % (section, section) ] inputName, dirName = convert_to_ascii(inputName, dirName) clean_name, ext = os.path.splitext(inputName) if len(ext) == 4: # we assume this was a standrard extension. inputName = clean_name params = {} params['nzb_folder'] = dirName if remote_path: params['nzb_folder'] = remoteDir(dirName) if inputName != None: params['nzb_name'] = inputName success = False logger.debug("Opening URL: %s" % (url), section) try: r = requests.get(url, auth=(username, password), params=params, stream=True, verify=False) except requests.ConnectionError: logger.error("Unable to open URL", section) return [1, "%s: Failed to post-process - Unable to connect to %s" % (section, section) ] for line in r.iter_lines(): if line: logger.postprocess("%s" % (line), section) if ("Post Processing SUCCESSFUL!" or "Post Processing SUCCESSFULL!")in line: success = True if not r.status_code in [requests.codes.ok, requests.codes.created, requests.codes.accepted]: logger.error("Server returned status %s" % (str(r.status_code)), section) return [1, "%s: Failed to post-process - Server returned status %s" % (section, str(r.status_code)) ] if success: logger.postprocess("SUCCESS: This issue has been processed successfully",section) return [0, "%s: Successfully post-processed %s" % (section, inputName) ] else: logger.warning("The issue does not appear to have successfully processed. Please check your Logs",section) return [1, "%s: Failed to post-process - Returned log from %s was not as expected." % (section, section) ]
def initialize(section=None): global NZBGET_POSTPROCESS_ERROR, NZBGET_POSTPROCESS_NONE, NZBGET_POSTPROCESS_PARCHECK, NZBGET_POSTPROCESS_SUCCESS, \ NZBTOMEDIA_TIMEOUT, FORKS, FORK_DEFAULT, FORK_FAILED_TORRENT, FORK_FAILED, SICKBEARD_TORRENT, SICKBEARD_FAILED, \ NZBTOMEDIA_BRANCH, NZBTOMEDIA_VERSION, NEWEST_VERSION, NEWEST_VERSION_STRING, VERSION_NOTIFY, SYS_ARGV, CFG, \ SABNZB_NO_OF_ARGUMENTS, SABNZB_0717_NO_OF_ARGUMENTS, CATEGORIES, TORRENT_CLIENTAGENT, USELINK, OUTPUTDIRECTORY, \ NOFLATTEN, UTORRENTPWD, UTORRENTUSR, UTORRENTWEBUI, DELUGEHOST, DELUGEPORT, DELUGEUSR, DELUGEPWD, VLEVEL, \ TRANSMISSIONHOST, TRANSMISSIONPORT, TRANSMISSIONPWD, TRANSMISSIONUSR, COMPRESSEDCONTAINER, MEDIACONTAINER, \ METACONTAINER, SECTIONS, ALL_FORKS, TEST_FILE, GENERALOPTS, LOG_GIT, GROUPS, SEVENZIP, CONCAT, VCRF, \ __INITIALIZED__, AUTO_UPDATE, APP_FILENAME, USER_DELAY, APP_NAME, TRANSCODE, DEFAULTS, GIT_PATH, GIT_USER, \ GIT_BRANCH, GIT_REPO, SYS_ENCODING, NZB_CLIENTAGENT, SABNZBDHOST, SABNZBDPORT, SABNZBDAPIKEY, \ DUPLICATE, IGNOREEXTENSIONS, VEXTENSION, OUTPUTVIDEOPATH, PROCESSOUTPUT, VCODEC, VCODEC_ALLOW, VPRESET, \ VFRAMERATE, LOG_DB, VBITRATE, VRESOLUTION, ALANGUAGE, AINCLUDE, ACODEC, ACODEC_ALLOW, ABITRATE, \ ACODEC2, ACODEC2_ALLOW, ABITRATE2, ACODEC3, ACODEC3_ALLOW, ABITRATE3, ALLOWSUBS, SEXTRACT, SEMBED, SLANGUAGES, \ SINCLUDE, SUBSDIR, SCODEC, OUTPUTFASTSTART, OUTPUTQUALITYPERCENT, BURN, GETSUBS, HWACCEL, LOG_DIR, LOG_FILE, \ NICENESS, LOG_DEBUG, FORCE_CLEAN, FFMPEG_PATH, FFMPEG, FFPROBE, AUDIOCONTAINER, EXTCONTAINER, TORRENT_CLASS, \ DELETE_ORIGINAL, PASSWORDSFILE, USER_DELAY, USER_SCRIPT, USER_SCRIPT_CLEAN, USER_SCRIPT_MEDIAEXTENSIONS, \ USER_SCRIPT_PARAM, USER_SCRIPT_RUNONCE, USER_SCRIPT_SUCCESSCODES, DOWNLOADINFO, CHECK_MEDIA, SAFE_MODE, \ TORRENT_DEFAULTDIR, NZB_DEFAULTDIR, REMOTEPATHS, LOG_ENV, PID_FILE, MYAPP, ACHANNELS, ACHANNELS2, ACHANNELS3 if __INITIALIZED__: return False if os.environ.has_key('NTM_LOGFILE'): LOG_FILE = os.environ['NTM_LOGFILE'] LOG_DIR = os.path.split(LOG_FILE)[0] if not makeDir(LOG_DIR): print("No log folder, logging to screen only") MYAPP = RunningProcess() while MYAPP.alreadyrunning(): print("Waiting for existing session to end") time.sleep(30) try: locale.setlocale(locale.LC_ALL, "") SYS_ENCODING = locale.getpreferredencoding() except (locale.Error, IOError): pass # For OSes that are poorly configured I'll just randomly force UTF-8 if not SYS_ENCODING or SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'): SYS_ENCODING = 'UTF-8' if not hasattr(sys, "setdefaultencoding"): reload(sys) try: # pylint: disable=E1101 # On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError sys.setdefaultencoding(SYS_ENCODING) except: print 'Sorry, you MUST add the nzbToMedia folder to the PYTHONPATH environment variable' print 'or find another way to force Python to use ' + SYS_ENCODING + ' for string encoding.' if os.environ.has_key('NZBOP_SCRIPTDIR'): sys.exit(NZBGET_POSTPROCESS_ERROR) else: sys.exit(1) # init logging logger.ntm_log_instance.initLogging() # run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options. if not config.migrate(): logger.error("Unable to migrate config file %s, exiting ..." % (CONFIG_FILE)) if os.environ.has_key('NZBOP_SCRIPTDIR'): pass # We will try and read config from Environment. else: sys.exit(-1) # run migrate to convert NzbGet data from old cfg style to new cfg style if os.environ.has_key('NZBOP_SCRIPTDIR'): CFG = config.addnzbget() else: # load newly migrated config logger.info("Loading config from [%s]" % (CONFIG_FILE)) CFG = config() # Enable/Disable DEBUG Logging LOG_DEBUG = int(CFG['General']['log_debug']) LOG_DB = int(CFG['General']['log_db']) LOG_ENV = int(CFG['General']['log_env']) LOG_GIT = int(CFG['General']['log_git']) if LOG_ENV: for item in os.environ: logger.info("%s: %s" % (item, os.environ[item]), "ENVIRONMENT") # initialize the main SB database nzbToMediaDB.upgradeDatabase(nzbToMediaDB.DBConnection(), mainDB.InitialSchema) # Set Version and GIT variables NZBTOMEDIA_VERSION = '10.8' VERSION_NOTIFY = int(CFG['General']['version_notify']) AUTO_UPDATE = int(CFG['General']['auto_update']) GIT_REPO = 'nzbToMedia' GIT_PATH = CFG['General']['git_path'] GIT_USER = CFG['General']['git_user'] or 'clinton-hall' GIT_BRANCH = CFG['General']['git_branch'] or 'master' FORCE_CLEAN = int(CFG["General"]["force_clean"]) FFMPEG_PATH = CFG["General"]["ffmpeg_path"] CHECK_MEDIA = int(CFG["General"]["check_media"]) SAFE_MODE = int(CFG["General"]["safe_mode"]) # Check for updates via GitHUB if versionCheck.CheckVersion().check_for_new_version(): if AUTO_UPDATE == 1: logger.info("Auto-Updating nzbToMedia, Please wait ...") updated = versionCheck.CheckVersion().update() if updated: # restart nzbToMedia try: del MYAPP except: pass restart() else: logger.error("Update wasn't successful, not restarting. Check your log for more information.") # Set Current Version logger.info( 'nzbToMedia Version:' + NZBTOMEDIA_VERSION + ' Branch:' + GIT_BRANCH + ' (' + platform.system() + ' ' + platform.release() + ')') if int(CFG["WakeOnLan"]["wake"]) == 1: WakeUp() NZB_CLIENTAGENT = CFG["Nzb"]["clientAgent"] # sabnzbd SABNZBDHOST = CFG["Nzb"]["sabnzbd_host"] SABNZBDPORT = int(CFG["Nzb"]["sabnzbd_port"]) SABNZBDAPIKEY = CFG["Nzb"]["sabnzbd_apikey"] NZB_DEFAULTDIR = CFG["Nzb"]["default_downloadDirectory"] GROUPS = CFG["Custom"]["remove_group"] if isinstance(GROUPS, str): GROUPS = GROUPS.split(',') if GROUPS == ['']: GROUPS = None TORRENT_CLIENTAGENT = CFG["Torrent"]["clientAgent"] # utorrent | deluge | transmission | rtorrent | vuze |other USELINK = CFG["Torrent"]["useLink"] # no | hard | sym OUTPUTDIRECTORY = CFG["Torrent"]["outputDirectory"] # /abs/path/to/complete/ TORRENT_DEFAULTDIR = CFG["Torrent"]["default_downloadDirectory"] CATEGORIES = (CFG["Torrent"]["categories"]) # music,music_videos,pictures,software NOFLATTEN = (CFG["Torrent"]["noFlatten"]) if isinstance(NOFLATTEN, str): NOFLATTEN = NOFLATTEN.split(',') if isinstance(CATEGORIES, str): CATEGORIES = CATEGORIES.split(',') DELETE_ORIGINAL = int(CFG["Torrent"]["deleteOriginal"]) UTORRENTWEBUI = CFG["Torrent"]["uTorrentWEBui"] # http://localhost:8090/gui/ UTORRENTUSR = CFG["Torrent"]["uTorrentUSR"] # mysecretusr UTORRENTPWD = CFG["Torrent"]["uTorrentPWD"] # mysecretpwr TRANSMISSIONHOST = CFG["Torrent"]["TransmissionHost"] # localhost TRANSMISSIONPORT = int(CFG["Torrent"]["TransmissionPort"]) TRANSMISSIONUSR = CFG["Torrent"]["TransmissionUSR"] # mysecretusr TRANSMISSIONPWD = CFG["Torrent"]["TransmissionPWD"] # mysecretpwr DELUGEHOST = CFG["Torrent"]["DelugeHost"] # localhost DELUGEPORT = int(CFG["Torrent"]["DelugePort"]) # 8084 DELUGEUSR = CFG["Torrent"]["DelugeUSR"] # mysecretusr DELUGEPWD = CFG["Torrent"]["DelugePWD"] # mysecretpwr REMOTEPATHS = CFG["Network"]["mount_points"] or None if REMOTEPATHS: if isinstance(REMOTEPATHS, list): REMOTEPATHS = ','.join(REMOTEPATHS) # fix in case this imported as list. REMOTEPATHS = [ tuple(item.split(',')) for item in REMOTEPATHS.split('|') ] # /volume1/Public/,E:\|/volume2/share/,\\NAS\ devnull = open(os.devnull, 'w') try: subprocess.Popen(["nice"], stdout=devnull, stderr=devnull).communicate() NICENESS.extend(['nice', '-n%s' % (int(CFG["Posix"]["niceness"]))]) except: pass try: subprocess.Popen(["ionice"], stdout=devnull, stderr=devnull).communicate() try: NICENESS.extend(['ionice', '-c%s' % (int(CFG["Posix"]["ionice_class"]))]) except: pass try: if 'ionice' in NICENESS: NICENESS.extend(['-n%s' % (int(CFG["Posix"]["ionice_classdata"]))]) else: NICENESS.extend(['ionice', '-n%s' % (int(CFG["Posix"]["ionice_classdata"]))]) except: pass except: pass devnull.close() COMPRESSEDCONTAINER = [re.compile('.r\d{2}$', re.I), re.compile('.part\d+.rar$', re.I), re.compile('.rar$', re.I)] COMPRESSEDCONTAINER += [re.compile('%s$' % ext, re.I) for ext in CFG["Extensions"]["compressedExtensions"]] MEDIACONTAINER = CFG["Extensions"]["mediaExtensions"] AUDIOCONTAINER = CFG["Extensions"]["audioExtensions"] METACONTAINER = CFG["Extensions"]["metaExtensions"] # .nfo,.sub,.srt if isinstance(COMPRESSEDCONTAINER, str): COMPRESSEDCONTAINER = COMPRESSEDCONTAINER.split(',') if isinstance(MEDIACONTAINER, str): MEDIACONTAINER = MEDIACONTAINER.split(',') if isinstance(AUDIOCONTAINER, str): AUDIOCONTAINER = AUDIOCONTAINER.split(',') if isinstance(METACONTAINER, str): METACONTAINER = METACONTAINER.split(',') GETSUBS = int(CFG["Transcoder"]["getSubs"]) TRANSCODE = int(CFG["Transcoder"]["transcode"]) DUPLICATE = int(CFG["Transcoder"]["duplicate"]) CONCAT = int(CFG["Transcoder"]["concat"]) IGNOREEXTENSIONS = (CFG["Transcoder"]["ignoreExtensions"]) if isinstance(IGNOREEXTENSIONS, str): IGNOREEXTENSIONS = IGNOREEXTENSIONS.split(',') OUTPUTFASTSTART = int(CFG["Transcoder"]["outputFastStart"]) GENERALOPTS = (CFG["Transcoder"]["generalOptions"]) if isinstance(GENERALOPTS, str): GENERALOPTS = GENERALOPTS.split(',') if GENERALOPTS == ['']: GENERALOPTS = [] try: OUTPUTQUALITYPERCENT = int(CFG["Transcoder"]["outputQualityPercent"]) except: pass OUTPUTVIDEOPATH = CFG["Transcoder"]["outputVideoPath"] PROCESSOUTPUT = int(CFG["Transcoder"]["processOutput"]) ALANGUAGE = CFG["Transcoder"]["audioLanguage"] AINCLUDE = int(CFG["Transcoder"]["allAudioLanguages"]) SLANGUAGES = CFG["Transcoder"]["subLanguages"] if isinstance(SLANGUAGES, str): SLANGUAGES = SLANGUAGES.split(',') if SLANGUAGES == ['']: SLANGUAGES = [] SINCLUDE = int(CFG["Transcoder"]["allSubLanguages"]) SEXTRACT = int(CFG["Transcoder"]["extractSubs"]) SEMBED = int(CFG["Transcoder"]["embedSubs"]) SUBSDIR = CFG["Transcoder"]["externalSubDir"] VEXTENSION = CFG["Transcoder"]["outputVideoExtension"].strip() VCODEC = CFG["Transcoder"]["outputVideoCodec"].strip() VCODEC_ALLOW = CFG["Transcoder"]["VideoCodecAllow"].strip() if isinstance(VCODEC_ALLOW, str): VCODEC_ALLOW = VCODEC_ALLOW.split(',') if VCODEC_ALLOW == ['']: VCODEC_ALLOW = [] VPRESET = CFG["Transcoder"]["outputVideoPreset"].strip() try: VFRAMERATE = float(CFG["Transcoder"]["outputVideoFramerate"].strip()) except: pass try: VCRF = int(CFG["Transcoder"]["outputVideoCRF"].strip()) except: pass try: VLEVEL = CFG["Transcoder"]["outputVideoLevel"].strip() except: pass try: VBITRATE = int((CFG["Transcoder"]["outputVideoBitrate"].strip()).replace('k','000')) except: pass VRESOLUTION = CFG["Transcoder"]["outputVideoResolution"] ACODEC = CFG["Transcoder"]["outputAudioCodec"].strip() ACODEC_ALLOW = CFG["Transcoder"]["AudioCodecAllow"].strip() if isinstance(ACODEC_ALLOW, str): ACODEC_ALLOW = ACODEC_ALLOW.split(',') if ACODEC_ALLOW == ['']: ACODEC_ALLOW = [] try: ACHANNELS = int(CFG["Transcoder"]["outputAudioChannels"].strip()) except: pass try: ABITRATE = int((CFG["Transcoder"]["outputAudioBitrate"].strip()).replace('k','000')) except: pass ACODEC2 = CFG["Transcoder"]["outputAudioTrack2Codec"].strip() ACODEC2_ALLOW = CFG["Transcoder"]["AudioCodec2Allow"].strip() if isinstance(ACODEC2_ALLOW, str): ACODEC2_ALLOW = ACODEC2_ALLOW.split(',') if ACODEC2_ALLOW == ['']: ACODEC2_ALLOW = [] try: ACHANNELS2 = int(CFG["Transcoder"]["outputAudioTrack2Channels"].strip()) except: pass try: ABITRATE2 = int((CFG["Transcoder"]["outputAudioTrack2Bitrate"].strip()).replace('k','000')) except: pass ACODEC3 = CFG["Transcoder"]["outputAudioOtherCodec"].strip() ACODEC3_ALLOW = CFG["Transcoder"]["AudioOtherCodecAllow"].strip() if isinstance(ACODEC3_ALLOW, str): ACODEC3_ALLOW = ACODEC3_ALLOW.split(',') if ACODEC3_ALLOW == ['']: ACODEC3_ALLOW = [] try: ACHANNELS3 = int(CFG["Transcoder"]["outputAudioOtherChannels"].strip()) except: pass try: ABITRATE3 = int((CFG["Transcoder"]["outputAudioOtherBitrate"].strip()).replace('k','000')) except: pass SCODEC = CFG["Transcoder"]["outputSubtitleCodec"].strip() BURN = int(CFG["Transcoder"]["burnInSubtitle"].strip()) DEFAULTS = CFG["Transcoder"]["outputDefault"].strip() HWACCEL = int(CFG["Transcoder"]["hwAccel"]) allow_subs = ['.mkv','.mp4', '.m4v', 'asf', 'wma', 'wmv'] codec_alias = { 'libx264':['libx264', 'h264', 'h.264', 'AVC', 'MPEG-4'], 'libmp3lame':['libmp3lame', 'mp3'], 'libfaac':['libfaac', 'aac', 'faac'] } transcode_defaults = { 'iPad':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':None,'VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'aac','ACODEC_ALLOW':['libfaac'],'ABITRATE':None, 'ACHANNELS':2, 'ACODEC2':'ac3','ACODEC2_ALLOW':['ac3'],'ABITRATE2':None, 'ACHANNELS2':6, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'iPad-1080p':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':'1920:1080','VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'aac','ACODEC_ALLOW':['libfaac'],'ABITRATE':None, 'ACHANNELS':2, 'ACODEC2':'ac3','ACODEC2_ALLOW':['ac3'],'ABITRATE2':None, 'ACHANNELS2':6, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'iPad-720p':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':'1280:720','VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'aac','ACODEC_ALLOW':['libfaac'],'ABITRATE':None, 'ACHANNELS':2, 'ACODEC2':'ac3','ACODEC2_ALLOW':['ac3'],'ABITRATE2':None, 'ACHANNELS2':6, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'Apple-TV':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':'1280:720','VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'ac3','ACODEC_ALLOW':['ac3'],'ABITRATE':None, 'ACHANNELS':6, 'ACODEC2':'aac','ACODEC2_ALLOW':['libfaac'],'ABITRATE2':None, 'ACHANNELS2':2, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'iPod':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':'1280:720','VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'aac','ACODEC_ALLOW':['libfaac'],'ABITRATE':128000, 'ACHANNELS':2, 'ACODEC2':None,'ACODEC2_ALLOW':[],'ABITRATE2':None, 'ACHANNELS2':None, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'iPhone':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':'460:320','VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'aac','ACODEC_ALLOW':['libfaac'],'ABITRATE':128000, 'ACHANNELS':2, 'ACODEC2':None,'ACODEC2_ALLOW':[],'ABITRATE2':None, 'ACHANNELS2':None, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'PS3':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':None,'VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'ac3','ACODEC_ALLOW':['ac3'],'ABITRATE':None, 'ACHANNELS':6, 'ACODEC2':'aac','ACODEC2_ALLOW':['libfaac'],'ABITRATE2':None, 'ACHANNELS2':2, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'xbox':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':None,'VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'ac3','ACODEC_ALLOW':['ac3'],'ABITRATE':None, 'ACHANNELS':6, 'ACODEC2':None,'ACODEC2_ALLOW':[],'ABITRATE2':None, 'ACHANNELS2':None, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'Roku-480p':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':None,'VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'aac','ACODEC_ALLOW':['libfaac'],'ABITRATE':128000, 'ACHANNELS':2, 'ACODEC2':'ac3','ACODEC2_ALLOW':['ac3'],'ABITRATE2':None, 'ACHANNELS2':6, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'Roku-720p':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':None,'VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'aac','ACODEC_ALLOW':['libfaac'],'ABITRATE':128000, 'ACHANNELS':2, 'ACODEC2':'ac3','ACODEC2_ALLOW':['ac3'],'ABITRATE2':None, 'ACHANNELS2':6, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'Roku-1080p':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':None,'VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC':'aac','ACODEC_ALLOW':['libfaac'],'ABITRATE':160000, 'ACHANNELS':2, 'ACODEC2':'ac3','ACODEC2_ALLOW':['ac3'],'ABITRATE2':None, 'ACHANNELS2':6, 'ACODEC3':None,'ACODEC3_ALLOW':[],'ABITRATE3':None, 'ACHANNELS3':None, 'SCODEC':'mov_text' }, 'mkv':{ 'VEXTENSION':'.mkv','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':None,'VLEVEL':None, 'VRESOLUTION':None,'VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4', 'mpeg2video'], 'ACODEC':'dts','ACODEC_ALLOW':['libfaac', 'dts', 'ac3', 'mp2', 'mp3'],'ABITRATE':None, 'ACHANNELS':8, 'ACODEC2':None,'ACODEC2_ALLOW':[],'ABITRATE2':None, 'ACHANNELS2':None, 'ACODEC3':'ac3','ACODEC3_ALLOW':['libfaac', 'dts', 'ac3', 'mp2', 'mp3'],'ABITRATE3':None, 'ACHANNELS3':8, 'SCODEC':'mov_text' }, 'mp4-scene-release':{ 'VEXTENSION':'.mp4','VCODEC':'libx264','VPRESET':None,'VFRAMERATE':None,'VBITRATE':None,'VCRF':19,'VLEVEL':'3.1', 'VRESOLUTION':None,'VCODEC_ALLOW':['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4', 'mpeg2video'], 'ACODEC':'dts','ACODEC_ALLOW':['libfaac', 'dts', 'ac3', 'mp2', 'mp3'],'ABITRATE':None, 'ACHANNELS':8, 'ACODEC2':None,'ACODEC2_ALLOW':[],'ABITRATE2':None, 'ACHANNELS2':None, 'ACODEC3':'ac3','ACODEC3_ALLOW':['libfaac', 'dts', 'ac3', 'mp2', 'mp3'],'ABITRATE3':None, 'ACHANNELS3':8, 'SCODEC':'mov_text' } } if DEFAULTS and DEFAULTS in transcode_defaults: VEXTENSION = transcode_defaults[DEFAULTS]['VEXTENSION'] VCODEC = transcode_defaults[DEFAULTS]['VCODEC'] VPRESET = transcode_defaults[DEFAULTS]['VPRESET'] VFRAMERATE = transcode_defaults[DEFAULTS]['VFRAMERATE'] VBITRATE = transcode_defaults[DEFAULTS]['VBITRATE'] VRESOLUTION = transcode_defaults[DEFAULTS]['VRESOLUTION'] VCRF = transcode_defaults[DEFAULTS]['VCRF'] VLEVEL = transcode_defaults[DEFAULTS]['VLEVEL'] VCODEC_ALLOW = transcode_defaults[DEFAULTS]['VCODEC_ALLOW'] ACODEC = transcode_defaults[DEFAULTS]['ACODEC'] ACODEC_ALLOW = transcode_defaults[DEFAULTS]['ACODEC_ALLOW'] ACHANNELS = transcode_defaults[DEFAULTS]['ACHANNELS'] ABITRATE = transcode_defaults[DEFAULTS]['ABITRATE'] ACODEC2 = transcode_defaults[DEFAULTS]['ACODEC2'] ACODEC2_ALLOW = transcode_defaults[DEFAULTS]['ACODEC2_ALLOW'] ACHANNELS2 = transcode_defaults[DEFAULTS]['ACHANNELS2'] ABITRATE2 = transcode_defaults[DEFAULTS]['ABITRATE2'] ACODEC3 = transcode_defaults[DEFAULTS]['ACODEC3'] ACODEC3_ALLOW = transcode_defaults[DEFAULTS]['ACODEC3_ALLOW'] ACHANNELS3 = transcode_defaults[DEFAULTS]['ACHANNELS3'] ABITRATE3 = transcode_defaults[DEFAULTS]['ABITRATE3'] SCODEC = transcode_defaults[DEFAULTS]['SCODEC'] transcode_defaults = {} # clear memory if transcode_defaults in ['mp4-scene-release'] and not OUTPUTQUALITYPERCENT: OUTPUTQUALITYPERCENT = 100 if VEXTENSION in allow_subs: ALLOWSUBS = 1 if not VCODEC_ALLOW and VCODEC: VCODEC_ALLOW.extend([VCODEC]) for codec in VCODEC_ALLOW: if codec in codec_alias: extra = [ item for item in codec_alias[codec] if item not in VCODEC_ALLOW ] VCODEC_ALLOW.extend(extra) if not ACODEC_ALLOW and ACODEC: ACODEC_ALLOW.extend([ACODEC]) for codec in ACODEC_ALLOW: if codec in codec_alias: extra = [ item for item in codec_alias[codec] if item not in ACODEC_ALLOW ] ACODEC_ALLOW.extend(extra) if not ACODEC2_ALLOW and ACODEC2: ACODEC2_ALLOW.extend([ACODEC2]) for codec in ACODEC2_ALLOW: if codec in codec_alias: extra = [ item for item in codec_alias[codec] if item not in ACODEC2_ALLOW ] ACODEC2_ALLOW.extend(extra) if not ACODEC3_ALLOW and ACODEC3: ACODEC3_ALLOW.extend([ACODEC3]) for codec in ACODEC3_ALLOW: if codec in codec_alias: extra = [ item for item in codec_alias[codec] if item not in ACODEC3_ALLOW ] ACODEC3_ALLOW.extend(extra) codec_alias = {} # clear memory PASSWORDSFILE = CFG["passwords"]["PassWordFile"] # Setup FFMPEG, FFPROBE and SEVENZIP locations if platform.system() == 'Windows': FFMPEG = os.path.join(FFMPEG_PATH, 'ffmpeg.exe') FFPROBE = os.path.join(FFMPEG_PATH, 'ffprobe.exe') SEVENZIP = os.path.join(PROGRAM_DIR, 'nzbtomedia', 'extractor', 'bin', platform.machine(), '7z.exe') if not (os.path.isfile(FFMPEG)): # problem FFMPEG = None logger.warning("Failed to locate ffmpeg.exe. Transcoding disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") if not (os.path.isfile(FFPROBE)): FFPROBE = None if CHECK_MEDIA: logger.warning("Failed to locate ffprobe.exe. Video corruption detection disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") else: try: SEVENZIP = subprocess.Popen(['which', '7z'], stdout=subprocess.PIPE).communicate()[0].strip() except: pass if not SEVENZIP: try: SEVENZIP = subprocess.Popen(['which', '7zr'], stdout=subprocess.PIPE).communicate()[0].strip() except: pass if not SEVENZIP: try: SEVENZIP = subprocess.Popen(['which', '7za'], stdout=subprocess.PIPE).communicate()[0].strip() except: pass if not SEVENZIP: SEVENZIP = None logger.warning("Failed to locate 7zip. Transcosing of disk images and extraction of .7z files will not be possible!") if os.path.isfile(os.path.join(FFMPEG_PATH, 'ffmpeg')) or os.access(os.path.join(FFMPEG_PATH, 'ffmpeg'), os.X_OK): FFMPEG = os.path.join(FFMPEG_PATH, 'ffmpeg') elif os.path.isfile(os.path.join(FFMPEG_PATH, 'avconv')) or os.access(os.path.join(FFMPEG_PATH, 'avconv'), os.X_OK): FFMPEG = os.path.join(FFMPEG_PATH, 'avconv') else: try: FFMPEG = subprocess.Popen(['which', 'ffmpeg'], stdout=subprocess.PIPE).communicate()[0].strip() except: pass if not FFMPEG: try: FFMPEG = subprocess.Popen(['which', 'avconv'], stdout=subprocess.PIPE).communicate()[0].strip() except: pass if not FFMPEG: FFMPEG = None logger.warning("Failed to locate ffmpeg. Transcoding disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") if os.path.isfile(os.path.join(FFMPEG_PATH, 'ffprobe')) or os.access(os.path.join(FFMPEG_PATH, 'ffprobe'), os.X_OK): FFPROBE = os.path.join(FFMPEG_PATH, 'ffprobe') elif os.path.isfile(os.path.join(FFMPEG_PATH, 'avprobe')) or os.access(os.path.join(FFMPEG_PATH, 'avprobe'), os.X_OK): FFPROBE = os.path.join(FFMPEG_PATH, 'avprobe') else: try: FFPROBE = subprocess.Popen(['which', 'ffprobe'], stdout=subprocess.PIPE).communicate()[0].strip() except: pass if not FFPROBE: try: FFPROBE = subprocess.Popen(['which', 'avprobe'], stdout=subprocess.PIPE).communicate()[0].strip() except: pass if not FFPROBE: FFPROBE = None if CHECK_MEDIA: logger.warning("Failed to locate ffprobe. Video corruption detection disabled!") logger.warning("Install ffmpeg with x264 support to enable this feature ...") # check for script-defied section and if None set to allow sections SECTIONS = CFG[tuple(x for x in CFG if CFG[x].sections and CFG[x].isenabled()) if not section else (section,)] for section,subsections in SECTIONS.items(): CATEGORIES.extend([subsection for subsection in subsections if CFG[section][subsection].isenabled()]) CATEGORIES = list(set(CATEGORIES)) # create torrent class TORRENT_CLASS = create_torrent_class(TORRENT_CLIENTAGENT) # finished initalizing return True
def autoFork(section, inputCategory): # auto-detect correct section # config settings try: host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] except: host = None port = None try: username = nzbtomedia.CFG[section][inputCategory]["username"] password = nzbtomedia.CFG[section][inputCategory]["password"] except: username = None password = None try: apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] except: apikey = None try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: fork = nzbtomedia.FORKS.items()[nzbtomedia.FORKS.keys().index(nzbtomedia.CFG[section][inputCategory]["fork"])] except: fork = "auto" if ssl: protocol = "https://" else: protocol = "http://" detected = False if section == "NzbDrone": logger.info("Attempting to verify %s fork" % inputCategory) url = "%s%s:%s%s/api/rootfolder" % (protocol,host,port,web_root) headers={"X-Api-Key": apikey} try: r = requests.get(url, headers=headers, stream=True, verify=False) except requests.ConnectionError: logger.warning("Could not connect to %s:%s to verify fork!" % (section, inputCategory)) if not r.ok: logger.warning("Connection to %s:%s failed! Check your configuration" % (section, inputCategory)) fork = ['default', {}] elif fork == "auto": logger.info("Attempting to auto-detect %s fork" % inputCategory) for fork in sorted(nzbtomedia.FORKS.iteritems(), reverse=False): url = "%s%s:%s%s/home/postprocess/processEpisode?%s" % (protocol,host,port,web_root,urllib.urlencode(fork[1])) # attempting to auto-detect fork try: if username and password: r = requests.get(url, auth=(username, password), verify=False) else: r = requests.get(url, verify=False) except requests.ConnectionError: logger.info("Could not connect to %s:%s to perform auto-fork detection!" % (section, inputCategory)) break if r.ok: detected = True break if detected: logger.info("%s:%s fork auto-detection successful ..." % (section, inputCategory)) else: logger.info("%s:%s fork auto-detection failed" % (section, inputCategory)) fork = nzbtomedia.FORKS.items()[nzbtomedia.FORKS.keys().index(nzbtomedia.FORK_DEFAULT)] logger.info("%s:%s fork set to %s" % (section, inputCategory, fork[0])) return fork[0], fork[1]
def process(self, section, dirName, inputName=None, status=0, clientAgent="manual", inputCategory=None): status = int(status) host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] wait_for = int(nzbtomedia.CFG[section][inputCategory]["wait_for"]) try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: remote_path = int(nzbtomedia.CFG[section][inputCategory]["remote_path"]) except: remote_path = 0 if ssl: protocol = "https://" else: protocol = "http://" inputName, dirName = convert_to_ascii(inputName, dirName) url = "%s%s:%s%s/api" % (protocol,host,port,web_root) if status == 0: params = {} params['apikey'] = apikey params['cmd'] = "forceProcess" params['dir'] = os.path.dirname(dirName) if remote_path: params['dir'] = remoteDir(dirName) release_status = self.get_status(url, apikey, dirName) if not release_status: logger.error("Could not find a status for %s, is it in the wanted list ?" % (inputName),section) return 1 logger.debug("Opening URL: %s with PARAMS: %s" % (url, params), section) try: r = requests.get(url, params=params, verify=False) except requests.ConnectionError: logger.error("Unable to open URL %s" % (url) ,section) return 1 # failure logger.debug("Result: %s" % (r.text),section) if not r.status_code in [requests.codes.ok, requests.codes.created, requests.codes.accepted]: logger.error("Server returned status %s" % (str(r.status_code)), section) return 1 elif r.text == "OK": logger.postprocess("SUCCESS: Post-Processing started for %s in folder %s ..." % (inputName, dirName),section) else: logger.error("FAILED: Post-Processing has NOT started for %s in folder %s. exiting!" % (inputName, dirName),section) return 1 # failure else: logger.warning("FAILED DOWNLOAD DETECTED", section) return 0 # Success (as far as this script is concerned) # we will now wait 1 minutes for this album to be processed before returning to TorrentToMedia and unpausing. timeout = time.time() + 60 * wait_for while (time.time() < timeout): # only wait 2 (default) minutes, then return. current_status = self.get_status(url, apikey, dirName) if current_status is not None and current_status != release_status: # Something has changed. CPS must have processed this movie. logger.postprocess("SUCCESS: This release is now marked as status [%s]" % (current_status),section) return 0 time.sleep(10 * wait_for) # The status hasn't changed. we have waited 2 minutes which is more than enough. uTorrent can resule seeding now. logger.warning("The music album does not appear to have changed status after %s minutes. Please check your Logs" % (wait_for),section) return 1 # failure