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.0+beta.5 #908

Merged
merged 7 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion addon.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.youtube" name="YouTube" version="7.1.0+beta.4" provider-name="anxdpanic, bromix, MoojMidge">
<addon id="plugin.video.youtube" name="YouTube" version="7.1.0+beta.5" provider-name="anxdpanic, bromix, MoojMidge">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.requests" version="2.27.1"/>
Expand Down
12 changes: 12 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## v7.1.0+beta.5
### Fixed
- Fix default thumbnails not being updated if available

### Changed
- Remove revoked API credentials
- Improve handling of "forbidden - The caller does not have permission" errors

### New
- Preliminary support for /watch_videos YouTube urls
- Player client updates

## v7.1.0+beta.4
### Fixed
- Fix playback history related context menu items not being shown #904
Expand Down
10 changes: 5 additions & 5 deletions resources/lib/youtube_plugin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@

key_sets = {
'youtube-tv': {
'client_id': 'ODYxNTU2NzA4NDU0LWQ2ZGxtM2xoMDVpZGQ4bnBlazE4azZiZThiYTNvYzY4',
'api_key': 'QUl6YVN5QzZmdlpTSkhBN1Z6NWo4akNpS1J0N3RVSU9xakUyTjNn',
'client_secret': 'U2JvVmhvRzlzMHJOYWZpeENTR0dLWEFU'
'api_key': '',
'client_id': '',
'client_secret': '',
},
'provided': {
'0': {
'client_id': '',
'api_key': '',
'client_secret': ''
'client_id': '',
'client_secret': '',
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class AbstractContext(object):
'channel_ids',
'item_filter',
'playlist_ids',
'video_ids',
}
_STRING_PARAMS = {
'api_key',
Expand Down
15 changes: 13 additions & 2 deletions resources/lib/youtube_plugin/kodion/plugin/xbmc/xbmc_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
)
from ...exceptions import KodionException
from ...items import (
CommandItem,
directory_listitem,
image_listitem,
media_listitem,
Expand Down Expand Up @@ -179,10 +180,20 @@ def run(self, provider, context, focused=None):
))
ui.on_ok('Error in ContentProvider', exc.__str__())

items = None
items = isinstance(result, (list, tuple))
item_count = 0
if items:
if not result:
result = [
CommandItem(
context.localize('page.back'),
'Action(ParentDir)',
context,
image='DefaultFolderBack.png',
plot=context.localize('page.empty'),
)
]

if result and isinstance(result, (list, tuple)):
show_fanart = settings.fanart_selection()
items = [
self._LIST_ITEM_MAP[item.__class__.__name__](
Expand Down
33 changes: 31 additions & 2 deletions resources/lib/youtube_plugin/youtube/client/request_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class YouTubeRequestClient(BaseRequestsClass):
},
},
'thirdParty': {
'embedUrl': 'https://www.youtube.com/embed/{json[videoId]}',
'embedUrl': 'https://www.youtube.com/',
},
},
'headers': {
Expand Down Expand Up @@ -129,6 +129,9 @@ class YouTubeRequestClient(BaseRequestsClass):
'platform': 'MOBILE',
},
},
'thirdParty': {
'embedUrl': 'https://www.google.com/',
},
},
'headers': {
'User-Agent': ('com.google.android.apps.youtube.unplugged/'
Expand All @@ -139,6 +142,32 @@ class YouTubeRequestClient(BaseRequestsClass):
'X-YouTube-Client-Version': '{json[context][client][clientVersion]}',
},
},
'android_vr': {
'_id': 28,
'_query_subtitles': False,
'json': {
'context': {
'client': {
'clientName': 'ANDROID_VR',
'clientVersion': '1.57.29',
'deviceMake': 'Oculus',
'deviceModel': 'Quest 3',
'osName': 'Android',
'osVersion': '12L',
'androidSdkVersion': '32'
}
}
},
'header': {
'User-Agent': ('com.google.android.apps.youtube.vr.oculus/'
'{json[context][client][clientVersion]}'
' (Linux; U; {json[context][client][osName]}'
' {json[context][client][osVersion]};'
' eureka-user Build/SQ3A.220605.009.A1) gzip'),
'X-YouTube-Client-Name': '{_id}',
'X-YouTube-Client-Version': '{json[context][client][clientVersion]}',
},
},
'ios': {
'_id': 5,
'_os': {
Expand Down Expand Up @@ -197,7 +226,7 @@ class YouTubeRequestClient(BaseRequestsClass):
},
},
'thirdParty': {
'embedUrl': 'https://www.youtube.com',
'embedUrl': 'https://www.google.com/',
},
},
# Headers from a 2022 Samsung Tizen 6.5 based Smart TV
Expand Down
2 changes: 1 addition & 1 deletion resources/lib/youtube_plugin/youtube/client/youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -1982,7 +1982,7 @@ def _error_hook(self, **kwargs):
if getattr(exc, 'notify', True):
ok_dialog = False
timeout = 5000
if reason == 'accessNotConfigured':
if reason in {'accessNotConfigured', 'forbidden'}:
notification = self._context.localize('key.requirement')
ok_dialog = True
elif reason == 'keyInvalid' and message == 'Bad Request':
Expand Down
3 changes: 2 additions & 1 deletion resources/lib/youtube_plugin/youtube/helper/stream_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,8 +711,9 @@ def __init__(self,
),
# Will play most videos with subtitles at full resolution with HDR
# Some restricted videos require additional requests for subtitles
# Limited audio stream availability
# Limited audio stream availability with some clients
'mpd': (
'android_vr',
'android_youtube_tv',
'android_testsuite',
),
Expand Down
11 changes: 11 additions & 0 deletions resources/lib/youtube_plugin/youtube/helper/url_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,17 @@ def resolve(self, url, url_components, method='HEAD'):
})
return url_components._replace(query=urlencode(params)).geturl()

