Enable Kodi libraries for Plex Music libraries

This commit is contained in:
croneter 2018-07-24 21:04:31 +02:00
parent 777b9e15e4
commit 25d80521c7
5 changed files with 164 additions and 73 deletions

View file

@ -329,8 +329,7 @@ class LibrarySync(Thread):
utils.playlist_xsp(mediatype, foldername, folderid, viewtype) utils.playlist_xsp(mediatype, foldername, folderid, viewtype)
lists.append(foldername) lists.append(foldername)
# Create the video node # Create the video node
if (foldername not in nodes and if foldername not in nodes:
mediatype != v.PLEX_TYPE_ARTIST):
vnodes.viewNode(sorted_views.index(foldername), vnodes.viewNode(sorted_views.index(foldername),
foldername, foldername,
mediatype, mediatype,
@ -362,42 +361,41 @@ class LibrarySync(Thread):
# Update view with new info # Update view with new info
plex_db.updateView(foldername, tagid, folderid) plex_db.updateView(foldername, tagid, folderid)
if mediatype != "artist": if plex_db.getView_byName(current_viewname) is None:
if plex_db.getView_byName(current_viewname) is None: # The tag could be a combined view. Ensure there's
# The tag could be a combined view. Ensure there's # no other tags with the same name before deleting
# no other tags with the same name before deleting # playlist.
# playlist. utils.playlist_xsp(mediatype,
utils.playlist_xsp(mediatype, current_viewname,
current_viewname, folderid,
folderid, current_viewtype,
current_viewtype, True)
True) # Delete video node
# Delete video node if mediatype != "musicvideos":
if mediatype != "musicvideos": vnodes.viewNode(
vnodes.viewNode( indexnumber=sorted_views.index(foldername),
indexnumber=sorted_views.index(foldername), tagname=current_viewname,
tagname=current_viewname, mediatype=mediatype,
mediatype=mediatype, viewtype=current_viewtype,
viewtype=current_viewtype, viewid=folderid,
viewid=folderid, delete=True)
delete=True) # Added new playlist
# Added new playlist if (foldername not in lists and mediatype in
if (foldername not in lists and mediatype in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)):
(v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)): utils.playlist_xsp(mediatype,
utils.playlist_xsp(mediatype, foldername,
foldername, folderid,
folderid, viewtype)
viewtype) lists.append(foldername)
lists.append(foldername) # Add new video node
# Add new video node if foldername not in nodes and mediatype != "musicvideos":
if foldername not in nodes and mediatype != "musicvideos": vnodes.viewNode(sorted_views.index(foldername),
vnodes.viewNode(sorted_views.index(foldername), foldername,
foldername, mediatype,
mediatype, viewtype,
viewtype, folderid)
folderid) nodes.append(foldername)
nodes.append(foldername) totalnodes += 1
totalnodes += 1
# Update items with new tag # Update items with new tag
items = plex_db.getItem_byView(folderid) items = plex_db.getItem_byView(folderid)
@ -407,23 +405,22 @@ class LibrarySync(Thread):
current_tagid, tagid, item[0], current_viewtype[:-1]) current_tagid, tagid, item[0], current_viewtype[:-1])
else: else:
# Validate the playlist exists or recreate it # Validate the playlist exists or recreate it
if mediatype != v.PLEX_TYPE_ARTIST: if (foldername not in lists and mediatype in
if (foldername not in lists and mediatype in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)):
(v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)): utils.playlist_xsp(mediatype,
utils.playlist_xsp(mediatype, foldername,
foldername, folderid,
folderid, viewtype)
viewtype) lists.append(foldername)
lists.append(foldername) # Create the video node if not already exists
# Create the video node if not already exists if foldername not in nodes and mediatype != "musicvideos":
if foldername not in nodes and mediatype != "musicvideos": vnodes.viewNode(sorted_views.index(foldername),
vnodes.viewNode(sorted_views.index(foldername), foldername,
foldername, mediatype,
mediatype, viewtype,
viewtype, folderid)
folderid) nodes.append(foldername)
nodes.append(foldername) totalnodes += 1
totalnodes += 1
return totalnodes return totalnodes
def maintain_views(self): def maintain_views(self):
@ -454,7 +451,8 @@ class LibrarySync(Thread):
for view in sections: for view in sections:
if (view.attrib['type'] in if (view.attrib['type'] in
(v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW, v.PLEX_TYPE_PHOTO)): (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW, v.PLEX_TYPE_PHOTO,
v.PLEX_TYPE_ARTIST)):
self.sorted_views.append(view.attrib['title']) self.sorted_views.append(view.attrib['title'])
LOG.debug('Sorted views: %s', self.sorted_views) LOG.debug('Sorted views: %s', self.sorted_views)

