diff --git a/addon.xml b/addon.xml
index 61c0caac..c9876322 100644
--- a/addon.xml
+++ b/addon.xml
@@ -99,3 +99,4 @@
此附加元件未由Google支持
+
diff --git a/resources/lib/youtube_plugin/kodion/abstract_provider.py b/resources/lib/youtube_plugin/kodion/abstract_provider.py
index 7069da60..f49e2e27 100644
--- a/resources/lib/youtube_plugin/kodion/abstract_provider.py
+++ b/resources/lib/youtube_plugin/kodion/abstract_provider.py
@@ -73,10 +73,29 @@ class AbstractProvider(object):
self._dict_path[re_path] = method_name
def _process_wizard(self, context):
+ def _setup_views(_context, _view):
+ view_manager = utils.ViewManager(_context)
+ if not view_manager.update_view_mode(_context.localize(self._local_map['kodion.wizard.view.%s' % _view]),
+ _view):
+ return
+
+ _context.get_settings().set_bool(constants.setting.VIEW_OVERRIDE, True)
+
# start the setup wizard
wizard_steps = []
if context.get_settings().is_setup_wizard_enabled():
context.get_settings().set_bool(constants.setting.SETUP_WIZARD, False)
+ if utils.ViewManager(context).has_supported_views():
+ views = self.get_wizard_supported_views()
+ for view in views:
+ if view in utils.ViewManager.SUPPORTED_VIEWS:
+ wizard_steps.append((_setup_views, [context, view]))
+ else:
+ context.log_warning('[Setup-Wizard] Unsupported view "%s"' % view)
+ else:
+ skin_id = context.get_ui().get_skin_id()
+ context.log("ViewManager: Unknown skin id '%s'" % skin_id)
+
wizard_steps.extend(self.get_wizard_steps(context))
if wizard_steps and context.get_ui().on_yes_no_input(context.get_name(),
@@ -279,7 +298,7 @@ class AbstractProvider(object):
query = query.decode('utf-8')
return self.on_search(query, context, re_match)
else:
- context.set_content_type(constants.content_type.FILES)
+ context.set_content_type(constants.content_type.VIDEOS)
result = []
location = str(context.get_param('location', False)).lower() == 'true'
diff --git a/resources/lib/youtube_plugin/kodion/constants/const_settings.py b/resources/lib/youtube_plugin/kodion/constants/const_settings.py
index ead2715e..129ffb5b 100644
--- a/resources/lib/youtube_plugin/kodion/constants/const_settings.py
+++ b/resources/lib/youtube_plugin/kodion/constants/const_settings.py
@@ -35,6 +35,10 @@ HIDE_SHORT_VIDEOS = 'youtube.hide_shorts' # (bool)
SUPPORT_ALTERNATIVE_PLAYER = 'kodion.support.alternative_player' # (bool)
ALTERNATIVE_PLAYER_WEB_URLS = 'kodion.alternative_player.web.urls' # (bool)
+VIEW_OVERRIDE = 'kodion.view.override' # (bool)
+VIEW_DEFAULT = 'kodion.view.default' # (int)
+VIEW_X = 'kodion.view.%s' # (int)
+
ALLOW_DEV_KEYS = 'youtube.allow.dev.keys' # (bool)
DASH_VIDEOS = 'kodion.mpd.videos' # (bool)
diff --git a/resources/lib/youtube_plugin/kodion/impl/abstract_context_ui.py b/resources/lib/youtube_plugin/kodion/impl/abstract_context_ui.py
index 7ed3feff..46eabf26 100644
--- a/resources/lib/youtube_plugin/kodion/impl/abstract_context_ui.py
+++ b/resources/lib/youtube_plugin/kodion/impl/abstract_context_ui.py
@@ -16,6 +16,12 @@ class AbstractContextUI(object):
def create_progress_dialog(self, heading, text=None, background=False):
raise NotImplementedError()
+ def set_view_mode(self, view_mode):
+ raise NotImplementedError()
+
+ def get_view_mode(self):
+ raise NotImplementedError()
+
def get_skin_id(self):
raise NotImplementedError()
diff --git a/resources/lib/youtube_plugin/kodion/impl/abstract_settings.py b/resources/lib/youtube_plugin/kodion/impl/abstract_settings.py
index 6a2e2887..ff5764c1 100644
--- a/resources/lib/youtube_plugin/kodion/impl/abstract_settings.py
+++ b/resources/lib/youtube_plugin/kodion/impl/abstract_settings.py
@@ -90,6 +90,9 @@ class AbstractSettings(object):
def is_setup_wizard_enabled(self):
return self.get_bool(constants.setting.SETUP_WIZARD, False)
+ def is_override_view_enabled(self):
+ return self.get_bool(constants.setting.VIEW_OVERRIDE, False)
+
def is_support_alternative_player_enabled(self):
return self.get_bool(constants.setting.SUPPORT_ALTERNATIVE_PLAYER, False)
diff --git a/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_context.py b/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_context.py
index dd000aa9..a7c74b9a 100644
--- a/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_context.py
+++ b/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_context.py
@@ -208,6 +208,7 @@ class XbmcContext(AbstractContext):
def set_content_type(self, content_type):
self.log_debug('Setting content-type: "%s" for "%s"' % (content_type, self.get_path()))
xbmcplugin.setContent(self._plugin_handle, content_type)
+ self.get_ui().set_view_mode(content_type)
def add_sort_method(self, *sort_methods):
for sort_method in sort_methods:
diff --git a/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_context_ui.py b/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_context_ui.py
index 49c95074..6aece7b9 100644
--- a/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_context_ui.py
+++ b/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_context_ui.py
@@ -9,6 +9,7 @@
"""
from six import PY3
+from six import string_types
import xbmc
import xbmcgui
@@ -35,6 +36,18 @@ class XbmcContextUI(AbstractContextUI):
return XbmcProgressDialog(heading, text)
+ def set_view_mode(self, view_mode):
+ if isinstance(view_mode, string_types):
+ view_mode = self._context.get_settings().get_int(constants.setting.VIEW_X % view_mode, self._context.get_settings().get_int(constants.setting.VIEW_DEFAULT, 50))
+
+ self._view_mode = view_mode
+
+ def get_view_mode(self):
+ if self._view_mode is not None:
+ return self._view_mode
+
+ return self._context.get_settings().get_int(constants.setting.VIEW_DEFAULT, 50)
+
def get_skin_id(self):
return xbmc.getSkinDir()
diff --git a/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_runner.py b/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_runner.py
index 9f69f4c1..7f42560a 100644
--- a/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_runner.py
+++ b/resources/lib/youtube_plugin/kodion/impl/xbmc/xbmc_runner.py
@@ -8,6 +8,7 @@
See LICENSES/GPL-2.0-only for more information.
"""
+import xbmc
import xbmcgui
import xbmcplugin
@@ -66,6 +67,13 @@ class XbmcRunner(AbstractProviderRunner):
self.handle, succeeded=True,
updateListing=options.get(AbstractProvider.RESULT_UPDATE_LISTING, False),
cacheToDisc=options.get(AbstractProvider.RESULT_CACHE_TO_DISC, True))
+
+ # set alternative view mode
+ if context.get_settings().is_override_view_enabled():
+ view_mode = context.get_ui().get_view_mode()
+ if view_mode is not None:
+ context.log_debug('Override view mode to "%d"' % view_mode)
+ xbmc.executebuiltin('Container.SetViewMode(%d)' % view_mode)
else:
# handle exception
pass
diff --git a/resources/lib/youtube_plugin/kodion/utils/__init__.py b/resources/lib/youtube_plugin/kodion/utils/__init__.py
index 20e9597e..4c279f9b 100644
--- a/resources/lib/youtube_plugin/kodion/utils/__init__.py
+++ b/resources/lib/youtube_plugin/kodion/utils/__init__.py
@@ -16,6 +16,7 @@ from .favorite_list import FavoriteList
from .watch_later_list import WatchLaterList
from .function_cache import FunctionCache
from .access_manager import AccessManager
+from .view_manager import ViewManager
from .http_server import get_http_server, is_httpd_live, get_client_ip_address
from .monitor import YouTubeMonitor
from .player import YouTubePlayer
@@ -25,7 +26,7 @@ from .system_version import SystemVersion
from . import ip_api
-__all__ = ['SearchHistory', 'FavoriteList', 'WatchLaterList', 'FunctionCache', 'AccessManager',
+__all__ = ['SearchHistory', 'FavoriteList', 'WatchLaterList', 'FunctionCache', 'AccessManager', 'ViewManager',
'strip_html_from_text', 'create_path', 'create_uri_path', 'find_best_fit', 'to_unicode', 'to_utf8',
'datetime_parser', 'select_stream', 'get_http_server', 'is_httpd_live', 'YouTubeMonitor',
'make_dirs', 'loose_version', 'ip_api', 'PlaybackHistory', 'DataCache', 'get_client_ip_address',
diff --git a/resources/lib/youtube_plugin/kodion/utils/view_manager.py b/resources/lib/youtube_plugin/kodion/utils/view_manager.py
new file mode 100644
index 00000000..9a5fe5ae
--- /dev/null
+++ b/resources/lib/youtube_plugin/kodion/utils/view_manager.py
@@ -0,0 +1,166 @@
+# -*- coding: utf-8 -*-
+"""
+
+ Copyright (C) 2014-2016 bromix (plugin.video.youtube)
+ Copyright (C) 2016-2018 plugin.video.youtube
+
+ SPDX-License-Identifier: GPL-2.0-only
+ See LICENSES/GPL-2.0-only for more information.
+"""
+
+from .. import constants
+
+
+class ViewManager(object):
+ SUPPORTED_VIEWS = ['default', 'movies', 'tvshows', 'episodes', 'musicvideos', 'songs', 'albums', 'artists']
+ SKIN_DATA = {
+ 'skin.confluence': {
+ 'default': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Big List', 'id': 51},
+ {'name': 'Thumbnail', 'id': 500}
+ ],
+ 'movies': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Big List', 'id': 51},
+ {'name': 'Thumbnail', 'id': 500},
+ {'name': 'Media info', 'id': 504},
+ {'name': 'Media info 2', 'id': 503}
+ ],
+ 'episodes': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Big List', 'id': 51},
+ {'name': 'Thumbnail', 'id': 500},
+ {'name': 'Media info', 'id': 504},
+ {'name': 'Media info 2', 'id': 503}
+ ],
+ 'tvshows': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Big List', 'id': 51},
+ {'name': 'Thumbnail', 'id': 500},
+ {'name': 'Poster', 'id': 500},
+ {'name': 'Wide', 'id': 505},
+ {'name': 'Media info', 'id': 504},
+ {'name': 'Media info 2', 'id': 503},
+ {'name': 'Fanart', 'id': 508}
+ ],
+ 'musicvideos': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Big List', 'id': 51},
+ {'name': 'Thumbnail', 'id': 500},
+ {'name': 'Media info', 'id': 504},
+ {'name': 'Media info 2', 'id': 503}
+ ],
+ 'songs': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Big List', 'id': 51},
+ {'name': 'Thumbnail', 'id': 500},
+ {'name': 'Media info', 'id': 506}
+ ],
+ 'albums': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Big List', 'id': 51},
+ {'name': 'Thumbnail', 'id': 500},
+ {'name': 'Media info', 'id': 506}
+ ],
+ 'artists': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Big List', 'id': 51},
+ {'name': 'Thumbnail', 'id': 500},
+ {'name': 'Media info', 'id': 506}
+ ]
+ },
+ 'skin.aeon.nox.5': {
+ 'default': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Episodes', 'id': 502},
+ {'name': 'LowList', 'id': 501},
+ {'name': 'BannerWall', 'id': 58},
+ {'name': 'Shift', 'id': 57},
+ {'name': 'Posters', 'id': 56},
+ {'name': 'ShowCase', 'id': 53},
+ {'name': 'Landscape', 'id': 52},
+ {'name': 'InfoWall', 'id': 51}
+ ]
+ },
+ 'skin.xperience1080+': {
+ 'default': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Thumbnail', 'id': 500},
+ ],
+ 'episodes': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Info list', 'id': 52},
+ {'name': 'Fanart', 'id': 502},
+ {'name': 'Landscape', 'id': 54},
+ {'name': 'Poster', 'id': 55},
+ {'name': 'Thumbnail', 'id': 500},
+ {'name': 'Banner', 'id': 60}
+ ],
+ },
+ 'skin.xperience1080': {
+ 'default': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Thumbnail', 'id': 500},
+ ],
+ 'episodes': [
+ {'name': 'List', 'id': 50},
+ {'name': 'Info list', 'id': 52},
+ {'name': 'Fanart', 'id': 502},
+ {'name': 'Landscape', 'id': 54},
+ {'name': 'Poster', 'id': 55},
+ {'name': 'Thumbnail', 'id': 500},
+ {'name': 'Banner', 'id': 60}
+ ],
+ },
+ 'skin.estuary': {
+ 'default': [
+ {'name': 'Shift', 'id': 53},
+ {'name': 'InfoWall', 'id': 54},
+ {'name': 'Wall', 'id': 500},
+ {'name': 'WideList', 'id': 55},
+ ],
+ 'episodes': [
+ {'name': 'InfoWall', 'id': 54},
+ {'name': 'Wall', 'id': 500},
+ {'name': 'WideList', 'id': 55},
+ ]
+ }
+ }
+
+ def __init__(self, context):
+ self._context = context
+
+ def has_supported_views(self):
+ """
+ Returns True if the View of the current skin are supported
+ :return: True if the View of the current skin are supported
+ """
+ return self._context.get_ui().get_skin_id() in self.SKIN_DATA
+
+ def update_view_mode(self, title, view='default'):
+ view_id = -1
+ settings = self._context.get_settings()
+
+ skin_id = self._context.get_ui().get_skin_id()
+ skin_data = self.SKIN_DATA.get(skin_id, {}).get(view, [])
+ if skin_data:
+ items = []
+ for view_data in skin_data:
+ items.append((view_data['name'], view_data['id']))
+ view_id = self._context.get_ui().on_select(title, items)
+ else:
+ self._context.log_notice("ViewManager: Unknown skin id '%s'" % skin_id)
+
+ if view_id == -1:
+ old_value = settings.get_string(constants.setting.VIEW_X % view, '')
+ if old_value:
+ result, view_id = self._context.get_ui().on_numeric_input(title, old_value)
+ if not result:
+ view_id = -1
+
+ if view_id > -1:
+ settings.set_int(constants.setting.VIEW_X % view, view_id)
+ return True
+
+ return False
diff --git a/resources/lib/youtube_plugin/youtube/helper/utils.py b/resources/lib/youtube_plugin/youtube/helper/utils.py
index 88a7fb7f..5fc6e374 100644
--- a/resources/lib/youtube_plugin/youtube/helper/utils.py
+++ b/resources/lib/youtube_plugin/youtube/helper/utils.py
@@ -258,7 +258,7 @@ def update_video_infos(provider, context, video_id_dict, playlist_item_id_dict=N
video_item = video_id_dict[video_id]
# set mediatype
- video_item.set_mediatype('video') # using video
+ video_item.set_mediatype('episode') # using video
if not yt_item:
continue
diff --git a/resources/lib/youtube_plugin/youtube/helper/yt_specials.py b/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
index 89ad2b11..c5c8fec3 100644
--- a/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
+++ b/resources/lib/youtube_plugin/youtube/helper/yt_specials.py
@@ -15,7 +15,7 @@ from . import utils
def _process_related_videos(provider, context):
- provider.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ provider.set_content_type(context, kodion.constants.content_type.EPISODES)
result = []
page_token = context.get_param('page_token', '')
@@ -60,7 +60,7 @@ def _process_child_comments(provider, context):
def _process_recommendations(provider, context):
- provider.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ provider.set_content_type(context, kodion.constants.content_type.EPISODES)
result = []
page_token = context.get_param('page_token', '')
@@ -72,7 +72,7 @@ def _process_recommendations(provider, context):
def _process_popular_right_now(provider, context):
- provider.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ provider.set_content_type(context, kodion.constants.content_type.EPISODES)
result = []
page_token = context.get_param('page_token', '')
@@ -85,7 +85,7 @@ def _process_popular_right_now(provider, context):
def _process_browse_channels(provider, context):
- provider.set_content_type(context, kodion.constants.content_type.FILES)
+ provider.set_content_type(context, kodion.constants.content_type.VIDEOS)
result = []
# page_token = context.get_param('page_token', '')
@@ -107,7 +107,7 @@ def _process_browse_channels(provider, context):
def _process_disliked_videos(provider, context):
- provider.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ provider.set_content_type(context, kodion.constants.content_type.EPISODES)
result = []
page_token = context.get_param('page_token', '')
@@ -122,7 +122,7 @@ def _process_live_events(provider, context, event_type='live'):
def _sort(x):
return x.get_aired()
- provider.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ provider.set_content_type(context, kodion.constants.content_type.EPISODES)
result = []
# TODO: cache result
@@ -142,7 +142,7 @@ def _process_description_links(provider, context):
addon_id = context.get_param('addon_id', '')
def _extract_urls(_video_id):
- provider.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ provider.set_content_type(context, kodion.constants.content_type.EPISODES)
url_resolver = UrlResolver(context)
result = []
@@ -304,7 +304,7 @@ def _process_purchases_tv(provider, context):
def _process_new_uploaded_videos_tv(provider, context):
- provider.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ provider.set_content_type(context, kodion.constants.content_type.EPISODES)
result = []
next_page_token = context.get_param('next_page_token', '')
@@ -316,7 +316,7 @@ def _process_new_uploaded_videos_tv(provider, context):
def _process_new_uploaded_videos_tv_filtered(provider, context):
- provider.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ provider.set_content_type(context, kodion.constants.content_type.EPISODES)
result = []
next_page_token = context.get_param('next_page_token', '')
diff --git a/resources/lib/youtube_plugin/youtube/provider.py b/resources/lib/youtube_plugin/youtube/provider.py
index fea29579..75c67802 100644
--- a/resources/lib/youtube_plugin/youtube/provider.py
+++ b/resources/lib/youtube_plugin/youtube/provider.py
@@ -437,7 +437,7 @@ class Provider(kodion.AbstractProvider):
@kodion.RegisterProviderPath('^/playlist/(?P[^/]+)/$')
def _on_playlist(self, context, re_match):
- self.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ self.set_content_type(context, kodion.constants.content_type.EPISODES)
result = []
@@ -461,7 +461,7 @@ class Provider(kodion.AbstractProvider):
@kodion.RegisterProviderPath('^/channel/(?P[^/]+)/playlist/(?P[^/]+)/$')
def _on_channel_playlist(self, context, re_match):
- self.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ self.set_content_type(context, kodion.constants.content_type.EPISODES)
client = self.get_client(context)
result = []
@@ -484,7 +484,7 @@ class Provider(kodion.AbstractProvider):
@kodion.RegisterProviderPath('^/channel/(?P[^/]+)/playlists/$')
def _on_channel_playlists(self, context, re_match):
- self.set_content_type(context, kodion.constants.content_type.FILES)
+ self.set_content_type(context, kodion.constants.content_type.VIDEOS)
result = []
channel_id = re_match.group('channel_id')
@@ -525,7 +525,7 @@ class Provider(kodion.AbstractProvider):
@kodion.RegisterProviderPath('^/channel/(?P[^/]+)/live/$')
def _on_channel_live(self, context, re_match):
- self.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ self.set_content_type(context, kodion.constants.content_type.EPISODES)
result = []
channel_id = re_match.group('channel_id')
@@ -560,7 +560,7 @@ class Provider(kodion.AbstractProvider):
if method == 'channel' and not channel_id:
return False
- self.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ self.set_content_type(context, kodion.constants.content_type.EPISODES)
resource_manager = self.get_resource_manager(context)
@@ -648,7 +648,7 @@ class Provider(kodion.AbstractProvider):
# noinspection PyUnusedLocal
@kodion.RegisterProviderPath('^/location/mine/$')
def _on_my_location(self, context, re_match):
- self.set_content_type(context, kodion.constants.content_type.FILES)
+ self.set_content_type(context, kodion.constants.content_type.VIDEOS)
settings = context.get_settings()
result = list()
@@ -793,7 +793,7 @@ class Provider(kodion.AbstractProvider):
subscriptions = yt_subscriptions.process(method, self, context)
if method == 'list':
- self.set_content_type(context, kodion.constants.content_type.FILES)
+ self.set_content_type(context, kodion.constants.content_type.VIDEOS)
channel_ids = []
for subscription in subscriptions:
channel_ids.append(subscription.get_channel_id())
@@ -1025,9 +1025,9 @@ class Provider(kodion.AbstractProvider):
context.set_param('q', search_text)
if search_type == 'video':
- self.set_content_type(context, kodion.constants.content_type.VIDEOS)
+ self.set_content_type(context, kodion.constants.content_type.EPISODES)
else:
- self.set_content_type(context, kodion.constants.content_type.FILES)
+ self.set_content_type(context, kodion.constants.content_type.VIDEOS)
if page == 1 and search_type == 'video' and not event_type and not hide_folders:
if not channel_id and not location:
@@ -1361,7 +1361,7 @@ class Provider(kodion.AbstractProvider):
settings = context.get_settings()
_ = self.get_client(context) # required for self.is_logged_in()
- self.set_content_type(context, kodion.constants.content_type.FILES)
+ self.set_content_type(context, kodion.constants.content_type.VIDEOS)
result = []
@@ -1596,7 +1596,7 @@ class Provider(kodion.AbstractProvider):
@staticmethod
def set_content_type(context, content_type):
context.set_content_type(content_type)
- if content_type == kodion.constants.content_type.VIDEOS:
+ if content_type == kodion.constants.content_type.EPISODES:
context.add_sort_method(kodion.constants.sort_method.UNSORTED,
kodion.constants.sort_method.VIDEO_RUNTIME,
kodion.constants.sort_method.DATE_ADDED,
diff --git a/resources/settings.xml b/resources/settings.xml
index 14bfc452..29661e89 100644
--- a/resources/settings.xml
+++ b/resources/settings.xml
@@ -610,6 +610,37 @@
+
+ 0
+ false
+
+
+
+ 0
+ 50
+
+
+ true
+
+
+
+ 30027
+
+
+
+ 0
+ 50
+
+
+ true
+
+
+
+ 30028
+
+
+
+
0
10
@@ -628,7 +659,7 @@
-
+
0
en-US