diff --git a/addon.xml b/addon.xml index 45aa64a7..d0f562d3 100644 --- a/addon.xml +++ b/addon.xml @@ -20,7 +20,7 @@ Settings for the Emby Server - !IsEmpty(ListItem.DBID) + [!IsEmpty(ListItem.DBID) + !IsEmpty(ListItem.DBTYPE)] | !IsEmpty(ListItem.Property(embyid)) diff --git a/contextmenu.py b/contextmenu.py index 6346a4c5..619ba149 100644 --- a/contextmenu.py +++ b/contextmenu.py @@ -33,35 +33,30 @@ def logMsg(msg, lvl=1): #Kodi contextmenu item to configure the emby settings #for now used to set ratings but can later be used to sync individual items etc. if __name__ == '__main__': - - itemid = xbmc.getInfoLabel("ListItem.DBID").decode("utf-8") itemtype = xbmc.getInfoLabel("ListItem.DBTYPE").decode("utf-8") + + emby = embyserver.Read_EmbyServer() + + embyid = "" if not itemtype and xbmc.getCondVisibility("Container.Content(albums)"): itemtype = "album" if not itemtype and xbmc.getCondVisibility("Container.Content(artists)"): itemtype = "artist" if not itemtype and xbmc.getCondVisibility("Container.Content(songs)"): itemtype = "song" + if not itemtype and xbmc.getCondVisibility("Container.Content(pictures)"): itemtype = "picture" - logMsg("Contextmenu opened for itemid: %s - itemtype: %s" %(itemid,itemtype)) + if (not itemid or itemid == "-1") and xbmc.getInfoLabel("ListItem.Property(embyid)"): + embyid = xbmc.getInfoLabel("ListItem.Property(embyid)") + else: + embyconn = utils.kodiSQL('emby') + embycursor = embyconn.cursor() + emby_db = embydb.Embydb_Functions(embycursor) + item = emby_db.getItem_byKodiId(itemid, itemtype) + if item: embyid = item[0] - userid = utils.window('emby_currUser') - server = utils.window('emby_server%s' % userid) - embyconn = utils.kodiSQL('emby') - embycursor = embyconn.cursor() - kodiconn = utils.kodiSQL('music') - kodicursor = kodiconn.cursor() - - emby = embyserver.Read_EmbyServer() - emby_db = embydb.Embydb_Functions(embycursor) - kodi_db = kodidb.Kodidb_Functions(kodicursor) - - item = emby_db.getItem_byKodiId(itemid, itemtype) - if item: - embyid = item[0] - + logMsg("Contextmenu opened for embyid: %s - itemtype: %s" %(embyid,itemtype)) + + if embyid: item = emby.getItem(embyid) - - print item - API = api.API(item) userdata = API.getUserData() likes = userdata['Likes'] @@ -105,6 +100,8 @@ if __name__ == '__main__': if options[ret] == utils.language(30406): API.updateUserRating(embyid, favourite=False) if options[ret] == utils.language(30407): + kodiconn = utils.kodiSQL('music') + kodicursor = kodiconn.cursor() query = ' '.join(("SELECT rating", "FROM song", "WHERE idSong = ?" )) kodicursor.execute(query, (itemid,)) currentvalue = int(round(float(kodicursor.fetchone()[0]),0)) diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml index 303c36fc..dc3c60c2 100644 --- a/resources/language/English/strings.xml +++ b/resources/language/English/strings.xml @@ -242,6 +242,11 @@ Enable server connection message on start-up Use local paths instead of addon redirect for playback + Recently added Home Videos + Recently added Photos + Favourite Home Videos + Favourite Photos + Favourite Albums Active diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index 4026c935..80d623ff 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -25,6 +25,7 @@ import playbackutils as pbutils import playutils import api + ################################################################################################# @@ -56,7 +57,6 @@ def addDirectoryItem(label, path, folder=True): xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=folder) def doMainListing(): - xbmcplugin.setContent(int(sys.argv[1]), 'files') # Get emby nodes from the window props embyprops = utils.window('Emby.nodes.total') @@ -67,8 +67,8 @@ def doMainListing(): if not path: path = utils.window('Emby.nodes.%s.content' % i) label = utils.window('Emby.nodes.%s.title' % i) - if path: - print path + type = utils.window('Emby.nodes.%s.type' % i) + if path and ((xbmc.getCondVisibility("Window.IsActive(Pictures)") and type=="photos") or (xbmc.getCondVisibility("Window.IsActive(VideoLibrary)") and type != "photos")): addDirectoryItem(label, path) # some extra entries for settings and stuff. TODO --> localize the labels @@ -402,98 +402,148 @@ def refreshPlaylist(): sound=False) ##### BROWSE EMBY HOMEVIDEOS AND PICTURES ##### -def BrowseContent(viewname, type="", folderid=None, filter=None): +def BrowseContent(viewname, type="", folderid=None, filter=""): - _addon_id = int(sys.argv[1]) - _addon_url = sys.argv[0] - doUtils = downloadutils.DownloadUtils() emby = embyserver.Read_EmbyServer() - art = artwork.Artwork() - utils.logMsg("BrowseHomeVideos","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname, type, folderid, filter),0) - - if type.lower() == "homevideos": - xbmcplugin.setContent(int(sys.argv[1]), 'episodes') - itemtype = "Video" - elif type.lower() == "photos": - xbmcplugin.setContent(int(sys.argv[1]), 'pictures') - itemtype = "Photo" - else: - itemtype = "" - + utils.logMsg("BrowseHomeVideos","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname, type, folderid, filter)) + xbmcplugin.setPluginCategory(int(sys.argv[1]), viewname) + #get views for root level if not folderid: views = emby.getViews(type) for view in views: if view.get("name") == viewname: folderid = view.get("id") - print view - + + #set the correct params for the content type + #only proceed if we have a folderid if folderid: - listing = emby.getSection(folderid).get("Items",[]) + if type.lower() == "homevideos": + xbmcplugin.setContent(int(sys.argv[1]), 'episodes') + itemtype = "Video,Folder,PhotoAlbum" + elif type.lower() == "photos": + xbmcplugin.setContent(int(sys.argv[1]), 'files') + itemtype = "Photo,PhotoAlbum" + else: + itemtype = "" + + #get the actual listing + if filter == "recent": + listing = emby.getFilteredSection("", itemtype=itemtype.split(",")[0], sortby="DateCreated", recursive=True, limit=25, sortorder="Descending").get("Items",[]) + elif filter == "random": + listing = emby.getFilteredSection("", itemtype=itemtype.split(",")[0], sortby="Random", recursive=True, limit=150, sortorder="Descending").get("Items",[]) + elif filter == "recommended": + listing = emby.getFilteredSection("", itemtype=itemtype.split(",")[0], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter="IsFavorite").get("Items",[]) + elif filter == "sets": + listing = emby.getFilteredSection("", itemtype=itemtype.split(",")[1], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter="IsFavorite").get("Items",[]) + else: + listing = emby.getFilteredSection(folderid, itemtype=itemtype, recursive=False).get("Items",[]) + + #process the listing for item in listing: - if item.get("Type") == itemtype or item.get("IsFolder") == True: - API = api.API(item) - itemid = item['Id'] - title = item.get('Name') - li = xbmcgui.ListItem(title) - - premieredate = API.getPremiereDate() - genre = API.getGenres() - overlay = 0 - userdata = API.getUserData() - seektime = userdata['Resume'] - if seektime: - li.setProperty("resumetime", seektime) - li.setProperty("totaltime", item.get("RunTimeTicks")/ 10000000.0) - - played = userdata['Played'] - if played: overlay = 7 - else: overlay = 6 - - favorite = userdata['Favorite'] - if favorite: overlay = 5 - - playcount = userdata['PlayCount'] - if playcount is None: - playcount = 0 - - rating = item.get('CommunityRating') - if not rating: rating = userdata['UserRating'] - - # Populate the extradata list and artwork - pbutils.PlaybackUtils(item).setArtwork(li) - extradata = { - - 'id': itemid, - 'rating': rating, - 'year': item.get('ProductionYear'), - 'premieredate': premieredate, - 'genre': genre, - 'playcount': str(playcount), - 'title': title, - 'plot': API.getOverview(), - 'Overlay': str(overlay), - } - li.setInfo('video', infoLabels=extradata) - li.setThumbnailImage(art.getAllArtwork(item)['Primary']) - li.setIconImage('DefaultTVShows.png') - - if item.get("IsFolder") == True: - path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" % (_addon_url, viewname, type, itemid) - xbmcplugin.addDirectoryItem(handle=_addon_id, url=path, listitem=li, isFolder=True) - else: - path = "%s?id=%s&mode=play" % (_addon_url, itemid) - li.setProperty('IsPlayable', 'true') - - mediastreams = API.getMediaStreams() - if mediastreams: - for key, value in mediastreams.iteritems(): - if value: li.addStreamInfo(key, value[0]) - - xbmcplugin.addDirectoryItem(handle=_addon_id, url=path, listitem=li) + li = createListItemFromEmbyItem(item) + if item.get("IsFolder") == True: + #for folders we add an additional browse request, passing the folderId + path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" % (sys.argv[0], viewname, type, item.get("Id")) + xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=True) + else: + #playable item, set plugin path and mediastreams + xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=li.getProperty("path"), listitem=li) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) + if filter == "recent": + xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE) + else: + xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_TITLE) + xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE) + xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RATING) + xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RUNTIME) + +##### CREATE LISTITEM FROM EMBY METADATA ##### +def createListItemFromEmbyItem(item): + API = api.API(item) + art = artwork.Artwork() + doUtils = downloadutils.DownloadUtils() + itemid = item['Id'] + + title = item.get('Name') + li = xbmcgui.ListItem(title) + + premieredate = item.get('PremiereDate',"") + if not premieredate: premieredate = item.get('DateCreated',"") + if premieredate: + premieredatelst = premieredate.split('T')[0].split("-") + premieredate = "%s.%s.%s" %(premieredatelst[2],premieredatelst[1],premieredatelst[0]) + + li.setProperty("embyid",itemid) + + allart = art.getAllArtwork(item) + + if item["Type"] in ["Photo","PhotoAlbum"]: + #listitem setup for pictures... + img_path = allart.get('Primary') + li.setProperty("path",img_path) + picture = doUtils.downloadUrl("{server}/Items/%s/Images" %itemid)[0] + if picture.get("Width") > picture.get("Height"): + li.setArt( {"fanart": img_path}) #add image as fanart for use with skinhelper auto thumb/backgrund creation + li.setInfo('pictures', infoLabels={ "picturepath": img_path, "date": premieredate, "size": picture.get("Size"), "exif:width": str(picture.get("Width")), "exif:height": str(picture.get("Height")), "title": "blaat" }) + li.setThumbnailImage(img_path) + li.setIconImage('DefaultPicture.png') + else: + #normal video items + li.setProperty('IsPlayable', 'true') + path = "%s?id=%s&mode=play" % (sys.argv[0], item.get("Id")) + li.setProperty("path",path) + genre = API.getGenres() + overlay = 0 + userdata = API.getUserData() + seektime = userdata['Resume'] + if seektime: + li.setProperty("resumetime", seektime) + li.setProperty("totaltime", item.get("RunTimeTicks")/ 10000000.0) + + played = userdata['Played'] + if played: overlay = 7 + else: overlay = 6 + + favorite = userdata['Favorite'] + if favorite: overlay = 5 + + playcount = userdata['PlayCount'] + if playcount is None: + playcount = 0 + rating = item.get('CommunityRating') + if not rating: rating = userdata['UserRating'] + + # Populate the extradata list and artwork + extradata = { + 'id': itemid, + 'rating': rating, + 'year': item.get('ProductionYear'), + 'premieredate': premieredate, + 'date': premieredate, + 'genre': genre, + 'playcount': str(playcount), + 'title': title, + 'plot': API.getOverview(), + 'Overlay': str(overlay), + } + li.setInfo('video', infoLabels=extradata) + li.setThumbnailImage(allart.get('Primary')) + li.setIconImage('DefaultTVShows.png') + if not allart.get('Background'): #add image as fanart for use with skinhelper auto thumb/backgrund creation + li.setArt( {"fanart": allart.get('Primary') } ) + else: + pbutils.PlaybackUtils(item).setArtwork(li) + + mediastreams = API.getMediaStreams() + if mediastreams: + for key, value in mediastreams.iteritems(): + if value: li.addStreamInfo(key, value[0]) + + return li + ##### BROWSE EMBY CHANNELS ##### def BrowseChannels(itemid, folderid=None): diff --git a/resources/lib/read_embyserver.py b/resources/lib/read_embyserver.py index ee2f4427..182c33fb 100644 --- a/resources/lib/read_embyserver.py +++ b/resources/lib/read_embyserver.py @@ -124,7 +124,30 @@ class Read_EmbyServer(): cursor_emby.close() return [viewName, viewId, mediatype] + + def getFilteredSection(self, parentid, itemtype=None, sortby="SortName", recursive=True, limit=None, sortorder="Ascending", filter=""): + doUtils = self.doUtils + url = "{server}/emby/Users/{UserId}/Items?format=json" + params = { + 'ParentId': parentid, + 'IncludeItemTypes': itemtype, + 'CollapseBoxSetItems': False, + 'IsVirtualUnaired': False, + 'IsMissing': False, + 'Recursive': recursive, + 'Limit': limit, + 'SortBy': sortby, + 'SortOrder': sortorder, + 'Filters': filter, + 'Fields': ( "Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines," + "CommunityRating,OfficialRating,CumulativeRunTimeTicks," + "Metascore,AirTime,DateCreated,MediaStreams,People,Overview," + "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," + "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers") + } + return doUtils.downloadUrl(url, parameters=params) + def getSection(self, parentid, itemtype=None, sortby="SortName", basic=False): doUtils = self.doUtils diff --git a/resources/lib/videonodes.py b/resources/lib/videonodes.py index 84564e7a..c1d42df1 100644 --- a/resources/lib/videonodes.py +++ b/resources/lib/videonodes.py @@ -120,11 +120,12 @@ class VideoNodes(object): '8': "sets", '9': "genres", '10': "random", - '11': "recommended" + '11': "recommended", } mediatypes = { # label according to nodetype per mediatype - 'movies': { + 'movies': + { '1': tagname, '2': 30174, '4': 30177, @@ -132,9 +133,11 @@ class VideoNodes(object): '8': 20434, '9': 135, '10': 30229, - '11': 30230}, + '11': 30230 + }, - 'tvshows': { + 'tvshows': + { '1': tagname, '2': 30170, '3': 30175, @@ -143,15 +146,23 @@ class VideoNodes(object): '7': 30179, '9': 135, '10': 30229, - '11': 30230}, + '11': 30230 + }, - 'homevideos': { + 'homevideos': + { '1': tagname, - '2': 30170}, + '2': 30251, + '11': 30253 + }, - 'photos': { + 'photos': + { '1': tagname, - '2': 30170}, + '2': 30252, + '8': 30255, + '11': 30254 + }, } nodes = mediatypes[mediatype] @@ -169,18 +180,12 @@ class VideoNodes(object): label = stringid # Set window properties - if mediatype == "homevideos" and nodetype == "all": + if (mediatype == "homevideos" or mediatype == "photos") and nodetype == "all": # Custom query - path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=homevideos" % tagname - elif mediatype == "homevideos" and nodetype == "recent": + path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=%s" %(tagname,mediatype) + elif (mediatype == "homevideos" or mediatype == "photos"): # Custom query - path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=homevideos&filter=recent" % tagname - elif mediatype == "photos" and nodetype == "all": - # Custom query - path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=photos" % tagname - elif mediatype == "photos" and nodetype == "recent": - # Custom query - path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=photos&filter=recent" % tagname + path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=%s&filter=%s" %(tagname,mediatype,nodetype) elif nodetype == "nextepisodes": # Custom query path = "plugin://plugin.video.emby/?id=%s&mode=nextup&limit=25" % tagname