Skip to content

Commit

Permalink
Update root menu items
Browse files Browse the repository at this point in the history
- New recommendations as per YouTube home page (will use account details if logged in)
- Old recommendations -> related videos (requires local or remote history)
- Popular right now -> Trending
- Cache recommended and related video results for 1 hour
  • Loading branch information
MoojMidge committed Jan 10, 2024
1 parent e2e7d13 commit 75488c3
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 68 deletions.
2 changes: 1 addition & 1 deletion resources/language/resource.language.en_au/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ msgid "Browse Channels"
msgstr ""

msgctxt "#30513"
msgid "Popular right now"
msgid "Trending"
msgstr ""

msgctxt "#30514"
Expand Down
2 changes: 1 addition & 1 deletion resources/language/resource.language.en_gb/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ msgid "Browse Channels"
msgstr ""

msgctxt "#30513"
msgid "Popular right now"
msgid "Trending"
msgstr ""

msgctxt "#30514"
Expand Down
2 changes: 1 addition & 1 deletion resources/language/resource.language.en_nz/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ msgid "Browse Channels"
msgstr ""

msgctxt "#30513"
msgid "Popular right now"
msgid "Trending"
msgstr ""

msgctxt "#30514"
Expand Down
2 changes: 1 addition & 1 deletion resources/language/resource.language.en_us/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ msgid "Browse Channels"
msgstr ""

msgctxt "#30513"
msgid "Popular right now"
msgid "Trending"
msgstr ""

msgctxt "#30514"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class AbstractContext(object):
'channel_name',
'client_id',
'client_secret',
'click_tracking',
'event_type',
'item',
'item_id',
Expand All @@ -85,9 +86,10 @@ class AbstractContext(object):
'rating',
'search_type',
'subscription_id',
'uri',
'videoid', # deprecated
'video_id',
'uri',
'visitor',
}

def __init__(self, path='/', params=None, plugin_name='', plugin_id=''):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ class XbmcContext(AbstractContext):
'playlist.select': 30521,
'playlists': 30501,
'please_wait': 30119,
'popular_right_now': 30513,
'prompt': 30566,
'purchases': 30622,
'recommendations': 30551,
Expand Down Expand Up @@ -199,6 +198,7 @@ class XbmcContext(AbstractContext):
'subtitles.no_auto_generated': 30602,
'subtitles.with_fallback': 30601,
'succeeded': 30575,
'trending': 30513,
'unrated.video': 30718,
'unsubscribe': 30505,
'unsubscribed.from.channel': 30720,
Expand Down
197 changes: 165 additions & 32 deletions resources/lib/youtube_plugin/youtube/client/youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ def get_guide_categories(self, page_token='', **kwargs):
params=params,
**kwargs)

def get_popular_videos(self, page_token='', **kwargs):
def get_trending_videos(self, page_token='', **kwargs):
params = {'part': 'snippet,status',
'maxResults': str(self._max_results),
'regionCode': self._region,
Expand Down Expand Up @@ -415,7 +415,141 @@ def get_video_categories(self, page_token='', **kwargs):
params=params,
**kwargs)

def _get_recommendations_for_home(self):
def get_recommended_for_home(self,
visitor='',
page_token='',
click_tracking=''):
payload = {
'kind': 'youtube#activityListResponse',
'items': []
}

post_data = {'browseId': 'FEwhat_to_watch'}
if page_token:
post_data['continuation'] = page_token
if click_tracking or visitor:
context = {}
if click_tracking:
context['clickTracking'] = {
'clickTrackingParams': click_tracking,
}
if visitor:
context['client'] = {
'visitorData': visitor,
}
post_data['context'] = context

result = self.api_request(version=1,
method='POST',
path='browse',
post_data=post_data)
if not result:
return payload

recommended_videos = self.json_traverse(
result,
path=(
(
(
'onResponseReceivedEndpoints',
'onResponseReceivedActions',
),
0,
'appendContinuationItemsAction',
'continuationItems',
) if page_token else (
'contents',
'twoColumnBrowseResultsRenderer',
'tabs',
0,
'tabRenderer',
'content',
'richGridRenderer',
'contents',
)
) + (
slice(None),
(
(
'richItemRenderer',
'content',
'videoRenderer',
# 'videoId',
),
(
'richSectionRenderer',
'content',
'richShelfRenderer',
'contents',
slice(None),
'richItemRenderer',
'content',
(
'videoRenderer',
'reelItemRenderer'
),
# 'videoId',
),
(
'continuationItemRenderer',
'continuationEndpoint',
),
),
)
)
if not recommended_videos:
return payload

v3_response = {
'kind': 'youtube#activityListResponse',
'items': [
{
'kind': "youtube#video",
'id': video['videoId'],
'partial': True,
'snippet': {
'title': self.json_traverse(video, (
('title', 'runs', 0, 'text'),
('headline', 'simpleText'),
)),
'thumbnails': dict(zip(
('default', 'high'),
video['thumbnail']['thumbnails'],
)),
'channelId': self.json_traverse(video, (
('longBylineText', 'shortBylineText'),
'runs',
0,
'navigationEndpoint',
'browseEndpoint',
'browseId',
)),
}
}
for videos in recommended_videos
for video in
(videos if isinstance(videos, list) else (videos,))
if video and 'videoId' in video
]
}

last_item = recommended_videos[-1]
if last_item and 'continuationCommand' in last_item:
if 'clickTrackingParams' in last_item:
v3_response['clickTracking'] = last_item['clickTrackingParams']
token = last_item['continuationCommand'].get('token')
if token:
v3_response['nextPageToken'] = token
visitor = self.json_traverse(result, (
'responseContext',
'visitorData',
)) or visitor
if visitor:
v3_response['visitorData'] = visitor

