add developer login

This commit is contained in:
anxdpanic 2018-07-27 14:24:41 -04:00
parent a7ad573eba
commit ee9527dcad
7 changed files with 467 additions and 92 deletions

View file

@ -0,0 +1,155 @@
from youtube_plugin.youtube.provider import Provider
from youtube_plugin.kodion.impl import Context
from youtube_plugin.youtube.helper import yt_login
from youtube_plugin.youtube.youtube_exceptions import LoginException # NOQA
SIGN_IN = 'in'
SIGN_OUT = 'out'
def __add_new_developer(addon_id):
"""
:param addon_id: id of the add-on being added
:return:
"""
params = {'addon_id': addon_id}
context = Context(params=params, plugin_id='plugin.video.youtube')
access_manager = context.get_access_manager()
developers = access_manager.get_developers()
if not developers.get(addon_id, None):
developers[addon_id] = access_manager.get_new_developer()
access_manager.set_developers(developers)
context.log_debug('Creating developer user: |%s|' % addon_id)
def __auth(addon_id, mode=SIGN_IN):
"""
:param addon_id: id of the add-on being signed in
:param mode: SIGN_IN or SIGN_OUT
:return: addon provider, context and client
"""
if not addon_id or addon_id == 'plugin.video.youtube':
context = Context(plugin_id='plugin.video.youtube')
context.log_error('Developer authentication: |%s| Invalid addon_id' % addon_id)
return
__add_new_developer(addon_id)
params = {'addon_id': addon_id}
provider = Provider()
context = Context(params=params, plugin_id='plugin.video.youtube')
client = provider.get_client(context=context) # NOQA
logged_in = provider.is_logged_in()
if mode == SIGN_IN:
if logged_in:
return True
else:
provider.reset_client()
yt_login.process(mode, provider, context, re_match=None, sign_out_refresh=False)
elif mode == SIGN_OUT:
if not logged_in:
return True
else:
provider.reset_client()
try:
yt_login.process(mode, provider, context, re_match=None, sign_out_refresh=False)
except:
reset_access_tokens(addon_id)
else:
raise Exception('Unknown mode: |%s|' % mode)
client = provider.get_client(context=context) # NOQA
if mode == SIGN_IN:
return provider.is_logged_in()
else:
return not provider.is_logged_in()
def sign_in(addon_id):
"""
To use the signed in context, see youtube_registration.py and youtube_requests.py
Usage:
addon.xml
---
<import addon="plugin.video.youtube" version="6.1.0"/>
---
.py
---
import youtube_registration
import youtube_authentication
youtube_registration.register_api_keys(addon_id='plugin.video.example',
api_key='A1zaSyA0b5sTjgxzTzYLmVtradlFVBfSHNOJKS0',
client_id='825419953561-ert5tccq1r0upsuqdf5nm3le39czk23a.apps.googleusercontent.com',
client_secret='Y5cE1IKzJQe1NZ0OsOoEqpu3')
try:
signed_in = youtube_authentication.sign_in(addon_id='plugin.video.example') # refreshes access tokens if already signed in
except youtube_authentication.LoginException as e:
error_message = e.get_message()
# handle error
signed_in = False
if signed_in:
pass # see youtube_registration.py and youtube_requests.py to use the signed in context
---
:param addon_id: id of the add-on being signed in
:return: boolean, True when signed in
"""
return __auth(addon_id, mode=SIGN_IN)
def sign_out(addon_id):
"""
Usage:
addon.xml
---
<import addon="plugin.video.youtube" version="6.1.0"/>
---
.py
---
import youtube_registration
import youtube_authentication
youtube_registration.register_api_keys(addon_id='plugin.video.example',
api_key='A1zaSyA0b5sTjgxzTzYLmVtradlFVBfSHNOJKS0',
client_id='825419953561-ert5tccq1r0upsuqdf5nm3le39czk23a.apps.googleusercontent.com',
client_secret='Y5cE1IKzJQe1NZ0OsOoEqpu3')
signed_out = youtube_authentication.sign_out(addon_id='plugin.video.example')
if signed_out:
pass
---
:param addon_id: id of the add-on being signed out
:return: boolean, True when signed out
"""
return __auth(addon_id, mode=SIGN_OUT)
def reset_access_tokens(addon_id):
"""
:param addon_id: id of the add-on having it's access tokens reset
:return:
"""
if not addon_id or addon_id == 'plugin.video.youtube':
context = Context(plugin_id='plugin.video.youtube')
context.log_error('Developer reset access tokens: |%s| Invalid addon_id' % addon_id)
return
params = {'addon_id': addon_id}
context = Context(params=params, plugin_id='plugin.video.youtube')
access_manager = context.get_access_manager()
access_manager.update_dev_access_token(addon_id, access_token='', refresh_token='')

