This commit is contained in:
angelblue05 2016-09-07 02:14:02 -05:00
parent b65d6baad0
commit e941674e74
4 changed files with 235 additions and 221 deletions

View file

@ -368,7 +368,7 @@ class Player(xbmc.Player):
# Report progress via websocketclient # Report progress via websocketclient
postdata = json.dumps(postdata) postdata = json.dumps(postdata)
log.debug("Report: %s" % postdata) log.debug("Report: %s" % postdata)
self.ws.sendProgressUpdate(postdata) self.ws.send_progress_update(postdata)
def onPlayBackPaused(self): def onPlayBackPaused(self):

View file

@ -55,7 +55,7 @@ def dialog(type_, **kwargs):
d = xbmcgui.Dialog() d = xbmcgui.Dialog()
if "icon" in kwargs: if "icon" in kwargs:
kwargs['icon'] = kwargs['icon'].replace("{default}", kwargs['icon'] = kwargs['icon'].replace("{emby}",
"special://home/addons/plugin.video.emby/icon.png") "special://home/addons/plugin.video.emby/icon.png")
types = { types = {

View file

@ -8,14 +8,13 @@ import threading
import websocket import websocket
import xbmc import xbmc
import xbmcgui
import clientinfo import clientinfo
import downloadutils import downloadutils
import librarysync import librarysync
import playlist import playlist
import userclient import userclient
from utils import window, settings, language as lang, JSONRPC from utils import window, settings, dialog, language as lang, JSONRPC
################################################################################################## ##################################################################################################
@ -28,8 +27,8 @@ class WebSocket_Client(threading.Thread):
_shared_state = {} _shared_state = {}
client = None _client = None
stopWebsocket = False _stop_websocket = False
def __init__(self): def __init__(self):
@ -37,103 +36,56 @@ class WebSocket_Client(threading.Thread):
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.client_info = clientinfo.ClientInfo()
self.deviceId = self.clientInfo.get_device_id() self.device_id = self.client_info.get_device_id()
self.librarySync = librarysync.LibrarySync() self.library_sync = librarysync.LibrarySync()
threading.Thread.__init__(self) threading.Thread.__init__(self)
def sendProgressUpdate(self, data): def send_progress_update(self, data):
log.debug("sendProgressUpdate") log.debug("sendProgressUpdate")
try: try:
messageData = { message = {
'MessageType': "ReportPlaybackProgress", 'MessageType': "ReportPlaybackProgress",
'Data': data 'Data': data
} }
messageString = json.dumps(messageData) message_str = json.dumps(message)
self.client.send(messageString) self._client.send(message_str)
log.debug("Message data: %s" % messageString) log.debug("Message data: %s", message_str)
except Exception as e: except Exception as error:
log.exception(e) log.exception(error)
def on_message(self, ws, message): def on_message(self, ws, message):
result = json.loads(message) result = json.loads(message)
messageType = result['MessageType'] message_type = result['MessageType']
data = result['Data'] data = result['Data']
dialog = xbmcgui.Dialog()
if messageType not in ('SessionEnded'): if message_type not in ('SessionEnded'):
# Mute certain events # Mute certain events
log.info("Message: %s" % message) log.info("Message: %s" % message)
if messageType == "Play": if message_type == "Play":
# A remote control play command has been sent from the server. # A remote control play command has been sent from the server.
itemIds = data['ItemIds'] self._play_(data)
command = data['PlayCommand']
pl = playlist.Playlist() elif message_type == "Playstate":
if command == "PlayNow":
dialog.notification(
heading=lang(29999),
message="%s %s" % (len(itemIds), lang(33004)),
icon="special://home/addons/plugin.video.emby/icon.png",
sound=False)
startat = data.get('StartPositionTicks', 0)
pl.playAll(itemIds, startat)
elif command == "PlayNext":
dialog.notification(
heading=lang(29999),
message="%s %s" % (len(itemIds), lang(33005)),
icon="special://home/addons/plugin.video.emby/icon.png",
sound=False)
newplaylist = pl.modifyPlaylist(itemIds)
player = xbmc.Player()
if not player.isPlaying():
# Only start the playlist if nothing is playing
player.play(newplaylist)
elif messageType == "Playstate":
# A remote control update playstate command has been sent from the server. # A remote control update playstate command has been sent from the server.
command = data['Command'] self._playstate_(data)
player = xbmc.Player()
actions = { elif message_type == "UserDataChanged":
'Stop': player.stop,
'Unpause': player.pause,
'Pause': player.pause,
'NextTrack': player.playnext,
'PreviousTrack': player.playprevious,
'Seek': player.seekTime
}
action = actions[command]
if command == "Seek":
seekto = data['SeekPositionTicks']
seektime = seekto / 10000000.0
action(seektime)
log.info("Seek to %s." % seektime)
else:
action()
log.info("Command: %s completed." % command)
window('emby_command', value="true")
elif messageType == "UserDataChanged":
# A user changed their personal rating for an item, or their playstate was updated # A user changed their personal rating for an item, or their playstate was updated
userdata_list = data['UserDataList'] userdata_list = data['UserDataList']
self.librarySync.triage_items("userdata", userdata_list) self.library_sync.triage_items("userdata", userdata_list)
elif messageType == "LibraryChanged": elif message_type == "LibraryChanged":
librarySync = self.librarySync librarySync = self.library_sync
processlist = { processlist = {
'added': data['ItemsAdded'], 'added': data['ItemsAdded'],
@ -143,163 +95,226 @@ class WebSocket_Client(threading.Thread):
for action in processlist: for action in processlist:
librarySync.triage_items(action, processlist[action]) librarySync.triage_items(action, processlist[action])
elif messageType == "GeneralCommand": elif message_type == "GeneralCommand":
self._general_commands(data)
command = data['Name']
arguments = data['Arguments']
if command in ('Mute', 'Unmute', 'SetVolume', elif message_type == "ServerRestarting":
'SetSubtitleStreamIndex', 'SetAudioStreamIndex'): self._server_restarting()
player = xbmc.Player() elif message_type == "UserConfigurationUpdated":
# 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 == "SetSubtitleStreamIndex":
embyindex = int(arguments['Index'])
currentFile = player.getPlayingFile()
mapping = window('emby_%s.indexMapping' % currentFile)
if mapping:
externalIndex = json.loads(mapping)
# If there's external subtitles added via playbackutils
for index in externalIndex:
if externalIndex[index] == embyindex:
player.setSubtitleStream(int(index))
break
else:
# User selected internal subtitles
external = len(externalIndex)
audioTracks = len(player.getAvailableAudioStreams())
player.setSubtitleStream(external + embyindex - audioTracks - 1)
else:
# Emby merges audio and subtitle index together
audioTracks = len(player.getAvailableAudioStreams())
player.setSubtitleStream(index - audioTracks - 1)
# Let service know
window('emby_command', value="true")
elif command == "DisplayMessage":
header = arguments['Header']
text = arguments['Text']
dialog.notification(
heading=header,
message=text,
icon="special://home/addons/plugin.video.emby/icon.png",
time=4000)
elif command == "SendString":
params = {
'text': arguments['String'],
'done': False
}
result = JSONRPC("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"
}
result = JSONRPC(actions[command]).execute()
elif command == "GoHome":
result = JSONRPC("GUI.ActivateWindow").execute({"window":"home"})
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)',
}
action = builtin.get(command)
if action:
xbmc.executebuiltin(action)
elif messageType == "ServerRestarting":
if settings('supressRestartMsg') == "true":
dialog.notification(
heading=lang(29999),
message=lang(33006),
icon="special://home/addons/plugin.video.emby/icon.png")
elif messageType == "UserConfigurationUpdated":
# Update user data set in userclient # Update user data set in userclient
userclient.UserClient().get_user(data) userclient.UserClient().get_user(data)
self.librarySync.refresh_views = True self.library_sync.refresh_views = True
elif messageType == "ServerShuttingDown": elif message_type == "ServerShuttingDown":
# Server went offline # Server went offline
window('emby_online', value="false") window('emby_online', value="false")
@classmethod
def _play_(cls, data):
item_ids = data['ItemIds']
command = data['PlayCommand']
playlist_ = playlist.Playlist()
if command == "PlayNow":
startat = data.get('StartPositionTicks', 0)
playlist_.playAll(item_ids, startat)
dialog(type_="notification",
heading=lang(29999),
message="%s %s" % (len(item_ids), lang(33004)),
icon="{emby}",
sound=False)
elif command == "PlayNext":
newplaylist = playlist_.modifyPlaylist(item_ids)
dialog(type_="notification",
heading=lang(29999),
message="%s %s" % (len(item_ids), lang(33005)),
icon="{emby}",
sound=False)
player = xbmc.Player()
if not player.isPlaying():
# Only start the playlist if nothing is playing
player.play(newplaylist)
@classmethod
def _playstate_(cls, data):
command = data['Command']
player = xbmc.Player()
actions = {
'Stop': player.stop,
'Unpause': player.pause,
'Pause': player.pause,
'NextTrack': player.playnext,
'PreviousTrack': player.playprevious,
'Seek': player.seekTime
}
action = actions[command]
if command == "Seek":
seekto = data['SeekPositionTicks']
seektime = seekto / 10000000.0
action(seektime)
log.info("Seek to %s", seektime)
else:
action()
log.info("Command: %s completed", command)
window('emby_command', value="true")
@classmethod
def _general_commands(cls, data):
command = data['Name']
arguments = data['Arguments']
if command in ('Mute', 'Unmute', 'SetVolume',
'SetSubtitleStreamIndex', 'SetAudioStreamIndex'):
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 == "SetSubtitleStreamIndex":
embyindex = int(arguments['Index'])
currentFile = player.getPlayingFile()
mapping = window('emby_%s.indexMapping' % currentFile)
if mapping:
externalIndex = json.loads(mapping)
# If there's external subtitles added via playbackutils
for index in externalIndex:
if externalIndex[index] == embyindex:
player.setSubtitleStream(int(index))
break
else:
# User selected internal subtitles
external = len(externalIndex)
audioTracks = len(player.getAvailableAudioStreams())
player.setSubtitleStream(external + embyindex - audioTracks - 1)
else:
# Emby merges audio and subtitle index together
audioTracks = len(player.getAvailableAudioStreams())
player.setSubtitleStream(index - audioTracks - 1)
# Let service know
window('emby_command', value="true")
elif command == "DisplayMessage":
header = arguments['Header']
text = arguments['Text']
dialog(type_="notification",
heading=header,
message=text,
icon="{emby}",
time=4000)
elif command == "SendString":
params = {
'text': arguments['String'],
'done': False
}
result = JSONRPC("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"
}
result = JSONRPC(actions[command]).execute()
elif command == "GoHome":
result = JSONRPC("GUI.ActivateWindow").execute({"window":"home"})
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)',
}
action = builtin.get(command)
if action:
xbmc.executebuiltin(action)
@classmethod
def _server_restarting(cls):
if settings('supressRestartMsg') == "true":
dialog(type_="notification",
heading=lang(29999),
message=lang(33006),
icon="{emby}")
def on_close(self, ws): def on_close(self, ws):
log.debug("Closed.") log.debug("closed")
def on_open(self, ws): def on_open(self, ws):
self.doUtils.postCapabilities(self.deviceId) self.doutils.postCapabilities(self.device_id)
def on_error(self, ws, error): def on_error(self, ws, error):
if "10061" in str(error): if "10061" in str(error):
# Server is offline # Server is offline
pass pass
else: else:
log.debug("Error: %s" % error) log.debug("Error: %s", error)
def run(self): def run(self):
loglevel = int(window('emby_logLevel'))
# websocket.enableTrace(True) # websocket.enableTrace(True)
userId = window('emby_currUser') user_id = window('emby_currUser')
server = window('emby_server%s' % userId) server = window('emby_server%s' % user_id)
token = window('emby_accessToken%s' % userId) token = window('emby_accessToken%s' % user_id)
# Get the appropriate prefix for the websocket # Get the appropriate prefix for the websocket
if "https" in server: if "https" in server:
server = server.replace('https', "wss") server = server.replace('https', "wss")
else: else:
server = server.replace('http', "ws") server = server.replace('http', "ws")
websocket_url = "%s?api_key=%s&deviceId=%s" % (server, token, self.deviceId) websocket_url = "%s?api_key=%s&deviceId=%s" % (server, token, self.device_id)
log.info("websocket url: %s" % websocket_url) log.info("websocket url: %s", websocket_url)
self.client = websocket.WebSocketApp(websocket_url, self._client = websocket.WebSocketApp(websocket_url,
on_message=self.on_message, on_message=self.on_message,
on_error=self.on_error, on_error=self.on_error,
on_close=self.on_close) on_close=self.on_close)
self._client.on_open = self.on_open
self.client.on_open = self.on_open
log.warn("----===## Starting WebSocketClient ##===----") log.warn("----===## Starting WebSocketClient ##===----")
while not self.monitor.abortRequested(): while not self.monitor.abortRequested():
self.client.run_forever(ping_interval=10) self._client.run_forever(ping_interval=10)
if self.stopWebsocket: if self._stop_websocket:
break break
if self.monitor.waitForAbort(5): if self.monitor.waitForAbort(5):
@ -308,8 +323,8 @@ class WebSocket_Client(threading.Thread):
log.warn("##===---- WebSocketClient Stopped ----===##") log.warn("##===---- WebSocketClient Stopped ----===##")
def stopClient(self): def stop_client(self):
self.stopWebsocket = True self._stop_websocket = True
self.client.close() self._client.close()
log.info("Stopping thread.") log.info("Stopping thread")