elif path == '/watch_videos':
params = dict(parse_qsl(url_components.query))
new_components = urlsplit(response.url)
new_params = dict(parse_qsl(new_components.query))
# add/overwrite all other params from original query string
new_params.update(params)
# build new URL from these components
return new_components._replace(
query=urlencode(new_params)
).geturl()

# we try to extract the channel id from the html content
# With the channel id we can construct a URL we already work with
# https://www.youtube.com/channel/<CHANNEL_ID>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def add_url(self, url, context):
('v', 'video_id', False),
('live', 'live', False),
('clip', 'clip', False),
('video_ids', 'video_ids', False),
)
if old in url_params
}
Expand All @@ -82,15 +83,26 @@ def add_url(self, url, context):
))
return

if 'video_id' in new_params:
if 'video_ids' in new_params:
for video_id in new_params['video_ids'].split(','):
video_item = VideoItem(
name='',
uri=context.create_uri(
(PATHS.PLAY,),
dict(new_params, video_id=video_id),
)
)
self._video_id_dict[video_id] = video_item

elif 'video_id' in new_params:
video_id = new_params['video_id']

video_item = VideoItem(
'', context.create_uri((PATHS.PLAY,), new_params)
)
self._video_id_dict[video_id] = video_item

elif 'playlist_id' in new_params:
if 'playlist_id' in new_params:
playlist_id = new_params['playlist_id']

if self._flatten:
Expand All @@ -102,7 +114,7 @@ def add_url(self, url, context):
)
self._playlist_id_dict[playlist_id] = playlist_item

elif 'channel_id' in new_params:
if 'channel_id' in new_params:
channel_id = new_params['channel_id']
live = new_params.get('live')

Expand Down
2 changes: 1 addition & 1 deletion resources/lib/youtube_plugin/youtube/helper/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ def update_video_infos(provider, context, video_id_dict,

# try to find a better resolution for the image
image = media_item.get_image()
if not image:
if not image or image.startswith('Default'):
image = get_thumbnail(thumb_size, snippet.get('thumbnails'))
if image.endswith('_live.jpg'):
image = ''.join((image, '?ct=', thumb_stamp))
Expand Down
14 changes: 4 additions & 10 deletions resources/lib/youtube_plugin/youtube/helper/v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,7 @@ def _process_list_response(provider, context, json_data, item_filter):
yt_items = json_data.get('items', [])
if not yt_items:
context.log_warning('v3 response: Items list is empty')
return [
CommandItem(
context.localize('page.back'),
'Action(ParentDir)',
context,
image='DefaultFolderBack.png',
plot=context.localize('page.empty'),
)
]
return []

video_id_dict = {}
channel_id_dict = {}
Expand Down Expand Up @@ -455,6 +447,8 @@ def response_to_items(provider,
result = _process_list_response(
provider, context, json_data, item_filter
)
if not result:
return result
else:
raise KodionException('Unknown kind: %s' % kind)

Expand All @@ -465,7 +459,7 @@ def response_to_items(provider,
result.sort(key=sort, reverse=reverse)

# no processing of next page item
if not result or not process_next_page or params.get('hide_next_page'):
if not process_next_page or params.get('hide_next_page'):
return result

# next page
Expand Down
Loading