View file

@ -37,6 +37,8 @@ class LoginTokenStore(JSONStore):
data['access_manager']['current_user'] = '0'
if 'last_origin' not in data['access_manager']:
data['access_manager']['last_origin'] = 'plugin.video.youtube'
if 'developers' not in data['access_manager']:
data['access_manager']['developers'] = dict()
# clean up
if data['access_manager']['current_user'] == 'default':

View file

@ -1,6 +1,8 @@
import uuid
import time
from hashlib import md5
from ..json_store import LoginTokenStore
__author__ = 'bromix'
@ -22,9 +24,10 @@ class AccessManager(object):
self._json = self._jstore.get_data()
return self._json['access_manager']['users'][self.get_user()]['id']
def get_new_user(self, user_name):
def get_new_user(self, user_name='', addon_id=''):
"""
:param user_name: string, users name
:param addon_id: string, addon id
:return: a new user dict
"""
uuids = list()
@ -196,6 +199,8 @@ class AccessManager(object):
"""
Updates the old access token with the new one.
:param access_token:
:param unix_timestamp:
:param refresh_token:
:return:
"""
self._json = self._jstore.get_data()
@ -208,3 +213,127 @@ class AccessManager(object):
self._json['access_manager']['users'][self._user]['refresh_token'] = refresh_token
self._jstore.save(self._json)
def get_new_developer(self, addon_id):
"""
:param addon_id: string, addon id
:return: a new developer dict
"""
return {'access_token': '', 'refresh_token': '', 'token_expires': -1, 'last_key_hash': ''}
def get_developers(self):
"""
Returns developers
:return: dict, developers
"""
return self._json['access_manager'].get('developers', {})
def set_developers(self, developers):
"""
Updates the users
:param developers: dict, developers
:return:
"""
self._json = self._jstore.get_data()
self._json['access_manager']['developers'] = developers
self._jstore.save(self._json)
def get_dev_access_token(self, addon_id):
"""
Returns the access token for some API
:param addon_id: addon id
:return: access_token
"""
self._json = self._jstore.get_data()
return self._json['access_manager']['developers'].get(addon_id, {}).get('access_token', '')
def get_dev_refresh_token(self, addon_id):
"""
Returns the refresh token
:return: refresh token
"""
self._json = self._jstore.get_data()
return self._json['access_manager']['developers'].get(addon_id, {}).get('refresh_token', '')
def developer_has_refresh_token(self, addon_id):
return self.get_dev_refresh_token(addon_id) != ''
def is_dev_access_token_expired(self, addon_id):
"""
Returns True if the access_token is expired otherwise False.
If no expiration date was provided and an access_token exists
this method will always return True
:return:
"""
self._json = self._jstore.get_data()
access_token = self._json['access_manager']['developers'].get(addon_id, {}).get('access_token', '')
expires = int(self._json['access_manager']['developers'].get(addon_id, {}).get('token_expires', -1))
# with no access_token it must be expired
if not access_token:
return True
# in this case no expiration date was set
if expires == -1:
return False
now = int(time.time())
return expires <= now
def update_dev_access_token(self, addon_id, access_token, unix_timestamp=None, refresh_token=None):
"""
Updates the old access token with the new one.
:param addon_id:
:param access_token:
:param unix_timestamp:
:param refresh_token:
:return:
"""
self._json = self._jstore.get_data()
self._json['access_manager']['developers'][addon_id]['access_token'] = access_token
if unix_timestamp is not None:
self._json['access_manager']['developers'][addon_id]['token_expires'] = int(unix_timestamp)
if refresh_token is not None:
self._json['access_manager']['developers'][addon_id]['refresh_token'] = refresh_token
self._jstore.save(self._json)
def get_dev_last_key_hash(self, addon_id):
self._json = self._jstore.get_data()
return self._json['access_manager']['developers'][addon_id]['last_key_hash']
def set_dev_last_key_hash(self, addon_id, key_hash):
self._json = self._jstore.get_data()
self._json['access_manager']['developers'][addon_id]['last_key_hash'] = key_hash
self._jstore.save(self._json)
def dev_keys_changed(self, addon_id, api_key, client_id, client_secret):
self._json = self._jstore.get_data()
last_hash = self._json['access_manager']['developers'][addon_id]['last_key_hash']
current_hash = self.__calc_key_hash(api_key, client_id, client_secret)
if not last_hash and current_hash:
self.set_dev_last_key_hash(addon_id, current_hash)
return False
if last_hash != current_hash:
self.set_dev_last_key_hash(addon_id, current_hash)
return True
else:
return False
@staticmethod
def __calc_key_hash(api_key, client_id, client_secret):
m = md5()
try:
m.update(api_key.encode('utf-8'))
m.update(client_id.encode('utf-8'))
m.update(client_secret.encode('utf-8'))
except:
m.update(api_key)
m.update(client_id)
m.update(client_secret)
return m.hexdigest()

