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