def extract_subs(file, newfilePath, bitbucket): video_details = getVideoDetails(file) if not video_details: return subStreams = [item for item in video_details["streams"] if item["codec_type"] == "subtitle"] if nzbtomedia.SUBSDIR: subdir = nzbtomedia.SUBSDIR else: subdir = os.path.split(newfilePath)[0] name = os.path.splitext(os.path.split(newfilePath)[1])[0] for n in range(len(subStreams)): sub = subStreams[n] lan = sub["tags"]["language"] outputFile = os.path.join(subdir, "%s(%s).srt" %(name, lan)) if os.path.isfile(outputFile): outputFile = os.path.join(subdir, "%s(%s)%s.srt" %(name, n, lan)) command = [nzbtomedia.FFMPEG, '-loglevel', 'warning', '-i', sub, '-vn', '-an', '-codec:s:' + str(n), 'srt', outputFile] if platform.system() != 'Windows': command = ['nice', '-%d' % nzbtomedia.NICENESS] + command logger.info("Extracting %s Subtitle from: %s" % (lan, file)) cmd = "" for item in command: cmd = cmd + " " + item logger.debug("calling command:%s" % (cmd)) result = 1 # set result to failed in case call fails. try: result = call(command, stdout=bitbucket, stderr=bitbucket) except: logger.error("Extracting subtitles has failed") if result == 0: logger.info("Extracting %s Subtitle from %s has succeeded" % (lan, file)) else: logger.error("Extracting subtitles has failed")
def Transcode_directory(dirName): if platform.system() == 'Windows': bitbucket = open('NUL') else: bitbucket = open('/dev/null') if not nzbtomedia.FFMPEG: return 1 logger.info("Checking for files to be transcoded") final_result = 0 # initialize as successful if nzbtomedia.OUTPUTVIDEOPATH: newDir = nzbtomedia.OUTPUTVIDEOPATH makeDir(newDir) else: newDir = dirName for file in nzbtomedia.listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False): if os.path.splitext(file)[1] in nzbtomedia.IGNOREEXTENSIONS: continue command = buildCommands(file, newDir) newfilePath = command[-1] try: # Try to remove the file that we're transcoding to just in case. (ffmpeg will return an error if it already exists for some reason) os.remove(newfilePath) except OSError, e: if e.errno != errno.ENOENT: # Ignore the error if it's just telling us that the file doesn't exist logger.debug("Error when removing transcoding target: %s" % (e)) except Exception, e: logger.debug("Error when removing transcoding target: %s" % (e))
def backupDatabase(version): logger.info("Backing up database before upgrade") if not backupVersionedFile(nzbToMediaDB.dbFilename(), version): logger.log_error_and_exit( "Database backup failed, abort upgrading database") else: logger.info("Proceeding with upgrade")
def process(nzbDir, inputName=None, status=0, clientAgent='manual', download_id=None, inputCategory=None): result = 0 # auto-detect section section = nzbtomedia.CFG.findsection(inputCategory) if section: logger.info("Sending %s to %s for post-processing ..." % (inputName, str(section).upper())) else: logger.error("We could not find a section with containing a download category labeled %s in your autoProcessMedia.cfg, Exiting!" % inputCategory) if nzbtomedia.CFG["CouchPotato"][inputCategory]: result = autoProcessMovie().process(nzbDir, inputName, status, clientAgent, download_id, inputCategory) elif nzbtomedia.CFG["SickBeard", "NzbDrone"][inputCategory]: result = autoProcessTV().processEpisode(nzbDir, inputName, status, clientAgent, inputCategory) elif nzbtomedia.CFG["HeadPhones"][inputCategory]: result = autoProcessMusic().process(nzbDir, inputName, status, clientAgent, inputCategory) elif nzbtomedia.CFG["Mylar"][inputCategory]: result = autoProcessComics().processEpisode(nzbDir, inputName, status, clientAgent, inputCategory) elif nzbtomedia.CFG["Gamez"][inputCategory]: result = autoProcessGames().process(nzbDir, inputName, status, clientAgent, inputCategory) if result == 0: # Clean up any leftover files cleanup_directories(inputCategory, section, result, nzbDir) return result
def isVideoGood(videofile): fileNameExt = os.path.basename(videofile) fileName, fileExt = os.path.splitext(fileNameExt) if fileExt not in nzbtomedia.MEDIACONTAINER: return True if platform.system() == 'Windows': bitbucket = open('NUL') else: bitbucket = open('/dev/null') if not nzbtomedia.FFPROBE: return True command = [nzbtomedia.FFPROBE, videofile] try: logger.info('Checking [%s] for corruption, please stand by ...' % (fileNameExt), 'TRANSCODER') result = call(command, stdout=bitbucket, stderr=bitbucket) except: logger.error("Checking [%s] for corruption has failed" % (fileNameExt), 'TRANSCODER') return False if result == 0: logger.info("SUCCESS: [%s] has no corruption." % (fileNameExt), 'TRANSCODER') return True else: logger.error("FAILED: [%s] is corrupted!" % (fileNameExt), 'TRANSCODER') return False
def extract_subs(file, newfilePath, bitbucket): video_details, result = getVideoDetails(file) if not video_details: return if nzbtomedia.SUBSDIR: subdir = nzbtomedia.SUBSDIR else: subdir = os.path.split(newfilePath)[0] name = os.path.splitext(os.path.split(newfilePath)[1])[0] try: subStreams = [item for item in video_details["streams"] if item["codec_type"] == "subtitle" and item["tags"]["language"] in nzbtomedia.SLANGUAGES and item["codec_name"] != "hdmv_pgs_subtitle" and item["codec_name"] != "pgssub"] except: subStreams = [item for item in video_details["streams"] if item["codec_type"] == "subtitle" and item["codec_name"] != "hdmv_pgs_subtitle" and item["codec_name"] != "pgssub"] num = len(subStreams) for n in range(num): sub = subStreams[n] idx = sub["index"] try: lan = sub["tags"]["language"] except: lan = "unk" if num == 1: outputFile = os.path.join(subdir, "%s.srt" %(name)) if os.path.isfile(outputFile): outputFile = os.path.join(subdir, "%s.%s.srt" %(name, n)) else: outputFile = os.path.join(subdir, "%s.%s.srt" %(name, lan)) if os.path.isfile(outputFile): outputFile = os.path.join(subdir, "%s.%s.%s.srt" %(name, lan, n)) command = [nzbtomedia.FFMPEG, '-loglevel', 'warning', '-i', file, '-vn', '-an', '-codec:' + str(idx), 'srt', outputFile] if platform.system() != 'Windows': command = nzbtomedia.NICENESS + command logger.info("Extracting %s subtitle from: %s" % (lan, file)) cmd = "" for item in command: cmd = cmd + " " + str(item) logger.debug("Calling command: %s" % (cmd)) result = 1 # set result to failed in case call fails. try: result = call(command, stdout=bitbucket, stderr=bitbucket) except: logger.error("Extracting subtitle has failed") if result == 0: try: shutil.copymode(file, outputFile) except: pass logger.info("Extracting %s subtitle from %s has succeeded" % (lan, file)) else: logger.error("Extracting subtitles has failed")
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 flatten(outputDestination): logger.info("FLATTEN: Flattening directory: %s" % (outputDestination)) for dirpath, dirnames, filenames in os.walk( outputDestination): # Flatten out the directory to make postprocessing easier if dirpath == outputDestination: continue # No need to try and move files in the root destination directory for filename in filenames: source = os.path.join(dirpath, filename) target = os.path.join(outputDestination, filename) try: shutil.move(source, target) except: logger.error("FLATTEN: Could not flatten %s" % (source)) removeEmptyFolders(outputDestination) # Cleanup empty directories
def reportNzb(failure_link, clientAgent): # Contact indexer site logger.info("Sending failure notification to indexer site") if clientAgent == 'nzbget': headers = {'User-Agent' : 'NZBGet / nzbToMedia.py'} elif clientAgent == 'sabnzbd': headers = {'User-Agent' : 'SABnzbd / nzbToMedia.py'} else: return try: r = requests.post(failure_link, headers=headers) except Exception as e: logger.error("Unable to open URL %s due to %s" % (failure_link, e)) return
def isVideoGood(videofile, status): fileNameExt = os.path.basename(videofile) fileName, fileExt = os.path.splitext(fileNameExt) if fileExt not in nzbtomedia.MEDIACONTAINER or not nzbtomedia.FFPROBE: if status: # if the download was "failed", assume bad. If it was successful, assume good. return False else: return True logger.info('Checking [%s] for corruption, please stand by ...' % (fileNameExt), 'TRANSCODER') video_details, result = getVideoDetails(videofile) if result != 0: logger.error("FAILED: [%s] is corrupted!" % (fileNameExt), 'TRANSCODER') return False if video_details.get("error"): logger.info("FAILED: [%s] returned error [%s]." % (fileNameExt, str(video_details.get("error"))), 'TRANSCODER') return False if video_details.get("streams"): videoStreams = [item for item in video_details["streams"] if item["codec_type"] == "video"] audioStreams = [item for item in video_details["streams"] if item["codec_type"] == "audio"] if len(videoStreams) > 0 and len(audioStreams) > 0: logger.info("SUCCESS: [%s] has no corruption." % (fileNameExt), 'TRANSCODER') return True else: logger.info("FAILED: [%s] has %s video streams and %s audio streams. Assume corruption." % (fileNameExt, str(len(videoStreams)), str(len(audioStreams))), 'TRANSCODER') return False
def cleanDir(path, section, subsection): if not os.path.exists(path): logger.info('Directory %s has been processed and removed ...' % (path), 'CLEANDIR') return if nzbtomedia.FORCE_CLEAN: logger.info('Doing Forceful Clean of %s' % (path), 'CLEANDIR') rmDir(path) return try: minSize = int(nzbtomedia.CFG[section][subsection]['minSize']) except:minSize = 0 try: delete_ignored = int(nzbtomedia.CFG[section][subsection]['delete_ignored']) except:delete_ignored = 0 try: num_files = len(listMediaFiles(path, minSize=minSize, delete_ignored=delete_ignored)) except: num_files = 'unknown' if num_files > 0: logger.info( "Directory %s still contains %s unprocessed file(s), skipping ..." % (path, num_files), 'CLEANDIRS') return logger.info("Directory %s has been processed, removing ..." % (path), 'CLEANDIRS') try: shutil.rmtree(path, onerror=onerror) except: logger.error("Unable to delete directory %s" % (path))
def processDir(path): folders = [] logger.info("Searching %s for mediafiles to post-process ..." % (path)) # search for single files and move them into there own folder for post-processing for mediafile in listMediaFiles(path): parentDir = os.path.dirname(mediafile) if parentDir == path: newPath = None fileExt = os.path.splitext(os.path.basename(mediafile))[1] try: if fileExt in nzbtomedia.AUDIOCONTAINER: f = beets.mediafile.MediaFile(mediafile) # get artist and album info artist = f.artist album = f.album # create new path newPath = os.path.join( parentDir, "%s - %s" % (sanitizeName(artist), sanitizeName(album))) elif fileExt in nzbtomedia.MEDIACONTAINER: f = guessit.guess_video_info(mediafile) # get title title = None try: title = f['series'] except: title = f['title'] if not title: title = os.path.basename(mediafile) newPath = os.path.join(parentDir, sanitizeName(title)) except Exception, e: logger.info("Exception from MediaFile for: %s: %s" % (dir, e)) # create new path if it does not exist if not os.path.exists(newPath): makeDir(newPath) # move file to its new path shutil.move(mediafile, newPath)
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 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 flatten(outputDestination): logger.info("FLATTEN: Flattening directory: %s" % (outputDestination)) for outputFile in listMediaFiles(outputDestination): dirPath = os.path.dirname(outputFile) fileName = os.path.basename(outputFile) if dirPath == outputDestination: continue target = os.path.join(outputDestination, fileName) try: shutil.move(outputFile, target) except: logger.error("Could not flatten %s" % (outputFile), 'FLATTEN') removeEmptyFolders(outputDestination) # Cleanup empty directories
def processDir(path): folders = [] logger.info("Searching %s for mediafiles to post-process ..." % (path)) # search for single files and move them into there own folder for post-processing for mediafile in listMediaFiles(path): parentDir = os.path.dirname(mediafile) if parentDir == path: newPath = None fileExt = os.path.splitext(os.path.basename(mediafile))[1] try: if fileExt in nzbtomedia.AUDIOCONTAINER: f = beets.mediafile.MediaFile(mediafile) # get artist and album info artist = f.artist album = f.album # create new path newPath = os.path.join(parentDir, "%s - %s" % (sanitizeName(artist), sanitizeName(album))) elif fileExt in nzbtomedia.MEDIACONTAINER: f = guessit.guess_video_info(mediafile) # get title title = None try: title = f['series'] except: title = f['title'] if not title: title = os.path.basename(mediafile) newPath = os.path.join(parentDir, sanitizeName(title)) except Exception, e: logger.info("Exception from MediaFile for: %s: %s" % (dir, e)) # create new path if it does not exist if not os.path.exists(newPath): makeDir(newPath) # move file to its new path shutil.move(mediafile, newPath)
def removeEmptyFolders(path): logger.info("REMOVER: Removing empty folders in: %s" % (path)) if not os.path.isdir(path): return # Remove empty subfolders files = os.listdir(path) if len(files): for f in files: fullpath = os.path.join(path, f) if os.path.isdir(fullpath): removeEmptyFolders(fullpath) # If folder empty, delete it files = os.listdir(path) if len(files) == 0: logger.debug("REMOVER: Removing empty folder: %s" % (path)) os.rmdir(path)
def Transcode_directory(dirName): if not nzbtomedia.FFMPEG: return 1, dirName logger.info("Checking for files to be transcoded") final_result = 0 # initialize as successful if nzbtomedia.OUTPUTVIDEOPATH: newDir = nzbtomedia.OUTPUTVIDEOPATH makeDir(newDir) else: newDir = dirName if platform.system() == 'Windows': bitbucket = open('NUL') else: bitbucket = open('/dev/null') movieName = os.path.splitext(os.path.split(dirName)[1])[0] List = nzbtomedia.listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False) List, remList, newList, success = processList(List, newDir, bitbucket) if not success: bitbucket.close() return 1, dirName for file in List: if isinstance(file, str) and os.path.splitext( file)[1] in nzbtomedia.IGNOREEXTENSIONS: continue command = buildCommands(file, newDir, movieName, bitbucket) newfilePath = command[-1] # transcoding files may remove the original file, so make sure to extract subtitles first if nzbtomedia.SEXTRACT and isinstance(file, str): extract_subs(file, newfilePath, bitbucket) try: # Try to remove the file that we're transcoding to just in case. (ffmpeg will return an error if it already exists for some reason) os.remove(newfilePath) except OSError, e: if e.errno != errno.ENOENT: # Ignore the error if it's just telling us that the file doesn't exist logger.debug("Error when removing transcoding target: %s" % (e)) except Exception, e: logger.debug("Error when removing transcoding target: %s" % (e))
def convert_to_ascii(nzbName, dirName): ascii_convert = int(nzbtomedia.CFG["ASCII"]["convert"]) if ascii_convert == 0 or os.name == 'nt': # just return if we don't want to convert or on windows os and "\" is replaced!. return nzbName, dirName nzbName2 = str(nzbName.decode('ascii', 'replace').replace(u'\ufffd', '_')) dirName2 = str(dirName.decode('ascii', 'replace').replace(u'\ufffd', '_')) if dirName != dirName2: logger.info("Renaming directory:%s to: %s." % (dirName, dirName2)) shutil.move(dirName, dirName2) for dirpath, dirnames, filesnames in os.walk(dirName2): for filename in filesnames: filename2 = str(filename.decode('ascii', 'replace').replace(u'\ufffd', '_')) if filename != filename2: logger.info("Renaming file:%s to: %s." % (filename, filename2)) shutil.move(filename, filename2) nzbName = nzbName2 dirName = dirName2 return nzbName, dirName
def convert_to_ascii(inputName, dirName): ascii_convert = int(nzbtomedia.CFG["ASCII"]["convert"]) if ascii_convert == 0 or os.name == 'nt': # just return if we don't want to convert or on windows os and "\" is replaced!. return inputName, dirName inputName2 = str(inputName.decode('ascii', 'replace').replace(u'\ufffd', '_')) dirName2 = str(dirName.decode('ascii', 'replace').replace(u'\ufffd', '_')) if dirName != dirName2: logger.info("Renaming directory:%s to: %s." % (dirName, dirName2)) shutil.move(dirName, dirName2) for dirpath, dirnames, filesnames in os.walk(dirName2): for filename in filesnames: filename2 = str(filename.decode('ascii', 'replace').replace(u'\ufffd', '_')) if filename != filename2: logger.info("Renaming file:%s to: %s." % (filename, filename2)) shutil.move(filename, filename2) inputName = inputName2 dirName = dirName2 return inputName, dirName
def cleanup_directories(inputCategory, processCategories, result, directory): if inputCategory in processCategories and result == 0 and os.path.isdir(directory): num_files_new = int(0) file_list = [] for dirpath, dirnames, filenames in os.walk(directory): for file in filenames: filePath = os.path.join(dirpath, file) fileName, fileExtension = os.path.splitext(file) if fileExtension in nzbtomedia.MEDIACONTAINER or fileExtension in nzbtomedia.METACONTAINER: num_files_new += 1 file_list.append(file) if num_files_new is 0 or int(nzbtomedia.CFG["General"]["force_clean"]) == 1: logger.info("All files have been processed. Cleaning directory %s" % (directory)) shutil.rmtree(directory) else: logger.info( "Directory %s still contains %s media and/or meta files. This directory will not be removed." % ( directory, num_files_new)) for item in file_list: logger.debug("media/meta file found: %s" % (item))
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 process(nzbDir, inputName=None, status=0, clientAgent='manual', download_id=None, inputCategory=None): result = 0 # auto-detect section section = nzbtomedia.CFG.findsection(inputCategory) if section: logger.info("Sending %s to %s for post-processing ..." % (inputName, str(section).upper())) else: logger.error( "We could not find a section with containing a download category labeled %s in your autoProcessMedia.cfg, Exiting!" % inputCategory) if nzbtomedia.CFG["CouchPotato"][inputCategory]: result = autoProcessMovie().process(nzbDir, inputName, status, clientAgent, download_id, inputCategory) elif nzbtomedia.CFG["SickBeard", "NzbDrone"][inputCategory]: result = autoProcessTV().processEpisode(nzbDir, inputName, status, clientAgent, inputCategory) elif nzbtomedia.CFG["HeadPhones"][inputCategory]: result = autoProcessMusic().process(nzbDir, inputName, status, clientAgent, inputCategory) elif nzbtomedia.CFG["Mylar"][inputCategory]: result = autoProcessComics().processEpisode(nzbDir, inputName, status, clientAgent, inputCategory) elif nzbtomedia.CFG["Gamez"][inputCategory]: result = autoProcessGames().process(nzbDir, inputName, status, clientAgent, inputCategory) if result == 0: # Clean up any leftover files cleanup_directories(inputCategory, section, result, nzbDir) return result
def cleanDir(path, section, subsection): if not os.path.exists(path): logger.info('Directory %s has been processed and removed ...' % (path), 'CLEANDIR') return try: minSize = int(nzbtomedia.CFG[section][subsection]['minSize']) except: minSize = 0 try: delete_ignored = int( nzbtomedia.CFG[section][subsection]['delete_ignored']) except: delete_ignored = 0 num_files = len( listMediaFiles(path, minSize=minSize, delete_ignored=delete_ignored)) if num_files > 0: logger.info( "Directory %s still contains %s unprocessed file(s), skipping ..." % (path, num_files), 'CLEANDIRS') logger.info("Directory %s has been processed, removing ..." % (path), 'CLEANDIRS') shutil.rmtree(path)
def convert_to_ascii(inputName, dirName): ascii_convert = int(nzbtomedia.CFG["ASCII"]["convert"]) if ascii_convert == 0 or os.name == 'nt': # just return if we don't want to convert or on windows os and "\" is replaced!. return inputName, dirName encoded, inputName = CharReplace(inputName) dir, base = os.path.split(dirName) if not base: # ended with "/" dir, base = os.path.split(dir) encoded, base2 = CharReplace(base) if encoded: dirName = os.path.join(dir, base2) logger.info("Renaming directory to: %s." % (base2), 'ENCODER') os.rename(os.path.join(dir,base), dirName) if os.environ.has_key('NZBOP_SCRIPTDIR'): print "[NZB] DIRECTORY=%s" % (dirName) # Return the new directory to NZBGet. for dirname, dirnames, filenames in os.walk(dirName, topdown=False): for subdirname in dirnames: encoded, subdirname2 = CharReplace(subdirname) if encoded: logger.info("Renaming directory to: %s." % (subdirname2), 'ENCODER') os.rename(os.path.join(dirname, subdirname), os.path.join(dirname, subdirname2)) for dirname, dirnames, filenames in os.walk(dirName): for filename in filenames: encoded, filename2 = CharReplace(filename) if encoded: logger.info("Renaming file to: %s." % (filename2), 'ENCODER') os.rename(os.path.join(dirname, filename), os.path.join(dirname, filename2)) return inputName, dirName
def Transcode_directory(dirName): if not nzbtomedia.FFMPEG: return 1, dirName logger.info("Checking for files to be transcoded") final_result = 0 # initialize as successful if nzbtomedia.OUTPUTVIDEOPATH: newDir = nzbtomedia.OUTPUTVIDEOPATH makeDir(newDir) else: newDir = dirName if platform.system() == 'Windows': bitbucket = open('NUL') else: bitbucket = open('/dev/null') movieName = os.path.splitext(os.path.split(dirName)[1])[0] List = nzbtomedia.listMediaFiles(dirName, media=True, audio=False, meta=False, archives=False) List, remList, newList, success = processList(List, newDir, bitbucket) if not success: bitbucket.close() return 1, dirName for file in List: if isinstance(file, str) and os.path.splitext(file)[1] in nzbtomedia.IGNOREEXTENSIONS: continue command = buildCommands(file, newDir, movieName, bitbucket) newfilePath = command[-1] # transcoding files may remove the original file, so make sure to extract subtitles first if nzbtomedia.SEXTRACT and isinstance(file, str): extract_subs(file, newfilePath, bitbucket) try: # Try to remove the file that we're transcoding to just in case. (ffmpeg will return an error if it already exists for some reason) os.remove(newfilePath) except OSError, e: if e.errno != errno.ENOENT: # Ignore the error if it's just telling us that the file doesn't exist logger.debug("Error when removing transcoding target: %s" % (e)) except Exception, e: logger.debug("Error when removing transcoding target: %s" % (e))
def cleanDir(path, section, subsection): if not os.path.exists(path): logger.info('Directory %s has been processed and removed ...' % (path), 'CLEANDIR') return try: minSize = int(nzbtomedia.CFG[section][subsection]['minSize']) except:minSize = 0 try: delete_ignored = int(nzbtomedia.CFG[section][subsection]['delete_ignored']) except:delete_ignored = 0 num_files = len(listMediaFiles(path, minSize=minSize, delete_ignored=delete_ignored)) if num_files > 0: logger.info( "Directory %s still contains %s unprocessed file(s), skipping ..." % (path, num_files), 'CLEANDIRS') logger.info("Directory %s has been processed, removing ..." % (path), 'CLEANDIRS') shutil.rmtree(path)
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 backupDatabase(version): logger.info("Backing up database before upgrade") if not backupVersionedFile(nzbToMediaDB.dbFilename(), version): logger.log_error_and_exit("Database backup failed, abort upgrading database") else: logger.info("Proceeding with upgrade")
def category_search(inputDirectory, inputName, inputCategory, root, categories): tordir = False try: inputName = inputName.encode(nzbtomedia.SYS_ENCODING) except: pass try: inputDirectory = inputDirectory.encode(nzbtomedia.SYS_ENCODING) except: pass if inputDirectory is None: # =Nothing to process here. return inputDirectory, inputName, inputCategory, root pathlist = os.path.normpath(inputDirectory).split(os.sep) if inputCategory and inputCategory in pathlist: logger.debug("SEARCH: Found the Category: %s in directory structure" % (inputCategory)) elif inputCategory: logger.debug("SEARCH: Could not find the category: %s in the directory structure" % (inputCategory)) else: try: inputCategory = list(set(pathlist) & set(categories))[-1] # assume last match is most relevant category. logger.debug("SEARCH: Found Category: %s in directory structure" % (inputCategory)) except IndexError: inputCategory = "" logger.debug("SEARCH: Could not find a category in the directory structure") if not os.path.isdir(inputDirectory) and os.path.isfile(inputDirectory): # If the input directory is a file if not inputName: inputName = os.path.split(os.path.normpath(inputDirectory))[1] return inputDirectory, inputName, inputCategory, root if inputCategory and os.path.isdir(os.path.join(inputDirectory, inputCategory)): logger.info( "SEARCH: Found category directory %s in input directory directory %s" % (inputCategory, inputDirectory)) inputDirectory = os.path.join(inputDirectory, inputCategory) logger.info("SEARCH: Setting inputDirectory to %s" % (inputDirectory)) if inputName and os.path.isdir(os.path.join(inputDirectory, inputName)): logger.info("SEARCH: Found torrent directory %s in input directory directory %s" % (inputName, inputDirectory)) inputDirectory = os.path.join(inputDirectory, inputName) logger.info("SEARCH: Setting inputDirectory to %s" % (inputDirectory)) tordir = True elif inputName and os.path.isdir(os.path.join(inputDirectory, sanitizeName(inputName))): logger.info("SEARCH: Found torrent directory %s in input directory directory %s" % ( sanitizeName(inputName), inputDirectory)) inputDirectory = os.path.join(inputDirectory, sanitizeName(inputName)) logger.info("SEARCH: Setting inputDirectory to %s" % (inputDirectory)) tordir = True elif inputName and os.path.isfile(os.path.join(inputDirectory, inputName)): logger.info("SEARCH: Found torrent file %s in input directory directory %s" % (inputName, inputDirectory)) inputDirectory = os.path.join(inputDirectory, inputName) logger.info("SEARCH: Setting inputDirectory to %s" % (inputDirectory)) tordir = True elif inputName and os.path.isfile(os.path.join(inputDirectory, sanitizeName(inputName))): logger.info("SEARCH: Found torrent file %s in input directory directory %s" % ( sanitizeName(inputName), inputDirectory)) inputDirectory = os.path.join(inputDirectory, sanitizeName(inputName)) logger.info("SEARCH: Setting inputDirectory to %s" % (inputDirectory)) tordir = True imdbid = [item for item in pathlist if '.cp(tt' in item] # This looks for the .cp(tt imdb id in the path. if imdbid and not '.cp(tt' in inputName: inputName = imdbid[0] # This ensures the imdb id is preserved and passed to CP tordir = True if inputCategory and not tordir: try: index = pathlist.index(inputCategory) if index + 1 < len(pathlist): tordir = True logger.info("SEARCH: Found a unique directory %s in the category directory" % (pathlist[index + 1])) if not inputName: inputName = pathlist[index + 1] except ValueError: pass if inputName and not tordir: if inputName in pathlist or sanitizeName(inputName) in pathlist: logger.info("SEARCH: Found torrent directory %s in the directory structure" % (inputName)) tordir = True else: root = 1 if not tordir: root = 2 if root > 0: logger.info("SEARCH: Could not find a unique directory for this download. Assume a common directory.") logger.info("SEARCH: We will try and determine which files to process, individually") return inputDirectory, inputName, inputCategory, root
def rmDir(dirName): logger.info("Deleting %s" % (dirName)) try: shutil.rmtree(dirName, onerror=onerror) except: logger.error("Unable to delete folder %s" % (dirName))
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') logger.info("Copying SOURCE MEDIAFILE -> TARGET FOLDER", 'COPYLINK') shutil.copy(src, targetLink) return True def flatten(outputDestination): logger.info("FLATTEN: Flattening directory: %s" % (outputDestination)) for outputFile in listMediaFiles(outputDestination): dirPath = os.path.dirname(outputFile) fileName = os.path.basename(outputFile) if dirPath == outputDestination: continue target = os.path.join(outputDestination, fileName)
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 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 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 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 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 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 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
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 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 external_script(outputDestination, torrentName, torrentLabel): final_result = 0 # start at 0. num_files = 0 for dirpath, dirnames, filenames in os.walk(outputDestination): for file in filenames: filePath = nzbtomedia.os.path.join(dirpath, file) fileName, fileExtension = os.path.splitext(file) if fileExtension in nzbtomedia.USER_SCRIPT_MEDIAEXTENSIONS or "ALL" in nzbtomedia.USER_SCRIPT_MEDIAEXTENSIONS: num_files = num_files + 1 if nzbtomedia.USER_SCRIPT_RUNONCE == 1 and num_files > 1: # we have already run once, so just continue to get number of files. continue command = [nzbtomedia.USER_SCRIPT] for param in nzbtomedia.USER_SCRIPT_PARAM: if param == "FN": command.append(file) continue elif param == "FP": command.append(filePath) continue elif param == "TN": command.append(torrentName) continue elif param == "TL": command.append(torrentLabel) continue elif param == "DN": if nzbtomedia.USER_SCRIPT_RUNONCE == 1: command.append(outputDestination) else: command.append(dirpath) continue else: command.append(param) continue cmd = "" for item in command: cmd = cmd + " " + item logger.info("Running script %s on file %s." % (cmd, filePath)) try: p = Popen(command) res = p.wait() if str( res ) in nzbtomedia.USER_SCRIPT_SUCCESSCODES: # Linux returns 0 for successful. logger.info("UserScript %s was successfull" % (command[0])) result = 0 else: logger.error( "UserScript %s has failed with return code: %s" % (command[0], res)) logger.info( "If the UserScript completed successfully you should add %s to the user_script_successCodes" % (res)) result = int(1) except: logger.error("UserScript %s has failed" % (command[0])) result = int(1) final_result = final_result + result num_files_new = 0 for dirpath, dirnames, filenames in os.walk(outputDestination): for file in filenames: filePath = nzbtomedia.os.path.join(dirpath, file) fileName, fileExtension = os.path.splitext(file) if fileExtension in nzbtomedia.USER_SCRIPT_MEDIAEXTENSIONS or nzbtomedia.USER_SCRIPT_MEDIAEXTENSIONS == "ALL": num_files_new = num_files_new + 1 if nzbtomedia.USER_SCRIPT_CLEAN == int( 1) and num_files_new == 0 and final_result == 0: logger.info( "All files have been processed. Cleaning outputDirectory %s" % (outputDestination)) shutil.rmtree(outputDestination) elif nzbtomedia.USER_SCRIPT_CLEAN == int(1) and num_files_new != 0: logger.info( "%s files were processed, but %s still remain. outputDirectory will not be cleaned." % (num_files, num_files_new)) return final_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 category_search(inputDirectory, inputName, inputCategory, root, categories): tordir = False if inputDirectory is None: # =Nothing to process here. return inputDirectory, inputName, inputCategory, root pathlist = os.path.normpath(inputDirectory).split(os.sep) try: inputCategory = list(set(pathlist) & set(categories))[-1] # assume last match is most relevant category. logger.debug("SEARCH: Found Category: %s in directory structure" % (inputCategory)) except IndexError: inputCategory = "" logger.debug("SEARCH: Could not find a category in the directory structure") if not os.path.isdir(inputDirectory) and os.path.isfile(inputDirectory): # If the input directory is a file if not inputName: inputName = os.path.split(os.path.normpath(inputDirectory))[1] return inputDirectory, inputName, inputCategory, root if inputCategory and os.path.isdir(os.path.join(inputDirectory, inputCategory)): logger.info( "SEARCH: Found category directory %s in input directory directory %s" % (inputCategory, inputDirectory)) inputDirectory = os.path.join(inputDirectory, inputCategory) logger.info("SEARCH: Setting inputDirectory to %s" % (inputDirectory)) if inputName and os.path.isdir(os.path.join(inputDirectory, inputName)): logger.info("SEARCH: Found torrent directory %s in input directory directory %s" % (inputName, inputDirectory)) inputDirectory = os.path.join(inputDirectory, inputName) logger.info("SEARCH: Setting inputDirectory to %s" % (inputDirectory)) tordir = True elif inputName and os.path.isdir(os.path.join(inputDirectory, sanitizeName(inputName))): logger.info("SEARCH: Found torrent directory %s in input directory directory %s" % ( sanitizeName(inputName), inputDirectory)) inputDirectory = os.path.join(inputDirectory, sanitizeName(inputName)) logger.info("SEARCH: Setting inputDirectory to %s" % (inputDirectory)) tordir = True elif inputName and os.path.isfile(os.path.join(inputDirectory, inputName)): logger.info("SEARCH: Found torrent file %s in input directory directory %s" % (inputName, inputDirectory)) inputDirectory = os.path.join(inputDirectory, inputName) logger.info("SEARCH: Setting inputDirectory to %s" % (inputDirectory)) tordir = True elif inputName and os.path.isfile(os.path.join(inputDirectory, sanitizeName(inputName))): logger.info("SEARCH: Found torrent file %s in input directory directory %s" % ( sanitizeName(inputName), inputDirectory)) inputDirectory = os.path.join(inputDirectory, sanitizeName(inputName)) logger.info("SEARCH: Setting inputDirectory to %s" % (inputDirectory)) tordir = True imdbid = [item for item in pathlist if '.cp(tt' in item] # This looks for the .cp(tt imdb id in the path. if imdbid and not '.cp(tt' in inputName: inputName = imdbid[0] # This ensures the imdb id is preserved and passed to CP tordir = True if inputCategory and not tordir: try: index = pathlist.index(inputCategory) if index + 1 < len(pathlist): tordir = True logger.info("SEARCH: Found a unique directory %s in the category directory" % (pathlist[index + 1])) if not inputName: inputName = pathlist[index + 1] except ValueError: pass if inputName and not tordir: if inputName in pathlist or sanitizeName(inputName) in pathlist: logger.info("SEARCH: Found torrent directory %s in the directory structure" % (inputName)) tordir = True else: root = 1 if not tordir: root = 2 if root > 0: logger.info("SEARCH: Could not find a unique directory for this download. Assume a common directory.") logger.info("SEARCH: We will try and determine which files to process, individually") return inputDirectory, inputName, inputCategory, root
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 processDir(path): folders = [] logger.info("Searching %s for mediafiles to post-process ..." % (path)) sync = [ o for o in os.listdir(path) if os.path.splitext(o)[1] == '.!sync' ] # search for single files and move them into their own folder for post-processing for mediafile in [ os.path.join(path, o) for o in os.listdir(path) if os.path.isfile(os.path.join(path, o)) ]: if len(sync) > 0: break try: logger.debug("Found file %s in root directory %s." % (os.path.split(mediafile)[1], path)) newPath = None fileExt = os.path.splitext(mediafile)[1] try: if fileExt in nzbtomedia.AUDIOCONTAINER: f = beets.mediafile.MediaFile(mediafile) # get artist and album info artist = f.artist album = f.album # create new path newPath = os.path.join(path, "%s - %s" % (sanitizeName(artist), sanitizeName(album))) elif fileExt in nzbtomedia.MEDIACONTAINER: f = guessit.guess_video_info(mediafile) # get title title = None try: title = f['series'] except: title = f['title'] if not title: title = os.path.splitext(os.path.basename(mediafile))[0] newPath = os.path.join(path, sanitizeName(title)) except Exception as e: logger.error("Exception parsing name for media file: %s: %s" % (os.path.split(mediafile)[1], e)) if not newPath: title = os.path.splitext(os.path.basename(mediafile))[0] newPath = os.path.join(path, sanitizeName(title)) try: newPath = newPath.encode(nzbtomedia.SYS_ENCODING) except: pass # Just fail-safe incase we already have afile with this clean-name (was actually a bug from earlier code, but let's be safe). if os.path.isfile(newPath): newPath2 = os.path.join(os.path.join(os.path.split(newPath)[0], 'new'), os.path.split(newPath)[1]) newPath = newPath2 # create new path if it does not exist if not os.path.exists(newPath): makeDir(newPath) newfile = os.path.join(newPath, sanitizeName(os.path.split(mediafile)[1])) try: newfile = newfile.encode(nzbtomedia.SYS_ENCODING) except: pass # link file to its new path copy_link(mediafile, newfile, link) except Exception as e: logger.error("Failed to move %s to its own directory: %s" % (os.path.split(mediafile)[1], e)) #removeEmptyFolders(path, removeRoot=False) if os.listdir(path): for dir in [os.path.join(path, o) for o in os.listdir(path) if os.path.isdir(os.path.join(path, o))]: sync = [ o for o in os.listdir(dir) if os.path.splitext(o)[1] == '.!sync' ] if len(sync) > 0 or len(os.listdir(dir)) == 0: continue folders.extend([dir]) return folders