From de5db9be64fd125f0ea61f9a30ccc7284702255b Mon Sep 17 00:00:00 2001 From: echel0n Date: Wed, 23 Jul 2014 21:44:11 -0700 Subject: [PATCH] Added ability to set a default indexer for trakt notifier used for adding shows from watch list so that SickRage knows what indexer to set the show as. Indexer mapping now uses indexer api calls to gather its information and then stores it to a new table called indexer_mapping for instant lookups later on. Fixed trakt related issues for adding new shows and syncing. Centered items at bottom of pages to just look a little nicer and fit properly. --- .../default/config_notifications.tmpl | 14 ++ gui/slick/interfaces/default/inc_bottom.tmpl | 16 +- lib/tvdb_api/tvdb_api.py | 5 + lib/tvrage_api/tvrage_api.py | 2 + sickbeard/__init__.py | 5 +- sickbeard/classes.py | 1 - sickbeard/databases/mainDB.py | 19 +- sickbeard/db.py | 4 + sickbeard/helpers.py | 122 +++++++---- sickbeard/indexers/indexer_api.py | 2 +- sickbeard/name_cache.py | 11 - sickbeard/name_parser/parser.py | 10 +- sickbeard/postProcessor.py | 55 +---- sickbeard/providers/btn.py | 2 +- sickbeard/providers/generic.py | 9 +- sickbeard/providers/newznab.py | 12 +- sickbeard/traktChecker.py | 200 ++++++++++-------- sickbeard/tv.py | 4 +- sickbeard/webapi.py | 23 +- sickbeard/webserve.py | 3 +- 20 files changed, 278 insertions(+), 241 deletions(-) diff --git a/gui/slick/interfaces/default/config_notifications.tmpl b/gui/slick/interfaces/default/config_notifications.tmpl index 1f9d4a96..253c205d 100644 --- a/gui/slick/interfaces/default/config_notifications.tmpl +++ b/gui/slick/interfaces/default/config_notifications.tmpl @@ -1184,6 +1184,20 @@ Get your key at: http://trakt.tv/settings/api +
+ +
+
- + \ No newline at end of file diff --git a/lib/tvdb_api/tvdb_api.py b/lib/tvdb_api/tvdb_api.py index 4a09261b..444d9958 100644 --- a/lib/tvdb_api/tvdb_api.py +++ b/lib/tvdb_api/tvdb_api.py @@ -534,6 +534,11 @@ class Tvdb: self.config['url_seriesBanner'] = u"%(base_url)s/api/%(apikey)s/series/%%s/banners.xml" % self.config self.config['url_artworkPrefix'] = u"%(base_url)s/banners/%%s" % self.config + self.config['url_updates_all'] = u"%(base_url)s/api/%(apikey)s/updates_all.zip" % self.config + self.config['url_updates_month'] = u"%(base_url)s/api/%(apikey)s/updates_month.zip" % self.config + self.config['url_updates_week'] = u"%(base_url)s/api/%(apikey)s/updates_week.zip" % self.config + self.config['url_updates_day'] = u"%(base_url)s/api/%(apikey)s/updates_day.zip" % self.config + def _getTempDir(self): """Returns the [system temp dir]/tvdb_api-u501 (or tvdb_api-myuser) diff --git a/lib/tvrage_api/tvrage_api.py b/lib/tvrage_api/tvrage_api.py index 9aae00d2..296819fa 100644 --- a/lib/tvrage_api/tvrage_api.py +++ b/lib/tvrage_api/tvrage_api.py @@ -377,6 +377,8 @@ class TVRage: self.config['url_seriesInfo'] = u"%(base_url)s/myfeeds/showinfo.php" % self.config self.config['params_seriesInfo'] = {"key": self.config['apikey'], "sid": ""} + self.config['url_updtes_all'] = u"%(base_url)s/myfeeds/currentshows.php" % self.config + def _getTempDir(self): """Returns the [system temp dir]/tvrage_api-u501 (or tvrage_api-myuser) diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 4d3b50fa..f3c928c0 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -357,6 +357,7 @@ TRAKT_METHOD_ADD = 0 TRAKT_START_PAUSED = False TRAKT_USE_RECOMMENDED = False TRAKT_SYNC = False +TRAKT_DEFAULT_INDEXER = None USE_PYTIVO = False PYTIVO_NOTIFY_ONSNATCH = False @@ -447,7 +448,7 @@ def initialize(consoleLogging=True): TORRENT_USERNAME, TORRENT_PASSWORD, TORRENT_HOST, TORRENT_PATH, TORRENT_SEED_TIME, TORRENT_PAUSED, TORRENT_HIGH_BANDWIDTH, TORRENT_LABEL, TORRENT_VERIFY_CERT, \ USE_XBMC, XBMC_ALWAYS_ON, XBMC_NOTIFY_ONSNATCH, XBMC_NOTIFY_ONDOWNLOAD, XBMC_NOTIFY_ONSUBTITLEDOWNLOAD, XBMC_UPDATE_FULL, XBMC_UPDATE_ONLYFIRST, \ XBMC_UPDATE_LIBRARY, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, BACKLOG_FREQUENCY, \ - USE_TRAKT, TRAKT_USERNAME, TRAKT_PASSWORD, TRAKT_API, TRAKT_REMOVE_WATCHLIST, TRAKT_USE_WATCHLIST, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, traktCheckerScheduler, TRAKT_USE_RECOMMENDED, TRAKT_SYNC, \ + USE_TRAKT, TRAKT_USERNAME, TRAKT_PASSWORD, TRAKT_API, TRAKT_REMOVE_WATCHLIST, TRAKT_USE_WATCHLIST, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, traktCheckerScheduler, TRAKT_USE_RECOMMENDED, TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, \ USE_PLEX, PLEX_NOTIFY_ONSNATCH, PLEX_NOTIFY_ONDOWNLOAD, PLEX_NOTIFY_ONSUBTITLEDOWNLOAD, PLEX_UPDATE_LIBRARY, \ PLEX_SERVER_HOST, PLEX_HOST, PLEX_USERNAME, PLEX_PASSWORD, DEFAULT_BACKLOG_FREQUENCY, MIN_BACKLOG_FREQUENCY, BACKLOG_STARTUP, SKIP_REMOVED_FILES, \ showUpdateScheduler, __INITIALIZED__, LAUNCH_BROWSER, UPDATE_SHOWS_ON_START, SORT_ARTICLE, showList, loadingShowList, \ @@ -799,6 +800,7 @@ def initialize(consoleLogging=True): TRAKT_START_PAUSED = bool(check_setting_int(CFG, 'Trakt', 'trakt_start_paused', 0)) TRAKT_USE_RECOMMENDED = bool(check_setting_int(CFG, 'Trakt', 'trakt_use_recommended', 0)) TRAKT_SYNC = bool(check_setting_int(CFG, 'Trakt', 'trakt_sync', 0)) + TRAKT_DEFAULT_INDEXER = check_setting_int(CFG, 'Trakt', 'trakt_default_indexer', 1) CheckSection(CFG, 'pyTivo') USE_PYTIVO = bool(check_setting_int(CFG, 'pyTivo', 'use_pytivo', 0)) @@ -1619,6 +1621,7 @@ def save_config(): new_config['Trakt']['trakt_start_paused'] = int(TRAKT_START_PAUSED) new_config['Trakt']['trakt_use_recommended'] = int(TRAKT_USE_RECOMMENDED) new_config['Trakt']['trakt_sync'] = int(TRAKT_SYNC) + new_config['Trakt']['trakt_default_indexer'] = int(TRAKT_DEFAULT_INDEXER) new_config['pyTivo'] = {} new_config['pyTivo']['use_pytivo'] = int(USE_PYTIVO) diff --git a/sickbeard/classes.py b/sickbeard/classes.py index 268a1bb9..69131317 100644 --- a/sickbeard/classes.py +++ b/sickbeard/classes.py @@ -145,7 +145,6 @@ class TorrentSearchResult(SearchResult): """ resultType = "torrent" - class AllShowsListUI: """ This class is for indexer api. Instead of prompting with a UI to pick the diff --git a/sickbeard/databases/mainDB.py b/sickbeard/databases/mainDB.py index 7bfa4d8f..a8450ea8 100644 --- a/sickbeard/databases/mainDB.py +++ b/sickbeard/databases/mainDB.py @@ -27,7 +27,7 @@ from sickbeard import encodingKludge as ek from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException MIN_DB_VERSION = 9 # oldest db version we support migrating from -MAX_DB_VERSION = 38 +MAX_DB_VERSION = 39 class MainSanityCheck(db.DBSanityCheck): def check(self): @@ -168,7 +168,7 @@ class InitialSchema(db.SchemaUpgrade): "CREATE TABLE info (last_backlog NUMERIC, last_indexer NUMERIC, last_proper_search NUMERIC)", "CREATE TABLE scene_numbering(indexer TEXT, indexer_id INTEGER, season INTEGER, episode INTEGER,scene_season INTEGER, scene_episode INTEGER, PRIMARY KEY(indexer_id, season, episode))", "CREATE TABLE tv_shows (show_id INTEGER PRIMARY KEY, indexer_id NUMERIC, indexer TEXT, show_name TEXT, location TEXT, network TEXT, genre TEXT, classification TEXT, runtime NUMERIC, quality NUMERIC, airs TEXT, status TEXT, flatten_folders NUMERIC, paused NUMERIC, startyear NUMERIC, air_by_date NUMERIC, lang TEXT, subtitles NUMERIC, notify_list TEXT, imdb_id TEXT, last_update_indexer NUMERIC, dvdorder NUMERIC, archive_firstmatch NUMERIC, rls_require_words TEXT, rls_ignore_words TEXT, sports NUMERIC);", - "CREATE TABLE tv_episodes (episode_id INTEGER PRIMARY KEY, showid NUMERIC, indexerid NUMERIC, indexer TEXT, name TEXT, season NUMERIC, episode NUMERIC, description TEXT, airdate NUMERIC, hasnfo NUMERIC, hastbn NUMERIC, status NUMERIC, location TEXT, file_size NUMERIC, release_name TEXT, subtitles TEXT, subtitles_searchcount NUMERIC, subtitles_lastsearch TIMESTAMP, is_proper NUMERIC, scene_season NUMERIC, scene_episode NUMERIC);", + "CREATE TABLE tv_episodes (episode_id INTEGER PRIMARY KEY, showid/ NUMERIC, indexerid NUMERIC, indexer TEXT, name TEXT, season NUMERIC, episode NUMERIC, description TEXT, airdate NUMERIC, hasnfo NUMERIC, hastbn NUMERIC, status NUMERIC, location TEXT, file_size NUMERIC, release_name TEXT, subtitles TEXT, subtitles_searchcount NUMERIC, subtitles_lastsearch TIMESTAMP, is_proper NUMERIC, scene_season NUMERIC, scene_episode NUMERIC);", "CREATE UNIQUE INDEX idx_indexer_id ON tv_shows (indexer_id)", "CREATE INDEX idx_showid ON tv_episodes (showid);", "CREATE INDEX idx_sta_epi_air ON tv_episodes (status,episode, airdate);", @@ -886,3 +886,18 @@ class AddSceneToTvShows(AddXemRefresh): self.incDBVersion() +class AddIndexerMapping(AddSceneToTvShows): + def test(self): + return self.checkDBVersion() >= 39 + + def execute(self): + backupDatabase(39) + + if self.hasTable("indexer_mapping"): + self.connection.action("DROP TABLE indexer_mapping") + + logger.log(u"Adding table indexer_mapping") + self.connection.action( + "CREATE TABLE indexer_mapping (indexer_id INTEGER, indexer NUMERIC, mindexer_id INTEGER, mindexer NUMERIC, PRIMARY KEY (indexer_id, indexer))") + + self.incDBVersion() diff --git a/sickbeard/db.py b/sickbeard/db.py index b0249f4a..fa48b6a1 100644 --- a/sickbeard/db.py +++ b/sickbeard/db.py @@ -321,6 +321,10 @@ def _processUpgrade(connection, upgradeClass): result = connection.select("SELECT db_version FROM db_version") if result: version = int(result[0]["db_version"]) + + # close db before attempting restore + connection.close() + if restoreDatabase(version): # initialize the main SB database upgradeDatabase(DBConnection(), sickbeard.mainDB.InitialSchema) diff --git a/sickbeard/helpers.py b/sickbeard/helpers.py index c51c01eb..82ceca5d 100644 --- a/sickbeard/helpers.py +++ b/sickbeard/helpers.py @@ -62,7 +62,7 @@ from lib import trakt urllib._urlopener = classes.SickBeardURLopener() session = requests.Session() -indexerMap = {} + def indentXML(elem, level=0): ''' @@ -85,6 +85,7 @@ def indentXML(elem, level=0): if level and (not elem.tail or not elem.tail.strip()): elem.tail = i + def remove_extension(name): """ Remove download or media extension from name (if any) @@ -97,6 +98,7 @@ def remove_extension(name): return name + def remove_non_release_groups(name): """ Remove non release groups from name @@ -109,6 +111,7 @@ def remove_non_release_groups(name): return name + def replaceExtension(filename, newExt): ''' >>> replaceExtension('foo.avi', 'mkv') @@ -291,12 +294,10 @@ def findCertainShow(showList, indexerid): if indexerid: results = filter(lambda x: int(x.indexerid) == int(indexerid), showList) - if len(results) == 0: - return None + if len(results): + return results[0] elif len(results) > 1: raise MultipleShowObjectsException() - else: - return results[0] def makeDir(path): @@ -379,9 +380,9 @@ def searchIndexerForShowID(regShowName, indexer=None, indexer_id=None, ui=None): continue if str(name).lower() == str(seriesname).lower and not indexer_id: - return (seriesname, int(sickbeard.indexerApi(i).config['id']), int(series_id)) + return (seriesname, i, int(series_id)) elif int(indexer_id) == int(series_id): - return (seriesname, int(sickbeard.indexerApi(i).config['id']), int(indexer_id)) + return (seriesname, i, int(indexer_id)) if indexer: break @@ -464,7 +465,9 @@ def hardlinkFile(srcFile, destFile): def symlink(src, dst): if os.name == 'nt': import ctypes - if ctypes.windll.kernel32.CreateSymbolicLinkW(unicode(dst), unicode(src), 1 if os.path.isdir(src) else 0) in [0,1280]: raise ctypes.WinError() + + if ctypes.windll.kernel32.CreateSymbolicLinkW(unicode(dst), unicode(src), 1 if os.path.isdir(src) else 0) in [0, + 1280]: raise ctypes.WinError() else: os.symlink(src, dst) @@ -718,26 +721,24 @@ def get_absolute_number_from_season_and_episode(show, season, episode): return None -def get_all_episodes_from_absolute_number(show, indexer_id, absolute_numbers): +def get_all_episodes_from_absolute_number(show, absolute_numbers, indexer_id=None): if len(absolute_numbers) == 0: raise EpisodeNotFoundByAbsoluteNumberException episodes = [] season = None - if not show and not indexer_id: - return (season, episodes) - if not show and indexer_id: show = findCertainShow(sickbeard.showList, indexer_id) - for absolute_number in absolute_numbers: - ep = show.getEpisode(None, None, absolute_number=absolute_number) - if ep: - episodes.append(ep.episode) - else: - raise EpisodeNotFoundByAbsoluteNumberException - season = ep.season # this will always take the last found seson so eps that cross the season border are not handeled well + if show: + for absolute_number in absolute_numbers: + ep = show.getEpisode(None, None, absolute_number=absolute_number) + if ep: + episodes.append(ep.episode) + else: + raise EpisodeNotFoundByAbsoluteNumberException + season = ep.season # this will always take the last found seson so eps that cross the season border are not handeled well return (season, episodes) @@ -1086,26 +1087,31 @@ def _check_against_names(nameInQuestion, show, season=-1): return False -def get_show(name, indexer_id=0, useIndexer=False): +def get_show(name, tryIndexers=False): + if not sickbeard.showList: + return + + showObj = None + fromCache = False + try: # check cache for show - showObj = sickbeard.name_cache.retrieveShowFromCache(name, indexer_id=indexer_id) - if showObj: - return showObj + cache = sickbeard.name_cache.retrieveNameFromCache(name) + if cache: + fromCache = True + showObj = findCertainShow(sickbeard.showList, int(cache)) - if useIndexer and sickbeard.showList and not showObj: - (sn, idx, id) = searchIndexerForShowID(full_sanitizeSceneName(name), ui=classes.ShowListUI) - if id: - showObj = findCertainShow(sickbeard.showList, int(id)) + if not showObj and tryIndexers: + showObj = findCertainShow(sickbeard.showList, + searchIndexerForShowID(full_sanitizeSceneName(name), ui=classes.ShowListUI)[2]) # add show to cache - if showObj: + if showObj and not fromCache: sickbeard.name_cache.addNameToCache(name, showObj.indexerid) + except Exception as e: + logger.log(u"Error when attempting to find show: " + name + " in SickRage: " + str(e), logger.DEBUG) - return showObj - except: - pass - + return showObj def is_hidden_folder(folder): """ @@ -1216,26 +1222,48 @@ def extractZip(archive, targetDir): def mapIndexersToShow(showObj): - global indexerMap + mapped = {showObj.indexer: showObj.indexerid} - mapped = {'tvdb_id': 0, 'tvrage_id': 0} + myDB = db.DBConnection() - if showObj.name in indexerMap: - logger.log(u"Found TVDB<->TVRAGE indexer mapping in cache for show: " + showObj.name, logger.DEBUG) - return indexerMap[showObj.name] + sqlResults = myDB.select( + "SELECT * FROM indexer_mapping WHERE indexer_id = ? AND indexer = ?", + [showObj.indexerid, showObj.indexer]) - logger.log(u"Mapping indexers TVDB<->TVRAGE for show: " + showObj.name, logger.DEBUG) - results = trakt.TraktCall("search/shows.json/%API%?query=" + sanitizeSceneName(showObj.name), - sickbeard.TRAKT_API_KEY) + # for each mapped entry + for curResult in sqlResults: + logger.log(u"Found " + sickbeard.indexerApi(showObj.indexer).name + "<->" + sickbeard.indexerApi( + int(curResult['mindexer'])).name + " mapping in cache for show: " + showObj.name, logger.DEBUG) - if results: - result = filter(lambda x: int(showObj.indexerid) in [int(x['tvdb_id']), int(x['tvrage_id'])], results) - if len(result): - mapped['tvdb_id'] = int(result[0]['tvdb_id']) - mapped['tvrage_id'] = int(result[0]['tvrage_id']) + mapped[int(curResult['mindexer'])] = int(curResult['mindexer_id']) + else: + sql_l = [] + for indexer in sickbeard.indexerApi().indexers: + if indexer == showObj.indexer: + mapped[indexer] = showObj.indexerid + continue - logger.log(u"Adding TVDB<->TVRAGE indexer mapping to cache for show: " + showObj.name, logger.DEBUG) - indexerMap[showObj.name] = mapped + lINDEXER_API_PARMS = sickbeard.indexerApi(indexer).api_params.copy() + lINDEXER_API_PARMS['custom_ui'] = classes.ShowListUI + t = sickbeard.indexerApi(indexer).indexer(**lINDEXER_API_PARMS) + + mapped_show = t[showObj.name] + if len(mapped_show) and not len(mapped_show) > 1: + logger.log(u"Mapping " + sickbeard.indexerApi(showObj.indexer).name + "<->" + sickbeard.indexerApi( + indexer).name + " for show " + showObj.name, + logger.DEBUG) + + mapped[indexer] = int(mapped_show[0]['id']) + + logger.log(u"Adding " + sickbeard.indexerApi(showObj.indexer).name + "<->" + sickbeard.indexerApi( + indexer).name + " mapping to DB for show: " + showObj.name, logger.DEBUG) + + sql_l.append([ + "INSERT OR IGNORE INTO indexer_mapping (indexer_id, indexer, mindexer_id, mindexer) VALUES (?,?,?,?)", + [showObj.indexerid, showObj.indexer, int(mapped_show[0]['id']), indexer]]) + + if len(sql_l) > 0: + myDB.mass_action(sql_l) return mapped diff --git a/sickbeard/indexers/indexer_api.py b/sickbeard/indexers/indexer_api.py index d8467c52..28969e66 100644 --- a/sickbeard/indexers/indexer_api.py +++ b/sickbeard/indexers/indexer_api.py @@ -57,4 +57,4 @@ class indexerApi(object): @property def indexers(self): - return dict((x['id'], x['name']) for x in indexerConfig.values()) \ No newline at end of file + return dict((int(x['id']), x['name']) for x in indexerConfig.values()) \ No newline at end of file diff --git a/sickbeard/name_cache.py b/sickbeard/name_cache.py index fd793cf4..15e208f0 100644 --- a/sickbeard/name_cache.py +++ b/sickbeard/name_cache.py @@ -55,17 +55,6 @@ def retrieveNameFromCache(name): if name in nameCache: return int(nameCache[name]) - -def retrieveShowFromCache(name, indexer_id=0): - global nameCache - - if not indexer_id: - indexer_id = retrieveNameFromCache(name) - - if indexer_id: - return sickbeard.helpers.findCertainShow(sickbeard.showList, int(indexer_id)) - - def clearCache(): """ Deletes all "unknown" entries from the cache (names with indexer_id of 0). diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 12b87949..728cde74 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -35,12 +35,12 @@ class NameParser(object): SPORTS_REGEX = 1 ANIME_REGEX = 2 - def __init__(self, file_name=True, showObj=None, useIndexers=False, convert=False, + def __init__(self, file_name=True, showObj=None, tryIndexers=False, convert=False, naming_pattern=False): self.file_name = file_name self.showObj = showObj - self.useIndexers = useIndexers + self.tryIndexers = tryIndexers self.convert = convert self.naming_pattern = naming_pattern @@ -132,7 +132,7 @@ class NameParser(object): # get show object if not result.show and not self.naming_pattern: - result.show = helpers.get_show(result.series_name, useIndexer=self.useIndexers) + result.show = helpers.get_show(result.series_name, self.tryIndexers) elif self.showObj and self.naming_pattern: result.show = self.showObj @@ -245,7 +245,7 @@ class NameParser(object): for epAbsNo in bestResult.ab_episode_numbers: try: - (s, e) = helpers.get_all_episodes_from_absolute_number(bestResult.show, None, [epAbsNo]) + (s, e) = helpers.get_all_episodes_from_absolute_number(bestResult.show, [epAbsNo]) except exceptions.EpisodeNotFoundByAbsoluteNumberException: pass else: @@ -531,7 +531,7 @@ class ParseResult(object): True, scene_season) if ab: try: - (s, e) = helpers.get_all_episodes_from_absolute_number(self.show, None, [ab]) + (s, e) = helpers.get_all_episodes_from_absolute_number(self.show, [ab]) except exceptions.EpisodeNotFoundByAbsoluteNumberException: logger.log(str(self.show.indexerid) + ": Indexer object absolute number " + str( ab) + " is incomplete, skipping this episode") diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index 790a4040..1c2c511e 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -472,7 +472,7 @@ class PostProcessor(object): name = helpers.remove_non_release_groups(helpers.remove_extension(name)) # parse the name to break it into show name, season, and episode - np = NameParser(file, useIndexers=True, convert=True) + np = NameParser(file, tryIndexers=True, convert=True) parse_result = np.parse(name) # show object @@ -493,54 +493,6 @@ class PostProcessor(object): self._finalize(parse_result) return to_return - def _analyze_anidb(self, filePath): - # TODO: rewrite this - return (None, None, None, None) - - if not helpers.set_up_anidb_connection(): - return (None, None, None, None) - - ep = self._build_anidb_episode(sickbeard.ADBA_CONNECTION, filePath) - try: - self._log(u"Trying to lookup " + str(filePath) + " on anidb", logger.MESSAGE) - ep.load_data() - except Exception, e: - self._log(u"exception msg: " + str(e)) - raise InvalidNameException - else: - self.anidbEpisode = ep - - # TODO: clean code. it looks like it's from hell - for name in ep.allNames: - - indexer_id = name_cache.retrieveNameFromCache(name) - if not indexer_id: - show = helpers.get_show(name) - if show: - indexer_id = show.indexerid - else: - indexer_id = 0 - - if indexer_id: - name_cache.addNameToCache(name, indexer_id) - if indexer_id: - try: - show = helpers.findCertainShow(sickbeard.showList, indexer_id) - (season, episodes) = helpers.get_all_episodes_from_absolute_number(show, None, [ep.epno]) - except exceptions.EpisodeNotFoundByAbsoluteNumberException: - self._log(str(indexer_id) + ": Indexer object absolute number " + str( - ep.epno) + " is incomplete, skipping this episode") - else: - if len(episodes): - self._log(u"Lookup successful from anidb. ", logger.DEBUG) - return (show, season, episodes, None) - - if ep.anidb_file_name: - self._log(u"Lookup successful, using anidb filename " + str(ep.anidb_file_name), logger.DEBUG) - return self._analyze_name(ep.anidb_file_name) - raise InvalidNameException - - def _build_anidb_episode(self, connection, filePath): ep = adba.Episode(connection, filePath=filePath, paramsF=["quality", "anidb_file_name", "crc32"], @@ -583,10 +535,7 @@ class PostProcessor(object): 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), - - # try to analyze the file path with the help of aniDB - lambda: self._analyze_anidb(self.file_path) + lambda: self._analyze_name(self.folder_name + u' ' + self.file_name) ] # attempt every possible method to get our info diff --git a/sickbeard/providers/btn.py b/sickbeard/providers/btn.py index 22af0f01..88f482e7 100644 --- a/sickbeard/providers/btn.py +++ b/sickbeard/providers/btn.py @@ -27,7 +27,7 @@ from sickbeard import classes from sickbeard import scene_exceptions from sickbeard import logger from sickbeard import tvcache -from sickbeard.helpers import sanitizeSceneName, mapIndexersToShow +from sickbeard.helpers import sanitizeSceneName from sickbeard.exceptions import ex, AuthException from lib import jsonrpclib diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py index 6be32027..a18ca573 100644 --- a/sickbeard/providers/generic.py +++ b/sickbeard/providers/generic.py @@ -23,25 +23,26 @@ import datetime import os import re import itertools +import Queue import sickbeard +import requests -from lib import requests -from lib.feedparser import feedparser from sickbeard import helpers, classes, logger, db -from sickbeard.common import MULTI_EP_RESULT, SEASON_RESULT, cpu_presets +from sickbeard.common import MULTI_EP_RESULT, SEASON_RESULT from sickbeard import tvcache from sickbeard import encodingKludge as ek from sickbeard.exceptions import ex -from lib.hachoir_parser import createParser from sickbeard.name_parser.parser import NameParser, InvalidNameException, InvalidShowException from sickbeard.common import Quality +from lib.hachoir_parser import createParser class GenericProvider: NZB = "nzb" TORRENT = "torrent" def __init__(self, name): + self.queue = Queue.Queue() # these need to be set in the subclass self.providerType = None diff --git a/sickbeard/providers/newznab.py b/sickbeard/providers/newznab.py index 33850f78..2a8f536d 100755 --- a/sickbeard/providers/newznab.py +++ b/sickbeard/providers/newznab.py @@ -98,9 +98,9 @@ class NewznabProvider(generic.NZBProvider): cur_params['season'] = str(ep_obj.scene_season) # search - indexers = helpers.mapIndexersToShow(ep_obj.show) - if indexers['tvrage_id']: - cur_params['rid'] = indexers['tvrage_id'] + mindexers = helpers.mapIndexersToShow(ep_obj.show) + if 2 in mindexers: + cur_params['rid'] = mindexers[2] to_return.append(cur_params) else: # add new query strings for exceptions @@ -131,9 +131,9 @@ class NewznabProvider(generic.NZBProvider): params['ep'] = ep_obj.scene_episode # search - indexers = helpers.mapIndexersToShow(ep_obj.show) - if indexers['tvrage_id']: - params['rid'] = indexers['tvrage_id'] + mindexers = helpers.mapIndexersToShow(ep_obj.show) + if 2 in mindexers: + params['rid'] = mindexers[2] to_return.append(params) else: # add new query strings for exceptions diff --git a/sickbeard/traktChecker.py b/sickbeard/traktChecker.py index f08dc1ce..88810ed2 100644 --- a/sickbeard/traktChecker.py +++ b/sickbeard/traktChecker.py @@ -54,15 +54,19 @@ class TraktChecker(): except Exception: logger.log(traceback.format_exc(), logger.DEBUG) - def findShow(self, indexerid): + def findShow(self, indexer, indexerid): library = TraktCall("user/library/shows/all.json/%API%/" + sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) - results = filter(lambda x: int(x['tvdb_id']) == int(indexerid), library) - if len(results) == 0: - return None - else: - return results[0] + if not library: + logger.log(u"Could not connect to trakt service, aborting library check", logger.ERROR) + return + + for show in library: + if int(indexer) == 1 and int(show['tvdb_id']) == int(indexerid): + return show + elif int(indexer) == 2 and int(show['tvrage_id']) == int(indexerid): + return show def syncLibrary(self): logger.log(u"Syncing library to trakt.tv show library", logger.DEBUG) @@ -71,20 +75,23 @@ class TraktChecker(): self.addShowToTraktLibrary(myShow) def removeShowFromTraktLibrary(self, show_obj): - if not self.findShow(show_obj.indexerid): - return + if self.findShow(show_obj.indexer, show_obj.indexerid): + # URL parameters + data = {} + if show_obj.indexer == 1: + data['tvdb_id'] = show_obj.indexerid + data['title'] = show_obj.name + data['year'] = show_obj.startyear - # URL parameters - data = { - 'tvdb_id': show_obj.indexerid, - 'title': show_obj.name, - 'year': show_obj.startyear, - } + elif show_obj.indexer == 2: + data['tvrage_id'] = show_obj.indexerid + data['title'] = show_obj.name + data['year'] = show_obj.startyear - if data is not None: - logger.log(u"Removing " + show_obj.name + " from trakt.tv library", logger.DEBUG) - TraktCall("show/unlibrary/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD, - data) + if data is not None: + logger.log(u"Removing " + show_obj.name + " from trakt.tv library", logger.DEBUG) + TraktCall("show/unlibrary/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD, + data) def addShowToTraktLibrary(self, show_obj): """ @@ -93,20 +100,23 @@ class TraktChecker(): show_obj: The TVShow object to add to trakt """ - if self.findShow(show_obj.indexerid): - return + if not self.findShow(show_obj.indexer, show_obj.indexerid): + # URL parameters + data = {} + if show_obj.indexer == 1: + data['tvdb_id'] = show_obj.indexerid + data['title'] = show_obj.name + data['year'] = show_obj.startyear - # URL parameters - data = { - 'tvdb_id': show_obj.indexerid, - 'title': show_obj.name, - 'year': show_obj.startyear, - } + elif show_obj.indexer == 2: + data['tvrage_id'] = show_obj.indexerid + data['title'] = show_obj.name + data['year'] = show_obj.startyear - if data is not None: - logger.log(u"Adding " + show_obj.name + " to trakt.tv library", logger.DEBUG) - TraktCall("show/library/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD, - data) + if data is not None: + logger.log(u"Adding " + show_obj.name + " to trakt.tv library", logger.DEBUG) + TraktCall("show/library/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD, + data) def updateShows(self): logger.log(u"Starting trakt show watchlist check", logger.DEBUG) @@ -117,19 +127,25 @@ class TraktChecker(): return for show in watchlist: - if int(sickbeard.TRAKT_METHOD_ADD) != 2: - self.addDefaultShow(show["tvdb_id"], show["title"], SKIPPED) + indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) + if indexer == 2: + indexer_id = int(show["tvrage_id"]) else: - self.addDefaultShow(show["tvdb_id"], show["title"], WANTED) + 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, int(show["tvdb_id"])) + newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) if newShow is not None: self.setEpisodeToWanted(newShow, 1, 1) self.startBacklog(newShow) else: - self.todoWanted.append((int(show["tvdb_id"]), 1, 1)) - self.todoWanted.append((int(show["tvdb_id"]), -1, -1)) # used to pause new shows if the settings say to + 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 updateEpisodes(self): """ @@ -143,69 +159,79 @@ class TraktChecker(): return for show in watchlist: - self.addDefaultShow(int(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) + indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) + if indexer == 2: + indexer_id = int(show["tvrage_id"]) + else: + indexer_id = int(show["tvdb_id"]) - def addDefaultShow(self, indexerid, name, status): + self.addDefaultShow(indexer, indexer_id, show["title"], SKIPPED) + newShow = helpers.findCertainShow(sickbeard.showList, indexer_id) + + 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) + + def addDefaultShow(self, indexer, indexer_id, name, status): """ Adds a new show with the default settings """ - if helpers.findCertainShow(sickbeard.showList, int(indexerid)): - return + if not helpers.findCertainShow(sickbeard.showList, int(indexer_id)): + logger.log(u"Adding show " + str(indexer_id)) + root_dirs = sickbeard.ROOT_DIRS.split('|') - logger.log(u"Adding show " + str(indexerid)) - root_dirs = sickbeard.ROOT_DIRS.split('|') + try: + location = root_dirs[int(root_dirs[0]) + 1] + except: + location = None - 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) - 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 + sickbeard.showQueueScheduler.action.addShow(int(indexer), int(indexer_id), showPath, status, + int(sickbeard.QUALITY_DEFAULT), + int(sickbeard.FLATTEN_FOLDERS_DEFAULT)) else: - helpers.chmodAsParent(showPath) - - sickbeard.showQueueScheduler.action.addShow(1, int(indexerid), 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 + logger.log(u"There was an error creating the show, no root directory setting found", logger.ERROR) + return def setEpisodeToWanted(self, show, s, e): """ Sets an episode to wanted, only is it is currently skipped """ epObj = show.getEpisode(int(s), int(e)) - if epObj == None: - return - with epObj.lock: - if epObj.status != SKIPPED: - return - logger.log(u"Setting episode s" + str(s) + "e" + str(e) + " of show " + show.name + " to wanted") - # figure out what segment the episode is in and remember it so we can backlog it - if epObj.show.air_by_date or epObj.show.sports: - ep_segment = str(epObj.airdate)[:7] - else: - ep_segment = epObj.season + if epObj: - epObj.status = WANTED - epObj.saveToDB() + ep_segment = {} - backlog = (show, ep_segment) - if self.todoBacklog.count(backlog) == 0: - self.todoBacklog.append(backlog) + with epObj.lock: + if epObj.status != SKIPPED: + return + + logger.log(u"Setting episode s" + str(s) + "e" + str(e) + " of show " + show.name + " to wanted") + # figure out what segment the episode is in and remember it so we can backlog it + + if epObj.season in ep_segment: + ep_segment[epObj.season].append(epObj) + else: + ep_segment[epObj.season] = [epObj] + + epObj.status = WANTED + epObj.saveToDB() + + backlog = (show, ep_segment) + if self.todoBacklog.count(backlog) == 0: + self.todoBacklog.append(backlog) def manageNewShow(self, show): @@ -223,8 +249,8 @@ class TraktChecker(): for segment in segments: cur_backlog_queue_item = search_queue.BacklogQueueItem(show, segment[1]) sickbeard.searchQueueScheduler.action.add_item(cur_backlog_queue_item) - logger.log(u"Starting backlog for " + show.name + " season " + str( - segment[1]) + " because some eps were set to wanted") - self.todoBacklog.remove(segment) - + for season in segment[1]: + logger.log(u"Starting backlog for " + show.name + " season " + str( + season) + " because some eps were set to wanted") + self.todoBacklog.remove(segment) \ No newline at end of file diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 1176201a..6dc8e887 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -428,7 +428,7 @@ class TVShow(object): try: parse_result = None - np = NameParser(False, showObj=self, useIndexers=True) + np = NameParser(False, showObj=self, tryIndexers=True) parse_result = np.parse(ep_file_name) except (InvalidNameException, InvalidShowException): pass @@ -612,7 +612,7 @@ class TVShow(object): logger.log(str(self.indexerid) + u": Creating episode object from " + file, logger.DEBUG) try: - myParser = NameParser(True, showObj=self, useIndexers=True) + myParser = NameParser(True, showObj=self, tryIndexers=True) parse_result = myParser.parse(file) except InvalidNameException: logger.log(u"Unable to parse the filename " + file + " into a valid episode", logger.DEBUG) diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py index 5d8650a4..7e897ecc 100644 --- a/sickbeard/webapi.py +++ b/sickbeard/webapi.py @@ -975,14 +975,14 @@ class CMD_EpisodeSetStatus(ApiCall): sql_l = [] for epObj in ep_list: - if self.status == WANTED: - # figure out what episodes are wanted so we can backlog them - if epObj.season in ep_segment: - ep_segment[epObj.season].append(epObj) - else: - ep_segment[epObj.season] = [epObj] - with epObj.lock: + if self.status == WANTED: + # figure out what episodes are wanted so we can backlog them + if epObj.season in ep_segment: + ep_segment[epObj.season].append(epObj) + else: + ep_segment[epObj.season] = [epObj] + # don't let them mess up UNAIRED episodes if epObj.status == UNAIRED: if self.e != None: # setting the status of a unaired is only considert a failure if we directly wanted this episode, but is ignored on a season request @@ -1723,6 +1723,8 @@ class CMD_Show(ApiCall): if not showObj: return _responds(RESULT_FAILURE, msg="Show not found") + mindexers = helpers.mapIndexersToShow(showObj) + showDict = {} showDict["season_list"] = CMD_ShowSeasonList(self.handler, (), {"indexerid": self.indexerid}).run()["data"] showDict["cache"] = CMD_ShowCache(self.handler, (), {"indexerid": self.indexerid}).run()["data"] @@ -1753,7 +1755,7 @@ class CMD_Show(ApiCall): showDict["anime"] = showObj.anime #clean up tvdb horrible airs field showDict["airs"] = str(showObj.airs).replace('am', ' AM').replace('pm', ' PM').replace(' ', ' ') - showDict["tvrage_id"] = helpers.mapIndexersToShow(showObj)['tvrage_id'] + showDict["tvrage_id"] = mindexers[2] if 2 in mindexers else 0 showDict["tvrage_name"] = showObj.name showDict["network"] = showObj.network if not showDict["network"]: @@ -2522,6 +2524,7 @@ class CMD_Shows(ApiCall): if self.paused != None and bool(self.paused) != bool(curShow.paused): continue + mindexers = helpers.mapIndexersToShow(curShow) showDict = { "paused": curShow.paused, "quality": _get_quality_string(curShow.quality), @@ -2530,8 +2533,8 @@ class CMD_Shows(ApiCall): "sports": curShow.sports, "anime": curShow.anime, "indexerid": curShow.indexerid, - "tvdbid": helpers.mapIndexersToShow(curShow)['tvdb_id'], - "tvrage_id": helpers.mapIndexersToShow(curShow)['tvrage_id'], + "tvdbid": mindexers[1] if 1 in mindexers else 0, + "tvrage_id": mindexers[2] if 2 in mindexers else 0, "tvrage_name": curShow.name, "network": curShow.network, "show_name": curShow.name, diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 232b9461..ee91d516 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -2213,7 +2213,7 @@ class ConfigNotifications(MainHandler): use_nmjv2=None, nmjv2_host=None, nmjv2_dbloc=None, nmjv2_database=None, use_trakt=None, trakt_username=None, trakt_password=None, trakt_api=None, trakt_remove_watchlist=None, trakt_use_watchlist=None, trakt_method_add=None, - trakt_start_paused=None, trakt_use_recommended=None, trakt_sync=None, + trakt_start_paused=None, trakt_use_recommended=None, trakt_sync=None, trakt_default_indexer=None, use_synologynotifier=None, synologynotifier_notify_onsnatch=None, synologynotifier_notify_ondownload=None, synologynotifier_notify_onsubtitledownload=None, use_pytivo=None, pytivo_notify_onsnatch=None, pytivo_notify_ondownload=None, @@ -2326,6 +2326,7 @@ class ConfigNotifications(MainHandler): sickbeard.TRAKT_START_PAUSED = config.checkbox_to_value(trakt_start_paused) sickbeard.TRAKT_USE_RECOMMENDED = config.checkbox_to_value(trakt_use_recommended) sickbeard.TRAKT_SYNC = config.checkbox_to_value(trakt_sync) + sickbeard.TRAKT_DEFAULT_INDEXER = int(trakt_default_indexer) if sickbeard.USE_TRAKT: sickbeard.traktCheckerScheduler.silent = False