From 79e4bd8a6a10ec8270cbc61e37672b4f4f73cdfc Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sat, 16 May 2015 01:31:08 -0500 Subject: [PATCH] Fix watched feedback and added General command Everything in the remote control is supported except for audiostream and subtitleindex. Turns out the watched playcount bug was indeed a feedback, so to prevent this I'm skipping the first message that has the itemId right after marking watched. --- resources/lib/DownloadUtils.py | 14 ++++- resources/lib/KodiMonitor.py | 4 +- resources/lib/PlaybackUtils.py | 7 +++ resources/lib/Player.py | 93 +++++++++++++++++--------------- resources/lib/WebSocketClient.py | 90 ++++++++++++++++++++++++++----- service.py | 2 + 6 files changed, 152 insertions(+), 58 deletions(-) diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py index dabef416..1335063a 100644 --- a/resources/lib/DownloadUtils.py +++ b/resources/lib/DownloadUtils.py @@ -71,8 +71,18 @@ class DownloadUtils(): url = "{server}/mediabrowser/Sessions/Capabilities/Full" data = { 'PlayableMediaTypes': "Audio,Video", - 'SupportedCommands': "Play,Playstate,SendString,DisplayMessage,PlayNext", - 'SupportsMediaControl': True + 'SupportsMediaControl': True, + 'SupportedCommands': ( + + "MoveUp,MoveDown,MoveLeft,MoveRight,Select," + "Back,ToggleContextMenu,ToggleFullscreen,ToggleOsdMenu," + "GoHome,PageUp,NextLetter,GoToSearch," + "GoToSettings,PageDown,PreviousLetter,TakeScreenshot," + "VolumeUp,VolumeDown,ToggleMute,SendString,DisplayMessage," + + "Mute,Unmute,SetVolume," + "Play,Playstate,PlayNext" + ) } self.logMsg("Capabilities URL: %s" % url, 2) diff --git a/resources/lib/KodiMonitor.py b/resources/lib/KodiMonitor.py index d0884da5..653b51f6 100644 --- a/resources/lib/KodiMonitor.py +++ b/resources/lib/KodiMonitor.py @@ -42,8 +42,9 @@ class Kodi_Monitor(xbmc.Monitor): item = jsondata.get("item").get("id") type = jsondata.get("item").get("type") prop = WINDOW.getProperty('Played%s%s' % (type,item)) + processWatched = WINDOW.getProperty('played_skipWatched') - if (playcount != None) and (prop != "true"): + if (playcount != None) and (prop != "true") and (processWatched != "true"): WINDOW.setProperty("Played%s%s" % (type,item), "true") utils.logMsg("MB# Sync","Kodi_Monitor--> VideoLibrary.OnUpdate : " + str(data),2) WriteKodiVideoDB().updatePlayCountFromKodi(item, type, playcount) @@ -87,6 +88,7 @@ class Kodi_Monitor(xbmc.Monitor): # triggers 3 times in a row. xbmc.sleep(100) self.WINDOW.clearProperty("Played%s%s" % (type,id)) + self.WINDOW.clearProperty('played_skipWatched') diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index 0d25fa71..3b80b597 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -108,10 +108,17 @@ class PlaybackUtils(): resume_result = resumeScreen.select(self.language(30105), display_list) if resume_result == 0: WINDOW.setProperty(playurl+"seektime", str(seekTime)) + elif resume_result < 0: + # User cancelled dialog + xbmc.log("Emby player -> User cancelled resume dialog.") + return else: WINDOW.clearProperty(playurl+"seektime") else: WINDOW.clearProperty(playurl+"seektime") + else: + # Playback started from library + WINDOW.setProperty(playurl+"seektime", str(seekTime)) if result.get("Type")=="Episode": WINDOW.setProperty(playurl+"refresh_id", result.get("SeriesId")) diff --git a/resources/lib/Player.py b/resources/lib/Player.py index b98eaa7c..6372e7ba 100644 --- a/resources/lib/Player.py +++ b/resources/lib/Player.py @@ -66,14 +66,13 @@ class Player( xbmc.Player ): addonSettings = xbmcaddon.Addon(id='plugin.video.emby') self.logMsg("emby Service -> played_information : " + str(self.played_information)) - + for item_url in self.played_information: data = self.played_information.get(item_url) - if (data is not None): self.logMsg("emby Service -> item_url : " + item_url) self.logMsg("emby Service -> item_data : " + str(data)) - + runtime = data.get("runtime") currentPosition = data.get("currentPosition") item_id = data.get("item_id") @@ -81,6 +80,9 @@ class Player( xbmc.Player ): currentFile = data.get("currentfile") type = data.get("Type") + # Prevent websocket feedback + self.WINDOW.setProperty("played_itemId", item_id) + if(currentPosition != None and self.hasData(runtime)): runtimeTicks = int(runtime) self.logMsg("emby Service -> runtimeticks:" + str(runtimeTicks)) @@ -88,6 +90,10 @@ class Player( xbmc.Player ): markPlayedAt = float(90) / 100 self.logMsg("emby Service -> Percent Complete:" + str(percentComplete) + " Mark Played At:" + str(markPlayedAt)) + if percentComplete < markPlayedAt: + # Do not mark as watched + self.WINDOW.setProperty('played_skipWatched', 'true') + self.stopPlayback(data) if percentComplete > .80 and data.get("Type") == "Episode" and addonSettings.getSetting("offerDelete")=="true": @@ -116,28 +122,16 @@ class Player( xbmc.Player ): self.logMsg("stopPlayback called", 2) item_id = data.get("item_id") - audioindex = data.get("AudioStreamIndex") - subtitleindex = data.get("SubtitleStreamIndex") - playMethod = data.get("playmethod") currentPosition = data.get("currentPosition") positionTicks = int(currentPosition * 10000000) url = "{server}/mediabrowser/Sessions/Playing/Stopped" postdata = { - 'QueueableMediaTypes': "Video", - 'CanSeek': True, 'ItemId': item_id, 'MediaSourceId': item_id, - 'PlayMethod': playMethod, 'PositionTicks': positionTicks - } - - if audioindex: - postdata['AudioStreamIndex'] = audioindex - - if subtitleindex: - postdata['SubtitleStreamIndex'] = subtitleindex + } self.doUtils.downloadUrl(url, postBody=postdata, type="POST") @@ -154,7 +148,7 @@ class Player( xbmc.Player ): data = self.played_information.get(currentFile) # only report playback if emby has initiated the playback (item_id has value) - if (data is not None) and (data.get("item_id") is not None): + if data is not None and data.get("item_id") is not None: # Get playback information item_id = data.get("item_id") @@ -167,14 +161,22 @@ class Player( xbmc.Player ): if paused is None: paused = False - #url = "{server}/mediabrowser/Sessions/Playing/Progress" + # Get playback volume + volume_query = '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume","muted"]}, "id": 1}' + result = xbmc.executeJSONRPC(volume_query) + result = json.loads(result) + volume = result.get(u'result').get(u'volume') + muted = result.get(u'result').get(u'muted') + postdata = { 'QueueableMediaTypes': "Video", 'CanSeek': True, 'ItemId': item_id, 'MediaSourceId': item_id, + 'PlayMethod': playMethod, 'IsPaused': paused, - 'PlayMethod': playMethod + 'VolumeLevel': volume, + 'IsMuted': muted } if playTime: @@ -243,15 +245,17 @@ class Player( xbmc.Player ): itemType = WINDOW.getProperty(currentFile + "type") seekTime = WINDOW.getProperty(currentFile + "seektime") - username = WINDOW.getProperty('currUser') - sessionId = WINDOW.getProperty('sessionId%s' % username) - - if seekTime != "": - PlaybackUtils().seekToPosition(int(seekTime)) + # Get playback volume + volume_query = '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume","muted"]}, "id": 1}' + result = xbmc.executeJSONRPC(volume_query) + result = json.loads(result) + volume = result.get(u'result').get(u'volume') + muted = result.get(u'result').get(u'muted') - if (not item_id) or (len(item_id) == 0): - self.logMsg("onPlayBackStarted: No info for current playing file", 0) - return + if seekTime: + PlaybackUtils().seekToPosition(int(seekTime)) + else: + seekTime = 0 url = "{server}/mediabrowser/Sessions/Playing" postdata = { @@ -259,7 +263,10 @@ class Player( xbmc.Player ): 'CanSeek': True, 'ItemId': item_id, 'MediaSourceId': item_id, - 'PlayMethod': playMethod + 'PlayMethod': playMethod, + 'VolumeLevel': volume, + 'PositionTicks': int(seekTime), + 'IsMuted': muted } if audioindex: @@ -268,24 +275,24 @@ class Player( xbmc.Player ): if subtitleindex: postdata['SubtitleStreamIndex'] = subtitleindex + # Post playback to server self.logMsg("Sending POST play started.", 1) - #self.logMsg("emby Service -> Sending Post Play Started : " + url, 0) - self.doUtils.downloadUrl(url, postBody=postdata, type="POST") + self.doUtils.downloadUrl(url, postBody=postdata, type="POST") # save data map for updates and position calls - data = {} - data["runtime"] = runtime - data["item_id"] = item_id - data["refresh_id"] = refresh_id - data["currentfile"] = currentFile - data["AudioStreamIndex"] = audioindex - data["SubtitleStreamIndex"] = subtitleindex - data["playmethod"] = playMethod - data["Type"] = itemType + data = { + 'runtime': runtime, + 'item_id': item_id, + 'refresh_id': refresh_id, + 'currentfile': currentFile, + 'AudioStreamIndex': audioindex, + 'SubtitleStreamIndex': subtitleindex, + 'playmethod': playMethod, + 'type': itemType, + 'PositionTicks': int(seekTime) + } self.played_information[currentFile] = data - - self.logMsg("emby Service -> ADDING_FILE : " + currentFile, 0) - self.logMsg("emby Service -> ADDING_FILE : " + str(self.played_information), 0) + self.logMsg("ADDING_FILE: %s" % self.played_information, 1) # log some playback stats if(itemType != None): @@ -303,7 +310,7 @@ class Player( xbmc.Player ): self.playStats[playMethod] = 1 # reset in progress position - self.reportPlayback() + #self.reportPlayback() def GetPlayStats(self): return self.playStats diff --git a/resources/lib/WebSocketClient.py b/resources/lib/WebSocketClient.py index c13a027f..fd17fd93 100644 --- a/resources/lib/WebSocketClient.py +++ b/resources/lib/WebSocketClient.py @@ -99,8 +99,14 @@ class WebSocketThread(threading.Thread): messageType = result.get("MessageType") data = result.get("Data") - - if(messageType != None and messageType == "Play" and data != None): + WINDOW = xbmcgui.Window( 10000 ) + playedItemId = WINDOW.getProperty('played_itemId') + + if (playedItemId != '') and (playedItemId in message): + # Prevent feedback for watched + WINDOW.clearProperty('played_itemId') + + elif(messageType != None and messageType == "Play" and data != None): itemIds = data.get("ItemIds") playCommand = data.get("PlayCommand") @@ -144,7 +150,6 @@ class WebSocketThread(threading.Thread): elif(messageType != None and messageType == "UserDataChanged"): # for now just do a full playcount sync - WINDOW = xbmcgui.Window( 10000 ) self.logMsg("Message : Doing UserDataChanged", 0) userDataList = data.get("UserDataList") self.logMsg("Message : Doing UserDataChanged : UserDataList : " + str(userDataList), 0) @@ -169,16 +174,77 @@ class WebSocketThread(threading.Thread): elif messageType == "GeneralCommand": - if data.get("Name") == "DisplayMessage": - message = data.get("Arguments") - header = message[u'Header'] - text = message[u'Text'] - xbmcgui.Dialog().notification(header, text) + command = data.get("Name") + arguments = data.get("Arguments") + + commandsPlayback = [ + 'Mute','Unmute','SetVolume', + 'SetAudioStreamIndex' + ] - elif data.get("Name") == "SendString": - message = data.get("Arguments") - string = message[u'String'] - xbmcgui.Dialog().notification("Emby server", string) + if command in commandsPlayback: + # These commands need to be reported back + if command == "Mute": + xbmc.executebuiltin('Mute') + elif command == "Unmute": + xbmc.executebuiltin('Mute') + elif command == "SetVolume": + volume = arguments[u'Volume'] + xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume) + # Report playback + WINDOW.setProperty('commandUpdate', 'true') + + else: + # GUI commands + if command == "ToggleFullscreen": + xbmc.executebuiltin('Action(FullScreen)') + elif command == "ToggleOsdMenu": + xbmc.executebuiltin('Action(OSD)') + elif command == "MoveUp": + xbmc.executebuiltin('Action(Up)') + elif command == "MoveDown": + xbmc.executebuiltin('Action(Down)') + elif command == "MoveLeft": + xbmc.executebuiltin('Action(Left)') + elif command == "MoveRight": + xbmc.executebuiltin('Action(Right)') + elif command == "Select": + xbmc.executebuiltin('Action(Select)') + elif command == "Back": + xbmc.executebuiltin('Action(back)') + elif command == "ToggleContextMenu": + xbmc.executebuiltin('Action(ContextMenu)') + elif command == "GoHome": + xbmc.executebuiltin('ActivateWindow(Home)') + elif command == "PageUp": + xbmc.executebuiltin('Action(PageUp)') + elif command == "NextLetter": + xbmc.executebuiltin('Action(NextLetter)') + elif command == "GoToSearch": + xbmc.executebuiltin('VideoLibrary.Search') + elif command == "GoToSettings": + xbmc.executebuiltin('ActivateWindow(Settings)') + elif command == "PageDown": + xbmc.executebuiltin('Action(PageDown)') + elif command == "PreviousLetter": + xbmc.executebuiltin('Action(PrevLetter)') + elif command == "TakeScreenshot": + xbmc.executebuiltin('TakeScreenshot') + elif command == "ToggleMute": + xbmc.executebuiltin('Mute') + elif command == "VolumeUp": + xbmc.executebuiltin('Action(VolumeUp)') + elif command == "VolumeDown": + xbmc.executebuiltin('Action(VolumeDown)') + elif command == "DisplayMessage": + header = arguments[u'Header'] + text = arguments[u'Text'] + xbmcgui.Dialog().notification(header, text) + elif command == "SendString": + string = arguments[u'String'] + xbmcgui.Dialog().notification("Emby server", string) + else: + self.logMsg("Unknown command.", 1) def remove_items(self, itemsRemoved): diff --git a/service.py b/service.py index 206ece22..820e5d43 100644 --- a/service.py +++ b/service.py @@ -98,6 +98,7 @@ class Service(): ws.start() if xbmc.Player().isPlaying(): + WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time()))) try: playTime = xbmc.Player().getTime() totalTime = xbmc.Player().getTotalTime() @@ -131,6 +132,7 @@ class Service(): pass else: + WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time()))) #full sync if (startupComplete == False): self.logMsg("Doing_Db_Sync: syncDatabase (Started)")