def makeShowNFO(showID, showDir): logger.log(u"Making NFO for show "+str(showID)+" in dir "+showDir, logger.DEBUG) if not makeDir(showDir): logger.log(u"Unable to create show dir, can't make NFO", logger.ERROR) return False showObj = findCertainShow(sickbeard.showList, showID) if not showObj: logger.log(u"This should never have happened, post a bug about this!", logger.ERROR) raise Exception("BAD STUFF HAPPENED") tvdb_lang = showObj.lang # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) try: myShow = t[int(showID)] except tvdb_exceptions.tvdb_shownotfound: logger.log(u"Unable to find show with id " + str(showID) + " on tvdb, skipping it", logger.ERROR) raise except tvdb_exceptions.tvdb_error: logger.log(u"TVDB is down, can't use its data to add this show", logger.ERROR) raise # check for title and id try: if myShow["seriesname"] == None or myShow["seriesname"] == "" or myShow["id"] == None or myShow["id"] == "": logger.log(u"Incomplete info for show with id " + str(showID) + " on tvdb, skipping it", logger.ERROR) return False except tvdb_exceptions.tvdb_attributenotfound: logger.log(u"Incomplete info for show with id " + str(showID) + " on tvdb, skipping it", logger.ERROR) return False tvNode = buildNFOXML(myShow) # Make it purdy indentXML( tvNode ) nfo = etree.ElementTree( tvNode ) logger.log(u"Writing NFO to "+os.path.join(showDir, "tvshow.nfo"), logger.DEBUG) nfo_filename = os.path.join(showDir, "tvshow.nfo").encode('utf-8') nfo_fh = open(nfo_filename, 'w') nfo.write( nfo_fh, encoding="utf-8" ) return True
def getTVDBIDFromNFO(dir): if not ek.ek(os.path.isdir, dir): logger.log(u"Show dir doesn't exist, can't load NFO") raise exceptions.NoNFOException( "The show dir doesn't exist, no NFO could be loaded") logger.log(u"Loading show info from NFO") xmlFile = ek.ek(os.path.join, dir, "tvshow.nfo") try: xmlFileObj = ek.ek(open, xmlFile, 'r') showXML = etree.ElementTree(file=xmlFileObj) if showXML.findtext('title') == None or ( showXML.findtext('tvdbid') == None and showXML.findtext('id') == None): raise exceptions.NoNFOException("Invalid info in tvshow.nfo (missing name or id):" \ + str(showXML.findtext('title')) + " " \ + str(showXML.findtext('tvdbid')) + " " \ + str(showXML.findtext('id'))) if showXML.findtext('tvdbid') != None: tvdb_id = int(showXML.findtext('tvdbid')) elif showXML.findtext('id'): tvdb_id = int(showXML.findtext('id')) else: raise exceptions.NoNFOException( "Empty <id> or <tvdbid> field in NFO") try: t = tvdb_api.Tvdb(search_all_languages=True, **sickbeard.TVDB_API_PARMS) s = t[int(tvdb_id)] if not s or not s['seriesname']: raise exceptions.NoNFOException( "Show has no name on TVDB, probably the wrong language") except tvdb_exceptions.tvdb_exception, e: raise exceptions.NoNFOException( "Unable to look up the show on TVDB, not using the NFO") except (exceptions.NoNFOException, SyntaxError, ValueError), e: logger.log( u"There was an error parsing your existing tvshow.nfo file: " + ex(e), logger.ERROR) logger.log(u"Attempting to rename it to tvshow.nfo.old", logger.DEBUG) try: xmlFileObj.close() ek.ek(os.rename, xmlFile, xmlFile + ".old") except Exception, e: logger.log( u"Failed to rename your tvshow.nfo file - you need to delete it or fix it: " + ex(e), logger.ERROR)
def execute(self): ShowQueueItem.execute(self) logger.log(u"Starting to add show " + self.showDir) try: # make sure the tvdb ids are valid try: ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if self.lang: ltvdb_api_parms['language'] = self.lang logger.log(u"TVDB: " + repr(ltvdb_api_parms)) t = tvdb_api.Tvdb(**ltvdb_api_parms) s = t[self.tvdb_id] # this usually only happens if they have an NFO in their show dir which gave us a TVDB ID that has no # proper english version of the show if not s or not s['seriesname']: ui.notifications.error( "Unable to add show", "Show in " + self.showDir + " has no name on TVDB, probably the wrong language. Delete .nfo and add manually in the correct language." ) self._finishEarly() return except tvdb_exceptions.tvdb_exception, e: logger.log(u"Error contacting TVDB: " + str(e), logger.ERROR) ui.notifications.error( "Unable to add show", "Unable to look up the show in " + self.showDir + " on TVDB, not using the NFO. Delete .nfo and add manually in the correct language." ) self._finishEarly() return # clear the name cache name_cache.clearCache() newShow = TVShow(self.tvdb_id, self.lang) newShow.loadFromTVDB() self.show = newShow # set up initial values self.show.location = self.showDir self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT self.show.seasonfolders = self.season_folders if self.season_folders != None else sickbeard.SEASON_FOLDERS_DEFAULT self.show.paused = False # be smartish about this if self.show.genre and "talk show" in self.show.genre.lower(): self.show.air_by_date = 1
def get_show_by_name(name, showList, useTvdb=False): logger.log(u"Trying to get the tvdbid for " + name, logger.DEBUG) if showList: for show in showList: if _check_against_names(name, show): logger.log( u"Matched " + name + " in the showlist to the show " + show.name, logger.DEBUG) return show if useTvdb: try: t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **sickbeard.TVDB_API_PARMS) showObj = t[name] except (tvdb_exceptions.tvdb_exception): # if none found, search on all languages try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() ltvdb_api_parms['search_all_languages'] = True t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **ltvdb_api_parms) showObj = t[name] except (tvdb_exceptions.tvdb_exception, IOError): pass return None except (IOError): return None else: show = findCertainShow(sickbeard.showList, int(showObj["id"])) if show: return show return None
def checkSync(self, info=None): logger.log(u"Checking the last aired episode to see if the dates match between TVDB and TVRage") if self.lastEpInfo == None or self.nextEpInfo == None: self._saveLatestInfo(info) if self.nextEpInfo['season'] == 0 or self.nextEpInfo['episode'] == 0: return None try: airdate = None tvdb_lang = self.show.lang # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang # make sure the last TVDB episode matches our last episode try: t = tvdb_api.Tvdb(**ltvdb_api_parms) ep = t[self.show.tvdbid][self.lastEpInfo['season']][self.lastEpInfo['episode']] if ep["firstaired"] == "" or ep["firstaired"] == None: return None rawAirdate = [int(x) for x in ep["firstaired"].split("-")] airdate = datetime.date(rawAirdate[0], rawAirdate[1], rawAirdate[2]) except tvdb_exceptions.tvdb_exception, e: logger.log(u"Unable to check TVRage info against TVDB: "+ex(e)) logger.log(u"Trying against DB instead", logger.DEBUG) myDB = db.DBConnection() sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE showid = ? AND season = ? and episode = ?", [self.show.tvdbid, self.lastEpInfo['season'], self.lastEpInfo['episode']]) if len(sqlResults) == 0: raise exceptions.EpisodeNotFoundException("Unable to find episode in DB") else: airdate = datetime.date.fromordinal(int(sqlResults[0]["airdate"])) logger.log(u"Date from TVDB for episode " + str(self.lastEpInfo['season']) + "x" + str(self.lastEpInfo['episode']) + ": " + str(airdate), logger.DEBUG) logger.log(u"Date from TVRage for episode " + str(self.lastEpInfo['season']) + "x" + str(self.lastEpInfo['episode']) + ": " + str(self.lastEpInfo['airdate']), logger.DEBUG) if self.lastEpInfo['airdate'] == airdate: return True
def _retrieve_show_image(self, image_type, show_obj, which=None): """ Gets an image URL from theTVDB.com, downloads it and returns the data. image_type: type of image to retrieve (currently supported: poster, fanart) show_obj: a TVShow object to use when searching for the image which: optional, a specific numbered poster to look for Returns: the binary image data if available, or else None """ if sickbeard.USE_ANIDB_POSTERS and show_obj.anime and show_obj.anidb_picname and image_type in ( 'poster', 'poster_thumb'): image_url = "http://img7.anidb.net/pics/anime/" + show_obj.anidb_picname else: tvdb_lang = show_obj.lang try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(banners=True, **ltvdb_api_parms) tvdb_show_obj = t[show_obj.tvdbid] except (tvdb_exceptions.tvdb_error, IOError), e: logger.log( u"Unable to look up show on TVDB, not downloading images: " + ex(e), logger.ERROR) return None if image_type not in ('fanart', 'poster', 'banner', 'poster_thumb', 'banner_thumb'): logger.log( u"Invalid image type " + str(image_type) + ", couldn't find it in the TVDB object", logger.ERROR) return None try: if image_type == 'poster_thumb': image_url = re.sub('posters', '_cache/posters', tvdb_show_obj['poster']) elif image_type == 'banner_thumb': image_url = re.sub('graphical', '_cache/graphical', tvdb_show_obj['banner']) else: image_url = tvdb_show_obj[image_type] except: return None
def execute(self): ShowQueueItem.execute(self) logger.log(u"Starting to add show " + self.showDir) try: # make sure the tvdb ids are valid try: ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if self.lang: ltvdb_api_parms['language'] = self.lang t = tvdb_api.Tvdb(**ltvdb_api_parms) s = t[self.tvdb_id] if not s or not s['seriesname']: ui.flash.error( "Unable to add show", "Show in " + str(self.showDir) + " has no name on TVDB, probably the wrong language. Delete .nfo and add manually in the correct language." ) self._finishEarly() return except tvdb_exceptions.tvdb_exception, e: ui.flash.error( "Unable to add show", "Unable to look up the show in " + str(self.showDir) + " on TVDB, not using the NFO. Delete .nfo and add manually in the correct language." ) self._finishEarly() return newShow = TVShow(self.tvdb_id, self.lang) newShow.loadFromTVDB() self.show = newShow # set up initial values self.show.location = self.showDir self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT self.show.seasonfolders = self.season_folders if self.season_folders != None else sickbeard.SEASON_FOLDERS_DEFAULT self.show.paused = False
def _convertADB(self, show, adb_part): self._log( "Getting season and episodes for ADB episode: " + str(adb_part), logger.DEBUG) if not show: return (None, None) myDB = db.DBConnection() sql_results = myDB.select( "SELECT season, episode FROM tv_episodes WHERE showid = ? AND airdate = ?", [show.tvdbid, adb_part.toordinal()]) if len(sql_results) == 1: return (int(sql_results[0]["season"]), [int(sql_results[0]["episode"])]) if self.tvdbActiveLookUp: try: # There's gotta be a better way of doing this but we don't wanna # change the cache value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if show.lang: ltvdb_api_parms['language'] = self.lang t = tvdb_api.Tvdb(**ltvdb_api_parms) epObj = t[show.tvdbid].airedOn(adb_part)[0] season = int(epObj["seasonnumber"]) episodes = [int(epObj["episodenumber"])] except tvdb_exceptions.tvdb_episodenotfound: self._log( u"Unable to find episode with date " + str(episodes[0]) + " for show " + self.name_to_parse + ", skipping", logger.WARNING) return (None, None) except tvdb_exceptions.tvdb_error, e: self._log(u"Unable to contact TVDB: " + ex(e), logger.WARNING) return (None, None) else: return (season, episodes)
def _ep_data(self, ep_obj): """ Creates an elementTree XML structure for an XBMC-style episode.nfo and returns the resulting data object. show_obj: a TVEpisode instance to create the NFO for """ eps_to_write = [ep_obj] + ep_obj.relatedEps tvdb_lang = ep_obj.show.lang # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang try: t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) myShow = t[ep_obj.show.tvdbid] except tvdb_exceptions.tvdb_shownotfound, e: raise exceptions.ShowNotFoundException(e.message)
def _ep_data(self, ep_obj): """ Creates a key value structure for a Tivo episode metadata file and returns the resulting data object. ep_obj: a TVEpisode instance to create the metadata file for. Lookup the show in http://thetvdb.com/ using the python library: https://github.com/dbr/tvdb_api/ The results are saved in the object myShow. The key values for the tivo metadata file are from: http://pytivo.sourceforge.net/wiki/index.php/Metadata """ data = "" eps_to_write = [ep_obj] + ep_obj.relatedEps tvdb_lang = ep_obj.show.lang try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang if ep_obj.show.dvdorder != 0: ltvdb_api_parms['dvdorder'] = True t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) myShow = t[ep_obj.show.tvdbid] except tvdb_exceptions.tvdb_shownotfound, e: raise exceptions.ShowNotFoundException(str(e))
def _get_episode_thumb_url(self, ep_obj): """ Returns the URL to use for downloading an episode's thumbnail. Uses theTVDB.com data. ep_obj: a TVEpisode object for which to grab the thumb URL """ all_eps = [ep_obj] + ep_obj.relatedEps tvdb_lang = ep_obj.show.lang # get a TVDB object try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) tvdb_show_obj = t[ep_obj.show.tvdbid] except tvdb_exceptions.tvdb_shownotfound, e: raise exceptions.ShowNotFoundException(e.message)
def _find_info(self): """ For a given file try to find the showid, season, and episode. """ tvdb_id = season = None episodes = [] # try to look up the nzb in history attempt_list = [ self._history_lookup, # try to analyze the nzb name lambda: self._analyze_name(self.nzb_name), # try to analyze the file name lambda: self._analyze_name(self.file_name), # try to analyze the dir name lambda: self._analyze_name(self.folder_name), # try to analyze the file+dir names together lambda: self._analyze_name(self.file_path), # try to analyze the dir + file name together as one name lambda: self._analyze_name(self.folder_name + u' ' + self.file_name ) ] # attempt every possible method to get our info for cur_attempt in attempt_list: try: (cur_tvdb_id, cur_season, cur_episodes) = cur_attempt() except InvalidNameException, e: logger.log(u"Unable to parse, skipping: " + ex(e), logger.DEBUG) continue # if we already did a successful history lookup then keep that tvdb_id value if cur_tvdb_id and not (self.in_history and tvdb_id): tvdb_id = cur_tvdb_id if cur_season != None: season = cur_season if cur_episodes: episodes = cur_episodes # for air-by-date shows we need to look up the season/episode from tvdb if season == -1 and tvdb_id and episodes: self._log( u"Looks like this is an air-by-date show, attempting to convert the date to season/episode", logger.DEBUG) # try to get language set for this show tvdb_lang = None try: showObj = helpers.findCertainShow(sickbeard.showList, tvdb_id) if (showObj != None): tvdb_lang = showObj.lang except exceptions.MultipleShowObjectsException: raise #TODO: later I'll just log this, for now I want to know about it ASAP try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(**ltvdb_api_parms) epObj = t[tvdb_id].airedOn(episodes[0])[0] season = int(epObj["seasonnumber"]) episodes = [int(epObj["episodenumber"])] self._log( u"Got season " + str(season) + " episodes " + str(episodes), logger.DEBUG) except tvdb_exceptions.tvdb_episodenotfound, e: self._log( u"Unable to find episode with date " + str(episodes[0]) + u" for show " + str(tvdb_id) + u", skipping", logger.DEBUG) # we don't want to leave dates in the episode list if we couldn't convert them to real episode numbers episodes = [] continue except tvdb_exceptions.tvdb_error, e: logger.log(u"Unable to contact TVDB: " + ex(e), logger.WARNING) episodes = [] continue
def _show_data(self, show_obj): """ Creates an elementTree XML structure for a MediaBrowser-style series.xml returns the resulting data object. show_obj: a TVShow instance to create the NFO for """ tvdb_lang = show_obj.lang # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) tv_node = etree.Element("Series") try: myShow = t[int(show_obj.tvdbid)] except tvdb_exceptions.tvdb_shownotfound: logger.log( u"Unable to find show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) raise except tvdb_exceptions.tvdb_error: logger.log(u"TVDB is down, can't use its data to make the NFO", logger.ERROR) raise # check for title and id try: if myShow['seriesname'] == None or myShow[ 'seriesname'] == "" or myShow['id'] == None or myShow[ 'id'] == "": logger.log( u"Incomplete info for show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) return False except tvdb_exceptions.tvdb_attributenotfound: logger.log( u"Incomplete info for show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) return False tvdbid = etree.SubElement(tv_node, "id") if myShow['id'] != None: tvdbid.text = myShow['id'] SeriesName = etree.SubElement(tv_node, "SeriesName") if myShow['seriesname'] != None: SeriesName.text = myShow['seriesname'] Status = etree.SubElement(tv_node, "Status") if myShow['status'] != None: Status.text = myShow['status'] Network = etree.SubElement(tv_node, "Network") if myShow['network'] != None: Network.text = myShow['network'] Airs_Time = etree.SubElement(tv_node, "Airs_Time") if myShow['airs_time'] != None: Airs_Time.text = myShow['airs_time'] Airs_DayOfWeek = etree.SubElement(tv_node, "Airs_DayOfWeek") if myShow['airs_dayofweek'] != None: Airs_DayOfWeek.text = myShow['airs_dayofweek'] FirstAired = etree.SubElement(tv_node, "FirstAired") if myShow['firstaired'] != None: FirstAired.text = myShow['firstaired'] ContentRating = etree.SubElement(tv_node, "ContentRating") MPAARating = etree.SubElement(tv_node, "MPAARating") certification = etree.SubElement(tv_node, "certification") if myShow['contentrating'] != None: ContentRating.text = myShow['contentrating'] MPAARating.text = myShow['contentrating'] certification.text = myShow['contentrating'] MetadataType = etree.SubElement(tv_node, "Type") MetadataType.text = "Series" Overview = etree.SubElement(tv_node, "Overview") if myShow['overview'] != None: Overview.text = myShow['overview'] PremiereDate = etree.SubElement(tv_node, "PremiereDate") if myShow['firstaired'] != None: PremiereDate.text = myShow['firstaired'] Rating = etree.SubElement(tv_node, "Rating") if myShow['rating'] != None: Rating.text = myShow['rating'] ProductionYear = etree.SubElement(tv_node, "ProductionYear") if myShow['firstaired'] != None: try: year_text = str( datetime.datetime.strptime(myShow['firstaired'], '%Y-%m-%d').year) if year_text: ProductionYear.text = year_text except: pass RunningTime = etree.SubElement(tv_node, "RunningTime") Runtime = etree.SubElement(tv_node, "Runtime") if myShow['runtime'] != None: RunningTime.text = myShow['runtime'] Runtime.text = myShow['runtime'] IMDB_ID = etree.SubElement(tv_node, "IMDB_ID") IMDB = etree.SubElement(tv_node, "IMDB") IMDbId = etree.SubElement(tv_node, "IMDbId") if myShow['imdb_id'] != None: IMDB_ID.text = myShow['imdb_id'] IMDB.text = myShow['imdb_id'] IMDbId.text = myShow['imdb_id'] Zap2ItId = etree.SubElement(tv_node, "Zap2ItId") if myShow['zap2it_id'] != None: Zap2ItId.text = myShow['zap2it_id'] Genres = etree.SubElement(tv_node, "Genres") if myShow["genre"] != None: for genre in myShow['genre'].split('|'): if genre and genre.strip(): cur_genre = etree.SubElement(Genres, "Genre") cur_genre.text = genre.strip() Genre = etree.SubElement(tv_node, "Genre") if myShow["genre"] != None: Genre.text = "|".join([ x.strip() for x in myShow["genre"].split('|') if x and x.strip() ]) Studios = etree.SubElement(tv_node, "Studios") Studio = etree.SubElement(Studios, "Studio") if myShow["network"] != None: Studio.text = myShow['network'] Persons = etree.SubElement(tv_node, "Persons") if myShow["_actors"] != None: for actor in myShow["_actors"]: cur_actor_name_text = actor['name'] if cur_actor_name_text != None and cur_actor_name_text.strip(): cur_actor = etree.SubElement(Persons, "Person") cur_actor_name = etree.SubElement(cur_actor, "Name") cur_actor_name.text = cur_actor_name_text.strip() cur_actor_type = etree.SubElement(cur_actor, "Type") cur_actor_type.text = "Actor" 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 helpers.indentXML(tv_node) data = etree.ElementTree(tv_node) return data
def _analyze_name(self, name, file=True): """ Takes a name and tries to figure out a show, season, and episode from it. name: A string which we want to analyze to determine show info from (unicode) Returns a (tvdb_id, season, [episodes]) tuple. The first two may be None and episodes may be [] if none were found. """ logger.log(u"Analyzing name " + repr(name)) to_return = (None, None, []) if not name: return to_return # parse the name to break it into show name, season, and episode np = NameParser(file) parse_result = np.parse(name) self._log( "Parsed " + name + " into " + str(parse_result).decode('utf-8'), logger.DEBUG) if parse_result.air_by_date: season = -1 episodes = [parse_result.air_date] else: season = parse_result.season_number episodes = parse_result.episode_numbers to_return = (None, season, episodes) # do a scene reverse-lookup to get a list of all possible names name_list = show_name_helpers.sceneToNormalShowNames( parse_result.series_name) if not name_list: return (None, season, episodes) def _finalize(parse_result): self.release_group = parse_result.release_group # remember whether it's a proper if parse_result.extra_info: self.is_proper = re.search( '(^|[\. _-])(proper|repack)([\. _-]|$)', parse_result.extra_info, re.I) != None # if the result is complete then remember that for later if parse_result.series_name and parse_result.season_number != None and parse_result.episode_numbers and parse_result.release_group: test_name = os.path.basename(name) if test_name == self.nzb_name: self.good_results[self.NZB_NAME] = True elif test_name == self.folder_name: self.good_results[self.FOLDER_NAME] = True elif test_name == self.file_name: self.good_results[self.FILE_NAME] = True else: logger.log(u"Nothing was good, found " + repr(test_name) + " and wanted either " + repr(self.nzb_name) + ", " + repr(self.folder_name) + ", or " + repr(self.file_name)) else: logger.log( "Parse result not suficent(all folowing have to be set). will not save release name", logger.DEBUG) logger.log( "Parse result(series_name): " + str(parse_result.series_name), logger.DEBUG) logger.log( "Parse result(season_number): " + str(parse_result.season_number), logger.DEBUG) logger.log( "Parse result(episode_numbers): " + str(parse_result.episode_numbers), logger.DEBUG) logger.log( "Parse result(release_group): " + str(parse_result.release_group), logger.DEBUG) # for each possible interpretation of that scene name for cur_name in name_list: self._log(u"Checking scene exceptions for a match on " + cur_name, logger.DEBUG) scene_id = scene_exceptions.get_scene_exception_by_name(cur_name) if scene_id: self._log( u"Scene exception lookup got tvdb id " + str(scene_id) + u", using that", logger.DEBUG) _finalize(parse_result) return (scene_id, season, episodes) # see if we can find the name directly in the DB, if so use it for cur_name in name_list: self._log(u"Looking up " + cur_name + u" in the DB", logger.DEBUG) db_result = helpers.searchDBForShow(cur_name) if db_result: self._log( u"Lookup successful, using tvdb id " + str(db_result[0]), logger.DEBUG) _finalize(parse_result) return (int(db_result[0]), season, episodes) # see if we can find the name with a TVDB lookup for cur_name in name_list: try: t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **sickbeard.TVDB_API_PARMS) self._log(u"Looking up name " + cur_name + u" on TVDB", logger.DEBUG) showObj = t[cur_name] except (tvdb_exceptions.tvdb_exception): # if none found, search on all languages try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() ltvdb_api_parms['search_all_languages'] = True t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **ltvdb_api_parms) self._log( u"Looking up name " + cur_name + u" in all languages on TVDB", logger.DEBUG) showObj = t[cur_name] except (tvdb_exceptions.tvdb_exception, IOError): pass continue except (IOError): continue self._log( u"Lookup successful, using tvdb id " + str(showObj["id"]), logger.DEBUG) _finalize(parse_result) return (int(showObj["id"]), season, episodes) _finalize(parse_result) return to_return
def confirmShow(self, force=False): if self.show.tvrid != 0 and not force: logger.log(u"We already have a TVRage ID, skipping confirmation", logger.DEBUG) return True logger.log( u"Checking the first episode of each season to see if the air dates match between TVDB and TVRage" ) tvdb_lang = self.show.lang try: try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(**ltvdb_api_parms) except tvdb_exceptions.tvdb_exception, e: logger.log( u"Currently this doesn't work with TVDB down but with some DB magic it can be added", logger.DEBUG) return None # check the first episode of every season for curSeason in t[self.show.tvdbid]: logger.log( u"Checking TVDB and TVRage sync for season " + str(curSeason), logger.DEBUG) airdate = None try: # don't do specials and don't do seasons with no episode 1 if curSeason == 0 or 1 not in t[self.show.tvdbid]: continue # get the episode info from TVDB ep = t[self.show.tvdbid][curSeason][1] # make sure we have a date to compare with if ep["firstaired"] == "" or ep["firstaired"] == None or ep[ "firstaired"] == "0000-00-00": continue # get a datetime object rawAirdate = [int(x) for x in ep["firstaired"].split("-")] airdate = datetime.date(rawAirdate[0], rawAirdate[1], rawAirdate[2]) # get the episode info from TVRage info = self._getTVRageInfo(curSeason, 1) # make sure we have enough info if info == None or not info.has_key('Episode Info'): logger.log( u"TVRage doesn't have the episode info, skipping it", logger.DEBUG) continue # parse the episode info curEpInfo = self._getEpInfo(info['Episode Info']) # make sure we got some info back if curEpInfo == None: continue # if we couldn't compare with TVDB try comparing it with the local database except tvdb_exceptions.tvdb_exception, e: logger.log(u"Unable to check TVRage info against TVDB: " + ex(e)) logger.log(u"Trying against DB instead", logger.DEBUG) myDB = db.DBConnection() sqlResults = myDB.select( "SELECT * FROM tv_episodes WHERE showid = ? AND season = ? and episode = ?", [ self.show.tvdbid, self.lastEpInfo['season'], self.lastEpInfo['episode'] ]) if len(sqlResults) == 0: raise exceptions.EpisodeNotFoundException( "Unable to find episode in DB") else: airdate = datetime.date.fromordinal( int(sqlResults[0]["airdate"])) # check if TVRage and TVDB have the same airdate for this episode if curEpInfo['airdate'] == airdate: logger.log( u"Successful match for TVRage and TVDB data for episode " + str(curSeason) + "x1)", logger.DEBUG) return True logger.log( u"Date from TVDB for episode " + str(curSeason) + "x1: " + str(airdate), logger.DEBUG) logger.log( u"Date from TVRage for episode " + str(curSeason) + "x1: " + str(curEpInfo['airdate']), logger.DEBUG)
class ProperFinder(): def __init__(self): self.updateInterval = datetime.timedelta(hours=1) def run(self): if not sickbeard.DOWNLOAD_PROPERS: return # look for propers every night at 1 AM updateTime = datetime.time(hour=1) logger.log(u"Checking proper time", logger.DEBUG) hourDiff = datetime.datetime.today().time().hour - updateTime.hour # if it's less than an interval after the update time then do an update if hourDiff >= 0 and hourDiff < self.updateInterval.seconds / 3600: logger.log(u"Beginning the search for new propers") else: return propers = self._getProperList() self._downloadPropers(propers) def _getProperList(self): propers = {} # for each provider get a list of the propers for curProvider in providers.sortedProviderList(): if not curProvider.isActive(): continue search_date = datetime.datetime.today() - datetime.timedelta( days=2) logger.log(u"Searching for any new PROPER releases from " + curProvider.name) try: curPropers = curProvider.findPropers(search_date) except exceptions.AuthException, e: logger.log(u"Authentication error: " + ex(e), logger.ERROR) continue # if they haven't been added by a different provider than add the proper to the list for x in curPropers: name = self._genericName(x.name) if not name in propers: logger.log(u"Found new proper: " + x.name, logger.DEBUG) x.provider = curProvider propers[name] = x # take the list of unique propers and get it sorted by sortedPropers = sorted(propers.values(), key=operator.attrgetter('date'), reverse=True) finalPropers = [] for curProper in sortedPropers: # parse the file name try: myParser = NameParser(False) parse_result = myParser.parse(curProper.name) except InvalidNameException: logger.log( u"Unable to parse the filename " + curProper.name + " into a valid episode", logger.DEBUG) continue if not parse_result.episode_numbers: logger.log( u"Ignoring " + curProper.name + " because it's for a full season rather than specific episode", logger.DEBUG) continue # populate our Proper instance if parse_result.air_by_date: curProper.season = -1 curProper.episode = parse_result.air_date else: curProper.season = parse_result.season_number if parse_result.season_number != None else 1 curProper.episode = parse_result.episode_numbers[0] curProper.quality = Quality.nameQuality(curProper.name) # for each show in our list for curShow in sickbeard.showList: if not parse_result.series_name: continue genericName = self._genericName(parse_result.series_name) # get the scene name masks sceneNames = set( show_name_helpers.makeSceneShowSearchStrings(curShow)) # for each scene name mask for curSceneName in sceneNames: # if it matches if genericName == self._genericName(curSceneName): logger.log( u"Successful match! Result " + parse_result.series_name + " matched to show " + curShow.name, logger.DEBUG) # set the tvdbid in the db to the show's tvdbid curProper.tvdbid = curShow.tvdbid # since we found it, break out break # if we found something in the inner for loop break out of this one if curProper.tvdbid != -1: break if curProper.tvdbid == -1: continue if not show_name_helpers.filterBadReleases(curProper.name): logger.log( u"Proper " + curProper.name + " isn't a valid scene release that we want, igoring it", logger.DEBUG) continue # if we have an air-by-date show then get the real season/episode numbers if curProper.season == -1 and curProper.tvdbid: showObj = helpers.findCertainShow(sickbeard.showList, curProper.tvdbid) if not showObj: logger.log( u"This should never have happened, post a bug about this!", logger.ERROR) raise Exception("BAD STUFF HAPPENED") tvdb_lang = showObj.lang # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang try: t = tvdb_api.Tvdb(**ltvdb_api_parms) epObj = t[curProper.tvdbid].airedOn(curProper.episode)[0] curProper.season = int(epObj["seasonnumber"]) curProper.episodes = [int(epObj["episodenumber"])] except tvdb_exceptions.tvdb_episodenotfound: logger.log( u"Unable to find episode with date " + str(curProper.episode) + " for show " + parse_result.series_name + ", skipping", logger.WARNING) continue # check if we actually want this proper (if it's the right quality) sqlResults = db.DBConnection().select( "SELECT status FROM tv_episodes WHERE showid = ? AND season = ? AND episode = ?", [curProper.tvdbid, curProper.season, curProper.episode]) if not sqlResults: continue oldStatus, oldQuality = Quality.splitCompositeStatus( int(sqlResults[0]["status"])) # only keep the proper if we have already retrieved the same quality ep (don't get better/worse ones) if oldStatus not in (DOWNLOADED, SNATCHED) or oldQuality != curProper.quality: continue # if the show is in our list and there hasn't been a proper already added for that particular episode then add it to our list of propers if curProper.tvdbid != -1 and (curProper.tvdbid, curProper.season, curProper.episode) not in map( operator.attrgetter( 'tvdbid', 'season', 'episode'), finalPropers): logger.log(u"Found a proper that we need: " + str(curProper.name)) finalPropers.append(curProper) return finalPropers
def _analyze_name(self, name, file=True): """ Takes a name and tries to figure out a show, season, and episode from it. Returns a (tvdb_id, season, [episodes]) tuple. The first two may be None and episodes may be [] if none were found. """ logger.log(u"Analyzing name " + repr(name)) to_return = (None, None, []) if not name: return to_return # parse the name to break it into show name, season, and episode np = NameParser(file) parse_result = np.parse(name) self._log( "Parsed " + name + " into " + str(parse_result).decode('utf-8'), logger.DEBUG) if parse_result.air_by_date: season = -1 episodes = [parse_result.air_date] else: season = parse_result.season_number episodes = parse_result.episode_numbers to_return = (None, season, episodes) # do a scene reverse-lookup to get a list of all possible names name_list = sceneHelpers.sceneToNormalShowNames( parse_result.series_name) if not name_list: return (None, season, episodes) def _finalize(parse_result): self.release_group = parse_result.release_group if parse_result.extra_info: self.is_proper = re.search( '(^|[\. _-])(proper|repack)([\. _-]|$)', parse_result.extra_info, re.I) != None # for each possible interpretation of that scene name for cur_name in name_list: self._log(u"Checking scene exceptions for a match on " + cur_name, logger.DEBUG) for exceptionID in common.sceneExceptions: # for each exception name for curException in common.sceneExceptions[exceptionID]: if cur_name.lower() in (curException.lower(), sceneHelpers.sanitizeSceneName( curException).lower().replace( '.', ' ')): self._log( u"Scene exception lookup got tvdb id " + str(exceptionID) + u", using that", logger.DEBUG) _finalize(parse_result) return (exceptionID, season, episodes) # see if we can find the name directly in the DB, if so use it for cur_name in name_list: self._log(u"Looking up " + cur_name + u" in the DB", logger.DEBUG) db_result = helpers.searchDBForShow(cur_name) if db_result: self._log( u"Lookup successful, using tvdb id " + str(db_result[0]), logger.DEBUG) _finalize(parse_result) return (int(db_result[0]), season, episodes) # see if we can find the name with a TVDB lookup for cur_name in name_list: try: t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **sickbeard.TVDB_API_PARMS) self._log(u"Looking up name " + cur_name + u" on TVDB", logger.DEBUG) showObj = t[cur_name] except (tvdb_exceptions.tvdb_exception), e: # if none found, search on all languages try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() ltvdb_api_parms['search_all_languages'] = True t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **ltvdb_api_parms) self._log( u"Looking up name " + cur_name + u" in all languages on TVDB", logger.DEBUG) showObj = t[cur_name] except (tvdb_exceptions.tvdb_exception, IOError), e: pass continue
def _addCacheEntry(self, name, url, season=None, episodes=None, tvdb_id=0, tvrage_id=0, quality=None, extraNames=[]): myDB = self._getDB() parse_result = None # if we don't have complete info then parse the filename to get it for curName in [name] + extraNames: try: myParser = NameParser() parse_result = myParser.parse(curName) except InvalidNameException: logger.log( u"Unable to parse the filename " + curName + " into a valid episode", logger.DEBUG) continue if not parse_result: logger.log( u"Giving up because I'm unable to parse this name: " + name, logger.DEBUG) return False if not parse_result.series_name: logger.log( u"No series name retrieved from " + name + ", unable to cache it", logger.DEBUG) return False tvdb_lang = None # if we need tvdb_id or tvrage_id then search the DB for them if not tvdb_id or not tvrage_id: # if we have only the tvdb_id, use the database if tvdb_id: showObj = helpers.findCertainShow(sickbeard.showList, tvdb_id) if showObj: tvrage_id = showObj.tvrid tvdb_lang = showObj.lang else: logger.log( u"We were given a TVDB id " + str(tvdb_id) + " but it doesn't match a show we have in our list, so leaving tvrage_id empty", logger.DEBUG) tvrage_id = 0 # if we have only a tvrage_id then use the database elif tvrage_id: showObj = helpers.findCertainTVRageShow( sickbeard.showList, tvrage_id) if showObj: tvdb_id = showObj.tvdbid tvdb_lang = showObj.lang else: logger.log( u"We were given a TVRage id " + str(tvrage_id) + " but it doesn't match a show we have in our list, so leaving tvdb_id empty", logger.DEBUG) tvdb_id = 0 # if they're both empty then fill out as much info as possible by searching the show name else: # check the name cache and see if we already know what show this is logger.log( u"Checking the cache to see if we already know the tvdb id of " + parse_result.series_name, logger.DEBUG) tvdb_id = name_cache.retrieveNameFromCache( parse_result.series_name) # remember if the cache lookup worked or not so we know whether we should bother updating it later if tvdb_id == None: logger.log( u"No cache results returned, continuing on with the search", logger.DEBUG) from_cache = False else: logger.log( u"Cache lookup found " + repr(tvdb_id) + ", using that", logger.DEBUG) from_cache = True # if the cache failed, try looking up the show name in the database if tvdb_id == None: logger.log( u"Trying to look the show up in the show database", logger.DEBUG) showResult = helpers.searchDBForShow( parse_result.series_name) if showResult: logger.log( parse_result.series_name + " was found to be show " + showResult[1] + " (" + str(showResult[0]) + ") in our DB.", logger.DEBUG) tvdb_id = showResult[0] # if the DB lookup fails then do a comprehensive regex search if tvdb_id == None: logger.log( u"Couldn't figure out a show name straight from the DB, trying a regex search instead", logger.DEBUG) for curShow in sickbeard.showList: if show_name_helpers.isGoodResult( name, curShow, False): logger.log( u"Successfully matched " + name + " to " + curShow.name + " with regex", logger.DEBUG) tvdb_id = curShow.tvdbid tvdb_lang = curShow.lang break # if tvdb_id was anything but None (0 or a number) then if not from_cache: name_cache.addNameToCache(parse_result.series_name, tvdb_id) # if we came out with tvdb_id = None it means we couldn't figure it out at all, just use 0 for that if tvdb_id == None: tvdb_id = 0 # if we found the show then retrieve the show object if tvdb_id: showObj = helpers.findCertainShow(sickbeard.showList, tvdb_id) if showObj: tvrage_id = showObj.tvrid tvdb_lang = showObj.lang # if we weren't provided with season/episode information then get it from the name that we parsed if not season: season = parse_result.season_number if parse_result.season_number != None else 1 if not episodes: episodes = parse_result.episode_numbers # if we have an air-by-date show then get the real season/episode numbers if parse_result.air_by_date and tvdb_id: try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if not (tvdb_lang == "" or tvdb_lang == "en" or tvdb_lang == None): ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(**ltvdb_api_parms) epObj = t[tvdb_id].airedOn(parse_result.air_date)[0] season = int(epObj["seasonnumber"]) episodes = [int(epObj["episodenumber"])] except tvdb_exceptions.tvdb_episodenotfound: logger.log( u"Unable to find episode with date " + str(parse_result.air_date) + " for show " + parse_result.series_name + ", skipping", logger.WARNING) return False except tvdb_exceptions.tvdb_error, e: logger.log(u"Unable to contact TVDB: " + ex(e), logger.WARNING) return False
def series_name_to_tvdb_id(cls, series_name, check_scene_exceptions=True, check_database=True, check_tvdb=False): """ Given a series name, return it's tvdbd_id. Returns None if not found. This is mostly robbed from postProcessor._analyze_name """ # do a scene reverse-lookup to get a list of all possible names name_list = sickbeard.show_name_helpers.sceneToNormalShowNames( series_name) # for each possible interpretation of that scene name if check_scene_exceptions: for cur_name in name_list: logger.log( u"Checking scene exceptions for a match on " + cur_name, logger.DEBUG) scene_id = sickbeard.scene_exceptions.get_scene_exception_by_name( cur_name) if scene_id: return scene_id # see if we can find the name directly in the DB, if so use it if check_database: for cur_name in name_list: logger.log(u"Looking up " + cur_name + u" in the DB", logger.DEBUG) db_result = sickbeard.helpers.searchDBForShow(cur_name) if db_result: return db_result[0] # see if we can find the name with a TVDB lookup if check_tvdb: for cur_name in name_list: try: t = tvdb_api.Tvdb(custom_ui=sickbeard.classes.ShowListUI, **sickbeard.TVDB_API_PARMS) logger.log(u"Looking up name " + cur_name + u" on TVDB", logger.DEBUG) showObj = t[cur_name] except (tvdb_exceptions.tvdb_exception): # if none found, search on all languages try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() ltvdb_api_parms['search_all_languages'] = True t = tvdb_api.Tvdb( custom_ui=sickbeard.classes.ShowListUI, **ltvdb_api_parms) logger.log( u"Looking up name " + cur_name + u" in all languages on TVDB", logger.DEBUG) showObj = t[cur_name] except (tvdb_exceptions.tvdb_exception, IOError): pass continue except (IOError): continue return showObj["id"] return None
def test_tvdb_api(self): tvdb = tvdb_api.Tvdb() for (fileName, serie_name, season, episode_numbers) in TVShows: serie_info = tvdb[serie_name] season_info = tvdb[serie_name][season] episode_info = tvdb[serie_name][season][episode_numbers[0]]
def _show_data(self, show_obj): """ Creates an elementTree XML structure for a MediaBrowser-style series.xml returns the resulting data object. show_obj: a TVShow instance to create the NFO for """ tvdb_lang = show_obj.lang # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) rootNode = etree.Element("details") tv_node = etree.SubElement(rootNode, "movie") tv_node.attrib["isExtra"] = "false" tv_node.attrib["isSet"] = "false" tv_node.attrib["isTV"] = "true" try: myShow = t[int(show_obj.tvdbid)] except tvdb_exceptions.tvdb_shownotfound: logger.log(u"Unable to find show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) raise except tvdb_exceptions.tvdb_error: logger.log(u"TVDB is down, can't use its data to make the NFO", logger.ERROR) raise # check for title and id try: if myShow['seriesname'] == None or myShow['seriesname'] == "" or myShow['id'] == None or myShow['id'] == "": logger.log(u"Incomplete info for show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) return False except tvdb_exceptions.tvdb_attributenotfound: logger.log(u"Incomplete info for show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) return False SeriesName = etree.SubElement(tv_node, "title") if myShow['seriesname'] != None: SeriesName.text = myShow['seriesname'] else: SeriesName.text = "" Genres = etree.SubElement(tv_node, "genres") if myShow["genre"] != None: for genre in myShow['genre'].split('|'): if genre and genre.strip(): cur_genre = etree.SubElement(Genres, "Genre") cur_genre.text = genre.strip() FirstAired = etree.SubElement(tv_node, "premiered") if myShow['firstaired'] != None: FirstAired.text = myShow['firstaired'] year = etree.SubElement(tv_node, "year") if myShow["firstaired"] != None: try: year_text = str(datetime.datetime.strptime(myShow["firstaired"], '%Y-%m-%d').year) if year_text: year.text = year_text except: pass if myShow['rating'] != None: try: rating = int((float(myShow['rating']) * 10)) except ValueError: rating = 0 Rating = etree.SubElement(tv_node, "rating") rating_text = str(rating) if rating_text != None: Rating.text = rating_text Status = etree.SubElement(tv_node, "status") if myShow['status'] != None: Status.text = myShow['status'] mpaa = etree.SubElement(tv_node, "mpaa") if myShow["contentrating"] != None: mpaa.text = myShow["contentrating"] IMDB_ID = etree.SubElement(tv_node, "id") if myShow['imdb_id'] != None: IMDB_ID.attrib["moviedb"] = "imdb" IMDB_ID.text = myShow['imdb_id'] tvdbid = etree.SubElement(tv_node, "tvdbid") if myShow['id'] != None: tvdbid.text = myShow['id'] Runtime = etree.SubElement(tv_node, "runtime") if myShow['runtime'] != None: Runtime.text = myShow['runtime'] cast = etree.SubElement(tv_node, "cast") if myShow["_actors"] != None: for actor in myShow['_actors']: cur_actor_name_text = actor['name'] if cur_actor_name_text != None and cur_actor_name_text.strip(): cur_actor = etree.SubElement(cast, "actor") cur_actor.text = cur_actor_name_text.strip() helpers.indentXML(rootNode) data = etree.ElementTree(rootNode) return data
def _show_data(self, show_obj): """ Creates an elementTree XML structure for an XBMC-style tvshow.nfo and returns the resulting data object. show_obj: a TVShow instance to create the NFO for """ show_ID = show_obj.tvdbid tvdb_lang = show_obj.lang # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) tv_node = etree.Element("tvshow") try: myShow = t[int(show_ID)] except tvdb_exceptions.tvdb_shownotfound: logger.log( u"Unable to find show with id " + str(show_ID) + " on tvdb, skipping it", logger.ERROR) raise except tvdb_exceptions.tvdb_error: logger.log(u"TVDB is down, can't use its data to add this show", logger.ERROR) raise # check for title and id try: if myShow["seriesname"] == None or myShow[ "seriesname"] == "" or myShow["id"] == None or myShow[ "id"] == "": logger.log( u"Incomplete info for show with id " + str(show_ID) + " on tvdb, skipping it", logger.ERROR) return False except tvdb_exceptions.tvdb_attributenotfound: logger.log( u"Incomplete info for show with id " + str(show_ID) + " on tvdb, skipping it", logger.ERROR) return False title = etree.SubElement(tv_node, "title") if myShow["seriesname"] != None: title.text = myShow["seriesname"] rating = etree.SubElement(tv_node, "rating") if myShow["rating"] != None: rating.text = myShow["rating"] year = etree.SubElement(tv_node, "year") if myShow["firstaired"] != None: try: year_text = str( datetime.datetime.strptime(myShow["firstaired"], '%Y-%m-%d').year) if year_text: year.text = year_text except: pass plot = etree.SubElement(tv_node, "plot") if myShow["overview"] != None: plot.text = myShow["overview"] episodeguide = etree.SubElement(tv_node, "episodeguide") episodeguideurl = etree.SubElement(episodeguide, "url") episodeguideurl2 = etree.SubElement(tv_node, "episodeguideurl") if myShow["id"] != None: showurl = sickbeard.TVDB_BASE_URL + '/series/' + myShow[ "id"] + '/all/en.zip' episodeguideurl.text = showurl episodeguideurl2.text = showurl mpaa = etree.SubElement(tv_node, "mpaa") if myShow["contentrating"] != None: mpaa.text = myShow["contentrating"] tvdbid = etree.SubElement(tv_node, "id") if myShow["id"] != None: tvdbid.text = myShow["id"] genre = etree.SubElement(tv_node, "genre") if myShow["genre"] != None: genre.text = " / ".join([ x.strip() for x in myShow["genre"].split('|') if x and x.strip() ]) premiered = etree.SubElement(tv_node, "premiered") if myShow["firstaired"] != None: premiered.text = myShow["firstaired"] studio = etree.SubElement(tv_node, "studio") if myShow["network"] != None: studio.text = myShow["network"] if myShow["_actors"] != None: for actor in myShow["_actors"]: cur_actor_name_text = actor['name'] if cur_actor_name_text != None and cur_actor_name_text.strip(): cur_actor = etree.SubElement(tv_node, "actor") cur_actor_name = etree.SubElement(cur_actor, "name") cur_actor_name.text = cur_actor_name_text.strip() 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 # Make it purdy helpers.indentXML(tv_node) data = etree.ElementTree(tv_node) return data
def _analyze_name(self, name, file=True): """ Takes a name and tries to figure out a show, season, and episode from it. name: A string which we want to analyze to determine show info from (unicode) Returns a (tvdb_id, season, [episodes]) tuple. The first two may be None and episodes may be [] if none were found. """ logger.log(u"Analyzing name " + repr(name)) to_return = (None, None, []) if not name: return to_return trimprefix = [ '^sof-', '^euhd-', '^amb-', '^itg-', '^idtv-', '^zzgtv-', '^itn-', '^tcpa-', '^tvp-' ] for regex in trimprefix: name = re.sub(regex, "", name) # parse the name to break it into show name, season, and episode np = NameParser(file) parse_result = np.parse(name) self._log( "Parsed " + name + " into " + str(parse_result).decode('utf-8'), logger.DEBUG) if parse_result.air_by_date: season = -1 episodes = [parse_result.air_date] else: season = parse_result.season_number episodes = parse_result.episode_numbers to_return = (None, season, episodes) # do a scene reverse-lookup to get a list of all possible names name_list = show_name_helpers.sceneToNormalShowNames( parse_result.series_name) if not name_list: return (None, season, episodes) def _finalize(parse_result): self.release_group = parse_result.release_group if parse_result.extra_info: self.is_proper = re.search( '(^|[\. _-])(proper|repack)([\. _-]|$)', parse_result.extra_info, re.I) != None # for each possible interpretation of that scene name for cur_name in name_list: self._log(u"Checking scene exceptions for a match on " + cur_name, logger.DEBUG) scene_id = scene_exceptions.get_scene_exception_by_name(cur_name) if scene_id: self._log( u"Scene exception lookup got tvdb id " + str(scene_id) + u", using that", logger.DEBUG) _finalize(parse_result) return (scene_id, season, episodes) # see if we can find the name directly in the DB, if so use it for cur_name in name_list: self._log(u"Looking up " + cur_name + u" in the DB", logger.DEBUG) db_result = helpers.searchDBForShow(cur_name) if db_result: self._log( u"Lookup successful, using tvdb id " + str(db_result[0]), logger.DEBUG) _finalize(parse_result) return (int(db_result[0]), season, episodes) # see if we can find the name with a TVDB lookup for cur_name in name_list: try: t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **sickbeard.TVDB_API_PARMS) self._log(u"Looking up name " + cur_name + u" on TVDB", logger.DEBUG) showObj = t[cur_name] except (tvdb_exceptions.tvdb_exception): # if none found, search on all languages try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() ltvdb_api_parms['search_all_languages'] = True t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **ltvdb_api_parms) self._log( u"Looking up name " + cur_name + u" in all languages on TVDB", logger.DEBUG) showObj = t[cur_name] except (tvdb_exceptions.tvdb_exception, IOError): pass continue except (IOError): continue self._log( u"Lookup successful, using tvdb id " + str(showObj["id"]), logger.DEBUG) _finalize(parse_result) return (int(showObj["id"]), season, episodes) _finalize(parse_result) return to_return
def _show_data(self, show_obj): """ Creates an elementTree XML structure for a Mede8er-style Series.xml returns the resulting data object. show_obj: a TVShow instance to create the XML-NFO for """ logger.log("Mede8er: Starting Mede8er _show_data method", logger.MESSAGE) tvdb_lang = show_obj.lang # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) rootNode = etree.Element("details") tv_node = etree.SubElement(rootNode, "movie") #tv_node = etree.Element("movie") tv_node.attrib["isExtra"] = "false" tv_node.attrib["isSet"] = "false" tv_node.attrib["isTV"] = "true" for ns in XML_NSMAP.keys(): tv_node.set(ns, XML_NSMAP[ns]) try: myShow = t[int(show_obj.tvdbid)] except tvdb_exceptions.tvdb_shownotfound: logger.log( "Mede8er: Unable to find show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) raise except tvdb_exceptions.tvdb_error: logger.log( "Mede8er: TVDB is down, can't use its data to make the XML-NFO", logger.ERROR) raise # check for title and id try: if myShow["seriesname"] == None or myShow[ "seriesname"] == "" or myShow["id"] == None or myShow[ "id"] == "": logger.log( "Mede8er: Incomplete info for show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) return False except tvdb_exceptions.tvdb_attributenotfound: logger.log( "Mede8er: Incomplete info for show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) return False title = etree.SubElement(tv_node, "title") if myShow["seriesname"] != None: title.text = myShow["seriesname"] tvdbid = etree.SubElement(tv_node, "tvdbid") if myShow["id"] != None: tvdbid.text = myShow["id"] seriesID = etree.SubElement(tv_node, "seriesID") if myShow["seriesid"] != None: seriesID.text = myShow["seriesid"] imdbid = etree.SubElement(tv_node, "imdbid") if myShow["imdb_id"] != None: imdbid.text = myShow["imdb_id"] zap2id = etree.SubElement(tv_node, "zap2itid") if myShow["zap2it_id"] != None: zap2id.text = myShow["zap2it_id"] premiered = etree.SubElement(tv_node, "releasedate") if myShow["firstaired"] != None: premiered.text = myShow["firstaired"] rating = etree.SubElement(tv_node, "rating") if myShow["rating"] != None: rating.text = myShow["rating"] ratingcount = etree.SubElement(tv_node, "ratingcount") if myShow["ratingcount"] != None: ratingcount.text = myShow["ratingcount"] network = etree.SubElement(tv_node, "network") if myShow["network"] != None: network.text = myShow["network"] Runtime = etree.SubElement(tv_node, "runtime") if myShow["runtime"] != None: Runtime.text = myShow["runtime"] genre = etree.SubElement(tv_node, "genre") if myShow["genre"] != None: genre.text = myShow["genre"] #tmpNode = etree.SubElement(tv_node, "myShow") #tmpNode.text = str(vars(myShow)) #logger.log("Printing myShow info: " + str(vars(myShow)), logger.MESSAGE) #Actors = etree.SubElement(tv_node, "Actors") #if myShow["actors"] != None: # Actors.text = myShow["actors"] rating = etree.SubElement(tv_node, "certification") if myShow["contentrating"] != None: rating.text = myShow["contentrating"] Overview = etree.SubElement(tv_node, "plot") if myShow["overview"] != None: Overview.text = myShow["overview"] cast = etree.SubElement(tv_node, "cast") for actor in myShow['_actors']: cast_actor = etree.SubElement(cast, "actor") cast_actor.text = actor['name'] rating = etree.SubElement(tv_node, "Status") if myShow["status"] != None: rating.text = myShow["status"] cover = etree.SubElement(tv_node, "cover") poster = etree.SubElement(cover, "name") if myShow["poster"] != None: poster.text = myShow["poster"] backdrop = etree.SubElement(tv_node, "backdrop") fanart = etree.SubElement(backdrop, "name") if myShow["fanart"] != None: fanart.text = myShow["fanart"] helpers.indentXML(tv_node) data = etree.ElementTree(tv_node) return data
elif season == -2: self._log( u"Looks like this is an anime with absolute numbering show, attempting to convert the absolute episode to season/episode", logger.DEBUG) ab_episodes = episodes episodes = [] for episode in ab_episodes: try: # There's gotta be a better way of doing this but we don't wanna # change the cache value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(**ltvdb_api_parms) epObj = t[tvdb_id].absoluteNumber(episode)[0] season = int(epObj["seasonnumber"]) episodes.append(int(epObj["episodenumber"])) except tvdb_exceptions.tvdb_episodenotfound: logger.log( u"Unable to find episode with absolute number " + str(episode) + " for show " + str(tvdb_id) + ", skipping", logger.WARNING) episodes = [] continue except tvdb_exceptions.tvdb_error, e: logger.log(u"Unable to contact TVDB: " + ex(e), logger.WARNING) episodes = []
def _analyze_name(self, name, file_name=True): """ Takes a name and tries to figure out a show, season, and episode from it. name: A string which we want to analyze to determine show info from (unicode) Returns a (tvdb_id, season, [episodes], quality) tuple. tvdb_id, season, quality may be None and episodes may be []. if none were found. """ logger.log(u"Analyzing name " + repr(name)) to_return = (None, None, [], None) if not name: return to_return name = helpers.remove_non_release_groups(helpers.remove_extension(name)) # parse the name to break it into show name, season, and episode np = NameParser(False) parse_result = np.parse(name) self._log(u"Parsed " + name + " into " + str(parse_result).decode('utf-8', 'xmlcharrefreplace'), logger.DEBUG) if parse_result.air_by_date: season = -1 episodes = [parse_result.air_date] else: season = parse_result.season_number episodes = parse_result.episode_numbers to_return = (None, season, episodes, None) # do a scene reverse-lookup to get a list of all possible names name_list = show_name_helpers.sceneToNormalShowNames(parse_result.series_name) if not name_list: return (None, season, episodes, None) # try finding name in DB for cur_name in name_list: self._log(u"Looking up " + cur_name + u" in the DB", logger.DEBUG) db_result = helpers.searchDBForShow(cur_name) if db_result: self._log(u"Lookup successful, using tvdb id " + str(db_result[0]), logger.DEBUG) self._finalize(parse_result) return (int(db_result[0]), season, episodes, None) # try finding name in scene exceptions for cur_name in name_list: self._log(u"Checking scene exceptions for a match on " + cur_name, logger.DEBUG) scene_id = scene_exceptions.get_scene_exception_by_name(cur_name) if scene_id: self._log(u"Scene exception lookup got tvdb id " + str(scene_id) + u", using that", logger.DEBUG) self._finalize(parse_result) return (scene_id, season, episodes, None) # try finding name on TVDB for cur_name in name_list: try: t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **sickbeard.TVDB_API_PARMS) self._log(u"Looking up name " + cur_name + u" on TVDB", logger.DEBUG) showObj = t[cur_name] except (tvdb_exceptions.tvdb_exception): # if none found, search on all languages try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() ltvdb_api_parms['search_all_languages'] = True t = tvdb_api.Tvdb(custom_ui=classes.ShowListUI, **ltvdb_api_parms) self._log(u"Looking up name " + cur_name + u" in all languages on TVDB", logger.DEBUG) showObj = t[cur_name] except (tvdb_exceptions.tvdb_exception, IOError): pass continue except (IOError): continue self._log(u"Lookup successful, using tvdb id " + str(showObj["id"]), logger.DEBUG) self._finalize(parse_result) return (int(showObj["id"]), season, episodes, None) self._finalize(parse_result) return to_return
# GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with pchtrakt. If not, see <http://www.gnu.org/licenses/>. from os.path import basename, isfile from urllib import quote from urllib2 import urlopen, HTTPError, URLError import json from lib import parser from movieparser import * from lib.tvdb_api import tvdb_exceptions from pchtrakt.config import * from lib.tvdb_api import tvdb_api, tvdb_exceptions tvdb = tvdb_api.Tvdb() class MediaParserResult(): def __init__(self, file_name): self.file_name = file_name class MediaParserResultTVShow(MediaParserResult): def __init__(self, file_name, name, season_number, episode_numbers): self.file_name = file_name self.name = name self.season_number = season_number self.episode_numbers = episode_numbers if self.name in cacheSerie.dictSerie: self.id = cacheSerie.dictSerie[self.name]['TvDbId']
def _show_data(self, show_obj): """ Creates an elementTree XML structure for a Synology-style series.xml returns the resulting data object. show_obj: a TVShow instance to create the NFO for """ tvdb_lang = show_obj.lang # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if tvdb_lang and not tvdb_lang == 'en': ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(actors=True, **ltvdb_api_parms) tv_node = etree.Element("Series") for ns in XML_NSMAP.keys(): tv_node.set(ns, XML_NSMAP[ns]) try: myShow = t[int(show_obj.tvdbid)] except tvdb_exceptions.tvdb_shownotfound: logger.log( "Unable to find show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) raise except tvdb_exceptions.tvdb_error: logger.log("TVDB is down, can't use its data to make the NFO", logger.ERROR) raise # check for title and id try: if myShow["seriesname"] == None or myShow[ "seriesname"] == "" or myShow["id"] == None or myShow[ "id"] == "": logger.log( "Incomplete info for show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) return False except tvdb_exceptions.tvdb_attributenotfound: logger.log( "Incomplete info for show with id " + str(show_obj.tvdbid) + " on tvdb, skipping it", logger.ERROR) return False tvdbid = etree.SubElement(tv_node, "id") if myShow["id"] != None: tvdbid.text = myShow["id"] Actors = etree.SubElement(tv_node, "Actors") if myShow["actors"] != None: Actors.text = myShow["actors"] ContentRating = etree.SubElement(tv_node, "ContentRating") if myShow["contentrating"] != None: ContentRating.text = myShow["contentrating"] premiered = etree.SubElement(tv_node, "FirstAired") if myShow["firstaired"] != None: premiered.text = myShow["firstaired"] genre = etree.SubElement(tv_node, "genre") if myShow["genre"] != None: genre.text = myShow["genre"] IMDBId = etree.SubElement(tv_node, "IMDBId") if myShow["imdb_id"] != None: IMDBId.text = myShow["imdb_id"] IMDB_ID = etree.SubElement(tv_node, "IMDB_ID") if myShow["imdb_id"] != None: IMDB_ID.text = myShow["imdb_id"] Overview = etree.SubElement(tv_node, "Overview") if myShow["overview"] != None: Overview.text = myShow["overview"] Network = etree.SubElement(tv_node, "Network") if myShow["network"] != None: Network.text = myShow["network"] Runtime = etree.SubElement(tv_node, "Runtime") if myShow["runtime"] != None: Runtime.text = myShow["runtime"] Rating = etree.SubElement(tv_node, "Rating") if myShow["rating"] != None: Rating.text = myShow["rating"] SeriesID = etree.SubElement(tv_node, "SeriesID") if myShow["seriesid"] != None: SeriesID.text = myShow["seriesid"] SeriesName = etree.SubElement(tv_node, "SeriesName") if myShow["seriesname"] != None: SeriesName.text = myShow["seriesname"] rating = etree.SubElement(tv_node, "Status") if myShow["status"] != None: rating.text = myShow["status"] helpers.indentXML(tv_node) data = etree.ElementTree(tv_node) return data
def _addCacheEntry(self, name, url, season=None, episodes=None, tvdb_id=0, tvrage_id=0, quality=None, extraNames=[]): myDB = self._getDB() parse_result = None # if we don't have complete info then parse the filename to get it for curName in [name] + extraNames: try: myParser = NameParser() parse_result = myParser.parse(curName) except InvalidNameException: logger.log( u"Unable to parse the filename " + curName + " into a valid episode", logger.DEBUG) continue if not parse_result: logger.log( u"Giving up because I'm unable to parse this name: " + name, logger.DEBUG) return False if not parse_result.series_name: logger.log( u"No series name retrieved from " + name + ", unable to cache it", logger.DEBUG) return False # if we need tvdb_id or tvrage_id then search the DB for them if not tvdb_id or not tvrage_id: # if we have only the tvdb_id, use the database if tvdb_id: showObj = helpers.findCertainShow(sickbeard.showList, tvdb_id) if showObj: tvrage_id = showObj.tvrid tvdb_lang = showObj.lang else: logger.log( u"We were given a TVDB id " + str(tvdb_id) + " but it doesn't match a show we have in our list, so leaving tvrage_id empty", logger.DEBUG) tvrage_id = 0 # if we have only a tvrage_id then use the database elif tvrage_id: showObj = helpers.findCertainTVRageShow( sickbeard.showList, tvrage_id) if showObj: tvdb_id = showObj.tvdbid tvdb_lang = showObj.lang else: logger.log( u"We were given a TVRage id " + str(tvrage_id) + " but it doesn't match a show we have in our list, so leaving tvdb_id empty", logger.DEBUG) tvdb_id = 0 # if they're both empty then fill out as much info as possible by searching the show name else: showResult = helpers.searchDBForShow(parse_result.series_name) if showResult: logger.log( parse_result.series_name + " was found to be show " + showResult[1] + " (" + str(showResult[0]) + ") in our DB.", logger.DEBUG) tvdb_id = showResult[0] else: logger.log( u"Couldn't figure out a show name straight from the DB, trying a regex search instead", logger.DEBUG) for curShow in sickbeard.showList: if sceneHelpers.isGoodResult(name, curShow, False): logger.log( u"Successfully matched " + name + " to " + curShow.name + " with regex", logger.DEBUG) tvdb_id = curShow.tvdbid tvdb_lang = curShow.lang break if tvdb_id: showObj = helpers.findCertainShow(sickbeard.showList, tvdb_id) if not showObj: logger.log( u"This should never have happened, post a bug about this!", logger.ERROR) raise Exception("BAD STUFF HAPPENED") tvrage_id = showObj.tvrid tvdb_lang = showObj.lang if not season: season = parse_result.season_number if parse_result.season_number != None else 1 if not episodes: episodes = parse_result.episode_numbers # if we have an air-by-date show then get the real season/episode numbers if parse_result.air_by_date and tvdb_id: try: # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere ltvdb_api_parms = sickbeard.TVDB_API_PARMS.copy() if not (tvdb_lang == "" or tvdb_lang == "en" or tvdb_lang == None): ltvdb_api_parms['language'] = tvdb_lang t = tvdb_api.Tvdb(**ltvdb_api_parms) epObj = t[tvdb_id].airedOn(parse_result.air_date)[0] season = int(epObj["seasonnumber"]) episodes = [int(epObj["episodenumber"])] except tvdb_exceptions.tvdb_episodenotfound, e: logger.log( u"Unable to find episode with date " + str(parse_result.air_date) + " for show " + parse_result.series_name + ", skipping", logger.WARNING) return False