return v3_response

def get_related_for_home(self, page_token=''):
"""
YouTube has deprecated this API, so we use history and related items to
form a recommended set.
Expand Down Expand Up @@ -445,6 +579,7 @@ def _get_recommendations_for_home(self):
video_ids = []
else:
return payload

for item in history_items:
try:
video_ids.append(item['snippet']['resourceId']['videoId'])
Expand Down Expand Up @@ -670,10 +805,6 @@ def get_activities(self, channel_id, page_token='', **kwargs):
'regionCode': self._region,
'hl': self._language}

if channel_id == 'home':
recommended = self._get_recommendations_for_home()
if 'items' in recommended and recommended['items']:
return recommended
if channel_id == 'home':
params['home'] = 'true'
elif channel_id == 'mine':
Expand Down Expand Up @@ -904,32 +1035,34 @@ def get_related_videos(self,

related_videos = self.json_traverse(
result,
path=((
'onResponseReceivedEndpoints',
0,
'appendContinuationItemsAction',
'continuationItems',
) if page_token else (
'contents',
'twoColumnWatchNextResults',
'secondaryResults',
'secondaryResults',
'results',
)) + (
slice(None),
(
(
'compactVideoRenderer',
# 'videoId',
),
(
'continuationItemRenderer',
'continuationEndpoint',
'continuationCommand',
# 'token',
),
),
)
path=(
(
'onResponseReceivedEndpoints',
0,
'appendContinuationItemsAction',
'continuationItems',
) if page_token else (
'contents',
'twoColumnWatchNextResults',
'secondaryResults',
'secondaryResults',
'results',
)
) + (
slice(None),
(
(
'compactVideoRenderer',
# 'videoId',
),
(
'continuationItemRenderer',
'continuationEndpoint',
'continuationCommand',
# 'token',
),
),
)
)
if not related_videos:
return []
Expand Down
6 changes: 6 additions & 0 deletions resources/lib/youtube_plugin/youtube/helper/v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,9 @@ def response_to_items(provider,
yt_total_results = int(page_info.get('totalResults', 0))
yt_results_per_page = int(page_info.get('resultsPerPage', 0))
page = int(context.get_param('page', 1))
yt_visitor_data = json_data.get('visitorData', '')
yt_next_page_token = json_data.get('nextPageToken', '')
yt_click_tracking = json_data.get('clickTracking', '')
if yt_next_page_token or (page * yt_results_per_page < yt_total_results):
if not yt_next_page_token:
client = provider.get_client(context)
Expand All @@ -392,6 +394,10 @@ def response_to_items(provider,

new_params = dict(context.get_params(),
page_token=yt_next_page_token)
if yt_click_tracking:
new_params['visitor'] = yt_visitor_data
if yt_click_tracking:
new_params['click_tracking'] = yt_click_tracking
new_context = context.clone(new_params=new_params)
current_page = new_context.get_param('page', 1)
next_page_item = NextPageItem(new_context, current_page)
Expand Down
46 changes: 29 additions & 17 deletions resources/lib/youtube_plugin/youtube/helper/yt_specials.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,22 @@

def _process_related_videos(provider, context):
context.set_content(content.VIDEOS)
video_id = context.get_param('video_id', '')
if not video_id:
return []

function_cache = context.get_function_cache()
json_data = function_cache.get(
provider.get_client(context).get_related_videos,
function_cache.ONE_HOUR,
video_id=video_id,
page_token=context.get_param('page_token', ''),
)

video_id = context.get_param('video_id', '')
if video_id:
json_data = function_cache.get(
provider.get_client(context).get_related_videos,
function_cache.ONE_HOUR,
video_id=video_id,
page_token=context.get_param('page_token', ''),
)
else:
json_data = function_cache.get(
provider.get_client(context).get_related_for_home,
function_cache.ONE_HOUR,
page_token=context.get_param('page_token', ''),
)
if not json_data:
return False
return v3.response_to_items(provider, context, json_data)
Expand Down Expand Up @@ -72,17 +77,24 @@ def _process_child_comments(provider, context):

def _process_recommendations(provider, context):
context.set_content(content.VIDEOS)
json_data = provider.get_client(context).get_activities(
channel_id='home', page_token=context.get_param('page_token', '')
params = context.get_params()
function_cache = context.get_function_cache()

json_data = function_cache.get(
provider.get_client(context).get_recommended_for_home,
function_cache.ONE_HOUR,
visitor=params.get('visitor', ''),
page_token=params.get('page_token', ''),
click_tracking=params.get('click_tracking', ''),
)
if not json_data:
return False
return v3.response_to_items(provider, context, json_data)


def _process_popular_right_now(provider, context):
def _process_trending(provider, context):
context.set_content(content.VIDEOS)
json_data = provider.get_client(context).get_popular_videos(
json_data = provider.get_client(context).get_trending_videos(
page_token=context.get_param('page_token', '')
)
if not json_data:
Expand Down Expand Up @@ -295,9 +307,9 @@ def process(category, provider, context):

if category == 'related_videos':
return _process_related_videos(provider, context)
if category == 'popular_right_now':
return _process_popular_right_now(provider, context)
if category == 'recommendations':
if category == 'trending':
return _process_trending(provider, context)
if category == 'recommended':
return _process_recommendations(provider, context)
if category == 'browse_channels':
return _process_browse_channels(provider, context)
Expand Down
Loading

0 comments on commit 75488c3

Please sign in to comment.