Skip to content

Commit

Permalink
Merge pull request #917 from MoojMidge/master
Browse files Browse the repository at this point in the history
v7.1.0
  • Loading branch information
MoojMidge authored Oct 2, 2024
2 parents 0497eda + 7a456f5 commit 28dd118
Show file tree
Hide file tree
Showing 15 changed files with 229 additions and 110 deletions.
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.5" provider-name="anxdpanic, bromix, MoojMidge">
<addon id="plugin.video.youtube" name="YouTube" version="7.1.0" 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
60 changes: 58 additions & 2 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,66 @@
## v7.1.0
### Fixed
- Fix logging/retry of sqlite3.OperationalError
- Fix trying to use ISA for progressive live streams
- Retain list position when refreshing listings
- Add workarounds for trying to play videos using RunPlugin rather PlayMedia
- Fix possible regression causing 6s delay on first play
- Fix regression in building client details causing wrong referer to be used
- Only reroute to new window if container was not filled by the plugin #896
- Only reroute to new window if modal dialog is not open #896
- Fix various timing and sync issues with script, service, plugin and Kodi settings
- Fix playback history related context menu items not being shown #904
- Fix new resume details not being saved in plugin local playback history #904
- Fix default thumbnails not being updated if available
- Fix login to personal project only #910

### Changed
- Update multiple busy dialog crash workaround #891
- Use all playable codecs but deprioritise if not selected in stream features
- Change default live stream type to suit ISA and Youtube stream availability
- Use a CommandItem that opens the Info dialog for comments to avoid log spam
- Revert old workaround for Kodi treating a non-folder listitem as playable
- Improve parsing of plugin url query parameters to allow empty values
- Move IP location lookup to script and add to settings dialog
- Move language and region selection to script and add to settings dialog
- Allow default thumbnail selection fallbacks for all results
- Simplify handling of local history
- Incognito will no longer prevent existing local history from being shown
- Incognito will continue to prevent any update to local history
- Remove revoked API credentials #905
- Improve handling of "forbidden - The caller does not have permission" errors #905
- Allow retries on POST requests #913

### New
- Allow ask for quality from context menu to override audio only setting
- Add items_per_page query parameter to allow number of items in widgets to be customised #896
- Add item_filter query parameter to override "Hide videos from listings" setting #896
- Comma seperated string of item types to be filtered out of listing
- "?item_filter=shorts" will remove shorts from listing
- "?item_filter=shorts,live" will remove shorts and live streams from listing
- "?item_filter" will show all item types
- Allowable item types:
- shorts
- upcoming
- upcoming_live
- live
- premieres
- completed
- vod
- Add hide_next_page query parameter to hide plugin Next page item #896
- Add new input_prompt command for search endpoint to bypass Kodi window caching
- plugin://plugin.video.youtube/kodion/search/input_prompt
- Add support for proxy settings #884
- Preliminary support for /watch_videos YouTube urls
- Player client updates

## 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
- Remove revoked API credentials #905
- Improve handling of "forbidden - The caller does not have permission" errors #905

### New
- Preliminary support for /watch_videos YouTube urls
Expand Down
4 changes: 2 additions & 2 deletions resources/language/resource.language.en_gb/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -490,11 +490,11 @@ msgid "No further links found."
msgstr ""

msgctxt "#30546"
msgid "Please log in twice!"
msgid "Please complete all login prompts"
msgstr ""

msgctxt "#30547"
msgid "You must enable two applications so that YouTube is functioning properly."
msgid "You may be prompted to enable two applications so that YouTube is functioning properly."
msgstr ""

