Replicate Plex views in video nodes
This commit is contained in:
parent
6cd9777e9e
commit
e7986e6289
5 changed files with 181 additions and 44 deletions
10
default.py
10
default.py
|
@ -69,7 +69,8 @@ class Main:
|
||||||
'deviceid': entrypoint.resetDeviceId,
|
'deviceid': entrypoint.resetDeviceId,
|
||||||
'reConnect': entrypoint.reConnect,
|
'reConnect': entrypoint.reConnect,
|
||||||
'delete': entrypoint.deleteItem,
|
'delete': entrypoint.deleteItem,
|
||||||
'browseplex': entrypoint.BrowsePlexContent
|
'browseplex': entrypoint.BrowsePlexContent,
|
||||||
|
'ondeck': entrypoint.getOnDeck
|
||||||
}
|
}
|
||||||
|
|
||||||
if "/extrafanart" in sys.argv[0]:
|
if "/extrafanart" in sys.argv[0]:
|
||||||
|
@ -105,6 +106,13 @@ class Main:
|
||||||
params.get('type', [""])[0],
|
params.get('type', [""])[0],
|
||||||
params.get('folderid', [""])[0])
|
params.get('folderid', [""])[0])
|
||||||
|
|
||||||
|
elif mode == 'ondeck':
|
||||||
|
modes[mode](
|
||||||
|
itemid,
|
||||||
|
params.get('type', [""])[0],
|
||||||
|
params.get('tagname', [""])[0],
|
||||||
|
params.get('limit', [""])[0])
|
||||||
|
|
||||||
elif mode == "channelsfolder":
|
elif mode == "channelsfolder":
|
||||||
folderid = params['folderid'][0]
|
folderid = params['folderid'][0]
|
||||||
modes[mode](itemid, folderid)
|
modes[mode](itemid, folderid)
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
<string id="30171">In Progress TV Shows</string><!-- Verified -->
|
<string id="30171">In Progress TV Shows</string><!-- Verified -->
|
||||||
<string id="30172">All Music</string>
|
<string id="30172">All Music</string>
|
||||||
<string id="30173">Channels</string><!-- Verified -->
|
<string id="30173">Channels</string><!-- Verified -->
|
||||||
<string id="30174">Recently Added Movies</string><!-- Verified -->
|
<string id="30174">Recently Added</string><!-- Verified -->
|
||||||
<string id="30175">Recently Added Episodes</string><!-- Verified -->
|
<string id="30175">Recently Added Episodes</string><!-- Verified -->
|
||||||
<string id="30176">Recently Added Albums</string>
|
<string id="30176">Recently Added Albums</string>
|
||||||
<string id="30177">In Progress Movies</string><!-- Verified -->
|
<string id="30177">In Progress Movies</string><!-- Verified -->
|
||||||
|
@ -203,10 +203,10 @@
|
||||||
<string id="30225">Use Kodi Sorting</string>
|
<string id="30225">Use Kodi Sorting</string>
|
||||||
<string id="30226">Runtime</string>
|
<string id="30226">Runtime</string>
|
||||||
|
|
||||||
<string id="30227">Random Movies</string>
|
<string id="30227">Random</string>
|
||||||
<string id="30228">Random Episodes</string>
|
<string id="30228">Recently releases</string>
|
||||||
<string id="30229">Random Items</string><!-- Verified -->
|
<string id="30229">Random Items</string><!-- Verified -->
|
||||||
<string id="30230">Recommended Items</string><!-- Verified -->
|
<string id="30230">Recommended</string><!-- Verified -->
|
||||||
|
|
||||||
<string id="30235">Extras</string><!-- Verified -->
|
<string id="30235">Extras</string><!-- Verified -->
|
||||||
<string id="30236">Sync Theme Music</string>
|
<string id="30236">Sync Theme Music</string>
|
||||||
|
@ -411,8 +411,4 @@
|
||||||
<string id="39407">Full library sync finished</string>
|
<string id="39407">Full library sync finished</string>
|
||||||
<string id="39408">Sync had to skip some items because they could not be processed. Kodi may be instable now!! Please post your Kodi logs to the Plex forum.</string>
|
<string id="39408">Sync had to skip some items because they could not be processed. Kodi may be instable now!! Please post your Kodi logs to the Plex forum.</string>
|
||||||
|
|
||||||
<!-- Plex videonodes.py -->
|
|
||||||
<string id="39500">On Deck</string>
|
|
||||||
|
|
||||||
|
|
||||||
</strings>
|
</strings>
|
||||||
|
|
|
@ -176,7 +176,7 @@
|
||||||
<string id="30171">Begonnene Serien</string>
|
<string id="30171">Begonnene Serien</string>
|
||||||
<string id="30172">Alles an Musik</string>
|
<string id="30172">Alles an Musik</string>
|
||||||
<string id="30173">Kanäle</string>
|
<string id="30173">Kanäle</string>
|
||||||
<string id="30174">Zuletzt hinzugefügte Filme</string>
|
<string id="30174">Zuletzt hinzugefügt</string> <!-- Movies -->
|
||||||
<string id="30175">Zuletzt hinzugefügte Episoden</string>
|
<string id="30175">Zuletzt hinzugefügte Episoden</string>
|
||||||
<string id="30176">Zuletzt hinzugefügte Alben</string>
|
<string id="30176">Zuletzt hinzugefügte Alben</string>
|
||||||
<string id="30177">Begonnene Filme</string>
|
<string id="30177">Begonnene Filme</string>
|
||||||
|
@ -231,8 +231,10 @@
|
||||||
<string id="30225">Benutze Kodi Sortierung</string>
|
<string id="30225">Benutze Kodi Sortierung</string>
|
||||||
<string id="30226">Laufzeit</string>
|
<string id="30226">Laufzeit</string>
|
||||||
|
|
||||||
<string id="30227">Zufällige Filme</string>
|
<string id="30227">Zufällig</string>
|
||||||
<string id="30228">Zufällige Episoden</string>
|
<string id="30228">Kürzlich veröffentlicht</string>
|
||||||
|
<string id="30230">Empfohlen</string>
|
||||||
|
|
||||||
|
|
||||||
<string id="30235">Extras</string>
|
<string id="30235">Extras</string>
|
||||||
<string id="30236">Synchronisiere Themen-Musik</string>
|
<string id="30236">Synchronisiere Themen-Musik</string>
|
||||||
|
@ -343,7 +345,4 @@
|
||||||
<string id="39407">Plex Bibliotheken aktualisiert</string>
|
<string id="39407">Plex Bibliotheken aktualisiert</string>
|
||||||
<string id="39408">Einige Plex Einträge mussten übersprungen werden, da sie nicht verarbeitet werden konnten. Kodi ist nun möglicherweise instabil!! Bitte teilen Sie Ihr Kodi log im Plex Forum.</string>
|
<string id="39408">Einige Plex Einträge mussten übersprungen werden, da sie nicht verarbeitet werden konnten. Kodi ist nun möglicherweise instabil!! Bitte teilen Sie Ihr Kodi log im Plex Forum.</string>
|
||||||
|
|
||||||
<!-- Plex videonodes.py -->
|
|
||||||
<string id="39500">Aktuell</string>
|
|
||||||
|
|
||||||
</strings>
|
</strings>
|
||||||
|
|
|
@ -671,19 +671,12 @@ def GetSubFolders(nodeindex):
|
||||||
|
|
||||||
##### BROWSE EMBY NODES DIRECTLY #####
|
##### BROWSE EMBY NODES DIRECTLY #####
|
||||||
def BrowseContent(viewname, type="", folderid=""):
|
def BrowseContent(viewname, type="", folderid=""):
|
||||||
"""
|
|
||||||
Plex:
|
|
||||||
viewname: PMS name of the library
|
|
||||||
type: PMS library section ID
|
|
||||||
folderid: e.g. 'ondeck'
|
|
||||||
"""
|
|
||||||
emby = embyserver.Read_EmbyServer()
|
emby = embyserver.Read_EmbyServer()
|
||||||
art = artwork.Artwork()
|
art = artwork.Artwork()
|
||||||
doUtils = downloadutils.DownloadUtils()
|
doUtils = downloadutils.DownloadUtils()
|
||||||
|
|
||||||
#folderid used as filter ?
|
#folderid used as filter ?
|
||||||
if folderid in ["recent","recentepisodes","inprogress","inprogressepisodes","unwatched","nextepisodes","sets","genres","random","recommended",
|
if folderid in ["recent","recentepisodes","inprogress","inprogressepisodes","unwatched","nextepisodes","sets","genres","random","recommended"]:
|
||||||
"ondeck"]:
|
|
||||||
filter = folderid
|
filter = folderid
|
||||||
folderid = ""
|
folderid = ""
|
||||||
else:
|
else:
|
||||||
|
@ -1348,3 +1341,122 @@ def BrowsePlexContent(viewid, mediatype="", nodetype=""):
|
||||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RUNTIME)
|
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RUNTIME)
|
||||||
|
|
||||||
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
||||||
|
|
||||||
|
|
||||||
|
def getOnDeck(viewid, mediatype, tagname, limit):
|
||||||
|
"""
|
||||||
|
Retrieves Plex On Deck items, currently only for TV shows
|
||||||
|
|
||||||
|
Input:
|
||||||
|
viewid: Plex id of the library section, e.g. '1'
|
||||||
|
mediatype: Kodi mediatype, e.g. 'tvshows', 'movies',
|
||||||
|
'homevideos', 'photos'
|
||||||
|
tagname: Name of the Plex library, e.g. "My Movies"
|
||||||
|
limit: Max. number of items to retrieve, e.g. '50'
|
||||||
|
"""
|
||||||
|
# if the addon is called with nextup parameter,
|
||||||
|
# we return the nextepisodes list of the given tagname
|
||||||
|
xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
|
||||||
|
# First we get a list of all the TV shows - filtered by tag
|
||||||
|
query = {
|
||||||
|
'jsonrpc': "2.0",
|
||||||
|
'id': "libTvShows",
|
||||||
|
'method': "VideoLibrary.GetTVShows",
|
||||||
|
'params': {
|
||||||
|
'sort': {'order': "descending", 'method': "lastplayed"},
|
||||||
|
'filter': {
|
||||||
|
'and': [
|
||||||
|
{'operator': "true", 'field': "inprogress", 'value': ""},
|
||||||
|
{'operator': "is", 'field': "tag", 'value': "%s" % tagname}
|
||||||
|
]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = xbmc.executeJSONRPC(json.dumps(query))
|
||||||
|
result = json.loads(result)
|
||||||
|
utils.logMsg('test', 'result: %s' % result, 1)
|
||||||
|
# If we found any, find the oldest unwatched show for each one.
|
||||||
|
try:
|
||||||
|
items = result['result'][mediatype]
|
||||||
|
except (KeyError, TypeError):
|
||||||
|
# Now items retrieved - empty directory
|
||||||
|
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
||||||
|
return
|
||||||
|
|
||||||
|
query = {
|
||||||
|
'jsonrpc': "2.0",
|
||||||
|
'id': 1,
|
||||||
|
'method': "VideoLibrary.GetEpisodes",
|
||||||
|
'params': {
|
||||||
|
'sort': {'method': "episode"},
|
||||||
|
'limits': {"end": 1},
|
||||||
|
'properties': [
|
||||||
|
"title", "playcount", "season", "episode", "showtitle",
|
||||||
|
"plot", "file", "rating", "resume", "tvshowid", "art",
|
||||||
|
"streamdetails", "firstaired", "runtime", "cast", "writer",
|
||||||
|
"dateadded", "lastplayed"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if utils.settings('ignoreSpecialsNextEpisodes') == "true":
|
||||||
|
query['params']['filter'] = {
|
||||||
|
'and': [
|
||||||
|
{'operator': "lessthan", 'field': "playcount", 'value': "1"},
|
||||||
|
{'operator': "greaterthan", 'field': "season", 'value': "0"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
query['params']['filter'] = {
|
||||||
|
'or': [
|
||||||
|
{'operator': "lessthan", 'field': "playcount", 'value': "1"},
|
||||||
|
{'operator': "true", 'field': "inprogress", 'value': ""}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Are there any episodes still in progress/not yet finished watching?!?
|
||||||
|
# Then we should show this episode, NOT the "next up"
|
||||||
|
inprogrQuery = {
|
||||||
|
'jsonrpc': "2.0",
|
||||||
|
'id': 1,
|
||||||
|
'method': "VideoLibrary.GetEpisodes",
|
||||||
|
'params': {
|
||||||
|
'sort': {'method': "episode"},
|
||||||
|
'filter': {'operator': "true", 'field': "inprogress", 'value': ""},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inprogrQuery['params']['properties'] = query['params']['properties']
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for item in items:
|
||||||
|
inprogrQuery['params']['tvshowid'] = item['tvshowid']
|
||||||
|
result = xbmc.executeJSONRPC(json.dumps(inprogrQuery))
|
||||||
|
result = json.loads(result)
|
||||||
|
utils.logMsg('test', 'result: %s' % result, 1)
|
||||||
|
try:
|
||||||
|
episodes = result['result']['episodes']
|
||||||
|
except (KeyError, TypeError):
|
||||||
|
# No, there are no episodes not yet finished. Get "next up"
|
||||||
|
query['params']['tvshowid'] = item['tvshowid']
|
||||||
|
result = xbmc.executeJSONRPC(json.dumps(query))
|
||||||
|
result = json.loads(result)
|
||||||
|
try:
|
||||||
|
episodes = result['result']['episodes']
|
||||||
|
except (KeyError, TypeError):
|
||||||
|
# Also no episodes currently coming up
|
||||||
|
continue
|
||||||
|
utils.logMsg('test', 'results: %s' % episodes, 1)
|
||||||
|
for episode in episodes:
|
||||||
|
# There will always be only 1 episode ('limit=1')
|
||||||
|
utils.logMsg('test', 'episode: %s' % episode, 1)
|
||||||
|
li = createListItem(episode)
|
||||||
|
xbmcplugin.addDirectoryItem(
|
||||||
|
handle=int(sys.argv[1]),
|
||||||
|
url=episode['file'],
|
||||||
|
listitem=li,
|
||||||
|
isFolder=False)
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
if count >= limit:
|
||||||
|
break
|
||||||
|
|
||||||
|
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
||||||
|
|
|
@ -42,6 +42,8 @@ class VideoNodes(object):
|
||||||
|
|
||||||
def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False):
|
def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False):
|
||||||
# Plex: reassign mediatype due to Kodi inner workings
|
# Plex: reassign mediatype due to Kodi inner workings
|
||||||
|
# How many items do we get at most?
|
||||||
|
limit = "100"
|
||||||
mediatypes = {
|
mediatypes = {
|
||||||
'movie': 'movies',
|
'movie': 'movies',
|
||||||
'show': 'tvshows',
|
'show': 'tvshows',
|
||||||
|
@ -135,26 +137,27 @@ class VideoNodes(object):
|
||||||
{
|
{
|
||||||
'1': tagname,
|
'1': tagname,
|
||||||
'2': 30174,
|
'2': 30174,
|
||||||
'4': 30177,
|
# '4': 30177,
|
||||||
'6': 30189,
|
# '6': 30189,
|
||||||
'8': 20434,
|
'8': 20434,
|
||||||
'9': 135,
|
'9': 135,
|
||||||
'10': 30229,
|
'10': 30227,
|
||||||
'11': 30230
|
'11': 30230,
|
||||||
|
'12': 39500,
|
||||||
},
|
},
|
||||||
|
|
||||||
'tvshows':
|
'tvshows':
|
||||||
{
|
{
|
||||||
'1': tagname,
|
'1': tagname,
|
||||||
'2': 30170,
|
# '2': 30170,
|
||||||
'3': 30175,
|
'3': 30174,
|
||||||
'4': 30171,
|
# '4': 30171,
|
||||||
'5': 30178,
|
# '5': 30178,
|
||||||
'7': 30179,
|
# '7': 30179,
|
||||||
'9': 135,
|
'9': 135,
|
||||||
'10': 30229,
|
'10': 30227,
|
||||||
'11': 30230,
|
# '11': 30230,
|
||||||
'12': 39500
|
'12': 39500,
|
||||||
},
|
},
|
||||||
|
|
||||||
'homevideos':
|
'homevideos':
|
||||||
|
@ -181,6 +184,22 @@ class VideoNodes(object):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Key: nodetypes, value: sort order in Kodi
|
||||||
|
sortorder = {
|
||||||
|
'1': '3', # "all",
|
||||||
|
'2': '2', # "recent",
|
||||||
|
'3': '2', # "recentepisodes",
|
||||||
|
# '4': # "inprogress",
|
||||||
|
# '5': # "inprogressepisodes",
|
||||||
|
# '6': # "unwatched",
|
||||||
|
# '7': # "nextepisodes",
|
||||||
|
'8': '7', # "sets",
|
||||||
|
'9': '6', # "genres",
|
||||||
|
'10': '8', # "random",
|
||||||
|
'11': '5', # "recommended",
|
||||||
|
'12': '1', # "ondeck"
|
||||||
|
}
|
||||||
|
|
||||||
nodes = mediatypes[mediatype]
|
nodes = mediatypes[mediatype]
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
|
|
||||||
|
@ -206,17 +225,21 @@ class VideoNodes(object):
|
||||||
% (tagname, mediatype, nodetype))
|
% (tagname, mediatype, nodetype))
|
||||||
elif nodetype == "nextepisodes":
|
elif nodetype == "nextepisodes":
|
||||||
# Custom query
|
# Custom query
|
||||||
path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=nextup&limit=50" % tagname
|
path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=nextup&limit=%s" % (tagname, limit)
|
||||||
elif kodiversion == 14 and nodetype == "recentepisodes":
|
elif kodiversion == 14 and nodetype == "recentepisodes":
|
||||||
# Custom query
|
# Custom query
|
||||||
path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=recentepisodes&limit=50" % tagname
|
path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=recentepisodes&limit=%s" % (tagname, limit)
|
||||||
elif kodiversion == 14 and nodetype == "inprogressepisodes":
|
elif kodiversion == 14 and nodetype == "inprogressepisodes":
|
||||||
# Custom query
|
# Custom query
|
||||||
path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=inprogressepisodes&limit=50"% tagname
|
path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=inprogressepisodes&limit=%s" % (tagname, limit)
|
||||||
elif nodetype == 'ondeck':
|
elif nodetype == 'ondeck':
|
||||||
# PLEX custom query
|
# PLEX custom query
|
||||||
path = ("plugin://plugin.video.plexkodiconnect/?id=%s&mode=browseplex&type=%s&folderid=%s"
|
if mediatype == "tvshows":
|
||||||
% (viewid, mediatype, nodetype))
|
path = ("plugin://plugin.video.plexkodiconnect/?id=%s&mode=ondeck&type=%s&tagname=%s&limit=%s"
|
||||||
|
% (viewid, mediatype, tagname, limit))
|
||||||
|
elif mediatype =="movies":
|
||||||
|
# Reset nodetype; we got the label
|
||||||
|
nodetype = 'inprogress'
|
||||||
else:
|
else:
|
||||||
path = "library://video/Plex-%s/%s_%s.xml" % (dirname, viewid, nodetype)
|
path = "library://video/Plex-%s/%s_%s.xml" % (dirname, viewid, nodetype)
|
||||||
|
|
||||||
|
@ -257,17 +280,16 @@ class VideoNodes(object):
|
||||||
if (nodetype in ("nextepisodes", "ondeck") or mediatype == "homevideos" or
|
if (nodetype in ("nextepisodes", "ondeck") or mediatype == "homevideos" or
|
||||||
(kodiversion == 14 and nodetype in ('recentepisodes', 'inprogressepisodes'))):
|
(kodiversion == 14 and nodetype in ('recentepisodes', 'inprogressepisodes'))):
|
||||||
# Folder type with plugin path
|
# Folder type with plugin path
|
||||||
root = self.commonRoot(order=node, label=label, tagname=tagname, roottype=2)
|
root = self.commonRoot(order=sortorder[node], label=label, tagname=tagname, roottype=2)
|
||||||
etree.SubElement(root, 'path').text = path
|
etree.SubElement(root, 'path').text = path
|
||||||
etree.SubElement(root, 'content').text = "episodes"
|
etree.SubElement(root, 'content').text = "episodes"
|
||||||
else:
|
else:
|
||||||
root = self.commonRoot(order=node, label=label, tagname=tagname)
|
root = self.commonRoot(order=sortorder[node], label=label, tagname=tagname)
|
||||||
if nodetype in ('recentepisodes', 'inprogressepisodes'):
|
if nodetype in ('recentepisodes', 'inprogressepisodes'):
|
||||||
etree.SubElement(root, 'content').text = "episodes"
|
etree.SubElement(root, 'content').text = "episodes"
|
||||||
else:
|
else:
|
||||||
etree.SubElement(root, 'content').text = mediatype
|
etree.SubElement(root, 'content').text = mediatype
|
||||||
|
|
||||||
limit = "50"
|
|
||||||
# Elements per nodetype
|
# Elements per nodetype
|
||||||
if nodetype == "all":
|
if nodetype == "all":
|
||||||
etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle"
|
etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle"
|
||||||
|
@ -317,7 +339,7 @@ class VideoNodes(object):
|
||||||
|
|
||||||
elif nodetype == "inprogressepisodes":
|
elif nodetype == "inprogressepisodes":
|
||||||
# Kodi Isengard, Jarvis
|
# Kodi Isengard, Jarvis
|
||||||
etree.SubElement(root, 'limit').text = "50"
|
etree.SubElement(root, 'limit').text = limit
|
||||||
rule = etree.SubElement(root, 'rule',
|
rule = etree.SubElement(root, 'rule',
|
||||||
attrib={'field': "inprogress", 'operator':"true"})
|
attrib={'field': "inprogress", 'operator':"true"})
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue