Skip to content

Commit

Permalink
Merge pull request #981 from MoojMidge/v7.1.1
Browse files Browse the repository at this point in the history
v7.1.1.1
  • Loading branch information
MoojMidge authored Nov 15, 2024
2 parents b385da9 + abc7cf1 commit 1f52678
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 95 deletions.
2 changes: 1 addition & 1 deletion addon.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.youtube" name="YouTube" version="7.1.1" provider-name="anxdpanic, bromix, MoojMidge">
<addon id="plugin.video.youtube" name="YouTube" version="7.1.1.1" provider-name="anxdpanic, bromix, MoojMidge">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.requests" version="2.27.1"/>
Expand Down
6 changes: 5 additions & 1 deletion changelog.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## v7.1.1
## v7.1.1.1
### Fixed
- Fix http server not listening on any interface if listen IP is 0.0.0.0 #927
- Standardise return type of LoginClient.refresh_token #932
Expand Down Expand Up @@ -29,6 +29,10 @@
- Fix loading of Watch Later playlist #971
- Also fix other incorrect/missing parameter names
- Fix possible exception if plugin navigation fails #976
- Fix sign in when one or more access token requests fail #979
- Attempt to fix possible deadlock on http server shutdown
- Fix potential infinite loop with old data from access_manager.json #980
- Reduce unnecessary window navigation fallback attempts

### Changed
- Improve display and update of bookmarks
Expand Down
7 changes: 1 addition & 6 deletions resources/lib/youtube_plugin/kodion/abstract_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,7 @@ def reroute(self, context, path=None, params=None, uri=None):
container_uri = context.get_infolabel('Container.FolderPath')
if context.is_plugin_path(container_uri):
context.log_debug('Rerouting - Fallback route not required')
return (
False,
{
self.RESULT_FALLBACK: False,
},
)
return False, {self.RESULT_FALLBACK: False}

if 'refresh' in params:
container = context.get_infolabel('System.CurrentControlId')
Expand Down
17 changes: 15 additions & 2 deletions resources/lib/youtube_plugin/kodion/monitors/service_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ def start_httpd(self):
return False

self.httpd_thread = threading.Thread(target=self.httpd.serve_forever)
self.httpd_thread.daemon = True
self.httpd_thread.start()

address = self.httpd.socket.getsockname()
Expand All @@ -280,9 +281,21 @@ def shutdown_httpd(self):
.format(ip=self._old_httpd_address,
port=self._old_httpd_port))
self.httpd_address_sync()
self.httpd.shutdown()

shutdown_thread = threading.Thread(target=self.httpd.shutdown)
shutdown_thread.daemon = True
shutdown_thread.start()

for thread in (self.httpd_thread, shutdown_thread):
if not thread.is_alive():
continue
try:
thread.join(5)
except RuntimeError:
pass

self.httpd.server_close()
self.httpd_thread.join()

self.httpd_thread = None
self.httpd = None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def run(self, provider, context, focused=None):
result, options = provider.navigate(context)
except KodionException as exc:
result = options = None
if provider.handle_exception(context, exc):
if not provider.handle_exception(context, exc):
msg = ('XbmcRunner.run - Error'
'\n\tException: {exc!r}'
'\n\tStack trace (most recent call last):\n{stack}'
Expand Down
6 changes: 3 additions & 3 deletions resources/lib/youtube_plugin/youtube/client/login_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def refresh_token(self, token_type, refresh_token=None):
error_title='Login Failed',
error_info=('Refresh token - Failed'
'\n\tException: {{exc!r}}'
'\n\tClient: |{client}|'
'{client}'
.format(client=client)),
raise_exc=True)
return json_data
Expand Down Expand Up @@ -204,7 +204,7 @@ def request_access_token(self, token_type, code=None):
error_title='Login Failed: Unknown response',
error_info=('Access token request - Failed'
'\n\tException: {{exc!r}}'
'\n\tClient: |{client}|'
'{client}'
.format(client=client)),
raise_exc=True)
return json_data
Expand Down Expand Up @@ -247,7 +247,7 @@ def request_device_and_user_code(self, token_type):
error_title='Login Failed: Unknown response',
error_info=('Device/user code request - Failed'
'\n\tException: {{exc!r}}'
'\n\tClient: |{client}|'
'{client}'
.format(client=client)),
raise_exc=True)
return json_data
Expand Down
16 changes: 5 additions & 11 deletions resources/lib/youtube_plugin/youtube/helper/yt_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def process(mode, provider, context, sign_out_refresh=True):
def _do_logout():
refresh_tokens = access_manager.get_refresh_token()
client = provider.get_client(context)
if refresh_tokens:
if any(refresh_tokens):
for _refresh_token in set(refresh_tokens):
try:
if _refresh_token:
Expand Down Expand Up @@ -121,24 +121,18 @@ def _do_login(token_type):

tokens = ['tv', 'personal']
for token_type, token in enumerate(tokens):
new_token = _do_login(token_type)
new_token = _do_login(token_type) or (None, 0, None)
tokens[token_type] = new_token
if new_token:
access_token, expiry, refresh_token = new_token
else:
access_token = None
expiry = 0
refresh_token = None

context.log_debug('YouTube Login:'
'\n\tType: |{0}|'
'\n\tAccess token: |{1}|'
'\n\tRefresh token: |{2}|'
'\n\tExpires: |{3}|'
.format(token,
bool(access_token),
bool(refresh_token),
expiry))
bool(new_token[0]),
bool(new_token[2]),
new_token[1]))

provider.reset_client()
access_manager.update_access_token(addon_id, *zip(*tokens))
Expand Down
2 changes: 1 addition & 1 deletion resources/lib/youtube_plugin/youtube/helper/yt_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def _process_rate_video(provider, context, re_match):
client = provider.get_client(context)
json_data = client.get_video_rating(video_id)
if not json_data:
return False
return False, {provider.RESULT_FALLBACK: False}

items = json_data.get('items', [])
if items:
Expand Down
137 changes: 68 additions & 69 deletions resources/lib/youtube_plugin/youtube/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def get_client(self, context):
.format(dev_keys['system']))

refresh_tokens = access_manager.get_refresh_token(dev_id)
if refresh_tokens:
if any(refresh_tokens):
keys_changed = access_manager.dev_keys_changed(
dev_id, dev_keys['key'], dev_keys['id'], dev_keys['secret']
) if dev_id else self._api_check.changed
Expand Down Expand Up @@ -767,19 +767,19 @@ def on_sign(provider, context, re_match):

if mode == 'in' or (mode == 'out' and sign_out_confirmed):
yt_login.process(mode, provider, context)
return False
return True

def _search_channel_or_playlist(self, context, identifier):
if re.match(r'U[CU][0-9a-zA-Z_\-]{20,24}', identifier):
json_data = self.get_client(context).get_channels(identifier)
elif re.match(r'[OP]L[0-9a-zA-Z_\-]{30,40}', identifier):
json_data = self.get_client(context).get_playlists(identifier)
else:
return False
return None

if json_data:
return v3.response_to_items(self, context, json_data)
return False
return None

def on_search_run(self, context, query):
data_cache = context.get_data_cache()
Expand Down Expand Up @@ -937,7 +937,7 @@ def on_configure_addon(provider, context, re_match):
action = re_match.group('action')
if action == 'setup_wizard':
provider.run_wizard(context)
return False
return False, {provider.RESULT_FALLBACK: False}
return UriItem('script://{addon},config/{action}'.format(
addon=ADDON_ID, action=action
))
Expand Down Expand Up @@ -1014,7 +1014,7 @@ def on_maintenance_actions(provider, context, re_match):
client = provider.get_client(context)
refresh_tokens = access_manager.get_refresh_token()
success = True
if refresh_tokens:
if any(refresh_tokens):
for refresh_token in set(refresh_tokens):
try:
if refresh_token:
Expand Down Expand Up @@ -1136,7 +1136,7 @@ def on_playback_history(provider, context, re_match):
localize('history.clear'),
localize('history.clear.check')
):
return False
return False, {provider.RESULT_FALLBACK: False}

playback_history.clear()
ui.refresh_container()
Expand All @@ -1159,7 +1159,7 @@ def on_playback_history(provider, context, re_match):
localize('content.remove'),
localize('content.remove.check') % video_name,
):
return False
return False, {provider.RESULT_FALLBACK: False}

