diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index 837ea6d0..77860d4a 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -962,6 +962,26 @@ msgctxt "#30967" msgid "Could not retrieve this program list. VRT Search API url is too long. Go to [B]VRT NU settings » Interface » Manage My favorites…[/B] and unfollow older favorite programs to fix this problem." msgstr "" +msgctxt "#30968" +msgid "No connection" +msgstr "" + +msgctxt "#30969" +msgid "There is a problem connecting to the Internet. This could be related to Kodi, your network, your ISP or VRT NU. Check out the Kodi log for more details." +msgstr "" + +msgctxt "#30970" +msgid "VRT NU authentication failed" +msgstr "" + +msgctxt "#30971" +msgid "There is an unknown problem authenticating your user credentials at VRT NU. Please check your VRT NU account at https://www.vrt.be/vrtnu/" +msgstr "" + +msgctxt "#30972" +msgid "There is a problem authenticating at VRT NU to enable favorites. Please check your VRT NU account at https://www.vrt.be/vrtnu/ or disable favorites in the add-on settings." +msgstr "" + msgctxt "#30975" msgid "Failed to get user token from VRT NU" msgstr "" diff --git a/resources/language/resource.language.nl_nl/strings.po b/resources/language/resource.language.nl_nl/strings.po index d79af6c5..6fd9a9fb 100644 --- a/resources/language/resource.language.nl_nl/strings.po +++ b/resources/language/resource.language.nl_nl/strings.po @@ -962,6 +962,26 @@ msgctxt "#30967" msgid "Could not retrieve this program list. VRT Search API url is too long. Go to [B]VRT NU settings » Interface » Manage My favorites…[/B] and unfollow older favorite programs to fix this problem." msgstr "Deze programmalijst kan niet opgehaald worden. VRT Search API url is te lang. Ga naar [B]VRT NU instellingen » Interface » Beheer Mijn favorieten[/B] en verwijder een aantal favoriete programma's om dit probleem op te lossen. " +msgctxt "#30968" +msgid "No connection" +msgstr "Geen verbinding" + +msgctxt "#30969" +msgid "There is a problem connecting to the Internet. This could be related to Kodi, your network, your ISP or VRT NU. Check out the Kodi log for more details." +msgstr "Er is een probleem met het verbinden met internet. Dit kan liggen aan Kodi, aan jouw netwerk, aan jouw ISP of aan VRT NU. Bekijk de Kodi-log voor meer details." + +msgctxt "#30970" +msgid "VRT NU authentication failed" +msgstr "VRT NU-verificatie is mislukt" + +msgctxt "#30971" +msgid "There is an unknown problem authenticating your user credentials at VRT NU. Please check your VRT NU account at https://www.vrt.be/vrtnu/" +msgstr "Er is een onbekend probleem bij het verifiëren van je gebruikersgegevens bij VRT NU. Controleer je VRT NU-account op https://www.vrt.be/vrtnu/" + +msgctxt "#30972" +msgid "There is a problem authenticating at VRT NU to enable favorites. Please check your VRT NU account at https://www.vrt.be/vrtnu/ or disable favorites in the add-on settings." +msgstr "Er is een probleem met de authenticatie bij VRT NU om favorieten in te schakelen. Controleer je VRT NU-account op https://www.vrt.be/vrtnu/ of schakel favorieten uit in de add-on-instellingen." + msgctxt "#30975" msgid "Failed to get user token from VRT NU" msgstr "Ophalen van het gebruikerstoken van VRT NU is mislukt" diff --git a/resources/lib/apihelper.py b/resources/lib/apihelper.py index eb3ddda9..b968963e 100644 --- a/resources/lib/apihelper.py +++ b/resources/lib/apihelper.py @@ -6,15 +6,14 @@ try: # Python 3 from urllib.parse import quote_plus, unquote - from urllib.request import build_opener, install_opener, ProxyHandler except ImportError: # Python 2 from urllib import quote_plus - from urllib2 import build_opener, install_opener, ProxyHandler, unquote + from urllib2 import unquote from data import CHANNELS from helperobjects import TitleItem from kodiutils import (delete_cached_thumbnail, get_cache, get_cached_url_json, get_global_setting, - get_proxies, get_setting_bool, get_setting_int, get_url_json, has_addon, localize, + get_setting_bool, get_setting_int, get_url_json, has_addon, localize, localize_from_data, log, ttl, url_for) from metadata import Metadata from utils import (html_to_kodi, find_entry, from_unicode, play_url_to_id, @@ -34,7 +33,6 @@ def __init__(self, _favorites, _resumepoints): self._favorites = _favorites self._resumepoints = _resumepoints self._metadata = Metadata(_favorites, _resumepoints) - install_opener(build_opener(ProxyHandler(get_proxies()))) def get_tvshows(self, category=None, channel=None, feature=None): """Get all TV shows for a given category, channel or feature, optionally filtered by favorites""" diff --git a/resources/lib/favorites.py b/resources/lib/favorites.py index f149b364..6fec70ee 100644 --- a/resources/lib/favorites.py +++ b/resources/lib/favorites.py @@ -8,11 +8,10 @@ try: # Python 3 from urllib.error import HTTPError from urllib.parse import unquote - from urllib.request import build_opener, install_opener, ProxyHandler except ImportError: # Python 2 - from urllib2 import build_opener, HTTPError, install_opener, ProxyHandler, unquote + from urllib2 import unquote -from kodiutils import (container_refresh, get_cache, get_proxies, get_setting_bool, get_url_json, +from kodiutils import (container_refresh, get_cache, get_setting_bool, get_url_json, has_credentials, input_down, invalidate_caches, localize, log_error, multiselect, notification, ok_dialog, update_cache) from utils import program_to_id @@ -24,7 +23,6 @@ class Favorites: def __init__(self): """Initialize favorites, relies on XBMC vfs and a special VRT token""" self._data = dict() # Our internal representation - install_opener(build_opener(ProxyHandler(get_proxies()))) @staticmethod def is_activated(): @@ -79,7 +77,7 @@ def update(self, program, title, value=True): data = dumps(payload).encode('utf-8') program_id = program_to_id(program) try: - get_url_json('https://video-user-data.vrt.be/favorites/{program_id}'.format(program_id=program_id), headers=headers, data=data) + get_url_json('https://video-user-data.vrt.be/favorites/{program_id}'.format(program_id=program_id), headers=headers, data=data, raise_errors='all') except HTTPError as exc: log_error("Failed to (un)follow program '{program}' at VRT NU ({error})", program=program, error=exc) notification(message=localize(30976, program=program)) diff --git a/resources/lib/kodiutils.py b/resources/lib/kodiutils.py index 4d6f530e..4e0dcf76 100644 --- a/resources/lib/kodiutils.py +++ b/resources/lib/kodiutils.py @@ -5,12 +5,19 @@ from __future__ import absolute_import, division, unicode_literals from contextlib import contextmanager from sys import version_info +from socket import timeout +from ssl import SSLError import xbmc import xbmcaddon import xbmcplugin from utils import from_unicode, to_unicode +try: # Python 3 + from urllib.request import HTTPErrorProcessor +except ImportError: # Python 2 + from urllib2 import HTTPErrorProcessor + ADDON = xbmcaddon.Addon() DEFAULT_CACHE_DIR = 'cache' @@ -80,6 +87,15 @@ } +class NoRedirection(HTTPErrorProcessor): + """Prevent urllib from following http redirects""" + + def http_response(self, request, response): + return response + + https_response = http_response + + class SafeDict(dict): """A safe dictionary implementation that does not break down on missing keys""" def __missing__(self, key): @@ -861,10 +877,10 @@ def wait_for_resumepoints(): update = get_property('vrtnu_resumepoints') if update == 'busy': import time - timeout = time.time() + 5 # 5 seconds timeout + time_out = time.time() + 5 # 5 seconds timeout log(3, 'Resumepoint update is busy, wait') while update != 'ready': - if time.time() > timeout: # Exit loop in case something goes wrong + if time.time() > time_out: # Exit loop in case something goes wrong break xbmc.sleep(50) update = get_property('vrtnu_resumepoints') @@ -1034,43 +1050,45 @@ def ttl(kind='direct'): return 5 * 60 -def get_json_data(response, fail=None): - """Return json object from HTTP response""" - from json import load, loads - try: - if (3, 0, 0) <= version_info < (3, 6, 0): # the JSON object must be str, not 'bytes' - return loads(to_unicode(response.read())) - return load(response) - except TypeError as exc: # 'NoneType' object is not callable - log_error('JSON TypeError: {exc}', exc=exc) - return fail - except ValueError as exc: # No JSON object could be decoded - log_error('JSON ValueError: {exc}', exc=exc) - return fail - - -def get_url_json(url, cache=None, headers=None, data=None, fail=None): - """Return HTTP data""" +def open_url(url, data=None, headers=None, method=None, cookiejar=None, follow_redirects=True, raise_errors=None): + """Return a urllib http response""" try: # Python 3 - from urllib.error import HTTPError + from urllib.error import HTTPError, URLError from urllib.parse import unquote - from urllib.request import urlopen, Request + from urllib.request import build_opener, HTTPCookieProcessor, ProxyHandler, Request except ImportError: # Python 2 - from urllib2 import HTTPError, unquote, urlopen, Request - - if headers is None: + from urllib2 import build_opener, HTTPError, HTTPCookieProcessor, ProxyHandler, Request, URLError, unquote + + opener_args = [] + if not follow_redirects: + opener_args.append(NoRedirection) + if cookiejar is not None: + opener_args.append(HTTPCookieProcessor(cookiejar)) + proxies = get_proxies() + if proxies: + opener_args.append(ProxyHandler(proxies)) + opener = build_opener(*opener_args) + + if not headers: headers = dict() req = Request(url, headers=headers) - if data is not None: + req.data = data log(2, 'URL post: {url}', url=unquote(url)) log(2, 'URL post data: {data}', data=data) - req.data = data else: log(2, 'URL get: {url}', url=unquote(url)) + + if method is not None: + req.get_method = lambda: method + + if raise_errors is None: + raise_errors = list() try: - json_data = get_json_data(urlopen(req), fail=fail) + return opener.open(req) except HTTPError as exc: + if isinstance(raise_errors, list) and 401 in raise_errors or raise_errors == 'all': + raise if hasattr(req, 'selector'): # Python 3.4+ url_length = len(req.selector) else: # Python 2.7 @@ -1079,25 +1097,64 @@ def get_url_json(url, cache=None, headers=None, data=None, fail=None): ok_dialog(heading='HTTP Error 400', message=localize(30967)) log_error('HTTP Error 400: Probably exceeded maximum url length: ' 'VRT Search API url has a length of {length} characters.', length=url_length) - return fail + return None if exc.code == 413 and url_length > 8192: ok_dialog(heading='HTTP Error 413', message=localize(30967)) log_error('HTTP Error 413: Exceeded maximum url length: ' 'VRT Search API url has a length of {length} characters.', length=url_length) - return fail + return None if exc.code == 431: ok_dialog(heading='HTTP Error 431', message=localize(30967)) log_error('HTTP Error 431: Request header fields too large: ' 'VRT Search API url has a length of {length} characters.', length=url_length) - return fail - json_data = get_json_data(exc, fail=fail) - if json_data is None: - raise - else: - if cache: - from json import dumps - update_cache(cache, dumps(json_data)) - return json_data + return None + if exc.code == 401: + ok_dialog(heading='HTTP Error {code}'.format(code=exc.code), message='{}\n{}'.format(url, exc.reason)) + log_error('HTTP Error {code}: {reason}', code=exc.code, reason=exc.reason) + return None + if exc.code in (400, 403) and exc.headers.get('Content-Type') and 'application/json' in exc.headers.get('Content-Type'): + return exc + reason = exc.reason + code = exc.code + ok_dialog(heading='HTTP Error {code}'.format(code=code), message='{}\n{}'.format(url, reason)) + log_error('HTTP Error {code}: {reason}', code=code, reason=reason) + return None + except URLError as exc: + ok_dialog(heading=localize(30968), message=localize(30969)) + log_error('URLError: {error}\nurl: {url}', error=exc.reason, url=url) + return None + except (timeout, SSLError) as exc: + ok_dialog(heading=localize(30968), message=localize(30969)) + log_error('{error}\nurl: {url}', error=exc.reason, url=url) + return None + + +def get_json_data(response, fail=None): + """Return json object from HTTP response""" + from json import load, loads + try: + if (3, 0, 0) <= version_info < (3, 6, 0): # the JSON object must be str, not 'bytes' + return loads(to_unicode(response.read())) + return load(response) + except TypeError as exc: # 'NoneType' object is not callable + log_error('JSON TypeError: {exc}', exc=exc) + return fail + except ValueError as exc: # No JSON object could be decoded + log_error('JSON ValueError: {exc}', exc=exc) + return fail + + +def get_url_json(url, cache=None, headers=None, data=None, fail=None, raise_errors=None): + """Return HTTP data""" + response = open_url(url, headers=headers, data=data, raise_errors=raise_errors) + if response: + json_data = get_json_data(response, fail=fail) + if json_data: + if cache: + from json import dumps + update_cache(cache, dumps(json_data)) + return json_data + return fail def delete_cache(cache_file, cache_dir=DEFAULT_CACHE_DIR): diff --git a/resources/lib/resumepoints.py b/resources/lib/resumepoints.py index 3391b655..8b1013b4 100644 --- a/resources/lib/resumepoints.py +++ b/resources/lib/resumepoints.py @@ -7,13 +7,12 @@ try: # Python 3 from urllib.error import HTTPError - from urllib.request import build_opener, install_opener, ProxyHandler, Request, urlopen except ImportError: # Python 2 - from urllib2 import build_opener, HTTPError, install_opener, ProxyHandler, Request, urlopen + from urllib2 import HTTPError from data import SECONDS_MARGIN -from kodiutils import (container_refresh, get_cache, get_proxies, get_setting_bool, get_url_json, has_credentials, - input_down, invalidate_caches, localize, log, log_error, notification, update_cache) +from kodiutils import (container_refresh, get_cache, get_setting_bool, get_url_json, has_credentials, input_down, + invalidate_caches, localize, log, log_error, notification, open_url, update_cache) class ResumePoints: @@ -22,12 +21,11 @@ class ResumePoints: def __init__(self): """Initialize resumepoints, relies on XBMC vfs and a special VRT token""" self._data = dict() # Our internal representation - install_opener(build_opener(ProxyHandler(get_proxies()))) @staticmethod def is_activated(): """Is resumepoints activated in the menu and do we have credentials ?""" - return get_setting_bool('useresumepoints', default=True) and has_credentials() + return get_setting_bool('usefavorites', default=True) and get_setting_bool('useresumepoints', default=True) and has_credentials() @staticmethod def resumepoint_headers(url=None): @@ -179,10 +177,9 @@ def delete_local(self, asset_id, menu_caches=None): def delete_online(self, asset_id): """Delete resumepoint online""" - req = Request('https://video-user-data.vrt.be/resume_points/{asset_id}'.format(asset_id=asset_id), headers=self.resumepoint_headers()) - req.get_method = lambda: 'DELETE' try: - result = urlopen(req) + result = open_url('https://video-user-data.vrt.be/resume_points/{asset_id}'.format(asset_id=asset_id), + headers=self.resumepoint_headers(), method='DELETE', raise_errors='all') log(3, "[Resumepoints] '{asset_id}' online deleted: {code}", asset_id=asset_id, code=result.getcode()) except HTTPError as exc: log_error("Failed to remove '{asset_id}' from resumepoints: {error}", asset_id=asset_id, error=exc) diff --git a/resources/lib/streamservice.py b/resources/lib/streamservice.py index 004e2976..d87e63f7 100644 --- a/resources/lib/streamservice.py +++ b/resources/lib/streamservice.py @@ -6,17 +6,16 @@ try: # Python 3 from urllib.error import HTTPError - from urllib.parse import quote, unquote, urlencode - from urllib.request import build_opener, install_opener, urlopen, ProxyHandler + from urllib.parse import quote, urlencode except ImportError: # Python 2 from urllib import urlencode - from urllib2 import build_opener, install_opener, urlopen, ProxyHandler, quote, unquote, HTTPError + from urllib2 import quote, HTTPError from helperobjects import ApiData, StreamURLS from kodiutils import (addon_profile, can_play_drm, container_reload, exists, end_of_directory, get_max_bandwidth, - get_proxies, get_setting_bool, get_url_json, has_inputstream_adaptive, - invalidate_caches, kodi_version_major, localize, log, log_error, mkdir, ok_dialog, open_settings, - supports_drm, to_unicode) + get_setting_bool, get_url_json, has_inputstream_adaptive, invalidate_caches, + kodi_version_major, localize, log, log_error, mkdir, ok_dialog, open_settings, + open_url, supports_drm, to_unicode) class StreamService: @@ -32,7 +31,6 @@ class StreamService: def __init__(self, _tokenresolver): """Initialize Stream Service class""" - install_opener(build_opener(ProxyHandler(get_proxies()))) self._tokenresolver = _tokenresolver self._create_settings_dir() self._can_play_drm = can_play_drm() @@ -309,14 +307,14 @@ def _select_hls_substreams(self, master_hls_url, protocol): hls_audio_id = None hls_subtitle_id = None hls_base_url = master_hls_url.split('.m3u8')[0] - log(2, 'URL get: {url}', url=unquote(master_hls_url)) try: - hls_playlist = to_unicode(urlopen(master_hls_url).read()) + response = open_url(master_hls_url, raise_errors=[415]) except HTTPError as exc: - if exc.code == 415: - self._handle_bad_stream_error(protocol, exc.code, exc.reason) - return None - raise + self._handle_bad_stream_error(protocol, exc.code, exc.reason) + return None + if response is None: + return None + hls_playlist = to_unicode(response.read()) max_bandwidth = get_max_bandwidth() stream_bandwidth = None diff --git a/resources/lib/tokenresolver.py b/resources/lib/tokenresolver.py index d0634d36..ad3aef2d 100644 --- a/resources/lib/tokenresolver.py +++ b/resources/lib/tokenresolver.py @@ -3,7 +3,7 @@ """This module contains all functionality for VRT NU API authentication.""" from __future__ import absolute_import, division, unicode_literals -from kodiutils import (addon_profile, delete, delete_cache, exists, get_cache, get_cache_dir, get_proxies, get_setting, +from kodiutils import (addon_profile, delete, delete_cache, exists, get_cache, get_cache_dir, get_setting, open_url, get_url_json, has_credentials, invalidate_caches, listdir, localize, log, log_error, notification, ok_dialog, open_settings, set_setting, update_cache) @@ -11,23 +11,14 @@ try: # Python 3 import http.cookiejar as cookielib - from urllib.parse import urlencode, unquote - from urllib.request import build_opener, install_opener, ProxyHandler, HTTPCookieProcessor, HTTPErrorProcessor, urlopen, Request + from urllib.error import HTTPError + from urllib.parse import urlencode except ImportError: # Python 2 from urllib import urlencode - from urllib2 import build_opener, install_opener, ProxyHandler, HTTPCookieProcessor, HTTPErrorProcessor, unquote, urlopen, Request + from urllib2 import HTTPError import cookielib -class NoRedirection(HTTPErrorProcessor): - """Prevent urllib from following http redirects""" - - def http_response(self, request, response): - return response - - https_response = http_response - - class TokenResolver: """Get, refresh and cache tokens for VRT NU API authentication.""" @@ -41,8 +32,6 @@ class TokenResolver: def __init__(self): """Initialize Token Resolver class""" - self._proxies = get_proxies() - install_opener(build_opener(ProxyHandler(self._proxies))) @staticmethod def _create_token_dictionary(cookie_data, cookie_name='X-VRT-Token'): @@ -110,6 +99,8 @@ def login(self, refresh=False, token_variant=None): while login_json.get('errorCode') != 0: # Show localized login error messages in Kodi GUI message = login_json.get('errorDetails') + if not message: + message = login_json or localize(30951) # Login failed! log_error('Login failed: {msg}', msg=message) if message == 'invalid loginID or password': message = localize(30953) # Invalid login! @@ -146,18 +137,16 @@ def _get_new_token(self, name, variant=None, url=None, roaming=False, login_json return self._get_playertoken(variant, url, roaming) if name in ('vrtlogin-at', 'vrtlogin-expiry', 'vrtlogin-rt', 'SESSION', 'OIDCXSRF', 'state'): - return self._get_usertoken(name) + return self._get_usertoken(name, roaming=roaming) return None - def _get_usertoken(self, name=None, login_json=None): + def _get_usertoken(self, name=None, login_json=None, roaming=False): """Get a user X-VRT-Token, vrtlogin-at, vrtlogin-expiry, vrtlogin-rt, SESSION, OIDCXSRF or state token""" if not login_json: login_json = self._get_login_json() cookiejar = cookielib.CookieJar() - opener = build_opener(HTTPCookieProcessor(cookiejar), ProxyHandler(self._proxies)) - log(2, 'URL get: {url}', url=unquote(self._USER_TOKEN_GATEWAY_URL)) - opener.open(self._USER_TOKEN_GATEWAY_URL) + open_url(self._USER_TOKEN_GATEWAY_URL, cookiejar=cookiejar) xsrf = next((cookie for cookie in cookiejar if cookie.name == 'OIDCXSRF'), None) if xsrf is None: return None @@ -169,8 +158,12 @@ def _get_usertoken(self, name=None, login_json=None): _csrf=xsrf.value ) data = urlencode(payload).encode() - log(2, 'URL post: {url}', url=unquote(self._VRT_LOGIN_URL)) - opener.open(self._VRT_LOGIN_URL, data=data) + destination = open_url(self._VRT_LOGIN_URL, data=data, cookiejar=cookiejar).geturl() + usertoken = TokenResolver._create_token_dictionary(cookiejar, name) + if not usertoken and not destination.startswith('https://www.vrt.be/vrtnu'): + if roaming is False: + ok_dialog(heading=localize(30970), message=localize(30972)) + return None # Cache additional tokens for later use refreshtoken = TokenResolver._create_token_dictionary(cookiejar, cookie_name='vrtlogin-rt') @@ -183,8 +176,7 @@ def _get_usertoken(self, name=None, login_json=None): from json import dumps cache_file = self._get_token_filename('vrtlogin-at') update_cache(cache_file, dumps(accesstoken), self._TOKEN_CACHE_DIR) - - return TokenResolver._create_token_dictionary(cookiejar, name) + return usertoken def _get_xvrttoken(self, login_json=None): """Get a one year valid X-VRT-Token""" @@ -203,9 +195,7 @@ def _get_xvrttoken(self, login_json=None): ) data = dumps(payload).encode() headers = {'Content-Type': 'application/json', 'Cookie': login_cookie} - log(2, 'URL post: {url}', url=unquote(self._TOKEN_GATEWAY_URL)) - req = Request(self._TOKEN_GATEWAY_URL, data=data, headers=headers) - setcookie_header = urlopen(req).info().get('Set-Cookie') + setcookie_header = open_url(self._TOKEN_GATEWAY_URL, data=data, headers=headers).info().get('Set-Cookie') xvrttoken = TokenResolver._create_token_dictionary(setcookie_header) if xvrttoken is None: return None @@ -214,25 +204,18 @@ def _get_xvrttoken(self, login_json=None): def _get_roaming_xvrttoken(self): """Get a X-VRT-Token for roaming""" - vrtlogin_at = self.get_token('vrtlogin-at') + vrtlogin_at = self.get_token('vrtlogin-at', roaming=True) if vrtlogin_at is None: return None cookie_value = 'vrtlogin-at=' + vrtlogin_at headers = {'Cookie': cookie_value} - opener = build_opener(NoRedirection, ProxyHandler(self._proxies)) - log(2, 'URL get: {url}', url=unquote(self._ROAMING_TOKEN_GATEWAY_URL)) - req = Request(self._ROAMING_TOKEN_GATEWAY_URL, headers=headers) - req_info = opener.open(req).info() + req_info = open_url(self._ROAMING_TOKEN_GATEWAY_URL, headers=headers, follow_redirects=False).info() cookie_value += '; state=' + req_info.get('Set-Cookie').split('state=')[1].split('; ')[0] - url = req_info.get('Location') - log(2, 'URL get: {url}', url=unquote(url)) - url = opener.open(url).info().get('Location') + url = open_url(req_info.get('Location'), follow_redirects=False).info().get('Location') headers = {'Cookie': cookie_value} if url is None: return None - req = Request(url, headers=headers) - log(2, 'URL get: {url}', url=unquote(url)) - setcookie_header = opener.open(req).info().get('Set-Cookie') + setcookie_header = open_url(url, headers=headers, follow_redirects=False).info().get('Set-Cookie') return TokenResolver._create_token_dictionary(setcookie_header) def get_token(self, name, variant=None, url=None, roaming=False): @@ -271,10 +254,10 @@ def _get_fresh_token(self, refresh_token, name): cookie_value = 'vrtlogin-rt=' + refresh_token headers = {'Cookie': cookie_value} cookiejar = cookielib.CookieJar() - opener = build_opener(HTTPCookieProcessor(cookiejar), ProxyHandler(self._proxies)) - req = Request(refresh_url, headers=headers) - log(2, 'URL get: {url}', url=refresh_url) - opener.open(req) + try: + open_url(refresh_url, headers=headers, cookiejar=cookiejar, raise_errors=[401]) + except HTTPError: + ok_dialog(heading=localize(30970), message=localize(30971)) return TokenResolver._create_token_dictionary(cookiejar, name) def _get_playertoken(self, variant, url, roaming=False): diff --git a/resources/lib/tvguide.py b/resources/lib/tvguide.py index 6c775d4e..65422c53 100644 --- a/resources/lib/tvguide.py +++ b/resources/lib/tvguide.py @@ -8,15 +8,10 @@ import dateutil.parser import dateutil.tz -try: # Python 3 - from urllib.request import build_opener, install_opener, ProxyHandler -except ImportError: # Python 2 - from urllib2 import build_opener, install_opener, ProxyHandler - from data import CHANNELS, RELATIVE_DATES from favorites import Favorites from helperobjects import TitleItem -from kodiutils import (colour, get_cached_url_json, get_proxies, get_url_json, has_addon, localize, +from kodiutils import (colour, get_cached_url_json, get_url_json, has_addon, localize, localize_datelong, show_listing, themecolour, ttl, url_for) from metadata import Metadata from resumepoints import ResumePoints @@ -33,7 +28,6 @@ def __init__(self): self._favorites = Favorites() self._resumepoints = ResumePoints() self._metadata = Metadata(self._favorites, self._resumepoints) - install_opener(build_opener(ProxyHandler(get_proxies()))) def show_tvguide(self, date=None, channel=None): """Offer a menu depending on the information provided""" @@ -302,6 +296,7 @@ def live_description(self, channel): episodes = iter(schedule.get(entry.get('id'), [])) description = '' + episode = None while True: try: episode = next(episodes) @@ -323,7 +318,7 @@ def live_description(self, channel): except StopIteration: break break - if not description: + if episode and not description: # Add a final 'No transmission' program description = '[COLOR={highlighted}][B]%s[/B] %s - 06:00\n» %s[/COLOR]' % (localize(30421), episode.get('end'), localize(30423)) return colour(description) diff --git a/resources/lib/webscraper.py b/resources/lib/webscraper.py index 6b583352..701f8a6b 100644 --- a/resources/lib/webscraper.py +++ b/resources/lib/webscraper.py @@ -6,16 +6,12 @@ try: # Python 3 from urllib.error import HTTPError - from urllib.parse import unquote - from urllib.request import build_opener, install_opener, urlopen, ProxyHandler except ImportError: # Python 2 - from urllib2 import build_opener, HTTPError, install_opener, ProxyHandler, unquote, urlopen + from urllib2 import HTTPError -from kodiutils import get_cache, get_setting_bool, get_proxies, log, log_error, ttl, update_cache +from kodiutils import get_cache, get_setting_bool, log_error, open_url, ttl, update_cache from utils import assetpath_to_id, add_https_proto, strip_newlines -install_opener(build_opener(ProxyHandler(get_proxies()))) - def valid_categories(categories): """Check if categories contain all necessary keys and values""" @@ -34,8 +30,7 @@ def get_categories(): # Try to scrape from the web if not valid_categories(categories): from bs4 import BeautifulSoup, SoupStrainer - log(2, 'URL get: https://www.vrt.be/vrtnu/categorieen/') - response = urlopen('https://www.vrt.be/vrtnu/categorieen/') + response = open_url('https://www.vrt.be/vrtnu/categorieen/') tiles = SoupStrainer('nui-list--content') soup = BeautifulSoup(response.read(), 'html.parser', parse_only=tiles) @@ -83,9 +78,8 @@ def get_video_attributes(vrtnu_url): # Scrape video attributes from bs4 import BeautifulSoup, SoupStrainer - log(2, 'URL get: {url}', url=unquote(vrtnu_url)) try: - html_page = urlopen(vrtnu_url).read() + html_page = open_url(vrtnu_url, raise_errors='all').read() except HTTPError as exc: log_error('Web scraping video attributes failed: {error}', error=exc) return None