Skip to content

Commit

Permalink
Merge pull request #740 from MoojMidge/master
Browse files Browse the repository at this point in the history
v7.0.7+beta.1
  • Loading branch information
MoojMidge authored May 10, 2024
2 parents a820606 + 7e20b40 commit 0faec8b
Show file tree
Hide file tree
Showing 51 changed files with 1,644 additions and 1,051 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.0.6.3" provider-name="anxdpanic, bromix, MoojMidge">
<addon id="plugin.video.youtube" name="YouTube" version="7.0.7+beta.1" 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
38 changes: 38 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
## v7.0.7+beta.1
### Fixed
- Fixed not being able to re-refresh a directory listing that has already been refreshed
- Fixed various window and history nagivation issues
- Fixed http server idle shutdown not restarting if plugin is run but GUI is still idle
- Additional improvements to busy dialog crash workaround
- Workaround for new settings interface not updated correctly
- Fix bookmarks icon background colour
- Fix adding channel items directly to bookmarks
- Fixes for player monitoring preventing item being marked as watched #746

### Changed
- Removed Settings > Advanced > Views > Show channel fanart
- Now included as option in Settings > Advanced > Views > Show fanart
- MPEG-DASH for live streams only enabled by default in Kodi v21
- Make better use of reuselanguageinvoker and various memory usage improvements

### New
- Improvements to plugin page navigation #715
- Refresh added to context menu of Next page item
- Jump to page added to context menu of Next page item
- Can also be used in plugin url: plugin://plugin.video.youtube/goto_page/<PAGE>/<PATH> #317
- Home added to context menu of Next page item
- Quick search added to context menu of Next page item
- Next page item added to last page of directory list to go back to first page
- Add option to use channel name as studio and/or cast #717
- Settings > Advanced > Views > Use channel name as
- Add option to use best available thumbnail quality
- Settings > Advanced > Views > Thumbnail size
- Added option to use video thumbnail as fanart in Settings > Advanced > Views > Show fanart #716
- Also added plugin url query parameter fanart_type to override settings
- Can be used to set fanart for specific widgets only: plugin://plugin.video.youtube/<PATH>?fanart_type=<0/1/2/3>
- Allowable values are the same as the setting:
- 0: No fanart
- 1: Default
- 2: Channel
- 3: Thumbnail

## v7.0.6.3
### Fixed
- Improve updating containers and (re)loading windows #681
Expand Down
10 changes: 9 additions & 1 deletion resources/language/resource.language.en_gb/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ msgid "Go to %s"
msgstr ""

msgctxt "#30503"
msgid "Show channel fanart"
msgid "Channel fanart"
msgstr ""

msgctxt "#30504"
Expand Down Expand Up @@ -1528,3 +1528,11 @@ msgstr ""
msgctxt "#30805"
msgid "Use adaptive streaming formats with external player"
msgstr ""

msgctxt "#30806"
msgid "Jump to page..."
msgstr ""

msgctxt "#30807"
msgid "Use channel name as"
msgstr ""
3 changes: 1 addition & 2 deletions resources/lib/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

from __future__ import absolute_import, division, unicode_literals

from youtube_plugin import youtube
from youtube_plugin.kodion import plugin_runner


plugin_runner.run(youtube.Provider())
plugin_runner.run()
9 changes: 5 additions & 4 deletions resources/lib/youtube_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,10 @@ def reset_access_tokens(addon_id):
"""
if not addon_id or addon_id == ADDON_ID:
context = XbmcContext()
context.log_error('Developer reset access tokens: |%s| Invalid addon_id' % addon_id)
context.log_error('Reset addon access tokens - invalid addon_id: |{0}|'
.format(addon_id))
return
context = XbmcContext(params={'addon_id': addon_id})

access_manager = context.get_access_manager()
access_manager.update_dev_access_token(addon_id, access_token='', refresh_token='')
context.get_access_manager().update_dev_access_token(
addon_id, access_token='', refresh_token=''
)
12 changes: 6 additions & 6 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': {
'id': 'ODYxNTU2NzA4NDU0LWQ2ZGxtM2xoMDVpZGQ4bnBlazE4azZiZThiYTNvYzY4',
'key': 'QUl6YVN5QzZmdlpTSkhBN1Z6NWo4akNpS1J0N3RVSU9xakUyTjNn',
'secret': 'U2JvVmhvRzlzMHJOYWZpeENTR0dLWEFU'
'client_id': 'ODYxNTU2NzA4NDU0LWQ2ZGxtM2xoMDVpZGQ4bnBlazE4azZiZThiYTNvYzY4',
'api_key': 'QUl6YVN5QzZmdlpTSkhBN1Z6NWo4akNpS1J0N3RVSU9xakUyTjNn',
'client_secret': 'U2JvVmhvRzlzMHJOYWZpeENTR0dLWEFU'
},
'provided': {
'0': {
'id': '',
'key': '',
'secret': ''
'client_id': '',
'api_key': '',
'client_secret': ''
}
}
}
Expand Down
163 changes: 117 additions & 46 deletions resources/lib/youtube_plugin/kodion/abstract_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@

import re

from .constants import content, paths
from .constants import CHECK_SETTINGS, REROUTE, content, paths
from .exceptions import KodionException
from .items import (
DirectoryItem,
NewSearchItem,
NextPageItem,
SearchHistoryItem,
menu_items,
)
from .utils import to_unicode

Expand All @@ -32,61 +32,81 @@ def __init__(self):
self._dict_path = {}

# register some default paths
self.register_path(r'^/$', '_internal_root')
self.register_path(r''.join((
'^',
'(?:', paths.HOME, ')?/?$'
)), self._internal_root)

self.register_path(r''.join((
'^',
paths.ROUTE,
'(?P<path>/[^?]+?)(?:/*[?].+|/*)$'
)), self.reroute)

self.register_path(r''.join((
'^',
paths.GOTO_PAGE,
'(?P<page>/[0-9]+)?'
'(?P<path>/[^?]+?)(?:/*[?].+|/*)$'
)), self._internal_goto_page)

self.register_path(r''.join((
'^',
paths.WATCH_LATER,
'/(?P<command>add|clear|list|remove)/?$'
)), 'on_watch_later')
)), self.on_watch_later)

self.register_path(r''.join((
'^',
paths.BOOKMARKS,
'/(?P<command>add|clear|list|remove)/?$'
)), 'on_bookmarks')
)), self.on_bookmarks)

self.register_path(r''.join((
'^',
'(', paths.SEARCH, '|', paths.EXTERNAL_SEARCH, ')',
'/(?P<command>input|query|list|remove|clear|rename)?/?$'
)), '_internal_search')
)), self._internal_search)

self.register_path(r''.join((
'^',
paths.HISTORY,
'/?$'
)), 'on_playback_history')
)), self.on_playback_history)

self.register_path(r'(?P<path>.*\/)extrafanart\/([\?#].+)?$',
'_internal_on_extra_fanart')
self._internal_on_extra_fanart)

"""
Test each method of this class for the appended attribute '_re_match' by the
decorator (RegisterProviderPath).
The '_re_match' attributes describes the path which must match for the decorated method.
Test each method of this class for the attribute 'kodion_re_path' added
by the decorator @RegisterProviderPath.
The 'kodion_re_path' attribute is a regular expression that must match
the current path in order for the decorated method to run.
"""

for method_name in dir(self):
method = getattr(self, method_name, None)
path = method and getattr(method, 'kodion_re_path', None)
if path:
self.register_path(path, method_name)

def register_path(self, re_path, method_name):
for attribute_name in dir(self):
if attribute_name.startswith('__'):
continue
attribute = getattr(self, attribute_name, None)
if not attribute or not callable(attribute):
continue
re_path = getattr(attribute, 'kodion_re_path', None)
if re_path:
self.register_path(re_path, attribute)

def register_path(self, re_path, method):
"""
Registers a new method by name (string) for the given regular expression
Registers a new method for the given regular expression
:param re_path: regular expression of the path
:param method_name: name of the method
:param method: method to be registered
:return:
"""
self._dict_path[re_path] = method_name
self._dict_path[re.compile(re_path, re.UNICODE)] = method

def run_wizard(self, context):
settings = context.get_settings()
ui = context.get_ui()

context.send_notification('check_settings', 'defer')
context.send_notification(CHECK_SETTINGS, 'defer')

wizard_steps = self.get_wizard_steps(context)

Expand All @@ -105,34 +125,34 @@ def run_wizard(self, context):
else:
step += 1
finally:
settings.set_bool(settings.SETUP_WIZARD, False)
context.send_notification('check_settings', 'process')
settings.setup_wizard_enabled(False)
context.send_notification(CHECK_SETTINGS, 'process')

def get_wizard_steps(self, context):
# can be overridden by the derived class
return []

def navigate(self, context):
path = context.get_path()
for re_path, method in self._dict_path.items():
re_match = re_path.search(path)
if not re_match:
continue

result = method(context, re_match)
if isinstance(result, tuple):
result, options = result
else:
options = {
self.RESULT_CACHE_TO_DISC: True,
self.RESULT_UPDATE_LISTING: False,
}

for key in self._dict_path:
re_match = re.search(key, path, re.UNICODE)
if re_match is not None:
method_name = self._dict_path.get(key, '')
method = getattr(self, method_name, None)
if method is not None:
result = method(context, re_match)
refresh = context.get_param('refresh', False)
if not isinstance(result, tuple):
options = {
self.RESULT_CACHE_TO_DISC: True,
self.RESULT_UPDATE_LISTING: refresh,
}
else:
result, options = result
if refresh:
options[self.RESULT_UPDATE_LISTING] = refresh
return result, options
refresh = context.get_param('refresh')
if refresh is not None:
options[self.RESULT_UPDATE_LISTING] = bool(refresh)

return result, options

raise KodionException("Mapping for path '%s' not found" % path)

Expand Down Expand Up @@ -164,6 +184,56 @@ def on_root(self, context, re_match):
def _internal_root(self, context, re_match):
return self.on_root(context, re_match)

def _internal_goto_page(self, context, re_match):
page = re_match.group('page')
if page:
page = int(page.lstrip('/'))
else:
result, page = context.get_ui().on_numeric_input(
context.localize('page.choose'), 1
)
if not result:
return False

path = re_match.group('path')
params = context.get_params()
page_token = NextPageItem.create_page_token(
page, params.get('items_per_page', 50)
)
params = dict(params, page=page, page_token=page_token)
return self.reroute(context, path=path, params=params)

def reroute(self, context, re_match=None, path=None, params=None):
current_path = context.get_path()
current_params = context.get_params()
if re_match:
path = re_match.group('path')
if params is None:
params = current_params
if (path and path != current_path
or 'refresh' in params
or params != current_params):
result = None
function_cache = context.get_function_cache()
window_return = params.pop('window_return', True)
try:
result, options = function_cache.run(
self.navigate,
seconds=None,
_cacheparams=function_cache.PARAMS_NONE,
_refresh=True,
context=context.clone(path, params),
)
finally:
if not result:
return False
context.get_ui().set_property(REROUTE, path)
context.execute('ActivateWindow(Videos, {0}{1})'.format(
context.create_uri(path, params),
', return' if window_return else '',
))
return False

def on_bookmarks(self, context, re_match):
raise NotImplementedError()

Expand Down Expand Up @@ -211,8 +281,9 @@ def _internal_search(self, context, re_match):
query = None
# came from page 1 of search query by '..'/back
# user doesn't want to input on this path
if (folder_path.startswith('plugin://%s' % context.get_id()) and
re.match('.+/(?:query|input)/.*', folder_path)):
if (not params.get('refresh')
and folder_path.startswith('plugin://%s' % context.get_id())
and re.match('.+/(?:query|input)/.*', folder_path)):
cached = data_cache.get_item('search_query', data_cache.ONE_DAY)
if cached:
query = to_unicode(cached)
Expand Down Expand Up @@ -260,7 +331,7 @@ def _internal_search(self, context, re_match):
def handle_exception(self, context, exception_to_handle):
return True

def tear_down(self, context):
def tear_down(self):
pass


Expand Down
Loading

0 comments on commit 0faec8b

Please sign in to comment.