예제 #1
0
    def load_from_nfo(self, location):
        if not os.path.isdir(self.show.location):
            sickrage.app.log.info(
                "{}: The show dir is missing, not bothering to try loading the episode NFO".format(
                    self.show.indexer_id))
            return False

        sickrage.app.log.debug(
            "{}: Loading episode details from the NFO file associated with {}".format(self.show.indexer_id, location))

        if os.path.isfile(location):
            self.location = location
            if self.status == UNKNOWN:
                if is_media_file(self.location):
                    sickrage.app.log.debug("7 Status changes from " + str(self.status) + " to " + str(
                        Quality.status_from_name(self.location, anime=self.show.is_anime)))
                    self.status = Quality.status_from_name(self.location, anime=self.show.is_anime)

            nfoFile = replace_extension(self.location, "nfo")
            sickrage.app.log.debug(str(self.show.indexer_id) + ": Using NFO name " + nfoFile)

            self.hasnfo = False
            if os.path.isfile(nfoFile):
                try:
                    showXML = ElementTree(file=nfoFile)
                except (SyntaxError, ValueError) as e:
                    sickrage.app.log.warning("Error loading the NFO, backing up the NFO and skipping for now: {}".format(e))

                    try:
                        os.rename(nfoFile, nfoFile + ".old")
                    except Exception as e:
                        sickrage.app.log.warning("Failed to rename your episode's NFO file - you need to delete it or fix it: {}".format(e))

                    raise NoNFOException("Error in NFO format")

                for epDetails in showXML.iter('episodedetails'):
                    if (epDetails.findtext('season') is None or int(epDetails.findtext('season')) != self.season) or (epDetails.findtext(
                            'episode') is None or int(epDetails.findtext('episode')) != self.episode):
                        sickrage.app.log.debug("%s: NFO has an <episodedetails> block for a different episode - wanted S%02dE%02d but got "
                                               "S%02dE%02d" % (self.show.indexer_id,
                                                               self.season or 0,
                                                               self.episode or 0,
                                                               int(epDetails.findtext('season')) or 0,
                                                               int(epDetails.findtext('episode')) or 0))
                        continue

                    if epDetails.findtext('title') is None or epDetails.findtext('aired') is None:
                        raise NoNFOException("Error in NFO format (missing episode title or airdate)")

                    self.name = epDetails.findtext('title')
                    self.episode = try_int(epDetails.findtext('episode'))
                    self.season = try_int(epDetails.findtext('season'))

                    from sickrage.core.scene_numbering import get_scene_absolute_numbering, get_scene_numbering

                    self.scene_absolute_number = get_scene_absolute_numbering(
                        self.show.indexer_id,
                        self.show.indexer,
                        self.absolute_number,
                        session=object_session(self)
                    )

                    self.scene_season, self.scene_episode = get_scene_numbering(
                        self.show.indexer_id,
                        self.show.indexer,
                        self.season, self.episode,
                        session=object_session(self)
                    )

                    self.description = epDetails.findtext('plot') or self.description

                    self.airdate = datetime.date.min
                    if epDetails.findtext('aired'):
                        rawAirdate = [int(x) for x in epDetails.findtext('aired').split("-")]
                        self.airdate = datetime.date(rawAirdate[0], rawAirdate[1], rawAirdate[2])

                    self.hasnfo = True

            self.hastbn = False
            if os.path.isfile(replace_extension(nfoFile, "tbn")):
                self.hastbn = True

        object_session(self).safe_commit()

        return self.hasnfo
