From e88f0d26e88545843f894a690fc75366418db9c2 Mon Sep 17 00:00:00 2001 From: MoojMidge <56883549+MoojMidge@users.noreply.github.com> Date: Sun, 23 Jun 2024 19:43:40 +1000 Subject: [PATCH 1/7] Fix Python2 UnicodeDecodeError due to implicit decode attempt when trying to encode data #815 --- resources/lib/youtube_plugin/kodion/abstract_provider.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/lib/youtube_plugin/kodion/abstract_provider.py b/resources/lib/youtube_plugin/kodion/abstract_provider.py index 69633e30c..d3d60a31e 100644 --- a/resources/lib/youtube_plugin/kodion/abstract_provider.py +++ b/resources/lib/youtube_plugin/kodion/abstract_provider.py @@ -264,13 +264,13 @@ def _internal_search(self, context, re_match): return self.on_search(query, context, re_match) if command == 'remove': - query = params.get('q', '') + query = to_unicode(params.get('q', '')) search_history.remove(query) ui.refresh_container() return True if command == 'rename': - query = params.get('q', '') + query = to_unicode(params.get('q', '')) result, new_query = ui.on_keyboard_input( context.localize('search.rename'), query ) From 1f2979bef27e11e2ac6bc39cde464f40eee8e362 Mon Sep 17 00:00:00 2001 From: MoojMidge <56883549+MoojMidge@users.noreply.github.com> Date: Sun, 23 Jun 2024 19:46:41 +1000 Subject: [PATCH 2/7] Fix not catching socket.error in Python2 when force shutting down socket --- resources/lib/youtube_plugin/kodion/network/http_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/youtube_plugin/kodion/network/http_server.py b/resources/lib/youtube_plugin/kodion/network/http_server.py index ec3d94862..ecd21b61b 100644 --- a/resources/lib/youtube_plugin/kodion/network/http_server.py +++ b/resources/lib/youtube_plugin/kodion/network/http_server.py @@ -38,7 +38,7 @@ class HTTPServer(TCPServer): def server_close(self): try: self.socket.shutdown(socket.SHUT_RDWR) - except OSError: + except (OSError, socket.error): pass self.socket.close() From 205b1c5a119caf4d0cc43e0e246e0340b52fbae2 Mon Sep 17 00:00:00 2001 From: MoojMidge <56883549+MoojMidge@users.noreply.github.com> Date: Fri, 21 Jun 2024 21:41:18 +1000 Subject: [PATCH 3/7] Enable subtitles for alternative client 2 #806 --- resources/lib/youtube_plugin/youtube/client/request_client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lib/youtube_plugin/youtube/client/request_client.py b/resources/lib/youtube_plugin/youtube/client/request_client.py index 3b5b931e1..bb68cfe65 100644 --- a/resources/lib/youtube_plugin/youtube/client/request_client.py +++ b/resources/lib/youtube_plugin/youtube/client/request_client.py @@ -208,6 +208,7 @@ class YouTubeRequestClient(BaseRequestsClass): 'media_connect_frontend': { '_id': 95, '_access_token': KeyError, + '_query_subtitles': True, 'json': { 'context': { 'client': { From 7e2107e50db55e3bd27b567868f2a145ab27084f Mon Sep 17 00:00:00 2001 From: MoojMidge <56883549+MoojMidge@users.noreply.github.com> Date: Sun, 23 Jun 2024 20:43:11 +1000 Subject: [PATCH 4/7] Update 720p preset in Setup Wizard #807 --- .../kodion/settings/abstract_settings.py | 14 +++++++++++--- .../youtube_plugin/youtube/helper/video_info.py | 7 ++++--- .../youtube/helper/yt_setup_wizard.py | 10 +++++++--- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/resources/lib/youtube_plugin/kodion/settings/abstract_settings.py b/resources/lib/youtube_plugin/kodion/settings/abstract_settings.py index b4cce62ae..bc8eb936c 100644 --- a/resources/lib/youtube_plugin/kodion/settings/abstract_settings.py +++ b/resources/lib/youtube_plugin/kodion/settings/abstract_settings.py @@ -70,9 +70,17 @@ def items_per_page(self, value=None): 4: 1080, } - def get_video_quality(self): - value = self.get_int(settings.VIDEO_QUALITY, 3) - return self._VIDEO_QUALITY_MAP[value] + def fixed_video_quality(self, value=None): + default = 3 + if value is None: + _value = self.get_int(settings.VIDEO_QUALITY, default) + else: + _value = value + if _value not in self._VIDEO_QUALITY_MAP: + _value = default + if value is not None: + self.set_int(settings.VIDEO_QUALITY, _value) + return self._VIDEO_QUALITY_MAP[_value] def ask_for_video_quality(self): return (self.get_bool(settings.VIDEO_QUALITY_ASK, False) diff --git a/resources/lib/youtube_plugin/youtube/helper/video_info.py b/resources/lib/youtube_plugin/youtube/helper/video_info.py index 796835d94..f7f68a14f 100644 --- a/resources/lib/youtube_plugin/youtube/helper/video_info.py +++ b/resources/lib/youtube_plugin/youtube/helper/video_info.py @@ -490,9 +490,10 @@ class VideoInfo(YouTubeRequestClient): 'audio': {'bitrate': 384, 'codec': 'ac-3'}}, # === HLS '9994': {'container': 'hls', - 'title': 'HLS', + 'title': 'Adaptive HLS', 'hls/audio': True, 'hls/video': True, + 'adaptive': True, 'sort': 9994, 'audio': {'bitrate': 0, 'codec': 'aac'}, 'video': {'height': 0, 'codec': 'h.264'}}, @@ -960,7 +961,7 @@ def _load_hls_manifest(self, url, is_live=False, meta_info=None, qualities = settings.mpd_video_qualities() selected_height = qualities[0]['nom_height'] else: - selected_height = settings.get_video_quality() + selected_height = settings.fixed_video_quality() # The playlist might include a #EXT-X-MEDIA entry, but it's usually for # a small default stream with itag 133 (240p) and can be ignored. @@ -1025,7 +1026,7 @@ def _create_stream_list(self, qualities = settings.mpd_video_qualities() selected_height = qualities[0]['nom_height'] else: - selected_height = settings.get_video_quality() + selected_height = settings.fixed_video_quality() stream_list = [] for stream_map in streams: diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_setup_wizard.py b/resources/lib/youtube_plugin/youtube/helper/yt_setup_wizard.py index 951331dff..68d9cd8a8 100644 --- a/resources/lib/youtube_plugin/youtube/helper/yt_setup_wizard.py +++ b/resources/lib/youtube_plugin/youtube/helper/yt_setup_wizard.py @@ -369,6 +369,8 @@ def process_performance_settings(_provider, context, step, steps): 'stream_features': ('avc1', 'mp4a', 'filter'), 'num_items': 10, 'settings': ( + (settings.use_isa, (False,)), + (settings.client_selection, (2,)), (settings.use_mpd_videos, (False,)), (settings.set_subtitle_download, (True,)), ), @@ -425,12 +427,14 @@ def process_performance_settings(_provider, context, step, steps): return step device_type = device_types[device_type] - settings.mpd_video_qualities(device_type['max_resolution']) - settings.stream_features(device_type['stream_features']) - settings.items_per_page(device_type['num_items']) if 'settings' in device_type: for setting in device_type['settings']: setting[0](*setting[1]) + settings.mpd_video_qualities(device_type['max_resolution']) + if not settings.use_mpd_videos(): + settings.fixed_video_quality(device_type['max_resolution']) + settings.stream_features(device_type['stream_features']) + settings.items_per_page(device_type['num_items']) return step From 08eba1ef3defcb2c238faddebb244a397180f962 Mon Sep 17 00:00:00 2001 From: MoojMidge <56883549+MoojMidge@users.noreply.github.com> Date: Thu, 20 Jun 2024 21:49:35 +1000 Subject: [PATCH 5/7] Update itags found in HLS playlists to ignore them when user chooses quality #806 --- .../youtube/helper/video_info.py | 98 +++++++++++++++++-- 1 file changed, 88 insertions(+), 10 deletions(-) diff --git a/resources/lib/youtube_plugin/youtube/helper/video_info.py b/resources/lib/youtube_plugin/youtube/helper/video_info.py index f7f68a14f..a2810cf0f 100644 --- a/resources/lib/youtube_plugin/youtube/helper/video_info.py +++ b/resources/lib/youtube_plugin/youtube/helper/video_info.py @@ -489,14 +489,91 @@ class VideoInfo(YouTubeRequestClient): 'dash/audio': True, 'audio': {'bitrate': 384, 'codec': 'ac-3'}}, # === HLS + '229': {'container': 'hls', + 'title': '240p', + 'hls/video': True, + 'video': {'height': 240, 'codec': 'h.264'}}, + '230': {'container': 'hls', + 'title': '360p', + 'hls/video': True, + 'video': {'height': 360, 'codec': 'h.264'}}, + '231': {'container': 'hls', + 'title': '480p', + 'hls/video': True, + 'video': {'height': 480, 'codec': 'h.264'}}, + '232': {'container': 'hls', + 'title': '720p', + 'hls/video': True, + 'video': {'height': 720, 'codec': 'h.264'}}, + '269': {'container': 'hls', + 'title': '144p', + 'hls/video': True, + 'video': {'height': 144, 'codec': 'h.264'}}, + '270': {'container': 'hls', + 'title': 'Premium 1080p', + 'hls/video': True, + 'video': {'height': 1080, 'codec': 'h.264'}}, + '311': {'container': 'hls', + 'title': '720p60', + 'hls/video': True, + 'fps': 60, + 'video': {'height': 720, 'codec': 'h.264'}}, + '312': {'container': 'hls', + 'title': 'Premium 1080p60', + 'hls/video': True, + 'fps': 60, + 'video': {'height': 1080, 'codec': 'h.264'}}, + '602': {'container': 'hls', + 'title': '144p15', + 'hls/video': True, + 'fps': 15, + 'video': {'height': 144, 'codec': 'vp9'}}, + '603': {'container': 'hls', + 'title': '144p', + 'hls/video': True, + 'video': {'height': 144, 'codec': 'vp9'}}, + '604': {'container': 'hls', + 'title': '240p', + 'hls/video': True, + 'video': {'height': 240, 'codec': 'vp9'}}, + '605': {'container': 'hls', + 'title': '360p', + 'hls/video': True, + 'video': {'height': 360, 'codec': 'vp9'}}, + '606': {'container': 'hls', + 'title': '480p', + 'hls/video': True, + 'video': {'height': 480, 'codec': 'vp9'}}, + '609': {'container': 'hls', + 'title': '720p', + 'hls/video': True, + 'video': {'height': 720, 'codec': 'vp9'}}, + '612': {'container': 'hls', + 'title': '720p60', + 'hls/video': True, + 'fps': 60, + 'video': {'height': 720, 'codec': 'vp9'}}, + '614': {'container': 'hls', + 'title': '1080p', + 'hls/video': True, + 'video': {'height': 1080, 'codec': 'vp9'}}, + '616': {'container': 'hls', + 'title': 'Premium 1080p', + 'hls/video': True, + 'video': {'height': 1080, 'codec': 'vp9'}}, + '617': {'container': 'hls', + 'title': 'Premium 1080p60', + 'hls/video': True, + 'fps': 60, + 'video': {'height': 1080, 'codec': 'vp9'}}, '9994': {'container': 'hls', 'title': 'Adaptive HLS', 'hls/audio': True, 'hls/video': True, 'adaptive': True, 'sort': 9994, - 'audio': {'bitrate': 0, 'codec': 'aac'}, - 'video': {'height': 0, 'codec': 'h.264'}}, + 'audio': {'bitrate': 0, 'codec': ''}, + 'video': {'height': 0, 'codec': ''}}, # === Live HLS '9995': {'container': 'hls', 'live': True, @@ -504,8 +581,8 @@ class VideoInfo(YouTubeRequestClient): 'hls/audio': True, 'hls/video': True, 'sort': 9995, - 'audio': {'bitrate': 0, 'codec': 'aac'}, - 'video': {'height': 0, 'codec': 'h.264'}}, + 'audio': {'bitrate': 0, 'codec': ''}, + 'video': {'height': 0, 'codec': ''}}, # === Live HLS adaptive '9996': {'container': 'hls', 'live': True, @@ -514,8 +591,8 @@ class VideoInfo(YouTubeRequestClient): 'hls/video': True, 'adaptive': True, 'sort': 9996, - 'audio': {'bitrate': 0, 'codec': 'aac'}, - 'video': {'height': 0, 'codec': 'h.264'}}, + 'audio': {'bitrate': 0, 'codec': ''}, + 'video': {'height': 0, 'codec': ''}}, # === DASH adaptive audio only '9997': {'container': 'mpd', 'title': 'DASH Audio', @@ -574,6 +651,7 @@ class VideoInfo(YouTubeRequestClient): # audio - order based on preference 'mp3': 0.5, 'vorbis': 0.75, + 'aac': 0.9, 'mp4a': 0.9, 'opus': 1, 'ac-3': 1.1, @@ -707,6 +785,8 @@ def _get_stream_format(self, itag, info=None, max_height=None, **kwargs): yt_format = self.FORMAT.get(itag) if not yt_format: return None + if yt_format.get('discontinued') or yt_format.get('unsupported'): + return False yt_format = yt_format.copy() manual_sort = yt_format.get('sort', 0) @@ -986,8 +1066,8 @@ def _load_hls_manifest(self, url, is_live=False, meta_info=None, itag=itag, stream=redact_ip_from_url(match[0]), )) if (not yt_format - or yt_format.get('discontinued') - or yt_format.get('unsupported')): + or (yt_format.get('hls/video') + and not yt_format.get('hls/audio'))): continue if is_live: @@ -1067,8 +1147,6 @@ def _create_stream_list(self, itag=itag, stream=stream_map, )) if (not yt_format - or yt_format.get('discontinued') - or yt_format.get('unsupported') or (yt_format.get('dash/video') and not yt_format.get('dash/audio'))): continue From 25d529fc5501434993f4569bc4d7882aab5f484e Mon Sep 17 00:00:00 2001 From: MoojMidge <56883549+MoojMidge@users.noreply.github.com> Date: Sun, 23 Jun 2024 21:55:01 +1000 Subject: [PATCH 6/7] Fix deleting window property with multiple threads causing Kodi to hang on exit #813 --- .../kodion/context/xbmc/xbmc_context.py | 28 ++++++++++++++----- .../kodion/monitors/service_monitor.py | 11 +++++--- .../youtube_plugin/youtube/helper/yt_play.py | 2 +- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/resources/lib/youtube_plugin/kodion/context/xbmc/xbmc_context.py b/resources/lib/youtube_plugin/kodion/context/xbmc/xbmc_context.py index b6ce38c7f..e2652b4bc 100644 --- a/resources/lib/youtube_plugin/kodion/context/xbmc/xbmc_context.py +++ b/resources/lib/youtube_plugin/kodion/context/xbmc/xbmc_context.py @@ -775,15 +775,29 @@ def tear_down(self): except AttributeError: pass - def wakeup(self, target): - self.send_notification(WAKEUP, target) - if not target: + def wakeup(self, target, timeout=None): + data = {'target': target, 'response_required': bool(timeout)} + self.send_notification(WAKEUP, data) + if not timeout: return + pop_property = self.get_ui().pop_property - while 1: + no_timeout = timeout < 0 + remaining = timeout + wait_period = 0.1 + + while no_timeout or remaining > 0: awake = pop_property(WAKEUP) if awake: - if awake != target: - self.log_error('Incorrect wakeup target') + if awake == target: + self.log_debug('Wakeup |{0}| in {1}s' + .format(awake, timeout - remaining)) + else: + self.log_error('Wakeup |{0}| in {1}s - expected |{2}|' + .format(awake, timeout - remaining, target)) break - wait(0.5) + wait(wait_period) + remaining -= wait_period + else: + self.log_error('Wakeup |{0}| timed out in {1}s' + .format(target, timeout)) diff --git a/resources/lib/youtube_plugin/kodion/monitors/service_monitor.py b/resources/lib/youtube_plugin/kodion/monitors/service_monitor.py index cf4a377a5..ec86358ca 100644 --- a/resources/lib/youtube_plugin/kodion/monitors/service_monitor.py +++ b/resources/lib/youtube_plugin/kodion/monitors/service_monitor.py @@ -96,13 +96,16 @@ def onNotification(self, sender, method, data): elif event == WAKEUP: if not isinstance(data, dict): data = json.loads(data) - if data: - self.set_property(WAKEUP, data) - if data == 'plugin': + if not data: + return + target = data.get('target') + if target == 'plugin': self.interrupt = True - elif data == 'server': + elif target == 'server': if not self.httpd and self.httpd_required(): self.start_httpd() + if data.get('response_required'): + self.set_property(WAKEUP, target) elif event == REFRESH_CONTAINER: self.refresh_container() elif event == RELOAD_ACCESS_MANAGER: diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_play.py b/resources/lib/youtube_plugin/youtube/helper/yt_play.py index ddd1a2f2e..6669c7c16 100644 --- a/resources/lib/youtube_plugin/youtube/helper/yt_play.py +++ b/resources/lib/youtube_plugin/youtube/helper/yt_play.py @@ -154,7 +154,7 @@ def play_video(provider, context): 'refresh_only': screensaver } - context.wakeup('server') + context.wakeup('server', timeout=30) ui.set_property(PLAYER_DATA, json.dumps(playback_data, ensure_ascii=False)) context.send_notification(PLAYBACK_INIT, playback_data) return video_item From b72306ae7f537d196f874cad262e51dd8412264c Mon Sep 17 00:00:00 2001 From: MoojMidge <56883549+MoojMidge@users.noreply.github.com> Date: Sun, 23 Jun 2024 22:08:59 +1000 Subject: [PATCH 7/7] Version bump v7.0.8+beta.5 --- addon.xml | 2 +- changelog.txt | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/addon.xml b/addon.xml index 7aafa5f66..2c1176c9b 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/changelog.txt b/changelog.txt index c27c7e293..75d17ef1e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,16 @@ +## v7.0.8+beta.5 +### Fixed +- Fix Python2 UnicodeDecodeError when removing/renaming searches #815 +- Fix not catching socket.error in Python2 when force shutting down socket +- Fix deleting window property with multiple threads causing hang on exit #813 + +### Changed +- Update 720p preset in Setup Wizard #807 +- Update itags found in HLS playlists and exclude them in quality selection #806 + +### New +- Enable subtitles for alternative client 2 #806 + ## v7.0.8+beta.4 ### Fixed - Poll for http server restart when required for playback #746 #808