def processEpisode(self, dirName, nzbName=None, failed=False, clientAgent = "manual", inputCategory=None): # auto-detect correct section section = nzbtomedia.CFG.findsection(inputCategory) if not section: logger.error( "We were unable to find a section for category %s, please check your autoProcessMedia.cfg file." % inputCategory) return 1 # auto-detect correct fork fork, fork_params = autoFork(inputCategory) status = int(failed) host = nzbtomedia.CFG[section][inputCategory]["host"] port = nzbtomedia.CFG[section][inputCategory]["port"] username = nzbtomedia.CFG[section][inputCategory]["username"] password = nzbtomedia.CFG[section][inputCategory]["password"] try: apikey = nzbtomedia.CFG[section][inputCategory]["apikey"] except: apikey = "" try: ssl = int(nzbtomedia.CFG[section][inputCategory]["ssl"]) except: ssl = 0 try: web_root = nzbtomedia.CFG[section][inputCategory]["web_root"] except: web_root = "" try: delete_failed = int(nzbtomedia.CFG[section][inputCategory]["delete_failed"]) except: delete_failed = 0 try: nzbExtractionBy = nzbtomedia.CFG[section][inputCategory]["nzbExtractionBy"] except: nzbExtractionBy = "Downloader" try: process_method = nzbtomedia.CFG[section][inputCategory]["process_method"] except: process_method = None try: Torrent_NoLink = int(nzbtomedia.CFG[section][inputCategory]["Torrent_NoLink"]) except: Torrent_NoLink = 0 try: remote_path = nzbtomedia.CFG[section][inputCategory]["remote_path"] except: remote_path = None if not os.path.isdir(dirName) and os.path.isfile(dirName): # If the input directory is a file, assume single file download and split dir/name. dirName = os.path.split(os.path.normpath(dirName))[0] SpecificPath = os.path.join(dirName, str(nzbName)) cleanName = os.path.splitext(SpecificPath) if cleanName[1] == ".nzb": SpecificPath = cleanName[0] if os.path.isdir(SpecificPath): dirName = SpecificPath if fork not in nzbtomedia.SICKBEARD_TORRENT or (clientAgent in ['nzbget','sabnzbd'] and nzbExtractionBy != "Destination"): if nzbName: process_all_exceptions(nzbName.lower(), dirName) nzbName, dirName = convert_to_ascii(nzbName, dirName) # Now check if tv files exist in destination. Eventually extraction may be done here if nzbExtractionBy == TorrentToMedia video = int(0) for dirpath, dirnames, filenames in os.walk(dirName): for file in filenames: filePath = os.path.join(dirpath, file) fileExtension = os.path.splitext(file)[1] if fileExtension in nzbtomedia.MEDIACONTAINER: # If the file is a video file if is_sample(filePath, nzbName, nzbtomedia.MINSAMPLESIZE, nzbtomedia.SAMPLEIDS): logger.debug("Removing sample file: %s" % (filePath), section) os.unlink(filePath) # remove samples else: video = video + 1 if video > 0: # Check that a video exists. if not, assume failed. flatten(dirName) # to make sure SickBeard can find the video (not in sub-folder) elif clientAgent == "manual": logger.warning("No media files found in directory %s to manually process." % (dirName), section) return 0 # Success (as far as this script is concerned) else: logger.warning("No media files found in directory %s. Processing this as a failed download" % (dirName), section) status = int(1) failed = True # configure SB params to pass fork_params['quiet'] = 1 if nzbName is not None: fork_params['nzbName'] = nzbName for param in copy.copy(fork_params): if param == "failed": fork_params[param] = failed if param in ["dirName", "dir"]: fork_params[param] = dirName if remote_path: dirName_new = os.path.join(remote_path, os.path.basename(dirName)).replace("\\", "/") fork_params[param] = dirName_new if param == "process_method": if fork in nzbtomedia.SICKBEARD_TORRENT and Torrent_NoLink == 1 and not clientAgent in ['nzbget','sabnzbd']: #use default SickBeard settings here. del fork_params[param] if process_method: fork_params[param] = process_method else: del fork_params[param] # delete any unused params so we don't pass them to SB by mistake [fork_params.pop(k) for k,v in fork_params.items() if v is None] if status == 0: logger.postprocess("SUCCESS: The download succeeded, sending a post-process request", section) else: if fork in nzbtomedia.SICKBEARD_FAILED: logger.postprocess("FAILED: The download failed. Sending 'failed' process request to %s branch" % (fork), section) else: logger.postprocess("FAILED: The download failed. %s branch does not handle failed downloads. Nothing to process" % (fork), section) if delete_failed and os.path.isdir(dirName) and not os.path.dirname(dirName) == dirName: logger.postprocess("Deleting failed files and folder %s" % (dirName), section) delete(dirName) return 0 # Success (as far as this script is concerned) if status == 0 and nzbtomedia.TRANSCODE == 1: # only transcode successful downlaods result = Transcoder().Transcode_directory(dirName) if result == 0: logger.debug("SUCCESS: Transcoding succeeded for files in %s" % (dirName), section) else: logger.warning("FAILED: Transcoding failed for files in %s" % (dirName), section) if ssl: protocol = "https://" else: protocol = "http://" url = None if section == "SickBeard": url = "%s%s:%s%s/home/postprocess/processEpisode" % (protocol,host,port,web_root) elif section == "NzbDrone": url = "%s%s:%s%s/api/command" % (protocol, host, port, web_root) logger.debug("Opening URL: %s" % (url),section) try: r = None if section == "SickBeard": r = requests.get(url, auth=(username, password), params=fork_params, stream=True) elif section == "NzbDrone": params = {"name": "DownloadedEpisodesScan", "path": dirName} headers = {"X-Api-Key": apikey} r = requests.get(url, params=params, headers=headers, stream=True) except requests.ConnectionError: logger.error("Unable to open URL: %s" % (url), section) return 1 # failure for line in r.iter_lines(): if line: logger.postprocess("%s" % (line), section) if status != 0 and delete_failed and not os.path.dirname(dirName) == dirName: logger.postprocess("Deleting failed files and folder %s" % (dirName),section) delete(dirName) return 0 # Success
def processTorrent(inputDirectory, inputName, inputCategory, inputHash, inputID, clientAgent): status = int(1) # 1 = failed | 0 = success root = int(0) video = int(0) archive = int(0) foundFile = int(0) extracted_folder = [] copy_list = [] logger.debug("Received Directory: %s | Name: %s | Category: %s" % (inputDirectory, inputName, inputCategory)) inputDirectory, inputName, inputCategory, root, single = 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)) TorrentClass = None if clientAgent != 'manual': TorrentClass = create_torrent_class(clientAgent) pause_torrent(clientAgent, TorrentClass, inputHash, inputID, inputName) processCategories = nzbtomedia.CFG[nzbtomedia.SECTIONS].sections if inputCategory == "": inputCategory = "UNCAT" outputDestination = os.path.normpath(os.path.join(nzbtomedia.OUTPUTDIRECTORY, inputCategory, sanitizeFileName(inputName))) logger.info("Output directory set to: %s" % (outputDestination)) if nzbtomedia.CFG["SickBeard"][inputCategory]: Torrent_NoLink = int(nzbtomedia.CFG["SickBeard"][inputCategory]["Torrent_NoLink"]) # 0 if Torrent_NoLink == 1: logger.info("Calling autoProcessTV to post-process: %s",inputName) result = autoProcessTV().processEpisode(inputDirectory, inputName, 0, clientAgent=clientAgent, inputCategory=inputCategory) if result != 0: logger.error("A problem was reported in the autoProcessTV script.") if clientAgent != 'manual': resume_torrent(clientAgent, TorrentClass, inputHash, inputID, result, inputName) cleanup_directories(inputCategory, processCategories, result, outputDestination) return result processOnly = nzbtomedia.CFG[nzbtomedia.SECTIONS].sections 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 nzbtomedia.CFG["HeadPhones"][inputCategory]: nzbtomedia.NOFLATTEN.extend(nzbtomedia.CFG["HeadPhones"].sections) # Make sure we preserve folder structure for HeadPhones. outputDestinationMaster = outputDestination # Save the original, so we can change this within the loop below, and reset afterwards. now = datetime.datetime.now() if single: inputDirectory,filename = os.path.split(inputDirectory) for dirpath, dirnames, filenames in os.walk(inputDirectory): if single: dirnames[:] = [] filenames[:] = [filenames] # we just want to work with this one file if single = True logger.debug("Found %s files in %s" % (str(len(filenames)), dirpath)) for file in filenames: filePath = os.path.join(dirpath, file) fileName, fileExtension = os.path.splitext(file) if inputCategory in nzbtomedia.NOFLATTEN and not single: newDir = dirpath # find the full path newDir = newDir.replace(inputDirectory, "") #find the extra-depth directory if len(newDir) > 0 and newDir[0] == "/": newDir = newDir[1:] # remove leading "/" to enable join to work. outputDestination = os.path.join(outputDestinationMaster, newDir) # join this extra directory to output. logger.debug("Setting outputDestination to %s to preserve folder structure" % (outputDestination)) targetDirectory = os.path.join(outputDestination, file) if root == 1: if foundFile == int(0): logger.debug("Looking for %s in: %s" % (inputName, file)) if (sanitizeFileName(inputName) in sanitizeFileName(file)) or (sanitizeFileName(fileName) in sanitizeFileName(inputName)): #pass # This file does match the Torrent name foundFile = 1 logger.debug("Found file %s that matches Torrent Name %s" % (file, inputName)) else: continue # This file does not match the Torrent name, skip it if root == 2: if foundFile == int(0): logger.debug("Looking for files with modified/created dates less than 5 minutes old.") mtime_lapse = now - datetime.datetime.fromtimestamp(os.path.getmtime(os.path.join(dirpath, file))) ctime_lapse = now - datetime.datetime.fromtimestamp(os.path.getctime(os.path.join(dirpath, file))) if (mtime_lapse < datetime.timedelta(minutes=5)) or (ctime_lapse < datetime.timedelta(minutes=5)): #pass # This file does match the date time criteria foundFile = 1 logger.debug("Found file %s with date modifed/created less than 5 minutes ago." % (file)) else: continue # This file has not been recently moved or created, skip it if fileExtension in nzbtomedia.MEDIACONTAINER and is_sample(filePath, inputName, nzbtomedia.MINSAMPLESIZE, nzbtomedia.SAMPLEIDS) and not nzbtomedia.CFG["HeadPhones"][inputCategory]: # Ignore samples logger.info("Ignoring sample file: %s " % (filePath)) continue if fileExtension in nzbtomedia.COMPRESSEDCONTAINER: if not (nzbtomedia.CFG["SickBeard"][inputCategory] and nzbtomedia.CFG["SickBeard"][inputCategory]["nzbExtractionBy"] == "Destination"): # find part numbers in second "extension" from right, if we have more than 1 compressed file in the same directory. if re.search(r'\d+', os.path.splitext(fileName)[1]) and os.path.dirname(filePath) in extracted_folder and not any(item in os.path.splitext(fileName)[1] for item in ['.720p','.1080p','.x264']): part = int(re.search(r'\d+', os.path.splitext(fileName)[1]).group()) if part == 1: # we only want to extract the primary part. logger.debug("Found primary part of a multi-part archive %s. Extracting" % (file)) else: logger.debug("Found part %s of a multi-part archive %s. Ignoring" % (part, file)) continue logger.info("Found compressed archive %s for file %s" % (fileExtension, filePath)) try: extractor.extract(filePath, outputDestination) extractionSuccess = True # we use this variable to determine if we need to pause a torrent or not in uTorrent (don't need to pause archived content) extracted_folder.append(os.path.dirname(filePath)) except: logger.error("Extraction failed for: %s" % (file)) continue try: copy_link(filePath, targetDirectory, nzbtomedia.USELINK, outputDestination) copy_list.append([filePath, os.path.join(outputDestination, file)]) except: logger.error("Failed to link file: %s" % (file)) outputDestination = outputDestinationMaster # Reset here. if not inputCategory in nzbtomedia.NOFLATTEN: #don't flatten hp in case multi cd albums, and we need to copy this back later. flatten(outputDestination) if platform.system().lower() == 'windows': # remove Read Only flag from files in Windows. remove_read_only(outputDestination) # Now check if video files exist in destination: if nzbtomedia.CFG["SickBeard","NzbDrone", "CouchPotato"][inputCategory]: for dirpath, dirnames, filenames in os.walk(outputDestination): for file in filenames: filePath = os.path.join(dirpath, file) fileName, fileExtension = os.path.splitext(file) if fileExtension in nzbtomedia.MEDIACONTAINER: # If the file is a video file logger.debug("Found media file: %s" % (filePath)) video += 1 if fileExtension in nzbtomedia.COMPRESSEDCONTAINER: # If the file is an archive file archive += 1 if video > int(0): # Check that media files exist logger.debug("Found %s media files" % (str(video))) status = int(0) elif not (nzbtomedia.CFG["SickBeard"][inputCategory] and nzbtomedia.CFG["SickBeard"][inputCategory]["nzbExtractionBy"] == "Destination") and archive > int(0): logger.debug("Found %s archive files to be extracted by SickBeard" % (str(archive))) status = int(0) else: logger.warning("Found no media files in output.") 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 == int(0) or (nzbtomedia.CFG['HeadPhones','Mylar','Gamez'][inputCategory]): # if movies linked/extracted or for other categories. logger.debug("Calling autoProcess script for successful download.") status = int(0) # hp, my, gz don't support failed. else: logger.error("Something failed! Please check logs. Exiting") return status result = 0 if nzbtomedia.CFG['CouchPotato'][inputCategory]: logger.info("Calling CouchPotato:" + inputCategory + " to post-process: %s" % (inputName)) download_id = inputHash result = autoProcessMovie().process(outputDestination, inputName, status, clientAgent, download_id, inputCategory) elif nzbtomedia.CFG['SickBeard'][inputCategory]: logger.info("Calling Sick-Beard:" + inputCategory + " to post-process: %s" % (inputName)) result = autoProcessTV().processEpisode(outputDestination, inputName, status, clientAgent, inputCategory) elif nzbtomedia.CFG['NzbDrone'][inputCategory]: logger.info("Calling NzbDrone:" + inputCategory + " to post-process: %s" % (inputName)) result = autoProcessTV().processEpisode(outputDestination, inputName, status, clientAgent, inputCategory) elif nzbtomedia.CFG['HeadPhones'][inputCategory]: logger.info("Calling HeadPhones:" + inputCategory + " to post-process: %s" % (inputName)) result = autoProcessMusic().process(outputDestination, inputName, status, clientAgent, inputCategory) elif nzbtomedia.CFG['Mylar'][inputCategory]: logger.info("Calling Mylar:" + inputCategory + " to post-process: %s" % (inputName)) result = autoProcessComics().processEpisode(outputDestination, inputName, status, clientAgent, inputCategory) elif nzbtomedia.CFG['Gamez'][inputCategory]: logger.info("Calling Gamez:" + inputCategory + " to post-process: %s" % (inputName)) result = autoProcessGames().process(outputDestination, inputName, status, clientAgent, inputCategory) if result == 1 and clientAgent != 'manual': logger.error("A problem was reported in the autoProcess* script. If torrent was paused we will resume seeding") if clientAgent != 'manual': resume_torrent(clientAgent, TorrentClass, inputHash, inputID, result, inputName) cleanup_directories(inputCategory, processCategories, result, outputDestination) return result