View file

@ -69,14 +69,19 @@ def playback_triage(plex_id=None, plex_type=None, path=None, resolve=True):
try: try:
pos = js.get_position(playqueue.playlistid) pos = js.get_position(playqueue.playlistid)
except KeyError: except KeyError:
LOG.error('Still no position - abort') LOG.info('Assuming video instead of audio playlist playback')
# "Play error" playqueue = PQ.get_playqueue_from_type(v.KODI_PLAYLIST_TYPE_VIDEO)
utils.dialog('notification', try:
utils.lang(29999), pos = js.get_position(playqueue.playlistid)
utils.lang(30128), except KeyError:
icon='{error}') LOG.error('Still no position - abort')
_ensure_resolve(abort=True) # "Play error"
return utils.dialog('notification',
utils.lang(29999),
utils.lang(30128),
icon='{error}')
_ensure_resolve(abort=True)
return
# HACK to detect playback of playlists for add-on paths # HACK to detect playback of playlists for add-on paths
items = js.playlist_get_items(playqueue.playlistid) items = js.playlist_get_items(playqueue.playlistid)
try: try:

View file

@ -313,7 +313,8 @@ def verify_kodi_item(plex_id, kodi_item):
LOG.debug('Detected song. Research results: %s', kodi_item) LOG.debug('Detected song. Research results: %s', kodi_item)
return kodi_item return kodi_item
# Need more info since we don't have kodi_id nor type. Use file path. # Need more info since we don't have kodi_id nor type. Use file path.
if (kodi_item['file'].startswith('plugin') or if ((kodi_item['file'].startswith('plugin') and
not kodi_item['file'].startswith('plugin://%s' % v.ADDON_ID)) or
kodi_item['file'].startswith('http')): kodi_item['file'].startswith('http')):
LOG.info('kodi_item %s cannot be used for Plex playback', kodi_item) LOG.info('kodi_item %s cannot be used for Plex playback', kodi_item)
raise PlaylistError raise PlaylistError

View file

