summaryrefslogtreecommitdiff
path: root/plugin.video.embycon/resources/lib/websocket_client.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugin.video.embycon/resources/lib/websocket_client.py')
-rw-r--r--plugin.video.embycon/resources/lib/websocket_client.py302
1 files changed, 302 insertions, 0 deletions
diff --git a/plugin.video.embycon/resources/lib/websocket_client.py b/plugin.video.embycon/resources/lib/websocket_client.py
new file mode 100644
index 0000000..db0a073
--- /dev/null
+++ b/plugin.video.embycon/resources/lib/websocket_client.py
@@ -0,0 +1,302 @@
+# -*- coding: utf-8 -*-
+
+#################################################################################################
+
+import json
+import threading
+import websocket
+
+import xbmc
+import xbmcgui
+
+from functions import PLAY
+from simple_logging import SimpleLogging
+import clientinfo
+import downloadutils
+from json_rpc import json_rpc
+
+log = SimpleLogging(__name__)
+
+class WebSocketClient(threading.Thread):
+
+ _shared_state = {}
+
+ _client = None
+ _stop_websocket = False
+
+ def __init__(self):
+
+ self.__dict__ = self._shared_state
+ self.monitor = xbmc.Monitor()
+
+ self.client_info = clientinfo.ClientInformation()
+ self.device_id = self.client_info.getDeviceId()
+
+ threading.Thread.__init__(self)
+
+ def on_message(self, ws, message):
+
+ result = json.loads(message)
+ message_type = result['MessageType']
+
+ if message_type == 'Play':
+ data = result['Data']
+ self._play(data)
+
+ elif message_type == 'Playstate':
+ data = result['Data']
+ self._playstate(data)
+
+ elif message_type == "UserDataChanged":
+ log.debug("WebSocket Message UserDataChanged: {0}", message)
+
+ elif message_type == "LibraryChanged":
+ log.debug("WebSocket Message LibraryChanged: {0}", message)
+
+ elif message_type == "GeneralCommand":
+ data = result['Data']
+ self._general_commands(data)
+
+ else:
+ log.debug("WebSocket Message Type: {0}", message)
+
+ def _play(cls, data):
+
+ item_ids = data['ItemIds']
+ command = data['PlayCommand']
+
+ if command == 'PlayNow':
+ startat = data.get('StartPositionTicks', 0)
+ log.debug("WebSocket Message PlayNow: {0}", data)
+
+ media_source_id = data.get("MediaSourceId", "")
+
+ params = {}
+ params["item_id"] = item_ids[0]
+ params["auto_resume"] = str(startat)
+ params["media_source_id"] = media_source_id
+ params["use_default"] = "true"
+ PLAY(params)
+
+
+ def _playstate(cls, data):
+
+ command = data['Command']
+ player = xbmc.Player()
+
+ actions = {
+
+ 'Stop': player.stop,
+ 'Unpause': player.pause,
+ 'Pause': player.pause,
+ 'PlayPause': player.pause,
+ 'NextTrack': player.playnext,
+ 'PreviousTrack': player.playprevious
+ }
+ if command == 'Seek':
+
+ if player.isPlaying():
+ seek_to = data['SeekPositionTicks']
+ seek_time = seek_to / 10000000.0
+ player.seekTime(seek_time)
+ log.debug("Seek to {0}", seek_time)
+
+ elif command in actions:
+ actions[command]()
+ log.debug("Command: {0} completed", command)
+
+ else:
+ log.debug("Unknown command: {0}", command)
+ return
+
+ def _general_commands(cls, data):
+
+ command = data['Name']
+ arguments = data['Arguments']
+
+ if command in ('Mute',
+ 'Unmute',
+ 'SetVolume',
+ 'SetSubtitleStreamIndex',
+ 'SetAudioStreamIndex',
+ 'SetRepeatMode'):
+
+ player = xbmc.Player()
+ # These commands need to be reported back
+ if command == 'Mute':
+ xbmc.executebuiltin('Mute')
+
+ elif command == 'Unmute':
+ xbmc.executebuiltin('Mute')
+
+ elif command == 'SetVolume':
+ volume = arguments['Volume']
+ xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume)
+
+ elif command == 'SetAudioStreamIndex':
+ index = int(arguments['Index'])
+ player.setAudioStream(index - 1)
+
+ elif command == 'SetRepeatMode':
+ mode = arguments['RepeatMode']
+ xbmc.executebuiltin('xbmc.PlayerControl(%s)' % mode)
+
+ elif command == 'DisplayMessage':
+
+ header = arguments['Header']
+ text = arguments['Text']
+ # show notification here
+ log.debug("WebSocket DisplayMessage: {0}", text)
+ xbmcgui.Dialog().notification("EmbyCon", text)
+
+ elif command == 'SendString':
+
+ params = {
+
+ 'text': arguments['String'],
+ 'done': False
+ }
+ json_rpc('Input.SendText').execute(params)
+
+ elif command in ('MoveUp', 'MoveDown', 'MoveRight', 'MoveLeft'):
+ # Commands that should wake up display
+ actions = {
+
+ 'MoveUp': "Input.Up",
+ 'MoveDown': "Input.Down",
+ 'MoveRight': "Input.Right",
+ 'MoveLeft': "Input.Left"
+ }
+ json_rpc(actions[command]).execute()
+
+ elif command == 'GoHome':
+ json_rpc('GUI.ActivateWindow').execute({'window': "home"})
+
+ elif command == "Guide":
+ json_rpc('GUI.ActivateWindow').execute({'window': "tvguide"})
+
+ else:
+ builtin = {
+
+ 'ToggleFullscreen': 'Action(FullScreen)',
+ 'ToggleOsdMenu': 'Action(OSD)',
+ 'ToggleContextMenu': 'Action(ContextMenu)',
+ 'Select': 'Action(Select)',
+ 'Back': 'Action(back)',
+ 'PageUp': 'Action(PageUp)',
+ 'NextLetter': 'Action(NextLetter)',
+ 'GoToSearch': 'VideoLibrary.Search',
+ 'GoToSettings': 'ActivateWindow(Settings)',
+ 'PageDown': 'Action(PageDown)',
+ 'PreviousLetter': 'Action(PrevLetter)',
+ 'TakeScreenshot': 'TakeScreenshot',
+ 'ToggleMute': 'Mute',
+ 'VolumeUp': 'Action(VolumeUp)',
+ 'VolumeDown': 'Action(VolumeDown)',
+ }
+ if command in builtin:
+ xbmc.executebuiltin(builtin[command])
+
+ def on_close(self, ws):
+ log.debug("closed")
+
+ def on_open(self, ws):
+ self.post_capabilities()
+
+ def on_error(self, ws, error):
+ log.debug("Error: {0}", error)
+
+ def run(self):
+
+ # websocket.enableTrace(True)
+ download_utils = downloadutils.DownloadUtils()
+
+ token = None
+ while token is None or token == "":
+ token = download_utils.authenticate()
+ if self.monitor.waitForAbort(10):
+ return
+
+ # Get the appropriate prefix for the websocket
+ server = download_utils.getServer()
+ if "https" in server:
+ server = server.replace('https', "wss")
+ else:
+ server = server.replace('http', "ws")
+
+ websocket_url = "%s/embywebsocket?api_key=%s&deviceId=%s" % (server, token, self.device_id)
+ log.debug("websocket url: {0}", websocket_url)
+
+ self._client = websocket.WebSocketApp(websocket_url,
+ on_message=self.on_message,
+ on_error=self.on_error,
+ on_close=self.on_close)
+ self._client.on_open = self.on_open
+ log.debug("Starting WebSocketClient")
+
+ while not self.monitor.abortRequested():
+
+ self._client.run_forever(ping_interval=10)
+
+ if self._stop_websocket:
+ break
+
+ if self.monitor.waitForAbort(20):
+ # Abort was requested, exit
+ break
+
+ log.debug("Reconnecting WebSocket")
+
+ log.debug("WebSocketClient Stopped")
+
+ def stop_client(self):
+
+ self._stop_websocket = True
+ if self._client is not None:
+ self._client.close()
+ log.debug("Stopping WebSocket (stop_client called)")
+
+ def post_capabilities(self):
+
+ url = "{server}/emby/Sessions/Capabilities/Full?format=json"
+ data = {
+ 'SupportsMediaControl': True,
+ 'PlayableMediaTypes': ["Video"],
+ 'SupportedCommands': ["MoveUp",
+ "MoveDown",
+ "MoveLeft",
+ "MoveRight",
+ "Select",
+ "Back",
+ "ToggleContextMenu",
+ "ToggleFullscreen",
+ "ToggleOsdMenu",
+ "GoHome",
+ "PageUp",
+ "NextLetter",
+ "GoToSearch",
+ "GoToSettings",
+ "PageDown",
+ "PreviousLetter",
+ "TakeScreenshot",
+ "VolumeUp",
+ "VolumeDown",
+ "ToggleMute",
+ "SendString",
+ "DisplayMessage",
+ #"SetAudioStreamIndex",
+ #"SetSubtitleStreamIndex",
+ "SetRepeatMode",
+ "Mute",
+ "Unmute",
+ "SetVolume",
+ "PlayNext",
+ "Play",
+ "Playstate",
+ "PlayMediaSource"]
+ }
+
+ download_utils = downloadutils.DownloadUtils()
+ download_utils.downloadUrl(url, postBody=data, method="POST")
+ log.debug("Posted Capabilities: {0}", data)
+