msgctxt "#30548"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ class XbmcContext(AbstractContext):
'sign.go_to': 30502,
'sign.in': 30111,
'sign.out': 30112,
'sign.twice.text': 30547,
'sign.twice.title': 30546,
'sign.multi.text': 30547,
'sign.multi.title': 30546,
'stats.commentCount': 30732,
# 'stats.favoriteCount': 1036,
'stats.likeCount': 30733,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ def update_access_token(self,

if unix_timestamp is not None:
details['token_expires'] = (
min(map(int, unix_timestamp))
min(map(int, [val for val in unix_timestamp if val]))
if isinstance(unix_timestamp, (list, tuple)) else
int(unix_timestamp)
)
Expand Down
1 change: 1 addition & 0 deletions resources/lib/youtube_plugin/kodion/network/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class BaseRequestsClass(object):
total=3,
backoff_factor=0.1,
status_forcelist={500, 502, 503, 504},
allowed_methods=None,
)
))
atexit.register(_session.close)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
CONTAINER_FOCUS,
CONTAINER_ID,
CONTAINER_POSITION,
CONTENT_TYPE,
PLAYLIST_PATH,
PLAYLIST_POSITION,
PLUGIN_SLEEPING,
Expand Down Expand Up @@ -258,6 +259,7 @@ def run(self, provider, context, focused=None):
cache_to_disc = options.get(provider.RESULT_CACHE_TO_DISC, True)
update_listing = options.get(provider.RESULT_UPDATE_LISTING, False)
else:
ui.clear_property(CONTENT_TYPE)
succeeded = bool(result)
cache_to_disc = False
update_listing = True
Expand Down
3 changes: 2 additions & 1 deletion resources/lib/youtube_plugin/youtube/client/__config__.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ def get_api_keys(self, switch):
key = key.partition('_')[-1]
if key and key in key_set:
key_set[key] = value
if not key_set['id'].endswith('.apps.googleusercontent.com'):
if (key_set['id']
and not key_set['id'].endswith('.apps.googleusercontent.com')):
key_set['id'] += '.apps.googleusercontent.com'
return key_set

Expand Down
51 changes: 32 additions & 19 deletions resources/lib/youtube_plugin/youtube/client/login_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ def _error_hook(**kwargs):
return None, None, None, json_data, False, InvalidGrant(json_data)
return None, None, None, json_data, False, LoginException(json_data)

def set_access_token(self, access_token=''):
self._access_token = access_token

def set_access_token_tv(self, access_token_tv=''):
self._access_token_tv = access_token_tv
def set_access_token(self, personal=None, tv=None):
if personal is not None:
self._access_token = personal
if tv is not None:
self._access_token_tv = tv

def revoke(self, refresh_token):
# https://developers.google.com/youtube/v3/guides/auth/devices
Expand All @@ -107,8 +107,10 @@ def revoke(self, refresh_token):
raise_exc=True)

def refresh_token_tv(self, refresh_token):
client_id = self._config_tv.get('id', '')
client_secret = self._config_tv.get('secret', '')
client_id = self._config_tv.get('id')
client_secret = self._config_tv.get('secret')
if not client_id or not client_secret:
return '', 0
return self.refresh_token(refresh_token,
client_id=client_id,
client_secret=client_secret)
Expand Down Expand Up @@ -151,13 +153,15 @@ def refresh_token(self, refresh_token, client_id='', client_secret=''):

if json_data:
access_token = json_data['access_token']
expires_in = time.time() + int(json_data.get('expires_in', 3600))
return access_token, expires_in
return '', ''
expiry = time.time() + int(json_data.get('expires_in', 3600))
return access_token, expiry
return '', 0

def request_access_token_tv(self, code, client_id='', client_secret=''):
client_id = client_id or self._config_tv.get('id', '')
client_secret = client_secret or self._config_tv.get('secret', '')
client_id = client_id or self._config_tv.get('id')
client_secret = client_secret or self._config_tv.get('secret')
if not client_id or not client_secret:
return '', ''
return self.request_access_token(code,
client_id=client_id,
client_secret=client_secret)
Expand Down Expand Up @@ -200,7 +204,9 @@ def request_access_token(self, code, client_id='', client_secret=''):
return json_data

def request_device_and_user_code_tv(self):
client_id = self._config_tv.get('id', '')
client_id = self._config_tv.get('id')
if not client_id:
return None
return self.request_device_and_user_code(client_id=client_id)

def request_device_and_user_code(self, client_id=''):
Expand Down Expand Up @@ -282,17 +288,24 @@ def authenticate(self, username, password):
def _get_config_type(self, client_id, client_secret=None):
"""used for logging"""
if client_secret is None:
using_conf_tv = client_id == self._config_tv.get('id', '')
using_conf_main = client_id == self._config.get('id', '')
config_id = self._config_tv.get('id')
using_conf_tv = config_id and client_id == config_id
config_id = self._config.get('id')
using_conf_main = config_id and client_id == config_id
else:
config_secret = self._config_tv.get('secret')
config_id = self._config_tv.get('id')
using_conf_tv = (
client_secret == self._config_tv.get('secret', '')
and client_id == self._config_tv.get('id', '')
config_secret and client_secret == config_secret
and config_id and client_id == config_id
)
config_secret = self._config.get('secret')
config_id = self._config.get('id')
using_conf_main = (
client_secret == self._config.get('secret', '')
and client_id == self._config.get('id', '')
config_secret and client_secret == config_secret
and config_id and client_id == config_id
)

if not using_conf_main and not using_conf_tv:
return 'None'
if using_conf_tv:
Expand Down
4 changes: 2 additions & 2 deletions resources/lib/youtube_plugin/youtube/client/request_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,11 @@ class YouTubeRequestClient(BaseRequestsClass):
'deviceModel': 'Quest 3',
'osName': 'Android',
'osVersion': '12L',
'androidSdkVersion': '32'
'androidSdkVersion': '32',
}
}
},
'header': {
'headers': {
'User-Agent': ('com.google.android.apps.youtube.vr.oculus/'
'{json[context][client][clientVersion]}'
' (Linux; U; {json[context][client][osName]}'
Expand Down
72 changes: 44 additions & 28 deletions resources/lib/youtube_plugin/youtube/client/youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class YouTube(LoginClient):
'headers': {
'Host': 'www.googleapis.com',
},
'auth_required': True,
},
'tv': {
'url': 'https://www.youtube.com/youtubei/v1/{_endpoint}',
Expand Down Expand Up @@ -194,7 +195,8 @@ def get_streams(self,
audio_only=False,
use_mpd=True):
return StreamInfo(context,
access_token=self._access_token_tv,
access_token=(self._access_token
or self._access_token_tv),
ask_for_quality=ask_for_quality,
audio_only=audio_only,
use_mpd=use_mpd).load_stream_info(video_id)
Expand Down Expand Up @@ -2032,22 +2034,31 @@ def api_request(self,
if params:
client_data['params'] = params

abort = False
if no_login:
pass
# a config can decide if a token is allowed
if (not no_login and self._access_token
and self._config.get('token-allowed', True)):
elif self._access_token and self._config.get('token-allowed', True):
client_data['_access_token'] = self._access_token
# abort if authentication is required but not available for request
elif self.CLIENTS.get(version, {}).get('auth_required'):
abort = True

client = self.build_client(version, client_data)

params = client.get('params')
if 'key' in params and not params['key']:
params = params.copy()
key = self._config.get('key') or self._config_tv.get('key')
if key:
params['key'] = key
if 'key' in params:
if params['key']:
abort = False
else:
del params['key']
client['params'] = params
params = params.copy()
key = self._config.get('key') or self._config_tv.get('key')
if key:
abort = False
params['key'] = key
else:
del params['key']
client['params'] = params

if clear_data and 'json' in client:
del client['json']
Expand All @@ -2070,21 +2081,26 @@ def api_request(self,
else:
log_headers = None

self._context.log_debug('API request:\n'
'version: |{version}|\n'
'method: |{method}|\n'
'path: |{path}|\n'
'params: |{params}|\n'
'post_data: |{data}|\n'
'headers: |{headers}|'
.format(version=version,
method=method,
path=path,
params=log_params,
data=client.get('json'),
headers=log_headers))
response = self.request(response_hook=self._response_hook,
response_hook_kwargs=kwargs,
error_hook=self._error_hook,
**client)
return response
context = self._context
context.log_debug('API request:\n'
'version: |{version}|\n'
'method: |{method}|\n'
'path: |{path}|\n'
'params: |{params}|\n'
'post_data: |{data}|\n'
'headers: |{headers}|'
.format(version=version,
method=method,
path=path,
params=log_params,
data=client.get('json'),
headers=log_headers))
if abort:
if kwargs.get('notify', True):
context.get_ui().on_ok(context.get_name(), context.localize('key.requirement'))
context.log_warning('API request: aborted')
return {}
return self.request(response_hook=self._response_hook,
response_hook_kwargs=kwargs,
error_hook=self._error_hook,
**client)
2 changes: 1 addition & 1 deletion resources/lib/youtube_plugin/youtube/helper/stream_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -1408,7 +1408,7 @@ def load_stream_info(self, video_id):
'auth': bool(_client.get('_access_token')),
},
**_client
)
) or {}

video_details = _result.get('videoDetails', {})
playability = _result.get('playabilityStatus', {})
Expand Down
Loading

0 comments on commit 28dd118

Please sign in to comment.