def ServiceEntryPoint(self): ConnectionManager().checkServer() lastProgressUpdate = datetime.today() startupComplete = False #interval_FullSync = 600 #interval_IncrementalSync = 300 #cur_seconds_fullsync = interval_FullSync #cur_seconds_incrsync = interval_IncrementalSync user = UserClient() player = Player() ws = WebSocketThread() lastFile = None while not self.KodiMonitor.abortRequested(): if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. We should exit break if xbmc.Player().isPlaying(): try: playTime = xbmc.Player().getTime() totalTime = xbmc.Player().getTotalTime() currentFile = xbmc.Player().getPlayingFile() if(player.played_information.get(currentFile) != None): player.played_information[currentFile]["currentPosition"] = playTime # send update td = datetime.today() - lastProgressUpdate secDiff = td.seconds if(secDiff > 3): try: player.reportPlayback() except Exception, msg: self.logMsg("Exception reporting progress: %s" % msg) pass lastProgressUpdate = datetime.today() # only try autoplay when there's 20 seconds or less remaining and only once! if (totalTime - playTime <= 20 and (lastFile==None or lastFile!=currentFile)): lastFile = currentFile player.autoPlayPlayback() except Exception, e: self.logMsg("Exception in Playback Monitor Service: %s" % e) pass
class Service(): KodiMonitor = KodiMonitor.Kodi_Monitor() clientInfo = ClientInformation() addonName = clientInfo.getAddonName() logLevel = UserClient().getLogLevel() WINDOW = xbmcgui.Window(10000) newWebSocketThread = None newUserClient = None newLibraryThread = None warn_auth = True welcome_msg = True server_online = True def __init__(self, *args): addonName = self.addonName clientInfo = self.clientInfo logLevel = self.logLevel utils.window('getLogLevel', value=str(logLevel)) utils.window('kodiProfile_emby', value=xbmc.translatePath("special://profile")) # Initial logging self.logMsg("Starting Monitor", 0) self.logMsg("======== START %s ========" % addonName, 0) self.logMsg("Platform: %s" % (clientInfo.getPlatform()), 0) self.logMsg("KODI Version: %s" % xbmc.getInfoLabel('System.BuildVersion'), 0) self.logMsg("%s Version: %s" % (addonName, clientInfo.getVersion()), 0) self.logMsg("Using plugin paths: %s" % (utils.settings('useDirectPaths') != "true"), 0) self.logMsg("Log Level: %s" % logLevel, 0) # Reset window props for profile switch utils.window('Server_online', clear=True) utils.window('Server_status', clear=True) utils.window('startup', clear=True) utils.window('OnWakeSync', clear=True) utils.window('kodiScan', clear=True) utils.window('minDBVersionCheck', clear=True) # Set min DB version utils.window('minDBVersion', value="1.1.52") embyProperty = utils.window('Emby.nodes.total') propNames = [ "index","path","title","content", "inprogress.content","inprogress.title", "inprogress.content","inprogress.path", "nextepisodes.title","nextepisodes.content", "nextepisodes.path","unwatched.title", "unwatched.content","unwatched.path", "recent.title","recent.content","recent.path", "recentepisodes.title","recentepisodes.content", "recentepisodes.path","inprogressepisodes.title", "inprogressepisodes.content","inprogressepisodes.path" ] if embyProperty: totalNodes = int(embyProperty) for i in range(totalNodes): for prop in propNames: utils.window('Emby.nodes.%s.%s' % (str(i), prop), clear=True) def logMsg(self, msg, lvl=1): className = self.__class__.__name__ utils.logMsg("%s %s" % (self.addonName, className), msg, int(lvl)) def ServiceEntryPoint(self): kodiProfile = xbmc.translatePath("special://profile") # Server auto-detect ConnectionManager().checkServer() # Initialize important threads user = UserClient() player = Player() ws = WebSocketThread() library = LibrarySync() # Sync and progress report lastProgressUpdate = datetime.today() while not self.KodiMonitor.abortRequested(): # Before proceeding, need to make sure: # 1. Server is online # 2. User is set # 3. User has access to the server if utils.window("kodiProfile_emby") != kodiProfile: # Profile change happened, terminate this thread self.logMsg("Kodi profile was: %s and changed to: %s. Terminating old Emby thread." % (kodiProfile, utils.window("kodiProfile_emby")), 1) break if utils.window('Server_online') == "true": # Emby server is online # Verify if user is set and has access to the server if (user.currUser is not None) and user.HasAccess: # If an item is playing if xbmc.Player().isPlaying(): try: # Update and report progress playTime = xbmc.Player().getTime() totalTime = xbmc.Player().getTotalTime() currentFile = player.currentFile # Update positionticks if player.played_information.get(currentFile) is not None: player.played_information[currentFile]['currentPosition'] = playTime td = datetime.today() - lastProgressUpdate secDiff = td.seconds # Report progress to Emby server if (secDiff > 3): player.reportPlayback() lastProgressUpdate = datetime.today() elif utils.window('commandUpdate') == "true": # Received a remote control command that # requires updating immediately utils.window('commandUpdate', clear=True) player.reportPlayback() lastProgressUpdate = da4tetime.today() except Exception as e: self.logMsg("Exception in Playback Monitor Service: %s" % e, 1) pass else: # Start up events self.warn_auth = True if utils.settings('supressConnectMsg') == "false": if self.welcome_msg: # Reset authentication warnings self.welcome_msg = False # Get additional users additionalUsers = user.AdditionalUser if additionalUsers: add = ", %s" % ", ".join(additionalUsers) else: add = "" xbmcgui.Dialog().notification("Emby server", "Welcome %s%s!" % (user.currUser, add), icon="special://home/addons/plugin.video.emby/icon.png", time=2000, sound=False) # Start the Websocket Client if (self.newWebSocketThread is None): self.newWebSocketThread = "Started" ws.start() # Start the Library Sync Thread if (self.newLibraryThread is None): self.newLibraryThread = "Started" library.start() else: if (user.currUser is None) and self.warn_auth: # Alert user is not authenticated and suppress future warning self.warn_auth = False self.logMsg("Not authenticated yet.", 1) # User access is restricted. # Keep verifying until access is granted # unless server goes offline or Kodi is shut down. while user.HasAccess == False: # Verify access with an API call user.hasAccess() if utils.window('Server_online') != "true": # Server went offline break if self.KodiMonitor.waitForAbort(5): # Abort was requested while waiting. We should exit break else: # Wait until Emby server is online # or Kodi is shut down. while not self.KodiMonitor.abortRequested(): if user.getServer() == "": # No server info set in add-on settings pass elif user.getPublicUsers() == False: # Server is offline. # Alert the user and suppress future warning if self.server_online: self.logMsg("Server is offline.", 1) utils.window('Server_online', value="false") xbmcgui.Dialog().notification("Error connecting", "%s Server is unreachable." % self.addonName, icon="special://home/addons/plugin.video.emby/icon.png", sound=False) self.server_online = False else: # Server is online if not self.server_online: # Server was offline when Kodi started. # Wait for server to be fully established. if self.KodiMonitor.waitForAbort(5): # Abort was requested while waiting. break # Alert the user that server is online. xbmcgui.Dialog().notification("Emby server", "Welcome %s!" % user.currUser, icon="special://home/addons/plugin.video.emby/icon.png", time=2000, sound=False) self.server_online = True self.logMsg("Server is online and ready.", 1) utils.window('Server_online', value="true") # Start the User client if self.newUserClient is None: self.newUserClient = "Started" user.start() break if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. break if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. We should exit break ##### Emby thread is terminating. ##### # If music is enabled and direct stream for music is enabled # We use Kodi pathsubstitution to allow for music to play outside network # The setting needs to be set before Kodi starts. if utils.settings('enableMusicSync') == "true" and utils.settings('directstreammusic') == "true": # We need to keep track of the settings alternate = utils.settings('altip') == "true" pathsub = utils.settings('pathsub') == "true" if pathsub and not alternate: # Path sub in place, but primary address in use, remove it utils.pathsubstitution(False) elif not pathsub and alternate: # Path sub not in place, but secondary address in use, add it utils.pathsubstitution() if (self.newWebSocketThread is not None): ws.stopClient() if (self.newUserClient is not None): user.stopClient() self.logMsg("======== STOP %s ========" % self.addonName, 0)
def ServiceEntryPoint(self): kodiProfile = xbmc.translatePath("special://profile") # Server auto-detect ConnectionManager().checkServer() # Initialize important threads user = UserClient() player = Player() ws = WebSocketThread() library = LibrarySync() # Sync and progress report lastProgressUpdate = datetime.today() while not self.KodiMonitor.abortRequested(): # Before proceeding, need to make sure: # 1. Server is online # 2. User is set # 3. User has access to the server if utils.window("kodiProfile_emby") != kodiProfile: # Profile change happened, terminate this thread self.logMsg("Kodi profile was: %s and changed to: %s. Terminating old Emby thread." % (kodiProfile, utils.window("kodiProfile_emby")), 1) break if utils.window('Server_online') == "true": # Emby server is online # Verify if user is set and has access to the server if (user.currUser is not None) and user.HasAccess: # If an item is playing if xbmc.Player().isPlaying(): try: # Update and report progress playTime = xbmc.Player().getTime() totalTime = xbmc.Player().getTotalTime() currentFile = player.currentFile # Update positionticks if player.played_information.get(currentFile) is not None: player.played_information[currentFile]['currentPosition'] = playTime td = datetime.today() - lastProgressUpdate secDiff = td.seconds # Report progress to Emby server if (secDiff > 3): player.reportPlayback() lastProgressUpdate = datetime.today() elif utils.window('commandUpdate') == "true": # Received a remote control command that # requires updating immediately utils.window('commandUpdate', clear=True) player.reportPlayback() lastProgressUpdate = da4tetime.today() except Exception as e: self.logMsg("Exception in Playback Monitor Service: %s" % e, 1) pass else: # Start up events self.warn_auth = True if utils.settings('supressConnectMsg') == "false": if self.welcome_msg: # Reset authentication warnings self.welcome_msg = False # Get additional users additionalUsers = user.AdditionalUser if additionalUsers: add = ", %s" % ", ".join(additionalUsers) else: add = "" xbmcgui.Dialog().notification("Emby server", "Welcome %s%s!" % (user.currUser, add), icon="special://home/addons/plugin.video.emby/icon.png", time=2000, sound=False) # Start the Websocket Client if (self.newWebSocketThread is None): self.newWebSocketThread = "Started" ws.start() # Start the Library Sync Thread if (self.newLibraryThread is None): self.newLibraryThread = "Started" library.start() else: if (user.currUser is None) and self.warn_auth: # Alert user is not authenticated and suppress future warning self.warn_auth = False self.logMsg("Not authenticated yet.", 1) # User access is restricted. # Keep verifying until access is granted # unless server goes offline or Kodi is shut down. while user.HasAccess == False: # Verify access with an API call user.hasAccess() if utils.window('Server_online') != "true": # Server went offline break if self.KodiMonitor.waitForAbort(5): # Abort was requested while waiting. We should exit break else: # Wait until Emby server is online # or Kodi is shut down. while not self.KodiMonitor.abortRequested(): if user.getServer() == "": # No server info set in add-on settings pass elif user.getPublicUsers() == False: # Server is offline. # Alert the user and suppress future warning if self.server_online: self.logMsg("Server is offline.", 1) utils.window('Server_online', value="false") xbmcgui.Dialog().notification("Error connecting", "%s Server is unreachable." % self.addonName, icon="special://home/addons/plugin.video.emby/icon.png", sound=False) self.server_online = False else: # Server is online if not self.server_online: # Server was offline when Kodi started. # Wait for server to be fully established. if self.KodiMonitor.waitForAbort(5): # Abort was requested while waiting. break # Alert the user that server is online. xbmcgui.Dialog().notification("Emby server", "Welcome %s!" % user.currUser, icon="special://home/addons/plugin.video.emby/icon.png", time=2000, sound=False) self.server_online = True self.logMsg("Server is online and ready.", 1) utils.window('Server_online', value="true") # Start the User client if self.newUserClient is None: self.newUserClient = "Started" user.start() break if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. break if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. We should exit break ##### Emby thread is terminating. ##### # If music is enabled and direct stream for music is enabled # We use Kodi pathsubstitution to allow for music to play outside network # The setting needs to be set before Kodi starts. if utils.settings('enableMusicSync') == "true" and utils.settings('directstreammusic') == "true": # We need to keep track of the settings alternate = utils.settings('altip') == "true" pathsub = utils.settings('pathsub') == "true" if pathsub and not alternate: # Path sub in place, but primary address in use, remove it utils.pathsubstitution(False) elif not pathsub and alternate: # Path sub not in place, but secondary address in use, add it utils.pathsubstitution() if (self.newWebSocketThread is not None): ws.stopClient() if (self.newUserClient is not None): user.stopClient() self.logMsg("======== STOP %s ========" % self.addonName, 0)
class ConnectionManager(): clientInfo = ClientInformation() uc = UserClient() doUtils = DownloadUtils() addonName = clientInfo.getAddonName() addonId = clientInfo.getAddonId() addon = xbmcaddon.Addon(id=addonId) WINDOW = xbmcgui.Window(10000) logLevel = 0 def __init__(self): self.className = self.__class__.__name__ self.__language__ = self.addon.getLocalizedString def logMsg(self, msg, lvl=1): utils.logMsg("%s %s" % (self.addonName, self.className), msg, int(lvl)) def checkServer(self): self.WINDOW.setProperty("Server_Checked", "True") self.logMsg("Connection Manager Called", 2) addon = self.addon server = self.uc.getServer() if (server != ""): self.logMsg("Server already set", 2) return serverInfo = self.getServerDetails() if (serverInfo == None): self.logMsg("getServerDetails failed", 1) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) return prefix,ip,port = serverInfo.split(":") setServer = xbmcgui.Dialog().yesno(self.__language__(30167), "Proceed with the following server?", self.__language__(30169) + serverInfo) if (setServer == 1): self.logMsg("Server selected. Saving information.", 1) addon.setSetting("ipaddress", ip.replace("/", "")) addon.setSetting("port", port) # If https is enabled if (prefix == 'https'): addon.setSetting('https', "true") else: self.logMsg("No server selected.", 1) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) return # Get List of public users self.logMsg("Getting user list", 1) server = ip.replace("/", "") + ":" + port url = "%s/mediabrowser/Users/Public?format=json" % serverInfo try: result = self.doUtils.downloadUrl(url, authenticate=False) except Exception, msg: error = "Unable to connect to %s: %s" % (server, msg) self.logMsg(error, 1) return "" if (result == ""): return self.logMsg("jsonData: %s" % result, 2) names = [] userList = [] for user in result: name = user[u'Name'] userList.append(name) if(user[u'HasPassword'] == True): name = name + " (Secure)" names.append(name) self.logMsg("User List: %s" % names, 1) self.logMsg("User List: %s" % userList, 2) return_value = xbmcgui.Dialog().select(self.__language__(30200), names) if (return_value > -1): selected_user = userList[return_value] self.logMsg("Selected User: %s" % selected_user, 1) self.addon.setSetting("username", selected_user) else: self.logMsg("No user selected.", 1) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) return # Option to play from http setPlayback = xbmcgui.Dialog().yesno("Playback option", "Play your files using HTTP?") if setPlayback == 1: self.logMsg("Playback will be set using HTTP.", 1) addon.setSetting("playFromStream", "true") else: self.logMsg("Playback will be set using SMB.", 1)
class ConnectionManager(): clientInfo = ClientInformation() user = UserClient() doUtils = DownloadUtils() addonName = clientInfo.getAddonName() addonId = clientInfo.getAddonId() addon = xbmcaddon.Addon() WINDOW = xbmcgui.Window(10000) def __init__(self): self.__language__ = self.addon.getLocalizedString def logMsg(self, msg, lvl=1): className = self.__class__.__name__ utils.logMsg("%s %s" % (self.addonName, className), msg, int(lvl)) def checkServer(self): self.WINDOW.setProperty("Server_Checked", "True") self.logMsg("Connection Manager Called", 2) server = self.user.getServer() if server != "": self.logMsg("Server already set", 2) return serverInfo = self.getServerDetails() try: prefix, ip, port = serverInfo.split(":") setServer = xbmcgui.Dialog().yesno( self.__language__(30167), "Proceed with the following server?", self.__language__(30169) + serverInfo) except: # serverInfo is None self.logMsg("getServerDetails failed", 1) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) return if setServer == 1: self.logMsg("Server selected. Saving information.", 1) utils.settings("ipaddress", ip.replace("/", "")) utils.settings("port", port) # If https, enable the setting if (prefix == 'https'): utils.settings('https', "true") else: self.logMsg("No server selected.", 1) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) return # Get List of public users self.logMsg("Getting user list", 1) server = "%s:%s" % (ip.replace("/", ""), port) url = "%s/mediabrowser/Users/Public?format=json" % serverInfo result = self.doUtils.downloadUrl(url, authenticate=False) if result == "": self.logMsg("Unable to connect to %s." % server, 1) return self.logMsg("Result: %s" % result, 2) # Process the list returned names = [] userList = [] for user in result: name = user['Name'] userList.append(name) if user['HasPassword']: name = "%s (Secure)" % name names.append(name) self.logMsg("User list: %s" % names, 1) resp = xbmcgui.Dialog().select(self.__language__(30200), names) if resp > -1: selected_user = userList[resp] self.logMsg("Selected User: %s" % selected_user, 1) utils.settings("username", selected_user) else: self.logMsg("No user selected.", 1) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) return musicDisabled = xbmcgui.Dialog().yesno("Music Setting", "Disable music library?") if musicDisabled: self.logMsg("User opted to disable music library.", 1) utils.settings('enableMusicSync', "false") else: # Music is enabled, prompt for direct stream musicPath = xbmcgui.Dialog().yesno( "Music Setting", "Direct stream the music library?", "Select this option only if you plan on listening to music outside your network." ) if musicPath: self.logMsg("User option to direct stream music library.", 1) utils.settings('directstreammusic', "true") return def getServerDetails(self): self.logMsg("Getting Server Details from Network") MULTI_GROUP = ("<broadcast>", 7359) MESSAGE = "who is EmbyServer?" sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(6.0) sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1) sock.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1) self.logMsg("MutliGroup : %s" % str(MULTI_GROUP), 2) self.logMsg("Sending UDP Data: %s" % MESSAGE, 2) sock.sendto(MESSAGE, MULTI_GROUP) try: data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes self.logMsg("Received Response: %s" % data) # Get the address data = json.loads(data) return data['Address'] except: self.logMsg("No UDP Response") pass return None
def ServiceEntryPoint(self): ConnectionManager().checkServer() lastProgressUpdate = datetime.today() interval_FullSync = 600 interval_IncrementalSync = 300 cur_seconds_fullsync = interval_FullSync cur_seconds_incrsync = interval_IncrementalSync user = UserClient() player = Player() ws = WebSocketThread() while not self.KodiMonitor.abortRequested(): xbmc.sleep(1000) if xbmc.Player().isPlaying(): try: playTime = xbmc.Player().getTime() currentFile = xbmc.Player().getPlayingFile() if(player.played_information.get(currentFile) != None): player.played_information[currentFile]["currentPosition"] = playTime # send update td = datetime.today() - lastProgressUpdate secDiff = td.seconds if(secDiff > 10): try: player.reportPlayback() except Exception, msg: xbmc.log("MB3 Sync Service -> Exception reporting progress : " + msg) pass lastProgressUpdate = datetime.today() except Exception, e: xbmc.log("MB3 Sync Service -> Exception in Playback Monitor Service : " + str(e)) pass else: if (self.newUserClient == None): self.newUserClient = "Started" user.start() # background worker for database sync if (user.currUser != None): # Correctly launch the websocket, if user manually launches the add-on if (self.newWebSocketThread == None): self.newWebSocketThread = "Started" ws.start() #full sync if(cur_seconds_fullsync >= interval_FullSync): xbmc.log("Doing_Db_Sync: syncDatabase (Started)") worked = librarySync.syncDatabase() xbmc.log("Doing_Db_Sync: syncDatabase (Finished) " + str(worked)) if(worked): cur_seconds_fullsync = 0 else: cur_seconds_fullsync = interval_FullSync - 10 else: cur_seconds_fullsync += 1 #incremental sync if(cur_seconds_incrsync >= interval_IncrementalSync): xbmc.log("Doing_Db_Sync: updatePlayCounts (Started)") worked = librarySync.updatePlayCounts() xbmc.log("Doing_Db_Sync: updatePlayCounts (Finished) " + str(worked)) if(worked): cur_seconds_incrsync = 0 else: cur_seconds_incrsync = interval_IncrementalSync - 10 else: cur_seconds_incrsync += 1 else: xbmc.log("Not authenticated yet")