diff --git a/default.py b/default.py index 2c86d9c9..aff4148d 100644 --- a/default.py +++ b/default.py @@ -69,7 +69,8 @@ class Main: 'deviceid': entrypoint.resetDeviceId, 'reConnect': entrypoint.reConnect, 'delete': entrypoint.deleteItem, - 'browseplex': entrypoint.BrowsePlexContent + 'browseplex': entrypoint.BrowsePlexContent, + 'ondeck': entrypoint.getOnDeck } if "/extrafanart" in sys.argv[0]: @@ -105,6 +106,13 @@ class Main: params.get('type', [""])[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": folderid = params['folderid'][0] modes[mode](itemid, folderid) diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml index 8dcbb467..f8173e3e 100644 --- a/resources/language/English/strings.xml +++ b/resources/language/English/strings.xml @@ -148,7 +148,7 @@ In Progress TV Shows All Music Channels - Recently Added Movies + Recently Added Recently Added Episodes Recently Added Albums In Progress Movies @@ -203,10 +203,10 @@ Use Kodi Sorting Runtime - Random Movies - Random Episodes + Random + Recently releases Random Items - Recommended Items + Recommended Extras Sync Theme Music @@ -411,8 +411,4 @@ Full library sync finished 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. - - On Deck - - diff --git a/resources/language/German/strings.xml b/resources/language/German/strings.xml index 25ed4e97..8eb91d7c 100644 --- a/resources/language/German/strings.xml +++ b/resources/language/German/strings.xml @@ -176,7 +176,7 @@ Begonnene Serien Alles an Musik Kanäle - Zuletzt hinzugefügte Filme + Zuletzt hinzugefügt Zuletzt hinzugefügte Episoden Zuletzt hinzugefügte Alben Begonnene Filme @@ -231,8 +231,10 @@ Benutze Kodi Sortierung Laufzeit - Zufällige Filme - Zufällige Episoden + Zufällig + Kürzlich veröffentlicht + Empfohlen + Extras Synchronisiere Themen-Musik @@ -343,7 +345,4 @@ Plex Bibliotheken aktualisiert 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. - - Aktuell - diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index 9682cbae..39296a16 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -671,19 +671,12 @@ def GetSubFolders(nodeindex): ##### BROWSE EMBY NODES DIRECTLY ##### 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() art = artwork.Artwork() doUtils = downloadutils.DownloadUtils() #folderid used as filter ? - if folderid in ["recent","recentepisodes","inprogress","inprogressepisodes","unwatched","nextepisodes","sets","genres","random","recommended", - "ondeck"]: + if folderid in ["recent","recentepisodes","inprogress","inprogressepisodes","unwatched","nextepisodes","sets","genres","random","recommended"]: filter = folderid folderid = "" else: @@ -1348,3 +1341,122 @@ def BrowsePlexContent(viewid, mediatype="", nodetype=""): xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RUNTIME) 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])) diff --git a/resources/lib/videonodes.py b/resources/lib/videonodes.py index 460beb96..4d742e35 100644 --- a/resources/lib/videonodes.py +++ b/resources/lib/videonodes.py @@ -42,6 +42,8 @@ class VideoNodes(object): def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False): # Plex: reassign mediatype due to Kodi inner workings + # How many items do we get at most? + limit = "100" mediatypes = { 'movie': 'movies', 'show': 'tvshows', @@ -135,26 +137,27 @@ class VideoNodes(object): { '1': tagname, '2': 30174, - '4': 30177, - '6': 30189, + # '4': 30177, + # '6': 30189, '8': 20434, '9': 135, - '10': 30229, - '11': 30230 + '10': 30227, + '11': 30230, + '12': 39500, }, 'tvshows': { '1': tagname, - '2': 30170, - '3': 30175, - '4': 30171, - '5': 30178, - '7': 30179, + # '2': 30170, + '3': 30174, + # '4': 30171, + # '5': 30178, + # '7': 30179, '9': 135, - '10': 30229, - '11': 30230, - '12': 39500 + '10': 30227, + # '11': 30230, + '12': 39500, }, '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] for node in nodes: @@ -206,17 +225,21 @@ class VideoNodes(object): % (tagname, mediatype, nodetype)) elif nodetype == "nextepisodes": # 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": # 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": # 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': # PLEX custom query - path = ("plugin://plugin.video.plexkodiconnect/?id=%s&mode=browseplex&type=%s&folderid=%s" - % (viewid, mediatype, nodetype)) + if mediatype == "tvshows": + 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: 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 (kodiversion == 14 and nodetype in ('recentepisodes', 'inprogressepisodes'))): # 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, 'content').text = "episodes" 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'): etree.SubElement(root, 'content').text = "episodes" else: etree.SubElement(root, 'content').text = mediatype - limit = "50" # Elements per nodetype if nodetype == "all": etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle" @@ -317,7 +339,7 @@ class VideoNodes(object): elif nodetype == "inprogressepisodes": # Kodi Isengard, Jarvis - etree.SubElement(root, 'limit').text = "50" + etree.SubElement(root, 'limit').text = limit rule = etree.SubElement(root, 'rule', attrib={'field': "inprogress", 'operator':"true"})