View file

@ -9,21 +9,36 @@ from ...youtube.youtube_exceptions import LoginException
def process(mode, provider, context, re_match, sign_out_refresh=True):
addon_id = context.get_param('addon_id', None)
def _do_logout():
# we clear the cache, so none cached data of an old account will be displayed.
provider.get_resource_manager(context).clear()
signout_access_manager = context.get_access_manager()
if signout_access_manager.has_refresh_token():
refresh_tokens = signout_access_manager.get_refresh_token().split('|')
refresh_tokens = list(set(refresh_tokens))
for _refresh_token in refresh_tokens:
provider.get_client(context).revoke(_refresh_token)
if addon_id:
if signout_access_manager.developer_has_refresh_token(addon_id):
refresh_tokens = signout_access_manager.get_dev_refresh_token(addon_id).split('|')
refresh_tokens = list(set(refresh_tokens))
for _refresh_token in refresh_tokens:
provider.get_client(context).revoke(_refresh_token)
else:
if signout_access_manager.has_refresh_token():
refresh_tokens = signout_access_manager.get_refresh_token().split('|')
refresh_tokens = list(set(refresh_tokens))
for _refresh_token in refresh_tokens:
provider.get_client(context).revoke(_refresh_token)
provider.reset_client()
signout_access_manager.update_access_token(access_token='', refresh_token='')
if addon_id:
signout_access_manager.update_dev_access_token(addon_id, access_token='', refresh_token='')
else:
signout_access_manager.update_access_token(access_token='', refresh_token='')
def _do_login(_for_tv=False):
_client = provider.get_client(context)
try:
if _for_tv:
json_data = _client.request_device_and_user_code_tv()
@ -32,6 +47,7 @@ def process(mode, provider, context, re_match, sign_out_refresh=True):
except LoginException:
_do_logout()
raise
interval = int(json_data.get('interval', 5)) * 1000
if interval > 60000:
interval = 5000
@ -89,6 +105,7 @@ def process(mode, provider, context, re_match, sign_out_refresh=True):
_do_logout()
if sign_out_refresh:
context.get_ui().refresh_container()
elif mode == 'in':
context.get_ui().on_ok(context.localize(provider.LOCAL_MAP['youtube.sign.twice.title']),
context.localize(provider.LOCAL_MAP['youtube.sign.twice.text']))
@ -98,7 +115,10 @@ def process(mode, provider, context, re_match, sign_out_refresh=True):
context.log_debug('YouTube-TV Login: Access Token |%s| Refresh Token |%s| Expires |%s|' % (access_token_tv != '', refresh_token_tv != '', expires_in_tv))
if not access_token_tv and not refresh_token_tv:
provider.reset_client()
context.get_access_manager().update_access_token('')
if addon_id:
context.get_access_manager().update_dev_access_token(addon_id, '')
else:
context.get_access_manager().update_access_token('')
context.get_ui().refresh_container()
return
@ -107,7 +127,10 @@ def process(mode, provider, context, re_match, sign_out_refresh=True):
context.log_debug('YouTube-Kodi Login: Access Token |%s| Refresh Token |%s| Expires |%s|' % (access_token_kodi != '', refresh_token_kodi != '', expires_in_kodi))
if not access_token_kodi and not refresh_token_kodi:
provider.reset_client()
context.get_access_manager().update_access_token('')
if addon_id:
context.get_access_manager().update_dev_access_token(addon_id, '')
else:
context.get_access_manager().update_access_token('')
context.get_ui().refresh_container()
return
@ -119,5 +142,10 @@ def process(mode, provider, context, re_match, sign_out_refresh=True):
provider.get_resource_manager(context).clear()
provider.reset_client()
context.get_access_manager().update_access_token(access_token, expires_in, refresh_token)
if addon_id:
context.get_access_manager().update_dev_access_token(addon_id, access_token, expires_in, refresh_token)
else:
context.get_access_manager().update_access_token(access_token, expires_in, refresh_token)
context.get_ui().refresh_container()