View file

@ -10,7 +10,6 @@ from datetime import datetime
import xbmc import xbmc
import xbmcaddon import xbmcaddon
import xbmcgui
################################################################################################# #################################################################################################
@ -55,22 +54,22 @@ class Service(object):
def __init__(self): def __init__(self):
self.clientInfo = clientinfo.ClientInfo() self.client_info = clientinfo.ClientInfo()
self.addonName = self.clientInfo.get_addon_name() self.addon_name = self.client_info.get_addon_name()
logLevel = settings('logLevel') log_level = settings('logLevel')
self.monitor = xbmc.Monitor() self.monitor = xbmc.Monitor()
window('emby_logLevel', value=str(logLevel)) window('emby_logLevel', value=str(log_level))
window('emby_kodiProfile', value=xbmc.translatePath('special://profile')) window('emby_kodiProfile', value=xbmc.translatePath('special://profile'))
# Initial logging # Initial logging
log.warn("======== START %s ========", self.addonName) log.warn("======== START %s ========", self.addon_name)
log.warn("Python Version: %s", sys.version) log.warn("Python Version: %s", sys.version)
log.warn("Platform: %s", self.clientInfo.get_platform()) log.warn("Platform: %s", self.client_info.get_platform())
log.warn("KODI Version: %s", xbmc.getInfoLabel('System.BuildVersion')) log.warn("KODI Version: %s", xbmc.getInfoLabel('System.BuildVersion'))
log.warn("%s Version: %s", self.addonName, self.clientInfo.get_version()) log.warn("%s Version: %s", self.addon_name, self.client_info.get_version())
log.warn("Using plugin paths: %s", settings('useDirectPaths') == "0") log.warn("Using plugin paths: %s", settings('useDirectPaths') == "0")
log.warn("Log Level: %s", logLevel) log.warn("Log Level: %s", log_level)
# Reset window props for profile switch # Reset window props for profile switch
properties = [ properties = [
@ -89,7 +88,7 @@ class Service(object):
# Set the minimum database version # Set the minimum database version
window('emby_minDBVersion', value="1.1.63") window('emby_minDBVersion', value="1.1.63")
def service_entry_point(self): def service_entry_point(self):
# Important: Threads depending on abortRequest will not trigger # Important: Threads depending on abortRequest will not trigger
@ -173,7 +172,7 @@ class Service(object):
message=("%s %s%s!" message=("%s %s%s!"
% (lang(33000), user.get_username().decode('utf-8'), % (lang(33000), user.get_username().decode('utf-8'),
add.decode('utf-8'))), add.decode('utf-8'))),
icon="{default}", icon="{emby}",
time=2000, time=2000,
sound=False) sound=False)
@ -227,16 +226,16 @@ class Service(object):
if settings('offlineMsg') == "true": if settings('offlineMsg') == "true":
dialog(type_="notification", dialog(type_="notification",
heading=lang(33001), heading=lang(33001),
message="%s %s" % (self.addonName, lang(33002)), message="%s %s" % (self.addon_name, lang(33002)),
icon="{default}", icon="{emby}",
sound=False) sound=False)
self.server_online = False self.server_online = False
elif window('emby_online') == "sleep": elif window('emby_online') == "sleep":
# device going to sleep # device going to sleep
if self.websocket_running: if self.websocket_running:
ws.stopClient() ws.stop_client()
ws = wsc.WebSocket_Client() ws = wsc.WebSocket_Client()
self.websocket_running = False self.websocket_running = False
@ -257,7 +256,7 @@ class Service(object):
dialog(type_="notification", dialog(type_="notification",
heading=lang(29999), heading=lang(29999),
message=lang(33003), message=lang(33003),
icon="{default}", icon="{emby}",
time=2000, time=2000,
sound=False) sound=False)
@ -289,9 +288,9 @@ class Service(object):
library.stopThread() library.stopThread()
if self.websocket_running: if self.websocket_running:
ws.stopClient() ws.stop_client()
log.warn("======== STOP %s ========", self.addonName) log.warn("======== STOP %s ========", self.addon_name)
# Delay option # Delay option
DELAY = int(settings('startupDelay')) DELAY = int(settings('startupDelay'))