Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v7.1.1+beta.4 #955

Merged
merged 12 commits into from
Nov 2, 2024
Prev Previous commit
Next Next commit
Add new YouTube.search_with_params method
- Allow search parameters to be stored per search #172 #689
- Allow additional optional search parameters to be used #689
MoojMidge committed Nov 2, 2024
commit 467d46f97a6debe7682d7cd30c47fb8b4794ca3e
34 changes: 34 additions & 0 deletions resources/lib/youtube_plugin/kodion/context/abstract_context.py
Original file line number Diff line number Diff line change
@@ -120,6 +120,33 @@ class AbstractContext(Logger):
_STRING_BOOL_PARAMS = {
'reload_path',
}
_SEARCH_PARAMS = {
'forMine',
'channelId',
'channelType',
'eventType',
'location',
'locationRadius',
'maxResults',
'order',
'pageToken'
'publishedAfter',
'publishedBefore',
'q',
'safeSearch',
'topicId',
'type',
'videoCaption',
'videoCategoryId',
'videoDefinition',
'videoDimension',
'videoDuration',
'videoEmbeddable',
'videoLicense',
'videoPaidProductPlacement',
'videoSyndicated',
'videoType',
}

def __init__(self, path='/', params=None, plugin_id=''):
self._access_manager = None
@@ -355,6 +382,13 @@ def parse_params(self, params, update=True):
elif params == 'playlist':
to_delete.append(param)
param = 'playlist_id'
elif param in self._SEARCH_PARAMS:
parsed_value = to_str(value)
parsed_value = VALUE_FROM_STR.get(
parsed_value, parsed_value
)
if not parsed_value:
raise ValueError
else:
self.log_debug('Unknown parameter - |{0}: {1!r}|'.format(
param, value
Original file line number Diff line number Diff line change
@@ -20,7 +20,11 @@ def __init__(self, context, query, image=None, fanart=None, location=False):
if image is None:
image = '{media}/search.png'

params = {'q': query}
if isinstance(query, dict):
params = query
query = params['q']
else:
params = {'q': query}
if location:
params['location'] = location

28 changes: 20 additions & 8 deletions resources/lib/youtube_plugin/kodion/sql_store/search_history.py
Original file line number Diff line number Diff line change
@@ -35,11 +35,23 @@ def get_items(self, process=None):
def _make_id(search_text):
return md5(search_text.encode('utf-8')).hexdigest()

def add_item(self, search_text):
self._set(self._make_id(search_text), search_text)

def del_item(self, search_text):
self._remove(self._make_id(search_text))

def update_item(self, search_text, timestamp=None):
self._update(self._make_id(search_text), search_text, timestamp)
def add_item(self, query):
if isinstance(query, dict):
params = query
query = params['q']
else:
params = {'q': query}
self._set(self._make_id(query), params)

def del_item(self, query):
if isinstance(query, dict):
query = query['q']
self._remove(self._make_id(query))

def update_item(self, query, timestamp=None):
if isinstance(query, dict):
params = query
query = params['q']
else:
params = {'q': query}
self._update(self._make_id(query), params, timestamp)
86 changes: 86 additions & 0 deletions resources/lib/youtube_plugin/youtube/client/youtube.py
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@

from __future__ import absolute_import, division, unicode_literals

import json
import threading
import xml.etree.ElementTree as ET
from functools import partial
@@ -1392,6 +1393,91 @@ def search(self,
params=params,
**kwargs)

def search_with_params(self, params, **kwargs):
settings = self._context.get_settings()

# prepare default params
search_params = {
'part': 'snippet',
'regionCode': self._region,
'hl': self._language,
'relevanceLanguage': self._language,
'maxResults': str(self.max_results()),
}

search_query = params.get('q')
if '|' in search_query:
search_params['q'] = search_query.replace('|', '%7C')

search_type = params.get('type')
if isinstance(search_type, (list, tuple)):
search_params['type'] = ','.join(search_type)

location = params.get('location')
if location is True:
location = settings.get_location()
if location:
search_params['location'] = location
search_params['locationRadius'] = settings.get_location_radius()

if 'safeSearch' not in params:
search_params['safeSearch'] = settings.safe_search()

published = params.get('publishedBefore')
if published:
if isinstance(published, string_type) and published.startswith('{'):
published = json.loads(published)
search_params['publishedBefore'] = (
datetime_parser.yt_datetime_offset(**published)
if isinstance(published, dict) else
published
)

published = params.get('publishedAfter')
if published:
if isinstance(published, string_type) and published.startswith('{'):
published = json.loads(published)
search_params['publishedAfter'] = (
datetime_parser.yt_datetime_offset(**published)
if isinstance(published, dict) else
published
)

params_to_delete = []
for param, value in params.items():
if value:
if param not in search_params:
search_params[param] = value
else:
params_to_delete.append(param)

for param in params_to_delete:
del params[param]

video_only_params = {
'eventType',
'forMine'
'location',
'relatedToVideoId',
'videoCaption',
'videoCategoryId',
'videoDefinition',
'videoDimension',
'videoDuration',
'videoEmbeddable',
'videoLicense',
'videoSyndicated',
'videoType',
}
if not video_only_params.isdisjoint(search_params.keys()):
search_params['type'] = 'video'

return (params,
self.api_request(method='GET',
path='search',
params=search_params,
**kwargs))

def get_my_subscriptions(self,
page_token=1,
logged_in=False,
11 changes: 6 additions & 5 deletions resources/lib/youtube_plugin/youtube/helper/yt_play.py
Original file line number Diff line number Diff line change
@@ -282,11 +282,12 @@ def _play_channel_live(provider, context):
index = context.get_param('live', 1) - 1
if index < 0:
index = 0
json_data = provider.get_client(context).search(q='',
search_type='video',
event_type='live',
channel_id=channel_id,
safe_search=False)
_, json_data = provider.get_client(context).search_with_params(params={
'type': 'video',
'eventType': 'live',
'channelId': channel_id,
'safeSearch': 'none',
})
if not json_data:
return False

30 changes: 18 additions & 12 deletions resources/lib/youtube_plugin/youtube/provider.py
Original file line number Diff line number Diff line change
@@ -864,25 +864,31 @@ def on_search_run(self, context, search_text):
)
result.append(live_item)

search_params = {
'q': search_text,
'order': order,
'channelId': channel_id,
'type': search_type,
'eventType': event_type,
'safeSearch': safe_search,
'pageToken': page_token,
'location': location,
}

function_cache = context.get_function_cache()
json_data = function_cache.run(self.get_client(context).search,
function_cache.ONE_MINUTE * 10,
_refresh=params.get('refresh'),
q=search_text,
search_type=search_type,
event_type=event_type,
safe_search=safe_search,
page_token=page_token,
channel_id=channel_id,
order=order,
location=location)
search_params, json_data = function_cache.run(
self.get_client(context).search_with_params,
function_cache.ONE_MINUTE * 10,
_refresh=params.get('refresh'),
params=search_params,
)
if not json_data:
return False

# Store current search query for Kodi window history navigation
if not params.get('incognito'):
if not params.get('channel_id'):
context.get_search_history().add_item(search_text)
context.get_search_history().add_item(search_params)
data_cache.set_item('search_query', search_text)

result.extend(v3.response_to_items(