From 05b7954aa86967735d79067ad905d1da65c1be8e Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Fri, 28 Jun 2024 21:05:43 +1000
Subject: [PATCH 01/15] Fix ask for video quality setting being inconsistently
applied
---
.../lib/youtube_plugin/kodion/settings/abstract_settings.py | 5 +++--
resources/lib/youtube_plugin/kodion/utils/methods.py | 4 ++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/resources/lib/youtube_plugin/kodion/settings/abstract_settings.py b/resources/lib/youtube_plugin/kodion/settings/abstract_settings.py
index da02fd67b..360b2989b 100644
--- a/resources/lib/youtube_plugin/kodion/settings/abstract_settings.py
+++ b/resources/lib/youtube_plugin/kodion/settings/abstract_settings.py
@@ -83,8 +83,9 @@ def fixed_video_quality(self, value=None):
return self._VIDEO_QUALITY_MAP[_value]
def ask_for_video_quality(self):
- return (self.get_bool(SETTINGS.VIDEO_QUALITY_ASK, False)
- or self.get_int(SETTINGS.MPD_STREAM_SELECT) == 4)
+ if self.use_mpd_videos():
+ return self.get_int(SETTINGS.MPD_STREAM_SELECT) == 4
+ return self.get_bool(SETTINGS.VIDEO_QUALITY_ASK, False)
def fanart_selection(self):
return self.get_int(SETTINGS.FANART_SELECTION, 2)
diff --git a/resources/lib/youtube_plugin/kodion/utils/methods.py b/resources/lib/youtube_plugin/kodion/utils/methods.py
index 5c9ff8494..2997a7b03 100644
--- a/resources/lib/youtube_plugin/kodion/utils/methods.py
+++ b/resources/lib/youtube_plugin/kodion/utils/methods.py
@@ -63,7 +63,7 @@ def select_stream(context,
use_adaptive_formats=True):
settings = context.get_settings()
if ask_for_quality is None:
- ask_for_quality = context.get_settings().ask_for_video_quality()
+ ask_for_quality = settings.ask_for_video_quality()
if audio_only is None:
audio_only = settings.audio_only()
@@ -98,7 +98,7 @@ def _stream_sort(_stream):
stream_list.sort(key=_stream_sort, reverse=True)
num_streams = len(stream_list)
- ask_for_quality = ask_for_quality and num_streams > 1
+ ask_for_quality = ask_for_quality and num_streams >= 1
context.log_debug('Available streams: {0}'.format(num_streams))
for idx, stream in enumerate(stream_list):
From e351abd9011b26a9aa9ed9f20606c575b739efff Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Sat, 29 Jun 2024 10:56:52 +1000
Subject: [PATCH 02/15] Make My Subscriptions filter list setting a child of
the My Subscriptions (Filtered) setting
---
resources/settings.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/settings.xml b/resources/settings.xml
index 8863e2215..d62d4cf09 100644
--- a/resources/settings.xml
+++ b/resources/settings.xml
@@ -353,7 +353,7 @@
-
+
0
From 7d08c0bc0c1902fcbf9f07a04b6babcbcb1e4a28 Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Sat, 29 Jun 2024 11:00:26 +1000
Subject: [PATCH 03/15] Rename My Subscriptions plugin url
- From:
plugin://plugin.video.youtube/special/new_uploaded_videos_tv
plugin://plugin.video.youtube/special/new_uploaded_videos_tv_filtered
- To:
plugin://plugin.video.youtube/special/my_subscriptions
plugin://plugin.video.youtube/special/my_subscriptions_filtered
- Old url retained for backwards compatibility, to be removed with Kodi v22 release
---
.../lib/youtube_plugin/kodion/constants/const_paths.py | 2 +-
.../lib/youtube_plugin/youtube/helper/yt_specials.py | 10 ++++------
resources/lib/youtube_plugin/youtube/provider.py | 4 ++--
3 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/resources/lib/youtube_plugin/kodion/constants/const_paths.py b/resources/lib/youtube_plugin/kodion/constants/const_paths.py
index 962cee461..3d1f3831a 100644
--- a/resources/lib/youtube_plugin/kodion/constants/const_paths.py
+++ b/resources/lib/youtube_plugin/kodion/constants/const_paths.py
@@ -24,7 +24,7 @@
HOME = '/home'
LIKED_VIDEOS = '/channel/mine/playlist/LL'
MY_PLAYLISTS = '/channel/mine/playlists'
-MY_SUBSCRIPTIONS = '/special/new_uploaded_videos'
+MY_SUBSCRIPTIONS = '/special/my_subscriptions'
SUBSCRIPTIONS = '/subscriptions/list'
API = '/youtube/api'
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_specials.py b/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
index 8c8006d65..a296f06a1 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
@@ -294,7 +294,7 @@ def _process_saved_playlists_tv(provider, context, client):
return tv.saved_playlists_to_items(provider, context, json_data)
-def _process_new_uploaded_videos_tv(provider, context, client, filtered=False):
+def _process_my_subscriptions(provider, context, client, filtered=False):
context.set_content(CONTENT.VIDEO_CONTENT)
function_cache = context.get_function_cache()
@@ -326,11 +326,9 @@ def process(category, provider, context):
return _process_recommendations(provider, context, client)
if category == 'browse_channels':
return _process_browse_channels(provider, context, client)
- if category == 'new_uploaded_videos_tv':
- return _process_new_uploaded_videos_tv(provider, context, client)
- if category == 'new_uploaded_videos_tv_filtered':
- return _process_new_uploaded_videos_tv(
- provider, context, client, filtered=True
+ if category.startswith(('my_subscriptions', 'new_uploaded_videos_tv')):
+ return _process_my_subscriptions(
+ provider, context, client, filtered=category.endswith('_filtered'),
)
if category == 'disliked_videos':
if provider.is_logged_in():
diff --git a/resources/lib/youtube_plugin/youtube/provider.py b/resources/lib/youtube_plugin/youtube/provider.py
index 78c3195a7..f172e81b5 100644
--- a/resources/lib/youtube_plugin/youtube/provider.py
+++ b/resources/lib/youtube_plugin/youtube/provider.py
@@ -1135,7 +1135,7 @@ def on_root(self, context, re_match):
item_label = localize('my_subscriptions')
my_subscriptions_item = DirectoryItem(
ui.bold(item_label),
- create_uri(('special', 'new_uploaded_videos_tv')),
+ create_uri(('special', 'my_subscriptions')),
image='{media}/new_uploads.png',
category_label=item_label,
)
@@ -1145,7 +1145,7 @@ def on_root(self, context, re_match):
# my subscriptions filtered
my_subscriptions_filtered_item = DirectoryItem(
localize('my_subscriptions.filtered'),
- create_uri(('special', 'new_uploaded_videos_tv_filtered')),
+ create_uri(('special', 'my_subscriptions_filtered')),
image='{media}/new_uploads.png',
)
result.append(my_subscriptions_filtered_item)
From 6f44e88c50edee88f16666ad4bb77e53a1d0b7a0 Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Sat, 29 Jun 2024 23:58:51 +1000
Subject: [PATCH 04/15] Add notifications for creating/removing/clearing
bookmarks #720
---
.../resource.language.en_gb/strings.po | 2 +-
.../kodion/context/xbmc/xbmc_context.py | 9 +++---
.../youtube_plugin/kodion/items/menu_items.py | 12 ++++----
.../youtube_plugin/kodion/script_actions.py | 2 +-
.../youtube_plugin/youtube/helper/utils.py | 12 ++++----
.../lib/youtube_plugin/youtube/provider.py | 29 ++++++++++++++++---
6 files changed, 44 insertions(+), 22 deletions(-)
diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po
index 2f78f4113..f3ed9d9b0 100644
--- a/resources/language/resource.language.en_gb/strings.po
+++ b/resources/language/resource.language.en_gb/strings.po
@@ -970,7 +970,7 @@ msgid "Switch to '%s' now?"
msgstr ""
msgctxt "#30666"
-msgid "Removed '%s'"
+msgid "%s removed"
msgstr ""
msgctxt "#30667"
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 80783a453..40c353f46 100644
--- a/resources/lib/youtube_plugin/kodion/context/xbmc/xbmc_context.py
+++ b/resources/lib/youtube_plugin/kodion/context/xbmc/xbmc_context.py
@@ -59,12 +59,13 @@ class XbmcContext(AbstractContext):
'archive': 30105,
'are_you_sure': 30703,
'auto_remove_watch_later': 30515,
+ 'bookmark': 30101,
+ 'bookmark.channel': 30803,
+ 'bookmark.created': 21362,
+ 'bookmark.remove': 20404,
'bookmarks': 30100,
- 'bookmarks.add': 30101,
- 'bookmarks.add.channel': 30803,
'bookmarks.clear': 30801,
'bookmarks.clear.confirm': 30802,
- 'bookmarks.remove': 20404,
'browse_channels': 30512,
'cancel': 30615,
'channels': 30500,
@@ -212,7 +213,7 @@ class XbmcContext(AbstractContext):
'sign.twice.text': 30547,
'sign.twice.title': 30546,
'stats.commentCount': 30732,
- # 'stats.favoriteCount': 30100,
+ # 'stats.favoriteCount': 1036,
'stats.likeCount': 30733,
'stats.viewCount': 30767,
'stream.alternate': 30747,
diff --git a/resources/lib/youtube_plugin/kodion/items/menu_items.py b/resources/lib/youtube_plugin/kodion/items/menu_items.py
index a7a1d2735..d442615fb 100644
--- a/resources/lib/youtube_plugin/kodion/items/menu_items.py
+++ b/resources/lib/youtube_plugin/kodion/items/menu_items.py
@@ -465,9 +465,9 @@ def history_reset_resume(context, video_id):
)
-def bookmarks_add(context, item):
+def bookmark_add(context, item):
return (
- context.localize('bookmarks.add'),
+ context.localize('bookmark'),
'RunPlugin({0})'.format(context.create_uri(
(PATHS.BOOKMARKS, 'add',),
{
@@ -478,9 +478,9 @@ def bookmarks_add(context, item):
)
-def bookmarks_add_channel(context, channel_id, channel_name=''):
+def bookmark_add_channel(context, channel_id, channel_name=''):
return (
- (context.localize('bookmarks.add.channel') % (
+ (context.localize('bookmark.channel') % (
context.get_ui().bold(channel_name) if channel_name else
context.localize(19029)
)),
@@ -494,9 +494,9 @@ def bookmarks_add_channel(context, channel_id, channel_name=''):
)
-def bookmarks_remove(context, item_id):
+def bookmark_remove(context, item_id):
return (
- context.localize('bookmarks.remove'),
+ context.localize('bookmark.remove'),
'RunPlugin({0})'.format(context.create_uri(
(PATHS.BOOKMARKS, 'remove',),
{
diff --git a/resources/lib/youtube_plugin/kodion/script_actions.py b/resources/lib/youtube_plugin/kodion/script_actions.py
index 27a0dd66a..f3234bd50 100644
--- a/resources/lib/youtube_plugin/kodion/script_actions.py
+++ b/resources/lib/youtube_plugin/kodion/script_actions.py
@@ -280,7 +280,7 @@ def switch_to_user(user):
username = access_manager.get_username(user)
if ui.on_remove_content(username):
access_manager.remove_user(user)
- ui.show_notification(localize('removed') % username,
+ ui.show_notification(localize('removed') % '"%s"' % username,
localize('remove'))
if user == 0:
access_manager.add_user(username=localize('user.default'),
diff --git a/resources/lib/youtube_plugin/youtube/helper/utils.py b/resources/lib/youtube_plugin/youtube/helper/utils.py
index 8ca667cf0..84a96fd8f 100644
--- a/resources/lib/youtube_plugin/youtube/helper/utils.py
+++ b/resources/lib/youtube_plugin/youtube/helper/utils.py
@@ -221,7 +221,7 @@ def update_channel_infos(provider, context, channel_id_dict,
if not in_bookmarks_list:
context_menu.append(
- menu_items.bookmarks_add_channel(
+ menu_items.bookmark_add_channel(
context, channel_id
)
)
@@ -289,7 +289,7 @@ def update_playlist_infos(provider, context, playlist_id_dict,
menu_items.play_all_from_playlist(
context, playlist_id
),
- menu_items.bookmarks_add(
+ menu_items.bookmark_add(
context, playlist_item
) if not in_bookmarks_list and channel_id != 'mine' else None,
]
@@ -333,7 +333,7 @@ def update_playlist_infos(provider, context, playlist_id_dict,
if not in_bookmarks_list and channel_id != 'mine':
context_menu.append(
# bookmark channel of the playlist
- menu_items.bookmarks_add_channel(
+ menu_items.bookmark_add_channel(
context, channel_id, channel_name
)
)
@@ -697,7 +697,7 @@ def update_video_infos(provider, context, video_id_dict,
if not in_bookmarks_list:
context_menu.append(
- menu_items.bookmarks_add(
+ menu_items.bookmark_add(
context, video_item
)
)
@@ -744,11 +744,11 @@ def update_video_infos(provider, context, video_id_dict,
if not in_bookmarks_list:
context_menu.append(
# remove bookmarked channel of the video
- menu_items.bookmarks_remove(
+ menu_items.bookmark_remove(
context, item_id=channel_id
) if in_my_subscriptions_list else
# bookmark channel of the video
- menu_items.bookmarks_add_channel(
+ menu_items.bookmark_add_channel(
context, channel_id, channel_name
)
)
diff --git a/resources/lib/youtube_plugin/youtube/provider.py b/resources/lib/youtube_plugin/youtube/provider.py
index f172e81b5..65f255a09 100644
--- a/resources/lib/youtube_plugin/youtube/provider.py
+++ b/resources/lib/youtube_plugin/youtube/provider.py
@@ -1451,7 +1451,7 @@ def on_bookmarks(self, context, re_match):
if not isinstance(item, BaseItem):
continue
context_menu = [
- menu_items.bookmarks_remove(
+ menu_items.bookmark_remove(
context, item_id
),
menu_items.bookmarks_clear(
@@ -1464,12 +1464,21 @@ def on_bookmarks(self, context, re_match):
return bookmarks
- if command == 'clear' and context.get_ui().on_yes_no_input(
+ ui = context.get_ui()
+ localize = context.localize
+
+ if command == 'clear' and ui.on_yes_no_input(
context.get_name(),
- context.localize('bookmarks.clear.confirm')
+ localize('bookmarks.clear.confirm')
):
context.get_bookmarks_list().clear()
- context.get_ui().refresh_container()
+ ui.refresh_container()
+
+ ui.show_notification(
+ localize('succeeded'),
+ time_ms=2500,
+ audible=False
+ )
return True
item_id = params.get('item_id')
@@ -1479,11 +1488,23 @@ def on_bookmarks(self, context, re_match):
if command == 'add':
item = params.get('item')
context.get_bookmarks_list().add(item_id, item)
+
+ ui.show_notification(
+ localize('bookmark.created'),
+ time_ms=2500,
+ audible=False
+ )
return True
if command == 'remove':
context.get_bookmarks_list().remove(item_id)
context.get_ui().refresh_container()
+
+ ui.show_notification(
+ localize('removed') % localize('bookmark'),
+ time_ms=2500,
+ audible=False
+ )
return True
return False
From b49bcddd3cefe221e191ce3bccaa547af6cd72ed Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Sun, 30 Jun 2024 20:23:25 +1000
Subject: [PATCH 05/15] Misc tidy up
---
.../kodion/abstract_provider.py | 2 +-
.../kodion/context/abstract_context.py | 2 +-
.../helper/signature/json_script_engine.py | 2 +-
.../lib/youtube_plugin/youtube/helper/v3.py | 2 +-
.../youtube/helper/yt_specials.py | 2 +-
.../youtube/helper/yt_subscriptions.py | 2 +-
.../youtube_plugin/youtube/helper/yt_video.py | 2 +-
.../lib/youtube_plugin/youtube/provider.py | 61 ++++++++++---------
8 files changed, 38 insertions(+), 37 deletions(-)
diff --git a/resources/lib/youtube_plugin/kodion/abstract_provider.py b/resources/lib/youtube_plugin/kodion/abstract_provider.py
index 613f9514e..64ece6560 100644
--- a/resources/lib/youtube_plugin/kodion/abstract_provider.py
+++ b/resources/lib/youtube_plugin/kodion/abstract_provider.py
@@ -162,7 +162,7 @@ def navigate(self, context):
return result, options
- raise KodionException("Mapping for path '%s' not found" % path)
+ raise KodionException('Mapping for path "%s" not found' % path)
# noinspection PyUnusedLocal
@staticmethod
diff --git a/resources/lib/youtube_plugin/kodion/context/abstract_context.py b/resources/lib/youtube_plugin/kodion/context/abstract_context.py
index 3fc802192..323bbc39d 100644
--- a/resources/lib/youtube_plugin/kodion/context/abstract_context.py
+++ b/resources/lib/youtube_plugin/kodion/context/abstract_context.py
@@ -72,9 +72,9 @@ class AbstractContext(object):
'refresh',
}
_FLOAT_PARAMS = {
+ 'end',
'seek',
'start',
- 'end'
}
_LIST_PARAMS = {
'channel_ids',
diff --git a/resources/lib/youtube_plugin/youtube/helper/signature/json_script_engine.py b/resources/lib/youtube_plugin/youtube/helper/signature/json_script_engine.py
index 90fb3a9d2..975d20e5d 100644
--- a/resources/lib/youtube_plugin/youtube/helper/signature/json_script_engine.py
+++ b/resources/lib/youtube_plugin/youtube/helper/signature/json_script_engine.py
@@ -35,7 +35,7 @@ def execute(self, signature):
if method:
_signature = method(*params)
else:
- raise Exception("Unknown method '%s'" % func)
+ raise Exception('Unknown method: %s' % func)
return _signature
diff --git a/resources/lib/youtube_plugin/youtube/helper/v3.py b/resources/lib/youtube_plugin/youtube/helper/v3.py
index 0336fbcae..c90eaea23 100644
--- a/resources/lib/youtube_plugin/youtube/helper/v3.py
+++ b/resources/lib/youtube_plugin/youtube/helper/v3.py
@@ -406,7 +406,7 @@ def response_to_items(provider,
provider, context, json_data, item_filter
)
else:
- raise KodionException("Unknown kind '%s'" % kind)
+ raise KodionException('Unknown kind: %s' % kind)
if item_filter:
result = filter_videos(result, **item_filter)
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_specials.py b/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
index a296f06a1..c2305fd2e 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
@@ -354,4 +354,4 @@ def process(category, provider, context):
return _process_child_comments(provider, context, client)
if category == 'saved_playlists':
return _process_saved_playlists_tv(provider, context, client)
- raise KodionException("YouTube special category '%s' not found" % category)
+ raise KodionException('YouTube special category "%s" not found' % category)
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py b/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py
index c4ceed0f9..aad82587a 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py
@@ -92,4 +92,4 @@ def process(method, provider, context):
return _process_add(provider, context, client)
if method == 'remove':
return _process_remove(provider, context, client)
- raise KodionException("Unknown subscriptions method '%s'" % method)
+ raise KodionException('Unknown subscriptions method: %s' % method)
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_video.py b/resources/lib/youtube_plugin/youtube/helper/yt_video.py
index 8560463a1..1d4beec00 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_video.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_video.py
@@ -120,4 +120,4 @@ def process(method, provider, context, re_match):
return _process_rate_video(provider, context, re_match)
if method == 'more':
return _process_more_for_video(context)
- raise KodionException("Unknown method '%s'" % method)
+ raise KodionException('Unknown method: %s' % method)
diff --git a/resources/lib/youtube_plugin/youtube/provider.py b/resources/lib/youtube_plugin/youtube/provider.py
index 65f255a09..1b90fcd8d 100644
--- a/resources/lib/youtube_plugin/youtube/provider.py
+++ b/resources/lib/youtube_plugin/youtube/provider.py
@@ -1108,7 +1108,8 @@ def on_root(self, context, re_match):
create_uri = context.create_uri
localize = context.localize
settings = context.get_settings()
- ui = context.get_ui()
+ settings_bool = settings.get_bool
+ bold = context.get_ui().bold
_ = self.get_client(context) # required for self.is_logged_in()
logged_in = self.is_logged_in()
@@ -1119,10 +1120,10 @@ def on_root(self, context, re_match):
result = []
# sign in
- if not logged_in and settings.get_bool('youtube.folder.sign.in.show', True):
+ if not logged_in and settings_bool('youtube.folder.sign.in.show', True):
item_label = localize('sign.in')
sign_in_item = DirectoryItem(
- ui.bold(item_label),
+ bold(item_label),
create_uri(('sign', 'in')),
image='{media}/sign_in.png',
action=True,
@@ -1130,18 +1131,18 @@ def on_root(self, context, re_match):
)
result.append(sign_in_item)
- if settings.get_bool('youtube.folder.my_subscriptions.show', True):
+ if settings_bool('youtube.folder.my_subscriptions.show', True):
# my subscription
item_label = localize('my_subscriptions')
my_subscriptions_item = DirectoryItem(
- ui.bold(item_label),
+ bold(item_label),
create_uri(('special', 'my_subscriptions')),
image='{media}/new_uploads.png',
category_label=item_label,
)
result.append(my_subscriptions_item)
- if settings.get_bool('youtube.folder.my_subscriptions_filtered.show', True):
+ if settings_bool('youtube.folder.my_subscriptions_filtered.show'):
# my subscriptions filtered
my_subscriptions_filtered_item = DirectoryItem(
localize('my_subscriptions.filtered'),
@@ -1156,7 +1157,7 @@ def on_root(self, context, re_match):
local_history = settings.use_local_history()
# Home / Recommendations
- if logged_in and settings.get_bool('youtube.folder.recommendations.show', True):
+ if logged_in and settings_bool('youtube.folder.recommendations.show', True):
recommendations_item = DirectoryItem(
localize('recommendations'),
create_uri(('special', 'recommendations')),
@@ -1165,7 +1166,7 @@ def on_root(self, context, re_match):
result.append(recommendations_item)
# Related
- if settings.get_bool('youtube.folder.related.show', True):
+ if settings_bool('youtube.folder.related.show', True):
if history_id or local_history:
related_item = DirectoryItem(
localize('related_videos'),
@@ -1175,7 +1176,7 @@ def on_root(self, context, re_match):
result.append(related_item)
# Trending
- if settings.get_bool('youtube.folder.popular_right_now.show', True):
+ if settings_bool('youtube.folder.popular_right_now.show', True):
trending_item = DirectoryItem(
localize('trending'),
create_uri(('special', 'popular_right_now')),
@@ -1184,13 +1185,13 @@ def on_root(self, context, re_match):
result.append(trending_item)
# search
- if settings.get_bool('youtube.folder.search.show', True):
+ if settings_bool('youtube.folder.search.show', True):
search_item = SearchItem(
context,
)
result.append(search_item)
- if settings.get_bool('youtube.folder.quick_search.show', True):
+ if settings_bool('youtube.folder.quick_search.show'):
quick_search_item = NewSearchItem(
context,
name=localize('search.quick'),
@@ -1198,7 +1199,7 @@ def on_root(self, context, re_match):
)
result.append(quick_search_item)
- if settings.get_bool('youtube.folder.quick_search_incognito.show', True):
+ if settings_bool('youtube.folder.quick_search_incognito.show'):
quick_search_incognito_item = NewSearchItem(
context,
name=localize('search.quick.incognito'),
@@ -1208,7 +1209,7 @@ def on_root(self, context, re_match):
result.append(quick_search_incognito_item)
# my location
- if settings.get_bool('youtube.folder.my_location.show', True) and settings.get_location():
+ if settings_bool('youtube.folder.my_location.show', True) and settings.get_location():
my_location_item = DirectoryItem(
localize('my_location'),
create_uri(('location', 'mine')),
@@ -1217,7 +1218,7 @@ def on_root(self, context, re_match):
result.append(my_location_item)
# my channel
- if logged_in and settings.get_bool('youtube.folder.my_channel.show', True):
+ if logged_in and settings_bool('youtube.folder.my_channel.show', True):
my_channel_item = DirectoryItem(
localize('my_channel'),
create_uri(('channel', 'mine')),
@@ -1226,7 +1227,7 @@ def on_root(self, context, re_match):
result.append(my_channel_item)
# watch later
- if settings.get_bool('youtube.folder.watch_later.show', True):
+ if settings_bool('youtube.folder.watch_later.show', True):
if watch_later_id:
watch_later_item = DirectoryItem(
localize('watch_later'),
@@ -1249,7 +1250,7 @@ def on_root(self, context, re_match):
result.append(watch_history_item)
# liked videos
- if logged_in and settings.get_bool('youtube.folder.liked_videos.show', True):
+ if logged_in and settings_bool('youtube.folder.liked_videos.show', True):
resource_manager = self.get_resource_manager(context)
playlists = resource_manager.get_related_playlists(channel_id='mine')
if playlists and 'likes' in playlists:
@@ -1267,7 +1268,7 @@ def on_root(self, context, re_match):
result.append(liked_videos_item)
# disliked videos
- if logged_in and settings.get_bool('youtube.folder.disliked_videos.show', True):
+ if logged_in and settings_bool('youtube.folder.disliked_videos.show', True):
disliked_videos_item = DirectoryItem(
localize('video.disliked'),
create_uri(('special', 'disliked_videos')),
@@ -1276,7 +1277,7 @@ def on_root(self, context, re_match):
result.append(disliked_videos_item)
# history
- if settings.get_bool('youtube.folder.history.show', False):
+ if settings_bool('youtube.folder.history.show', False):
if history_id:
watch_history_item = DirectoryItem(
localize('history'),
@@ -1299,7 +1300,7 @@ def on_root(self, context, re_match):
result.append(watch_history_item)
# (my) playlists
- if logged_in and settings.get_bool('youtube.folder.playlists.show', True):
+ if logged_in and settings_bool('youtube.folder.playlists.show', True):
playlists_item = DirectoryItem(
localize('playlists'),
create_uri(('channel', 'mine', 'playlists')),
@@ -1309,7 +1310,7 @@ def on_root(self, context, re_match):
# saved playlists
# TODO: re-enable once functionality is restored
- # if logged_in and settings.get_bool('youtube.folder.saved.playlists.show', True):
+ # if logged_in and settings_bool('youtube.folder.saved.playlists.show', True):
# playlists_item = DirectoryItem(
# localize('saved.playlists'),
# create_uri(('special', 'saved_playlists')),
@@ -1318,7 +1319,7 @@ def on_root(self, context, re_match):
# result.append(playlists_item)
# subscriptions
- if logged_in and settings.get_bool('youtube.folder.subscriptions.show', True):
+ if logged_in and settings_bool('youtube.folder.subscriptions.show', True):
subscriptions_item = DirectoryItem(
localize('subscriptions'),
create_uri(('subscriptions', 'list')),
@@ -1327,7 +1328,7 @@ def on_root(self, context, re_match):
result.append(subscriptions_item)
# bookmarks
- if settings.get_bool('youtube.folder.bookmarks.show', True):
+ if settings_bool('youtube.folder.bookmarks.show', True):
bookmarks_item = DirectoryItem(
localize('bookmarks'),
create_uri((PATHS.BOOKMARKS, 'list')),
@@ -1336,7 +1337,7 @@ def on_root(self, context, re_match):
result.append(bookmarks_item)
# browse channels
- if logged_in and settings.get_bool('youtube.folder.browse_channels.show', True):
+ if logged_in and settings_bool('youtube.folder.browse_channels.show', True):
browse_channels_item = DirectoryItem(
localize('browse_channels'),
create_uri(('special', 'browse_channels')),
@@ -1345,7 +1346,7 @@ def on_root(self, context, re_match):
result.append(browse_channels_item)
# completed live events
- if settings.get_bool('youtube.folder.completed.live.show', True):
+ if settings_bool('youtube.folder.completed.live.show', True):
live_events_item = DirectoryItem(
localize('live.completed'),
create_uri(('special', 'completed_live')),
@@ -1354,7 +1355,7 @@ def on_root(self, context, re_match):
result.append(live_events_item)
# upcoming live events
- if settings.get_bool('youtube.folder.upcoming.live.show', True):
+ if settings_bool('youtube.folder.upcoming.live.show', True):
live_events_item = DirectoryItem(
localize('live.upcoming'),
create_uri(('special', 'upcoming_live')),
@@ -1363,7 +1364,7 @@ def on_root(self, context, re_match):
result.append(live_events_item)
# live events
- if settings.get_bool('youtube.folder.live.show', True):
+ if settings_bool('youtube.folder.live.show', True):
live_events_item = DirectoryItem(
localize('live'),
create_uri(('special', 'live')),
@@ -1372,7 +1373,7 @@ def on_root(self, context, re_match):
result.append(live_events_item)
# switch user
- if settings.get_bool('youtube.folder.switch.user.show', True):
+ if settings_bool('youtube.folder.switch.user.show', True):
switch_user_item = DirectoryItem(
localize('user.switch'),
create_uri(('users', 'switch')),
@@ -1382,7 +1383,7 @@ def on_root(self, context, re_match):
result.append(switch_user_item)
# sign out
- if logged_in and settings.get_bool('youtube.folder.sign.out.show', True):
+ if logged_in and settings_bool('youtube.folder.sign.out.show', True):
sign_out_item = DirectoryItem(
localize('sign.out'),
create_uri(('sign', 'out')),
@@ -1391,7 +1392,7 @@ def on_root(self, context, re_match):
)
result.append(sign_out_item)
- if settings.get_bool('youtube.folder.settings.show', True):
+ if settings_bool('youtube.folder.settings.show', True):
settings_menu_item = DirectoryItem(
localize('setup_wizard'),
create_uri(('config', 'setup_wizard')),
@@ -1400,7 +1401,7 @@ def on_root(self, context, re_match):
)
result.append(settings_menu_item)
- if settings.get_bool('youtube.folder.settings.advanced.show', True):
+ if settings_bool('youtube.folder.settings.advanced.show'):
settings_menu_item = DirectoryItem(
localize('settings'),
create_uri(('config', 'youtube')),
From 4a8641a4d8faf76628617230abf4fa0bf82ef279 Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Mon, 1 Jul 2024 08:44:26 +1000
Subject: [PATCH 06/15] Fix http server not sleeping after initial start of
service
---
.../kodion/monitors/service_monitor.py | 2 ++
.../lib/youtube_plugin/kodion/service_runner.py | 14 +++++++-------
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/resources/lib/youtube_plugin/kodion/monitors/service_monitor.py b/resources/lib/youtube_plugin/kodion/monitors/service_monitor.py
index 739f1ff9c..9b7ef586e 100644
--- a/resources/lib/youtube_plugin/kodion/monitors/service_monitor.py
+++ b/resources/lib/youtube_plugin/kodion/monitors/service_monitor.py
@@ -41,6 +41,7 @@ def __init__(self, context):
self.httpd = None
self.httpd_thread = None
+ self.httpd_sleep_allowed = True
self.refresh = False
self.interrupt = False
@@ -103,6 +104,7 @@ def onNotification(self, sender, method, data):
self.interrupt = True
elif target == SERVER_WAKEUP:
if not self.httpd and self.httpd_required():
+ self.httpd_sleep_allowed = False
self.start_httpd()
if data.get('response_required'):
self.set_property(WAKEUP, target)
diff --git a/resources/lib/youtube_plugin/kodion/service_runner.py b/resources/lib/youtube_plugin/kodion/service_runner.py
index 31f4c66ba..3d0405998 100644
--- a/resources/lib/youtube_plugin/kodion/service_runner.py
+++ b/resources/lib/youtube_plugin/kodion/service_runner.py
@@ -51,7 +51,7 @@ def run():
# wipe add-on temp folder on updates/restarts (subtitles, and mpd files)
rm_dir(TEMP_PATH)
- plugin_sleeping = httpd_can_sleep = False
+ plugin_sleeping = False
plugin_sleep_timeout = httpd_sleep_timeout = 0
ping_period = 60
loop_num = sub_loop_num = 0
@@ -72,15 +72,15 @@ def run():
plugin_sleeping = clear_property(PLUGIN_SLEEPING)
if not monitor.httpd:
- httpd_can_sleep = False
httpd_sleep_timeout = 0
elif idle:
- if pop_property(SERVER_POST_START):
- httpd_can_sleep = True
+ if monitor.httpd_sleep_allowed:
+ if httpd_sleep_timeout >= 30:
+ monitor.shutdown_httpd(sleep=True)
+ else:
+ if pop_property(SERVER_POST_START):
+ monitor.httpd_sleep_allowed = True
httpd_sleep_timeout = 0
- if httpd_can_sleep and httpd_sleep_timeout >= 30:
- httpd_can_sleep = False
- monitor.shutdown_httpd(sleep=True)
else:
if httpd_sleep_timeout >= ping_period:
httpd_sleep_timeout = 0
From f3d504ba7e76bbb5e1173264733d9732552ba650 Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Tue, 2 Jul 2024 09:34:50 +1000
Subject: [PATCH 07/15] Add ability for sub-classes of Storage to define a
subset of the sql statements they will use
- Remainder of sql statement will be updated from the Storage parent class
---
.../lib/youtube_plugin/kodion/sql_store/storage.py | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/resources/lib/youtube_plugin/kodion/sql_store/storage.py b/resources/lib/youtube_plugin/kodion/sql_store/storage.py
index 984228c0f..92fc6e582 100644
--- a/resources/lib/youtube_plugin/kodion/sql_store/storage.py
+++ b/resources/lib/youtube_plugin/kodion/sql_store/storage.py
@@ -181,6 +181,20 @@ def __init__(self,
for name, sql in Storage._sql.items()
}
self._base._sql.update(statements)
+ elif self._sql and '_partial' in self._sql:
+ statements = {
+ name: sql.format(table=self._table_name,
+ order_col='timestamp')
+ for name, sql in Storage._sql.items()
+ }
+ partial_statements = {
+ name: sql.format(table=self._table_name,
+ order_col='timestamp')
+ for name, sql in self._base._sql.items()
+ if not name.startswith('_')
+ }
+ statements.update(partial_statements)
+ self._base._sql = statements
def set_max_item_count(self, max_item_count):
self._max_item_count = max_item_count
From 7ec0ae627ae198cf07b34c03f5dc2cbbd4922ba8 Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Wed, 3 Jul 2024 09:29:14 +1000
Subject: [PATCH 08/15] Add methods to properly update rows in sqlite database
- Also rename all methods consistently
- Allow inserting rows with auto-incrementing primary key
---
.../kodion/abstract_provider.py | 9 ++++----
.../kodion/items/xbmc/xbmc_items.py | 2 +-
.../kodion/monitors/player_monitor.py | 6 +++---
.../kodion/sql_store/bookmarks_list.py | 8 +++----
.../kodion/sql_store/data_cache.py | 6 +++---
.../kodion/sql_store/playback_history.py | 9 +++++---
.../kodion/sql_store/search_history.py | 11 +++++-----
.../kodion/sql_store/storage.py | 19 +++++++++++++++--
.../kodion/sql_store/watch_later_list.py | 4 ++--
.../youtube/helper/yt_playlist.py | 6 +++---
.../youtube/helper/yt_setup_wizard.py | 4 ++--
.../lib/youtube_plugin/youtube/provider.py | 21 ++++++++++++-------
12 files changed, 64 insertions(+), 41 deletions(-)
diff --git a/resources/lib/youtube_plugin/kodion/abstract_provider.py b/resources/lib/youtube_plugin/kodion/abstract_provider.py
index 64ece6560..1dc39cda1 100644
--- a/resources/lib/youtube_plugin/kodion/abstract_provider.py
+++ b/resources/lib/youtube_plugin/kodion/abstract_provider.py
@@ -266,12 +266,12 @@ def _internal_search(self, context, re_match):
if not command or command == 'query':
query = to_unicode(params.get('q', ''))
if not params.get('incognito') and not params.get('channel_id'):
- search_history.update(query)
+ search_history.add_item(query)
return self.on_search(query, context, re_match)
if command == 'remove':
query = to_unicode(params.get('q', ''))
- search_history.remove(query)
+ search_history.del_item(query)
ui.refresh_container()
return True
@@ -281,7 +281,8 @@ def _internal_search(self, context, re_match):
context.localize('search.rename'), query
)
if result:
- search_history.rename(query, new_query)
+ search_history.del_item(query)
+ search_history.add_item(new_query)
ui.refresh_container()
return True
@@ -317,7 +318,7 @@ def _internal_search(self, context, re_match):
data_cache.set_item('search_query', query)
if not params.get('incognito') and not params.get('channel_id'):
- search_history.update(query)
+ search_history.add_item(query)
context.set_path(PATHS.SEARCH, 'query')
return self.on_search(query, context, re_match)
diff --git a/resources/lib/youtube_plugin/kodion/items/xbmc/xbmc_items.py b/resources/lib/youtube_plugin/kodion/items/xbmc/xbmc_items.py
index 0dbf6fa11..08c350fa5 100644
--- a/resources/lib/youtube_plugin/kodion/items/xbmc/xbmc_items.py
+++ b/resources/lib/youtube_plugin/kodion/items/xbmc/xbmc_items.py
@@ -722,7 +722,7 @@ def video_listitem(context,
if not set_play_count:
video_id = video_item.video_id
playback_history = context.get_playback_history()
- playback_history.update(video_id, dict(
+ playback_history.set_item(video_id, dict(
playback_history.get_item(video_id) or {},
play_count=int(not video_item.get_play_count()),
played_time=0.0,
diff --git a/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py b/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py
index 311939f9f..6bd9989de 100644
--- a/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py
+++ b/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py
@@ -217,8 +217,8 @@ def run(self):
status=(segment_end, segment_end, segment_end, 'stopped'),
)
if use_local_history:
- self._context.get_playback_history().update(self.video_id,
- play_data)
+ self._context.get_playback_history().update_item(self.video_id,
+ play_data)
self._context.send_notification(PLAYBACK_STOPPED, self.playback_data)
self._context.log_debug('Playback stopped [{video_id}]:'
@@ -246,7 +246,7 @@ def run(self):
confirmed=True,
)
else:
- self._context.get_watch_later_list().remove(self.video_id)
+ self._context.get_watch_later_list().del_item(self.video_id)
if logged_in and not refresh_only:
history_id = access_manager.get_watch_history_id()
diff --git a/resources/lib/youtube_plugin/kodion/sql_store/bookmarks_list.py b/resources/lib/youtube_plugin/kodion/sql_store/bookmarks_list.py
index 9d5683095..1fe376796 100644
--- a/resources/lib/youtube_plugin/kodion/sql_store/bookmarks_list.py
+++ b/resources/lib/youtube_plugin/kodion/sql_store/bookmarks_list.py
@@ -27,14 +27,14 @@ def get_items(self):
result = self._get_by_ids(process=from_json, as_dict=True)
return result
- def add(self, item_id, item):
+ def add_item(self, item_id, item):
self._set(item_id, item)
- def remove(self, item_id):
+ def del_item(self, item_id):
self._remove(item_id)
- def update(self, item_id, item, timestamp=None):
- self._set(item_id, item, timestamp)
+ def update_item(self, item_id, item, timestamp=None):
+ self._update(item_id, item, timestamp)
def _optimize_item_count(self, limit=-1, defer=False):
return False
diff --git a/resources/lib/youtube_plugin/kodion/sql_store/data_cache.py b/resources/lib/youtube_plugin/kodion/sql_store/data_cache.py
index 6a62724a3..595813be8 100644
--- a/resources/lib/youtube_plugin/kodion/sql_store/data_cache.py
+++ b/resources/lib/youtube_plugin/kodion/sql_store/data_cache.py
@@ -63,11 +63,11 @@ def set_item(self, content_id, item):
def set_items(self, items):
self._set_many(items)
- def remove(self, content_id):
+ def del_item(self, content_id):
self._remove(content_id)
- def update(self, content_id, item, timestamp=None):
- self._set(content_id, item, timestamp)
+ def update_item(self, content_id, item, timestamp=None):
+ self._update(content_id, item, timestamp)
def _optimize_item_count(self, limit=-1, defer=False):
return False
diff --git a/resources/lib/youtube_plugin/kodion/sql_store/playback_history.py b/resources/lib/youtube_plugin/kodion/sql_store/playback_history.py
index 7077a3a95..8f679075f 100644
--- a/resources/lib/youtube_plugin/kodion/sql_store/playback_history.py
+++ b/resources/lib/youtube_plugin/kodion/sql_store/playback_history.py
@@ -40,11 +40,14 @@ def get_item(self, key):
result = self._get(key, process=self._add_last_played)
return result
- def remove(self, video_id):
+ def set_item(self, video_id, play_data, timestamp=None):
+ self._set(video_id, play_data, timestamp)
+
+ def del_item(self, video_id):
self._remove(video_id)
- def update(self, video_id, play_data, timestamp=None):
- self._set(video_id, play_data, timestamp)
+ def update_item(self, video_id, play_data, timestamp=None):
+ self._update(video_id, play_data, timestamp)
def _optimize_item_count(self, limit=-1, defer=False):
return False
diff --git a/resources/lib/youtube_plugin/kodion/sql_store/search_history.py b/resources/lib/youtube_plugin/kodion/sql_store/search_history.py
index 1c504f468..66e5ad723 100644
--- a/resources/lib/youtube_plugin/kodion/sql_store/search_history.py
+++ b/resources/lib/youtube_plugin/kodion/sql_store/search_history.py
@@ -36,12 +36,11 @@ def get_items(self, process=None):
def _make_id(search_text):
return md5(search_text.encode('utf-8')).hexdigest()
- def rename(self, old_search_text, new_search_text):
- self.remove(old_search_text)
- self.update(new_search_text)
+ def add_item(self, search_text):
+ self._set(self._make_id(search_text), search_text)
- def remove(self, search_text):
+ def del_item(self, search_text):
self._remove(self._make_id(search_text))
- def update(self, search_text, timestamp=None):
- self._set(self._make_id(search_text), search_text, timestamp)
+ def update_item(self, search_text, timestamp=None):
+ self._update(self._make_id(search_text), search_text, timestamp)
diff --git a/resources/lib/youtube_plugin/kodion/sql_store/storage.py b/resources/lib/youtube_plugin/kodion/sql_store/storage.py
index 92fc6e582..6edb6ce2f 100644
--- a/resources/lib/youtube_plugin/kodion/sql_store/storage.py
+++ b/resources/lib/youtube_plugin/kodion/sql_store/storage.py
@@ -150,6 +150,12 @@ class Storage(object):
' (key, timestamp, value, size)'
' VALUES {{0}};'
),
+ 'update': (
+ 'UPDATE'
+ ' {table}'
+ ' SET timestamp = ?, value = ?, size = ?'
+ ' WHERE key = ?;'
+ ),
}
def __init__(self,
@@ -389,6 +395,11 @@ def _set_many(self, items, flatten=False):
self._execute(cursor, query, many=(not flatten), values=values)
self._optimize_file_size()
+ def _update(self, item_id, item, timestamp=None):
+ values = self._encode(item_id, item, timestamp, for_update=True)
+ with self as (db, cursor), db:
+ self._execute(cursor, self._sql['update'], values=values)
+
def clear(self, defer=False):
query = self._sql['clear']
if defer:
@@ -416,7 +427,7 @@ def _decode(obj, process=None, item=None):
return decoded_obj
@staticmethod
- def _encode(key, obj, timestamp=None):
+ def _encode(key, obj, timestamp=None, for_update=False):
timestamp = timestamp or since_epoch()
blob = sqlite3.Binary(pickle.dumps(
obj, protocol=pickle.HIGHEST_PROTOCOL
@@ -424,7 +435,11 @@ def _encode(key, obj, timestamp=None):
size = getattr(blob, 'nbytes', None)
if not size:
size = int(memoryview(blob).itemsize) * len(blob)
- return str(key), timestamp, blob, size
+ if key:
+ if for_update:
+ return timestamp, blob, size, str(key)
+ return str(key), timestamp, blob, size
+ return timestamp, blob, size
def _get(self, item_id, process=None, seconds=None, as_dict=False):
with self as (db, cursor), db:
diff --git a/resources/lib/youtube_plugin/kodion/sql_store/watch_later_list.py b/resources/lib/youtube_plugin/kodion/sql_store/watch_later_list.py
index 1efa3b935..54150c577 100644
--- a/resources/lib/youtube_plugin/kodion/sql_store/watch_later_list.py
+++ b/resources/lib/youtube_plugin/kodion/sql_store/watch_later_list.py
@@ -27,8 +27,8 @@ def get_items(self):
result = self._get_by_ids(process=from_json, as_dict=True)
return result
- def add(self, video_id, item):
+ def add_item(self, video_id, item):
self._set(video_id, item)
- def remove(self, video_id):
+ def del_item(self, video_id):
self._remove(video_id)
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py b/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
index 60a137dd0..965a76493 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
@@ -63,7 +63,7 @@ def _process_add_video(provider, context, keymap_action=False):
if playlist_cache:
cache_key, _, cached_last_page = playlist_cache[0]
if cached_last_page:
- data_cache.update(cache_key, None)
+ data_cache.update_item(cache_key, None)
return True
@@ -170,7 +170,7 @@ def _process_remove_playlist(provider, context):
if channel_id:
data_cache = context.get_data_cache()
- data_cache.remove(channel_id)
+ data_cache.del_item(channel_id)
ui.refresh_container()
return False
@@ -301,7 +301,7 @@ def _process_rename_playlist(provider, context):
return False
data_cache = context.get_data_cache()
- data_cache.remove(playlist_id)
+ data_cache.del_item(playlist_id)
ui.refresh_container()
return False
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 68d9cd8a8..ab7124cec 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_setup_wizard.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_setup_wizard.py
@@ -481,7 +481,7 @@ def _convert_old_search_item(value, item):
)
items = old_search_db.get_items(process=_convert_old_search_item)
for search in items:
- search_history.update(search['text'], search['timestamp'])
+ search_history.update_item(search['text'], search['timestamp'])
ui.show_notification(localize('succeeded'))
context.execute(
@@ -527,7 +527,7 @@ def _convert_old_history_item(value, item):
items = old_history_db.get_items(process=_convert_old_history_item)
for video_id, history in items.items():
timestamp = history.pop('timestamp', None)
- playback_history.update(video_id, history, timestamp)
+ playback_history.update_item(video_id, history, timestamp)
ui.show_notification(localize('succeeded'))
context.execute(
diff --git a/resources/lib/youtube_plugin/youtube/provider.py b/resources/lib/youtube_plugin/youtube/provider.py
index 1b90fcd8d..e060ea913 100644
--- a/resources/lib/youtube_plugin/youtube/provider.py
+++ b/resources/lib/youtube_plugin/youtube/provider.py
@@ -1073,12 +1073,15 @@ def on_playback_history(self, context, re_match):
return False
if action == 'remove':
- playback_history.remove(video_id)
+ playback_history.del_item(video_id)
context.get_ui().refresh_container()
return True
play_data = playback_history.get_item(video_id)
- if not play_data:
+ if play_data:
+ playback_history_method = playback_history.update_item
+ else:
+ playback_history_method = playback_history.set_item
play_data = {
'play_count': 0,
'total_time': 0,
@@ -1100,7 +1103,7 @@ def on_playback_history(self, context, re_match):
play_data['played_time'] = 0
play_data['played_percent'] = 0
- playback_history.update(video_id, play_data)
+ playback_history_method(video_id, play_data)
context.get_ui().refresh_container()
return True
@@ -1445,7 +1448,9 @@ def on_bookmarks(self, context, re_match):
timestamp = items[channel_id]
channel_item.set_bookmark_timestamp(timestamp)
items[channel_id] = channel_item
- bookmarks_list.update(channel_id, repr(channel_item), timestamp)
+ bookmarks_list.update_item(
+ channel_id, repr(channel_item), timestamp
+ )
bookmarks = []
for item_id, item in items.items():
@@ -1488,7 +1493,7 @@ def on_bookmarks(self, context, re_match):
if command == 'add':
item = params.get('item')
- context.get_bookmarks_list().add(item_id, item)
+ context.get_bookmarks_list().add_item(item_id, item)
ui.show_notification(
localize('bookmark.created'),
@@ -1498,7 +1503,7 @@ def on_bookmarks(self, context, re_match):
return True
if command == 'remove':
- context.get_bookmarks_list().remove(item_id)
+ context.get_bookmarks_list().del_item(item_id)
context.get_ui().refresh_container()
ui.show_notification(
@@ -1564,11 +1569,11 @@ def on_watch_later(self, context, re_match):
if command == 'add':
item = params.get('item')
if item:
- context.get_watch_later_list().add(video_id, item)
+ context.get_watch_later_list().add_item(video_id, item)
return True
if command == 'remove':
- context.get_watch_later_list().remove(video_id)
+ context.get_watch_later_list().del_item(video_id)
context.get_ui().refresh_container()
return True
From da804f49c0c5a46cb6cc59f51757c8f35b44e0fa Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Wed, 3 Jul 2024 22:25:47 +1000
Subject: [PATCH 09/15] Use create_uri in XbmcContext.is_plugin_path
- Test paths should use the same creation method as the original path they are being tested against
---
.../youtube_plugin/kodion/context/abstract_context.py | 2 +-
.../youtube_plugin/kodion/context/xbmc/xbmc_context.py | 9 +++------
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/resources/lib/youtube_plugin/kodion/context/abstract_context.py b/resources/lib/youtube_plugin/kodion/context/abstract_context.py
index 323bbc39d..de63edfe9 100644
--- a/resources/lib/youtube_plugin/kodion/context/abstract_context.py
+++ b/resources/lib/youtube_plugin/kodion/context/abstract_context.py
@@ -262,7 +262,7 @@ def create_uri(self, path=None, params=None):
elif path:
uri = path
else:
- uri = '/' if params else '/?'
+ uri = '/'
uri = self._plugin_id.join(('plugin://', uri))
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 40c353f46..853125600 100644
--- a/resources/lib/youtube_plugin/kodion/context/xbmc/xbmc_context.py
+++ b/resources/lib/youtube_plugin/kodion/context/xbmc/xbmc_context.py
@@ -365,23 +365,20 @@ def get_region(self):
pass # implement from abstract
def is_plugin_path(self, uri, uri_path='', partial=False):
- plugin = self.get_id()
-
if isinstance(uri_path, (list, tuple)):
if partial:
- paths = ['plugin://{0}/{1}'.format(plugin, path).rstrip('/')
- for path in uri_path]
+ paths = [self.create_uri(path).rstrip('/') for path in uri_path]
else:
paths = []
for path in uri_path:
- path = 'plugin://{0}/{1}'.format(plugin, path).rstrip('/')
+ path = self.create_uri(path).rstrip('/')
paths.extend((
path + '/',
path + '?'
))
return uri.startswith(tuple(paths))
- uri_path = 'plugin://{0}/{1}'.format(plugin, uri_path).rstrip('/')
+ uri_path = self.create_uri(uri_path).rstrip('/')
if not partial:
uri_path = (
uri_path + '/',
From 595b377cfed2d7eb53e0b8dc7e787e055c786c45 Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Wed, 3 Jul 2024 22:28:54 +1000
Subject: [PATCH 10/15] Use constant for plugin play path
---
.../youtube_plugin/kodion/constants/const_paths.py | 1 +
.../kodion/context/abstract_context.py | 3 ++-
.../lib/youtube_plugin/kodion/items/menu_items.py | 12 ++++++------
.../youtube_plugin/kodion/monitors/player_monitor.py | 3 ++-
resources/lib/youtube_plugin/youtube/helper/tv.py | 3 ++-
.../youtube/helper/url_to_item_converter.py | 7 ++++---
.../lib/youtube_plugin/youtube/helper/yt_playlist.py | 6 +++---
.../lib/youtube_plugin/youtube/helper/yt_video.py | 3 ++-
resources/lib/youtube_plugin/youtube/provider.py | 2 +-
9 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/resources/lib/youtube_plugin/kodion/constants/const_paths.py b/resources/lib/youtube_plugin/kodion/constants/const_paths.py
index 3d1f3831a..e0003afb4 100644
--- a/resources/lib/youtube_plugin/kodion/constants/const_paths.py
+++ b/resources/lib/youtube_plugin/kodion/constants/const_paths.py
@@ -25,6 +25,7 @@
LIKED_VIDEOS = '/channel/mine/playlist/LL'
MY_PLAYLISTS = '/channel/mine/playlists'
MY_SUBSCRIPTIONS = '/special/my_subscriptions'
+PLAY = '/play'
SUBSCRIPTIONS = '/subscriptions/list'
API = '/youtube/api'
diff --git a/resources/lib/youtube_plugin/kodion/context/abstract_context.py b/resources/lib/youtube_plugin/kodion/context/abstract_context.py
index de63edfe9..a1cf01023 100644
--- a/resources/lib/youtube_plugin/kodion/context/abstract_context.py
+++ b/resources/lib/youtube_plugin/kodion/context/abstract_context.py
@@ -15,6 +15,7 @@
from .. import logger
from ..compatibility import quote, to_str, urlencode
from ..constants import (
+ PATHS,
PLAY_FORCE_AUDIO,
PLAY_PROMPT_QUALITY,
PLAY_PROMPT_SUBTITLES,
@@ -337,7 +338,7 @@ def parse_params(self, params=None):
elif param == 'action':
if parsed_value in {'play_all', 'play_video'}:
to_delete.append(param)
- self.set_path('play')
+ self.set_path(PATHS.PLAY)
continue
elif param == 'videoid':
to_delete.append(param)
diff --git a/resources/lib/youtube_plugin/kodion/items/menu_items.py b/resources/lib/youtube_plugin/kodion/items/menu_items.py
index d442615fb..2e3ac4269 100644
--- a/resources/lib/youtube_plugin/kodion/items/menu_items.py
+++ b/resources/lib/youtube_plugin/kodion/items/menu_items.py
@@ -75,7 +75,7 @@ def play_with(context, video_id):
return (
context.localize('video.play.with'),
'RunPlugin({0})'.format(context.create_uri(
- ('play',),
+ (PATHS.PLAY,),
{
'video_id': video_id,
PLAY_WITH: True,
@@ -107,7 +107,7 @@ def play_all_from_playlist(context, playlist_id, video_id=''):
return (
context.localize('playlist.play.from_here'),
'RunPlugin({0})'.format(context.create_uri(
- ('play',),
+ (PATHS.PLAY,),
{
'playlist_id': playlist_id,
'video_id': video_id,
@@ -118,7 +118,7 @@ def play_all_from_playlist(context, playlist_id, video_id=''):
return (
context.localize('playlist.play.all'),
'RunPlugin({0})'.format(context.create_uri(
- ('play',),
+ (PATHS.PLAY,),
{
'playlist_id': playlist_id,
'play': True,
@@ -366,7 +366,7 @@ def play_with_subtitles(context, video_id):
return (
context.localize('video.play.with_subtitles'),
'RunPlugin({0})'.format(context.create_uri(
- ('play',),
+ (PATHS.PLAY,),
{
'video_id': video_id,
PLAY_PROMPT_SUBTITLES: True,
@@ -379,7 +379,7 @@ def play_audio_only(context, video_id):
return (
context.localize('video.play.audio_only'),
'RunPlugin({0})'.format(context.create_uri(
- ('play',),
+ (PATHS.PLAY,),
{
'video_id': video_id,
PLAY_FORCE_AUDIO: True,
@@ -392,7 +392,7 @@ def play_ask_for_quality(context, video_id):
return (
context.localize('video.play.ask_for_quality'),
'RunPlugin({0})'.format(context.create_uri(
- ('play',),
+ (PATHS.PLAY,),
{
'video_id': video_id,
PLAY_PROMPT_QUALITY: True,
diff --git a/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py b/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py
index 6bd9989de..03e435beb 100644
--- a/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py
+++ b/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py
@@ -16,6 +16,7 @@
from ..compatibility import xbmc
from ..constants import (
BUSY_FLAG,
+ PATHS,
PLAYBACK_STARTED,
PLAYBACK_STOPPED,
PLAYER_DATA,
@@ -122,7 +123,7 @@ def run(self):
break
if (not current_file.startswith(playing_file) and not (
- self._context.is_plugin_path(current_file, 'play')
+ self._context.is_plugin_path(current_file, PATHS.PLAY)
and video_id_param in current_file
)) or total_time <= 0:
self.stop()
diff --git a/resources/lib/youtube_plugin/youtube/helper/tv.py b/resources/lib/youtube_plugin/youtube/helper/tv.py
index 155670d9f..4dde234fd 100644
--- a/resources/lib/youtube_plugin/youtube/helper/tv.py
+++ b/resources/lib/youtube_plugin/youtube/helper/tv.py
@@ -11,6 +11,7 @@
from __future__ import absolute_import, division, unicode_literals
from ..helper import utils
+from ...kodion.constants import PATHS
from ...kodion.items import DirectoryItem, NextPageItem, VideoItem
@@ -31,7 +32,7 @@ def tv_videos_to_items(provider, context, json_data):
video_id = item['id']
item_params['video_id'] = video_id
video_item = VideoItem(
- item['title'], context.create_uri(('play',), item_params)
+ item['title'], context.create_uri((PATHS.PLAY,), item_params)
)
if incognito:
video_item.set_play_count(0)
diff --git a/resources/lib/youtube_plugin/youtube/helper/url_to_item_converter.py b/resources/lib/youtube_plugin/youtube/helper/url_to_item_converter.py
index 1489dce86..737720607 100644
--- a/resources/lib/youtube_plugin/youtube/helper/url_to_item_converter.py
+++ b/resources/lib/youtube_plugin/youtube/helper/url_to_item_converter.py
@@ -14,6 +14,7 @@
from . import utils
from ...kodion.compatibility import parse_qsl, urlsplit
+from ...kodion.constants import PATHS
from ...kodion.items import DirectoryItem, UriItem, VideoItem
from ...kodion.utils import duration_to_seconds
@@ -85,7 +86,7 @@ def add_url(self, url, context):
video_id = new_params['video_id']
video_item = VideoItem(
- '', context.create_uri(('play',), new_params)
+ '', context.create_uri((PATHS.PLAY,), new_params)
)
self._video_id_dict[video_id] = video_item
@@ -110,7 +111,7 @@ def add_url(self, url, context):
return
channel_item = VideoItem(
- '', context.create_uri(('play',), new_params)
+ '', context.create_uri((PATHS.PLAY,), new_params)
) if live else DirectoryItem(
'', context.create_uri(('channel', channel_id,), new_params)
)
@@ -151,7 +152,7 @@ def get_items(self, provider, context, skip_title=False):
if context.get_param('uri'):
playlists_item = UriItem(
context.create_uri(
- ('play',),
+ (PATHS.PLAY,),
{
'playlist_ids': ','.join(self._playlist_ids),
'play': True,
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py b/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
index 965a76493..fc637c94b 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
@@ -12,7 +12,7 @@
from .utils import get_thumbnail
from ...kodion import KodionException
-from ...kodion.constants import CHANNEL_ID, PLAYLISTITEM_ID, PLAYLIST_ID
+from ...kodion.constants import CHANNEL_ID, PATHS, PLAYLISTITEM_ID, PLAYLIST_ID
from ...kodion.utils import find_video_id
@@ -36,7 +36,7 @@ def _process_add_video(provider, context, keymap_action=False):
video_id = context.get_param('video_id', '')
if not video_id:
- if context.is_plugin_path(listitem_path, 'play'):
+ if context.is_plugin_path(listitem_path, PATHS.PLAY):
video_id = find_video_id(listitem_path)
keymap_action = True
if not video_id:
@@ -187,7 +187,7 @@ def _process_select_playlist(provider, context):
video_id = params.get('video_id', '')
if not video_id:
- if context.is_plugin_path(listitem_path, 'play'):
+ if context.is_plugin_path(listitem_path, PATHS.PLAY):
video_id = find_video_id(listitem_path)
if video_id:
context.set_param('video_id', video_id)
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_video.py b/resources/lib/youtube_plugin/youtube/helper/yt_video.py
index 1d4beec00..eb270a457 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_video.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_video.py
@@ -11,6 +11,7 @@
from __future__ import absolute_import, division, unicode_literals
from ...kodion import KodionException
+from ...kodion.constants import PATHS
from ...kodion.items import menu_items
from ...kodion.utils import find_video_id
@@ -28,7 +29,7 @@ def _process_rate_video(provider, context, re_match):
try:
video_id = re_match.group('video_id')
except IndexError:
- if context.is_plugin_path(listitem_path, 'play'):
+ if context.is_plugin_path(listitem_path, PATHS.PLAY):
video_id = find_video_id(listitem_path)
if not video_id:
diff --git a/resources/lib/youtube_plugin/youtube/provider.py b/resources/lib/youtube_plugin/youtube/provider.py
index e060ea913..a17a5bb49 100644
--- a/resources/lib/youtube_plugin/youtube/provider.py
+++ b/resources/lib/youtube_plugin/youtube/provider.py
@@ -666,7 +666,7 @@ def on_play(self, context, re_match):
if ({'channel_id', 'playlist_id', 'playlist_ids', 'video_id'}
.isdisjoint(param_keys)):
listitem_path = context.get_listitem_info('FileNameAndPath')
- if context.is_plugin_path(listitem_path, 'play'):
+ if context.is_plugin_path(listitem_path, PATHS.PLAY):
video_id = find_video_id(listitem_path)
if video_id:
context.set_param('video_id', video_id)
From b058abc2387c20256ea35fb620fa9275198251bf Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Wed, 3 Jul 2024 22:40:39 +1000
Subject: [PATCH 11/15] Update v3 module methods
- Allow for custom plugin kinds
- plugin#pluginListResponse
- plugin#pluginItem
- plugin#commandItem
- Allow passing context params as part of item creation using custom '_params' value of response item
- Allow adding context menu items as part of item creation using custom '_context_menu' value of response item
- Support for playlist response items without channelId
---
.../lib/youtube_plugin/youtube/helper/v3.py | 152 +++++++++++-------
1 file changed, 95 insertions(+), 57 deletions(-)
diff --git a/resources/lib/youtube_plugin/youtube/helper/v3.py b/resources/lib/youtube_plugin/youtube/helper/v3.py
index c90eaea23..4f16e5151 100644
--- a/resources/lib/youtube_plugin/youtube/helper/v3.py
+++ b/resources/lib/youtube_plugin/youtube/helper/v3.py
@@ -49,14 +49,14 @@ def _process_list_response(provider, context, json_data, item_filter):
result = []
- item_params = {}
+ new_params = {}
params = context.get_params()
incognito = params.get('incognito', False)
if incognito:
- item_params['incognito'] = incognito
+ new_params['incognito'] = incognito
addon_id = params.get('addon_id', '')
if addon_id:
- item_params['addon_id'] = addon_id
+ new_params['addon_id'] = addon_id
settings = context.get_settings()
use_play_data = not incognito and settings.use_local_history()
@@ -71,46 +71,59 @@ def _process_list_response(provider, context, json_data, item_filter):
fanart_type = False
for yt_item in yt_items:
- is_youtube, kind = _parse_kind(yt_item)
- if not is_youtube or not kind:
- context.log_debug('v3 response: Item discarded, is_youtube=False')
+ kind, is_youtube, is_plugin, kind_type = _parse_kind(yt_item)
+ if not (is_youtube or is_plugin) or not kind_type:
+ context.log_debug('v3 item discarded: |%s|' % kind)
continue
- item_id = yt_item.get('id')
- snippet = yt_item.get('snippet', {})
- title = snippet.get('title', context.localize('untitled'))
-
- thumbnails = snippet.get('thumbnails')
- if not thumbnails and yt_item.get('_partial'):
- thumbnails = {
- thumb_type: {
- 'url': thumb['url'].format(item_id, ''),
- 'size': thumb['size'],
- 'ratio': thumb['ratio'],
+ item_params = yt_item.get('_params', {})
+ item_params.update(new_params)
+
+ if is_youtube:
+ item_id = yt_item.get('id')
+ snippet = yt_item.get('snippet', {})
+ title = snippet.get('title', context.localize('untitled'))
+
+ thumbnails = snippet.get('thumbnails')
+ if not thumbnails and yt_item.get('_partial'):
+ thumbnails = {
+ thumb_type: {
+ 'url': thumb['url'].format(item_id, ''),
+ 'size': thumb['size'],
+ 'ratio': thumb['ratio'],
+ }
+ for thumb_type, thumb in THUMB_TYPES.items()
}
- for thumb_type, thumb in THUMB_TYPES.items()
- }
- image = get_thumbnail(thumb_size, thumbnails)
- fanart = get_thumbnail(fanart_type, thumbnails) if fanart_type else None
-
- if kind == 'searchresult':
- _, kind = _parse_kind(item_id)
- if kind == 'video':
+ image = get_thumbnail(thumb_size, thumbnails)
+ if fanart_type:
+ fanart = get_thumbnail(fanart_type, thumbnails)
+ else:
+ fanart = None
+
+ if kind_type == 'searchresult':
+ kind, _, _, kind_type = _parse_kind(item_id)
+ if kind_type == 'video' and 'videoId' in item_id:
item_id = item_id['videoId']
- elif kind == 'playlist':
+ elif kind_type == 'playlist' and 'playlistId' in item_id:
item_id = item_id['playlistId']
- elif kind == 'channel':
+ elif kind_type == 'channel' and 'channelId' in item_id:
item_id = item_id['channelId']
+ else:
+ item_id = None
+ if not item_id:
+ context.log_debug('v3 searchResult discarded: |%s|' % kind)
+ continue
- if kind == 'video':
+ if kind_type == 'video':
+ item_params['video_id'] = item_id
item_uri = context.create_uri(
- ('play',),
- dict(item_params, video_id=item_id),
+ (PATHS.PLAY,),
+ item_params,
)
item = VideoItem(title, item_uri, image=image, fanart=fanart)
video_id_dict[item_id] = item
- elif kind == 'channel':
+ elif kind_type == 'channel':
item_uri = context.create_uri(
('channel', item_id),
item_params,
@@ -122,14 +135,15 @@ def _process_list_response(provider, context, json_data, item_filter):
channel_id=item_id)
channel_id_dict[item_id] = item
- elif kind == 'guidecategory':
+ elif kind_type == 'guidecategory':
+ item_params['guide_id'] = item_id
item_uri = context.create_uri(
('special', 'browse_channels'),
- dict(item_params, guide_id=item_id),
+ item_params,
)
item = DirectoryItem(title, item_uri)
- elif kind == 'subscription':
+ elif kind_type == 'subscription':
subscription_id = item_id
item_id = snippet['resourceId']['channelId']
# map channel id with subscription id - needed to unsubscribe
@@ -147,17 +161,23 @@ def _process_list_response(provider, context, json_data, item_filter):
subscription_id=subscription_id)
channel_id_dict[item_id] = item
- elif kind == 'playlist':
+ elif kind_type == 'playlist':
# set channel id to 'mine' if the path is for a playlist of our own
+ channel_id = snippet.get('channelId')
if context.get_path().startswith(PATHS.MY_PLAYLISTS):
uri_channel_id = 'mine'
- channel_id = snippet['channelId']
else:
- uri_channel_id = channel_id = snippet['channelId']
- item_uri = context.create_uri(
- ('channel', uri_channel_id, 'playlist', item_id),
- item_params,
- )
+ uri_channel_id = channel_id
+ if uri_channel_id:
+ item_uri = context.create_uri(
+ ('channel', uri_channel_id, 'playlist', item_id),
+ item_params,
+ )
+ else:
+ item_uri = context.create_uri(
+ ('playlist', item_id),
+ item_params,
+ )
item = DirectoryItem(title,
item_uri,
image=image,
@@ -166,20 +186,21 @@ def _process_list_response(provider, context, json_data, item_filter):
playlist_id=item_id)
playlist_id_dict[item_id] = item
- elif kind == 'playlistitem':
+ elif kind_type == 'playlistitem':
playlistitem_id = item_id
item_id = snippet['resourceId']['videoId']
# store the id of the playlistItem - needed for deleting item
playlist_item_id_dict[item_id] = playlistitem_id
+ item_params['video_id'] = item_id
item_uri = context.create_uri(
- ('play',),
- dict(item_params, video_id=item_id),
+ (PATHS.PLAY,),
+ item_params,
)
item = VideoItem(title, item_uri, image=image, fanart=fanart)
video_id_dict[item_id] = item
- elif kind == 'activity':
+ elif kind_type == 'activity':
details = yt_item['contentDetails']
activity_type = snippet['type']
if activity_type == 'recommendation':
@@ -189,14 +210,15 @@ def _process_list_response(provider, context, json_data, item_filter):
else:
continue
+ item_params['video_id'] = item_id
item_uri = context.create_uri(
- ('play',),
- dict(item_params, video_id=item_id),
+ (PATHS.PLAY,),
+ item_params,
)
item = VideoItem(title, item_uri, image=image, fanart=fanart)
video_id_dict[item_id] = item
- elif kind == 'commentthread':
+ elif kind_type == 'commentthread':
total_replies = snippet['totalReplyCount']
snippet = snippet['topLevelComment']['snippet']
if total_replies:
@@ -208,14 +230,25 @@ def _process_list_response(provider, context, json_data, item_filter):
item_uri = ''
item = make_comment_item(context, snippet, item_uri, total_replies)
- elif kind == 'comment':
+ elif kind_type == 'comment':
item = make_comment_item(context, snippet, uri='')
+ elif kind_type == 'pluginitem':
+ item = DirectoryItem(**item_params)
+
+ elif kind_type == 'commanditem':
+ item = CommandItem(context=context, **item_params)
+
else:
- raise KodionException("Unknown kind '%s'" % kind)
+ item = None
+ raise KodionException('Unknown kind: %s' % kind)
if not item:
continue
+
+ if '_context_menu' in yt_item:
+ item.add_context_menu(**yt_item['_context_menu'])
+
if isinstance(item, VideoItem):
item.video_id = item_id
if incognito:
@@ -224,6 +257,7 @@ def _process_list_response(provider, context, json_data, item_filter):
# match "Default" (unsorted) sort order
position = snippet.get('position') or len(result)
item.set_track_number(position + 1)
+
result.append(item)
# this will also update the channel_id_dict with the correct channel_id
@@ -385,6 +419,8 @@ def _fetch(resource):
'searchlistresponse',
'subscriptionlistresponse',
'videolistresponse',
+ # plugin kinds
+ 'pluginlistresponse',
}
@@ -395,12 +431,12 @@ def response_to_items(provider,
reverse=False,
process_next_page=True,
item_filter=None):
- is_youtube, kind = _parse_kind(json_data)
- if not is_youtube:
- context.log_debug('v3 response: Response discarded, is_youtube=False')
+ kind, is_youtube, is_plugin, kind_type = _parse_kind(json_data)
+ if not is_youtube and not is_plugin:
+ context.log_debug('v3 response discarded: |%s|' % kind)
return []
- if kind in _KNOWN_RESPONSE_KINDS:
+ if kind_type in _KNOWN_RESPONSE_KINDS:
item_filter = context.get_settings().item_filter(item_filter)
result = _process_list_response(
provider, context, json_data, item_filter
@@ -475,7 +511,9 @@ def response_to_items(provider,
def _parse_kind(item):
- parts = item.get('kind', '').split('#')
+ kind = item.get('kind', '')
+ parts = kind.split('#')
is_youtube = parts[0] == 'youtube'
- kind = parts[1 if len(parts) > 1 else 0].lower()
- return is_youtube, kind
+ is_plugin = parts[0] == 'plugin'
+ kind_type = parts[1 if len(parts) > 1 else 0].lower()
+ return kind, is_youtube, is_plugin, kind_type
From e76a9c5355a4defd49507f2f6a55e8ac8015df14 Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Thu, 4 Jul 2024 20:39:12 +1000
Subject: [PATCH 12/15] Ensure context menu items are not overwritten
unnecessarily and are seperated from Kodi items
---
resources/lib/youtube_plugin/youtube/helper/utils.py | 12 ++++++------
resources/lib/youtube_plugin/youtube/provider.py | 6 +++---
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/resources/lib/youtube_plugin/youtube/helper/utils.py b/resources/lib/youtube_plugin/youtube/helper/utils.py
index 84a96fd8f..072136ade 100644
--- a/resources/lib/youtube_plugin/youtube/helper/utils.py
+++ b/resources/lib/youtube_plugin/youtube/helper/utils.py
@@ -227,7 +227,8 @@ def update_channel_infos(provider, context, channel_id_dict,
)
if context_menu:
- channel_item.add_context_menu(context_menu, replace=True)
+ context_menu.append(menu_items.separator())
+ channel_item.add_context_menu(context_menu)
# update channel mapping
if channel_items_dict is not None:
@@ -339,7 +340,8 @@ def update_playlist_infos(provider, context, playlist_id_dict,
)
if context_menu:
- playlist_item.add_context_menu(context_menu, replace=True)
+ context_menu.append(menu_items.separator())
+ playlist_item.add_context_menu(context_menu)
# update channel mapping
if channel_items_dict is not None:
@@ -808,10 +810,8 @@ def update_video_infos(provider, context, video_id_dict,
)
if context_menu:
- context_menu.append(
- menu_items.separator(),
- )
- video_item.add_context_menu(context_menu, replace=True)
+ context_menu.append(menu_items.separator())
+ video_item.add_context_menu(context_menu)
def update_play_info(provider, context, video_id, video_item, video_stream,
diff --git a/resources/lib/youtube_plugin/youtube/provider.py b/resources/lib/youtube_plugin/youtube/provider.py
index a17a5bb49..29a00a006 100644
--- a/resources/lib/youtube_plugin/youtube/provider.py
+++ b/resources/lib/youtube_plugin/youtube/provider.py
@@ -1242,7 +1242,7 @@ def on_root(self, context, re_match):
context, watch_later_id
)
]
- watch_later_item.add_context_menu(context_menu, replace=True)
+ watch_later_item.add_context_menu(context_menu)
result.append(watch_later_item)
else:
watch_history_item = DirectoryItem(
@@ -1267,7 +1267,7 @@ def on_root(self, context, re_match):
context, playlists['likes']
)
]
- liked_videos_item.add_context_menu(context_menu, replace=True)
+ liked_videos_item.add_context_menu(context_menu)
result.append(liked_videos_item)
# disliked videos
@@ -1292,7 +1292,7 @@ def on_root(self, context, re_match):
context, history_id
)
]
- watch_history_item.add_context_menu(context_menu, replace=True)
+ watch_history_item.add_context_menu(context_menu)
result.append(watch_history_item)
elif local_history:
watch_history_item = DirectoryItem(
From 985c88a6a7cc03617da6d0747cd7980eb9ee27de Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Fri, 5 Jul 2024 06:05:19 +1000
Subject: [PATCH 13/15] Fix not reloading WL playlist if open after playback of
video in playlist
---
.../youtube/helper/yt_playlist.py | 33 ++++++++++++-------
1 file changed, 22 insertions(+), 11 deletions(-)
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py b/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
index fc637c94b..2f7440891 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
@@ -12,6 +12,7 @@
from .utils import get_thumbnail
from ...kodion import KodionException
+from ...kodion.compatibility import parse_qsl, urlsplit
from ...kodion.constants import CHANNEL_ID, PATHS, PLAYLISTITEM_ID, PLAYLIST_ID
from ...kodion.utils import find_video_id
@@ -74,7 +75,7 @@ def _process_remove_video(provider,
video_id=None,
video_name=None,
confirmed=None):
- listitem_path = context.get_listitem_info('FileNameAndPath')
+ container_uri = context.get_infolabel('Container.FolderPath')
listitem_playlist_id = context.get_listitem_property(PLAYLIST_ID)
listitem_video_id = context.get_listitem_property(PLAYLISTITEM_ID)
listitem_video_name = context.get_listitem_info('Title')
@@ -130,21 +131,31 @@ def _process_remove_video(provider,
if not success:
return False
- path = params.pop('reload_path', False if confirmed else None)
- if keymap_action and not confirmed:
- context.get_ui().set_focus_next_item()
- elif path is not False and context.is_plugin_path(listitem_path):
- provider.reroute(
- context,
- path=path,
- params=dict(params, refresh=params.get('refresh', 0) + 1),
- )
-
context.get_ui().show_notification(
message=context.localize('playlist.removed_from'),
time_ms=2500,
audible=False
)
+
+ if not context.is_plugin_path(container_uri):
+ return True
+
+ if (keymap_action or video_id == listitem_video_id) and not confirmed:
+ context.get_ui().set_focus_next_item()
+
+ if playlist_id in container_uri:
+ container_uri = urlsplit(container_uri)
+ path = container_uri.path
+ params = dict(parse_qsl(container_uri.query))
+ else:
+ path = params.pop('reload_path', False if confirmed else None)
+
+ if path is not False:
+ provider.reroute(
+ context,
+ path=path,
+ params=dict(params, refresh=int(params.get('refresh', 0)) + 1),
+ )
return True
return False
From ace0e799fb5b459c7a2e19e8c602eecfabc882b1 Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Fri, 5 Jul 2024 06:12:06 +1000
Subject: [PATCH 14/15] Update method to register routes to allow removal of
some wrapper methods
---
.../kodion/abstract_provider.py | 14 +++--
.../kodion/monitors/player_monitor.py | 2 +
.../youtube/helper/yt_playlist.py | 20 ++++++-
.../youtube/helper/yt_specials.py | 17 +++++-
.../youtube/helper/yt_subscriptions.py | 10 +++-
.../youtube_plugin/youtube/helper/yt_video.py | 7 ++-
.../lib/youtube_plugin/youtube/provider.py | 54 +++++++------------
7 files changed, 82 insertions(+), 42 deletions(-)
diff --git a/resources/lib/youtube_plugin/kodion/abstract_provider.py b/resources/lib/youtube_plugin/kodion/abstract_provider.py
index 1dc39cda1..f297039fb 100644
--- a/resources/lib/youtube_plugin/kodion/abstract_provider.py
+++ b/resources/lib/youtube_plugin/kodion/abstract_provider.py
@@ -108,7 +108,12 @@ def register_path(self, re_path, method):
:param method: method to be registered
:return:
"""
- self._dict_path[re.compile(re_path, re.UNICODE)] = method
+ self._dict_path[re.compile(re_path, re.UNICODE)] = {
+ 'method': method,
+ 'bound': isinstance(getattr(method, '__self__', None),
+ self.__class__),
+ }
+ return method
def run_wizard(self, context):
settings = context.get_settings()
@@ -142,7 +147,7 @@ def get_wizard_steps(self, context):
def navigate(self, context):
path = context.get_path()
- for re_path, method in self._dict_path.items():
+ for re_path, handler in self._dict_path.items():
re_match = re_path.search(path)
if not re_match:
continue
@@ -151,7 +156,10 @@ def navigate(self, context):
self.RESULT_CACHE_TO_DISC: True,
self.RESULT_UPDATE_LISTING: False,
}
- result = method(context, re_match)
+ if handler['bound']:
+ result = handler['method'](context, re_match)
+ else:
+ result = handler['method'](self, context, re_match)
if isinstance(result, tuple):
result, new_options = result
options.update(new_options)
diff --git a/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py b/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py
index 03e435beb..af6ca2f8d 100644
--- a/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py
+++ b/resources/lib/youtube_plugin/kodion/monitors/player_monitor.py
@@ -238,6 +238,7 @@ def run(self):
)
if playlist_item_id:
self._provider.on_playlist_x(
+ self._provider,
self._context,
method='remove',
category='video',
@@ -268,6 +269,7 @@ def run(self):
'/{0}/{1}/'.format(self.video_id, rating)
)
self._provider.on_video_x(
+ self._provider,
self._context,
rating_match,
method='rate',
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py b/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
index 2f7440891..d0c04e965 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_playlist.py
@@ -343,20 +343,38 @@ def _playlist_id_change(context, playlist, method):
return False
-def process(method, category, provider, context, **kwargs):
+def process(provider,
+ context,
+ re_match=None,
+ method=None,
+ category=None,
+ **kwargs):
+ if re_match:
+ if method is None:
+ method = re_match.group('method')
+ if category is None:
+ category = re_match.group('category')
+
if method == 'add' and category == 'video':
return _process_add_video(provider, context)
+
if method == 'remove' and category == 'video':
return _process_remove_video(provider, context, **kwargs)
+
if method == 'remove' and category == 'playlist':
return _process_remove_playlist(provider, context)
+
if method == 'select' and category == 'playlist':
return _process_select_playlist(provider, context)
+
if method == 'rename' and category == 'playlist':
return _process_rename_playlist(provider, context)
+
if method in {'set', 'remove'} and category == 'watch_later':
return _playlist_id_change(context, category, method)
+
if method in {'set', 'remove'} and category == 'history':
return _playlist_id_change(context, category, method)
+
raise KodionException('Unknown category |{0}| or method |{1}|'
.format(category, method))
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_specials.py b/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
index c2305fd2e..d9565fd00 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
@@ -314,44 +314,59 @@ def _process_my_subscriptions(provider, context, client, filtered=False):
return v3.response_to_items(provider, context, json_data)
-def process(category, provider, context):
+def process(provider, context, re_match):
+ category = re_match.group('category')
+
# required for provider.is_logged_in()
client = provider.get_client(context)
if category == 'related_videos':
return _process_related_videos(provider, context, client)
+
if category == 'popular_right_now':
return _process_trending(provider, context, client)
+
if category == 'recommendations':
return _process_recommendations(provider, context, client)
+
if category == 'browse_channels':
return _process_browse_channels(provider, context, client)
+
if category.startswith(('my_subscriptions', 'new_uploaded_videos_tv')):
return _process_my_subscriptions(
provider, context, client, filtered=category.endswith('_filtered'),
)
+
if category == 'disliked_videos':
if provider.is_logged_in():
return _process_disliked_videos(provider, context, client)
return UriItem(context.create_uri(('sign', 'in')))
+
if category == 'live':
return _process_live_events(
provider, context, client, event_type='live'
)
+
if category == 'upcoming_live':
return _process_live_events(
provider, context, client, event_type='upcoming'
)
+
if category == 'completed_live':
return _process_live_events(
provider, context, client, event_type='completed'
)
+
if category == 'description_links':
return _process_description_links(provider, context)
+
if category == 'parent_comments':
return _process_parent_comments(provider, context, client)
+
if category == 'child_comments':
return _process_child_comments(provider, context, client)
+
if category == 'saved_playlists':
return _process_saved_playlists_tv(provider, context, client)
+
raise KodionException('YouTube special category "%s" not found' % category)
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py b/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py
index aad82587a..f9cea5627 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_subscriptions.py
@@ -12,11 +12,12 @@
from ..helper import v3
from ...kodion import KodionException
-from ...kodion.constants import CHANNEL_ID, SUBSCRIPTION_ID
+from ...kodion.constants import CHANNEL_ID, CONTENT, SUBSCRIPTION_ID
from ...kodion.items import UriItem
def _process_list(provider, context, client):
+ context.set_content(CONTENT.LIST_CONTENT)
json_data = client.get_subscription(
'mine', page_token=context.get_param('page_token', '')
)
@@ -80,7 +81,9 @@ def _process_remove(_provider, context, client):
return True
-def process(method, provider, context):
+def process(provider, context, re_match):
+ method = re_match.group('method')
+
# we need a login
client = provider.get_client(context)
if not provider.is_logged_in():
@@ -88,8 +91,11 @@ def process(method, provider, context):
if method == 'list':
return _process_list(provider, context, client)
+
if method == 'add':
return _process_add(provider, context, client)
+
if method == 'remove':
return _process_remove(provider, context, client)
+
raise KodionException('Unknown subscriptions method: %s' % method)
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_video.py b/resources/lib/youtube_plugin/youtube/helper/yt_video.py
index eb270a457..a877a2b9a 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_video.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_video.py
@@ -116,9 +116,14 @@ def _process_more_for_video(context):
context.execute(result)
-def process(method, provider, context, re_match):
+def process(provider, context, re_match=None, method=None):
+ if re_match and method is None:
+ method = re_match.group('method')
+
if method == 'rate':
return _process_rate_video(provider, context, re_match)
+
if method == 'more':
return _process_more_for_video(context)
+
raise KodionException('Unknown method: %s' % method)
diff --git a/resources/lib/youtube_plugin/youtube/provider.py b/resources/lib/youtube_plugin/youtube/provider.py
index 29a00a006..9310de6f1 100644
--- a/resources/lib/youtube_plugin/youtube/provider.py
+++ b/resources/lib/youtube_plugin/youtube/provider.py
@@ -64,6 +64,26 @@ def __init__(self):
self._api_check = None
self._logged_in = False
+ self.on_video_x = self.register_path(
+ '^/video/(?P[^/]+)/?$',
+ yt_video.process,
+ )
+
+ self.on_playlist_x = self.register_path(
+ '^/playlist/(?P[^/]+)/(?P[^/]+)/?$',
+ yt_playlist.process,
+ )
+
+ self.register_path(
+ '^/special/(?P[^/]+)/?$',
+ yt_specials.process,
+ )
+
+ self.register_path(
+ '^/subscriptions/(?P[^/]+)/?$',
+ yt_subscriptions.process,
+ )
+
atexit.register(self.tear_down)
def get_wizard_steps(self, context):
@@ -706,40 +726,6 @@ def on_play(self, context, re_match):
return yt_play.play_channel_live(self, context)
return False
- @RegisterProviderPath('^/video/(?P[^/]+)/?$')
- def on_video_x(self, context, re_match=None, method=None):
- if method is None:
- method = re_match.group('method')
- return yt_video.process(method, self, context, re_match)
-
- @RegisterProviderPath('^/playlist/(?P[^/]+)/(?P[^/]+)/?$')
- def on_playlist_x(self,
- context,
- re_match=None,
- method=None,
- category=None,
- **kwargs):
- if method is None:
- method = re_match.group('method')
- if category is None:
- category = re_match.group('category')
- return yt_playlist.process(method, category, self, context, **kwargs)
-
- @RegisterProviderPath('^/subscriptions/(?P[^/]+)/?$')
- def _on_subscriptions(self, context, re_match):
- method = re_match.group('method')
- subscriptions = yt_subscriptions.process(method, self, context)
-
- if method == 'list':
- context.set_content(CONTENT.LIST_CONTENT)
-
- return subscriptions
-
- @RegisterProviderPath('^/special/(?P[^/]+)/?$')
- def _on_yt_specials(self, context, re_match):
- category = re_match.group('category')
- return yt_specials.process(category, self, context)
-
@RegisterProviderPath('^/users/(?P[^/]+)/?$')
def _on_users(self, _context, re_match):
action = re_match.group('action')
From 72d7d118c26737496d969cd52691608e85c651f2 Mon Sep 17 00:00:00 2001
From: MoojMidge <56883549+MoojMidge@users.noreply.github.com>
Date: Fri, 5 Jul 2024 16:56:37 +1000
Subject: [PATCH 15/15] Version bump v7.0.9+beta.2
---
addon.xml | 2 +-
changelog.txt | 21 ++++++++++++++++++++-
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/addon.xml b/addon.xml
index 8a4169d11..e12e26256 100644
--- a/addon.xml
+++ b/addon.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/changelog.txt b/changelog.txt
index a982ebc6f..af54f637c 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,7 +1,26 @@
+## v7.0.9+beta.2
+### Fixed
+- Fix ask for video quality setting being inconsistently applied
+- Fix http server not sleeping after initial start of service #746 #801
+- Fix not reloading WL playlist if open after playback of video in WL
+
+### Changed
+- Rename My Subscriptions plugin url
+ - From:
+ - plugin://plugin.video.youtube/special/new_uploaded_videos_tv
+ - plugin://plugin.video.youtube/special/new_uploaded_videos_tv_filtered
+ - To:
+ - plugin://plugin.video.youtube/special/my_subscriptions
+ - plugin://plugin.video.youtube/special/my_subscriptions_filtered
+ - Old url retained for backwards compatibility, to be removed with Kodi v22
+
+### New
+- Add notifications for creating/removing/clearing bookmarks #720
+
## v7.0.9+beta.1
### Fixed
- Fix renaming playlists
-- Improve https server wakeup #746 #801
+- Improve http server wakeup #746 #801
### Changed
- Make live query parameter optional when playing channel live stream