Пример #1
0
 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.')
Пример #2
0
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
Пример #3
0
    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)
Пример #4
0
	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 
Пример #5
0
    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)
Пример #6
0
    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)
Пример #7
0
    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
Пример #8
0
 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
Пример #9
0
    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)
Пример #10
0
    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
Пример #11
0
    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
Пример #12
0
    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
Пример #13
0
    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
Пример #14
0
    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
Пример #15
0
    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)
Пример #16
0
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)
Пример #17
0
 def get_episode_file_path(self, ep_obj):
     return helpers.replaceExtension(ep_obj.location,
                                     self._ep_nfo_extension)
Пример #18
0
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)
Пример #19
0
    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)
Пример #20
0
    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)
Пример #21
0
				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
Пример #22
0
 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.')
Пример #23
0
    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)
Пример #24
0
 def get_episode_thumb_path(self, ep_obj):
     return helpers.replaceExtension(ep_obj.location, 'jpg')
Пример #25
0
    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)
Пример #26
0
 def get_episode_file_path(self, ep_obj):
     return helpers.replaceExtension(ep_obj.location, self._ep_nfo_extension)
Пример #27
0
 def get_episode_thumb_path(ep_obj):
     return helpers.replaceExtension(ep_obj.location, 'jpg')
Пример #28
0
    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
Пример #29
0
    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)
Пример #30
0
    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