Merge pull request #917 from croneter/fix-skin

Ensure correct Kodi Container.Type is set for PKC widgets
This commit is contained in:
croneter 2019-07-07 18:09:21 +02:00 committed by GitHub
commit 53139a7e45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 216 additions and 135 deletions

View file

@ -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()

View file

@ -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)

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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):
"""

View file

@ -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'

View file

@ -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 = {

View file

@ -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',
}