def updateShows(self): logger.log(u"Starting trakt show watchlist check", logger.DEBUG) watchlist = TraktCall("user/watchlist/shows.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) if watchlist is None: logger.log(u"Could not connect to trakt service, aborting watchlist update", logger.DEBUG) return for show in watchlist: if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(show["tvdb_id"], show["title"], SKIPPED) else: self.addDefaultShow(show["tvdb_id"], show["title"], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = helpers.findCertainShow(sickbeard.showList, int(show["tvdb_id"])) if newShow is not None: self.setEpisodeToWanted(newShow, 1, 1) self.startBacklog(newShow) else: self.todoWanted.append((int(show["tvdb_id"]), 1, 1)) if int(sickbeard.TRAKT_METHOD_ADD) == 3: newShow = helpers.findCertainShow(sickbeard.showList, int(show["tvdb_id"])) if newShow is not None: for ep in range(1,4): self.setEpisodeToWanted(newShow, 1, ep) self.startBacklog(newShow) else: for ep in range(1,4): self.todoWanted.append((int(show["tvdb_id"]), 1, ep))
def _addCacheEntry(self, name, url, season=None, episodes=None, tvdb_id=0, tvrage_id=0, quality=None, extraNames=[]): """Return False|None Parse the name and try to get as much info out of it as we can Will use anime regex's if this is called from fanzub On a succesfull parse it will add the parsed infos into the cache.db This dosen't mean the parsed result is usefull """ myDB = self._getDB() show = None if tvdb_id: show = helpers.findCertainShow(sickbeard.showList, tvdb_id) # if we don't have complete info then parse the filename to get it for curName in [name] + extraNames: cp = CompleteParser(show=show) cpr = cp.parse(curName) if cpr.sxxexx and cpr.parse_result: break else: return False episodeText = "|"+"|".join(map(str, cpr.episodes))+"|" # get the current timestamp curTimestamp = int(time.mktime(datetime.datetime.today().timetuple())) myDB.action("INSERT INTO "+self.providerID+" (name, season, episodes, tvrid, tvdbid, url, time, quality, release_group, proper) VALUES (?,?,?,?,?,?,?,?,?,?)", [name, cpr.season, episodeText, 0, cpr.tvdbid, url, curTimestamp, cpr.quality, cpr.release_group, int(cpr.is_proper)])
def findNeededEpisodes(self, episode = None, manualSearch=False): neededEps = {} if episode: neededEps[episode] = [] myDB = self._getDB() if not episode: sqlResults = myDB.select("SELECT * FROM "+self.providerID) else: sqlResults = myDB.select("SELECT * FROM "+self.providerID+" WHERE tvdbid = ? AND season = ? AND episodes LIKE ?", [episode.show.tvdbid, episode.season, "|"+str(episode.episode)+"|"]) # for each cache entry for curResult in sqlResults: # get the show object, or if it's not one of our shows then ignore it showObj = helpers.findCertainShow(sickbeard.showList, int(curResult["tvdbid"])) if not showObj: continue # get season and ep data (ignoring multi-eps for now) curSeason = int(curResult["season"]) if curSeason == -1: continue curEp = curResult["episodes"].split("|")[1] if not curEp: continue curEp = int(curEp) curQuality = int(curResult["quality"]) # if the show says we want that episode then add it to the list if not showObj.wantEpisode(curSeason, curEp, curQuality, manualSearch): logger.log("Skipping "+curResult["name"]+" because we don't want an episode that's "+Quality.qualityStrings[curQuality], logger.DEBUG) else: if episode: epObj = episode else: epObj = showObj.getEpisode(curSeason, curEp) # build a result object title = curResult["name"] url = curResult["url"] logger.log("Found result " + title + " at " + url) result = self.provider.getResult([epObj]) result.url = url result.name = title result.quality = curQuality # add it to the list if epObj not in neededEps: neededEps[epObj] = [result] else: neededEps[epObj].append(result) return neededEps
def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log(u"Starting trakt episode watchlist check", logger.DEBUG) try: watchlist = self.trakt_api.traktRequest("sync/watchlist/episodes") except (traktException, traktAuthException, traktServerBusy) as e: logger.log(u"Could not connect to Trakt service: %s" % ex(e), logger.WARNING) return if not len(watchlist): logger.log(u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return for show in watchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["show"]["ids"]["tvrage"]) else: indexer_id = int(show["show"]["ids"]["tvdb"]) self.addDefaultShow(indexer, indexer_id, show["show"]["title"], SKIPPED) newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) try: if newShow and newShow.indexer == indexer: for episode in show["episode"]: if newShow is not None: self.setEpisodeToWanted(newShow, episode["season"], episode["number"]) else: self.todoWanted.append((indexer_id, episode["season"], episode["number"])) except TypeError: logger.log(u"Could not parse the output from trakt for " + show["show"]["title"], logger.DEBUG)
def updateShows(self): logger.log(u"Starting trakt show watchlist check", logger.DEBUG) try: watchlist = self.trakt_api.traktRequest("sync/watchlist/shows") except (traktException, traktAuthException, traktServerBusy) as e: logger.log(u"Could not connect to Trakt service: %s" % ex(e), logger.WARNING) return if not len(watchlist): logger.log(u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return for show in watchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["show"]["ids"]["tvrage"]) else: indexer_id = int(show["show"]["ids"]["tvdb"]) if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(indexer, indexer_id, show["show"]["title"], SKIPPED) else: self.addDefaultShow(indexer, indexer_id, show["show"]["title"], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) if newShow is not None: self.setEpisodeToWanted(newShow, 1, 1) else: self.todoWanted.append((indexer_id, 1, 1))
def find_propers(self, **kwargs): """ Search for releases of type PROPER :return: list of Proper objects """ results = [] search_terms = getattr(self, 'proper_search_terms', ['proper', 'repack']) if not isinstance(search_terms, list): if None is search_terms: search_terms = 'proper|repack' search_terms = [search_terms] items = self._search_provider({'Propers': search_terms}) clean_term = re.compile(r'(?i)[^a-z1-9\|\.]+') for proper_term in search_terms: proper_check = re.compile(r'(?i)(?:%s)' % clean_term.sub('', proper_term)) for item in items: title, url = self._title_and_url(item) if proper_check.search(title): results.append(classes.Proper(title, url, datetime.datetime.today(), helpers.findCertainShow(sickbeard.showList, None))) return results
def _changeMissingEpisodes(self): logger.log(u"Changing all old missing episodes to status WANTED") curDate = datetime.date.today().toordinal() myDB = db.DBConnection() sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE status = ? AND airdate < ?", [common.UNAIRED, curDate]) for sqlEp in sqlResults: try: show = helpers.findCertainShow(sickbeard.showList, int(sqlEp["showid"])) except exceptions.MultipleShowObjectsException: logger.log(u"ERROR: expected to find a single show matching " + str(sqlEp["showid"])) return None if show == None: logger.log(u"Unable to find the show with ID " + str( sqlEp["showid"]) + " in your show list! DB value was " + str(sqlEp), logger.ERROR) return None ep = show.getEpisode(sqlEp["season"], sqlEp["episode"]) with ep.lock: if ep.show.paused: ep.status = common.SKIPPED else: ep.status = common.WANTED ep.saveToDB()
def findPropers(self, search_date=datetime.datetime.today()): results = [] sqlResults = db.DBConnection().select( "SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e" + " INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)" + " WHERE e.airdate >= " + str(search_date.toordinal()) + " AND (e.status IN (" + ",".join([str(x) for x in Quality.DOWNLOADED]) + ")" + " OR (e.status IN (" + ",".join([str(x) for x in Quality.SNATCHED]) + ")))" ) if not sqlResults: return [] for sqlShow in sqlResults: curShow = helpers.findCertainShow(sickbeard.showList, int(sqlShow["showid"])) curEp = curShow.getEpisode(int(sqlShow["season"]), int(sqlShow["episode"])) searchString = self._get_episode_search_strings(curEp, add_string="PROPER|REPACK") for item in self._doSearch(searchString[0]): title, url = self._get_title_and_url(item) results.append(classes.Proper(title, url, datetime.datetime.today())) return results
def massEdit(self, toEdit=None): t = PageTemplate(file="manage_massEdit.tmpl") t.submenu = ManageMenu if not toEdit: redirect("/manage") showIDs = toEdit.split("|") showList = [] for curID in showIDs: curID = int(curID) showObj = helpers.findCertainShow(sickbeard.showList, curID) if showObj: showList.append(showObj) season_folders_all_same = True last_season_folders = None paused_all_same = True last_paused = None quality_all_same = True last_quality = None root_dir_list = [] for curShow in showList: cur_root_dir = ek.ek(os.path.dirname, curShow._location) if cur_root_dir not in root_dir_list: root_dir_list.append(cur_root_dir) # if we know they're not all the same then no point even bothering if paused_all_same: # if we had a value already and this value is different then they're not all the same if last_paused not in (curShow.paused, None): paused_all_same = False else: last_paused = curShow.paused if season_folders_all_same: if last_season_folders not in (None, curShow.seasonfolders): season_folders_all_same = False else: last_season_folders = curShow.seasonfolders if quality_all_same: if last_quality not in (None, curShow.quality): quality_all_same = False else: last_quality = curShow.quality t.showList = toEdit t.paused_value = last_paused if paused_all_same else None t.season_folders_value = last_season_folders if season_folders_all_same else None t.quality_value = last_quality if quality_all_same else None t.root_dir_list = root_dir_list return _munge(t)
def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log(u"Starting trakt episode watchlist check", logger.DEBUG) if not len(self.EpisodeWatchlist): logger.log(u"No episode found in your watchlist, aborting episode update", logger.DEBUG) return managed_show = [] for show in self.EpisodeWatchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["show"]["ids"]["tvrage"]) else: indexer_id = int(show["show"]["ids"]["tvdb"]) newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) try: if newShow is None: if indexer_id not in managed_show: self.addDefaultShow(indexer, indexer_id, show["show"]["title"], SKIPPED) managed_show.append(indexer_id) self.todoWanted.append((indexer_id, show['episode']['season'], show['episode']['number'])) else: if newShow.indexer == indexer: self.setEpisodeToWanted(newShow, show['episode']['season'], show['episode']['number']) except TypeError: logger.log(u"Could not parse the output from trakt for " + show["show"]["title"], logger.DEBUG)
def updateMissingList(): logger.log("Searching DB and building list of MISSED episodes") myDB = db.DBConnection() sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE status=" + str(MISSED)) epList = [] for sqlEp in sqlResults: try: show = helpers.findCertainShow(sickbeard.showList, int(sqlEp["showid"])) except exceptions.MultipleShowObjectsException: logger.log("ERROR: expected to find a single show matching " + sqlEp["showid"]) return None # we aren't ever downloading specials if int(sqlEp["season"]) == 0: continue if show == None: continue ep = show.getEpisode(sqlEp["season"], sqlEp["episode"]) if ep == None: logger.log( "Somehow " + show.name + " - " + str(sqlEp["season"]) + "x" + str(sqlEp["episode"]) + " is None", logger.ERROR, ) else: epList.append(ep) sickbeard.missingList = epList
def _load_saved_torrents(deleteSaveFile=True): torrent_save_file = _get_running_torrents_pickle_path(False) if os.path.isfile(torrent_save_file): try: data_from_pickle = pickle.load(open(torrent_save_file, "rb")) for td in data_from_pickle: if 'episodes' not in td: # older pickles won't have these... td['episodes'] = [] if 'originalTorrentUrl' not in td: td['originalTorrentUrl'] = None if 'blacklistOrigUrlOnFailure' not in td: td['blacklistOrigUrlOnFailure'] = False tvEpObjs = [] for ep in td['episodes']: shw = helpers.findCertainShow(sickbeard.showList, ep['tvdbid']) tvEpObjs.append(TVEpisode(show=shw, season=ep['season'], episode=ep['episode'])) download_from_torrent(torrent=td['torrent'], postProcessingDone=td['post_processed'], start_time=td['start_time'], key=td['key'], episodes=tvEpObjs, originalTorrentUrl=td['originalTorrentUrl'], blacklistOrigUrlOnFailure=td['blacklistOrigUrlOnFailure']) except Exception, e: logger.log(u'Failure while reloading running torrents: %s' % (ex(e)), logger.ERROR) if deleteSaveFile: os.remove(torrent_save_file)
def findPropers(self, search_date=datetime.datetime.today()): results = [] myDB = db.DBConnection() sqlResults = myDB.select( 'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e' + ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)' + ' WHERE e.airdate >= ' + str(search_date.toordinal()) + ' AND (e.status IN (' + ','.join([str(x) for x in Quality.DOWNLOADED]) + ')' + ' OR (e.status IN (' + ','.join([str(x) for x in Quality.SNATCHED]) + ')))' ) if not sqlResults: return [] for sqlshow in sqlResults: self.show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) if self.show: curEp = self.show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) searchString = self._get_episode_search_strings(curEp, add_string='PROPER|REPACK') for item in self._doSearch(searchString[0]): title, url = self._get_title_and_url(item) results.append(classes.Proper(title, url, datetime.datetime.today(), self.show)) return results
def updateShows(self): logger.log(u"SHOW_WATCHLIST::CHECK::START - Trakt Show Watchlist", logger.DEBUG) if not len(self.ShowWatchlist): logger.log(u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) trakt_id = sickbeard.indexerApi(indexer).config['trakt_id'] for show_el in self.ShowWatchlist[trakt_id]: indexer_id = int(str(show_el)) show = self.ShowWatchlist[trakt_id][show_el] #logger.log(u"Checking Show: %s %s %s" % (trakt_id, indexer_id, show['title']),logger.DEBUG) if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(indexer, indexer_id, show['title'], SKIPPED) else: self.addDefaultShow(indexer, indexer_id, show['title'], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) if newShow is not None: setEpisodeToWanted(newShow, 1, 1) else: self.todoWanted.append((indexer_id, 1, 1)) logger.log(u"SHOW_WATCHLIST::CHECK::FINISH - Trakt Show Watchlist", logger.DEBUG)
def set_scene_numbering(indexer_id, indexer, season=None, episode=None, absolute_number=None, sceneSeason=None, sceneEpisode=None, sceneAbsolute=None): """ Set scene numbering for a season/episode. To clear the scene numbering, leave both sceneSeason and sceneEpisode as None. """ if indexer_id is None: return indexer_id = int(indexer_id) indexer = int(indexer) myDB = db.DBConnection() if season and episode: myDB.action( "INSERT OR IGNORE INTO scene_numbering (indexer, indexer_id, season, episode) VALUES (?,?,?,?)", [indexer, indexer_id, season, episode]) myDB.action( "UPDATE scene_numbering SET scene_season = ?, scene_episode = ? WHERE indexer = ? and indexer_id = ? and season = ? and episode = ?", [sceneSeason, sceneEpisode, indexer, indexer_id, season, episode]) elif absolute_number: myDB.action( "INSERT OR IGNORE INTO scene_numbering (indexer, indexer_id, absolute_number) VALUES (?,?,?)", [indexer, indexer_id, absolute_number]) myDB.action( "UPDATE scene_numbering SET scene_absolute_number = ? WHERE indexer = ? and indexer_id = ? and absolute_number = ?", [sceneAbsolute, indexer, indexer_id, absolute_number]) #Reload data from DB so that cache and db are in sync show = helpers.findCertainShow(sickbeard.showList, indexer_id) show.flushEpisodes()
def _addCacheEntry(self, name, url, parse_result=None, indexer_id=0): # check if we passed in a parsed result or should we try and create one if not parse_result: # create showObj from indexer_id if available showObj=None if indexer_id: showObj = helpers.findCertainShow(sickbeard.showList, indexer_id) try: myParser = NameParser(showObj=showObj, convert=True) parse_result = myParser.parse(name) except InvalidNameException: logger.log(u"Unable to parse the filename " + name + " into a valid episode", logger.DEBUG) return None except InvalidShowException: logger.log(u"Unable to parse the filename " + name + " into a valid show", logger.DEBUG) return None if not parse_result or not parse_result.series_name: return None # if we made it this far then lets add the parsed result to cache for usager later on season = episodes = None if parse_result.is_air_by_date or parse_result.is_sports: airdate = parse_result.air_date.toordinal() if parse_result.air_date else parse_result.sports_air_date.toordinal() myDB = db.DBConnection() sql_results = myDB.select( "SELECT season, episode FROM tv_episodes WHERE showid = ? AND indexer = ? AND airdate = ?", [parse_result.show.indexerid, parse_result.show.indexer, airdate]) if sql_results > 0: season = int(sql_results[0]["season"]) episodes = [int(sql_results[0]["episode"])] else: season = parse_result.season_number if parse_result.season_number else 1 episodes = parse_result.episode_numbers if season and episodes: # store episodes as a seperated string episodeText = "|" + "|".join(map(str, episodes)) + "|" # get the current timestamp curTimestamp = int(time.mktime(datetime.datetime.today().timetuple())) # get quality of release quality = parse_result.quality if not isinstance(name, unicode): name = unicode(name, 'utf-8', 'replace') # get release group release_group = parse_result.release_group logger.log(u"Added RSS item: [" + name + "] to cache: [" + self.providerID + "]", logger.DEBUG) return [ "INSERT OR IGNORE INTO [" + self.providerID + "] (name, season, episodes, indexerid, url, time, quality, release_group) VALUES (?,?,?,?,?,?,?,?)", [name, season, episodeText, parse_result.show.indexerid, url, curTimestamp, quality, release_group]]
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: showObj = helpers.findCertainShow(sickbeard.showList, x.indexerid) if not showObj: logger.log(u"Unable to find the show in our watch list " + str(x.name), logger.DEBUG) continue 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
def find_xem_numbering(indexer_id, season, episode): """ Returns the scene numbering, as retrieved from xem. Refreshes/Loads as needed. @param indexer_id: int @param season: int @param episode: int @return: (int, int) a tuple of scene_season, scene_episode, or None if there is no special mapping. """ if indexer_id is None or season is None or episode is None: return None showObj = helpers.findCertainShow(sickbeard.showList, indexer_id) if showObj is None: return None indexer = showObj.indexer if _xem_refresh_needed(indexer_id): _xem_refresh(indexer_id) cacheDB = db.DBConnection('cache.db') rows = cacheDB.select( "SELECT scene_season, scene_episode FROM xem_numbering WHERE indexer = ? and indexer_id = ? and season = ? and episode = ?", [indexer, indexer_id, season, episode]) if rows: return (int(rows[0]["scene_season"]), int(rows[0]["scene_episode"])) else: return None
def get_indexer_numbering_for_xem(indexer_id, sceneSeason, sceneEpisode): """ Reverse of find_xem_numbering: lookup a tvdb season and episode using scene numbering @param indexer_id: int @param sceneSeason: int @param sceneEpisode: int @return: (int, int) a tuple of (season, episode) """ if indexer_id is None or sceneSeason is None or sceneEpisode is None: return None showObj = helpers.findCertainShow(sickbeard.showList, indexer_id) if showObj is None: return None indexer = showObj.indexer if _xem_refresh_needed(indexer_id): _xem_refresh(indexer_id) cacheDB = db.DBConnection('cache.db') rows = cacheDB.select( "SELECT season, episode FROM xem_numbering WHERE indexer = ? and indexer_id = ? and scene_season = ? and scene_episode = ?", [indexer, indexer_id, sceneSeason, sceneEpisode]) if rows: return (int(rows[0]["season"]), int(rows[0]["episode"])) else: return (sceneSeason, sceneEpisode)
def _change_missing_episodes(): if not network_timezones.network_dict: network_timezones.update_network_dict() if network_timezones.network_dict: cur_date = (datetime.date.today() + datetime.timedelta(days=1)).toordinal() else: cur_date = (datetime.date.today() - datetime.timedelta(days=2)).toordinal() cur_time = datetime.datetime.now(network_timezones.sb_timezone) my_db = db.DBConnection() sql_results = my_db.select( 'SELECT * FROM tv_episodes' ' WHERE status = ? AND season > 0 AND airdate <= ? AND airdate > 1' ' ORDER BY showid', [common.UNAIRED, cur_date]) sql_l = [] show = None wanted = False for sqlEp in sql_results: try: if not show or show.indexerid != int(sqlEp['showid']): show = helpers.findCertainShow(sickbeard.showList, int(sqlEp['showid'])) # for when there is orphaned series in the database but not loaded into our showlist if not show: continue except exceptions.MultipleShowObjectsException: logger.log(u'ERROR: expected to find a single show matching %s' % sqlEp['showid']) continue try: end_time = (network_timezones.parse_date_time(sqlEp['airdate'], show.airs, show.network) + datetime.timedelta(minutes=helpers.tryInt(show.runtime, 60))) # filter out any episodes that haven't aired yet if end_time > cur_time: continue except (StandardError, Exception): # if an error occurred assume the episode hasn't aired yet continue ep = show.getEpisode(int(sqlEp['season']), int(sqlEp['episode'])) with ep.lock: # Now that it is time, change state of UNAIRED show into expected or skipped ep.status = (common.WANTED, common.SKIPPED)[ep.show.paused] result = ep.get_sql() if None is not result: sql_l.append(result) wanted |= (False, True)[common.WANTED == ep.status] else: logger.log(u'No unaired episodes marked wanted') if 0 < len(sql_l): my_db = db.DBConnection() my_db.mass_action(sql_l) if wanted: logger.log(u'Found new episodes marked wanted')
def findPropers(self, search_date=datetime.datetime.today()): results = [] myDB = db.DBConnection() sqlResults = myDB.select( "SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e" + " INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)" + " WHERE e.airdate >= " + str(search_date.toordinal()) + " AND e.status IN (" + ",".join([str(x) for x in Quality.DOWNLOADED + Quality.SNATCHED + Quality.SNATCHED_BEST]) + ")" ) for sqlshow in sqlResults or []: show = helpers.findCertainShow(sickbeard.showList, int(sqlshow["showid"])) if show: curEp = show.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) for term in self.proper_strings: searchString = self._get_episode_search_strings(curEp, add_string=term) for item in self._doSearch(searchString[0]): title, url = self._get_title_and_url(item) results.append(classes.Proper(title, url, datetime.datetime.today(), show)) return results
def _get_ep_obj(self, tvdb_id, season, episodes): show_obj = None self._log(u"Loading show object for tvdb_id "+str(tvdb_id), logger.DEBUG) # find the show in the showlist try: show_obj = helpers.findCertainShow(sickbeard.showList, tvdb_id) except exceptions.MultipleShowObjectsException: raise #TODO: later I'll just log this, for now I want to know about it ASAP if not show_obj: self._log(u"This show isn't in your list, you need to add it to SB before post-processing an episode", logger.ERROR) raise exceptions.PostProcessingFailed() root_ep = None for cur_episode in episodes: episode = int(cur_episode) self._log(u"Retrieving episode object for " + str(season) + "x" + str(episode), logger.DEBUG) # now that we've figured out which episode this file is just load it manually try: curEp = show_obj.getEpisode(season, episode) except exceptions.EpisodeNotFoundException, e: self._log(u"Unable to create episode: "+ex(e), logger.DEBUG) raise exceptions.PostProcessingFailed() if root_ep == None: root_ep = curEp root_ep.relatedEps = [] else: root_ep.relatedEps.append(curEp)
def set_scene_numbering(indexer_id, season, episode, sceneSeason=None, sceneEpisode=None): """ Set scene numbering for a season/episode. To clear the scene numbering, leave both sceneSeason and sceneEpisode as None. """ if indexer_id is None or season is None or episode is None: return showObj = helpers.findCertainShow(sickbeard.showList, indexer_id) if showObj is None: return indexer = showObj.indexer myDB = db.DBConnection() # sanity #if sceneSeason == None: sceneSeason = season #if sceneEpisode == None: sceneEpisode = episode # delete any existing record first myDB.action('DELETE FROM scene_numbering where indexer = ? and indexer_id = ? and season = ? and episode = ?', [indexer, indexer_id, season, episode]) # now, if the new numbering is not the default, we save a new record if sceneSeason is not None and sceneEpisode is not None: myDB.action( "INSERT INTO scene_numbering (indexer, indexer_id, season, episode, scene_season, scene_episode) VALUES (?,?,?,?,?,?)", [indexer, indexer_id, season, episode, sceneSeason, sceneEpisode])
def updateAiringList(): logger.log("Searching DB and building list of airing episodes") curDate = datetime.date.today().toordinal() myDB = db.DBConnection() sqlResults = myDB.select("SELECT * FROM tv_episodes WHERE status == " + str(UNAIRED) + " AND airdate <= " + str(curDate)) epList = [] for sqlEp in sqlResults: try: show = helpers.findCertainShow (sickbeard.showList, int(sqlEp["showid"])) except exceptions.MultipleShowObjectsException: logger.log("ERROR: expected to find a single show matching " + sqlEp["showid"]) return None except exceptions.SickBeardException, e: logger.log("Unexpected exception: "+str(e), logger.ERROR) continue # we aren't ever downloading specials if int(sqlEp["season"]) == 0: continue if show == None: continue ep = show.getEpisode(sqlEp["season"], sqlEp["episode"]) if ep == None: logger.log("Somehow "+show.name+" - "+str(sqlEp["season"])+"x"+str(sqlEp["episode"])+" is None", logger.ERROR) else: epList.append(ep)
def updateShows(self): logger.log(u"Starting trakt show watchlist check", logger.DEBUG) if not len(self.ShowWatchlist): logger.log(u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return for show in self.ShowWatchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["show"]["ids"]["tvrage"]) else: indexer_id = int(show["show"]["ids"]["tvdb"]) if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(indexer, indexer_id, show["show"]["title"], SKIPPED) else: self.addDefaultShow(indexer, indexer_id, show["show"]["title"], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) if newShow is not None: self.setEpisodeToWanted(newShow, 1, 1) else: self.todoWanted.append((indexer_id, 1, 1))
def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log(u"Starting trakt episode watchlist check", logger.DEBUG) watchlist = TraktCall("user/watchlist/episodes.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) if watchlist == 'NULL': logger.log(u"No episodes found in your watchlist, aborting watchlist update", logger.DEBUG) return if not watchlist: logger.log(u"Could not connect to trakt service, aborting watchlist update", logger.ERROR) return for show in watchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["tvrage_id"]) else: indexer_id = int(show["tvdb_id"]) self.addDefaultShow(indexer, indexer_id, show["title"], SKIPPED) newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) try: if newShow and int(newShow['indexer']) == indexer: for episode in show["episodes"]: if newShow is not None: self.setEpisodeToWanted(newShow, episode["season"], episode["number"]) else: self.todoWanted.append((indexer_id, episode["season"], episode["number"])) self.startBacklog(newShow) except TypeError: logger.log(u"Could not parse the output from trakt for " + show["title"], logger.DEBUG)
def addDefaultShow(self, indexer, indexer_id, name, status): """ Adds a new show with the default settings """ if not helpers.findCertainShow(sickbeard.showList, int(indexer_id)): logger.log(u"Adding show " + str(indexer_id)) root_dirs = sickbeard.ROOT_DIRS.split('|') try: location = root_dirs[int(root_dirs[0]) + 1] except: location = None if location: showPath = ek.ek(os.path.join, location, helpers.sanitizeFileName(name)) dir_exists = helpers.makeDir(showPath) if not dir_exists: logger.log(u"Unable to create the folder " + showPath + ", can't add the show", logger.ERROR) return else: helpers.chmodAsParent(showPath) sickbeard.showQueueScheduler.action.addShow(int(indexer), int(indexer_id), showPath, status, int(sickbeard.QUALITY_DEFAULT), int(sickbeard.FLATTEN_FOLDERS_DEFAULT)) else: logger.log(u"There was an error creating the show, no root directory setting found", logger.ERROR) return
def updateShows(self): logger.log(u"Starting trakt show watchlist check", logger.DEBUG) watchlist = TraktCall("user/watchlist/shows.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) if watchlist == 'NULL': logger.log(u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return if not watchlist: logger.log(u"Could not connect to trakt service, aborting watchlist update", logger.ERROR) return for show in watchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["tvrage_id"]) else: indexer_id = int(show["tvdb_id"]) if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(indexer, indexer_id, show["title"], SKIPPED) else: self.addDefaultShow(indexer, indexer_id, show["title"], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) if newShow is not None: self.setEpisodeToWanted(newShow, 1, 1) self.startBacklog(newShow) else: self.todoWanted.append((indexer_id, 1, 1)) self.todoWanted.append((indexer_id, -1, -1)) # used to pause new shows if the settings say to
def get_xem_numbering_for_season(indexer_id, season): """ Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings for an entire show. Both the keys and values of the dict are tuples. Will be empty if there are no scene numbers set """ if indexer_id is None or season is None: return {} showObj = helpers.findCertainShow(sickbeard.showList, indexer_id) if showObj is None: return {} indexer = showObj.indexer if _xem_refresh_needed(indexer_id): _xem_refresh(indexer_id) cacheDB = db.DBConnection('cache.db') rows = cacheDB.select( 'SELECT season, scene_season FROM xem_numbering WHERE indexer = ? and indexer_id = ? AND season = ? ORDER BY season, [indexer, indexer_id, season]') result = {} if rows: for row in rows: result.setdefault(int(row['season']), []).append(int(row['scene_season'])) else: result.setdefault(int(season), []).append(int(season)) return result
def addDefaultShow(self, indexer, indexer_id, name, status): """ Adds a new show with the default settings """ if not helpers.findCertainShow(sickbeard.showList, int(indexer_id)): logger.log(u"Adding show " + str(indexer_id)) root_dirs = sickbeard.ROOT_DIRS.split('|') try: location = root_dirs[int(root_dirs[0]) + 1] except: location = None if location: showPath = ek(os.path.join, location, helpers.sanitizeFileName(name)) dir_exists = helpers.makeDir(showPath) if not dir_exists: logger.log(u"Unable to create the folder %s , can't add the show" % showPath, logger.WARNING) return else: helpers.chmodAsParent(showPath) sickbeard.showQueueScheduler.action.addShow(int(indexer), int(indexer_id), showPath, default_status=status, quality=int(sickbeard.QUALITY_DEFAULT), flatten_folders=int(sickbeard.FLATTEN_FOLDERS_DEFAULT), paused=sickbeard.TRAKT_START_PAUSED, default_status_after=status, archive=sickbeard.ARCHIVE_DEFAULT) else: logger.log(u"There was an error creating the show, no root directory setting found", logger.WARNING) return
def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log(u"SHOW_WATCHLIST::CHECK::START - Trakt Episode Watchlist", logger.DEBUG) if not len(self.EpisodeWatchlist): logger.log( u"No episode found in your watchlist, aborting episode update", logger.DEBUG) return managed_show = [] indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) trakt_id = sickbeard.indexerApi(indexer).config['trakt_id'] for show_el in self.EpisodeWatchlist[trakt_id]: indexer_id = int(show_el) show = self.EpisodeWatchlist[trakt_id][show_el] newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) try: if newShow is None: if indexer_id not in managed_show: self.addDefaultShow(indexer, indexer_id, show['title'], SKIPPED) managed_show.append(indexer_id) for season_el in show['seasons']: season = int(season_el) for episode_el in show['seasons'][season_el][ 'episodes']: self.todoWanted.append( (indexer_id, season, int(episode_el))) else: if newShow.indexer == indexer: for season_el in show['seasons']: season = int(season_el) for episode_el in show['seasons'][season_el][ 'episodes']: setEpisodeToWanted(newShow, season, int(episode_el)) except TypeError: logger.log( u"Could not parse the output from trakt for " + show["title"], logger.DEBUG) logger.log(u"SHOW_WATCHLIST::CHECK::FINISH - Trakt Episode Watchlist", logger.DEBUG)
def _get_ep_obj(self, tvdb_id, season, episodes): """ Retrieve the TVEpisode object requested. tvdb_id: The TVDBID of the show (int) season: The season of the episode (int) episodes: A list of episodes to find (list of ints) If the episode(s) can be found then a TVEpisode object with the correct related eps will be instantiated and returned. If the episode can't be found then None will be returned. """ show_obj = None self._log(u"Loading show object for tvdb_id " + str(tvdb_id), logger.DEBUG) # find the show in the showlist try: show_obj = helpers.findCertainShow(sickbeard.showList, tvdb_id) except exceptions.MultipleShowObjectsException: raise #TODO: later I'll just log this, for now I want to know about it ASAP # if we can't find the show then there's nothing we can really do if not show_obj: self._log( u"This show isn't in your list, you need to add it to SB before post-processing an episode", logger.ERROR) raise exceptions.PostProcessingFailed() root_ep = None for cur_episode in episodes: episode = int(cur_episode) self._log( u"Retrieving episode object for " + str(season) + "x" + str(episode), logger.DEBUG) # now that we've figured out which episode this file is just load it manually try: curEp = show_obj.getEpisode(season, episode) except exceptions.EpisodeNotFoundException, e: self._log(u"Unable to create episode: " + ex(e), logger.DEBUG) raise exceptions.PostProcessingFailed() # associate all the episodes together under a single root episode if root_ep == None: root_ep = curEp root_ep.relatedEps = [] elif curEp not in root_ep.relatedEps: root_ep.relatedEps.append(curEp)
def _downloadPropers(self, properList): for curProper in properList: historyLimit = datetime.datetime.today() - datetime.timedelta(days=30) # make sure the episode has been downloaded before myDB = db.DBConnection() historyResults = myDB.select( "SELECT resource FROM history " "WHERE showid = ? AND season = ? AND episode = ? AND quality = ? AND date >= ? " "AND action IN (" + ",".join([str(x) for x in Quality.SNATCHED]) + ")", [curProper.indexerid, curProper.season, curProper.episode, curProper.quality, historyLimit.strftime(history.dateFormat)]) # if we didn't download this episode in the first place we don't know what quality to use for the proper so we can't do it if len(historyResults) == 0: logger.log( u"Unable to find an original history entry for proper " + curProper.name + " so I'm not downloading it.") continue else: # make sure that none of the existing history downloads are the same proper we're trying to download isSame = False for curResult in historyResults: # if the result exists in history already we need to skip it if self._genericName(curResult["resource"]) == self._genericName(curProper.name): isSame = True break if isSame: logger.log(u"This proper is already in history, skipping it", logger.DEBUG) continue # get the episode object showObj = helpers.findCertainShow(sickbeard.showList, curProper.indexerid) if showObj == None: logger.log(u"Unable to find the show with indexerid " + str( curProper .indexerid) + " so unable to download the proper", logger.ERROR) continue epObj = showObj.getEpisode(curProper.season, curProper.episode) # make the result object result = curProper.provider.getResult([epObj]) result.url = curProper.url result.name = curProper.name result.quality = curProper.quality # snatch it search.snatchEpisode(result, SNATCHED_PROPER)
def _addCacheEntry(self, name, url, parse_result=None, indexer_id=0): # check if we passed in a parsed result or should we try and create one if not parse_result: # create showObj from indexer_id if available showObj = None if indexer_id: showObj = helpers.findCertainShow(sickbeard.showList, indexer_id) try: myParser = NameParser(showObj=showObj) parse_result = myParser.parse(name) except InvalidNameException: logger.log(u"Unable to parse the filename " + name + " into a valid episode", logger.DEBUG) return None except InvalidShowException: logger.log(u"Unable to parse the filename " + name + " into a valid show", logger.DEBUG) return None if not parse_result or not parse_result.series_name: return None # if we made it this far then lets add the parsed result to cache for usager later on season = parse_result.season_number if parse_result.season_number else 1 episodes = parse_result.episode_numbers if season and episodes: # store episodes as a seperated string episodeText = "|" + "|".join(map(str, episodes)) + "|" # get the current timestamp curTimestamp = int(time.mktime(datetime.datetime.today().timetuple())) # get quality of release quality = parse_result.quality name = ek.ss(name) # get release group release_group = parse_result.release_group # get version version = parse_result.version logger.log(u"Added RSS item: [" + name + "] to cache: [" + self.providerID + "]", logger.DEBUG) return [ "INSERT OR IGNORE INTO [" + self.providerID + "] (name, season, episodes, indexerid, url, time, quality, release_group, version) VALUES (?,?,?,?,?,?,?,?,?)", [name, season, episodeText, parse_result.show.indexerid, url, curTimestamp, quality, release_group, version]]
def process(self): self._log(u"Failed download detected: (" + str(self.nzb_name) + ", " + str(self.dir_name) + ")") releaseName = show_name_helpers.determineReleaseName(self.dir_name, self.nzb_name) if releaseName is None: self._log(u"Warning: unable to find a valid release name.", logger.WARNING) raise exceptions.FailedProcessingFailed() parser = NameParser(False) try: parsed = parser.parse(releaseName) except InvalidNameException: self._log(u"Error: release name is invalid: " + releaseName, logger.WARNING) raise exceptions.FailedProcessingFailed() logger.log(u"name_parser info: ", logger.DEBUG) logger.log(u" - " + str(parsed.series_name), logger.DEBUG) logger.log(u" - " + str(parsed.season_number), logger.DEBUG) logger.log(u" - " + str(parsed.episode_numbers), logger.DEBUG) logger.log(u" - " + str(parsed.extra_info), logger.DEBUG) logger.log(u" - " + str(parsed.release_group), logger.DEBUG) logger.log(u" - " + str(parsed.air_date), logger.DEBUG) show_id = self._get_show_id(parsed.series_name) if show_id is None: self._log(u"Warning: couldn't find show ID", logger.WARNING) raise exceptions.FailedProcessingFailed() self._log(u"Found show_id: " + str(show_id), logger.DEBUG) self._show_obj = helpers.findCertainShow(sickbeard.showList, show_id) if self._show_obj is None: self._log(u"Could not create show object. Either the show hasn't been added to SickBeard, or it's still loading (if SB was restarted recently)", logger.WARNING) raise exceptions.FailedProcessingFailed() # # Revert before fail, as fail alters the history # self._log(u"Reverting episodes...") # self.log += failed_history.revertEpisodes(self._show_obj, parsed.season_number, parsed.episode_numbers) # self._log(u"Marking release as bad: " + releaseName) # self.log += failed_history.logFailed(releaseName) self.log += failed_history.markFailed(self._show_obj, parsed.season_number, parsed.episode_numbers) self._log(u"Marking release as Failed: " + releaseName) self.log += failed_history.logFailed(releaseName) cur_failed_queue_item = search_queue.FailedQueueItem(self._show_obj, parsed.season_number) sickbeard.searchQueueScheduler.action.add_item(cur_failed_queue_item) return True
def updateShows(self): logger.log(u"Starting trakt show watchlist check", logger.DEBUG) watchlist = TraktCall( "user/watchlist/shows.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) if watchlist is None: logger.log( u"Could not connect to trakt service, aborting watchlist update", logger.DEBUG) return for show in watchlist: if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(show["tvdb_id"], show["title"], SKIPPED) else: self.addDefaultShow(show["tvdb_id"], show["title"], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = helpers.findCertainShow(sickbeard.showList, int(show["tvdb_id"])) if newShow is not None: self.setEpisodeToWanted(newShow, 1, 1) self.startBacklog(newShow) else: self.todoWanted.append((int(show["tvdb_id"]), 1, 1)) if int(sickbeard.TRAKT_METHOD_ADD) == 3: newShow = helpers.findCertainShow(sickbeard.showList, int(show["tvdb_id"])) if newShow is not None: for ep in range(1, 4): self.setEpisodeToWanted(newShow, 1, ep) self.startBacklog(newShow) else: for ep in range(1, 4): self.todoWanted.append((int(show["tvdb_id"]), 1, ep))
def run(self, force=False): self.amActive = True logger.log(u"Searching for new released episodes ...") curDate = datetime.date.today().toordinal() myDB = db.DBConnection() sqlResults = myDB.select( "SELECT * FROM tv_episodes WHERE status = ? AND season > 0 AND airdate <= ?", [common.UNAIRED, curDate]) sql_l = [] show = None for sqlEp in sqlResults: try: if not show or int(sqlEp["showid"]) != show.indexerid: show = helpers.findCertainShow(sickbeard.showList, int(sqlEp["showid"])) except exceptions.MultipleShowObjectsException: logger.log(u"ERROR: expected to find a single show matching " + sqlEp["showid"]) continue ep = show.getEpisode(int(sqlEp["season"]), int(sqlEp["episode"])) with ep.lock: if ep.show.paused: ep.status = common.SKIPPED else: ep.status = common.WANTED sql_l.append(ep.get_sql()) else: logger.log(u"No new released episodes found ...") if len(sql_l) > 0: myDB = db.DBConnection() myDB.mass_action(sql_l) # queue episode for daily search dailysearch_queue_item = sickbeard.search_queue.DailySearchQueueItem() sickbeard.searchQueueScheduler.action.add_item(dailysearch_queue_item) self.amActive = False
def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log(u"Starting trakt episode watchlist check", logger.DEBUG) watchlist = TraktCall( "user/watchlist/episodes.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) if watchlist == 'NULL': logger.log( u"No episodes found in your watchlist, aborting watchlist update", logger.DEBUG) return if not watchlist: logger.log( u"Could not connect to trakt service, aborting watchlist update", logger.ERROR) return for show in watchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["tvrage_id"]) else: indexer_id = int(show["tvdb_id"]) self.addDefaultShow(indexer, indexer_id, show["title"], SKIPPED) newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) try: if newShow and int(newShow['indexer']) == indexer: for episode in show["episodes"]: if newShow is not None: self.setEpisodeToWanted(newShow, episode["season"], episode["number"]) else: self.todoWanted.append( (indexer_id, episode["season"], episode["number"])) self.startBacklog(newShow) except TypeError: logger.log( u"Could not parse the output from trakt for " + show["title"], logger.DEBUG)
def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log(u"Starting trakt episode watchlist check", logger.DEBUG) watchlist = TraktCall("user/watchlist/episodes.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) if watchlist is None: logger.log(u"Could not connect to trakt service, aborting watchlist update", logger.ERROR) return for show in watchlist: self.addDefaultShow(show["tvdb_id"], show["title"], SKIPPED) newShow = helpers.findCertainShow(sickbeard.showList, int(show["tvdb_id"])) for episode in show["episodes"]: if newShow is not None: self.setEpisodeToWanted(newShow, episode["season"], episode["number"]) else: self.todoWanted.append((int(show["tvdb_id"]), episode["season"], episode["number"])) self.startBacklog(newShow)
def find_scene_numbering(indexer_id, season, episode): """ Same as get_scene_numbering(), but returns None if scene numbering is not set """ if indexer_id is None or season is None or episode is None: return (season, episode) showObj = helpers.findCertainShow(sickbeard.showList, indexer_id) if showObj is None: return (season, episode) indexer = showObj.indexer myDB = db.DBConnection() rows = myDB.select( "SELECT scene_season, scene_episode FROM scene_numbering WHERE indexer = ? and indexer_id = ? and season = ? and episode = ?", [indexer, indexer_id, season, episode]) if rows: return (int(rows[0]["scene_season"]), int(rows[0]["scene_episode"]))
def _validate_indexer_id(indexer_id): """ Check that the provided indexer_id is valid and corresponds with a known show :param indexer_id: The indexer id to check :return: A tuple containing: - an error message if the indexer id is not correct, ``None`` otherwise - the show object corresponding to ``indexer_id`` if it exists, ``None`` otherwise """ if indexer_id is None: return 'Invalid show ID', None try: show = findCertainShow(sickbeard.showList, int(indexer_id)) except MultipleShowObjectsException: return 'Unable to find the specified show', None return None, show
def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log(u"Starting trakt episode watchlist check", logger.DEBUG) try: watchlist = self.trakt_api.traktRequest("sync/watchlist/episodes") except (traktException, traktAuthException, traktServerBusy) as e: logger.log(u"Could not connect to Trakt service: %s" % ex(e), logger.WARNING) return if not len(watchlist): logger.log( u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return for show in watchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["show"]["ids"]["tvrage"]) else: indexer_id = int(show["show"]["ids"]["tvdb"]) self.addDefaultShow(indexer, indexer_id, show["show"]["title"], SKIPPED) newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) try: if newShow and newShow.indexer == indexer: for episode in show["episode"]: if newShow is not None: self.setEpisodeToWanted(newShow, episode["season"], episode["number"]) else: self.todoWanted.append( (indexer_id, episode["season"], episode["number"])) except TypeError: logger.log( u"Could not parse the output from trakt for " + show["show"]["title"], logger.DEBUG)
def check_name(self, name): if self.is_basedir: return None so = None my_db = db.DBConnection() sql_results = my_db.select( 'SELECT showid FROM history' + ' WHERE resource = ?' + ' AND (%s)' % ' OR '.join('action LIKE "%%%02d"' % x for x in SNATCHED_ANY) + ' ORDER BY rowid', [name]) if sql_results: try: so = helpers.findCertainShow(sickbeard.showList, int(sql_results[-1]['showid'])) if hasattr(so, 'name'): logger.log('Found Show: %s in snatch history for: %s' % (so.name, name), logger.DEBUG) except MultipleShowObjectsException: so = None return so
def updateShows(self): logger.log(u"Starting trakt show watchlist check", logger.DEBUG) watchlist = TraktCall( "user/watchlist/shows.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) if watchlist == 'NULL': logger.log( u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return if not watchlist: logger.log( u"Could not connect to trakt service, aborting watchlist update", logger.ERROR) return for show in watchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["tvrage_id"]) else: indexer_id = int(show["tvdb_id"]) if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(indexer, indexer_id, show["title"], SKIPPED) else: self.addDefaultShow(indexer, indexer_id, show["title"], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) if newShow is not None: self.setEpisodeToWanted(newShow, 1, 1) self.startBacklog(newShow) else: self.todoWanted.append((indexer_id, 1, 1)) self.todoWanted.append( (indexer_id, -1, -1)) # used to pause new shows if the settings say to
def addDefaultShow(self, tvdbid, name, status): """ Adds a new show with the default settings """ showObj = helpers.findCertainShow(sickbeard.showList, int(tvdbid)) if showObj != None: return logger.log(u"Adding show " + tvdbid) root_dirs = sickbeard.ROOT_DIRS.split('|') location = root_dirs[int(root_dirs[0]) + 1] showPath = ek.ek(os.path.join, location, helpers.sanitizeFileName(name)) dir_exists = helpers.makeDir(showPath) if not dir_exists: logger.log(u"Unable to create the folder " + showPath + ", can't add the show", logger.ERROR) return else: helpers.chmodAsParent(showPath) sickbeard.showQueueScheduler.action.addShow(int(tvdbid), showPath, status, int(sickbeard.QUALITY_DEFAULT), int(sickbeard.FLATTEN_FOLDERS_DEFAULT))
def findPropers(self, search_date=datetime.datetime.today()): results = [] myDB = db.DBConnection() sqlResults = myDB.select( 'SELECT s.show_name, e.showid, e.season, e.episode, e.status, e.airdate FROM tv_episodes AS e' + ' INNER JOIN tv_shows AS s ON (e.showid = s.indexer_id)' + ' WHERE e.airdate >= ' + str(search_date.toordinal()) + ' AND (e.status IN (' + ','.join([str(x) for x in Quality.DOWNLOADED]) + ')' + ' OR (e.status IN (' + ','.join([str(x) for x in Quality.SNATCHED]) + ')))') if not sqlResults: return [] for sqlshow in sqlResults: self.show = curshow = helpers.findCertainShow( sickbeard.showList, int(sqlshow["showid"])) if not self.show: continue curEp = curshow.getEpisode(int(sqlshow["season"]), int(sqlshow["episode"])) proper_searchString = self._get_episode_search_strings( curEp, add_string='PROPER') for item in self._doSearch(proper_searchString[0]): title, url = self._get_title_and_url(item) results.append( classes.Proper(title, url, datetime.datetime.today(), self.show)) repack_searchString = self._get_episode_search_strings( curEp, add_string='REPACK') for item in self._doSearch(repack_searchString[0]): title, url = self._get_title_and_url(item) results.append( classes.Proper(title, url, datetime.datetime.today(), self.show)) return results
def history_snatched_proper_fix(): my_db = db.DBConnection() if not my_db.has_flag('history_snatch_proper'): logger.log( 'Updating history items with status Snatched Proper in a background process...' ) sql_result = my_db.select('SELECT rowid, resource, quality, showid' ' FROM history' ' WHERE action LIKE "%%%02d"' % SNATCHED + ' AND (UPPER(resource) LIKE "%PROPER%"' ' OR UPPER(resource) LIKE "%REPACK%"' ' OR UPPER(resource) LIKE "%REAL%")') if sql_result: cl = [] for r in sql_result: show_obj = None try: show_obj = helpers.findCertainShow(sickbeard.showList, int(r['showid'])) except (StandardError, Exception): pass np = NameParser(False, showObj=show_obj, testing=True) try: pr = np.parse(r['resource']) except (StandardError, Exception): continue if 0 < Quality.get_proper_level(pr.extra_info_no_name(), pr.version, pr.is_anime): cl.append([ 'UPDATE history SET action = ? WHERE rowid = ?', [ Quality.compositeStatus(SNATCHED_PROPER, int(r['quality'])), r['rowid'] ] ]) if cl: my_db.mass_action(cl) logger.log( 'Completed the history table update with status Snatched Proper.' ) my_db.add_flag('history_snatch_proper')
def addEpisodeToTraktWatchList(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log( u"Start looking if some WANTED episode need to be added to watchlist", logger.DEBUG) myDB = db.DBConnection() sql_selection = 'select tv_shows.indexer, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join( [ str(x) for x in Quality.SNATCHED + Quality.SNATCHED_PROPER + [WANTED] ]) + ')' episodes = myDB.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: newShow = helpers.findCertainShow( sickbeard.showList, int(cur_episode["showid"])) if not self.check_watchlist(newShow, cur_episode["season"], cur_episode["episode"]): logger.log( u"Episode: Indexer " + str(cur_episode["indexer"]) + ", indexer_id " + str(cur_episode["showid"]) + ", Title " + str(cur_episode["show_name"]) + " " + str(cur_episode["season"]) + "x" + str(cur_episode["episode"]) + " should be added to watchlist", logger.DEBUG) trakt_data.append( (cur_episode["season"], cur_episode["episode"])) if len(trakt_data): data = notifiers.trakt_notifier.trakt_episode_data_generate( trakt_data) notifiers.trakt_notifier.update_watchlist( newShow, data_episode=data) self._getEpisodeWatchlist() logger.log( u"Stop looking if some WANTED episode need to be added to watchlist", logger.DEBUG)
def addEpisodeToWatchList(self, indexer_id=None): if sickbeard.TRAKT_REMOVE_WATCHLIST and sickbeard.USE_TRAKT: logger.log( u"Start looking if some WANTED episode need to be added to watchlist", logger.DEBUG) myDB = db.DBConnection() sql_selection = 'select tv_shows.indexer, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join( [ str(x) for x in Quality.SNATCHED + Quality.SNATCHED_PROPER + [WANTED] ]) + ')' if indexer_id is None: episodes = myDB.select(sql_selection) else: sql_selection = sql_selection + " and showid=?" episodes = myDB.select(sql_selection, [indexer_id]) if episodes is not None: for cur_episode in episodes: newShow = helpers.findCertainShow( sickbeard.showList, int(cur_episode["showid"])) if not self.episode_in_watchlist(newShow, cur_episode["season"], cur_episode["episode"]): logger.log( u"Episode: Indexer " + str(cur_episode["indexer"]) + ", indexer_id " + str(cur_episode["showid"]) + ", Title " + str(cur_episode["show_name"]) + " " + str(cur_episode["season"]) + "x" + str(cur_episode["episode"]) + " should be added to watchlist", logger.DEBUG) if not self.update_watchlist("episode", "add", newShow, cur_episode["season"], cur_episode["episode"]): return False logger.log( u"Stop looking if some WANTED episode need to be added to watchlist", logger.DEBUG)
def addDefaultShow(indexer, indexer_id, name, status): """ Adds a new show with the default settings """ if not helpers.findCertainShow(sickbeard.showList, int(indexer_id)): logging.info("Adding show " + str(indexer_id)) root_dirs = sickbeard.ROOT_DIRS.split('|') try: location = root_dirs[int(root_dirs[0]) + 1] except Exception: location = None if location: showPath = ek(os.path.join, location, helpers.sanitizeFileName(name)) dir_exists = helpers.makeDir(showPath) if not dir_exists: logging.warning( "Unable to create the folder %s , can't add the show" % showPath) return else: helpers.chmodAsParent(showPath) sickbeard.showQueueScheduler.action.addShow( int(indexer), int(indexer_id), showPath, default_status=status, quality=int(sickbeard.QUALITY_DEFAULT), flatten_folders=int(sickbeard.FLATTEN_FOLDERS_DEFAULT), paused=sickbeard.TRAKT_START_PAUSED, default_status_after=status, archive=sickbeard.ARCHIVE_DEFAULT) else: logging.warning( "There was an error creating the show, no root directory setting found" ) return
def _get_ep_obj(self, tvdb_id, season, episodes): show_obj = None self._log(u"Loading show object for tvdb_id " + str(tvdb_id), logger.DEBUG) # find the show in the showlist try: show_obj = helpers.findCertainShow(sickbeard.showList, tvdb_id) except exceptions.MultipleShowObjectsException: raise #TODO: later I'll just log this, for now I want to know about it ASAP if not show_obj: self._log( u"This show isn't in your list, you need to add it to SB before post-processing an episode", logger.ERROR) raise exceptions.PostProcessingFailed() root_ep = None for cur_episode in episodes: episode = int(cur_episode) self._log( u"Retrieving episode object for " + str(season) + "x" + str(episode), logger.DEBUG) # now that we've figured out which episode this file is just load it manually try: curEp = show_obj.getEpisode(season, episode) except exceptions.EpisodeNotFoundException, e: self._log( u"Unable to create episode: " + str(e).decode('utf-8'), logger.DEBUG) raise exceptions.PostProcessingFailed() if root_ep == None: root_ep = curEp root_ep.relatedEps = [] else: root_ep.relatedEps.append(curEp)
def _addDefaultShow(self, indexer, indexer_id, name, status): """ Adds a new show with the default settings """ if not helpers.findCertainShow(sickbeard.showList, int(indexer_id)): logger.log(u"Adding show " + str(indexer_id)) root_dirs = sickbeard.ROOT_DIRS.split('|') try: location = root_dirs[int(root_dirs[0]) + 1] except: location = None if location: showPath = ek.ek(os.path.join, location, helpers.sanitizeFileName(name)) dir_exists = helpers.makeDir(showPath) if not dir_exists: logger.log( u"Unable to create the folder " + showPath + ", can't add the show", logger.ERROR) return else: helpers.chmodAsParent(showPath) sickbeard.showQueueScheduler.action.addShow( int(indexer), int(indexer_id), showPath, status, int(sickbeard.QUALITY_DEFAULT), int(sickbeard.FLATTEN_FOLDERS_DEFAULT), paused=False, anime=False) else: logger.log( u"There was an error creating the show, no root directory setting found", logger.ERROR) return
def _changeMissingEpisodes(self): logger.log(u"Changing all old missing episodes to status WANTED") curDate = datetime.date.today().toordinal() myDB = db.DBConnection() sqlResults = myDB.select( "SELECT * FROM tv_episodes WHERE status = ? AND airdate < ? AND airdate > 1", [common.UNAIRED, curDate]) for sqlEp in sqlResults: try: show = helpers.findCertainShow(sickbeard.showList, int(sqlEp["showid"])) except exceptions.MultipleShowObjectsException: logger.log(u"ERROR: expected to find a single show matching " + sqlEp["showid"]) return None if show == None: logger.log( u"Unable to find the show with ID " + str(sqlEp["showid"]) + " in your show list! DB value was " + str(sqlEp), logger.ERROR) return None ep = show.getEpisode(sqlEp["season"], sqlEp["episode"]) with ep.lock: if ep.season == 0: # The episode is a special: ignore by default. ep.status = common.IGNORED elif show.paused: ep.status = common.WAITING else: ep.status = common.WAITING ep.saveToDB()
def _addCacheEntry(self, name, url, season=None, episodes=None, tvdb_id=0, tvrage_id=0, quality=None, extraNames=[]): """Return False|None Parse the name and try to get as much info out of it as we can Will use anime regex's if this is called from fanzub On a succesfull parse it will add the parsed infos into the cache.db This dosen't mean the parsed result is usefull """ myDB = self._getDB() show = None if tvdb_id: show = helpers.findCertainShow(sickbeard.showList, tvdb_id) # if we don't have complete info then parse the filename to get it for curName in [name] + extraNames: cp = CompleteParser(show=show) cpr = cp.parse(curName) if cpr.sxxexx and cpr.parse_result: break else: return False episodeText = "|" + "|".join(map(str, cpr.episodes)) + "|" # get the current timestamp curTimestamp = int(time.mktime(datetime.datetime.today().timetuple())) myDB.action( "INSERT INTO " + self.providerID + " (name, season, episodes, tvrid, tvdbid, url, time, quality, release_group, proper) VALUES (?,?,?,?,?,?,?,?,?,?)", [ name, cpr.season, episodeText, 0, cpr.tvdbid, url, curTimestamp, cpr.quality, cpr.release_group, int(cpr.is_proper) ])
def getEpList(epIDs, showid=None): if epIDs == None or len(epIDs) == 0: return [] query = "SELECT * FROM tv_episodes WHERE tvdbid in (%s)" % (",".join(['?'] * len(epIDs)),) params = epIDs if showid != None: query += " AND showid = ?" params.append(showid) myDB = db.DBConnection() sqlResults = myDB.select(query, params) epList = [] for curEp in sqlResults: curShowObj = helpers.findCertainShow(showList, int(curEp["showid"])) curEpObj = curShowObj.getEpisode(int(curEp["season"]), int(curEp["episode"])) epList.append(curEpObj) return epList
def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log(u"Starting trakt episode watchlist check", logger.DEBUG) if not len(self.EpisodeWatchlist): logger.log( u"No episode found in your watchlist, aborting episode update", logger.DEBUG) return managed_show = [] for show in self.EpisodeWatchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["show"]["ids"]["tvrage"]) else: indexer_id = int(show["show"]["ids"]["tvdb"]) newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) try: if newShow is None: if indexer_id not in managed_show: self.addDefaultShow(indexer, indexer_id, show["show"]["title"], SKIPPED) managed_show.append(indexer_id) self.todoWanted.append( (indexer_id, show['episode']['season'], show['episode']['number'])) else: if newShow.indexer == indexer: setEpisodeToWanted(newShow, show['episode']['season'], show['episode']['number']) except TypeError: logger.log( u"Could not parse the output from trakt for " + show["show"]["title"], logger.DEBUG)
def _xem_refresh_needed(indexer_id): """ Is a refresh needed on a show? @param indexer_id: int @return: bool """ if indexer_id is None: return False showObj = helpers.findCertainShow(sickbeard.showList, indexer_id) if showObj is None: return False indexer = showObj.indexer cacheDB = db.DBConnection('cache.db') rows = cacheDB.select( "SELECT last_refreshed FROM xem_refresh WHERE indexer = ? and indexer_id = ?", [indexer, indexer_id]) if rows: return time.time() > (int(rows[0]['last_refreshed']) + MAX_XEM_AGE_SECS) else: return True
def updateShows(self): logger.log(u"Starting trakt show watchlist check", logger.DEBUG) try: watchlist = self.trakt_api.traktRequest("sync/watchlist/shows") except (traktException, traktAuthException, traktServerBusy) as e: logger.log(u"Could not connect to Trakt service: %s" % ex(e), logger.WARNING) return if not len(watchlist): logger.log( u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return for show in watchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == 2: indexer_id = int(show["show"]["ids"]["tvrage"]) else: indexer_id = int(show["show"]["ids"]["tvdb"]) if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(indexer, indexer_id, show["show"]["title"], SKIPPED) else: self.addDefaultShow(indexer, indexer_id, show["show"]["title"], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) if newShow is not None: self.setEpisodeToWanted(newShow, 1, 1) else: self.todoWanted.append((indexer_id, 1, 1))
def updateShows(self): logger.log(u"Start looking if some show need to be added to SickBeard", logger.DEBUG) if self.ShowWatchlist == 'NULL': logger.log(u"Show watchlist is empty", logger.DEBUG) return True for show in self.ShowWatchlist: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) if indexer == INDEXER_TVRAGE: indexer_id = int(show["tvrage_id"]) else: indexer_id = int(show["tvdb_id"]) if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(indexer, indexer_id, show["title"], SKIPPED) else: self.addDefaultShow(indexer, indexer_id, show["title"], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) if newShow is not None: self.setEpisodeToWanted(newShow, 1, 1) if not self.episode_in_watchlist(newShow, 1, 1): if not self.update_watchlist("episode", "add", newShow, 1, 1): return False self.startBacklog(newShow) else: self.todoWanted.append((indexer_id, 1, 1)) self.todoWanted.append( (indexer_id, -1, -1)) # used to pause new shows if the settings say to logger.log(u"Stop looking if some show need to be added to SickBeard", logger.DEBUG)