diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py
index f29c148f..1a0ad5d0 100644
--- a/resources/lib/DownloadUtils.py
+++ b/resources/lib/DownloadUtils.py
@@ -55,7 +55,8 @@ class DownloadUtils():
host = addon.getSetting('ipaddress')
port = addon.getSetting('port')
server = host + ":" + port
-
+ return server
+ '''
if len(server) < 2:
self.logMsg("No server information saved.")
return ""
@@ -71,7 +72,7 @@ class DownloadUtils():
# If only the host:port is required
elif (prefix == False):
return server
-
+ '''
def getUserId(self, suppress=True):
WINDOW = xbmcgui.Window( 10000 )
diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py
index 746c24a5..b12d355a 100644
--- a/resources/lib/PlaybackUtils.py
+++ b/resources/lib/PlaybackUtils.py
@@ -203,3 +203,128 @@ class PlaybackUtils():
listItem.setInfo('video', {'writer' : people.get('Writer')})
listItem.setInfo('video', {'mpaa': result.get("OfficialRating")})
listItem.setInfo('video', {'genre': genre})
+
+ def seekToPosition(self, seekTo):
+
+ #Set a loop to wait for positive confirmation of playback
+ count = 0
+ while not xbmc.Player().isPlaying():
+ self.logMsg( "Not playing yet...sleep for 1 sec")
+ count = count + 1
+ if count >= 10:
+ return
+ else:
+ time.sleep(1)
+
+ #Jump to resume point
+ jumpBackSec = int(self.settings.getSetting("resumeJumpBack"))
+ seekToTime = seekTo - jumpBackSec
+ count = 0
+ while xbmc.Player().getTime() < (seekToTime - 5) and count < 11: # only try 10 times
+ count = count + 1
+ xbmc.Player().pause
+ xbmc.sleep(100)
+ xbmc.Player().seekTime(seekToTime)
+ xbmc.sleep(100)
+ xbmc.Player().play()
+
+ def PLAYAllItems(self, items, startPositionTicks):
+ xbmc.log("== ENTER: PLAYAllItems ==")
+ xbmc.log("Items : " + str(items))
+
+ du = DownloadUtils()
+ userid = du.getUserId()
+ server = du.getServer()
+
+ playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
+ playlist.clear()
+ started = False
+
+ for itemID in items:
+
+ xbmc.log("Adding Item to Playlist : " + itemID)
+ item_url = "http://" + server + "/mediabrowser/Users/" + userid + "/Items/" + itemID + "?format=json"
+ jsonData = du.downloadUrl(item_url, suppress=False, popup=1 )
+
+ item_data = json.loads(jsonData)
+ added = self.addPlaylistItem(playlist, item_data, server, userid)
+ if(added and started == False):
+ started = True
+ xbmc.log("Starting Playback Pre")
+ xbmc.Player().play(playlist)
+
+ if(started == False):
+ xbmc.log("Starting Playback Post")
+ xbmc.Player().play(playlist)
+
+ #seek to position
+ seekTime = 0
+ if(startPositionTicks != None):
+ seekTime = (startPositionTicks / 1000) / 10000
+
+ if seekTime > 0:
+ self.seekToPosition(seekTime)
+
+ def AddToPlaylist(self, itemIds):
+ xbmc.log("== ENTER: PLAYAllItems ==")
+
+ du = DownloadUtils()
+ userid = du.getUserId()
+ server = du.getServer()
+
+ playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
+
+ for itemID in itemIds:
+
+ xbmc.log("Adding Item to Playlist : " + itemID)
+ item_url = "http://" + server + "/mediabrowser/Users/" + userid + "/Items/" + itemID + "?format=json"
+ jsonData = du.downloadUrl(item_url, suppress=False, popup=1 )
+
+ item_data = json.loads(jsonData)
+ self.addPlaylistItem(playlist, item_data, server, userid)
+
+ return playlist
+
+ def addPlaylistItem(self, playlist, item, server, userid):
+
+ id = item.get("Id")
+
+ playurl = PlayUtils().getPlayUrl(server, id, item)
+ xbmc.log("Play URL: " + playurl)
+ api = API()
+ thumbPath = api.getArtwork(item, "Primary")
+ listItem = xbmcgui.ListItem(path=playurl, iconImage=thumbPath, thumbnailImage=thumbPath)
+ self.setListItemProps(server, id, listItem, item)
+
+ # Can not play virtual items
+ if (item.get("LocationType") == "Virtual") or (item.get("IsPlaceHolder") == True):
+
+ xbmcgui.Dialog().ok(self.language(30128), self.language(30129))
+ return False
+
+ else:
+
+ watchedurl = 'http://' + server + '/mediabrowser/Users/'+ userid + '/PlayedItems/' + id
+ positionurl = 'http://' + server + '/mediabrowser/Users/'+ userid + '/PlayingItems/' + id
+
+ # set the current playing info
+ WINDOW = xbmcgui.Window( 10000 )
+ WINDOW.setProperty(playurl + "watchedurl", watchedurl)
+ WINDOW.setProperty(playurl + "positionurl", positionurl)
+
+ WINDOW.setProperty(playurl + "runtimeticks", str(item.get("RunTimeTicks")))
+ WINDOW.setProperty(playurl+"type", item.get("Type"))
+ WINDOW.setProperty(playurl + "item_id", id)
+
+ if (item.get("Type") == "Episode"):
+ WINDOW.setProperty(playurl + "refresh_id", item.get("SeriesId"))
+ else:
+ WINDOW.setProperty(playurl + "refresh_id", id)
+
+ xbmc.log( "PlayList Item Url : " + str(playurl))
+
+ playlist.add(playurl, listItem)
+
+ return True
+
+
\ No newline at end of file
diff --git a/resources/lib/WebSocketClient.py b/resources/lib/WebSocketClient.py
new file mode 100644
index 00000000..89ef2f99
--- /dev/null
+++ b/resources/lib/WebSocketClient.py
@@ -0,0 +1,262 @@
+#################################################################################################
+# WebSocket Client thread
+#################################################################################################
+
+import xbmc
+import xbmcgui
+import xbmcaddon
+
+import json
+import threading
+import urllib
+import socket
+import websocket
+from ClientInformation import ClientInformation
+from DownloadUtils import DownloadUtils
+from PlaybackUtils import PlaybackUtils
+
+_MODE_BASICPLAY=12
+
+class WebSocketThread(threading.Thread):
+
+ logLevel = 0
+ client = None
+ keepRunning = True
+
+ def __init__(self, *args):
+ addonSettings = xbmcaddon.Addon(id='plugin.video.mb3sync')
+ level = addonSettings.getSetting('logLevel')
+ self.logLevel = 0
+ if(level != None):
+ self.logLevel = int(level)
+
+ xbmc.log("MB3SYNC WebSocketThread -> Log Level:" + str(self.logLevel))
+
+ threading.Thread.__init__(self, *args)
+
+ def logMsg(self, msg, level = 1):
+ if(self.logLevel >= level):
+ try:
+ xbmc.log("MB3SYNC WebSocketThread -> " + str(msg))
+ except UnicodeEncodeError:
+ try:
+ xbmc.log("MB3SYNC WebSocketThread -> " + str(msg.encode('utf-8')))
+ except: pass
+
+ '''
+ def playbackStarted(self, itemId):
+ if(self.client != None):
+ try:
+ self.logMsg("Sending Playback Started")
+ messageData = {}
+ messageData["MessageType"] = "PlaybackStart"
+ messageData["Data"] = itemId + "|true|audio,video"
+ messageString = json.dumps(messageData)
+ self.logMsg("Message Data : " + messageString)
+ self.client.send(messageString)
+ except Exception, e:
+ self.logMsg("Exception : " + str(e), level=0)
+ else:
+ self.logMsg("Sending Playback Started NO Object ERROR")
+ '''
+
+ '''
+ def playbackStopped(self, itemId, ticks):
+ if(self.client != None):
+ try:
+ self.logMsg("Sending Playback Stopped")
+ messageData = {}
+ messageData["MessageType"] = "PlaybackStopped"
+ messageData["Data"] = itemId + "|" + str(ticks)
+ messageString = json.dumps(messageData)
+ self.client.send(messageString)
+ except Exception, e:
+ self.logMsg("Exception : " + str(e), level=0)
+ else:
+ self.logMsg("Sending Playback Stopped NO Object ERROR")
+ '''
+
+ '''
+ def sendProgressUpdate(self, itemId, ticks):
+ if(self.client != None):
+ try:
+ self.logMsg("Sending Progress Update")
+ messageData = {}
+ messageData["MessageType"] = "PlaybackProgress"
+ messageData["Data"] = itemId + "|" + str(ticks) + "|false|false"
+ messageString = json.dumps(messageData)
+ self.logMsg("Message Data : " + messageString)
+ self.client.send(messageString)
+ except Exception, e:
+ self.logMsg("Exception : " + str(e), level=0)
+ else:
+ self.logMsg("Sending Progress Update NO Object ERROR")
+ '''
+
+ def stopClient(self):
+ # stopping the client is tricky, first set keep_running to false and then trigger one
+ # more message by requesting one SessionsStart message, this causes the
+ # client to receive the message and then exit
+ if(self.client != None):
+ self.logMsg("Stopping Client")
+ self.keepRunning = False
+ self.client.keep_running = False
+ self.client.close()
+ self.logMsg("Stopping Client : KeepRunning set to False")
+ '''
+ try:
+ self.keepRunning = False
+ self.client.keep_running = False
+ self.logMsg("Stopping Client")
+ self.logMsg("Calling Ping")
+ self.client.sock.ping()
+
+ self.logMsg("Calling Socket Shutdown()")
+ self.client.sock.sock.shutdown(socket.SHUT_RDWR)
+ self.logMsg("Calling Socket Close()")
+ self.client.sock.sock.close()
+ self.logMsg("Stopping Client Done")
+ self.logMsg("Calling Ping")
+ self.client.sock.ping()
+
+ except Exception, e:
+ self.logMsg("Exception : " + str(e), level=0)
+ '''
+ else:
+ self.logMsg("Stopping Client NO Object ERROR")
+
+ def on_message(self, ws, message):
+ self.logMsg("Message : " + str(message))
+ result = json.loads(message)
+
+ messageType = result.get("MessageType")
+ playCommand = result.get("PlayCommand")
+ data = result.get("Data")
+
+ if(messageType != None and messageType == "Play" and data != None):
+ itemIds = data.get("ItemIds")
+ playCommand = data.get("PlayCommand")
+
+ if(playCommand != None and playCommand == "PlayNow"):
+
+ xbmc.executebuiltin("Dialog.Close(all,true)")
+ startPositionTicks = data.get("StartPositionTicks")
+ PlaybackUtils().PLAYAllItems(itemIds, startPositionTicks)
+ xbmc.executebuiltin("XBMC.Notification(Playlist: Added " + str(len(itemIds)) + " items to Playlist,)")
+
+ elif(playCommand != None and playCommand == "PlayNext"):
+
+ playlist = PlaybackUtils().AddToPlaylist(itemIds)
+ xbmc.executebuiltin("XBMC.Notification(Playlist: Added " + str(len(itemIds)) + " items to Playlist,)")
+ if(xbmc.Player().isPlaying() == False):
+ xbmc.Player().play(playlist)
+
+ elif(messageType != None and messageType == "Playstate"):
+ command = data.get("Command")
+ if(command != None and command == "Stop"):
+ self.logMsg("Playback Stopped")
+ xbmc.executebuiltin('xbmc.activatewindow(10000)')
+ xbmc.Player().stop()
+ elif(command != None and command == "Pause"):
+ self.logMsg("Playback Paused")
+ xbmc.Player().pause()
+ elif(command != None and command == "Unpause"):
+ self.logMsg("Playback UnPaused")
+ xbmc.Player().pause()
+ elif(command != None and command == "NextTrack"):
+ self.logMsg("Playback NextTrack")
+ xbmc.Player().playnext()
+ elif(command != None and command == "PreviousTrack"):
+ self.logMsg("Playback PreviousTrack")
+ xbmc.Player().playprevious()
+ elif(command != None and command == "Seek"):
+ seekPositionTicks = data.get("SeekPositionTicks")
+ self.logMsg("Playback Seek : " + str(seekPositionTicks))
+ seekTime = (seekPositionTicks / 1000) / 10000
+ xbmc.Player().seekTime(seekTime)
+
+
+ def on_error(self, ws, error):
+ self.logMsg("Error : " + str(error))
+ #raise
+
+ def on_close(self, ws):
+ self.logMsg("Closed")
+
+ def on_open(self, ws):
+
+ clientInfo = ClientInformation()
+ machineId = clientInfo.getMachineId()
+ version = clientInfo.getVersion()
+ messageData = {}
+ messageData["MessageType"] = "Identity"
+
+ addonSettings = xbmcaddon.Addon(id='plugin.video.mb3sync')
+ deviceName = addonSettings.getSetting('deviceName')
+ deviceName = deviceName.replace("\"", "_")
+
+ messageData["Data"] = "Kodi|" + machineId + "|" + version + "|" + deviceName
+ messageString = json.dumps(messageData)
+ self.logMsg("Opened : " + str(messageString))
+ ws.send(messageString)
+
+ # Set Capabilities
+ xbmc.log("postcapabilities_called")
+ downloadUtils = DownloadUtils()
+ downloadUtils.postcapabilities()
+
+
+ def getWebSocketPort(self, host, port):
+
+ userUrl = "http://" + host + ":" + port + "/mediabrowser/System/Info?format=json"
+
+ downloadUtils = DownloadUtils()
+ jsonData = downloadUtils.downloadUrl(userUrl, suppress=True, popup=1 )
+ if(jsonData == ""):
+ return -1
+
+ result = json.loads(jsonData)
+
+ wsPort = result.get("WebSocketPortNumber")
+ if(wsPort != None):
+ return wsPort
+ else:
+ return -1
+
+ def run(self):
+
+ addonSettings = xbmcaddon.Addon(id='plugin.video.mb3sync')
+ mb3Host = addonSettings.getSetting('ipaddress')
+ mb3Port = addonSettings.getSetting('port')
+
+ if(self.logLevel >= 1):
+ websocket.enableTrace(True)
+ '''
+ wsPort = self.getWebSocketPort(mb3Host, mb3Port);
+ self.logMsg("WebSocketPortNumber = " + str(wsPort))
+ if(wsPort == -1):
+ self.logMsg("Could not retrieve WebSocket port, can not run WebScoket Client")
+ return
+ '''
+ # Make a call to /System/Info. WebSocketPortNumber is the port hosting the web socket.
+ webSocketUrl = "ws://" + mb3Host + ":" + mb3Port + "/mediabrowser"
+ self.logMsg("WebSocket URL : " + webSocketUrl)
+ self.client = websocket.WebSocketApp(webSocketUrl,
+ on_message = self.on_message,
+ on_error = self.on_error,
+ on_close = self.on_close)
+
+ self.client.on_open = self.on_open
+
+ while(self.keepRunning):
+ self.logMsg("Client Starting")
+ self.client.run_forever()
+ if(self.keepRunning):
+ self.logMsg("Client Needs To Restart")
+ xbmc.sleep(10000)
+
+ self.logMsg("Thread Exited")
+
+
+
+
\ No newline at end of file
diff --git a/resources/settings.xml b/resources/settings.xml
index b19448ad..12807cce 100644
--- a/resources/settings.xml
+++ b/resources/settings.xml
@@ -20,6 +20,8 @@
+
+
diff --git a/service.py b/service.py
index 746617ae..45bde93c 100644
--- a/service.py
+++ b/service.py
@@ -17,6 +17,7 @@ from LibrarySync import LibrarySync
from Player import Player
from DownloadUtils import DownloadUtils
from ConnectionManager import ConnectionManager
+from WebSocketClient import WebSocketThread
librarySync = LibrarySync()
class Service():
@@ -37,6 +38,8 @@ class Service():
player = Player()
lastProgressUpdate = datetime.today()
+ newWebSocketThread = WebSocketThread()
+ newWebSocketThread.start()
# check kodi library sources
mayRun = utils.checkKodiSources()
@@ -116,6 +119,9 @@ class Service():
xbmc.log("Not authenticated yet")
utils.logMsg("MB3 Sync Service", "stopping Service",0)
+
+ if(newWebSocketThread != None):
+ newWebSocketThread.stopClient()
#start the service