Merge pull request #917 from croneter/fix-skin
Ensure correct Kodi Container.Type is set for PKC widgets
This commit is contained in:
commit
53139a7e45
9 changed files with 216 additions and 135 deletions
|
@ -52,6 +52,9 @@ class Main():
|
|||
synched=params.get('synched') != 'false',
|
||||
prompt=params.get('prompt'))
|
||||
|
||||
elif mode == 'show_section':
|
||||
entrypoint.show_section(params.get('section_index'))
|
||||
|
||||
elif mode == 'watchlater':
|
||||
entrypoint.watchlater()
|
||||
|
||||
|
|
|
@ -20,11 +20,13 @@ from . import plex_functions as PF
|
|||
from . import variables as v
|
||||
# Be careful - your using app in another Python instance!
|
||||
from . import app, widgets
|
||||
from .library_sync.nodes import NODE_TYPES
|
||||
|
||||
|
||||
LOG = getLogger('PLEX.entrypoint')
|
||||
|
||||
|
||||
def guess_content_type():
|
||||
def guess_video_or_audio():
|
||||
"""
|
||||
Returns either 'video', 'audio' or 'image', based how the user navigated to
|
||||
the current view.
|
||||
|
@ -102,9 +104,9 @@ def show_main_menu(content_type=None):
|
|||
"""
|
||||
Shows the main PKC menu listing with all libraries, Channel, settings, etc.
|
||||
"""
|
||||
content_type = content_type or guess_content_type()
|
||||
LOG.debug('Do main listing for content_type: %s', content_type)
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'files')
|
||||
content_type = content_type or guess_video_or_audio()
|
||||
LOG.debug('Do main listing for %s', content_type)
|
||||
xbmcplugin.setContent(int(sys.argv[1]), v.CONTENT_TYPE_FILE)
|
||||
# Get nodes from the window props
|
||||
totalnodes = int(utils.window('Plex.nodes.total') or 0)
|
||||
for i in range(totalnodes):
|
||||
|
@ -133,14 +135,6 @@ def show_main_menu(content_type=None):
|
|||
# Should only be called if the user selects widgets
|
||||
LOG.info('Detected user selecting widgets')
|
||||
directory_item(label, path)
|
||||
if not path.startswith('library://'):
|
||||
# Already using add-on paths (e.g. section not synched)
|
||||
continue
|
||||
# Add ANOTHER menu item that uses add-on paths instead of direct
|
||||
# paths in order to let the user navigate into all submenus
|
||||
addon_index = utils.window('Plex.nodes.%s.addon_index' % i)
|
||||
# Append "(More...)" to the label
|
||||
directory_item('%s (%s)' % (label, utils.lang(22082)), addon_index)
|
||||
# Playlists
|
||||
if content_type != 'image':
|
||||
path = 'plugin://%s?mode=playlists' % v.ADDON_ID
|
||||
|
@ -169,32 +163,64 @@ def show_main_menu(content_type=None):
|
|||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
|
||||
|
||||
def show_listing(xml, plex_type=None, section_id=None, synched=True, key=None,
|
||||
content_type=None):
|
||||
def show_section(section_index):
|
||||
"""
|
||||
Displays menu for an entire Plex section. We're using add-on paths instead
|
||||
of Kodi video library xmls to be able to use type="filter" library xmls
|
||||
and thus set the "content"
|
||||
|
||||
Only used for synched Plex sections - otherwise, PMS xml for the section
|
||||
is used directly
|
||||
"""
|
||||
LOG.debug('Do section listing for section index %s', section_index)
|
||||
xbmcplugin.setContent(int(sys.argv[1]), v.CONTENT_TYPE_FILE)
|
||||
# Get nodes from the window props
|
||||
node = 'Plex.nodes.%s' % section_index
|
||||
content = utils.window('%s.type' % node)
|
||||
plex_type = v.PLEX_TYPE_MOVIE if content == v.CONTENT_TYPE_MOVIE \
|
||||
else v.PLEX_TYPE_SHOW
|
||||
for node_type, _, _, _, _ in NODE_TYPES[plex_type]:
|
||||
label = utils.window('%s.%s.title' % (node, node_type))
|
||||
path = utils.window('%s.%s.index' % (node, node_type))
|
||||
directory_item(label, path)
|
||||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
|
||||
|
||||
def show_listing(xml, plex_type=None, section_id=None, synched=True, key=None):
|
||||
"""
|
||||
Pass synched=False if the items have not been synched to the Kodi DB
|
||||
|
||||
Kodi content type will be set using the very first item returned by the PMS
|
||||
"""
|
||||
content_type = content_type or guess_content_type()
|
||||
LOG.debug('show_listing: content_type %s, section_id %s, synched %s, '
|
||||
'key %s, plex_type %s', content_type, section_id, synched, key,
|
||||
plex_type)
|
||||
try:
|
||||
xml[0]
|
||||
except IndexError:
|
||||
LOG.info('xml received from the PMS is empty: %s', xml.attrib)
|
||||
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
||||
LOG.info('xml received from the PMS is empty: %s, %s',
|
||||
xml.tag, xml.attrib)
|
||||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
return
|
||||
if content_type == 'video':
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'videos')
|
||||
elif content_type == 'audio':
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'artists')
|
||||
elif plex_type in (v.PLEX_TYPE_PLAYLIST, v.PLEX_TYPE_CHANNEL):
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'videos')
|
||||
elif plex_type:
|
||||
xbmcplugin.setContent(int(sys.argv[1]),
|
||||
v.MEDIATYPE_FROM_PLEX_TYPE[plex_type])
|
||||
api = API(xml[0])
|
||||
# Determine content type for Kodi's Container.content
|
||||
if key == '/hubs/home/continueWatching':
|
||||
# Mix of movies and episodes
|
||||
plex_type = v.PLEX_TYPE_VIDEO
|
||||
elif key == '/hubs/home/recentlyAdded?type=2':
|
||||
# "Recently Added TV", potentially a mix of Seasons and Episodes
|
||||
plex_type = v.PLEX_TYPE_VIDEO
|
||||
elif api.plex_type is None and api.fast_key and '?collection=' in api.fast_key:
|
||||
# Collections/Kodi sets
|
||||
plex_type = v.PLEX_TYPE_SET
|
||||
elif api.plex_type is None and plex_type:
|
||||
# e.g. browse by folder - folders will be listed first
|
||||
# Retain plex_type
|
||||
pass
|
||||
else:
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'files')
|
||||
plex_type = api.plex_type
|
||||
content_type = v.CONTENT_FROM_PLEX_TYPE[plex_type]
|
||||
LOG.debug('show_listing: section_id %s, synched %s, key %s, plex_type %s, '
|
||||
'content type %s',
|
||||
section_id, synched, key, plex_type, content_type)
|
||||
xbmcplugin.setContent(int(sys.argv[1]), content_type)
|
||||
# Initialization
|
||||
widgets.PLEX_TYPE = plex_type
|
||||
widgets.SYNCHED = synched
|
||||
|
@ -204,11 +230,15 @@ def show_listing(xml, plex_type=None, section_id=None, synched=True, key=None,
|
|||
if plex_type == v.PLEX_TYPE_SHOW and key and 'recentlyAdded' in key:
|
||||
widgets.APPEND_SHOW_TITLE = utils.settings('RecentTvAppendShow') == 'true'
|
||||
widgets.APPEND_SXXEXX = utils.settings('RecentTvAppendSeason') == 'true'
|
||||
if content_type and xml[0].tag == 'Playlist':
|
||||
# Certain views mix playlist types audio and video
|
||||
for entry in reversed(xml):
|
||||
if entry.get('playlistType') != content_type:
|
||||
xml.remove(entry)
|
||||
if api.tag == 'Playlist':
|
||||
# Only show video playlists if navigation started for videos
|
||||
# and vice-versa for audio playlists
|
||||
content = guess_video_or_audio()
|
||||
if content:
|
||||
for entry in reversed(xml):
|
||||
tmp_api = API(entry)
|
||||
if tmp_api.playlist_type() != content:
|
||||
xml.remove(entry)
|
||||
if xml.get('librarySectionID'):
|
||||
widgets.SECTION_ID = utils.cast(int, xml.get('librarySectionID'))
|
||||
elif section_id:
|
||||
|
@ -355,15 +385,14 @@ def playlists(content_type):
|
|||
Lists all Plex playlists of the media type plex_playlist_type
|
||||
content_type: 'audio', 'video'
|
||||
"""
|
||||
content_type = content_type or guess_content_type()
|
||||
LOG.debug('Listing Plex %s playlists', content_type)
|
||||
LOG.debug('Listing Plex playlists for content type %s', content_type)
|
||||
if not _wait_for_auth():
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
app.init(entrypoint=True)
|
||||
from .playlists.pms import all_playlists
|
||||
xml = all_playlists()
|
||||
if xml is None:
|
||||
return
|
||||
return xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
||||
if content_type is not None:
|
||||
# This will be skipped if user selects a widget
|
||||
# Buggy xml.remove(child) requires reversed()
|
||||
|
@ -371,7 +400,7 @@ def playlists(content_type):
|
|||
api = API(entry)
|
||||
if not api.playlist_type() == content_type:
|
||||
xml.remove(entry)
|
||||
show_listing(xml, content_type=content_type)
|
||||
show_listing(xml)
|
||||
|
||||
|
||||
def hub(content_type):
|
||||
|
@ -380,7 +409,7 @@ def hub(content_type):
|
|||
content_type:
|
||||
audio, video, image
|
||||
"""
|
||||
content_type = content_type or guess_content_type()
|
||||
content_type = content_type or guess_video_or_audio()
|
||||
LOG.debug('Showing Plex Hub entries for %s', content_type)
|
||||
if not _wait_for_auth():
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
|
@ -410,7 +439,7 @@ def hub(content_type):
|
|||
append = True
|
||||
if not append:
|
||||
xml.remove(entry)
|
||||
show_listing(xml, content_type=content_type)
|
||||
show_listing(xml)
|
||||
|
||||
|
||||
def watchlater():
|
||||
|
@ -447,7 +476,8 @@ def browse_plex(key=None, plex_type=None, section_id=None, synched=True,
|
|||
LOG.debug('Browsing to key %s, section %s, plex_type: %s, synched: %s, '
|
||||
'prompt "%s"', key, section_id, plex_type, synched, prompt)
|
||||
if not _wait_for_auth():
|
||||
return xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
xbmcplugin.endOfDirectory(int(sys.argv[1]), False)
|
||||
return
|
||||
app.init(entrypoint=True)
|
||||
if prompt:
|
||||
prompt = utils.dialog('input', prompt)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
import urllib
|
||||
import copy
|
||||
|
||||
from ..utils import etree
|
||||
from .. import variables as v, utils
|
||||
|
@ -23,10 +24,9 @@ NODE_TYPES = {
|
|||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/onDeck',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'movies',
|
||||
v.CONTENT_TYPE_MOVIE,
|
||||
True),
|
||||
('pkc_ondeck',
|
||||
utils.lang(39502), # "PKC On Deck (faster)"
|
||||
|
@ -38,20 +38,18 @@ NODE_TYPES = {
|
|||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/recentlyAdded',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'movies',
|
||||
v.CONTENT_TYPE_MOVIE,
|
||||
False),
|
||||
('all',
|
||||
'{self.name}', # We're using this section's name
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/all',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'movies',
|
||||
v.CONTENT_TYPE_MOVIE,
|
||||
False),
|
||||
('recommended',
|
||||
utils.lang(30230), # "Recommended"
|
||||
|
@ -59,30 +57,27 @@ NODE_TYPES = {
|
|||
'mode': 'browseplex',
|
||||
'key': ('/library/sections/{self.section_id}&%s'
|
||||
% urllib.urlencode({'sort': 'rating:desc'})),
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'movies',
|
||||
v.CONTENT_TYPE_MOVIE,
|
||||
False),
|
||||
('genres',
|
||||
utils.lang(135), # "Genres"
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/genre',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'movies',
|
||||
v.CONTENT_TYPE_MOVIE,
|
||||
False),
|
||||
('sets',
|
||||
utils.lang(39501), # "Collections"
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/collection',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'movies',
|
||||
v.CONTENT_TYPE_MOVIE,
|
||||
False),
|
||||
('random',
|
||||
utils.lang(30227), # "Random"
|
||||
|
@ -90,20 +85,18 @@ NODE_TYPES = {
|
|||
'mode': 'browseplex',
|
||||
'key': ('/library/sections/{self.section_id}&%s'
|
||||
% urllib.urlencode({'sort': 'random'})),
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'movies',
|
||||
v.CONTENT_TYPE_MOVIE,
|
||||
False),
|
||||
('lastplayed',
|
||||
utils.lang(568), # "Last played"
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/recentlyViewed',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'movies',
|
||||
v.CONTENT_TYPE_MOVIE,
|
||||
False),
|
||||
('browse',
|
||||
utils.lang(39702), # "Browse by folder"
|
||||
|
@ -111,19 +104,20 @@ NODE_TYPES = {
|
|||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/folder',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
'section_id': '{self.section_id}',
|
||||
'folder': True
|
||||
},
|
||||
'movies',
|
||||
v.CONTENT_TYPE_MOVIE,
|
||||
True),
|
||||
('more',
|
||||
utils.lang(22082), # "More..."
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
'section_id': '{self.section_id}',
|
||||
'folder': True
|
||||
},
|
||||
'movies',
|
||||
v.CONTENT_TYPE_FILE,
|
||||
True),
|
||||
),
|
||||
###########################################################
|
||||
|
@ -133,30 +127,27 @@ NODE_TYPES = {
|
|||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/onDeck',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'episodes',
|
||||
v.CONTENT_TYPE_EPISODE,
|
||||
True),
|
||||
('recent',
|
||||
utils.lang(30174), # "Recently Added"
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/recentlyAdded',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'episodes',
|
||||
v.CONTENT_TYPE_EPISODE,
|
||||
False),
|
||||
('all',
|
||||
'{self.name}', # We're using this section's name
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/all',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'tvshows',
|
||||
v.CONTENT_TYPE_SHOW,
|
||||
False),
|
||||
('recommended',
|
||||
utils.lang(30230), # "Recommended"
|
||||
|
@ -164,30 +155,27 @@ NODE_TYPES = {
|
|||
'mode': 'browseplex',
|
||||
'key': ('/library/sections/{self.section_id}&%s'
|
||||
% urllib.urlencode({'sort': 'rating:desc'})),
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'tvshows',
|
||||
v.CONTENT_TYPE_SHOW,
|
||||
False),
|
||||
('genres',
|
||||
utils.lang(135), # "Genres"
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/genre',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'tvshows',
|
||||
v.CONTENT_TYPE_SHOW,
|
||||
False),
|
||||
('sets',
|
||||
utils.lang(39501), # "Collections"
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/collection',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'tvshows',
|
||||
v.CONTENT_TYPE_SHOW,
|
||||
True), # There are no sets/collections for shows with Kodi
|
||||
('random',
|
||||
utils.lang(30227), # "Random"
|
||||
|
@ -195,10 +183,9 @@ NODE_TYPES = {
|
|||
'mode': 'browseplex',
|
||||
'key': ('/library/sections/{self.section_id}&%s'
|
||||
% urllib.urlencode({'sort': 'random'})),
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'tvshows',
|
||||
v.CONTENT_TYPE_SHOW,
|
||||
False),
|
||||
('lastplayed',
|
||||
utils.lang(568), # "Last played"
|
||||
|
@ -206,30 +193,29 @@ NODE_TYPES = {
|
|||
'mode': 'browseplex',
|
||||
'key': ('/library/sections/{self.section_id}/recentlyViewed&%s'
|
||||
% urllib.urlencode({'type': v.PLEX_TYPE_NUMBER_FROM_PLEX_TYPE[v.PLEX_TYPE_EPISODE]})),
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
},
|
||||
'episodes',
|
||||
v.CONTENT_TYPE_EPISODE,
|
||||
False),
|
||||
('browse',
|
||||
utils.lang(39702), # "Browse by folder"
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}/folder',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
'section_id': '{self.section_id}',
|
||||
'folder': True
|
||||
},
|
||||
'episodes',
|
||||
v.CONTENT_TYPE_EPISODE,
|
||||
True),
|
||||
('more',
|
||||
utils.lang(22082), # "More..."
|
||||
{
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/{self.section_id}',
|
||||
'plex_type': '{self.section_type}',
|
||||
'section_id': '{self.section_id}'
|
||||
'section_id': '{self.section_id}',
|
||||
'folder': True
|
||||
},
|
||||
'episodes',
|
||||
v.CONTENT_TYPE_FILE,
|
||||
True),
|
||||
),
|
||||
}
|
||||
|
@ -239,9 +225,19 @@ def node_pms(section, node_name, args):
|
|||
"""
|
||||
Nodes where the logic resides with the PMS - we're NOT building an
|
||||
xml that filters and sorts, but point to PKC add-on path
|
||||
|
||||
Be sure to set args['folder'] = True if the listing is a folder and does
|
||||
not contain playable elements like movies, episodes or tracks
|
||||
"""
|
||||
xml = etree.Element('node', attrib={'order': unicode(section.order),
|
||||
'type': 'folder'})
|
||||
if 'folder' in args:
|
||||
args = copy.deepcopy(args)
|
||||
args.pop('folder')
|
||||
folder = True
|
||||
else:
|
||||
folder = False
|
||||
xml = etree.Element('node',
|
||||
attrib={'order': unicode(section.order),
|
||||
'type': 'folder' if folder else 'filter'})
|
||||
etree.SubElement(xml, 'label').text = node_name
|
||||
etree.SubElement(xml, 'icon').text = ICON_PATH
|
||||
etree.SubElement(xml, 'content').text = section.content
|
||||
|
|
|
@ -132,7 +132,7 @@ class Section(object):
|
|||
@section_type.setter
|
||||
def section_type(self, value):
|
||||
self._section_type = value
|
||||
self.content = v.MEDIATYPE_FROM_PLEX_TYPE[value]
|
||||
self.content = v.CONTENT_FROM_PLEX_TYPE[value]
|
||||
# Default values whether we sync or not based on the Plex type
|
||||
if value == v.PLEX_TYPE_PHOTO:
|
||||
self.sync_to_kodi = False
|
||||
|
@ -239,25 +239,24 @@ class Section(object):
|
|||
raise RuntimeError('Index not initialized')
|
||||
# Main list entry for this section - which will show the different
|
||||
# nodes as "submenus" once the user navigates into this section
|
||||
args = {
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/%s' % self.section_id,
|
||||
'plex_type': self.section_type,
|
||||
'section_id': unicode(self.section_id)
|
||||
}
|
||||
if not self.sync_to_kodi:
|
||||
args['synched'] = 'false'
|
||||
addon_index = self.addon_path(args)
|
||||
if self.sync_to_kodi and self.section_type in v.PLEX_VIDEOTYPES:
|
||||
path = 'library://video/Plex-{0}/{0}_all.xml'
|
||||
path = path.format(self.section_id)
|
||||
index = 'library://video/Plex-%s' % self.section_id
|
||||
args = {
|
||||
'mode': 'show_section',
|
||||
'section_index': self.index
|
||||
}
|
||||
path = utils.extend_url('plugin://%s' % v.ADDON_ID, args)
|
||||
else:
|
||||
# No xmls to link to - let's show the listings on the fly
|
||||
index = addon_index
|
||||
args['key'] = '/library/sections/%s/all' % self.section_id
|
||||
args = {
|
||||
'mode': 'browseplex',
|
||||
'key': '/library/sections/%s/all' % self.section_id,
|
||||
'section_id': unicode(self.section_id)
|
||||
}
|
||||
if not self.sync_to_kodi:
|
||||
args['synched'] = 'false'
|
||||
# No library xmls to speed things up
|
||||
# Immediately show the PMS options for this section
|
||||
path = self.addon_path(args)
|
||||
# .index will list all possible nodes for this library
|
||||
index = path
|
||||
utils.window('%s.index' % self.node, value=index)
|
||||
utils.window('%s.title' % self.node, value=self.name)
|
||||
utils.window('%s.type' % self.node, value=self.content)
|
||||
|
@ -274,8 +273,6 @@ class Section(object):
|
|||
utils.window('%s.path' % self.node,
|
||||
value='ActivateWindow(pictures,%s,return)' % path)
|
||||
utils.window('%s.id' % self.node, value=str(self.section_id))
|
||||
# To let the user navigate into this node when selecting widgets
|
||||
utils.window('%s.addon_index' % self.node, value=addon_index)
|
||||
if not self.sync_to_kodi:
|
||||
self.remove_files_from_kodi()
|
||||
return
|
||||
|
@ -312,18 +309,22 @@ class Section(object):
|
|||
def _build_node(self, node_type, node_name, args, content, pms_node):
|
||||
self.content = content
|
||||
node_name = node_name.format(self=self)
|
||||
xml_name = '%s_%s.xml' % (self.section_id, node_type)
|
||||
path = path_ops.path.join(self.path, xml_name)
|
||||
if not path_ops.exists(path):
|
||||
if pms_node:
|
||||
# Even the xml will point back to the PKC add-on
|
||||
xml = nodes.node_pms(self, node_name, args)
|
||||
else:
|
||||
if pms_node:
|
||||
# Do NOT write a Kodi video library xml - can't use type="filter"
|
||||
# to point back to plugin://plugin.video.plexkodiconnect
|
||||
xml = nodes.node_pms(self, node_name, args)
|
||||
args.pop('folder', None)
|
||||
path = self.addon_path(args)
|
||||
else:
|
||||
# Write a Kodi video library xml
|
||||
xml_name = '%s_%s.xml' % (self.section_id, node_type)
|
||||
path = path_ops.path.join(self.path, xml_name)
|
||||
if not path_ops.exists(path):
|
||||
# Let's use Kodi's logic to sort/filter the Kodi library
|
||||
xml = getattr(nodes, 'node_%s' % node_type)(self, node_name)
|
||||
self._write_xml(xml, xml_name)
|
||||
self._write_xml(xml, xml_name)
|
||||
path = 'library://video/Plex-%s/%s' % (self.section_id, xml_name)
|
||||
self.order += 1
|
||||
path = 'library://video/Plex-%s/%s' % (self.section_id, xml_name)
|
||||
self._window_node(path, node_name, node_type, pms_node)
|
||||
|
||||
def _write_xml(self, xml, xml_name):
|
||||
|
@ -337,7 +338,7 @@ class Section(object):
|
|||
LOG.debug('Creating smart playlist for section %s: %s',
|
||||
self.name, self.playlist_path)
|
||||
xml = etree.Element('smartplaylist',
|
||||
attrib={'type': v.MEDIATYPE_FROM_PLEX_TYPE[self.section_type]})
|
||||
attrib={'type': v.CONTENT_FROM_PLEX_TYPE[self.section_type]})
|
||||
etree.SubElement(xml, 'name').text = self.name
|
||||
etree.SubElement(xml, 'match').text = 'all'
|
||||
rule = etree.SubElement(xml, 'rule', attrib={'field': 'tag',
|
||||
|
@ -647,7 +648,6 @@ def _clear_window_vars(index):
|
|||
utils.window('%s.content' % node, clear=True)
|
||||
utils.window('%s.path' % node, clear=True)
|
||||
utils.window('%s.id' % node, clear=True)
|
||||
utils.window('%s.addon_index' % node, clear=True)
|
||||
# Just clear everything here, ignore the plex_type
|
||||
for typus in (x[0] for y in nodes.NODE_TYPES.values() for x in y):
|
||||
for kind in WINDOW_ARGS:
|
||||
|
|
|
@ -51,4 +51,10 @@ def check_migration():
|
|||
plexdb.cursor.execute('DROP INDEX IF EXISTS ix_playlists_3')
|
||||
# Index will be automatically recreated on next PKC startup
|
||||
|
||||
if not utils.compare_version(last_migration, '2.8.9'):
|
||||
LOG.info('Migrating to version 2.8.8')
|
||||
from .library_sync import sections
|
||||
sections.clear_window_vars()
|
||||
sections.delete_videonode_files()
|
||||
|
||||
utils.settings('last_migrated_PKC_version', value=v.ADDON_VERSION)
|
||||
|
|
|
@ -71,6 +71,13 @@ class Base(object):
|
|||
"""
|
||||
return cast(int, self.xml.get('ratingKey'))
|
||||
|
||||
@property
|
||||
def fast_key(self):
|
||||
"""
|
||||
Returns the 'fastKey' as unicode or None
|
||||
"""
|
||||
return self.xml.get('fastKey')
|
||||
|
||||
@property
|
||||
def plex_type(self):
|
||||
"""
|
||||
|
|
|
@ -91,9 +91,10 @@ class File(object):
|
|||
key = '/library/sections/%s/%s' % (section_id, key)
|
||||
params = {
|
||||
'mode': 'browseplex',
|
||||
'key': key,
|
||||
'plex_type': plex_type or self.plex_type
|
||||
'key': key
|
||||
}
|
||||
if plex_type or self.plex_type:
|
||||
params['plex_type'] = plex_type or self.plex_type
|
||||
if not synched:
|
||||
# No item to be found in the Kodi DB
|
||||
params['synched'] = 'false'
|
||||
|
|
|
@ -165,6 +165,7 @@ PLEX_TYPE_VIDEO = 'video'
|
|||
PLEX_TYPE_MOVIE = 'movie'
|
||||
PLEX_TYPE_CLIP = 'clip' # e.g. trailers
|
||||
PLEX_TYPE_SET = 'collection' # sets/collections
|
||||
PLEX_TYPE_GENRE = 'genre'
|
||||
PLEX_TYPE_MIXED = 'mixed'
|
||||
|
||||
PLEX_TYPE_EPISODE = 'episode'
|
||||
|
@ -201,7 +202,7 @@ KODI_PLAYLIST_TYPE_FROM_PLEX_PLAYLIST_TYPE = {
|
|||
KODI_TYPE_VIDEO = 'video'
|
||||
KODI_TYPE_MOVIE = 'movie'
|
||||
KODI_TYPE_SET = 'set' # for movie sets of several movies
|
||||
KODI_TYPE_CLIP = 'clip' # e.g. trailers
|
||||
KODI_TYPE_CLIP = 'video' # e.g. trailers
|
||||
|
||||
KODI_TYPE_EPISODE = 'episode'
|
||||
KODI_TYPE_SEASON = 'season'
|
||||
|
@ -216,6 +217,24 @@ KODI_TYPE_MUSICVIDEO = 'musicvideo'
|
|||
KODI_TYPE_PHOTO = 'photo'
|
||||
|
||||
KODI_TYPE_PLAYLIST = 'playlist'
|
||||
KODI_TYPE_GENRE = 'genre'
|
||||
|
||||
# Kodi content types, primarily used for xbmcplugin.setContent()
|
||||
CONTENT_TYPE_MOVIE = 'movies'
|
||||
CONTENT_TYPE_SHOW = 'tvshows'
|
||||
CONTENT_TYPE_SEASON = 'seasons'
|
||||
CONTENT_TYPE_EPISODE = 'episodes'
|
||||
CONTENT_TYPE_ARTIST = 'artists'
|
||||
CONTENT_TYPE_ALBUM = 'albums'
|
||||
CONTENT_TYPE_SONG = 'songs'
|
||||
CONTENT_TYPE_CLIP = 'movies'
|
||||
CONTENT_TYPE_SET = 'sets'
|
||||
CONTENT_TYPE_PHOTO = 'photos'
|
||||
CONTENT_TYPE_GENRE = 'genres'
|
||||
CONTENT_TYPE_VIDEO = 'videos'
|
||||
CONTENT_TYPE_PLAYLIST = 'playlists'
|
||||
CONTENT_TYPE_FILE = 'files'
|
||||
|
||||
|
||||
KODI_VIDEOTYPES = (
|
||||
KODI_TYPE_VIDEO,
|
||||
|
@ -306,7 +325,6 @@ PLEX_TYPE_FROM_KODI_TYPE = {
|
|||
KODI_TYPE_EPISODE: PLEX_TYPE_EPISODE,
|
||||
KODI_TYPE_SEASON: PLEX_TYPE_SEASON,
|
||||
KODI_TYPE_SHOW: PLEX_TYPE_SHOW,
|
||||
KODI_TYPE_CLIP: PLEX_TYPE_CLIP,
|
||||
KODI_TYPE_ARTIST: PLEX_TYPE_ARTIST,
|
||||
KODI_TYPE_ALBUM: PLEX_TYPE_ALBUM,
|
||||
KODI_TYPE_SONG: PLEX_TYPE_SONG,
|
||||
|
@ -418,24 +436,29 @@ PLEX_TYPE_NUMBER_FROM_PLEX_TYPE = {
|
|||
PLEX_TYPE_ALBUM: 9,
|
||||
PLEX_TYPE_SONG: 10,
|
||||
PLEX_TYPE_CLIP: 12,
|
||||
'playlist': 15,
|
||||
PLEX_TYPE_PLAYLIST: 15,
|
||||
PLEX_TYPE_SET: 18
|
||||
}
|
||||
|
||||
|
||||
# To be used with e.g. Kodi Widgets
|
||||
MEDIATYPE_FROM_PLEX_TYPE = {
|
||||
PLEX_TYPE_MOVIE: 'movies',
|
||||
PLEX_TYPE_SHOW: 'tvshows',
|
||||
PLEX_TYPE_SEASON: 'tvshows',
|
||||
PLEX_TYPE_EPISODE: 'episodes',
|
||||
PLEX_TYPE_ARTIST: 'artists',
|
||||
PLEX_TYPE_ALBUM: 'albumbs',
|
||||
PLEX_TYPE_SONG: 'songs',
|
||||
PLEX_TYPE_CLIP: 'videos',
|
||||
PLEX_TYPE_SET: 'movies',
|
||||
PLEX_TYPE_PHOTO: 'photos',
|
||||
'mixed': 'tvshows',
|
||||
CONTENT_FROM_PLEX_TYPE = {
|
||||
PLEX_TYPE_MOVIE: CONTENT_TYPE_MOVIE,
|
||||
PLEX_TYPE_SHOW: CONTENT_TYPE_SHOW,
|
||||
PLEX_TYPE_SEASON: CONTENT_TYPE_SEASON,
|
||||
PLEX_TYPE_EPISODE: CONTENT_TYPE_EPISODE,
|
||||
PLEX_TYPE_ARTIST: CONTENT_TYPE_ARTIST,
|
||||
PLEX_TYPE_ALBUM: CONTENT_TYPE_ALBUM,
|
||||
PLEX_TYPE_SONG: CONTENT_TYPE_SONG,
|
||||
PLEX_TYPE_CLIP: CONTENT_TYPE_CLIP,
|
||||
PLEX_TYPE_SET: CONTENT_TYPE_SET,
|
||||
PLEX_TYPE_PHOTO: CONTENT_TYPE_PHOTO,
|
||||
PLEX_TYPE_GENRE: CONTENT_TYPE_GENRE,
|
||||
PLEX_TYPE_VIDEO: CONTENT_TYPE_VIDEO,
|
||||
PLEX_TYPE_PLAYLIST: CONTENT_TYPE_PLAYLIST,
|
||||
PLEX_TYPE_CHANNEL: CONTENT_TYPE_FILE,
|
||||
'mixed': CONTENT_TYPE_SHOW,
|
||||
None: CONTENT_TYPE_FILE
|
||||
}
|
||||
|
||||
KODI_TO_PLEX_ARTWORK = {
|
||||
|
|
|
@ -80,6 +80,21 @@ def generate_item(api):
|
|||
def _generate_folder(api):
|
||||
'''Generates "folder"/"directory" items that user can further navigate'''
|
||||
art = api.artwork()
|
||||
typus = ''
|
||||
if api.plex_type == v.PLEX_TYPE_GENRE:
|
||||
# Unfortunately, 'genre' is not yet supported by Kodi
|
||||
# typus = v.KODI_TYPE_GENRE
|
||||
pass
|
||||
elif api.plex_type == v.PLEX_TYPE_SHOW:
|
||||
typus = v.KODI_TYPE_SHOW
|
||||
elif api.plex_type == v.PLEX_TYPE_SEASON:
|
||||
typus = v.KODI_TYPE_SEASON
|
||||
elif api.plex_type == v.PLEX_TYPE_ARTIST:
|
||||
typus = v.KODI_TYPE_ARTIST
|
||||
elif api.plex_type == v.PLEX_TYPE_ALBUM:
|
||||
typus = v.KODI_TYPE_ALBUM
|
||||
elif api.fast_key and '?collection=' in api.fast_key:
|
||||
typus = v.KODI_TYPE_SET
|
||||
return {
|
||||
'title': api.title(),
|
||||
'label': api.title(),
|
||||
|
@ -94,7 +109,7 @@ def _generate_folder(api):
|
|||
'fanart': art['fanart'] if 'fanart' in art else
|
||||
'special://home/addons/%s/fanart.jpg' % v.ADDON_ID},
|
||||
'isFolder': True,
|
||||
'type': '',
|
||||
'type': typus,
|
||||
'IsPlayable': 'false',
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue