From 860defdfc00fc73c1e9f893a30e02b71175c9043 Mon Sep 17 00:00:00 2001 From: MoojMidge <56883549+MoojMidge@users.noreply.github.com> Date: Fri, 15 Dec 2023 15:05:27 +1100 Subject: [PATCH] Use same response/error hooks for Youtube.perform_v3_request - Partially fixes #545 - Remove the other handle_error methods --- .../lib/youtube_plugin/kodion/utils/player.py | 11 +- .../youtube_plugin/youtube/client/youtube.py | 408 +++++++++++++----- .../lib/youtube_plugin/youtube/helper/v3.py | 34 -- .../youtube_plugin/youtube/helper/yt_play.py | 13 +- .../youtube/helper/yt_playlist.py | 10 +- .../youtube/helper/yt_specials.py | 18 +- .../youtube/helper/yt_subscriptions.py | 6 +- .../youtube_plugin/youtube/helper/yt_video.py | 2 +- .../lib/youtube_plugin/youtube/provider.py | 13 +- resources/lib/youtube_requests.py | 121 ++++-- 10 files changed, 422 insertions(+), 214 deletions(-) diff --git a/resources/lib/youtube_plugin/kodion/utils/player.py b/resources/lib/youtube_plugin/kodion/utils/player.py index 830f299c6..8c3adc136 100644 --- a/resources/lib/youtube_plugin/kodion/utils/player.py +++ b/resources/lib/youtube_plugin/kodion/utils/player.py @@ -348,17 +348,11 @@ def run(self): json_data = client.remove_video_from_playlist( watch_later_id, playlist_item_id ) - _ = self.provider.v3_handle_error(self.provider, - self._context, - json_data) history_playlist_id = access_manager.get_watch_history_id() if history_playlist_id and history_playlist_id != 'HL': json_data = client.add_video_to_playlist(history_playlist_id, self.video_id) - _ = self.provider.v3_handle_error(self.provider, - self._context, - json_data) # rate video if settings.get_bool('youtube.post.play.rate', False): @@ -370,10 +364,7 @@ def run(self): if do_rating: json_data = client.get_video_rating(self.video_id) - success = self.provider.v3_handle_error(self.provider, - self._context, - json_data) - if success: + if json_data: items = json_data.get('items', [{'rating': 'none'}]) rating = items[0].get('rating', 'none') if rating == 'none': diff --git a/resources/lib/youtube_plugin/youtube/client/youtube.py b/resources/lib/youtube_plugin/youtube/client/youtube.py index 002267b0f..741b56d52 100644 --- a/resources/lib/youtube_plugin/youtube/client/youtube.py +++ b/resources/lib/youtube_plugin/youtube/client/youtube.py @@ -11,15 +11,15 @@ from __future__ import absolute_import, division, unicode_literals import copy -import json import re import threading import xml.etree.ElementTree as ET from .login_client import LoginClient from ..helper.video_info import VideoInfo +from ..youtube_exceptions import InvalidJSON, YouTubeException from ...kodion import Context -from ...kodion.utils import datetime_parser, to_unicode +from ...kodion.utils import datetime_parser, strip_html_from_text, to_unicode _context = Context(plugin_id='plugin.video.youtube') @@ -153,52 +153,76 @@ def get_video_streams(self, context, video_id): return video_streams - def remove_playlist(self, playlist_id): + def remove_playlist(self, playlist_id, **kwargs): params = {'id': playlist_id, 'mine': 'true'} - return self.perform_v3_request(method='DELETE', path='playlists', params=params) + return self.perform_v3_request(method='DELETE', + path='playlists', + params=params, + **kwargs) - def get_supported_languages(self, language=None): + def get_supported_languages(self, language=None, **kwargs): _language = language if not _language: _language = self._language _language = _language.replace('-', '_') params = {'part': 'snippet', 'hl': _language} - return self.perform_v3_request(method='GET', path='i18nLanguages', params=params) + return self.perform_v3_request(method='GET', + path='i18nLanguages', + params=params, + **kwargs) - def get_supported_regions(self, language=None): + def get_supported_regions(self, language=None, **kwargs): _language = language if not _language: _language = self._language _language = _language.replace('-', '_') params = {'part': 'snippet', 'hl': _language} - return self.perform_v3_request(method='GET', path='i18nRegions', params=params) - - def rename_playlist(self, playlist_id, new_title, privacy_status='private'): + return self.perform_v3_request(method='GET', + path='i18nRegions', + params=params, + **kwargs) + + def rename_playlist(self, + playlist_id, + new_title, + privacy_status='private', + **kwargs): params = {'part': 'snippet,id,status'} post_data = {'kind': 'youtube#playlist', 'id': playlist_id, 'snippet': {'title': new_title}, 'status': {'privacyStatus': privacy_status}} - return self.perform_v3_request(method='PUT', path='playlists', params=params, post_data=post_data) + return self.perform_v3_request(method='PUT', + path='playlists', + params=params, + post_data=post_data, + **kwargs) - def create_playlist(self, title, privacy_status='private'): + def create_playlist(self, title, privacy_status='private', **kwargs): params = {'part': 'snippet,status'} post_data = {'kind': 'youtube#playlist', 'snippet': {'title': title}, 'status': {'privacyStatus': privacy_status}} - return self.perform_v3_request(method='POST', path='playlists', params=params, post_data=post_data) + return self.perform_v3_request(method='POST', + path='playlists', + params=params, + post_data=post_data, + **kwargs) - def get_video_rating(self, video_id): + def get_video_rating(self, video_id, **kwargs): if isinstance(video_id, list): video_id = ','.join(video_id) params = {'id': video_id} - return self.perform_v3_request(method='GET', path='videos/getRating', params=params) + return self.perform_v3_request(method='GET', + path='videos/getRating', + params=params, + **kwargs) - def rate_video(self, video_id, rating='like'): + def rate_video(self, video_id, rating='like', **kwargs): """ Rate a video :param video_id: if of the video @@ -207,34 +231,58 @@ def rate_video(self, video_id, rating='like'): """ params = {'id': video_id, 'rating': rating} - return self.perform_v3_request(method='POST', path='videos/rate', params=params) + return self.perform_v3_request(method='POST', + path='videos/rate', + params=params, + **kwargs) - def add_video_to_playlist(self, playlist_id, video_id): + def add_video_to_playlist(self, playlist_id, video_id, **kwargs): params = {'part': 'snippet', 'mine': 'true'} post_data = {'kind': 'youtube#playlistItem', 'snippet': {'playlistId': playlist_id, 'resourceId': {'kind': 'youtube#video', 'videoId': video_id}}} - return self.perform_v3_request(method='POST', path='playlistItems', params=params, post_data=post_data) + return self.perform_v3_request(method='POST', + path='playlistItems', + params=params, + post_data=post_data, + **kwargs) # noinspection PyUnusedLocal - def remove_video_from_playlist(self, playlist_id, playlist_item_id): + def remove_video_from_playlist(self, + playlist_id, + playlist_item_id, + **kwargs): params = {'id': playlist_item_id} - return self.perform_v3_request(method='DELETE', path='playlistItems', params=params) + return self.perform_v3_request(method='DELETE', + path='playlistItems', + params=params, + **kwargs) - def unsubscribe(self, subscription_id): + def unsubscribe(self, subscription_id, **kwargs): params = {'id': subscription_id} - return self.perform_v3_request(method='DELETE', path='subscriptions', params=params) + return self.perform_v3_request(method='DELETE', + path='subscriptions', + params=params, + **kwargs) - def subscribe(self, channel_id): + def subscribe(self, channel_id, **kwargs): params = {'part': 'snippet'} post_data = {'kind': 'youtube#subscription', 'snippet': {'resourceId': {'kind': 'youtube#channel', 'channelId': channel_id}}} - return self.perform_v3_request(method='POST', path='subscriptions', params=params, post_data=post_data) - - def get_subscription(self, channel_id, order='alphabetical', page_token=''): + return self.perform_v3_request(method='POST', + path='subscriptions', + params=params, + post_data=post_data, + **kwargs) + + def get_subscription(self, + channel_id, + order='alphabetical', + page_token='', + **kwargs): """ :param channel_id: [channel-id|'mine'] @@ -252,9 +300,12 @@ def get_subscription(self, channel_id, order='alphabetical', page_token=''): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='subscriptions', params=params) + return self.perform_v3_request(method='GET', + path='subscriptions', + params=params, + **kwargs) - def get_guide_category(self, guide_category_id, page_token=''): + def get_guide_category(self, guide_category_id, page_token='', **kwargs): params = {'part': 'snippet,contentDetails,brandingSettings', 'maxResults': str(self._max_results), 'categoryId': guide_category_id, @@ -262,9 +313,12 @@ def get_guide_category(self, guide_category_id, page_token=''): 'hl': self._language} if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='channels', params=params) + return self.perform_v3_request(method='GET', + path='channels', + params=params, + **kwargs) - def get_guide_categories(self, page_token=''): + def get_guide_categories(self, page_token='', **kwargs): params = {'part': 'snippet', 'maxResults': str(self._max_results), 'regionCode': self._region, @@ -272,9 +326,12 @@ def get_guide_categories(self, page_token=''): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='guideCategories', params=params) + return self.perform_v3_request(method='GET', + path='guideCategories', + params=params, + **kwargs) - def get_popular_videos(self, page_token=''): + def get_popular_videos(self, page_token='', **kwargs): params = {'part': 'snippet,status', 'maxResults': str(self._max_results), 'regionCode': self._region, @@ -282,9 +339,12 @@ def get_popular_videos(self, page_token=''): 'chart': 'mostPopular'} if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='videos', params=params) + return self.perform_v3_request(method='GET', + path='videos', + params=params, + **kwargs) - def get_video_category(self, video_category_id, page_token=''): + def get_video_category(self, video_category_id, page_token='', **kwargs): params = {'part': 'snippet,contentDetails,status', 'maxResults': str(self._max_results), 'videoCategoryId': video_category_id, @@ -293,9 +353,12 @@ def get_video_category(self, video_category_id, page_token=''): 'hl': self._language} if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='videos', params=params) + return self.perform_v3_request(method='GET', + path='videos', + params=params, + **kwargs) - def get_video_categories(self, page_token=''): + def get_video_categories(self, page_token='', **kwargs): params = {'part': 'snippet', 'maxResults': str(self._max_results), 'regionCode': self._region, @@ -303,7 +366,10 @@ def get_video_categories(self, page_token=''): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='videoCategories', params=params) + return self.perform_v3_request(method='GET', + path='videoCategories', + params=params, + **kwargs) def _get_recommendations_for_home(self): # YouTube has deprecated this API, so use history and related items to form @@ -443,7 +509,7 @@ def _sort_by_date_time(item): # If there are no sorted_items we fall back to default API behaviour return payload - def get_activities(self, channel_id, page_token=''): + def get_activities(self, channel_id, page_token='', **kwargs): params = {'part': 'snippet,contentDetails', 'maxResults': str(self._max_results), 'regionCode': self._region, @@ -462,9 +528,12 @@ def get_activities(self, channel_id, page_token=''): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='activities', params=params) + return self.perform_v3_request(method='GET', + path='activities', + params=params, + **kwargs) - def get_channel_sections(self, channel_id): + def get_channel_sections(self, channel_id, **kwargs): params = {'part': 'snippet,contentDetails', 'regionCode': self._region, 'hl': self._language} @@ -472,9 +541,12 @@ def get_channel_sections(self, channel_id): params['mine'] = 'true' else: params['channelId'] = channel_id - return self.perform_v3_request(method='GET', path='channelSections', params=params) + return self.perform_v3_request(method='GET', + path='channelSections', + params=params, + **kwargs) - def get_playlists_of_channel(self, channel_id, page_token=''): + def get_playlists_of_channel(self, channel_id, page_token='', **kwargs): params = {'part': 'snippet', 'maxResults': str(self._max_results)} if channel_id != 'mine': @@ -484,7 +556,10 @@ def get_playlists_of_channel(self, channel_id, page_token=''): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='playlists', params=params) + return self.perform_v3_request(method='GET', + path='playlists', + params=params, + **kwargs) def get_playlist_item_id_of_video_id(self, playlist_id, video_id, page_token=''): old_max_results = self._max_results @@ -506,7 +581,11 @@ def get_playlist_item_id_of_video_id(self, playlist_id, video_id, page_token='') return None - def get_playlist_items(self, playlist_id, page_token='', max_results=None): + def get_playlist_items(self, + playlist_id, + page_token='', + max_results=None, + **kwargs): # prepare params max_results = str(self._max_results) if max_results is None else str(max_results) params = {'part': 'snippet', @@ -515,9 +594,12 @@ def get_playlist_items(self, playlist_id, page_token='', max_results=None): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='playlistItems', params=params) + return self.perform_v3_request(method='GET', + path='playlistItems', + params=params, + **kwargs) - def get_channel_by_username(self, username): + def get_channel_by_username(self, username, **kwargs): """ Returns a collection of zero or more channel resources that match the request criteria. :param username: retrieve channel_id for username @@ -529,9 +611,12 @@ def get_channel_by_username(self, username): else: params.update({'forUsername': username}) - return self.perform_v3_request(method='GET', path='channels', params=params) + return self.perform_v3_request(method='GET', + path='channels', + params=params, + **kwargs) - def get_channels(self, channel_id): + def get_channels(self, channel_id, **kwargs): """ Returns a collection of zero or more channel resources that match the request criteria. :param channel_id: list or comma-separated list of the YouTube channel ID(s) @@ -545,9 +630,12 @@ def get_channels(self, channel_id): params['id'] = channel_id else: params['mine'] = 'true' - return self.perform_v3_request(method='GET', path='channels', params=params) + return self.perform_v3_request(method='GET', + path='channels', + params=params, + **kwargs) - def get_disliked_videos(self, page_token=''): + def get_disliked_videos(self, page_token='', **kwargs): # prepare page token if not page_token: page_token = '' @@ -559,9 +647,12 @@ def get_disliked_videos(self, page_token=''): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='videos', params=params) + return self.perform_v3_request(method='GET', + path='videos', + params=params, + **kwargs) - def get_videos(self, video_id, live_details=False): + def get_videos(self, video_id, live_details=False, **kwargs): """ Returns a list of videos that match the API request parameters :param video_id: list of video ids @@ -577,19 +668,29 @@ def get_videos(self, video_id, live_details=False): params = {'part': ''.join(parts), 'id': video_id} - return self.perform_v3_request(method='GET', path='videos', params=params) + return self.perform_v3_request(method='GET', + path='videos', + params=params, + **kwargs) - def get_playlists(self, playlist_id): + def get_playlists(self, playlist_id, **kwargs): if isinstance(playlist_id, list): playlist_id = ','.join(playlist_id) params = {'part': 'snippet,contentDetails', 'id': playlist_id} - return self.perform_v3_request(method='GET', path='playlists', params=params) - - def get_live_events(self, event_type='live', order='relevance', page_token='', location=False): + return self.perform_v3_request(method='GET', + path='playlists', + params=params, + **kwargs) + + def get_live_events(self, + event_type='live', + order='relevance', + page_token='', + location=False, + **kwargs): """ - :param event_type: one of: 'live', 'completed', 'upcoming' :param order: one of: 'date', 'rating', 'relevance', 'title', 'videoCount', 'viewCount' :param page_token: @@ -619,9 +720,16 @@ def get_live_events(self, event_type='live', order='relevance', page_token='', l if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='search', params=params) + return self.perform_v3_request(method='GET', + path='search', + params=params, + **kwargs) - def get_related_videos(self, video_id, page_token='', max_results=0): + def get_related_videos(self, + video_id, + page_token='', + max_results=0, + **kwargs): # prepare page token if not page_token: page_token = '' @@ -638,9 +746,16 @@ def get_related_videos(self, video_id, page_token='', max_results=0): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='search', params=params) + return self.perform_v3_request(method='GET', + path='search', + params=params, + **kwargs) - def get_parent_comments(self, video_id, page_token='', max_results=0): + def get_parent_comments(self, + video_id, + page_token='', + max_results=0, + **kwargs): max_results = self._max_results if max_results <= 0 else max_results # prepare params @@ -652,9 +767,17 @@ def get_parent_comments(self, video_id, page_token='', max_results=0): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='commentThreads', params=params, no_login=True) - - def get_child_comments(self, parent_id, page_token='', max_results=0): + return self.perform_v3_request(method='GET', + path='commentThreads', + params=params, + no_login=True, + **kwargs) + + def get_child_comments(self, + parent_id, + page_token='', + max_results=0, + **kwargs): max_results = self._max_results if max_results <= 0 else max_results # prepare params @@ -665,9 +788,13 @@ def get_child_comments(self, parent_id, page_token='', max_results=0): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='comments', params=params, no_login=True) + return self.perform_v3_request(method='GET', + path='comments', + params=params, + no_login=True, + **kwargs) - def get_channel_videos(self, channel_id, page_token=''): + def get_channel_videos(self, channel_id, page_token='', **kwargs): """ Returns a collection of video search results for the specified channel_id """ @@ -687,10 +814,21 @@ def get_channel_videos(self, channel_id, page_token=''): if page_token: params['pageToken'] = page_token - return self.perform_v3_request(method='GET', path='search', params=params) - - def search(self, q, search_type=None, event_type='', channel_id='', - order='relevance', safe_search='moderate', page_token='', location=False): + return self.perform_v3_request(method='GET', + path='search', + params=params, + **kwargs) + + def search(self, + q, + search_type=None, + event_type='', + channel_id='', + order='relevance', + safe_search='moderate', + page_token='', + location=False, + **kwargs): """ Returns a collection of search results that match the query parameters specified in the API request. By default, a search result set identifies matching video, channel, and playlist resources, but you can also configure @@ -754,9 +892,12 @@ def search(self, q, search_type=None, event_type='', channel_id='', params['location'] = location params['locationRadius'] = _context.get_settings().get_location_radius() - return self.perform_v3_request(method='GET', path='search', params=params) + return self.perform_v3_request(method='GET', + path='search', + params=params, + **kwargs) - def get_my_subscriptions(self, page_token=None, offset=0): + def get_my_subscriptions(self, page_token=None, offset=0, **kwargs): """ modified by PureHemp, using YouTube RSS for fetching latest videos """ @@ -805,19 +946,22 @@ def _perform(_page_token, _offset, _result): if sub_page_token: params['pageToken'] = sub_page_token - sub_json_data = self.perform_v3_request(method='GET', path='subscriptions', params=params) + json_data = self.perform_v3_request(method='GET', + path='subscriptions', + params=params, + **kwargs) - if not sub_json_data: - sub_json_data = {} + if not json_data: + json_data = {} - items = sub_json_data.get('items', []) + items = json_data.get('items', []) for item in items: item = item.get('snippet', {}).get('resourceId', {}).get('channelId', '') sub_channel_ids.append(item) # get next token if exists - sub_page_token = sub_json_data.get('nextPageToken', '') + sub_page_token = json_data.get('nextPageToken', '') # terminate loop when last page if not sub_page_token: @@ -1045,19 +1189,82 @@ def _perform(_playlist_idx, _page_token, _offset, _result): return result - def perform_v3_request(self, method='GET', headers=None, path=None, - post_data=None, params=None, no_login=False): + @staticmethod + def _response_hook(**kwargs): + response = kwargs['response'] + _context.log_debug('[data] v3 response: |{0.status_code}|\n' + '\theaders: |{0.headers}|'.format(response)) + try: + json_data = response.json() + if 'error' in json_data: + raise YouTubeException('"error" in response JSON data', + json_data=json_data, + **kwargs) + except ValueError as error: + raise InvalidJSON(error, **kwargs) + response.raise_for_status() + return json_data + @staticmethod + def _error_hook(**kwargs): + exc = kwargs['exc'] + json_data = getattr(exc, 'json_data', None) + data = getattr(exc, 'pass_data', False) and json_data + exception = getattr(exc, 'raise_exc', False) and YouTubeException + + if not json_data or 'error' not in json_data: + return None, None, None, data, None, exception + + details = json_data['error'] + reason = details.get('errors', [{}])[0].get('reason', 'Unknown') + message = strip_html_from_text(details.get('message', 'Unknown error')) + + notify = getattr(exc, 'notify', True) + if notify: + ok_dialog = False + timeout = 5000 + if reason == 'accessNotConfigured': + notification = _context.localize('key.requirement.notification') + ok_dialog = True + elif reason == 'keyInvalid' and message == 'Bad Request': + notification = _context.localize('api.key.incorrect') + timeout = 7000 + elif reason in ('quotaExceeded', 'dailyLimitExceeded'): + notification = message + timeout = 7000 + else: + notification = message + + title = '{0}: {1}'.format(_context.get_name(), reason) + if ok_dialog: + _context.get_ui().on_ok(title, notification) + else: + _context.get_ui().show_notification(notification, + title, + time_ms=timeout) + + info = ('[data] v3 error: {reason}\n' + '\texc: |{exc}|\n' + '\tmessage: |{message}|') + details = {'reason': reason, 'message': message} + return '', info, details, data, False, exception + + def perform_v3_request(self, method='GET', headers=None, path=None, + post_data=None, params=None, no_login=False, + **kwargs): # params _params = {} # headers _headers = {'Host': 'www.googleapis.com', - 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.36 Safari/537.36', + 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64)' + ' AppleWebKit/537.36 (KHTML, like Gecko)' + ' Chrome/39.0.2171.36 Safari/537.36', 'Accept-Encoding': 'gzip, deflate'} # a config can decide if a token is allowed - if self._access_token and self._config.get('token-allowed', True) and not no_login: + if (not no_login and self._access_token + and self._config.get('token-allowed', True)): _headers['Authorization'] = 'Bearer %s' % self._access_token else: _params['key'] = self._config_tv['key'] @@ -1074,23 +1281,26 @@ def perform_v3_request(self, method='GET', headers=None, path=None, log_params['location'] = 'xx.xxxx,xx.xxxx' else: log_params = None - _context.log_debug('[data] v3 request: |{0}| path: |{1}| params: |{2}| post_data: |{3}|'.format(method, path, log_params, post_data)) - - result = self.request(_url, method=method, headers=_headers, json=post_data, params=_params) - if result is None: - return {} - - _context.log_debug('[data] v3 response: |{0}| headers: |{1}|'.format(result.status_code, result.headers)) - if result.headers.get('content-type', '').startswith('application/json'): - try: - return result.json() - except ValueError: - return { - 'status_code': result.status_code, - 'payload': result.text - } - return {} + _context.log_debug('[data] v3 request: |{method}|\n' + '\tpath: |{path}|\n' + '\tparams: |{params}|\n' + '\tpost_data: |{data}|\n' + '\theaders: |{headers}|'.format(method=method, + path=path, + params=log_params, + data=post_data, + headers=_headers)) + + json_data = self.request(_url, + method=method, + headers=_headers, + json=post_data, + params=_params, + response_hook=self._response_hook, + response_hook_kwargs=kwargs, + error_hook=self._error_hook) + return json_data def perform_v1_tv_request(self, method='GET', headers=None, path=None, post_data=None, params=None, no_login=False): diff --git a/resources/lib/youtube_plugin/youtube/helper/v3.py b/resources/lib/youtube_plugin/youtube/helper/v3.py index e0e66f463..295c25efa 100644 --- a/resources/lib/youtube_plugin/youtube/helper/v3.py +++ b/resources/lib/youtube_plugin/youtube/helper/v3.py @@ -24,7 +24,6 @@ from ..helper import yt_context_menu from ...kodion import KodionException from ...kodion.items import DirectoryItem, NextPageItem, VideoItem -from ...kodion.utils import strip_html_from_text def _process_list_response(provider, context, json_data): @@ -434,39 +433,6 @@ def response_to_items(provider, context, json_data, sort=None, reverse=False, pr return result -def handle_error(context, json_data): - if json_data and 'error' in json_data: - ok_dialog = False - message_timeout = 5000 - - message = strip_html_from_text(json_data['error'].get('message', '')) - log_message = strip_html_from_text(json_data['error'].get('message', '')) - reason = json_data['error']['errors'][0].get('reason', '') - title = '%s: %s' % (context.get_name(), reason) - - context.log_error('Error reason: |%s| with message: |%s|' % (reason, log_message)) - - if reason == 'accessNotConfigured': - message = context.localize('key.requirement.notification') - ok_dialog = True - - if reason == 'keyInvalid' and message == 'Bad Request': - message = context.localize('api.key.incorrect') - message_timeout = 7000 - - if reason in {'quotaExceeded', 'dailyLimitExceeded'}: - message_timeout = 7000 - - if ok_dialog: - context.get_ui().on_ok(title, message) - else: - context.get_ui().show_notification(message, title, time_ms=message_timeout) - - return False - - return True - - def _parse_kind(item): parts = item.get('kind', '').split('#') is_youtube = parts[0] == 'youtube' diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_play.py b/resources/lib/youtube_plugin/youtube/helper/yt_play.py index a233a7bc0..92ad9b9b1 100644 --- a/resources/lib/youtube_plugin/youtube/helper/yt_play.py +++ b/resources/lib/youtube_plugin/youtube/helper/yt_play.py @@ -246,11 +246,18 @@ def play_channel_live(provider, context): index = context.get_param('live') - 1 if index < 0: index = 0 - json_data = provider.get_client(context).search(q='', search_type='video', event_type='live', channel_id=channel_id, safe_search=False) - if not v3.handle_error(context, json_data): + json_data = provider.get_client(context).search(q='', + search_type='video', + event_type='live', + channel_id=channel_id, + safe_search=False) + if not json_data: return False - video_items = v3.response_to_items(provider, context, json_data, process_next_page=False) + video_items = v3.response_to_items(provider, + context, + json_data, + process_next_page=False) try: video_item = video_items[index] diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py b/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py index ffb69fdb3..b5fbacca6 100644 --- a/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py +++ b/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py @@ -38,7 +38,7 @@ def _process_add_video(provider, context, keymap_action=False): if playlist_id != 'HL': json_data = client.add_video_to_playlist(playlist_id=playlist_id, video_id=video_id) - if not v3.handle_error(context, json_data): + if not json_data: return False if playlist_id == watch_later_id: @@ -96,7 +96,7 @@ def _process_remove_video(provider, context): if context.get_ui().on_remove_content(video_name): json_data = provider.get_client(context).remove_video_from_playlist(playlist_id=playlist_id, playlist_item_id=video_id) - if not v3.handle_error(context, json_data): + if not json_data: return False context.get_ui().refresh_container() @@ -128,7 +128,7 @@ def _process_remove_playlist(provider, context): if context.get_ui().on_delete_content(playlist_name): json_data = provider.get_client(context).remove_playlist(playlist_id=playlist_id) - if not v3.handle_error(context, json_data): + if not json_data: return False context.get_ui().refresh_container() @@ -203,7 +203,7 @@ def _process_select_playlist(provider, context): context.localize('playlist.create')) if result and text: json_data = client.create_playlist(title=text) - if not v3.handle_error(context, json_data): + if not json_data: break playlist_id = json_data.get('id', '') @@ -236,7 +236,7 @@ def _process_rename_playlist(provider, context): default=current_playlist_name) if result and text: json_data = provider.get_client(context).rename_playlist(playlist_id=playlist_id, new_title=text) - if not v3.handle_error(context, json_data): + if not json_data: return context.get_ui().refresh_container() diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_specials.py b/resources/lib/youtube_plugin/youtube/helper/yt_specials.py index ea2e29a1a..5a4456ba8 100644 --- a/resources/lib/youtube_plugin/youtube/helper/yt_specials.py +++ b/resources/lib/youtube_plugin/youtube/helper/yt_specials.py @@ -33,7 +33,7 @@ def _process_related_videos(provider, context): json_data = provider.get_client(context).get_related_videos( video_id=video_id, page_token=context.get_param('page_token', '') ) - if not v3.handle_error(context, json_data): + if not json_data: return False return v3.response_to_items(provider, context, @@ -50,7 +50,7 @@ def _process_parent_comments(provider, context): json_data = provider.get_client(context).get_parent_comments( video_id=video_id, page_token=context.get_param('page_token', '') ) - if not v3.handle_error(context, json_data): + if not json_data: return False return v3.response_to_items(provider, context, json_data) @@ -64,7 +64,7 @@ def _process_child_comments(provider, context): json_data = provider.get_client(context).get_child_comments( parent_id=parent_id, page_token=context.get_param('page_token', '') ) - if not v3.handle_error(context, json_data): + if not json_data: return False return v3.response_to_items(provider, context, json_data) @@ -74,7 +74,7 @@ def _process_recommendations(provider, context): json_data = provider.get_client(context).get_activities( channel_id='home', page_token=context.get_param('page_token', '') ) - if not v3.handle_error(context, json_data): + if not json_data: return False return v3.response_to_items(provider, context, json_data) @@ -84,7 +84,7 @@ def _process_popular_right_now(provider, context): json_data = provider.get_client(context).get_popular_videos( page_token=context.get_param('page_token', '') ) - if not v3.handle_error(context, json_data): + if not json_data: return False return v3.response_to_items(provider, context, json_data) @@ -95,14 +95,14 @@ def _process_browse_channels(provider, context): guide_id = context.get_param('guide_id', '') if guide_id: json_data = client.get_guide_category(guide_id) - if not v3.handle_error(context, json_data): + if not json_data: return False return v3.response_to_items(provider, context, json_data) function_cache = context.get_function_cache() json_data = function_cache.get(client.get_guide_categories, function_cache.ONE_MONTH) - if not v3.handle_error(context, json_data): + if not json_data: return False return v3.response_to_items(provider, context, json_data) @@ -112,7 +112,7 @@ def _process_disliked_videos(provider, context): json_data = provider.get_client(context).get_disliked_videos( page_token=context.get_param('page_token', '') ) - if not v3.handle_error(context, json_data): + if not json_data: return False return v3.response_to_items(provider, context, json_data) @@ -128,7 +128,7 @@ def _sort(x): page_token=context.get_param('page_token', ''), location=context.get_param('location', False), ) - if not v3.handle_error(context, json_data): + if not json_data: return False return v3.response_to_items(provider, context, json_data, sort=_sort) diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py b/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py index c90893947..39e81309b 100644 --- a/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py +++ b/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py @@ -21,7 +21,7 @@ def _process_list(provider, context): page_token = context.get_param('page_token', '') # no caching json_data = provider.get_client(context).get_subscription('mine', page_token=page_token) - if not v3.handle_error(context, json_data): + if not json_data: return [] result.extend(v3.response_to_items(provider, context, json_data)) @@ -38,7 +38,7 @@ def _process_add(provider, context): if subscription_id: json_data = provider.get_client(context).subscribe(subscription_id) - if not v3.handle_error(context, json_data): + if not json_data: return False context.get_ui().show_notification( @@ -61,7 +61,7 @@ def _process_remove(provider, context): if subscription_id: json_data = provider.get_client(context).unsubscribe(subscription_id) - if not v3.handle_error(context, json_data): + if not json_data: return False context.get_ui().refresh_container() diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_video.py b/resources/lib/youtube_plugin/youtube/helper/yt_video.py index 63c517875..9ce0f8523 100644 --- a/resources/lib/youtube_plugin/youtube/helper/yt_video.py +++ b/resources/lib/youtube_plugin/youtube/helper/yt_video.py @@ -42,7 +42,7 @@ def _process_rate_video(provider, context, re_match): if not current_rating: client = provider.get_client(context) json_data = client.get_video_rating(video_id) - if not v3.handle_error(context, json_data): + if not json_data: return False items = json_data.get('items', []) diff --git a/resources/lib/youtube_plugin/youtube/provider.py b/resources/lib/youtube_plugin/youtube/provider.py index e6d5740ad..4bdc07206 100644 --- a/resources/lib/youtube_plugin/youtube/provider.py +++ b/resources/lib/youtube_plugin/youtube/provider.py @@ -49,7 +49,6 @@ def __init__(self): self._client = None self._is_logged_in = False - self.v3_handle_error = v3.handle_error self.yt_video = yt_video def get_wizard_supported_views(self): @@ -354,7 +353,7 @@ def _on_channel_playlists(self, context, re_match): # no caching json_data = self.get_client(context).get_playlists_of_channel(channel_id, page_token) - if not v3.handle_error(context, json_data): + if not json_data: return False result.extend(v3.response_to_items(self, context, json_data)) @@ -377,7 +376,7 @@ def _on_channel_live(self, context, re_match): # no caching json_data = self.get_client(context).search(q='', search_type='video', event_type='live', channel_id=channel_id, page_token=page_token, safe_search=safe_search) - if not v3.handle_error(context, json_data): + if not json_data: return False result.extend(v3.response_to_items(self, context, json_data)) @@ -428,7 +427,7 @@ def _on_channel(self, context, re_match): json_data = function_cache.get(client.get_channel_by_username, function_cache.ONE_DAY, channel_id) - if not v3.handle_error(context, json_data): + if not json_data: return False # we correct the channel id based on the username @@ -490,7 +489,7 @@ def _on_channel(self, context, re_match): function_cache.ONE_MINUTE * 5, upload_playlist, page_token=page_token) - if not v3.handle_error(context, json_data): + if not json_data: return False result.extend(v3.response_to_items(self, context, json_data)) @@ -821,7 +820,7 @@ def _search_channel_or_playlist(self, context, id_string): elif re.match(r'[OP]L[0-9a-zA-Z_\-]{30,40}', id_string): json_data = self.get_client(context).get_playlists(id_string) - if not json_data or not v3.handle_error(context, json_data): + if not json_data: return [] result.extend(v3.response_to_items(self, context, json_data)) @@ -893,7 +892,7 @@ def on_search(self, search_text, context, re_match): page_token=page_token, channel_id=channel_id, location=location) - if not v3.handle_error(context, json_data): + if not json_data: return False result.extend(v3.response_to_items(self, context, json_data)) return result diff --git a/resources/lib/youtube_requests.py b/resources/lib/youtube_requests.py index b25204c74..391018b8f 100644 --- a/resources/lib/youtube_requests.py +++ b/resources/lib/youtube_requests.py @@ -30,17 +30,6 @@ def __get_core_components(addon_id=None): return provider, context, client -def handle_error(context, json_data): - if json_data and 'error' in json_data: - message = json_data['error'].get('message', '') - reason = json_data['error']['errors'][0].get('reason', '') - context.log_error('Error reason: |%s| with message: |%s|' % (reason, message)) - - return False - - return True - - def v3_request(method='GET', headers=None, path=None, post_data=None, params=None, addon_id=None): """ https://developers.google.com/youtube/v3/docs/ @@ -53,7 +42,14 @@ def v3_request(method='GET', headers=None, path=None, post_data=None, params=Non :type addon_id: str """ provider, context, client = __get_core_components(addon_id) - return client.perform_v3_request(method=method, headers=headers, path=path, post_data=post_data, params=params) + return client.perform_v3_request(method=method, + headers=headers, + path=path, + post_data=post_data, + params=params, + notify=False, + pass_data=True, + raise_exc=False) def _append_missing_page_token(items): @@ -76,11 +72,14 @@ def get_videos(video_id, addon_id=None): """ provider, context, client = __get_core_components(addon_id) - json_data = client.get_videos(video_id) - if not handle_error(context, json_data): + json_data = client.get_videos(video_id, + notify=False, + pass_data=True, + raise_exc=False) + if not json_data or 'error' in json_data: return [json_data] - return json_data.get('items', []) + return json_data.get('items', [{}]) def get_activities(channel_id, page_token='', all_pages=False, addon_id=None): @@ -103,11 +102,15 @@ def get_activities(channel_id, page_token='', all_pages=False, addon_id=None): items = [] def get_items(_page_token=''): - json_data = client.get_activities(channel_id, page_token=_page_token) - if not handle_error(context, json_data): + json_data = client.get_activities(channel_id, + page_token=_page_token, + notify=False, + pass_data=True, + raise_exc=False) + if not json_data or 'error' in json_data: return [json_data] - items.extend(json_data.get('items', [])) + items.extend(json_data.get('items', [{}])) error = False next_page_token = json_data.get('nextPageToken') @@ -148,11 +151,15 @@ def get_playlist_items(playlist_id, page_token='', all_pages=False, addon_id=Non items = [] def get_items(_page_token=''): - json_data = client.get_playlist_items(playlist_id, page_token=_page_token) - if not handle_error(context, json_data): + json_data = client.get_playlist_items(playlist_id, + page_token=_page_token, + notify=False, + pass_data=True, + raise_exc=False) + if not json_data or 'error' in json_data: return [json_data] - items.extend(json_data.get('items', [])) + items.extend(json_data.get('items', [{}])) error = False next_page_token = json_data.get('nextPageToken') @@ -185,11 +192,14 @@ def get_channel_id(channel_name, addon_id=None): """ provider, context, client = __get_core_components(addon_id) - json_data = client.get_channel_by_username(channel_name) - if not handle_error(context, json_data): + json_data = client.get_channel_by_username(channel_name, + notify=False, + pass_data=True, + raise_exc=False) + if not json_data or 'error' in json_data: return [json_data] - return json_data.get('items', []) + return json_data.get('items', [{}]) def get_channels(channel_id, addon_id=None): @@ -205,11 +215,14 @@ def get_channels(channel_id, addon_id=None): """ provider, context, client = __get_core_components(addon_id) - json_data = client.get_channels(channel_id) - if not handle_error(context, json_data): + json_data = client.get_channels(channel_id, + notify=False, + pass_data=True, + raise_exc=False) + if not json_data or 'error' in json_data: return [json_data] - return json_data.get('items', []) + return json_data.get('items', [{}]) def get_channel_sections(channel_id, addon_id=None): @@ -225,11 +238,14 @@ def get_channel_sections(channel_id, addon_id=None): """ provider, context, client = __get_core_components(addon_id) - json_data = client.get_channel_sections(channel_id) - if not handle_error(context, json_data): + json_data = client.get_channel_sections(channel_id, + notify=False, + pass_data=True, + raise_exc=False) + if not json_data or 'error' in json_data: return [json_data] - return json_data.get('items', []) + return json_data.get('items', [{}]) def get_playlists_of_channel(channel_id, page_token='', all_pages=False, addon_id=None): @@ -253,11 +269,15 @@ def get_playlists_of_channel(channel_id, page_token='', all_pages=False, addon_i items = [] def get_items(_page_token=''): - json_data = client.get_playlists_of_channel(channel_id, page_token=_page_token) - if not handle_error(context, json_data): + json_data = client.get_playlists_of_channel(channel_id, + page_token=_page_token, + notify=False, + pass_data=True, + raise_exc=False) + if not json_data or 'error' in json_data: return [json_data] - items.extend(json_data.get('items', [])) + items.extend(json_data.get('items', [{}])) error = False next_page_token = json_data.get('nextPageToken') @@ -290,11 +310,14 @@ def get_playlists(playlist_id, addon_id=None): """ provider, context, client = __get_core_components(addon_id) - json_data = client.get_playlists(playlist_id) - if not handle_error(context, json_data): + json_data = client.get_playlists(playlist_id, + notify=False, + pass_data=True, + raise_exc=False) + if not json_data or 'error' in json_data: return [json_data] - return json_data.get('items', []) + return json_data.get('items', [{}]) def get_related_videos(video_id, page_token='', addon_id=None): @@ -317,11 +340,15 @@ def get_related_videos(video_id, page_token='', addon_id=None): items = [] def get_items(_page_token=''): - json_data = client.get_related_videos(video_id, page_token=_page_token) - if not handle_error(context, json_data): + json_data = client.get_related_videos(video_id, + page_token=_page_token, + notify=False, + pass_data=True, + raise_exc=False) + if not json_data or 'error' in json_data: return [json_data] - items.extend([item for item in json_data.get('items', []) + items.extend([item for item in json_data.get('items', [{}]) if 'snippet' in item]) error = False @@ -369,12 +396,20 @@ def get_search(q, search_type='', event_type='', channel_id='', order='relevance items = [] def get_items(_page_token=''): - json_data = client.search(q, search_type=search_type, event_type=event_type, channel_id=channel_id, - order=order, safe_search=safe_search, page_token=_page_token) - if not handle_error(context, json_data): + json_data = client.search(q, + search_type=search_type, + event_type=event_type, + channel_id=channel_id, + order=order, + safe_search=safe_search, + page_token=_page_token, + notify=False, + pass_data=True, + raise_exc=False) + if not json_data or 'error' in json_data: return [json_data] - items.extend(json_data.get('items', [])) + items.extend(json_data.get('items', [{}])) error = False next_page_token = json_data.get('nextPageToken')