@ -1474,6 +1474,9 @@ class API(object):
# Only set the bare minimum of artwork # Only set the bare minimum of artwork
listitem.setArt({'icon': 'DefaultPicture.png', listitem.setArt({'icon': 'DefaultPicture.png',
'fanart': self.one_artwork('thumb')}) 'fanart': self.one_artwork('thumb')})
elif self.plex_type() == v.PLEX_TYPE_SONG:
listitem = self._create_audio_listitem(listitem)
listitem.setArt(self.artwork())
else: else:
listitem = self._create_video_listitem(listitem, listitem = self._create_video_listitem(listitem,
append_show_title, append_show_title,
@ -1596,6 +1599,74 @@ class API(object):
pass pass
return listitem return listitem
def track_number(self):
"""
Returns the song's track number as an int or None if not found
"""
try:
return int(self.item.get('index'))
except TypeError:
pass
def disc_number(self):
"""
Returns the song's disc number as an int or None if not found
"""
try:
return int(self.item.get('parentIndex'))
except TypeError:
pass
def _create_audio_listitem(self, listitem=None):
"""
Use for songs only
Call on a child level of PMS xml response (e.g. in a for loop)
listitem : existing xbmcgui.ListItem to work with
otherwise, a new one is created
Returns XBMC listitem for this PMS library item
"""
if listitem is None:
listitem = ListItem(self.title())
else:
listitem.setLabel(self.title())
listitem.setProperty('IsPlayable', 'true')
userdata = self.userdata()
metadata = {
'mediatype': 'song',
'tracknumber': self.track_number(),
'discnumber': self.track_number(),
'duration': userdata['Runtime'],
'year': self.year(),
# Kodi does not support list of str
'genre': ','.join(self.genre_list()) or None,
'album': self.item.get('parentTitle'),
'artist': self.item.get('originalTitle') or self.grandparent_title(),
'title': self.title(),
'rating': self.audience_rating(),
'playcount': userdata['PlayCount'],
'lastplayed': userdata['LastPlayedDate'],
# lyrics string (On a dark desert highway...)
# userrating integer - range is 1..10
# comment string (This is a great song)
# listeners integer (25614)
# musicbrainztrackid string (cd1de9af-0b71-4503-9f96-9f5efe27923c)
# musicbrainzartistid string (d87e52c5-bb8d-4da8-b941-9f4928627dc8)
# musicbrainzalbumid string (24944755-2f68-3778-974e-f572a9e30108)
# musicbrainzalbumartistid string (d87e52c5-bb8d-4da8-b941-9f4928627dc8)
}
plex_id = self.plex_id()
listitem.setProperty('plexid', plex_id)
if v.KODIVERSION >= 18:
with plexdb.Get_Plex_DB() as plex_db:
kodi_id = plex_db.getItem_byId(plex_id)
if kodi_id:
kodi_id = kodi_id[0]
metadata['dbid'] = kodi_id
listitem.setInfo('music', infoLabels=metadata)
return listitem
def add_video_streams(self, listitem): def add_video_streams(self, listitem):
""" """
Add media stream information to xbmcgui.ListItem Add media stream information to xbmcgui.ListItem

View file

@ -54,7 +54,8 @@ class VideoNodes(object):
'show': 'tvshows', 'show': 'tvshows',
'photo': 'photos', 'photo': 'photos',
'homevideo': 'homevideos', 'homevideo': 'homevideos',
'musicvideos': 'musicvideos' 'musicvideos': 'musicvideos',
'artist': 'albums'
} }
mediatype = mediatypes[mediatype] mediatype = mediatypes[mediatype]
@ -196,6 +197,15 @@ class VideoNodes(object):
'4': 30257, '4': 30257,
'6': 30258, '6': 30258,
'13': 39702 '13': 39702
},
'albums':
{
'1': tagname,
'2': 517, # Recently played albums
'2': 359, # Recently added albums
'13': 39702, # browse by folder
'14': 136 # Playlists
} }
} }
@ -317,17 +327,23 @@ class VideoNodes(object):
label=label, label=label,
tagname=tagname, tagname=tagname,
roottype=2) roottype=2)
etree.SubElement(root, 'path').text = path
etree.SubElement(root, 'content').text = "episodes"
else: else:
root = self.commonRoot(order=sortorder[node], root = self.commonRoot(order=sortorder[node],
label=label, label=label,
tagname=tagname) tagname=tagname)
if nodetype in ('recentepisodes', 'inprogressepisodes'): # Set the content type
etree.SubElement(root, 'content').text = "episodes" if mediatype == 'tvshows':
else: etree.SubElement(root, 'content').text = 'episodes'
etree.SubElement(root, 'content').text = mediatype else:
etree.SubElement(root, 'content').text = mediatype
# Now fill the view
if (nodetype in ("nextepisodes",
"ondeck",
'recentepisodes',
'browsefiles',
'playlists') or mediatype == "homevideos"):
etree.SubElement(root, 'path').text = path
else:
# Elements per nodetype # Elements per nodetype
if nodetype == "all": if nodetype == "all":
etree.SubElement(root, etree.SubElement(root,