playback_history.del_item(video_id)
ui.refresh_container()
Expand Down Expand Up @@ -1708,7 +1708,7 @@ def _update(new_item):
context.localize('bookmarks.clear'),
localize('bookmarks.clear.check')
):
return False
return False, {provider.RESULT_FALLBACK: False}

context.get_bookmarks_list().clear()
ui.refresh_container()
Expand Down Expand Up @@ -1742,7 +1742,7 @@ def _update(new_item):
localize('content.remove'),
localize('content.remove.check') % bookmark_name,
):
return False
return False, {provider.RESULT_FALLBACK: False}

context.get_bookmarks_list().del_item(item_id)
context.get_ui().refresh_container()
Expand Down Expand Up @@ -1809,7 +1809,7 @@ def on_watch_later(provider, context, re_match):
localize('watch_later.clear'),
localize('watch_later.clear.check')
):
return False
return False, {provider.RESULT_FALLBACK: False}

context.get_watch_later_list().clear()
ui.refresh_container()
Expand Down Expand Up @@ -1838,7 +1838,7 @@ def on_watch_later(provider, context, re_match):
localize('content.remove'),
localize('content.remove.check') % video_name,
):
return False
return False, {provider.RESULT_FALLBACK: False}

context.get_watch_later_list().del_item(video_id)
ui.refresh_container()
Expand All @@ -1853,69 +1853,68 @@ def on_watch_later(provider, context, re_match):
return False

def handle_exception(self, context, exception_to_handle):
if isinstance(exception_to_handle, (InvalidGrant, LoginException)):
ok_dialog = False
message_timeout = 5000

message = exception_to_handle.get_message()
msg = exception_to_handle.get_message()
log_message = exception_to_handle.get_message()

error = ''
code = ''
if isinstance(msg, dict):
if 'error_description' in msg:
message = strip_html_from_text(msg['error_description'])
log_message = strip_html_from_text(msg['error_description'])
elif 'message' in msg:
message = strip_html_from_text(msg['message'])
log_message = strip_html_from_text(msg['message'])
else:
message = 'No error message'
log_message = 'No error message'

if 'error' in msg:
error = msg['error']

if 'code' in msg:
code = msg['code']
if not isinstance(exception_to_handle, (InvalidGrant, LoginException)):
return False

if error and code:
title = '%s: [%s] %s' % ('LoginException', code, error)
elif error:
title = '%s: %s' % ('LoginException', error)
ok_dialog = False
message_timeout = 5000

message = exception_to_handle.get_message()
msg = exception_to_handle.get_message()
log_message = exception_to_handle.get_message()

error = ''
code = ''
if isinstance(msg, dict):
if 'error_description' in msg:
message = strip_html_from_text(msg['error_description'])
log_message = strip_html_from_text(msg['error_description'])
elif 'message' in msg:
message = strip_html_from_text(msg['message'])
log_message = strip_html_from_text(msg['message'])
else:
title = 'LoginException'
message = 'No error message'
log_message = 'No error message'

context.log_error('%s: %s' % (title, log_message))
if 'error' in msg:
error = msg['error']

if error == 'deleted_client':
message = context.localize('key.requirement')
context.get_access_manager().update_access_token(
context.get_param('addon_id', None),
access_token='',
expiry=-1,
refresh_token='',
)
ok_dialog = True

if error == 'invalid_client':
if message == 'The OAuth client was not found.':
message = context.localize('client.id.incorrect')
message_timeout = 7000
elif message == 'Unauthorized':
message = context.localize('client.secret.incorrect')
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)
if 'code' in msg:
code = msg['code']

return False
if error and code:
title = '%s: [%s] %s' % ('LoginException', code, error)
elif error:
title = '%s: %s' % ('LoginException', error)
else:
title = 'LoginException'

context.log_error('%s: %s' % (title, log_message))

if error == 'deleted_client':
message = context.localize('key.requirement')
context.get_access_manager().update_access_token(
context.get_param('addon_id', None),
access_token='',
expiry=-1,
refresh_token='',
)
ok_dialog = True

if error == 'invalid_client':
if message == 'The OAuth client was not found.':
message = context.localize('client.id.incorrect')
message_timeout = 7000
elif message == 'Unauthorized':
message = context.localize('client.secret.incorrect')
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 True

def tear_down(self):
Expand Down

0 comments on commit 1f52678

Please sign in to comment.