View file

@ -162,7 +162,7 @@ class Provider(kodion.AbstractProvider):
_dev_config = context.get_ui().get_home_window_property('configs')
context.get_ui().clear_home_window_property('configs')
dev_config = None
dev_config = dict()
if _dev_config is not None:
context.log_debug('Using window property for developer keys is deprecated, instead use the youtube_registration module.')
try:
@ -172,7 +172,7 @@ class Provider(kodion.AbstractProvider):
if not dev_config and addon_id and dev_configs:
dev_config = dev_configs.get(addon_id)
if dev_config is not None and not context.get_settings().allow_dev_keys():
if dev_config and not context.get_settings().allow_dev_keys():
context.log_debug('Developer config ignored')
return None
elif dev_config:
@ -181,7 +181,7 @@ class Provider(kodion.AbstractProvider):
or not dev_config['main'].get('id') or not dev_config['main'].get('secret'):
context.log_error('Error loading developer config: |invalid structure| '
'expected: |{"origin": ADDON_ID, "main": {"system": SYSTEM_NAME, "key": API_KEY, "id": CLIENT_ID, "secret": CLIENT_SECRET}}|')
return None
return dict()
else:
dev_origin = dev_config['origin']
dev_main = dev_config['main']
@ -197,7 +197,7 @@ class Provider(kodion.AbstractProvider):
context.log_debug('Using developer config: origin: |{0}| system |{1}|'.format(dev_origin, dev_system))
return {'origin': dev_origin, 'main': {'id': dev_id, 'secret': dev_secret, 'key': dev_key, 'system': dev_system}}
else:
return None
return dict()
def reset_client(self):
self._client = None
@ -221,88 +221,136 @@ class Provider(kodion.AbstractProvider):
dev_id = context.get_param('addon_id', None)
dev_configs = YouTube.CONFIGS.get('developer')
dev_config = self.get_dev_config(context, dev_id, dev_configs)
dev_keys = dict()
if dev_config:
dev_keys = dev_config.get('main')
if api_last_origin != dev_config.get('origin'):
context.log_debug('API key origin changed, clearing cache. |%s|' % dev_config.get('origin'))
client = None
refresh_tokens = list()
if dev_id:
dev_origin = dev_config.get('origin') if dev_config.get('origin') else dev_id
if api_last_origin != dev_origin:
context.log_debug('API key origin changed, clearing cache. |%s|' % dev_origin)
access_manager.set_last_origin(dev_origin)
self.get_resource_manager(context).clear()
access_manager.set_last_origin(dev_config.get('origin'))
self._client = YouTube(items_per_page=items_per_page, language=language, region=region, config=dev_keys)
self._client.set_log_error(context.log_error)
else:
if api_last_origin != 'plugin.video.youtube':
context.log_debug('API key origin changed, clearing cache. |plugin.video.youtube|')
self.get_resource_manager(context).clear()
access_manager.set_last_origin('plugin.video.youtube')
self.get_resource_manager(context).clear()
if dev_id:
access_tokens = access_manager.get_dev_access_token(dev_id).split('|')
if len(access_tokens) != 2 or access_manager.is_dev_access_token_expired(dev_id):
# reset access_token
access_manager.update_dev_access_token(dev_id, '')
access_tokens = list()
else:
access_tokens = access_manager.get_access_token().split('|')
if len(access_tokens) != 2 or access_manager.is_access_token_expired():
# reset access_token
access_manager.update_access_token('')
# we clear the cache, so none cached data of an old account will be displayed.
# context.get_function_cache().clear()
# reset the client
self._client = None
access_tokens = list()
if not self._client:
context.log_debug('Selecting YouTube config "%s"' % youtube_config['system'])
if dev_id:
if dev_keys:
context.log_debug('Selecting YouTube developer config "%s"' % dev_id)
else:
context.log_debug('Selecting YouTube config "%s" w/ developer access tokens' % youtube_config['system'])
if access_manager.has_refresh_token():
if YouTube.api_keys_changed:
context.log_warning('API key set changed: Resetting client and updating access token')
self.reset_client()
access_manager.update_access_token(access_token='', refresh_token='')
access_tokens = access_manager.get_access_token()
if access_tokens:
access_tokens = access_tokens.split('|')
refresh_tokens = access_manager.get_refresh_token()
if refresh_tokens:
refresh_tokens = refresh_tokens.split('|')
context.log_debug('Access token count: |%d| Refresh token count: |%d|' % (len(access_tokens), len(refresh_tokens)))
# create a new access_token
client = YouTube(language=language, region=region, items_per_page=items_per_page, config=youtube_config)
if len(access_tokens) != 2 and len(refresh_tokens) == 2:
try:
access_token_kodi, expires_in_kodi = client.refresh_token(refresh_tokens[1])
access_token_tv, expires_in_tv = client.refresh_token_tv(refresh_tokens[0])
access_tokens = [access_token_tv, access_token_kodi]
access_token = '%s|%s' % (access_token_tv, access_token_kodi)
expires_in = min(expires_in_tv, expires_in_kodi)
access_manager.update_access_token(access_token, expires_in)
except LoginException as ex:
self.handle_exception(context, ex)
access_tokens = ['', '']
# reset access_token
access_manager.update_access_token('')
# we clear the cache, so none cached data of an old account will be displayed.
self.get_resource_manager(context).clear()
# in debug log the login status
self._is_logged_in = len(access_tokens) == 2
if self._is_logged_in:
context.log_debug('User is logged in')
else:
context.log_debug('User is not logged in')
if len(access_tokens) == 0:
access_tokens = ['', '']
client.set_access_token(access_token=access_tokens[1])
client.set_access_token_tv(access_token_tv=access_tokens[0])
self._client = client
self._client.set_log_error(context.log_error)
if access_manager.developer_has_refresh_token(dev_id):
if dev_keys:
keys_changed = access_manager.dev_keys_changed(dev_id, dev_keys['key'], dev_keys['id'], dev_keys['secret'])
else:
self._client = YouTube(items_per_page=items_per_page, language=language, region=region, config=youtube_config)
self._client.set_log_error(context.log_error)
keys_changed = access_manager.dev_keys_changed(dev_id, youtube_config['key'], youtube_config['id'], youtube_config['secret'])
# in debug log the login status
context.log_debug('User is not logged in')
if keys_changed:
context.log_warning('API key set changed: Resetting client and updating access token')
self.reset_client()
access_manager.update_dev_access_token(dev_id, access_token='', refresh_token='')
access_tokens = access_manager.get_dev_access_token(dev_id)
if access_tokens:
access_tokens = access_tokens.split('|')
refresh_tokens = access_manager.get_dev_refresh_token(dev_id)
if refresh_tokens:
refresh_tokens = refresh_tokens.split('|')
context.log_debug('Access token count: |%d| Refresh token count: |%d|' % (len(access_tokens), len(refresh_tokens)))
# create a new access_token
if dev_keys:
client = YouTube(language=language, region=region, items_per_page=items_per_page, config=dev_keys)
else:
client = YouTube(language=language, region=region, items_per_page=items_per_page, config=youtube_config)
else:
context.log_debug('Selecting YouTube config "%s"' % youtube_config['system'])
if access_manager.has_refresh_token():
if YouTube.api_keys_changed:
context.log_warning('API key set changed: Resetting client and updating access token')
self.reset_client()
access_manager.update_access_token(access_token='', refresh_token='')
access_tokens = access_manager.get_access_token()
if access_tokens:
access_tokens = access_tokens.split('|')
refresh_tokens = access_manager.get_refresh_token()
if refresh_tokens:
refresh_tokens = refresh_tokens.split('|')
context.log_debug('Access token count: |%d| Refresh token count: |%d|' % (len(access_tokens), len(refresh_tokens)))
# create a new access_token
client = YouTube(language=language, region=region, items_per_page=items_per_page, config=youtube_config)
if client:
if len(access_tokens) != 2 and len(refresh_tokens) == 2:
try:
access_token_kodi, expires_in_kodi = client.refresh_token(refresh_tokens[1])
access_token_tv, expires_in_tv = client.refresh_token_tv(refresh_tokens[0])
access_tokens = [access_token_tv, access_token_kodi]
access_token = '%s|%s' % (access_token_tv, access_token_kodi)
expires_in = min(expires_in_tv, expires_in_kodi)
if dev_id:
access_manager.update_dev_access_token(dev_id, access_token, expires_in)
else:
access_manager.update_access_token(access_token, expires_in)
except LoginException as ex:
self.handle_exception(context, ex)
access_tokens = ['', '']
# reset access_token
if dev_id:
access_manager.update_dev_access_token(dev_id, '')
else:
access_manager.update_access_token('')
# we clear the cache, so none cached data of an old account will be displayed.
self.get_resource_manager(context).clear()
# in debug log the login status
self._is_logged_in = len(access_tokens) == 2
if self._is_logged_in:
context.log_debug('User is logged in')
else:
context.log_debug('User is not logged in')
if len(access_tokens) == 0:
access_tokens = ['', '']
client.set_access_token(access_token=access_tokens[1])
client.set_access_token_tv(access_token_tv=access_tokens[0])
self._client = client
self._client.set_log_error(context.log_error)
else:
self._client = YouTube(items_per_page=items_per_page, language=language, region=region, config=youtube_config)
self._client.set_log_error(context.log_error)
# in debug log the login status
context.log_debug('User is not logged in')
return self._client

View file

@ -22,6 +22,7 @@ def register_api_keys(addon_id, api_key, client_id, client_secret):
# then use your keys by appending an addon_id param to the plugin url
xbmc.executebuiltin('RunPlugin(plugin://plugin.video.youtube/channel/UCaBf1a-dpIsw8OxqH4ki2Kg/?addon_id=plugin.video.example)')
# addon_id will be passed to all following calls
# also see youtube_authentication.py and youtube_requests.py
---
:param addon_id: id of the add-on being registered
@ -39,6 +40,8 @@ def register_api_keys(addon_id, api_key, client_id, client_secret):
api_jstore = APIKeyStore()
json_api = api_jstore.get_data()
access_manager = context.get_access_manager()
jkeys = json_api['keys']['developer'].get(addon_id, {})
api_keys = {'origin': addon_id, 'main': {'system': 'JSONStore', 'key': b64encode(api_key), 'id': b64encode(client_id), 'secret': b64encode(client_secret)}}
@ -48,3 +51,9 @@ def register_api_keys(addon_id, api_key, client_id, client_secret):
json_api['keys']['developer'][addon_id] = api_keys
api_jstore.save(json_api)
context.log_debug('Register API Keys: |%s| Keys registered' % addon_id)
developers = access_manager.get_developers()
if not developers.get(addon_id, None):
developers[addon_id] = access_manager.get_new_developer()
access_manager.set_developers(developers)
context.log_debug('Creating developer user: |%s|' % addon_id)

View file

@ -2,7 +2,11 @@ from youtube_plugin.youtube.provider import Provider
from youtube_plugin.kodion.impl import Context
def get_core_components(addon_id=None):
def __get_core_components(addon_id=None):
"""
:param addon_id: addon id associated with developer keys to use for requests
:return: addon provider, context and client
"""
provider = Provider()
if addon_id is not None:
context = Context(params={'addon_id': addon_id}, plugin_id='plugin.video.youtube')
@ -30,7 +34,7 @@ def v3_request(method='GET', headers=None, path=None, post_data=None, params=Non
:param addon_id: addon id associated with developer keys to use for requests
:type addon_id: str
"""
provider, context, client = get_core_components(addon_id)
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, allow_redirects=allow_redirects)
@ -52,7 +56,7 @@ def get_videos(video_id, addon_id=None):
see also https://developers.google.com/youtube/v3/docs/videos#resource
:rtype: list of dict
"""
provider, context, client = get_core_components(addon_id)
provider, context, client = __get_core_components(addon_id)
json_data = client.get_videos(video_id)
if not handle_error(context, json_data):
@ -76,7 +80,7 @@ def get_activities(channel_id, page_token='', all_pages=False, addon_id=None):
last item contains nextPageToken
:rtype: list of dict
"""
provider, context, client = get_core_components(addon_id)
provider, context, client = __get_core_components(addon_id)
items = []
@ -117,7 +121,7 @@ def get_playlist_items(playlist_id, page_token='', all_pages=False, addon_id=Non
last item contains nextPageToken
:rtype: list of dict
"""
provider, context, client = get_core_components(addon_id)
provider, context, client = __get_core_components(addon_id)
items = []
@ -153,7 +157,7 @@ def get_channel_id(channel_name, addon_id=None):
see also https://developers.google.com/youtube/v3/docs/channels#resource
:rtype: list of dict
"""
provider, context, client = get_core_components(addon_id)
provider, context, client = __get_core_components(addon_id)
json_data = client.get_channel_by_username(channel_name)
if not handle_error(context, json_data):
@ -173,7 +177,7 @@ def get_channels(channel_id, addon_id=None):
see also https://developers.google.com/youtube/v3/docs/channels#resource
:rtype: list of dict
"""
provider, context, client = get_core_components(addon_id)
provider, context, client = __get_core_components(addon_id)
json_data = client.get_channels(channel_id)
if not handle_error(context, json_data):
@ -193,7 +197,7 @@ def get_channel_sections(channel_id, addon_id=None):
see also https://developers.google.com/youtube/v3/docs/channelSections#resource
:rtype: list of dict
"""
provider, context, client = get_core_components(addon_id)
provider, context, client = __get_core_components(addon_id)
json_data = client.get_channel_sections(channel_id)
if not handle_error(context, json_data):
@ -218,7 +222,7 @@ def get_playlists_of_channel(channel_id, page_token='', all_pages=False, addon_i
last item contains nextPageToken
:rtype: list of dict
"""
provider, context, client = get_core_components(addon_id)
provider, context, client = __get_core_components(addon_id)
items = []
@ -254,7 +258,7 @@ def get_playlists(playlist_id, addon_id=None):
see also https://developers.google.com/youtube/v3/docs/playlists#resource
:rtype: list of dict
"""
provider, context, client = get_core_components(addon_id)
provider, context, client = __get_core_components(addon_id)
json_data = client.get_playlists(playlist_id)
if not handle_error(context, json_data):
@ -278,7 +282,7 @@ def get_related_videos(video_id, page_token='', addon_id=None):
:rtype: list of dict
:note: this is a search api request with high cost
"""
provider, context, client = get_core_components(addon_id)
provider, context, client = __get_core_components(addon_id)
items = []
@ -328,7 +332,7 @@ def get_search(q, search_type='', event_type='', channel_id='', order='relevance
:note: this is a search api request with high cost
"""
search_type = search_type or ['video', 'channel', 'playlist']
provider, context, client = get_core_components(addon_id)
provider, context, client = __get_core_components(addon_id)
items = []