Example #1
0
    def _get_ep_obj(self, tvdb_id, season, episodes):

        show_obj = None

        self._log(u"Loading show object for tvdb_id "+str(tvdb_id), logger.DEBUG)
        # find the show in the showlist
        try:
            show_obj = helpers.findCertainShow(sickbeard.showList, tvdb_id)
        except exceptions.MultipleShowObjectsException:
            raise #TODO: later I'll just log this, for now I want to know about it ASAP

        if not show_obj:
            self._log(u"This show isn't in your list, you need to add it to SB before post-processing an episode", logger.ERROR)
            raise exceptions.PostProcessingFailed()

        root_ep = None
        for cur_episode in episodes:
            episode = int(cur_episode)
    
            self._log(u"Retrieving episode object for " + str(season) + "x" + str(episode), logger.DEBUG)
    
            # now that we've figured out which episode this file is just load it manually
            try:
                curEp = show_obj.getEpisode(season, episode)
            except exceptions.EpisodeNotFoundException, e:
                self._log(u"Unable to create episode: "+ex(e), logger.DEBUG)
                raise exceptions.PostProcessingFailed()
    
            if root_ep == None:
                root_ep = curEp
                root_ep.relatedEps = []
            else:
                root_ep.relatedEps.append(curEp)
Example #2
0
    def _get_ep_obj(self, indexer_id, indexer, season, episodes):
        """
        Retrieve the TVEpisode object requested.

        indexer_id: The indexerid of the show (int)
        season: The season of the episode (int)
        episodes: A list of episodes to find (list of ints)

        If the episode(s) can be found then a TVEpisode object with the correct related eps will
        be instantiated and returned. If the episode can't be found then None will be returned.
        """

        self._log(
            u"Loading show object with Indexer ID:[" + str(indexer_id) +
            "] for Indexer:[" + str(sickbeard.indexerApi(indexer).name) + "]",
            logger.DEBUG)
        # find the show in the showlist
        try:
            show_obj = helpers.findCertainShow(sickbeard.showList, indexer_id)
        except exceptions.MultipleShowObjectsException:
            raise  #TODO: later I'll just log this, for now I want to know about it ASAP

        # if we can't find the show then there's nothing we can really do
        if not show_obj:
            self._log(
                u"This show isn't in your list, you need to add it to SB before post-processing an episode",
                logger.ERROR)
            raise exceptions.PostProcessingFailed()

        root_ep = None
        for cur_episode in episodes:
            self._log(
                u"Retrieving episode object for " + str(season) + "x" +
                str(cur_episode), logger.DEBUG)

            # detect and convert scene numbered releases
            season, cur_episode = sickbeard.scene_numbering.get_indexer_numbering(
                indexer_id, indexer, season, cur_episode)

            # now that we've figured out which episode this file is just load it manually
            try:
                curEp = show_obj.getEpisode(season, cur_episode)
            except exceptions.EpisodeNotFoundException, e:
                self._log(u"Unable to create episode: " + ex(e), logger.DEBUG)
                raise exceptions.PostProcessingFailed()

            self._log(
                u"Episode object has been converted from Scene numbering " +
                str(curEp.scene_season) + "x" + str(curEp.scene_episode) +
                " to Indexer numbering" + str(curEp.season) + "x" +
                str(curEp.episode))

            # associate all the episodes together under a single root episode
            if root_ep == None:
                root_ep = curEp
                root_ep.relatedEps = []
            elif curEp not in root_ep.relatedEps:
                root_ep.relatedEps.append(curEp)
    def _get_ep_obj(self, tvdb_id, season, episodes, scene=False):
        """
        Retrieve the TVEpisode object requested.
        
        tvdb_id: The TVDBID of the show (int)
        season: The season of the episode (int)
        episodes: A list of episodes to find (list of ints)
        
        If the episode(s) can be found then a TVEpisode object with the correct related eps will
        be instantiated and returned. If the episode can't be found then None will be returned. 
        """

        show_obj = None
        sceneMsg = ""
        if scene:
            sceneMsg = "(scene numbers) "

        self._log(u"Loading show object for tvdb_id " + str(tvdb_id),
                  logger.DEBUG)
        # find the show in the showlist
        try:
            show_obj = helpers.findCertainShow(sickbeard.showList, tvdb_id)
        except exceptions.MultipleShowObjectsException:
            raise  #TODO: later I'll just log this, for now I want to know about it ASAP

        # if we can't find the show then there's nothing we can really do
        if not show_obj:
            self._log(
                u"This show isn't in your list, you need to add it to SB before post-processing an episode",
                logger.ERROR)
            raise exceptions.PostProcessingFailed()

        root_ep = None
        for cur_episode in episodes:
            episode = int(cur_episode)
            self._log(
                u"Retrieving episode object for " + sceneMsg + str(season) +
                "x" + str(episode), logger.DEBUG)

            # now that we've figured out which episode this file is just load it manually
            try:
                curEp = show_obj.getEpisode(season, episode, scene=scene)
            except exceptions.EpisodeNotFoundException, e:
                self._log(u"Unable to create episode: " + ex(e), logger.DEBUG)
                raise exceptions.PostProcessingFailed()

            # associate all the episodes together under a single root episode
            if root_ep == None:
                root_ep = curEp
                if not scene:
                    root_ep.relatedEps = []
            else:
                self._log("Adding a related episode: " + str(curEp.season) +
                          "x" + str(curEp.episode))
                root_ep.relatedEps.append(curEp)
Example #4
0
    def _get_ep_obj(self, show, season, episodes):
        """
        Retrieve the TVEpisode object requested.

        show: The show object belonging to the show we want to process
        season: The season of the episode (int)
        episodes: A list of episodes to find (list of ints)

        If the episode(s) can be found then a TVEpisode object with the correct related eps will
        be instantiated and returned. If the episode can't be found then None will be returned.
        """

        root_ep = None
        for cur_episode in episodes:
            self._log(
                u"Retrieving episode object for " + str(season) + "x" +
                str(cur_episode), logger.DEBUG)

            # now that we've figured out which episode this file is just load it manually
            try:
                curEp = show.getEpisode(season, cur_episode)
                if not curEp:
                    raise exceptions.EpisodeNotFoundException()
            except exceptions.EpisodeNotFoundException, e:
                self._log(u"Unable to create episode: " + ex(e), logger.DEBUG)
                raise exceptions.PostProcessingFailed()

            # associate all the episodes together under a single root episode
            if root_ep == None:
                root_ep = curEp
                root_ep.relatedEps = []
            elif curEp not in root_ep.relatedEps:
                root_ep.relatedEps.append(curEp)
Example #5
0
    def process(self):
        """
        Post-process a given file
        """
        
        self._log(u"Processing "+self.file_path+" ("+str(self.nzb_name)+")")
        
        # 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)
            except OSError, IOError:
                raise exceptions.PostProcessingFailed("Unable to delete the existing files")
Example #6
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

        # reset per-file stuff
        self.in_history = False

        # try to find the file info
        (tvdb_id, season, episodes, quality) = self._find_info()

        # if we don't have it then give up
        if not tvdb_id or season is None or not episodes:
            self._log(u"Not enough information to determine what episode this is", logger.DEBUG)
            self._log(u"Quitting post-processing", logger.DEBUG)
            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
        if quality:
            self._log(u"Snatch history had a quality in it, using that: " + common.Quality.qualityStrings[quality], logger.DEBUG)
            new_ep_quality = quality
        else:
            new_ep_quality = self._get_quality(ep_obj)

        logger.log(u"Quality of the processing episode: " + str(new_ep_quality), logger.DEBUG)

        # see if it's safe to replace existing episode (is download snatched, PROPER, better quality)
        safe_replace = self._safe_replace(ep_obj, new_ep_quality)

        # if it's not safe to replace, stop here
        if not safe_replace:
            self._log(u"Quitting post-processing", logger.DEBUG)
            return False

        # if the file is safe to replace then we're going to replace it even if it exists
        else:
            self._log(u"This download is marked as safe to replace existing file", 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(u"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(u"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:

            if self.release_name:
                self._log(u"Found release name " + self.release_name, logger.DEBUG)
                cur_ep.release_name = self.release_name
            else:
                cur_ep.release_name = ""

            cur_ep.status = common.Quality.compositeStatus(common.DOWNLOADED, new_ep_quality)

        # 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
        if not helpers.make_dirs(dest_path):
            raise exceptions.PostProcessingFailed(u"Unable to create destination folder: " + 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)
            else:
                self._move(self.file_path, dest_path, new_base_name, sickbeard.MOVE_ASSOCIATED_FILES)
        except (OSError, IOError):
            raise exceptions.PostProcessingFailed(u"Unable to move the files to destination folder: " + dest_path)

        # 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 notifiers download notification
        if not ep_obj.show.skip_notices:
            notifiers.notify_download(ep_obj.prettyName())

        # generate nfo/tbn
        ep_obj.createMetaFiles()
        ep_obj.saveToDB()

        # send notifiers library update
        notifiers.update_library(ep_obj)

        self._run_extra_scripts(ep_obj)

        return True
Example #7
0
    def process(self):
        """
        Post-process a given file
        """

        self._log(u"Processing " + self.file_path + " (" + str(self.nzb_name) +
                  ")")

        if 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("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)
            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)

        # download subtitles
        if sickbeard.USE_SUBTITLES and ep_obj.show.subtitles:
            cur_ep.downloadSubtitles()

        # 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
Example #8
0
        # 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)
            except OSError, IOError:
                raise exceptions.PostProcessingFailed("Unable to delete the existing files")
        
        # find the destination folder
        try:
            dest_path = self._find_ep_destination_folder(ep_obj)
        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)
        
        # if the dir doesn't exist (new season folder) then make it
        if not ek.ek(os.path.isdir, dest_path):
            self._log(u"Season folder didn't exist, creating it", logger.DEBUG)
            try:
                ek.ek(os.mkdir, dest_path)
                helpers.chmodAsParent(dest_path)
            except OSError, IOError:
                raise exceptions.PostProcessingFailed("Unable to create the episode's destination folder: "+dest_path)

        # update the statuses before we rename so the quality goes into the name properly
        for cur_ep in [ep_obj] + ep_obj.relatedEps:
            with cur_ep.lock:
Example #9
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

        # reset the anidb episode object
        self.anidbEpisode = None

        # try to find the file info
        (show, season, episodes, quality, version) = self._find_info()
        if not show:
            self._log(
                u"This show isn't in your list, you need to add it to SB before post-processing an episode",
                logger.WARNING)
            raise exceptions.PostProcessingFailed()
        elif season == None or not episodes:
            self._log(
                u"Not enough information to determine what episode this is",
                logger.DEBUG)
            self._log(u"Quitting post-processing", logger.DEBUG)
            return False

        # retrieve/create the corresponding TVEpisode objects
        ep_obj = self._get_ep_obj(show, season, episodes)

        # get the quality of the episode we're processing
        if quality:
            self._log(
                u"Snatch history had a quality in it, using that: " +
                common.Quality.qualityStrings[quality], logger.DEBUG)
            new_ep_quality = quality
        else:
            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, PROPER, or BEST)
        priority_download = self._is_priority(ep_obj, new_ep_quality)
        self._log(u"Is ep a priority download: " + str(priority_download),
                  logger.DEBUG)

        # get the version of the episode we're processing
        if version:
            self._log(
                u"Snatch history had a version in it, using that: v" +
                str(version), logger.DEBUG)
            new_ep_version = version
        else:
            new_ep_version = -1

        # 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 == PostProcessor.EXISTS_LARGER:
                if self.is_proper:
                    self._log(
                        u"File exists and new file is smaller, new file is a proper/repack, marking it safe to replace",
                        logger.DEBUG)
                    return True

                else:
                    self._log(
                        u"File exists and new file is smaller, marking it unsafe to replace",
                        logger.DEBUG)
                    return False

            elif existing_file_status == PostProcessor.EXISTS_SAME:
                self._log(
                    u"File exists and new file is same size, marking it unsafe to replace",
                    logger.DEBUG)
                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")

            # set the status of the episodes
            # for curEp in [ep_obj] + ep_obj.relatedEps:
            #    curEp.status = common.Quality.compositeStatus(common.SNATCHED, new_ep_quality)

        # 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
        sql_l = []
        trakt_data = []
        for cur_ep in [ep_obj] + ep_obj.relatedEps:
            with cur_ep.lock:

                if self.release_name:
                    self._log("Found release name " + self.release_name,
                              logger.DEBUG)
                    cur_ep.release_name = self.release_name
                else:
                    cur_ep.release_name = ""

                if ep_obj.status in common.Quality.SNATCHED_BEST:
                    cur_ep.status = common.Quality.compositeStatus(
                        common.ARCHIVED, new_ep_quality)
                else:
                    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.version = new_ep_version

                if self.release_group:
                    cur_ep.release_group = self.release_group
                else:
                    cur_ep.release_group = ""

                sql_l.append(cur_ep.get_sql())

                trakt_data.append((cur_ep.season, cur_ep.episode))

        data = notifiers.trakt_notifier.trakt_episode_data_generate(trakt_data)

        if sickbeard.USE_TRAKT and sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.TRAKT_REMOVE_WATCHLIST:
            logger.log(
                u"Remove episodes, showid: indexerid " + str(show.indexerid) +
                ", Title " + str(show.name) + " to Traktv Watchlist",
                logger.DEBUG)
            if data:
                notifiers.trakt_notifier.update_watchlist(show,
                                                          data_episode=data,
                                                          update="remove")

        if len(sql_l) > 0:
            myDB = db.DBConnection()
            myDB.mass_action(sql_l)

        # Just want to keep this consistent for failed handling right now
        releaseName = show_name_helpers.determineReleaseName(
            self.folder_path, self.nzb_name)
        if releaseName is not None:
            failed_history.logSuccess(releaseName)
        else:
            self._log(u"Couldn't find release in snatch history",
                      logger.WARNING)

        # 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

        # add to anidb
        if ep_obj.show.is_anime and sickbeard.ANIDB_USE_MYLIST:
            self._add_to_anidb_mylist(self.file_path)

        try:
            # move the episode and associated files to the show dir
            if self.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)
            elif self.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 self.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 self.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: " + str(self.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")

        # download subtitles
        if sickbeard.USE_SUBTITLES and ep_obj.show.subtitles:
            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.downloadSubtitles(force=True)

        # put the new location in the database
        sql_l = []
        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)
                sql_l.append(cur_ep.get_sql())

        if len(sql_l) > 0:
            myDB = db.DBConnection()
            myDB.mass_action(sql_l)

        # set file modify stamp to show airdate
        if sickbeard.AIRDATE_EPISODES:
            for cur_ep in [ep_obj] + ep_obj.relatedEps:
                with cur_ep.lock:
                    cur_ep.airdateModifyStamp()

        # generate nfo/tbn
        ep_obj.createMetaFiles()

        # log it to history
        history.logDownload(ep_obj, self.file_path, new_ep_quality,
                            self.release_group, new_ep_version)

        # send notifications
        notifiers.notify_download(
            ep_obj._format_pattern('%SN - %Sx%0E - %EN - %QN'))

        # do the library update for KODI
        notifiers.kodi_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
Example #10
0
    def process(self):
        """
        Post-process a given file
        """

        self._log(u"Processing " + self.file_path + " (" + str(self.nzb_name) +
                  ")")

        # 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)

        # if renaming is turned on then rename the episode (and associated files, if necessary)
        if sickbeard.RENAME_EPISODES:
            new_file_name = helpers.sanitizeFileName(ep_obj.prettyName())
            try:
                self._rename(self.file_path, new_file_name,
                             sickbeard.MOVE_ASSOCIATED_FILES)
            except OSError, IOError:
                raise exceptions.PostProcessingFailed(
                    "Unable to rename the files")

            # remember the new name of the file
            new_file_path = ek.ek(
                os.path.join, self.folder_path,
                new_file_name + '.' + self.file_name.rpartition('.')[-1])
            self._log(u"After renaming the new file path is " + new_file_path,
                      logger.DEBUG)
Example #11
0
            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)

            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
                elif self.good_results[self.FOLDER_NAME]:
                    cur_release_name = self.folder_name