From 29d22b8a8f4f2d667613983a9df53f2c21aa4f37 Mon Sep 17 00:00:00 2001 From: echel0n Date: Sun, 23 Nov 2014 04:08:37 -0800 Subject: [PATCH] Trakt.tv recommend shows and trending shows now work with both TVDB and TVRAGE Indexer's --- lib/trakt/__init__.py | 4 -- sickbeard/helpers.py | 8 ++- sickbeard/webserve.py | 137 ++++++++++++++++++++++-------------------- 3 files changed, 78 insertions(+), 71 deletions(-) diff --git a/lib/trakt/__init__.py b/lib/trakt/__init__.py index 822a5d31..501370ae 100644 --- a/lib/trakt/__init__.py +++ b/lib/trakt/__init__.py @@ -4,10 +4,6 @@ import requests def TraktCall(method, api, username=None, password=None, data={}): base_url = 'http://api.trakt.tv/' - # if the API isn't given then it failed - if not api: - return None - # if username and password given then encode password with sha1 auth = None if username and password: diff --git a/sickbeard/helpers.py b/sickbeard/helpers.py index cca9f5f9..3e8847c8 100644 --- a/sickbeard/helpers.py +++ b/sickbeard/helpers.py @@ -213,8 +213,12 @@ def _remove_file_failed(file): def findCertainShow(showList, indexerid): results = [] - if showList and indexerid: - results = filter(lambda x: int(x.indexerid) == int(indexerid), showList) + + if not isinstance(indexerid, list): + indexerid = [indexerid] + + if showList and len(indexerid): + results = filter(lambda x: int(x.indexerid) in indexerid, showList) if len(results) == 1: return results[0] diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index efd29866..5be66a68 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -84,6 +84,7 @@ from tornado.web import RequestHandler, HTTPError, asynchronous from bug_tracker import BugTracker + def authenticated(handler_class): def wrap_execute(handler_execute): def basicauth(handler, transforms, *args, **kwargs): @@ -101,7 +102,7 @@ def authenticated(handler_class): '/api/builder' not in handler.request.uri): return True elif (handler.request.uri.startswith(sickbeard.WEB_ROOT + '/calendar') and - sickbeard.CALENDAR_UNPROTECTED): + sickbeard.CALENDAR_UNPROTECTED): return True auth_hdr = handler.request.headers.get('Authorization') @@ -394,8 +395,9 @@ class MainHandler(RequestHandler): # add localtime to the dict for index, item in enumerate(sql_results): - sql_results[index]['localtime'] = sbdatetime.sbdatetime.convert_to_setting(network_timezones.parse_date_time(item['airdate'], - item['airs'], item['network'])) + sql_results[index]['localtime'] = sbdatetime.sbdatetime.convert_to_setting( + network_timezones.parse_date_time(item['airdate'], + item['airs'], item['network'])) sql_results.sort(sorts[sickbeard.COMING_EPS_SORT]) @@ -424,7 +426,7 @@ class MainHandler(RequestHandler): t.sql_results = sql_results # Allow local overriding of layout parameter - if layout and layout in ('poster', 'banner', 'list','calendar'): + if layout and layout in ('poster', 'banner', 'list', 'calendar'): t.layout = layout else: t.layout = sickbeard.COMING_EPS_LAYOUT @@ -487,7 +489,8 @@ class MainHandler(RequestHandler): ical = ical + 'DESCRIPTION:' + show['airs'] + ' on ' + show['network'] + '\\n\\n' + \ episode['description'].splitlines()[0] + '\r\n' else: - ical = ical + 'DESCRIPTION:' + (show['airs'] or '(Unknown airs)') + ' on ' + (show['network'] or 'Unknown network') + '\r\n' + ical = ical + 'DESCRIPTION:' + (show['airs'] or '(Unknown airs)') + ' on ' + ( + show['network'] or 'Unknown network') + '\r\n' ical = ical + 'END:VEVENT\r\n' @@ -1074,7 +1077,8 @@ class Manage(MainHandler): return _munge(t) - def massEditSubmit(self, archive_firstmatch=None, paused=None, anime=None, sports=None, scene=None, flatten_folders=None, + def massEditSubmit(self, archive_firstmatch=None, paused=None, anime=None, sports=None, scene=None, + flatten_folders=None, quality_preset=False, subtitles=None, air_by_date=None, anyQualities=[], bestQualities=[], toEdit=None, *args, **kwargs): @@ -1179,7 +1183,8 @@ class Manage(MainHandler): redirect("/manage/") - def massUpdate(self, toUpdate=None, toRefresh=None, toRename=None, toDelete=None, toRemove=None, toMetadata=None, toSubtitle=None): + def massUpdate(self, toUpdate=None, toRefresh=None, toRename=None, toDelete=None, toRemove=None, toMetadata=None, + toSubtitle=None): if toUpdate is not None: toUpdate = toUpdate.split('|') @@ -1515,11 +1520,13 @@ class ConfigGeneral(MainHandler): def saveGeneral(self, log_dir=None, web_port=None, web_log=None, encryption_version=None, web_ipv6=None, - update_shows_on_start=None, trash_remove_show=None, trash_rotate_logs=None, update_frequency=None, launch_browser=None, web_username=None, + update_shows_on_start=None, trash_remove_show=None, trash_rotate_logs=None, update_frequency=None, + launch_browser=None, web_username=None, use_api=None, api_key=None, indexer_default=None, timezone_display=None, cpu_preset=None, web_password=None, version_notify=None, enable_https=None, https_cert=None, https_key=None, handle_reverse_proxy=None, sort_article=None, auto_update=None, notify_on_update=None, - proxy_setting=None, proxy_indexers=None, anon_redirect=None, git_path=None, git_remote=None, calendar_unprotected=None, + proxy_setting=None, proxy_indexers=None, anon_redirect=None, git_path=None, git_remote=None, + calendar_unprotected=None, fuzzy_dating=None, trim_zero=None, date_preset=None, date_preset_na=None, time_preset=None, indexer_timeout=None, play_videos=None, rootDir=None, theme_name=None): @@ -1671,7 +1678,8 @@ class ConfigSearch(MainHandler): backlog_startup=None, dailysearch_startup=None, torrent_dir=None, torrent_username=None, torrent_password=None, torrent_host=None, torrent_label=None, torrent_path=None, torrent_verify_cert=None, - torrent_seed_time=None, torrent_paused=None, torrent_high_bandwidth=None, ignore_words=None, require_words=None): + torrent_seed_time=None, torrent_paused=None, torrent_high_bandwidth=None, ignore_words=None, + require_words=None): results = [] @@ -1753,7 +1761,8 @@ class ConfigPostProcessing(MainHandler): wdtv_data=None, tivo_data=None, mede8er_data=None, keep_processed_dir=None, process_method=None, process_automatically=None, rename_episodes=None, airdate_episodes=None, unpack=None, - move_associated_files=None, postpone_if_sync_files=None, nfo_rename=None, tv_download_dir=None, naming_custom_abd=None, + move_associated_files=None, postpone_if_sync_files=None, nfo_rename=None, + tv_download_dir=None, naming_custom_abd=None, naming_anime=None, naming_abd_pattern=None, naming_strip_year=None, use_failed_downloads=None, delete_failed=None, extra_scripts=None, skip_removed_files=None, @@ -1783,7 +1792,6 @@ class ConfigPostProcessing(MainHandler): except: pass - if unpack: if self.isRarSupported() != 'not supported': sickbeard.UNPACK = config.checkbox_to_value(unpack) @@ -2004,17 +2012,17 @@ class ConfigProviders(MainHandler): error += "\nNo Provider Api key specified" if error <> "": - return json.dumps({'success' : False, 'error': error}) + return json.dumps({'success': False, 'error': error}) - #Get list with Newznabproviders - #providerDict = dict(zip([x.getID() for x in sickbeard.newznabProviderList], sickbeard.newznabProviderList)) + # Get list with Newznabproviders + # providerDict = dict(zip([x.getID() for x in sickbeard.newznabProviderList], sickbeard.newznabProviderList)) - #Get newznabprovider obj with provided name - tempProvider= newznab.NewznabProvider(name, url, key) + # Get newznabprovider obj with provided name + tempProvider = newznab.NewznabProvider(name, url, key) success, tv_categories, error = tempProvider.get_newznab_categories() - return json.dumps({'success' : success,'tv_categories' : tv_categories, 'error' : error}) + return json.dumps({'success': success, 'tv_categories': tv_categories, 'error': error}) def deleteNewznabProvider(self, nnid): @@ -2310,14 +2318,14 @@ class ConfigProviders(MainHandler): curTorrentProvider.enable_daily = config.checkbox_to_value( kwargs[curTorrentProvider.getID() + '_enable_daily']) except: - curTorrentProvider.enable_daily = 0 # these exceptions are actually catching unselected checkboxes + curTorrentProvider.enable_daily = 0 # these exceptions are actually catching unselected checkboxes if hasattr(curTorrentProvider, 'enable_backlog'): try: curTorrentProvider.enable_backlog = config.checkbox_to_value( kwargs[curTorrentProvider.getID() + '_enable_backlog']) except: - curTorrentProvider.enable_backlog = 0 # these exceptions are actually catching unselected checkboxes + curTorrentProvider.enable_backlog = 0 # these exceptions are actually catching unselected checkboxes for curNzbProvider in [curProvider for curProvider in sickbeard.providers.sortedProviderList() if curProvider.providerType == sickbeard.GenericProvider.NZB]: @@ -2959,19 +2967,13 @@ class NewHomeAddShows(MainHandler): recommendedlist = TraktCall("recommendations/shows.json/%API%", sickbeard.TRAKT_API, sickbeard.TRAKT_USERNAME, sickbeard.TRAKT_PASSWORD) - if recommendedlist == 'NULL': - logger.log(u"No shows found in your recommendedlist, aborting recommendedlist update", logger.DEBUG) - return - - if recommendedlist is None: - logger.log(u"Could not connect to trakt service, aborting recommended list update", logger.ERROR) - return - - map(final_results.append, - ([int(show['tvdb_id'] or 0) if sickbeard.TRAKT_DEFAULT_INDEXER == 1 else int(show['tvdb_id'] or 0), - show['url'], show['title'], show['overview'], - datetime.date.fromtimestamp(int(show['first_aired']) / 1000.0).strftime('%Y%m%d')] for show in - recommendedlist if not helpers.findCertainShow(sickbeard.showList, indexerid=int(show['tvdb_id'])))) + if recommendedlist: + indexers = ['tvdb_id', 'tvrage_id'] + map(final_results.append, ( + [int(show[indexers[sickbeard.TRAKT_DEFAULT_INDEXER - 1]]), show['url'], show['title'], show['overview'], + datetime.date.fromtimestamp(int(show['first_aired']) / 1000.0).strftime('%Y%m%d')] + for show in recommendedlist if not helpers.findCertainShow(sickbeard.showList, [ + int(show[indexers[sickbeard.TRAKT_DEFAULT_INDEXER - 1]])]))) return json.dumps({'results': final_results}) @@ -3000,12 +3002,13 @@ class NewHomeAddShows(MainHandler): t = PageTemplate(headers=self.request.headers, file="home_trendingShows.tmpl") t.submenu = HomeMenu() - t.trending_shows = TraktCall("shows/trending.json/%API%", sickbeard.TRAKT_API_KEY) + t.trending_shows = [] - if None is not t.trending_shows: - for item in t.trending_shows: - if helpers.findCertainShow(sickbeard.showList, int(item['tvdb_id'])): - item['tvdb_id'] = u'ExistsInLibrary' + trending_shows = TraktCall("shows/trending.json/%API%", sickbeard.TRAKT_API_KEY) + if trending_shows: + for show in trending_shows: + if not helpers.findCertainShow(sickbeard.showList, [int(show['tvdb_id']), int(show['tvrage_id'])]): + t.trending_shows += [show] return _munge(t) @@ -4088,8 +4091,8 @@ class Home(MainHandler): ui.notifications.message('%s has been %s %s' % (showObj.name, - ('deleted', 'trashed')[sickbeard.TRASH_REMOVE_SHOW], - ('(media untouched)', '(with all related media)')[bool(full)])) + ('deleted', 'trashed')[sickbeard.TRASH_REMOVE_SHOW], + ('(media untouched)', '(with all related media)')[bool(full)])) redirect("/home/") @@ -4407,7 +4410,8 @@ class Home(MainHandler): sickbeard.searchQueueScheduler.action.add_item(ep_queue_item) # @UndefinedVariable if not ep_queue_item.started and ep_queue_item.success is None: - return json.dumps({'result': 'success'}) #I Actually want to call it queued, because the search hasnt been started yet! + return json.dumps( + {'result': 'success'}) # I Actually want to call it queued, because the search hasnt been started yet! if ep_queue_item.started and ep_queue_item.success is None: return json.dumps({'result': 'success'}) else: @@ -4431,7 +4435,7 @@ class Home(MainHandler): currentManualSearchThreadActive = sickbeard.searchQueueScheduler.action.currentItem # Finished Searches - finishedManualSearchThreadItems = sickbeard.search_queue.MANUAL_SEARCH_HISTORY + finishedManualSearchThreadItems = sickbeard.search_queue.MANUAL_SEARCH_HISTORY if currentManualSearchThreadsQueued: for searchThread in currentManualSearchThreadsQueued: @@ -4439,18 +4443,18 @@ class Home(MainHandler): if isinstance(searchThread, sickbeard.search_queue.ManualSearchQueueItem): episodes.append({'episode': searchThread.segment.episode, 'episodeindexid': searchThread.segment.indexerid, - 'season' : searchThread.segment.season, - 'searchstatus' : searchstatus, - 'status' : statusStrings[searchThread.segment.status], + 'season': searchThread.segment.season, + 'searchstatus': searchstatus, + 'status': statusStrings[searchThread.segment.status], 'quality': self.getQualityClass(searchThread.segment)}) else: for epObj in searchThread.segment: episodes.append({'episode': epObj.episode, - 'episodeindexid': epObj.indexerid, - 'season' : epObj.season, - 'searchstatus' : searchstatus, - 'status' : statusStrings[epObj.status], - 'quality': self.getQualityClass(epObj)}) + 'episodeindexid': epObj.indexerid, + 'season': epObj.season, + 'searchstatus': searchstatus, + 'status': statusStrings[epObj.status], + 'quality': self.getQualityClass(epObj)}) if currentManualSearchThreadActive: searchThread = currentManualSearchThreadActive @@ -4461,22 +4465,23 @@ class Home(MainHandler): searchstatus = 'searching' episodes.append({'episode': searchThread.segment.episode, 'episodeindexid': searchThread.segment.indexerid, - 'season' : searchThread.segment.season, - 'searchstatus' : searchstatus, - 'status' : statusStrings[searchThread.segment.status], + 'season': searchThread.segment.season, + 'searchstatus': searchstatus, + 'status': statusStrings[searchThread.segment.status], 'quality': self.getQualityClass(searchThread.segment)}) if finishedManualSearchThreadItems: for searchThread in finishedManualSearchThreadItems: if isinstance(searchThread, sickbeard.search_queue.ManualSearchQueueItem): - if str(searchThread.show.indexerid) == show and not [x for x in episodes if x['episodeindexid'] == searchThread.segment.indexerid]: + if str(searchThread.show.indexerid) == show and not [x for x in episodes if x[ + 'episodeindexid'] == searchThread.segment.indexerid]: searchstatus = 'finished' episodes.append({'episode': searchThread.segment.episode, 'episodeindexid': searchThread.segment.indexerid, - 'season' : searchThread.segment.season, - 'searchstatus' : searchstatus, - 'status' : statusStrings[searchThread.segment.status], - 'quality': self.getQualityClass(searchThread.segment)}) + 'season': searchThread.segment.season, + 'searchstatus': searchstatus, + 'status': statusStrings[searchThread.segment.status], + 'quality': self.getQualityClass(searchThread.segment)}) else: ### These are only Failed Downloads/Retry SearchThreadItems.. lets loop through the segement/episodes if str(searchThread.show.indexerid) == show: @@ -4485,12 +4490,12 @@ class Home(MainHandler): searchstatus = 'finished' episodes.append({'episode': epObj.episode, 'episodeindexid': epObj.indexerid, - 'season' : epObj.season, - 'searchstatus' : searchstatus, - 'status' : statusStrings[epObj.status], - 'quality': self.getQualityClass(epObj)}) + 'season': epObj.season, + 'searchstatus': searchstatus, + 'status': statusStrings[epObj.status], + 'quality': self.getQualityClass(epObj)}) - return json.dumps({'show': show, 'episodes' : episodes}) + return json.dumps({'show': show, 'episodes': episodes}) def getQualityClass(self, ep_obj): # return the correct json value @@ -4528,7 +4533,8 @@ class Home(MainHandler): status = 'No subtitles downloaded' ui.notifications.message('Subtitles Search', status) return json.dumps({'result': status, 'subtitles': ','.join(sorted([x.alpha2 for x in - ep_obj.subtitles.union(previous_subtitles)]))}) + ep_obj.subtitles.union( + previous_subtitles)]))}) def setSceneNumbering(self, show, indexer, forSeason=None, forEpisode=None, forAbsolute=None, sceneSeason=None, sceneEpisode=None, sceneAbsolute=None): @@ -4616,7 +4622,8 @@ class Home(MainHandler): sickbeard.searchQueueScheduler.action.add_item(ep_queue_item) # @UndefinedVariable if not ep_queue_item.started and ep_queue_item.success is None: - return json.dumps({'result': 'success'}) #I Actually want to call it queued, because the search hasnt been started yet! + return json.dumps( + {'result': 'success'}) # I Actually want to call it queued, because the search hasnt been started yet! if ep_queue_item.started and ep_queue_item.success is None: return json.dumps({'result': 'success'}) else: