This commit is contained in:
SpootDev 2016-03-31 14:48:52 -05:00
parent 9da11785d6
commit 372c61ef92

View file

@ -1,327 +1,323 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################################# #################################################################################################
import json import json
import threading import threading
import websocket import websocket
import xbmc import xbmc
import xbmcgui import xbmcgui
import clientinfo import clientinfo
import downloadutils import downloadutils
import librarysync import librarysync
import playlist import playlist
import userclient import userclient
import utils import utils
import logging import logging
logging.basicConfig() logging.basicConfig()
################################################################################################# #################################################################################################
class WebSocket_Client(threading.Thread): class WebSocket_Client(threading.Thread):
_shared_state = {} _shared_state = {}
client = None client = None
stopWebsocket = False stopWebsocket = False
def __init__(self): def __init__(self):
self.__dict__ = self._shared_state self.__dict__ = self._shared_state
self.monitor = xbmc.Monitor() self.monitor = xbmc.Monitor()
self.doUtils = downloadutils.DownloadUtils() self.doUtils = downloadutils.DownloadUtils()
self.clientInfo = clientinfo.ClientInfo() self.clientInfo = clientinfo.ClientInfo()
self.addonName = self.clientInfo.getAddonName() self.addonName = self.clientInfo.getAddonName()
self.deviceId = self.clientInfo.getDeviceId() self.deviceId = self.clientInfo.getDeviceId()
self.librarySync = librarysync.LibrarySync() self.librarySync = librarysync.LibrarySync()
threading.Thread.__init__(self) threading.Thread.__init__(self)
def logMsg(self, msg, lvl=1): def logMsg(self, msg, lvl=1):
self.className = self.__class__.__name__ self.className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl) utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
def sendProgressUpdate(self, data): def sendProgressUpdate(self, data):
log = self.logMsg self.logMsg("sendProgressUpdate", 2)
try:
log("sendProgressUpdate", 2) messageData = {
try:
messageData = { 'MessageType': "ReportPlaybackProgress",
'Data': data
'MessageType': "ReportPlaybackProgress", }
'Data': data messageString = json.dumps(messageData)
} self.client.send(messageString)
messageString = json.dumps(messageData) self.logMsg("Message data: %s" % messageString, 2)
self.client.send(messageString)
log("Message data: %s" % messageString, 2) except Exception as e:
self.logMsg("Exception: %s" % e, 1)
except Exception as e:
log("Exception: %s" % e, 1) def on_message(self, ws, message):
def on_message(self, ws, message): window = utils.window
lang = utils.language
log = self.logMsg
window = utils.window result = json.loads(message)
lang = utils.language messageType = result['MessageType']
data = result['Data']
result = json.loads(message)
messageType = result['MessageType'] if messageType not in ('SessionEnded'):
data = result['Data'] # Mute certain events
self.logMsg("Message: %s" % message, 1)
if messageType not in ('SessionEnded'):
# Mute certain events if messageType == "Play":
log("Message: %s" % message, 1) # A remote control play command has been sent from the server.
itemIds = data['ItemIds']
if messageType == "Play": command = data['PlayCommand']
# A remote control play command has been sent from the server.
itemIds = data['ItemIds'] pl = playlist.Playlist()
command = data['PlayCommand'] dialog = xbmcgui.Dialog()
pl = playlist.Playlist() if command == "PlayNow":
dialog = xbmcgui.Dialog() dialog.notification(
heading="Emby for Kodi",
if command == "PlayNow": message="%s %s" % (len(itemIds), lang(33004)),
dialog.notification( icon="special://home/addons/plugin.video.emby/icon.png",
heading="Emby for Kodi", sound=False)
message="%s %s" % (len(itemIds), lang(33004)), startat = data.get('StartPositionTicks', 0)
icon="special://home/addons/plugin.video.emby/icon.png", pl.playAll(itemIds, startat)
sound=False)
startat = data.get('StartPositionTicks', 0) elif command == "PlayNext":
pl.playAll(itemIds, startat) dialog.notification(
heading="Emby for Kodi",
elif command == "PlayNext": message="%s %s" % (len(itemIds), lang(33005)),
dialog.notification( icon="special://home/addons/plugin.video.emby/icon.png",
heading="Emby for Kodi", sound=False)
message="%s %s" % (len(itemIds), lang(33005)), newplaylist = pl.modifyPlaylist(itemIds)
icon="special://home/addons/plugin.video.emby/icon.png", player = xbmc.Player()
sound=False) if not player.isPlaying():
newplaylist = pl.modifyPlaylist(itemIds) # Only start the playlist if nothing is playing
player = xbmc.Player() player.play(newplaylist)
if not player.isPlaying():
# Only start the playlist if nothing is playing elif messageType == "Playstate":
player.play(newplaylist) # A remote control update playstate command has been sent from the server.
command = data['Command']
elif messageType == "Playstate": player = xbmc.Player()
# A remote control update playstate command has been sent from the server.
command = data['Command'] actions = {
player = xbmc.Player()
'Stop': player.stop,
actions = { 'Unpause': player.pause,
'Pause': player.pause,
'Stop': player.stop, 'NextTrack': player.playnext,
'Unpause': player.pause, 'PreviousTrack': player.playprevious,
'Pause': player.pause, 'Seek': player.seekTime
'NextTrack': player.playnext, }
'PreviousTrack': player.playprevious, action = actions[command]
'Seek': player.seekTime if command == "Seek":
} seekto = data['SeekPositionTicks']
action = actions[command] seektime = seekto / 10000000.0
if command == "Seek": action(seektime)
seekto = data['SeekPositionTicks'] self.logMsg("Seek to %s." % seektime, 1)
seektime = seekto / 10000000.0 else:
action(seektime) action()
log("Seek to %s." % seektime, 1) self.logMsg("Command: %s completed." % command, 1)
else:
action() window('emby_command', value="true")
log("Command: %s completed." % command, 1)
elif messageType == "UserDataChanged":
window('emby_command', value="true") # A user changed their personal rating for an item, or their playstate was updated
userdata_list = data['UserDataList']
elif messageType == "UserDataChanged": self.librarySync.triage_items("userdata", userdata_list)
# A user changed their personal rating for an item, or their playstate was updated
userdata_list = data['UserDataList'] elif messageType == "LibraryChanged":
self.librarySync.triage_items("userdata", userdata_list)
librarySync = self.librarySync
elif messageType == "LibraryChanged": processlist = {
librarySync = self.librarySync 'added': data['ItemsAdded'],
processlist = { 'update': data['ItemsUpdated'],
'remove': data['ItemsRemoved']
'added': data['ItemsAdded'], }
'update': data['ItemsUpdated'], for action in processlist:
'remove': data['ItemsRemoved'] librarySync.triage_items(action, processlist[action])
}
for action in processlist: elif messageType == "GeneralCommand":
librarySync.triage_items(action, processlist[action])
command = data['Name']
elif messageType == "GeneralCommand": arguments = data['Arguments']
command = data['Name'] if command in ('Mute', 'Unmute', 'SetVolume',
arguments = data['Arguments'] 'SetSubtitleStreamIndex', 'SetAudioStreamIndex'):
if command in ('Mute', 'Unmute', 'SetVolume', player = xbmc.Player()
'SetSubtitleStreamIndex', 'SetAudioStreamIndex'): # These commands need to be reported back
if command == "Mute":
player = xbmc.Player() xbmc.executebuiltin('Mute')
# These commands need to be reported back elif command == "Unmute":
if command == "Mute": xbmc.executebuiltin('Mute')
xbmc.executebuiltin('Mute') elif command == "SetVolume":
elif command == "Unmute": volume = arguments['Volume']
xbmc.executebuiltin('Mute') xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume)
elif command == "SetVolume": elif command == "SetAudioStreamIndex":
volume = arguments['Volume'] index = int(arguments['Index'])
xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume) player.setAudioStream(index - 1)
elif command == "SetAudioStreamIndex": elif command == "SetSubtitleStreamIndex":
index = int(arguments['Index']) embyindex = int(arguments['Index'])
player.setAudioStream(index - 1) currentFile = player.getPlayingFile()
elif command == "SetSubtitleStreamIndex":
embyindex = int(arguments['Index']) mapping = window('emby_%s.indexMapping' % currentFile)
currentFile = player.getPlayingFile() if mapping:
externalIndex = json.loads(mapping)
mapping = window('emby_%s.indexMapping' % currentFile) # If there's external subtitles added via playbackutils
if mapping: for index in externalIndex:
externalIndex = json.loads(mapping) if externalIndex[index] == embyindex:
# If there's external subtitles added via playbackutils player.setSubtitleStream(int(index))
for index in externalIndex: break
if externalIndex[index] == embyindex: else:
player.setSubtitleStream(int(index)) # User selected internal subtitles
break external = len(externalIndex)
else: audioTracks = len(player.getAvailableAudioStreams())
# User selected internal subtitles player.setSubtitleStream(external + embyindex - audioTracks - 1)
external = len(externalIndex) else:
audioTracks = len(player.getAvailableAudioStreams()) # Emby merges audio and subtitle index together
player.setSubtitleStream(external + embyindex - audioTracks - 1) audioTracks = len(player.getAvailableAudioStreams())
else: player.setSubtitleStream(index - audioTracks - 1)
# Emby merges audio and subtitle index together
audioTracks = len(player.getAvailableAudioStreams()) # Let service know
player.setSubtitleStream(index - audioTracks - 1) window('emby_command', value="true")
# Let service know elif command == "DisplayMessage":
window('emby_command', value="true")
header = arguments['Header']
elif command == "DisplayMessage": text = arguments['Text']
xbmcgui.Dialog().notification(
header = arguments['Header'] heading=header,
text = arguments['Text'] message=text,
xbmcgui.Dialog().notification( icon="special://home/addons/plugin.video.emby/icon.png",
heading=header, time=4000)
message=text,
icon="special://home/addons/plugin.video.emby/icon.png", elif command == "SendString":
time=4000)
string = arguments['String']
elif command == "SendString": text = {
string = arguments['String'] 'jsonrpc': "2.0",
text = { 'id': 0,
'method': "Input.SendText",
'jsonrpc': "2.0", 'params': {
'id': 0,
'method': "Input.SendText", 'text': "%s" % string,
'params': { 'done': False
}
'text': "%s" % string, }
'done': False result = xbmc.executeJSONRPC(json.dumps(text))
}
} else:
result = xbmc.executeJSONRPC(json.dumps(text)) builtin = {
else: 'ToggleFullscreen': 'Action(FullScreen)',
builtin = { 'ToggleOsdMenu': 'Action(OSD)',
'ToggleContextMenu': 'Action(ContextMenu)',
'ToggleFullscreen': 'Action(FullScreen)', 'MoveUp': 'Action(Up)',
'ToggleOsdMenu': 'Action(OSD)', 'MoveDown': 'Action(Down)',
'ToggleContextMenu': 'Action(ContextMenu)', 'MoveLeft': 'Action(Left)',
'MoveUp': 'Action(Up)', 'MoveRight': 'Action(Right)',
'MoveDown': 'Action(Down)', 'Select': 'Action(Select)',
'MoveLeft': 'Action(Left)', 'Back': 'Action(back)',
'MoveRight': 'Action(Right)', 'GoHome': 'ActivateWindow(Home)',
'Select': 'Action(Select)', 'PageUp': 'Action(PageUp)',
'Back': 'Action(back)', 'NextLetter': 'Action(NextLetter)',
'GoHome': 'ActivateWindow(Home)', 'GoToSearch': 'VideoLibrary.Search',
'PageUp': 'Action(PageUp)', 'GoToSettings': 'ActivateWindow(Settings)',
'NextLetter': 'Action(NextLetter)', 'PageDown': 'Action(PageDown)',
'GoToSearch': 'VideoLibrary.Search', 'PreviousLetter': 'Action(PrevLetter)',
'GoToSettings': 'ActivateWindow(Settings)', 'TakeScreenshot': 'TakeScreenshot',
'PageDown': 'Action(PageDown)', 'ToggleMute': 'Mute',
'PreviousLetter': 'Action(PrevLetter)', 'VolumeUp': 'Action(VolumeUp)',
'TakeScreenshot': 'TakeScreenshot', 'VolumeDown': 'Action(VolumeDown)',
'ToggleMute': 'Mute', }
'VolumeUp': 'Action(VolumeUp)', action = builtin.get(command)
'VolumeDown': 'Action(VolumeDown)', if action:
} xbmc.executebuiltin(action)
action = builtin.get(command)
if action: elif messageType == "ServerRestarting":
xbmc.executebuiltin(action) if utils.settings('supressRestartMsg') == "true":
xbmcgui.Dialog().notification(
elif messageType == "ServerRestarting": heading="Emby for Kodi",
if utils.settings('supressRestartMsg') == "true": message=lang(33006),
xbmcgui.Dialog().notification( icon="special://home/addons/plugin.video.emby/icon.png")
heading="Emby for Kodi",
message=lang(33006), elif messageType == "UserConfigurationUpdated":
icon="special://home/addons/plugin.video.emby/icon.png") # Update user data set in userclient
userclient.UserClient().userSettings = data
elif messageType == "UserConfigurationUpdated": self.librarySync.refresh_views = True
# Update user data set in userclient
userclient.UserClient().userSettings = data def on_close(self, ws):
self.librarySync.refresh_views = True self.logMsg("Closed.", 2)
def on_close(self, ws): def on_open(self, ws):
self.logMsg("Closed.", 2) self.doUtils.postCapabilities(self.deviceId)
def on_open(self, ws): def on_error(self, ws, error):
self.doUtils.postCapabilities(self.deviceId) if "10061" in str(error):
# Server is offline
def on_error(self, ws, error): pass
if "10061" in str(error): else:
# Server is offline self.logMsg("Error: %s" % error, 2)
pass
else: def run(self):
self.logMsg("Error: %s" % error, 2)
window = utils.window
def run(self): monitor = self.monitor
log = self.logMsg loglevel = int(window('emby_logLevel'))
window = utils.window # websocket.enableTrace(True)
monitor = self.monitor
userId = window('emby_currUser')
loglevel = int(window('emby_logLevel')) server = window('emby_server%s' % userId)
# websocket.enableTrace(True) token = window('emby_accessToken%s' % userId)
deviceId = self.deviceId
userId = window('emby_currUser')
server = window('emby_server%s' % userId) # Get the appropriate prefix for the websocket
token = window('emby_accessToken%s' % userId) if "https" in server:
deviceId = self.deviceId server = server.replace('https', "wss")
else:
# Get the appropriate prefix for the websocket server = server.replace('http', "ws")
if "https" in server:
server = server.replace('https', "wss") websocket_url = "%s?api_key=%s&deviceId=%s" % (server, token, deviceId)
else: self.logMsg("websocket url: %s" % websocket_url, 1)
server = server.replace('http', "ws")
self.client = websocket.WebSocketApp(websocket_url,
websocket_url = "%s?api_key=%s&deviceId=%s" % (server, token, deviceId) on_message=self.on_message,
log("websocket url: %s" % websocket_url, 1) on_error=self.on_error,
on_close=self.on_close)
self.client = websocket.WebSocketApp(websocket_url,
on_message=self.on_message, self.client.on_open = self.on_open
on_error=self.on_error, self.logMsg("----===## Starting WebSocketClient ##===----", 0)
on_close=self.on_close)
while not monitor.abortRequested():
self.client.on_open = self.on_open
log("----===## Starting WebSocketClient ##===----", 0) self.client.run_forever(ping_interval=10)
if self.stopWebsocket:
while not monitor.abortRequested(): break
self.client.run_forever(ping_interval=10) if monitor.waitForAbort(5):
if self.stopWebsocket: # Abort was requested, exit
break break
if monitor.waitForAbort(5): self.logMsg("##===---- WebSocketClient Stopped ----===##", 0)
# Abort was requested, exit
break def stopClient(self):
log("##===---- WebSocketClient Stopped ----===##", 0) self.stopWebsocket = True
self.client.close()
def stopClient(self):
self.stopWebsocket = True
self.client.close()
self.logMsg("Stopping thread.", 1) self.logMsg("Stopping thread.", 1)