def test_replaceExtension(self): self.assertEqual(helpers.replaceExtension('foo.avi', 'mkv'), 'foo.mkv') self.assertEqual(helpers.replaceExtension('.vimrc', 'arglebargle'), '.vimrc') self.assertEqual(helpers.replaceExtension('a.b.c', 'd'), 'a.b.d') self.assertEqual(helpers.replaceExtension('', 'a'), '') self.assertEqual(helpers.replaceExtension('foo.bar', ''), 'foo.')
def hasProcessedHelperFile(file): # check if file has already been processed - an empty helper file will exist helper_file = helpers.replaceExtension(file, "processed") if ek.ek(os.path.isfile, helper_file): return True return False
def _combined_file_operation(self, file_path, new_path, new_base_name, associated_files=False, action=None): """ Performs a generic operation (move or copy) on a file. Can rename the file as well as change its location, and optionally move associated files too. file_path: The full path of the media file to act on new_path: Destination path where we want to move/copy the file to new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. associated_files: Boolean, whether we should copy similarly-named files too action: function that takes an old path and new path and does an operation with them (move/copy) """ if not action: self._log( u"Must provide an action for the combined file operation", logger.ERROR) return file_list = [file_path] if associated_files: file_list = file_list + helpers.list_associated_files( file_path, filter_ext=sickbeard.FILTER_ASSOCIATED_FILES) if not file_list: self._log( u"There were no files associated with " + file_path + ", not moving anything", logger.DEBUG) return # create base name with file_path (media_file without .extension) old_base_name = file_path.rpartition('.')[0] old_base_name_length = len(old_base_name) # deal with all files for cur_file_path in file_list: cur_file_name = ek.ek(os.path.basename, cur_file_path) # get the extension without . cur_extension = cur_file_path[old_base_name_length + 1:] # replace .nfo with .nfo-orig to avoid conflicts if cur_extension == 'nfo': cur_extension = 'nfo-orig' # If new base name then convert name if new_base_name: new_file_name = new_base_name + '.' + cur_extension # if we're not renaming we still want to change extensions sometimes else: new_file_name = helpers.replaceExtension( cur_file_name, cur_extension) new_file_path = ek.ek(os.path.join, new_path, new_file_name) action(cur_file_path, new_file_path)
def checkForMetaFiles(self): oldhasnfo = self.hasnfo oldhastbn = self.hastbn # check for nfo and tbn if os.path.isfile(self.location): if os.path.isfile(os.path.join(self.show.location, helpers.replaceExtension(self.location, 'nfo'))): self.hasnfo = True else: self.hasnfo = False if os.path.isfile(os.path.join(self.show.location, helpers.replaceExtension(self.location, 'tbn'))): self.hastbn = True else: self.hastbn = False # if either setting has changed return true, if not return false return oldhasnfo != self.hasnfo or oldhastbn != self.hastbn
def _combined_file_operation(self, file_path, new_path, new_base_name, associated_files=False, action=None): """ file_path: The full path of the media file to copy new_path: Destination path where we want to copy the file to new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. associated_files: Boolean, whether we should copy similarly-named files too action: function that takes an old path and new path and does an operation with them (move/copy) """ if not action: self._log( u"Must provide an action for the combined file operation", logger.ERROR) return if associated_files: file_list = self._list_associated_files(file_path) else: file_list = [file_path] if not file_list: self._log( u"There were no files associated with " + file_path + ", not moving anything", logger.DEBUG) return for cur_file_path in file_list: cur_file_name = ek.ek(os.path.basename, cur_file_path) # get the extension cur_extension = cur_file_path.rpartition('.')[-1] # replace .nfo with .nfo-orig to avoid conflicts if cur_extension == 'nfo': cur_extension = 'nfo-orig' # If new base name then convert name if new_base_name: new_file_name = new_base_name + ' (' + self.release_group + ')' + '.' + cur_extension # if we're not renaming we still want to change extensions sometimes else: new_file_name = helpers.replaceExtension( cur_file_name, cur_extension) new_file_path = ek.ek(os.path.join, new_path, new_file_name) action(cur_file_path, new_file_path)
def _combined_file_operation(self, file_path, new_path, new_base_name, associated_files=False, action=None): """ Performs a generic operation (move or copy) on a file. Can rename the file as well as change its location, and optionally move associated files too. file_path: The full path of the media file to act on new_path: Destination path where we want to move/copy the file to new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. associated_files: Boolean, whether we should copy similarly-named files too action: function that takes an old path and new path and does an operation with them (move/copy) """ if not action: self._log(u"Must provide an action for the combined file operation", logger.ERROR) return file_list = [file_path] if associated_files: file_list = file_list + helpers.list_associated_files(file_path, filter_ext=sickbeard.FILTER_ASSOCIATED_FILES) if not file_list: self._log(u"There were no files associated with " + file_path + ", not moving anything", logger.DEBUG) return # create base name with file_path (media_file without .extension) old_base_name = file_path.rpartition('.')[0] old_base_name_length = len(old_base_name) # deal with all files for cur_file_path in file_list: cur_file_name = ek.ek(os.path.basename, cur_file_path) # get the extension without . cur_extension = cur_file_path[old_base_name_length + 1:] cur_file_name = ek.ek(os.path.basename, cur_file_path) # get the extension cur_extension = cur_file_path.rpartition('.')[-1] # replace .nfo with .nfo-orig to avoid conflicts if cur_extension == 'nfo': cur_extension = 'nfo-orig' # If new base name then convert name if new_base_name: new_file_name = new_base_name + '.' + cur_extension # if we're not renaming we still want to change extensions sometimes else: new_file_name = helpers.replaceExtension(cur_file_name, cur_extension) new_file_path = ek.ek(os.path.join, new_path, new_file_name) action(cur_file_path, new_file_path)
def get_episode_thumb_path(self, ep_obj): """ Returns the path where the episode thumbnail should be stored. Defaults to the same path as the episode file but with a .tbn extension. ep_obj: a TVEpisode instance for which to create the thumbnail """ if ek.ek(os.path.isfile, ep_obj.location): tbn_filename = helpers.replaceExtension(ep_obj.location, 'tbn') else: return None return tbn_filename
def _combined_file_operation( self, file_path, new_path, new_base_name, associated_files=False, action=None, subtitles=False ): """ Performs a generic operation (move or copy) on a file. Can rename the file as well as change its location, and optionally move associated files too. file_path: The full path of the media file to act on new_path: Destination path where we want to move/copy the file to new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. associated_files: Boolean, whether we should copy similarly-named files too action: function that takes an old path and new path and does an operation with them (move/copy) """ if not action: self._log(u"Must provide an action for the combined file operation", logger.ERROR) return if associated_files: file_list = self._list_associated_files(file_path) else: if subtitles: file_list = self._list_associated_files(file_path, True) file_list.append(file_path) else: file_list = [file_path] if not file_list: self._log(u"There were no files associated with " + file_path + ", not moving anything", logger.DEBUG) return for cur_file_path in file_list: cur_file_name = ek.ek(os.path.basename, cur_file_path) # get the extension cur_extension = cur_file_path[len(file_path.rpartition(".")[0] + ".") :] # If new base name then convert name if new_base_name: new_file_name = new_base_name + "." + cur_extension # if we're not renaming we still want to change extensions sometimes else: if cur_extension == "nfo": new_file_name = helpers.replaceExtension(cur_file_name, "nfo-orig") else: new_file_name = cur_file_name new_file_path = ek.ek(os.path.join, new_path, new_file_name) action(cur_file_path, new_file_path)
def get_episode_file_path(self, ep_obj): """ Returns a full show dir/metadata/episode.xml path for MediaBrowser episode metadata files ep_obj: a TVEpisode object to get the path for """ if ek.ek(os.path.isfile, ep_obj.location): xml_file_name = helpers.replaceExtension(ek.ek(os.path.basename, ep_obj.location), self._ep_nfo_extension) metadata_dir_name = ek.ek(os.path.join, ep_obj.show.location, 'metadata') xml_file_path = ek.ek(os.path.join, metadata_dir_name, xml_file_name) else: return None return xml_file_path
def get_episode_thumb_path(self, ep_obj): """ Returns a full show dir/metadata/episode.jpg path for MediaBrowser episode thumbs. ep_obj: a TVEpisode object to get the path from """ if ek.ek(os.path.isfile, ep_obj.location): tbn_file_name = helpers.replaceExtension(ek.ek(os.path.basename, ep_obj.location), 'jpg') metadata_dir_name = ek.ek(os.path.join, ek.ek(os.path.dirname, ep_obj.location), 'metadata') tbn_file_path = ek.ek(os.path.join, metadata_dir_name, tbn_file_name) else: return None return tbn_file_path
def get_episode_file_path(self, ep_obj): """ Returns a full show dir/metadata/episode.xml path for MediaBrowser episode metadata files ep_obj: a TVEpisode object to get the path for """ if ek.ek(os.path.isfile, ep_obj.location): xml_file_name = helpers.replaceExtension(ek.ek(os.path.basename, ep_obj.location), self._ep_nfo_extension) metadata_dir_name = ek.ek(os.path.join, ek.ek(os.path.dirname, ep_obj.location), 'metadata') xml_file_path = ek.ek(os.path.join, metadata_dir_name, xml_file_name) else: logger.log(u"Episode location doesn't exist: " + str(ep_obj.location), logger.DEBUG) return '' return xml_file_path
def get_episode_file_path(self, ep_obj): """ Returns a full show dir/metadata/episode.xml path for MediaBrowser episode metadata files ep_obj: a TVEpisode object to get the path for """ if ek.ek(os.path.isfile, ep_obj.location): xml_file_name = helpers.replaceExtension(ek.ek(os.path.basename, ep_obj.location), self._ep_nfo_extension) metadata_dir_name = ek.ek(os.path.join, ek.ek(os.path.dirname, ep_obj.location), 'metadata') xml_file_path = ek.ek(os.path.join, metadata_dir_name, xml_file_name) else: logger.log(u"Episode location doesn't exist: "+str(ep_obj.location), logger.DEBUG) return '' return xml_file_path
def _combined_file_operation (self, file_path, new_path, new_base_name, associated_files=False, action=None): """ file_path: The full path of the media file to copy new_path: Destination path where we want to copy the file to new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. associated_files: Boolean, whether we should copy similarly-named files too action: function that takes an old path and new path and does an operation with them (move/copy) """ if not action: self._log(u"Must provide an action for the combined file operation", logger.ERROR) return if associated_files: file_list = self._list_associated_files(file_path) else: file_list = [file_path] if not file_list: self._log(u"There were no files associated with "+file_path+", not moving anything", logger.DEBUG) return for cur_file_path in file_list: cur_file_name = ek.ek(os.path.basename, cur_file_path) # get the extension cur_extension = cur_file_path.rpartition('.')[-1] # replace .nfo with .nfo-orig to avoid conflicts if cur_extension == 'nfo': cur_extension = 'nfo-orig' # If new base name then convert name if new_base_name: new_file_name = new_base_name +'.' + cur_extension # if we're not renaming we still want to change extensions sometimes else: new_file_name = helpers.replaceExtension(cur_file_name, cur_extension) new_file_path = ek.ek(os.path.join, new_path, new_file_name) action(cur_file_path, new_file_path)
def processDir (dirName, nzbName=None, recurse=False): """ Scans through the files in dirName and processes whatever media files it finds dirName: The folder name to look in nzbName: The NZB name which resulted in this folder being downloaded recurse: Boolean for whether we should descend into subfolders or not """ returnStr = '' returnStr += logHelper(u"Processing folder "+dirName, logger.DEBUG) # if they passed us a real dir then assume it's the one we want if ek.ek(os.path.isdir, dirName): dirName = ek.ek(os.path.realpath, dirName) # if they've got a download dir configured then use it elif sickbeard.TV_DOWNLOAD_DIR and ek.ek(os.path.isdir, sickbeard.TV_DOWNLOAD_DIR) \ and ek.ek(os.path.normpath, dirName) != ek.ek(os.path.normpath, sickbeard.TV_DOWNLOAD_DIR): dirName = ek.ek(os.path.join, sickbeard.TV_DOWNLOAD_DIR, ek.ek(os.path.abspath, dirName).split(os.path.sep)[-1]) returnStr += logHelper(u"Trying to use folder "+dirName, logger.DEBUG) # if we didn't find a real dir then quit if not ek.ek(os.path.isdir, dirName): returnStr += logHelper(u"Unable to figure out what folder to process. If your downloader and Sick Beard aren't on the same PC make sure you fill out your TV download dir in the config.", logger.DEBUG) return returnStr # TODO: check if it's failed and deal with it if it is if ek.ek(os.path.basename, dirName).startswith('_FAILED_'): returnStr += logHelper(u"The directory name indicates it failed to extract, cancelling", logger.DEBUG) return returnStr elif ek.ek(os.path.basename, dirName).startswith('_UNDERSIZED_'): returnStr += logHelper(u"The directory name indicates that it was previously rejected for being undersized, cancelling", logger.DEBUG) return returnStr elif ek.ek(os.path.basename, dirName).startswith('_UNPACK_'): returnStr += logHelper(u"The directory name indicates that this release is in the process of being unpacked, skipping", logger.DEBUG) return returnStr # make sure the dir isn't inside a show dir myDB = db.DBConnection() sqlResults = myDB.select("SELECT * FROM tv_shows") for sqlShow in sqlResults: if dirName.lower().startswith(ek.ek(os.path.realpath, sqlShow["location"]).lower()+os.sep) or dirName.lower() == ek.ek(os.path.realpath, sqlShow["location"]).lower(): returnStr += logHelper(u"You're trying to post process an episode that's already been moved to its show dir", logger.ERROR) return returnStr fileList = ek.ek(os.listdir, dirName) # split the list into video files and folders folders = filter(lambda x: ek.ek(os.path.isdir, ek.ek(os.path.join, dirName, x)), fileList) videoFiles = filter(helpers.isMediaFile, fileList) _checkOrphanedProcessedFiles(dirName, fileList) # recursively process all the folders for curFolder in folders: returnStr += logHelper(u"Recursively processing a folder: "+curFolder, logger.DEBUG) returnStr += processDir(ek.ek(os.path.join, dirName, curFolder), recurse=True) remainingFolders = filter(lambda x: ek.ek(os.path.isdir, ek.ek(os.path.join, dirName, x)), fileList) # If nzbName is set and there's more than one videofile in the folder, files will be lost (overwritten). if nzbName != None and len(videoFiles) >= 2: nzbName = None # process any files in the dir for cur_video_file_path in videoFiles: cur_video_file_path = ek.ek(os.path.join, dirName, cur_video_file_path) # prevent infinite auto process loop when KEEP_PROCESSED_DIR = true, by marking videos as processed if sickbeard.KEEP_PROCESSED_DIR: # check if file has already been processed - a .processed file will exist helper_file = helpers.replaceExtension(cur_video_file_path, "processed") if ek.ek(os.path.isfile, helper_file): logHelper(u"Processing skipped for " + cur_video_file_path + ": .processed file detected.") continue try: processor = postProcessor.PostProcessor(cur_video_file_path, nzbName) process_result = processor.process() process_fail_message = "" except exceptions.PostProcessingFailed, e: process_result = False process_fail_message = ex(e) returnStr += processor.log # as long as the postprocessing was successful delete the old folder unless the config wants us not to if process_result: if len(videoFiles) == 1 and not sickbeard.KEEP_PROCESSED_DIR and \ ek.ek(os.path.normpath, dirName) != ek.ek(os.path.normpath, sickbeard.TV_DOWNLOAD_DIR) and \ len(remainingFolders) == 0: returnStr += logHelper(u"Deleting folder " + dirName, logger.DEBUG) try: shutil.rmtree(dirName) except (OSError, IOError), e: returnStr += logHelper(u"Warning: unable to remove the folder " + dirName + ": " + ex(e), logger.WARNING) returnStr += logHelper(u"Processing succeeded for "+cur_video_file_path)
def get_episode_file_path(self, ep_obj): return helpers.replaceExtension(ep_obj.location, self._ep_nfo_extension)
def processDir(dirName, nzbName=None, recurse=False): """ Scans through the files in dirName and processes whatever media files it finds dirName: The folder name to look in nzbName: The NZB name which resulted in this folder being downloaded recurse: Boolean for whether we should descend into subfolders or not """ returnStr = '' returnStr += logHelper(u"Processing folder " + dirName, logger.DEBUG) # if they passed us a real dir then assume it's the one we want if ek.ek(os.path.isdir, dirName): dirName = ek.ek(os.path.realpath, dirName) # if they've got a download dir configured then use it elif sickbeard.TV_DOWNLOAD_DIR and ek.ek(os.path.isdir, sickbeard.TV_DOWNLOAD_DIR) \ and ek.ek(os.path.normpath, dirName) != ek.ek(os.path.normpath, sickbeard.TV_DOWNLOAD_DIR): dirName = ek.ek(os.path.join, sickbeard.TV_DOWNLOAD_DIR, ek.ek(os.path.abspath, dirName).split(os.path.sep)[-1]) returnStr += logHelper(u"Trying to use folder " + dirName, logger.DEBUG) # if we didn't find a real dir then quit if not ek.ek(os.path.isdir, dirName): returnStr += logHelper( u"Unable to figure out what folder to process. If your downloader and Sick Beard aren't on the same PC make sure you fill out your TV download dir in the config.", logger.DEBUG) return returnStr # TODO: check if it's failed and deal with it if it is if ek.ek(os.path.basename, dirName).startswith('_FAILED_'): returnStr += logHelper( u"The directory name indicates it failed to extract, cancelling", logger.DEBUG) return returnStr elif ek.ek(os.path.basename, dirName).startswith('_UNDERSIZED_'): returnStr += logHelper( u"The directory name indicates that it was previously rejected for being undersized, cancelling", logger.DEBUG) return returnStr elif ek.ek(os.path.basename, dirName).startswith('_UNPACK_'): returnStr += logHelper( u"The directory name indicates that this release is in the process of being unpacked, skipping", logger.DEBUG) return returnStr # make sure the dir isn't inside a show dir myDB = db.DBConnection() sqlResults = myDB.select("SELECT * FROM tv_shows") for sqlShow in sqlResults: if dirName.lower().startswith( ek.ek(os.path.realpath, sqlShow["location"]).lower() + os.sep) or dirName.lower() == ek.ek( os.path.realpath, sqlShow["location"]).lower(): returnStr += logHelper( u"You're trying to post process an episode that's already been moved to its show dir", logger.ERROR) return returnStr fileList = ek.ek(os.listdir, dirName) # split the list into video files and folders folders = filter( lambda x: ek.ek(os.path.isdir, ek.ek(os.path.join, dirName, x)), fileList) videoFiles = filter(helpers.isMediaFile, fileList) _checkOrphanedProcessedFiles(dirName, fileList) # recursively process all the folders for curFolder in folders: returnStr += logHelper( u"Recursively processing a folder: " + curFolder, logger.DEBUG) returnStr += processDir(ek.ek(os.path.join, dirName, curFolder), recurse=True) remainingFolders = filter( lambda x: ek.ek(os.path.isdir, ek.ek(os.path.join, dirName, x)), fileList) # If nzbName is set and there's more than one videofile in the folder, files will be lost (overwritten). if nzbName != None and len(videoFiles) >= 2: nzbName = None # process any files in the dir for cur_video_file_path in videoFiles: cur_video_file_path = ek.ek(os.path.join, dirName, cur_video_file_path) # prevent infinite auto process loop when KEEP_PROCESSED_DIR = true, by marking videos as processed if sickbeard.KEEP_PROCESSED_DIR: # check if file has already been processed - a .processed file will exist helper_file = helpers.replaceExtension(cur_video_file_path, "processed") if ek.ek(os.path.isfile, helper_file): logHelper(u"Processing skipped for " + cur_video_file_path + ": .processed file detected.") continue try: processor = postProcessor.PostProcessor(cur_video_file_path, nzbName) process_result = processor.process() process_fail_message = "" except exceptions.PostProcessingFailed, e: process_result = False process_fail_message = ex(e) returnStr += processor.log # as long as the postprocessing was successful delete the old folder unless the config wants us not to if process_result: if len(videoFiles) == 1 and not sickbeard.KEEP_PROCESSED_DIR and \ ek.ek(os.path.normpath, dirName) != ek.ek(os.path.normpath, sickbeard.TV_DOWNLOAD_DIR) and \ len(remainingFolders) == 0: returnStr += logHelper(u"Deleting folder " + dirName, logger.DEBUG) try: shutil.rmtree(dirName) except (OSError, IOError), e: returnStr += logHelper( u"Warning: unable to remove the folder " + dirName + ": " + ex(e), logger.WARNING) returnStr += logHelper(u"Processing succeeded for " + cur_video_file_path)
def _combined_file_operation(self, file_path, new_path, new_base_name, associated_files=False, action=None, subtitles=False): """ Performs a generic operation (move or copy) on a file. Can rename the file as well as change its location, and optionally move associated files too. file_path: The full path of the media file to act on new_path: Destination path where we want to move/copy the file to new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. associated_files: Boolean, whether we should copy similarly-named files too action: function that takes an old path and new path and does an operation with them (move/copy) """ if not action: self._log( u"Must provide an action for the combined file operation", logger.ERROR) return file_list = [file_path] self._list_dummy_files(file_path) if associated_files: file_list = file_list + self._list_associated_files(file_path) elif subtitles: file_list = file_list + self._list_associated_files( file_path, True) if not file_list: self._log( u"There were no files associated with " + file_path + ", not moving anything", logger.DEBUG) return # deal with all files for cur_file_path in file_list: cur_file_name = ek.ek(os.path.basename, cur_file_path) # get the extension cur_extension = cur_file_path.rpartition('.')[-1] # check if file have language of subtitles if cur_extension in common.subtitleExtensions: cur_lang = cur_file_path.rpartition('.')[0].rpartition('.')[-1] if cur_lang in sickbeard.SUBTITLES_LANGUAGES: cur_extension = cur_lang + '.' + cur_extension # replace .nfo with .nfo-orig to avoid conflicts if cur_extension == 'nfo': cur_extension = 'nfo-orig' # If new base name then convert name if new_base_name: new_file_name = new_base_name + '.' + cur_extension # if we're not renaming we still want to change extensions sometimes else: new_file_name = helpers.replaceExtension( cur_file_name, cur_extension) if sickbeard.SUBTITLES_DIR and cur_extension in common.subtitleExtensions: subs_new_path = ek.ek(os.path.join, new_path, sickbeard.SUBTITLES_DIR) dir_exists = helpers.makeDir(subs_new_path) if not dir_exists: logger.log( u"Unable to create subtitles folder " + subs_new_path, logger.ERROR) else: helpers.chmodAsParent(subs_new_path) new_file_path = ek.ek(os.path.join, subs_new_path, new_file_name) else: if sickbeard.SUBTITLES_DIR_SUB and cur_extension in common.subtitleExtensions: subs_new_path = os.path.join(os.path.dirname(file.path), "Subs") dir_exists = helpers.makeDir(subs_new_path) if not dir_exists: logger.log( u"Unable to create subtitles folder " + subs_new_path, logger.ERROR) else: helpers.chmodAsParent(subs_new_path) new_file_path = ek.ek(os.path.join, subs_new_path, new_file_name) else: new_file_path = ek.ek(os.path.join, new_path, new_file_name) action(cur_file_path, new_file_path)
def _combined_file_operation (self, file_path, new_path, new_base_name, associated_files=False, action=None, subtitles=False): """ Performs a generic operation (move or copy) on a file. Can rename the file as well as change its location, and optionally move associated files too. file_path: The full path of the media file to act on new_path: Destination path where we want to move/copy the file to new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. associated_files: Boolean, whether we should copy similarly-named files too action: function that takes an old path and new path and does an operation with them (move/copy) """ if not action: self._log(u"Must provide an action for the combined file operation", logger.ERROR) return file_list = [file_path] self._list_dummy_files(file_path) if associated_files: file_list = file_list + self._list_associated_files(file_path) elif subtitles: file_list = file_list + self._list_associated_files(file_path, True) if not file_list: self._log(u"There were no files associated with " + file_path + ", not moving anything", logger.DEBUG) return # deal with all files for cur_file_path in file_list: cur_file_name = ek.ek(os.path.basename, cur_file_path) # get the extension cur_extension = cur_file_path.rpartition('.')[-1] # check if file have language of subtitles if cur_extension in common.subtitleExtensions: cur_lang = cur_file_path.rpartition('.')[0].rpartition('.')[-1] if cur_lang in sickbeard.SUBTITLES_LANGUAGES: cur_extension = cur_lang + '.' + cur_extension # replace .nfo with .nfo-orig to avoid conflicts if cur_extension == 'nfo': cur_extension = 'nfo-orig' # If new base name then convert name if new_base_name: new_file_name = new_base_name +'.' + cur_extension # if we're not renaming we still want to change extensions sometimes else: new_file_name = helpers.replaceExtension(cur_file_name, cur_extension) if sickbeard.SUBTITLES_DIR and cur_extension in common.subtitleExtensions: subs_new_path = ek.ek(os.path.join, new_path, sickbeard.SUBTITLES_DIR) dir_exists = helpers.makeDir(subs_new_path) if not dir_exists: logger.log(u"Unable to create subtitles folder "+subs_new_path, logger.ERROR) else: helpers.chmodAsParent(subs_new_path) new_file_path = ek.ek(os.path.join, subs_new_path, new_file_name) else: if sickbeard.SUBTITLES_DIR_SUB and cur_extension in common.subtitleExtensions: subs_new_path = os.path.join(os.path.dirname(file.path),"Subs") dir_exists = helpers.makeDir(subs_new_path) if not dir_exists: logger.log(u"Unable to create subtitles folder "+subs_new_path, logger.ERROR) else: helpers.chmodAsParent(subs_new_path) new_file_path = ek.ek(os.path.join, subs_new_path, new_file_name) else : new_file_path = ek.ek(os.path.join, new_path, new_file_name) action(cur_file_path, new_file_path)
cur_actor_name = etree.SubElement( cur_actor, "name" ) cur_actor_name.text = actor['name'] cur_actor_role = etree.SubElement( cur_actor, "role" ) cur_actor_role_text = actor['role'] if cur_actor_role_text != None: cur_actor_role.text = cur_actor_role_text cur_actor_thumb = etree.SubElement( cur_actor, "thumb" ) cur_actor_thumb_text = actor['image'] if cur_actor_thumb_text != None: cur_actor_thumb.text = cur_actor_thumb_text if os.path.isfile(self.location): nfoFilename = helpers.replaceExtension(self.location, 'nfo') else: nfoFilename = helpers.sanitizeFileName(self.prettyName() + '.nfo') logger.log('Writing nfo to ' + os.path.join(self.show.location, nfoFilename)) # # Make it purdy helpers.indentXML( rootNode ) nfo = etree.ElementTree( rootNode ) nfo_fh = open(os.path.join(self.show.location, nfoFilename), 'w') nfo.write( nfo_fh, encoding="utf-8" ) nfo_fh.close() for epToWrite in epsToWrite: epToWrite.hasnfo = True
def _combined_file_operation (self, file_path, new_path, new_base_name, associated_files=False, action=None): """ Performs a generic operation (move or copy) on a file. Can rename the file as well as change its location, and optionally move associated files too. file_path: The full path of the media file to act on new_path: Destination path where we want to move/copy the file to new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. associated_files: Boolean, whether we should copy similarly-named files too action: function that takes an old path and new path and does an operation with them (move/copy) """ if not action: self._log(u"Must provide an action for the combined file operation", logger.ERROR) return file_list = [file_path] if associated_files: file_list = file_list + self._list_associated_files(file_path) if not file_list: self._log(u"There were no files associated with " + file_path + ", not moving anything", logger.DEBUG) return # deal with all files for cur_file_path in file_list: cur_file_name = ek.ek(os.path.basename, cur_file_path) # get the extension cur_extension = cur_file_path.rpartition('.')[-1] # replace .nfo with .nfo-orig to avoid conflicts if cur_extension == 'nfo': cur_extension = 'nfo-orig' # list of ISO693-1 country codes ISO693 = ["ab", "aa", "af", "ak", "sq", "am", "ar", "an", "hy", "as", "av", "ae", "ay", "az", "bm", "ba", "eu", "be", "bn", "bh", "bi", "bs", "br", "bg", "my", "ca", "ch", "ce", "ny", "zh", "cv", "kw", "co", "cr", "hr", "cs", "da", "dv", "nl", "dz", "en", "eo", "et", "ee", "fo", "fj", "fi", "fr", "ff", "gl", "ka", "de", "el", "gn", "gu", "ht", "ha", "he", "hz", "hi", "ho", "hu", "ia", "id", "ie", "ga", "ig", "ik", "io", "is", "it", "iu", "ja", "jv", "kl", "kn", "kr", "ks", "kk", "km", "ki", "rw", "ky", "kv", "kg", "ko", "ku", "kj", "la", "lb", "lg", "li", "ln", "lo", "lt", "lu", "lv", "gv", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mh", "mn", "na", "nv", "nb", "nd", "ne", "ng", "nn", "no", "ii", "nr", "oc", "oj", "cu", "om", "or", "os", "pa", "pi", "fa", "pl", "ps", "pt", "qu", "rm", "rn", "ro", "ru", "sa", "sc", "sd", "se", "sm", "sg", "sr", "gd", "sn", "si", "sk", "sl", "so", "st", "es", "su", "sw", "ss", "sv", "ta", "te", "tg", "th", "ti", "bo", "tk", "tl", "tn", "to", "tr", "ts", "tt", "tw", "ty", "ug", "uk", "ur", "uz", "ve", "vi", "vo", "wa", "cy", "wo", "fy", "xh", "yi", "yo", "za", "zu"] # If file ends with srt, check if there is an vallid ISO963 value in front of it. if (cur_extension == "srt" and (cur_file_path.rpartition('.')[0].rpartition('.')[-1]) in ISO693): cur_extension = (cur_file_path.rpartition('.')[0].rpartition('.')[-1]) +'.' + 'srt' # If new base name then convert name if new_base_name: new_file_name = new_base_name +'.' + cur_extension # if we're not renaming we still want to change extensions sometimes else: new_file_name = helpers.replaceExtension(cur_file_name, cur_extension) new_file_path = ek.ek(os.path.join, new_path, new_file_name) action(cur_file_path, new_file_path)
def get_episode_thumb_path(self, ep_obj): return helpers.replaceExtension(ep_obj.location, 'jpg')
def _combined_file_operation(self, file_path, new_path, new_base_name, associated_files=False, action=None, subtitles=False): """ Performs a generic operation (move or copy) on a file. Can rename the file as well as change its location, and optionally move associated files too. :param file_path: The full path of the media file to act on :param new_path: Destination path where we want to move/copy the file to :param new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. :param associated_files: Boolean, whether we should copy similarly-named files too :param action: function that takes an old path and new path and does an operation with them (move/copy) :param subtitles: Boolean, whether we should process subtitles too """ if not action: self._log(u"Must provide an action for the combined file operation", logger.ERROR) return file_list = [file_path] if associated_files: file_list = file_list + self.list_associated_files(file_path) elif subtitles: file_list = file_list + self.list_associated_files(file_path, subtitles_only=True) if not file_list: self._log(u"There were no files associated with " + file_path + ", not moving anything", logger.DEBUG) return # create base name with file_path (media_file without .extension) old_base_name = file_path.rpartition('.')[0] old_base_name_length = len(old_base_name) # deal with all files for cur_file_path in file_list: cur_file_name = ek(os.path.basename, cur_file_path) # get the extension without . cur_extension = cur_file_path[old_base_name_length + 1:] # check if file have subtitles language if os.path.splitext(cur_extension)[1][1:] in common.subtitleExtensions: cur_lang = os.path.splitext(cur_extension)[0] if cur_lang in subtitles.wantedLanguages(): cur_extension = cur_lang + os.path.splitext(cur_extension)[1] # replace .nfo with .nfo-orig to avoid conflicts if cur_extension == 'nfo' and sickbeard.NFO_RENAME == True: cur_extension = 'nfo-orig' # If new base name then convert name if new_base_name: new_file_name = new_base_name + '.' + cur_extension # if we're not renaming we still want to change extensions sometimes else: new_file_name = helpers.replaceExtension(cur_file_name, cur_extension) if sickbeard.SUBTITLES_DIR and cur_extension in common.subtitleExtensions: subs_new_path = ek(os.path.join, new_path, sickbeard.SUBTITLES_DIR) dir_exists = helpers.makeDir(subs_new_path) if not dir_exists: logger.log(u"Unable to create subtitles folder " + subs_new_path, logger.ERROR) else: helpers.chmodAsParent(subs_new_path) new_file_path = ek(os.path.join, subs_new_path, new_file_name) else: new_file_path = ek(os.path.join, new_path, new_file_name) action(cur_file_path, new_file_path)
def get_episode_thumb_path(ep_obj): return helpers.replaceExtension(ep_obj.location, 'jpg')
def process(self): """ Post-process a given file """ self._log(u"Processing " + self.file_path + " (" + str(self.nzb_name) + ")") if ek.ek(os.path.isdir, self.file_path): self._log(u"File " + self.file_path + " seems to be a directory") return False for ignore_file in self.IGNORED_FILESTRINGS: if ignore_file in self.file_path: self._log(u"File " + self.file_path + " is ignored type, skipping") return False # reset per-file stuff self.in_history = False # try to find the file info (tvdb_id, season, episodes) = self._find_info() # if we don't have it then give up if not tvdb_id or season == None or not episodes: return False # retrieve/create the corresponding TVEpisode objects ep_obj = self._get_ep_obj(tvdb_id, season, episodes) # get the quality of the episode we're processing new_ep_quality = self._get_quality(ep_obj) logger.log(u"Quality of the episode we're processing: " + str(new_ep_quality), logger.DEBUG) # see if this is a priority download (is it snatched, in history, or PROPER) priority_download = self._is_priority(ep_obj, new_ep_quality) self._log(u"Is ep a priority download: " + str(priority_download), logger.DEBUG) # set the status of the episodes for curEp in [ep_obj] + ep_obj.relatedEps: curEp.status = common.Quality.compositeStatus(common.SNATCHED, new_ep_quality) # check for an existing file existing_file_status = self._checkForExistingFile(ep_obj.location) # if it's not priority then we don't want to replace smaller files in case it was a mistake if not priority_download: # if there's an existing file that we don't want to replace stop here if existing_file_status in (PostProcessor.EXISTS_LARGER, PostProcessor.EXISTS_SAME): self._log(u"File exists and we are not going to replace it because it's not smaller, quitting post-processing", logger.DEBUG) return False elif existing_file_status == PostProcessor.EXISTS_SMALLER: self._log(u"File exists and is smaller than the new file so I'm going to replace it", logger.DEBUG) elif existing_file_status != PostProcessor.DOESNT_EXIST: self._log(u"Unknown existing file status. This should never happen, please log this as a bug.", logger.ERROR) return False # if the file is priority then we're going to replace it even if it exists else: self._log(u"This download is marked a priority download so I'm going to replace an existing file if I find one", logger.DEBUG) # delete the existing file (and company) for cur_ep in [ep_obj] + ep_obj.relatedEps: try: self._delete(cur_ep.location, associated_files=True) # clean up any left over folders if cur_ep.location: helpers.delete_empty_folders(ek.ek(os.path.dirname, cur_ep.location), keep_dir=ep_obj.show._location) except (OSError, IOError): raise exceptions.PostProcessingFailed("Unable to delete the existing files") # if the show directory doesn't exist then make it if allowed if not ek.ek(os.path.isdir, ep_obj.show._location) and sickbeard.CREATE_MISSING_SHOW_DIRS: self._log(u"Show directory doesn't exist, creating it", logger.DEBUG) try: ek.ek(os.mkdir, ep_obj.show._location) # do the library update for synoindex notifiers.synoindex_notifier.addFolder(ep_obj.show._location) except (OSError, IOError): raise exceptions.PostProcessingFailed("Unable to create the show directory: " + ep_obj.show._location) # get metadata for the show (but not episode because it hasn't been fully processed) ep_obj.show.writeMetadata(True) # update the ep info before we rename so the quality & release name go into the name properly for cur_ep in [ep_obj] + ep_obj.relatedEps: with cur_ep.lock: cur_release_name = None # use the best possible representation of the release name if self.good_results[self.NZB_NAME]: cur_release_name = self.nzb_name if cur_release_name.lower().endswith('.nzb'): cur_release_name = cur_release_name.rpartition('.')[0] elif self.good_results[self.FOLDER_NAME]: cur_release_name = self.folder_name elif self.good_results[self.FILE_NAME]: cur_release_name = self.file_name # take the extension off the filename, it's not needed if '.' in self.file_name: cur_release_name = self.file_name.rpartition('.')[0] if cur_release_name: self._log("Found release name " + cur_release_name, logger.DEBUG) cur_ep.release_name = cur_release_name else: logger.log(u"good results: " + repr(self.good_results), logger.DEBUG) cur_ep.status = common.Quality.compositeStatus(common.DOWNLOADED, new_ep_quality) cur_ep.subtitles = [] cur_ep.subtitles_searchcount = 0 cur_ep.subtitles_lastsearch = '0001-01-01 00:00:00' cur_ep.is_proper = self.is_proper cur_ep.saveToDB() # find the destination folder try: proper_path = ep_obj.proper_path() proper_absolute_path = ek.ek(os.path.join, ep_obj.show.location, proper_path) dest_path = ek.ek(os.path.dirname, proper_absolute_path) except exceptions.ShowDirNotFoundException: raise exceptions.PostProcessingFailed(u"Unable to post-process an episode if the show dir doesn't exist, quitting") self._log(u"Destination folder for this episode: " + dest_path, logger.DEBUG) # create any folders we need helpers.make_dirs(dest_path) # download subtitles if sickbeard.USE_SUBTITLES and ep_obj.show.subtitles: cur_ep.location = self.file_path cur_ep.downloadSubtitles(force=True) # figure out the base name of the resulting episode file if sickbeard.RENAME_EPISODES: orig_extension = self.file_name.rpartition('.')[-1] new_base_name = ek.ek(os.path.basename, proper_path) new_file_name = new_base_name + '.' + orig_extension else: # if we're not renaming then there's no new base name, we'll just use the existing name new_base_name = None new_file_name = self.file_name try: # move the episode and associated files to the show dir if sickbeard.PROCESS_METHOD == "copy": self._copy(self.file_path, dest_path, new_base_name, sickbeard.MOVE_ASSOCIATED_FILES, sickbeard.USE_SUBTITLES and ep_obj.show.subtitles) # create an empty helper file to indicate that this video has been processed helper_file = helpers.replaceExtension(self.file_path, "processed") open(helper_file, 'w') elif sickbeard.PROCESS_METHOD == "move": self._move(self.file_path, dest_path, new_base_name, sickbeard.MOVE_ASSOCIATED_FILES, sickbeard.USE_SUBTITLES and ep_obj.show.subtitles) elif sickbeard.PROCESS_METHOD == "hardlink": self._hardlink(self.file_path, dest_path, new_base_name, sickbeard.MOVE_ASSOCIATED_FILES, sickbeard.USE_SUBTITLES and ep_obj.show.subtitles) elif sickbeard.PROCESS_METHOD == "symlink": self._moveAndSymlink(self.file_path, dest_path, new_base_name, sickbeard.MOVE_ASSOCIATED_FILES, sickbeard.USE_SUBTITLES and ep_obj.show.subtitles) else: logger.log(u"Unknown process method: " + sickbeard.PROCESS_METHOD, logger.ERROR) raise exceptions.PostProcessingFailed("Unable to move the files to their new home") except (OSError, IOError): raise exceptions.PostProcessingFailed("Unable to move the files to their new home") # put the new location in the database for cur_ep in [ep_obj] + ep_obj.relatedEps: with cur_ep.lock: cur_ep.location = ek.ek(os.path.join, dest_path, new_file_name) cur_ep.saveToDB() # log it to history history.logDownload(ep_obj, self.file_path, new_ep_quality, self.release_group) # send notifications notifiers.notify_download(ep_obj._format_pattern('%SN - %Sx%0E - %EN - %QN')) # generate nfo/tbn ep_obj.createMetaFiles() ep_obj.saveToDB() # do the library update for XBMC notifiers.xbmc_notifier.update_library(ep_obj.show.name) # do the library update for Plex notifiers.plex_notifier.update_library() # do the library update for NMJ # nmj_notifier kicks off its library update when the notify_download is issued (inside notifiers) # do the library update for Synology Indexer notifiers.synoindex_notifier.addFile(ep_obj.location) # do the library update for pyTivo notifiers.pytivo_notifier.update_library(ep_obj) # do the library update for Trakt notifiers.trakt_notifier.update_library(ep_obj) self._run_extra_scripts(ep_obj) return True
def _combined_file_operation(self, file_path, new_path, new_base_name, associated_files=False, action=None, subtitles=False, action_tmpl=None): """ Performs a generic operation (move or copy) on a file. Can rename the file as well as change its location, and optionally move associated files too. file_path: The full path of the media file to act on new_path: Destination path where we want to move/copy the file to new_base_name: The base filename (no extension) to use during the copy. Use None to keep the same name. associated_files: Boolean, whether we should copy similarly-named files too action: function that takes an old path and new path and does an operation with them (move/copy) """ if not action: self._log(u'Must provide an action for the combined file operation', logger.ERROR) return file_list = [file_path] if associated_files: file_list = file_list + self.list_associated_files(file_path) elif subtitles: file_list = file_list + self.list_associated_files(file_path, subtitles_only=True) if not file_list: self._log(u'Not moving anything because there are no files associated with %s' % file_path, logger.DEBUG) return # create base name with file_path (media_file without .extension) old_base_name = file_path.rpartition('.')[0] old_base_name_length = len(old_base_name) # deal with all files for cur_file_path in file_list: cur_file_name = ek.ek(os.path.basename, cur_file_path) # get the extension without . cur_extension = cur_file_path[old_base_name_length + 1:] # replace .nfo with .nfo-orig to avoid conflicts if 'nfo' == cur_extension and True is sickbeard.NFO_RENAME: cur_extension = 'nfo-orig' # check if file have subtitles language if os.path.splitext(cur_extension)[1][1:] in common.subtitleExtensions: cur_lang = os.path.splitext(cur_extension)[0] if cur_lang in sickbeard.SUBTITLES_LANGUAGES: cur_extension = cur_lang + os.path.splitext(cur_extension)[1] # If new base name then convert name if new_base_name: new_file_name = new_base_name + '.' + cur_extension # if we're not renaming we still want to change extensions sometimes else: new_file_name = helpers.replaceExtension(cur_file_name, cur_extension) if sickbeard.SUBTITLES_DIR and cur_extension in common.subtitleExtensions: subs_new_path = ek.ek(os.path.join, new_path, sickbeard.SUBTITLES_DIR) dir_exists = helpers.makeDir(subs_new_path) if not dir_exists: logger.log(u'Unable to create subtitles folder ' + subs_new_path, logger.ERROR) else: helpers.chmodAsParent(subs_new_path) new_file_path = ek.ek(os.path.join, subs_new_path, new_file_name) else: new_file_path = ek.ek(os.path.join, new_path, new_file_name) if None is action_tmpl: action(cur_file_path, new_file_path) else: action(cur_file_path, new_file_path, action_tmpl)
def process(self): """ Post-process a given file """ self._log(u"Processing " + self.file_path + " (" + str(self.nzb_name) + ")") if ek.ek(os.path.isdir, self.file_path): self._log(u"File " + self.file_path + " seems to be a directory") return False for ignore_file in self.IGNORED_FILESTRINGS: if ignore_file in self.file_path: self._log(u"File " + self.file_path + " is ignored type, skipping") return False # reset per-file stuff self.in_history = False # try to find the file info (tvdb_id, season, episodes) = self._find_info() # if we don't have it then give up if not tvdb_id or season == None or not episodes: return False # retrieve/create the corresponding TVEpisode objects ep_obj = self._get_ep_obj(tvdb_id, season, episodes) # get the quality of the episode we're processing new_ep_quality = self._get_quality(ep_obj) logger.log(u"Quality of the episode we're processing: " + str(new_ep_quality), logger.DEBUG) # see if this is a priority download (is it snatched, in history, or PROPER) priority_download = self._is_priority(ep_obj, new_ep_quality) self._log(u"Is ep a priority download: " + str(priority_download), logger.DEBUG) # set the status of the episodes for curEp in [ep_obj] + ep_obj.relatedEps: curEp.status = common.Quality.compositeStatus(common.SNATCHED, new_ep_quality) # check for an existing file existing_file_status = self._checkForExistingFile(ep_obj.location) # if it's not priority then we don't want to replace smaller files in case it was a mistake if not priority_download: # if there's an existing file that we don't want to replace stop here if existing_file_status in (PostProcessor.EXISTS_LARGER, PostProcessor.EXISTS_SAME): self._log(u"File exists and we are not going to replace it because it's not smaller, quitting post-processing", logger.DEBUG) return False elif existing_file_status == PostProcessor.EXISTS_SMALLER: self._log(u"File exists and is smaller than the new file so I'm going to replace it", logger.DEBUG) elif existing_file_status != PostProcessor.DOESNT_EXIST: self._log(u"Unknown existing file status. This should never happen, please log this as a bug.", logger.ERROR) return False # if the file is priority then we're going to replace it even if it exists else: self._log(u"This download is marked a priority download so I'm going to replace an existing file if I find one", logger.DEBUG) # delete the existing file (and company) for cur_ep in [ep_obj] + ep_obj.relatedEps: try: self._delete(cur_ep.location, associated_files=True) # clean up any left over folders if cur_ep.location: helpers.delete_empty_folders(ek.ek(os.path.dirname, cur_ep.location), keep_dir=ep_obj.show._location) except (OSError, IOError): raise exceptions.PostProcessingFailed("Unable to delete the existing files") # if the show directory doesn't exist then make it if allowed if not ek.ek(os.path.isdir, ep_obj.show._location) and sickbeard.CREATE_MISSING_SHOW_DIRS: self._log(u"Show directory doesn't exist, creating it", logger.DEBUG) try: ek.ek(os.mkdir, ep_obj.show._location) # do the library update for synoindex notifiers.synoindex_notifier.addFolder(ep_obj.show._location) except (OSError, IOError): raise exceptions.PostProcessingFailed("Unable to create the show directory: " + ep_obj.show._location) # get metadata for the show (but not episode because it hasn't been fully processed) ep_obj.show.writeMetadata(True) # update the ep info before we rename so the quality & release name go into the name properly for cur_ep in [ep_obj] + ep_obj.relatedEps: with cur_ep.lock: cur_release_name = None # use the best possible representation of the release name if self.good_results[self.NZB_NAME]: cur_release_name = self.nzb_name if cur_release_name.lower().endswith('.nzb'): cur_release_name = cur_release_name.rpartition('.')[0] elif self.good_results[self.FOLDER_NAME]: cur_release_name = self.folder_name elif self.good_results[self.FILE_NAME]: cur_release_name = self.file_name # take the extension off the filename, it's not needed if '.' in self.file_name: cur_release_name = self.file_name.rpartition('.')[0] if cur_release_name: self._log("Found release name " + cur_release_name, logger.DEBUG) cur_ep.release_name = cur_release_name else: logger.log(u"good results: " + repr(self.good_results), logger.DEBUG) cur_ep.status = common.Quality.compositeStatus(common.DOWNLOADED, new_ep_quality) cur_ep.saveToDB() # find the destination folder try: proper_path = ep_obj.proper_path() proper_absolute_path = ek.ek(os.path.join, ep_obj.show.location, proper_path) dest_path = ek.ek(os.path.dirname, proper_absolute_path) except exceptions.ShowDirNotFoundException: raise exceptions.PostProcessingFailed(u"Unable to post-process an episode if the show dir doesn't exist, quitting") self._log(u"Destination folder for this episode: " + dest_path, logger.DEBUG) # create any folders we need helpers.make_dirs(dest_path) # figure out the base name of the resulting episode file if sickbeard.RENAME_EPISODES: orig_extension = self.file_name.rpartition('.')[-1] new_base_name = ek.ek(os.path.basename, proper_path) new_file_name = new_base_name + '.' + orig_extension else: # if we're not renaming then there's no new base name, we'll just use the existing name new_base_name = None new_file_name = self.file_name try: # move the episode and associated files to the show dir if sickbeard.KEEP_PROCESSED_DIR: self._copy(self.file_path, dest_path, new_base_name, sickbeard.MOVE_ASSOCIATED_FILES) # create an empty helper file to indicate that this video has been processed helper_file = helpers.replaceExtension(self.file_path, "processed") open(helper_file, 'w') else: self._move(self.file_path, dest_path, new_base_name, sickbeard.MOVE_ASSOCIATED_FILES) except (OSError, IOError): raise exceptions.PostProcessingFailed("Unable to move the files to their new home") # put the new location in the database for cur_ep in [ep_obj] + ep_obj.relatedEps: with cur_ep.lock: cur_ep.location = ek.ek(os.path.join, dest_path, new_file_name) cur_ep.saveToDB() # log it to history history.logDownload(ep_obj, self.file_path, new_ep_quality, self.release_group) # send notifications notifiers.notify_download(ep_obj.prettyName()) # generate nfo/tbn ep_obj.createMetaFiles() ep_obj.saveToDB() # do the library update for XBMC notifiers.xbmc_notifier.update_library(ep_obj.show.name) # do the library update for Plex notifiers.plex_notifier.update_library() # do the library update for NMJ # nmj_notifier kicks off its library update when the notify_download is issued (inside notifiers) # do the library update for Synology Indexer notifiers.synoindex_notifier.addFile(ep_obj.location) # do the library update for pyTivo notifiers.pytivo_notifier.update_library(ep_obj) # do the library update for Trakt notifiers.trakt_notifier.update_library(ep_obj) self._run_extra_scripts(ep_obj) return True