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