diff --git a/default.py b/default.py index 54074ad8..a50efa3f 100644 --- a/default.py +++ b/default.py @@ -21,6 +21,7 @@ try: params = utils.get_params(sys.argv[2]) mode = params['mode'] id = params.get('id', None) + name = params.get('name',None) except: params = {} mode = None @@ -28,6 +29,12 @@ except: ##### Play items via plugin://plugin.video.emby/ ##### if mode == "play": entrypoint.doPlayback(id) + +elif mode == "info": + entrypoint.showInfo(id) + +elif mode == "person": + entrypoint.showPersonInfo(id,name) ##### DO DATABASE RESET ##### elif mode == "reset": diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml index 532dbd65..347fb2c4 100644 --- a/resources/language/English/strings.xml +++ b/resources/language/English/strings.xml @@ -245,6 +245,11 @@ Enable HTTPS Force Transcoding Codecs + Enable Netflix style next up notification + - The number of seconds before the end to show the notification + Show Emby Info dialog on play/select action + + Active Clear Settings diff --git a/resources/lib/API.py b/resources/lib/API.py index 3239f60b..7823f45e 100644 --- a/resources/lib/API.py +++ b/resources/lib/API.py @@ -2,6 +2,7 @@ # This class helps translate more complex cases from the MediaBrowser API to the XBMC API from datetime import datetime +from random import randrange import xbmc import xbmcgui import xbmcaddon diff --git a/resources/lib/Entrypoint.py b/resources/lib/Entrypoint.py index 64bcac16..bb3f5ff3 100644 --- a/resources/lib/Entrypoint.py +++ b/resources/lib/Entrypoint.py @@ -17,6 +17,8 @@ from PlaybackUtils import PlaybackUtils from DownloadUtils import DownloadUtils from ReadEmbyDB import ReadEmbyDB from API import API +from ItemInfo import ItemInfo +from PersonInfo import PersonInfo ##### Play items via plugin://plugin.video.emby/ ##### @@ -26,6 +28,29 @@ def doPlayback(id): item = PlaybackUtils().PLAY(result, setup="default") +##### Show the item info window ##### +def showInfo(id): + xbmcplugin.endOfDirectory(int(sys.argv[1]), cacheToDisc=False) + addonSettings = xbmcaddon.Addon(id='plugin.video.emby') + infoPage = ItemInfo("ItemInfo.xml", addonSettings.getAddonInfo('path'), "default", "720p") + infoPage.setId(id) + infoPage.doModal() + del infoPage + + +def showPersonInfo(id,basename): + xbmcplugin.endOfDirectory(int(sys.argv[1]), cacheToDisc=False) + addonSettings = xbmcaddon.Addon(id='plugin.video.emby') + infoPage = PersonInfo("PersonInfo.xml", addonSettings.getAddonInfo('path'), "default", "720p") + infoPage.setPersonName(basename) + infoPage.doModal() + + if(infoPage.showMovies == True): + xbmc.log("RUNNING_PLUGIN: " + infoPage.pluginCastLink) + xbmc.executebuiltin(infoPage.pluginCastLink) + + del infoPage + #### DO RESET AUTH ##### def resetAuth(): # User tried login and failed too many times diff --git a/resources/lib/ItemInfo.py b/resources/lib/ItemInfo.py new file mode 100644 index 00000000..cb890c88 --- /dev/null +++ b/resources/lib/ItemInfo.py @@ -0,0 +1,526 @@ + +import sys +import xbmc +import xbmcgui +import xbmcaddon +import json as json +import urllib +from DownloadUtils import DownloadUtils +from API import API + + +_MODE_BASICPLAY=12 +_MODE_CAST_LIST=14 +_MODE_PERSON_DETAILS=15 +CP_ADD_URL = 'plugin://plugin.video.couchpotato_manager/movies/add?title=' +CP_ADD_VIA_IMDB = 'plugin://plugin.video.couchpotato_manager/movies/add?imdb_id=' + + +class ItemInfo(xbmcgui.WindowXMLDialog): + + id = "" + playUrl = "" + trailerUrl = "" + couchPotatoUrl = "" + userid = "" + server = "" + downloadUtils = DownloadUtils() + item= [] + isTrailer = False + + def __init__(self, *args, **kwargs): + xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs) + xbmc.log("WINDOW INITIALISED") + + def onInit(self): + self.action_exitkeys_id = [10, 13] + url = "{server}/mediabrowser/Users/{UserId}/Items/" + self.id + "?Fields=SeriesGenres,AirTime&format=json" + item = self.downloadUtils.downloadUrl(url) + self.item = item + + id = item.get("Id") + WINDOW = xbmcgui.Window( 10025 ) + WINDOW.setProperty('ItemGUID', id) + + name = item.get("Name") + image = API().getArtwork(item, "poster") + fanArt = API().getArtwork(item, "BackdropNoIndicators") + self.getControl(3001).setImage(fanArt) + + discart = API().getArtwork(item ,"Disc") + logo = API().getArtwork(item ,"Logo") + # calculate the percentage complete + userData = item.get("UserData") + cappedPercentage = 0 + + if(userData != None): + playBackTicks = float(userData.get("PlaybackPositionTicks")) + if(playBackTicks != None and playBackTicks > 0): + runTimeTicks = float(item.get("RunTimeTicks", "0")) + if(runTimeTicks > 0): + percentage = int((playBackTicks / runTimeTicks) * 100.0) + cappedPercentage = percentage - (percentage % 10) + if(cappedPercentage == 0): + cappedPercentage = 10 + if(cappedPercentage == 100): + cappedPercentage = 90 + + try: + watchedButton = self.getControl(3192) + except: + watchedButton = None + if(watchedButton != None): + if userData.get("Played") == True: + watchedButton.setSelected(True) + else: + watchedButton.setSelected(False) + + try: + dislikeButton = self.getControl(3193) + except: + dislikeButton = None + if(dislikeButton != None): + if userData.get("Likes") != None and userData.get("Likes") == False: + dislikeButton.setSelected(True) + else: + dislikeButton.setSelected(False) + + try: + likeButton = self.getControl(3194) + except: + likeButton = None + if(likeButton != None): + if userData.get("Likes") != None and userData.get("Likes") == True: + likeButton.setSelected(True) + else: + likeButton.setSelected(False) + + try: + favouriteButton = self.getControl(3195) + except: + favouriteButton = None + if(favouriteButton != None): + if userData.get("IsFavorite") == True: + favouriteButton.setSelected(True) + else: + favouriteButton.setSelected(False) + + + episodeInfo = "" + type = item.get("Type") + WINDOW.setProperty('ItemType', type) + if(type == "Episode" or type == "Season"): + WINDOW.setProperty('ItemGUID', item.get("SeriesId")) + name = item.get("SeriesName") + ": " + name + season = str(item.get("ParentIndexNumber")).zfill(2) + episodeNum = str(item.get("IndexNumber")).zfill(2) + episodeInfo = "S" + season + "xE" + episodeNum + elif type == "Movie": + if item.get("Taglines") != None and item.get("Taglines") != [] and item.get("Taglines")[0] != None: + episodeInfo = item.get("Taglines")[0] + elif type == "ChannelVideoItem": + if item.get("ExtraType") != None: + if item.get('ExtraType') == "Trailer": + self.isTrailer = True + + + self.playUrl = "plugin://plugin.video.emby/?id=%s&mode=play" % id + + try: + trailerButton = self.getControl(3102) + if(trailerButton != None): + if not self.isTrailer and item.get("LocalTrailerCount") != None and item.get("LocalTrailerCount") > 0: + itemTrailerUrl = "{server}/mediabrowser/Users/{UserId}/Items/" + id + "/LocalTrailers?format=json" + jsonData = self.downloadUtils.downloadUrl(itemTrailerUrl) + if(jsonData != ""): + trailerItem = jsonData + self.trailerUrl = "plugin://plugin.video.emby/trailer/?id=%s&mode=play" % trailerItem[0][u'Id'] + else: + trailerButton.setEnabled(False) + except: + pass + + try: + couchPotatoButton = self.getControl(3103) + if(couchPotatoButton != None): + if self.isTrailer and item.get("ProviderIds") != None and item.get("ProviderIds").get("Imdb") != None: + self.couchPotatoUrl = CP_ADD_VIA_IMDB + item.get("ProviderIds").get("Imdb") + elif self.isTrailer: + self.couchPotatoUrl = CP_ADD_URL + name + elif not self.isTrailer: + couchPotatoButton.setEnabled(False) + except: + pass + + # all the media stream info + mediaList = self.getControl(3220) + + mediaStreams = item.get("MediaStreams") + if(mediaStreams != None): + for mediaStream in mediaStreams: + if(mediaStream.get("Type") == "Video"): + videocodec = mediaStream.get("Codec") + if(videocodec == "mpeg2video"): + videocodec = "mpeg2" + height = str(mediaStream.get("Height")) + width = str(mediaStream.get("Width")) + aspectratio = mediaStream.get("AspectRatio") + fr = mediaStream.get("RealFrameRate") + videoInfo = width + "x" + height + " " + videocodec + " " + str(round(fr, 2)) + listItem = xbmcgui.ListItem("Video:", videoInfo) + mediaList.addItem(listItem) + if(mediaStream.get("Type") == "Audio"): + audiocodec = mediaStream.get("Codec") + channels = mediaStream.get("Channels") + lang = mediaStream.get("Language") + audioInfo = audiocodec + " " + str(channels) + if(lang != None and len(lang) > 0 and lang != "und"): + audioInfo = audioInfo + " " + lang + listItem = xbmcgui.ListItem("Audio:", audioInfo) + mediaList.addItem(listItem) + if(mediaStream.get("Type") == "Subtitle"): + lang = mediaStream.get("Language") + codec = mediaStream.get("Codec") + subInfo = codec + if(lang != None and len(lang) > 0 and lang != "und"): + subInfo = subInfo + " " + lang + listItem = xbmcgui.ListItem("Sub:", subInfo) + mediaList.addItem(listItem) + + + #for x in range(0, 10): + # listItem = xbmcgui.ListItem("Test:", "Test 02 " + str(x)) + # mediaList.addItem(listItem) + + # add overview + overview = item.get("Overview") + self.getControl(3223).setText(overview) + + # add people + peopleList = self.getControl(3230) + people = item.get("People") + director='' + writer='' + for person in people: + displayName = person.get("Name") + if person.get("Role") != None and person.get("Role") != '': + role = "as " + person.get("Role") + else: + role = '' + id = person.get("Id") + tag = person.get("PrimaryImageTag") + + baseName = person.get("Name") + baseName = baseName.replace(" ", "+") + baseName = baseName.replace("&", "_") + baseName = baseName.replace("?", "_") + baseName = baseName.replace("=", "_") + + actionUrl = "plugin://plugin.video.emby?mode=person&name=" + baseName + + if(tag != None and len(tag) > 0): + thumbPath = self.downloadUtils.imageUrl(id, "Primary", 0, 400, 400) + listItem = xbmcgui.ListItem(label=displayName, label2=role, iconImage=thumbPath, thumbnailImage=thumbPath) + else: + listItem = xbmcgui.ListItem(label=displayName, label2=role) + + listItem.setProperty("ActionUrl", actionUrl) + peopleList.addItem(listItem) + if(person.get("Type") == "Director") and director =='': + director = displayName + if(tag != None and len(tag) > 0): + thumbPath = self.downloadUtils.imageUrl(id, "Primary", 0, 580, 860) + directorlistItem = xbmcgui.ListItem("Director:", label2=displayName, iconImage=thumbPath, thumbnailImage=thumbPath) + else: + directorlistItem = xbmcgui.ListItem("Director:", label2=displayName) + directorlistItem.setProperty("ActionUrl", actionUrl) + if(person.get("Type") == "Writing") and writer == '': + writer = person.get("Name") + if(tag != None and len(tag) > 0): + thumbPath = self.downloadUtils.imageUrl(id, "Primary", 0, 580, 860) + writerlistItem = xbmcgui.ListItem("Writer:", label2=displayName, iconImage=thumbPath, thumbnailImage=thumbPath) + else: + writerlistItem = xbmcgui.ListItem("Writer:", label2=displayName) + writerlistItem.setProperty("ActionUrl", actionUrl) + if(person.get("Type") == "Writer") and writer == '': + writer = person.get("Name") + if(tag != None and len(tag) > 0): + thumbPath = self.downloadUtils.imageUrl(id, "Primary", 0, 580, 860) + writerlistItem = xbmcgui.ListItem("Writer:", label2=displayName, iconImage=thumbPath, thumbnailImage=thumbPath) + else: + writerlistItem = xbmcgui.ListItem("Writer:", label2=displayName) + writerlistItem.setProperty("ActionUrl", actionUrl) + # add general info + infoList = self.getControl(3226) + listItem = xbmcgui.ListItem("Year:", str(item.get("ProductionYear"))) + infoList.addItem(listItem) + listItem = xbmcgui.ListItem("Rating:", str(item.get("CommunityRating"))) + infoList.addItem(listItem) + listItem = xbmcgui.ListItem("MPAA:", str(item.get("OfficialRating"))) + infoList.addItem(listItem) + duration = str(int(item.get("RunTimeTicks", "0"))/(10000000*60)) + listItem = xbmcgui.ListItem("RunTime:", str(duration) + " Minutes") + infoList.addItem(listItem) + + genre = "" + genres = item.get("Genres") + if genres != None and genres != []: + for genre_string in genres: + if genre == "": #Just take the first genre + genre = genre_string + else: + genre = genre + " / " + genre_string + elif item.get("SeriesGenres") != None and item.get("SeriesGenres") != '': + genres = item.get("SeriesGenres") + if genres != None and genres != []: + for genre_string in genres: + if genre == "": #Just take the first genre + genre = genre_string + else: + genre = genre + " / " + genre_string + + genrelistItem = xbmcgui.ListItem("Genre:", genre) + genrelistItem2 = xbmcgui.ListItem("Genre:", genre) + infoList.addItem(genrelistItem) + + path = item.get('Path') + pathlistItem = xbmcgui.ListItem("Path:", path) + pathlistItem2 = xbmcgui.ListItem("Path:", path) + infoList.addItem(pathlistItem) + + if item.get("CriticRating") != None: + listItem = xbmcgui.ListItem("CriticRating:", str(item.get("CriticRating"))) + infoList.addItem(listItem) + + # Process Studio + studio = "" + if item.get("SeriesStudio") != None and item.get("SeriesStudio") != '': + studio = item.get("SeriesStudio") + if studio == "": + studios = item.get("Studios") + if(studios != None): + for studio_string in studios: + if studio=="": #Just take the first one + temp=studio_string.get("Name") + studio=temp.encode('utf-8') + + if studio != "": + listItem = xbmcgui.ListItem("Studio:", studio) + infoList.addItem(listItem) + + if item.get("Metascore") != None: + listItem = xbmcgui.ListItem("Metascore:", str(item.get("Metascore"))) + infoList.addItem(listItem) + + playCount = 0 + if(userData != None and userData.get("Played") == True): + playCount = 1 + listItem = xbmcgui.ListItem("PlayedCount:", str(playCount)) + infoList.addItem(listItem) + + if item.get("ProviderIds") != None and item.get("ProviderIds").get("Imdb") != None and type == "Movie": + listItem = xbmcgui.ListItem("ID:", item.get("ProviderIds").get("Imdb")) + infoList.addItem(listItem) + elif item.get("ProviderIds") != None and item.get("ProviderIds").get("Tvdb") != None and type == "Series": + listItem = xbmcgui.ListItem("ID:", item.get("ProviderIds").get("Tvdb")) + infoList.addItem(listItem) + elif (type == "Episode" or type == "Season"): + url = "{server}/mediabrowser/Users/{UserId}/Items/" + item.get("SeriesId") + "?Fields=SeriesGenres,AirTime&format=json" + seriesitem = self.downloadUtils.downloadUrl(url) + + if seriesitem.get("ProviderIds") != None and seriesitem.get("ProviderIds").get("Tvdb") != None: + listItem = xbmcgui.ListItem("ID:", seriesitem.get("ProviderIds").get("Tvdb")) + infoList.addItem(listItem) + + # alternate list + try: + alternateList = self.getControl(3291) + if alternateList != None: + if directorlistItem != None: + alternateList.addItem(directorlistItem) + if writerlistItem != None: + alternateList.addItem(writerlistItem) + alternateList.addItem(genrelistItem2) + if item.get("ProductionLocations") !=None and item.get("ProductionLocations") != []: + listItem = xbmcgui.ListItem("Country:", item.get("ProductionLocations")[0]) + alternateList.addItem(listItem) + elif item.get("AirTime") !=None: + listItem = xbmcgui.ListItem("Air Time:", item.get("AirTime")) + alternateList.addItem(listItem) + if(item.get("PremiereDate") != None): + premieredatelist = (item.get("PremiereDate")).split("T") + premieredate = premieredatelist[0] + listItem = xbmcgui.ListItem("Premiered Date:", premieredate) + alternateList.addItem(listItem) + alternateList.addItem(pathlistItem2) + + except: + pass + + self.getControl(3000).setLabel(name) + self.getControl(3003).setLabel(episodeInfo) + + try: + discartImageControl = self.getControl(3091) + artImageControl = self.getControl(3092) + thumbImageControl = self.getControl(3093) + logoImageControl = self.getControl(3094) + + if discartImageControl != None and artImageControl != None and thumbImageControl != None and logoImageControl != None: + + if logo != "": + self.getControl(3094).setImage(logo) + else: + self.getControl(3000).setVisible(True) + + if discart != '': + self.getControl(3091).setImage(discart) + self.getControl(3092).setVisible(False) + self.getControl(3093).setVisible(False) + else: + self.getControl(3091).setVisible(False) + art = API().getArtwork(item,"Art") + if (artImageControl != None): + if art != '': + self.getControl(3092).setImage(art) + self.getControl(3093).setVisible(False) + else: + self.getControl(3092).setVisible(False) + if (type == "Episode"): + thumb = API().getArtwork(item,"Thumb3") + else: + thumb = API().getArtwork(item,"Thumb") + if (thumbImageControl != None): + if thumb != '': + self.getControl(3093).setImage(thumb) + else: + self.getControl(3093).setVisible(False) + + + except: + pass + + if(type == "Episode"): + # null_pointer - I have removed this in favor of letting the user chose from the setting and using the "poster" type in the above image url create + #image = API().getArtwork(seriesitem, "Primary") + seriesimage = API().getArtwork(item, "SeriesPrimary") + try: + self.getControl(3099).setImage(seriesimage) + except: + pass + + self.getControl(3009).setImage(image) + if(cappedPercentage != None): + self.getControl(3010).setImage("Progress\progress_" + str(cappedPercentage) + ".png") + else: + self.getControl(3011).setImage(image) + if(cappedPercentage != None): + self.getControl(3012).setImage("Progress\progress_" + str(cappedPercentage) + ".png") + + # disable play button + if(type == "Season" or type == "Series"): + self.setFocusId(3226) + self.getControl(3002).setEnabled(False) + + def setId(self, id): + self.id = id + + def onFocus(self, controlId): + pass + + def doAction(self): + pass + + def closeDialog(self): + self.close() + + def onClick(self, controlID): + + if(controlID == 3002): + + # close all dialogs when playing an item + xbmc.executebuiltin("Dialog.Close(all,true)") + + xbmc.executebuiltin("RunPlugin(" + self.playUrl + ")") + self.close() + + elif(controlID == 3102): + + # close all dialogs when playing an item + xbmc.executebuiltin("Dialog.Close(all,true)") + + xbmc.executebuiltin("RunPlugin(" + self.trailerUrl + ")") + self.close() + + elif(controlID == 3103): + + # close all dialogs when playing an item + xbmc.executebuiltin("Dialog.Close(all,true)") + xbmc.executebuiltin("RunPlugin(" + self.couchPotatoUrl + ")") + + elif(controlID == 3230): + + peopleList = self.getControl(3230) + item = peopleList.getSelectedItem() + action = item.getProperty("ActionUrl") + + xbmc.log(action) + xbmc.executebuiltin("RunPlugin(" + action + ")") + elif(controlID == 3291): + + list = self.getControl(3291) + item = list.getSelectedItem() + action = item.getProperty("ActionUrl") + + xbmc.log(action) + xbmc.executebuiltin("RunPlugin(" + action + ")") + elif(controlID == 3192): + url = '{server}/mediabrowser/Users/{UserId}/PlayedItems/' + self.id + button = self.getControl(3192) + watched = button.isSelected() + if watched == True: + self.postUrl(url) + else: + self.deleteUrl(url) + self.onInit() + elif(controlID == 3193): + url = '{server}/mediabrowser/Users/{UserId}/Items/' + self.id + '/Rating' + dislikebutton = self.getControl(3193) + dislike = dislikebutton.isSelected() + if dislike == True: + url = url + '?likes=false' + self.postUrl(url) + else: + self.deleteUrl(url) + self.onInit() + elif(controlID == 3194): + url = '{server}/mediabrowser/Users/{UserId}/Items/' + self.id + '/Rating' + likebutton = self.getControl(3194) + like = likebutton.isSelected() + if like == True: + url = url + '?likes=true' + self.postUrl(url) + else: + self.deleteUrl(url) + self.onInit() + elif(controlID == 3195): + url = '{server}/mediabrowser/Users/{UserId}/FavoriteItems/' + self.id + button = self.getControl(3195) + favourite = button.isSelected() + if favourite == True: + self.postUrl(url) + else: + self.deleteUrl(url) + self.onInit() + elif(controlID == 3006): + url = "{server}/mediabrowser/Users/{UserId}/PlayingItems/" + self.id + "/Progress?PositionTicks=0" + self.postUrl(url) + self.onInit() + pass + + def postUrl (self,url): + self.downloadUtils.downloadUrl(url, postBody="", type="POST") + + def deleteUrl (self,url): + self.downloadUtils.downloadUrl(url, type="DELETE") + diff --git a/resources/lib/NextUpInfo.py b/resources/lib/NextUpInfo.py new file mode 100644 index 00000000..ec54567a --- /dev/null +++ b/resources/lib/NextUpInfo.py @@ -0,0 +1,102 @@ + +import sys +import xbmc +import xbmcgui +import xbmcaddon +import json as json +import urllib +from API import API +from PlaybackUtils import PlaybackUtils + +ACTION_PLAYER_STOP = 13 + +class NextUpInfo(xbmcgui.WindowXMLDialog): + + item = None + cancel = False + watchnow = False + + def __init__(self, *args, **kwargs): + xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs) + + def onInit(self): + self.action_exitkeys_id = [10, 13] + + image = API().getArtwork(self.item, "Primary2") + clearartimage = API().getArtwork(self.item, "Art") + overview = API().getOverview(self.item) + name = API().getName(self.item) + + episodeInfo = "" + season = str(self.item.get("ParentIndexNumber")) + episodeNum = str(self.item.get("IndexNumber")) + episodeInfo = season + "x" + episodeNum + "." + + rating = None + if self.item.get("CommunityRating") != None and self.item.get("CommunityRating") !="": + rating = str(self.item.get("CommunityRating")) + year = API().getPremiereDate(self.item) + duration = str(int(self.item.get("RunTimeTicks", "0"))/(10000000*60)) + info = year + " " + str(duration) + " min" + # set the dialog data + self.getControl(3000).setLabel(name) + self.getControl(3001).setText(overview) + self.getControl(3002).setLabel(episodeInfo) + self.getControl(3004).setLabel(info) + + self.getControl(3009).setImage(image) + self.getControl(3006).setImage(clearartimage) + + if rating != None: + self.getControl(3003).setLabel(rating) + else: + self.getControl(3003).setVisible(False) + + + def setItem(self, item): + self.item = item + + def setCancel(self, cancel): + self.cancel = cancel + + def isCancel(self): + return self.cancel + + def setWatchNow(self, watchnow): + self.watchnow = watchnow + + def isWatchNow(self): + return self.watchnow + + def onFocus(self, controlId): + pass + + def doAction(self): + pass + + def closeDialog(self): + self.close() + + def onClick(self, controlID): + + xbmc.log("nextup info onclick: "+str(controlID)) + + if(controlID == 3012): + # watch now + self.setWatchNow(True) + self.close() + + elif(controlID == 3013): + #cancel + self.setCancel(True) + self.close() + + pass + + def onAction(self, action): + + xbmc.log("nextup info action: "+str(action.getId())) + if action == ACTION_PLAYER_STOP: + self.close() + + diff --git a/resources/lib/PersonInfo.py b/resources/lib/PersonInfo.py new file mode 100644 index 00000000..56af1813 --- /dev/null +++ b/resources/lib/PersonInfo.py @@ -0,0 +1,169 @@ + +import sys +import xbmc +import xbmcgui +import xbmcaddon +import json as json +import urllib +from DownloadUtils import DownloadUtils +from API import API + +_MODE_GETCONTENT=0 +_MODE_ITEM_DETAILS=17 + +class PersonInfo(xbmcgui.WindowXMLDialog): + + pluginCastLink = "" + showMovies = False + personName = "" + + def __init__(self, *args, **kwargs): + xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs) + + def onInit(self): + self.action_exitkeys_id = [10, 13] + downloadUtils = DownloadUtils() + url = "{server}/mediabrowser/Persons/" + self.personName + "?format=json" + jsonData = downloadUtils.downloadUrl(url ) + result = jsonData + + name = result.get("Name") + id = result.get("Id") + + # other lib items count + contentCounts = "" + if(result.get("AdultVideoCount") != None and result.get("AdultVideoCount") > 0): + contentCounts = contentCounts + "\nAdult Count : " + str(result.get("AdultVideoCount")) + if(result.get("MovieCount") != None and result.get("MovieCount") > 0): + contentCounts = contentCounts + "\nMovie Count : " + str(result.get("MovieCount")) + if(result.get("SeriesCount") != None and result.get("SeriesCount") > 0): + contentCounts = contentCounts + "\nSeries Count : " + str(result.get("SeriesCount")) + if(result.get("EpisodeCount") != None and result.get("EpisodeCount") > 0): + contentCounts = contentCounts + "\nEpisode Count : " + str(result.get("EpisodeCount")) + + if(len(contentCounts) > 0): + contentCounts = "Total Library Counts:" + contentCounts + + #overview + overview = "" + if(len(contentCounts) > 0): + overview = contentCounts + "\n\n" + over = result.get("Overview") + if(over == None or over == ""): + overview = overview + "No details available" + else: + overview = overview + over + + #person image + image = API().getArtwork(result, "Primary") + + #get other movies + encoded = name.encode("utf-8") + encoded = urllib.quote(encoded) + url = "{server}/mediabrowser/Users/{UserId}/Items/?Recursive=True&Person=" + encoded + "&format=json" + jsonData = downloadUtils.downloadUrl(url) + otherMovieResult = jsonData + + baseName = name.replace(" ", "+") + baseName = baseName.replace("&", "_") + baseName = baseName.replace("?", "_") + baseName = baseName.replace("=", "_") + + #detailsString = getDetailsString() + #search_url = "http://" + host + ":" + port + "/mediabrowser/Users/" + userid + "/Items/?Recursive=True&Person=PERSON_NAME&Fields=" + detailsString + "&format=json" + #search_url = "http://" + host + ":" + port + "/mediabrowser/Users/" + userid + "/Items/?Recursive=True&Person=PERSON_NAME&format=json" + #search_url = urllib.quote(search_url) + #search_url = search_url.replace("PERSON_NAME", baseName) + #self.pluginCastLink = "XBMC.Container.Update(plugin://plugin.video.xbmb3c?mode=" + str(_MODE_GETCONTENT) + "&url=" + search_url + ")" + + otherItemsList = None + try: + otherItemsList = self.getControl(3010) + + items = otherMovieResult.get("Items") + if(items == None): + items = [] + + for item in items: + item_id = item.get("Id") + item_name = item.get("Name") + + type_info = "" + image_id = item_id + item_type = item.get("Type") + + if(item_type == "Season"): + image_id = item.get("SeriesId") + season = item.get("IndexNumber") + type_info = "Season " + str(season).zfill(2) + elif(item_type == "Series"): + image_id = item.get("Id") + type_info = "Series" + elif(item_type == "Movie"): + image_id = item.get("Id") + type_info = "Movie" + elif(item_type == "Episode"): + image_id = item.get("SeriesId") + season = item.get("ParentIndexNumber") + eppNum = item.get("IndexNumber") + type_info = "S" + str(season).zfill(2) + "E" + str(eppNum).zfill(2) + + thumbPath = downloadUtils.imageUrl(image_id, "Primary", 0, 200, 200) + + fanArt = downloadUtils.imageUrl(image_id, "Backdrop",0,10000,10000) + listItem = xbmcgui.ListItem(label=item_name, label2=type_info, iconImage=thumbPath, thumbnailImage=thumbPath) + listItem.setArt({"fanart":fanArt}) + + actionUrl = "plugin://plugin.video.emby?id=" + item_id + "&mode=info" + listItem.setProperty("ActionUrl", actionUrl) + + otherItemsList.addItem(listItem) + + except Exception, e: + xbmc.log("Exception : " + str(e)) + pass + + + + # set the dialog data + self.getControl(3000).setLabel(name) + self.getControl(3001).setText(overview) + self.getControl(3009).setImage(image) + + def setPersonName(self, name): + self.personName = name + + def setInfo(self, data): + self.details = data + + def onFocus(self, controlId): + pass + + def doAction(self): + pass + + def closeDialog(self): + self.close() + + def onClick(self, controlID): + + if(controlID == 3002): + self.showMovies = True + + xbmc.executebuiltin('Dialog.Close(movieinformation)') + self.close() + + elif(controlID == 3010): + + #xbmc.executebuiltin("Dialog.Close(all,true)") + + itemList = self.getControl(3010) + item = itemList.getSelectedItem() + action = item.getProperty("ActionUrl") + + xbmc.executebuiltin("RunPlugin(" + action + ")") + + self.close() + + pass + diff --git a/resources/lib/Player.py b/resources/lib/Player.py index 56d0838f..5025400b 100644 --- a/resources/lib/Player.py +++ b/resources/lib/Player.py @@ -18,6 +18,7 @@ from LibrarySync import LibrarySync from PlaybackUtils import PlaybackUtils from ReadEmbyDB import ReadEmbyDB from API import API +from NextUpInfo import NextUpInfo librarySync = LibrarySync() # service class for playback monitoring @@ -348,29 +349,23 @@ class Player( xbmc.Player ): seasonId = MB3Episode["SeasonId"] url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&ImageTypeLimit=1&Limit=1&SortBy=SortName&SortOrder=Ascending&Filters=IsUnPlayed&IncludeItemTypes=Episode&IsVirtualUnaired=false&Recursive=true&IsMissing=False&format=json" % seasonId jsonData = self.doUtils.downloadUrl(url) - if(jsonData != ""): seasonData = jsonData - if seasonData.get("Items") != None: item = seasonData.get("Items")[0] - pDialog.create("Auto Play next episode", str(item.get("ParentIndexNumber")) + "x" + str(item.get("IndexNumber")) + ". " + item["Name"] + " found","Cancel to stop automatic play") - count = 0 - while(pDialog.iscanceled()==False and count < 10): - xbmc.sleep(1000) - count += 1 - progress = count * 10 - remainingsecs = 10 - count - pDialog.update(progress, str(item.get("ParentIndexNumber")) + "x" + str(item.get("IndexNumber")) + ". " + item["Name"] + " found","Cancel to stop automatic play", str(remainingsecs) + " second(s) until auto dismiss") - - pDialog.close() - - if pDialog.iscanceled()==False: + item = ReadEmbyDB().getItem(item["Id"]) + nextUpPage = NextUpInfo("NextUpInfo.xml", addonSettings.getAddonInfo('path'), "default", "720p") + nextUpPage.setItem(item) playTime = xbmc.Player().getTime() totalTime = xbmc.Player().getTotalTime() - while xbmc.Player().isPlaying() and (totalTime-playTime > 2): - xbmc.sleep(500) + nextUpPage.show() + playTime = xbmc.Player().getTime() + totalTime = xbmc.Player().getTotalTime() + while xbmc.Player().isPlaying() and (totalTime-playTime > 1) and not nextUpPage.isCancel() and not nextUpPage.isWatchNow(): + xbmc.sleep(100) playTime = xbmc.Player().getTime() totalTime = xbmc.Player().getTotalTime() - - PlaybackUtils().PLAYAllEpisodes(seasonData.get("Items")) \ No newline at end of file + nextUpPage.close() + if not nextUpPage.isCancel(): + PlaybackUtils().PLAY(item) + diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 6acdb7e0..133cd8ab 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -122,8 +122,13 @@ class WriteKodiDB(): #### ADD OR UPDATE THE FILE AND PATH ########### #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY path = "plugin://plugin.video.emby/movies/%s/" % MBitem["Id"] - filename = "plugin://plugin.video.emby/movies/%s/?id=%s&mode=play" % (MBitem["Id"],MBitem["Id"]) - + addonSettings = xbmcaddon.Addon(id='plugin.video.emby') + selectAction = addonSettings.getSetting('selectAction') + if(selectAction == "1"): + filename = "plugin://plugin.video.emby/movies/%s/?id=%s&mode=info" % (MBitem["Id"],MBitem["Id"]) + else: + filename = "plugin://plugin.video.emby/movies/%s/?id=%s&mode=play" % (MBitem["Id"],MBitem["Id"]) + #create the path cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) result = cursor.fetchone() @@ -543,8 +548,14 @@ class WriteKodiDB(): #### ADD OR UPDATE THE FILE AND PATH ########### #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY path = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/" - filename = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/?id=" + MBitem["Id"] + "&mode=play" + addonSettings = xbmcaddon.Addon(id='plugin.video.emby') + selectAction = addonSettings.getSetting('selectAction') + if(selectAction == "1"): + filename = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/?id=" + MBitem["Id"] + "&mode=info" + else: + filename = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/?id=" + MBitem["Id"] + "&mode=play" + #create the new path - return id if already exists cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) result = cursor.fetchone() diff --git a/resources/settings.xml b/resources/settings.xml index c571617a..ec3d8736 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -22,8 +22,12 @@ - - + + + + + + diff --git a/resources/skins/default/720p/ItemInfo.xml b/resources/skins/default/720p/ItemInfo.xml new file mode 100644 index 00000000..64d100c2 --- /dev/null +++ b/resources/skins/default/720p/ItemInfo.xml @@ -0,0 +1,415 @@ + + + 3002 + 2 + + 1 + 120 + 50 + + dialogeffect + + + + 0 + 0 + 1040 + 600 + DialogBack.png + + + + 20 + 20 + 1000 + 560 + FF444444 + + + + 30 + 25 + 950 + 20 + left + + font24_title + FFFFFFFFFF + + + + 30 + 55 + 300 + 20 + left + + font18_title + FFFFFFFFFF + + + + + 40 + 130 + 250 + 140 + stretch + + + 40 + 265 + 250 + 5 + - + AAFFFFFF + stretch + + + + + 60 + 100 + 175 + 250 + stretch + + + 60 + 345 + 175 + 5 + - + AAFFFFFF + stretch + + + + 30 + 380 + 240 + 120 + 3002 + 3221 + 3235 + 3002 + 3221 + 200 + + + 60 + 0 + 60 + 20 + font10 + right + center + blue + selected + ListItem.Label + + + 65 + 0 + 180 + 20 + font10 + left + center + white + white + ListItem.Label2 + + + + + 0 + 0 + 240 + 20 + Control.HasFocus(3220) + MenuItemFO.png + VisibleFadeEffect + + + 60 + 0 + 60 + 20 + font10 + right + center + blue + selected + ListItem.Label + + + 65 + 0 + 180 + 20 + font10 + left + center + white + white + ListItem.Label2 + + + + + 270 + 380 + 20 + 120 + ScrollBarV.png + ScrollBarV_bar.png + ScrollBarV_bar_focus.png + ScrollBarNib.png + ScrollBarNib.png + 3220 + 3226 + false + vertical + + + + 310 + 380 + 415 + 120 + 3221 + 3235 + 3235 + 3002 + - + 200 + + + 70 + 0 + 70 + 20 + font10 + right + center + blue + selected + ListItem.Label + + + 75 + 0 + 340 + 20 + font10 + left + center + white + white + ListItem.Label2 + + + + + 0 + 0 + 400 + 20 + Control.HasFocus(3226) + MenuItemFO.png + VisibleFadeEffect + + + 70 + 0 + 70 + 20 + font10 + right + center + blue + selected + ListItem.Label + + + 75 + 0 + 340 + 20 + font10 + left + center + white + white + ListItem.Label2 + + + + + + + 320 + 100 + 400 + 250 + font12 + + white + 3235 + true + + + 720 + 100 + 20 + 250 + ScrollBarV.png + ScrollBarV_bar.png + ScrollBarV_bar_focus.png + ScrollBarNib.png + ScrollBarNib.png + 3226 + - + 3230 + false + vertical + + + + 760 + 100 + 245calc + 450 + 3235 + 3231 + - + - + 3231 + 200 + + + 0 + 0 + 60 + 60 + $INFO[Listitem.Icon] + scale + + + 65 + 0 + 160 + 30 + font12 + left + center + blue + selected + ListItem.Label + + + 65 + 30 + 160 + 30 + font10 + left + center + white + white + ListItem.Label2 + + + + + 0 + 0 + 60 + 60 + $INFO[Listitem.Icon] + scale + + + 60 + 0 + 160 + 30 + Control.HasFocus(3230) + MenuItemFO.png + VisibleFadeEffect + + + 65 + 0 + 160 + 30 + font12 + left + center + blue + selected + ListItem.Label + + + 65 + 30 + 160 + 30 + font10 + left + center + white + white + ListItem.Label2 + + + + + 985 + 100 + 20 + 450 + ScrollBarV.png + ScrollBarV_bar.png + ScrollBarV_bar_focus.png + ScrollBarNib.png + ScrollBarNib.png + 3230 + - + false + vertical + + + + 30 + 520 + 150 + 40 + center + + font13 + - + 3220 + 3220 + + + + + \ No newline at end of file diff --git a/resources/skins/default/720p/NextUpInfo.xml b/resources/skins/default/720p/NextUpInfo.xml new file mode 100644 index 00000000..05ada47a --- /dev/null +++ b/resources/skins/default/720p/NextUpInfo.xml @@ -0,0 +1,245 @@ + + + 3012 + 0 + + + + 0 + -150 + 1280 + 256 + HomeNowPlayingBack.png + + + Clock label + 450 + 5 + 800 + 25 + right + center + font13 + white + black + + conditional + + + 0 + 230r + 1280 + 230 + HomeNowPlayingBack.png + + + cover image + 20 + 350r + 300 + 330 + + + clearart + false + + + 330 + 185r + + TV Show label + 20 + 30 + 910 + 25 + left + font12 + + grey2 + black + VideoPlayer.Content(Episodes) + + + 100% + 0 + 175 + 40 + false + + + 100% + 267 + 0 + 40 + false + + + text + 30 + 62 + 550 + 98 + left + + font13 + true + false + + + 20 + 60 + 910 + 35 + 5 + horizontal + + 100% + 50 + 40 + false + + + 100% + 50 + 40 + false + false + + + auto + 30 + font30 + left + center + + grey + true + + + Watch now button + 200 + 40 + + font12_title + 3013 + 3013 + + + cancel button + 200 + 40 + + font12_title + 3012 + 3012 + + + + 0 + 120 + 910 + 25 + + center + center + font12 + grey + true + !Window.IsVisible(VideoOSD) + !VideoPlayer.Content(LiveTV) + VisibleChange + + + + 330 + 95r + !VideoPlayer.Content(LiveTV) | [VideoPlayer.Content(LiveTV) + VideoPlayer.HasEpg] + + !VideoPlayer.Content(LiveTV) + 0 + 0 + 100 + 40 + font13 + left + center + + + + ProgressbarCache + 100 + 15 + 720 + 16 + Player.ProgressCache + OSDProgressMidLight.png + + + Progressbar + 100 + 15 + 720 + 16 + Player.Progress + + + !VideoPlayer.Content(LiveTV) + 820 + 0 + 100 + 40 + font13 + right + center + + + + + + + 0 + 20 + VisibleChange + + media info background image + 0 + 0 + 1280 + 160 + black-back.png + + + row 1 label + 50 + 10 + 1180 + 30 + left + center + font12 + + + + row 2 label + 50 + 55 + 1180 + 30 + left + center + font12 + + + + row 3 label + 50 + 100 + 1180 + 45 + left + center + font12 + + + + + \ No newline at end of file diff --git a/resources/skins/default/720p/PersonInfo.xml b/resources/skins/default/720p/PersonInfo.xml new file mode 100644 index 00000000..e05ca112 --- /dev/null +++ b/resources/skins/default/720p/PersonInfo.xml @@ -0,0 +1,205 @@ + + + 3010 + 2 + + 1 + 120 + 50 + + dialogeffect + + + 0 + 0 + 1040 + 600 + DialogBack.png + + + + 20 + 20 + 1000 + 560 + $INFO[Skin.CurrentTheme,special://skin/backgrounds/,.jpg] + ![Skin.HasSetting(UseCustomBackground) + !IsEmpty(Skin.String(CustomBackgroundPath))] + VisibleFadeEffect + FF444444 + + + + Dialog Header image + 40 + 16 + 960 + 40 + dialogheader.png + + + + header label + 40 + 20 + 960 + 30 + font13_title + + center + center + selected + black + + + + + + person name + 30 + 65 + 550 + 100 + left + + font13 + white + + + + 30 + 120 + 250 + 250 + keep + + + + text + 300 + 100 + 630 + 280 + left + + font12 + 3005 + + + 940 + 100 + 20 + 280 + ScrollBarV.png + ScrollBarV_bar.png + ScrollBarV_bar_focus.png + ScrollBarNib.png + ScrollBarNib.png + 8 + 3001 + - + 3010 + false + vertical + + + + + 40 + 390 + 940 + 170 + - + - + 3005 + 3011 + 3011 + 200 + horizontal + + + 0 + 0 + 100 + 150 + $INFO[Listitem.Icon] + button-nofocus.png + 5 + + + 0 + 150 + 100 + 20 + left + font10 + FFFFFFFFFF + + + + + + 0 + 0 + 100 + 150 + $INFO[Listitem.Icon] + button-nofocus.png + 5 + + + 0 + 0 + 100 + 150 + $INFO[Listitem.Icon] + button-focus.png + 5 + Control.HasFocus(3010) + + + 0 + 150 + 100 + 20 + left + font10 + FFFFFFFFFF + + + + + + 40 + 560 + 940 + 20 + ScrollBarH.png + ScrollBarH_bar.png + ScrollBarH_bar_focus.png + ScrollBarNib.png + ScrollBarNib.png + 3010 + false + horizontal + + + + + diff --git a/service.py b/service.py index 80395ad4..f21bb036 100644 --- a/service.py +++ b/service.py @@ -94,9 +94,14 @@ class Service(): pass lastProgressUpdate = datetime.today() # only try autoplay when there's 20 seconds or less remaining and only once! - if (totalTime - playTime <= 20 and (lastFile==None or lastFile!=currentFile)): - lastFile = currentFile - player.autoPlayPlayback() + addonSettings = xbmcaddon.Addon(id='plugin.video.emby') + + # if its an episode see if autoplay is enabled + if addonSettings.getSetting("autoPlaySeason")=="true": + notificationtime = addonSettings.getSetting("autoPlaySeasonTime") + if (totalTime - playTime <= int(notificationtime) and (lastFile==None or lastFile!=currentFile)): + lastFile = currentFile + player.autoPlayPlayback() except Exception, e: self.logMsg("Exception in Playback Monitor Service: %s" % e)