예제 #2
0
    def make_ep_from_file(self, filename):
        if not os.path.isfile(filename):
            sickrage.app.log.info(
                str(self.indexer_id) +
                ": That isn't even a real file dude... " + filename)
            return None

        sickrage.app.log.debug(
            str(self.indexer_id) + ": Creating episode object from " +
            filename)

        try:
            parse_result = NameParser(validate_show=False).parse(
                filename, skip_scene_detection=True)
        except InvalidNameException:
            sickrage.app.log.debug("Unable to parse the filename " + filename +
                                   " into a valid episode")
            return None
        except InvalidShowException:
            sickrage.app.log.debug("Unable to parse the filename " + filename +
                                   " into a valid show")
            return None

        if not len(parse_result.episode_numbers):
            sickrage.app.log.info("parse_result: " + str(parse_result))
            sickrage.app.log.warning("No episode number found in " + filename +
                                     ", ignoring it")
            return None

        # for now lets assume that any episode in the show dir belongs to that show
        season = parse_result.season_number if parse_result.season_number is not None else 1
        root_ep = None

        for curEpNum in parse_result.episode_numbers:
            episode = int(curEpNum)

            sickrage.app.log.debug("%s: %s parsed to %s S%02dE%02d" %
                                   (self.indexer_id, filename, self.name,
                                    season or 0, episode or 0))

            check_quality_again = False

            try:
                episode_obj = self.get_episode(season, episode)
            except EpisodeNotFoundException:
                object_session(self).add(
                    TVEpisode(
                        **{
                            'showid': self.indexer_id,
                            'indexer': self.indexer,
                            'season': season,
                            'episode': episode,
                            'location': filename
                        }))
                object_session(self).commit()
                episode_obj = self.get_episode(season, episode)

            # if there is a new file associated with this ep then re-check the quality
            if episode_obj.location and os.path.normpath(
                    episode_obj.location) != os.path.normpath(filename):
                sickrage.app.log.debug(
                    "The old episode had a different file associated with it, I will re-check "
                    "the quality based on the new filename " + filename)
                check_quality_again = True

            # if the sizes are the same then it's probably the same file
            old_size = episode_obj.file_size
            episode_obj.location = filename
            same_file = old_size and episode_obj.file_size == old_size
            episode_obj.checkForMetaFiles()

            if root_ep is None:
                root_ep = episode_obj
            else:
                if episode_obj not in root_ep.related_episodes:
                    root_ep.related_episodes.append(episode_obj)

            # if it's a new file then
            if not same_file:
                episode_obj.release_name = ''

            # if they replace a file on me I'll make some attempt at re-checking the quality unless I know it's the
            # same file
            if check_quality_again and not same_file:
                new_quality = Quality.name_quality(filename, self.is_anime)
                sickrage.app.log.debug("Since this file has been renamed")

                episode_obj.status = Quality.composite_status(
                    DOWNLOADED, new_quality)

            # check for status/quality changes as long as it's a new file
            elif not same_file and is_media_file(
                    filename
            ) and episode_obj.status not in Quality.DOWNLOADED + Quality.ARCHIVED + [
                    IGNORED
            ]:
                old_status, old_quality = Quality.split_composite_status(
                    episode_obj.status)
                new_quality = Quality.name_quality(filename, self.is_anime)

                new_status = None

                # if it was snatched and now exists then set the status correctly
                if old_status == SNATCHED and old_quality <= new_quality:
                    sickrage.app.log.debug(
                        "STATUS: this ep used to be snatched with quality " +
                        Quality.qualityStrings[old_quality] +
                        " but a file exists with quality " +
                        Quality.qualityStrings[new_quality] +
                        " so I'm setting the status to DOWNLOADED")
                    new_status = DOWNLOADED

                # if it was snatched proper and we found a higher quality one then allow the status change
                elif old_status == SNATCHED_PROPER and old_quality < new_quality:
                    sickrage.app.log.debug(
                        "STATUS: this ep used to be snatched proper with quality "
                        + Quality.qualityStrings[old_quality] +
                        " but a file exists with quality " +
                        Quality.qualityStrings[new_quality] +
                        " so I'm setting the status to DOWNLOADED")
                    new_status = DOWNLOADED

                elif old_status not in (SNATCHED, SNATCHED_PROPER):
                    new_status = DOWNLOADED

                if new_status is not None:
                    sickrage.app.log.debug(
                        "STATUS: we have an associated file, so setting the status from "
                        + str(episode_obj.status) + " to DOWNLOADED/" + str(
                            Quality.status_from_name(filename,
                                                     anime=self.is_anime)))
                    episode_obj.status = Quality.composite_status(
                        new_status, new_quality)

        # creating metafiles on the root should be good enough
        if root_ep:
            root_ep.create_meta_files()

        object_session(self).commit()

        return root_ep
예제 #3
0
    def load_from_indexer(self, season=None, episode=None, cache=True, tvapi=None, cachedSeason=None):
        indexer_name = IndexerApi(self.indexer).name

        season = (self.season, season)[season is not None]
        episode = (self.episode, episode)[episode is not None]

        sickrage.app.log.debug("{}: Loading episode details from {} for episode S{:02d}E{:02d}".format(
            self.show.indexer_id, indexer_name, season or 0, episode or 0)
        )

        indexer_lang = self.show.lang or sickrage.app.config.indexer_default_language

        try:
            if cachedSeason is None:
                t = tvapi
                if not t:
                    lINDEXER_API_PARMS = IndexerApi(self.indexer).api_params.copy()
                    lINDEXER_API_PARMS['cache'] = cache

                    lINDEXER_API_PARMS['language'] = indexer_lang

                    if self.show.dvdorder != 0:
                        lINDEXER_API_PARMS['dvdorder'] = True

                    t = IndexerApi(self.indexer).indexer(**lINDEXER_API_PARMS)
                myEp = t[self.show.indexer_id][season][episode]
            else:
                myEp = cachedSeason[episode]
        except (indexer_error, IOError) as e:
            sickrage.app.log.debug("{} threw up an error: {}".format(indexer_name, e))

            # if the episode is already valid just log it, if not throw it up
            if self.name:
                sickrage.app.log.debug("{} timed out but we have enough info from other sources, allowing the error".format(indexer_name))
                return False
            else:
                sickrage.app.log.error("{} timed out, unable to create the episode".format(indexer_name))
                return False
        except (indexer_episodenotfound, indexer_seasonnotfound):
            sickrage.app.log.debug("Unable to find the episode on {}, has it been removed?".format(indexer_name))

            # if I'm no longer on the Indexers but I once was then delete myself from the DB
            if self.indexer_id != -1:
                self.delete_episode()
            return False

        self.indexer_id = try_int(safe_getattr(myEp, 'id'), self.indexer_id)
        if not self.indexer_id:
            sickrage.app.log.warning("Failed to retrieve ID from " + IndexerApi(self.indexer).name)
            object_session(self).rollback()
            object_session(self).safe_commit()
            self.delete_episode()
            return False

        self.name = safe_getattr(myEp, 'episodename', self.name)
        if not myEp.get('episodename'):
            sickrage.app.log.info("This episode {} - S{:02d}E{:02d} has no name on {}. "
                                  "Setting to an empty string".format(self.show.name, season or 0, episode or 0, indexer_name))

        if not myEp.get('absolutenumber'):
            sickrage.app.log.debug("This episode {} - S{:02d}E{:02d} has no absolute number on {}".format(
                self.show.name, season or 0, episode or 0, indexer_name))
        else:
            sickrage.app.log.debug("{}: The absolute_number for S{:02d}E{:02d} is: {}".format(
                self.show.indexer_id, season or 0, episode or 0, myEp["absolutenumber"]))
            self.absolute_number = try_int(safe_getattr(myEp, 'absolutenumber'), self.absolute_number)

        self.season = season
        self.episode = episode

        from sickrage.core.scene_numbering import get_scene_absolute_numbering, get_scene_numbering

        self.scene_absolute_number = get_scene_absolute_numbering(
            self.show.indexer_id,
            self.show.indexer,
            self.absolute_number,
            session=object_session(self)
        )

        self.scene_season, self.scene_episode = get_scene_numbering(
            self.show.indexer_id,
            self.show.indexer,
            self.season, self.episode,
            session=object_session(self)
        )

        self.description = safe_getattr(myEp, 'overview', self.description)

        firstaired = safe_getattr(myEp, 'firstaired') or datetime.date.min

        try:
            rawAirdate = [int(x) for x in str(firstaired).split("-")]
            self.airdate = datetime.date(rawAirdate[0], rawAirdate[1], rawAirdate[2])
        except (ValueError, IndexError, TypeError):
            sickrage.app.log.warning("Malformed air date of {} retrieved from {} for ({} - S{:02d}E{:02d})".format(
                firstaired, indexer_name, self.show.name, season or 0, episode or 0))

            # if I'm incomplete on the indexer but I once was complete then just delete myself from the DB for now
            object_session(self).rollback()
            object_session(self).safe_commit()
            self.delete_episode()
            return False

        # don't update show status if show dir is missing, unless it's missing on purpose
        if not os.path.isdir(self.show.location) and not sickrage.app.config.create_missing_show_dirs and not sickrage.app.config.add_shows_wo_dir:
            sickrage.app.log.info("The show dir %s is missing, not bothering to change the episode statuses since "
                                  "it'd probably be invalid" % self.show.location)
            return False

        if self.location:
            sickrage.app.log.debug("%s: Setting status for S%02dE%02d based on status %s and location %s" %
                                   (self.show.indexer_id, season or 0, episode or 0, statusStrings[self.status],
                                    self.location))

        if not os.path.isfile(self.location):
            if self.airdate >= datetime.date.today() or not self.airdate > datetime.date.min:
                sickrage.app.log.debug(
                    "Episode airs in the future or has no airdate, marking it %s" % statusStrings[
                        UNAIRED])
                self.status = UNAIRED
            elif self.status in [UNAIRED, UNKNOWN]:
                # Only do UNAIRED/UNKNOWN, it could already be snatched/ignored/skipped, or downloaded/archived to
                # disconnected media
                sickrage.app.log.debug(
                    "Episode has already aired, marking it %s" % statusStrings[self.show.default_ep_status])
                self.status = self.show.default_ep_status if self.season > 0 else SKIPPED  # auto-skip specials
            else:
                sickrage.app.log.debug(
                    "Not touching status [ %s ] It could be skipped/ignored/snatched/archived" % statusStrings[
                        self.status])

        # if we have a media file then it's downloaded
        elif is_media_file(self.location):
            # leave propers alone, you have to either post-process them or manually change them back
            if self.status not in Quality.SNATCHED_PROPER + Quality.DOWNLOADED + Quality.SNATCHED + Quality.ARCHIVED:
                sickrage.app.log.debug(
                    "5 Status changes from " + str(self.status) + " to " + str(
                        Quality.status_from_name(self.location)))
                self.status = Quality.status_from_name(self.location, anime=self.show.is_anime)

        # shouldn't get here probably
        else:
            sickrage.app.log.debug("6 Status changes from " + str(self.status) + " to " + str(UNKNOWN))
            self.status = UNKNOWN

        object_session(self).safe_commit()

        return True