diff --git a/addon.xml b/addon.xml index 20626c66..03fe0b8d 100644 --- a/addon.xml +++ b/addon.xml @@ -1,7 +1,7 @@ diff --git a/resources/lib/API.py b/resources/lib/API.py index c49f1c3c..ae7ab419 100644 --- a/resources/lib/API.py +++ b/resources/lib/API.py @@ -6,7 +6,8 @@ from datetime import datetime from random import randrange import xbmc import xbmcgui -import xbmcaddon + +import Utils as utils class API(): @@ -406,7 +407,6 @@ class API(): def getArtwork(self, data, type, mediaType = "", index = "0", userParentInfo = False): - addonSettings = xbmcaddon.Addon(id='plugin.video.emby') id = data.get("Id") getSeriesData = False userData = data.get("UserData") @@ -415,7 +415,7 @@ class API(): if data.get("Type") == "Season" or data.get("Type")== "Episode": id = data.get("SeriesId") getSeriesData = True - elif type == "poster" and data.get("Type") == "Episode" and addonSettings.getSetting('useSeasonPoster')=='true': # Change the Id to the Season to get the season poster + elif type == "poster" and data.get("Type") == "Episode" and utils.settings('useSeasonPoster')=='true': # Change the Id to the Season to get the season poster id = data.get("SeasonId") if type == "poster" or type == "tvshow.poster": # Now that the Ids are right, change type to MB3 name type="Primary" @@ -478,7 +478,7 @@ class API(): played = "0" totalbackdrops = 0 - if addonSettings.getSetting('coverArtratio') == "true": + if utils.settings('coverArtratio') == "true": if mediaType in ("movie","boxset","tvshow"): if "Primary" in type: # Only force ratio for cover art for main covers @@ -496,7 +496,7 @@ class API(): username = WINDOW.getProperty('currUser') server = WINDOW.getProperty('server%s' % username) - if addonSettings.getSetting('compressArt')=='true': + if utils.settings('compressArt')=='true': query = query + "&Quality=90" if imageTag == None: @@ -504,7 +504,7 @@ class API(): artwork = "%s/mediabrowser/Items/%s/Images/%s/%s?MaxWidth=%s&MaxHeight=%s%s%s&Format=original&Tag=%s%s" % (server, id, type, index, maxWidth, maxHeight, height, width, imageTag, query) #artwork = "%s/mediabrowser/Items/%s/Images/%s/%s/%s/original/%s/%s/%s?%s" % (server, id, type, index, imageTag, width, height, played, query) <- broken - if addonSettings.getSetting('disableCoverArt')=='true': + if utils.settings('disableCoverArt')=='true': artwork = artwork + "&EnableImageEnhancers=false" # do not return non-existing images diff --git a/resources/lib/ClientInformation.py b/resources/lib/ClientInformation.py index 9d2bceac..f014b165 100644 --- a/resources/lib/ClientInformation.py +++ b/resources/lib/ClientInformation.py @@ -37,13 +37,11 @@ class ClientInformation(): def getDeviceName(self): - addon = self.addon - - if addon.getSetting('deviceNameOpt') == "false": + if utils.settings('deviceNameOpt') == "false": # Use Kodi's deviceName deviceName = xbmc.getInfoLabel('System.FriendlyName') else: - deviceName = addon.getSetting('deviceName') + deviceName = utils.settings('deviceName') deviceName = deviceName.replace("\"", "_") deviceName = deviceName.replace("/", "_") diff --git a/resources/lib/ConnectionManager.py b/resources/lib/ConnectionManager.py index a2befbdb..b6eff13b 100644 --- a/resources/lib/ConnectionManager.py +++ b/resources/lib/ConnectionManager.py @@ -42,7 +42,6 @@ class ConnectionManager(): self.WINDOW.setProperty("Server_Checked", "True") self.logMsg("Connection Manager Called", 2) - addon = self.addon server = self.user.getServer() if server != "": @@ -61,11 +60,11 @@ class ConnectionManager(): if setServer == 1: self.logMsg("Server selected. Saving information.", 1) - addon.setSetting("ipaddress", ip.replace("/", "")) - addon.setSetting("port", port) + utils.settings("ipaddress", ip.replace("/", "")) + utils.settings("port", port) # If https, enable the setting if (prefix == 'https'): - addon.setSetting('https', "true") + utils.settings('https', "true") else: self.logMsg("No server selected.", 1) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) @@ -99,7 +98,7 @@ class ConnectionManager(): if resp > -1: selected_user = userList[resp] self.logMsg("Selected User: %s" % selected_user, 1) - self.addon.setSetting("username", selected_user) + utils.settings("username", selected_user) else: self.logMsg("No user selected.", 1) xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId) diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py index c76681bd..177db42d 100644 --- a/resources/lib/DownloadUtils.py +++ b/resources/lib/DownloadUtils.py @@ -135,9 +135,11 @@ class DownloadUtils(): self.logMsg("Requests session started on: %s" % self.server) - def imageUrl(self, id, type, index, width, height): - # To move to API.py - return "%s/mediabrowser/Items/%s/Images/%s?MaxWidth=%s&MaxHeight=%s&Index=%s" % (self.server, id, type, width, height, index) + def stopSession(self): + try: + self.s.close() + except: + self.logMsg("Requests session could not be terminated.", 1) def getHeader(self, authenticate=True): @@ -206,10 +208,10 @@ class DownloadUtils(): # IF user enables ssl verification try: - if self.addon.getSetting('sslverify') == "true": + if utils.settings('sslverify') == "true": verifyssl = True - if self.addon.getSetting('sslcert') != "None": - cert = self.addon.getSetting('sslcert') + if utils.settings('sslcert') != "None": + cert = utils.settings('sslcert') except: self.logMsg("Could not load SSL settings.", 1) pass diff --git a/resources/lib/Entrypoint.py b/resources/lib/Entrypoint.py index 03cf7c80..52937421 100644 --- a/resources/lib/Entrypoint.py +++ b/resources/lib/Entrypoint.py @@ -437,7 +437,7 @@ def BrowseChannels(id, folderid=None): ##### GET NEXTUP EPISODES FOR TAGNAME ##### def getNextUpEpisodes(tagname,limit): count=0 - addonSettings = xbmcaddon.Addon(id='plugin.video.emby') + #if the addon is called with nextup parameter, we return the nextepisodes list of the given tagname xbmcplugin.setContent(int(sys.argv[1]), 'episodes') # First we get a list of all the in-progress TV shows - filtered by tag @@ -449,7 +449,7 @@ def getNextUpEpisodes(tagname,limit): for item in json_result['result']['tvshows']: # If Ignore Specials is true only choose episodes from seasons greater than 0. - if addonSettings.getSetting("ignoreSpecialsNextEpisodes")=="true": + if utils.settings("ignoreSpecialsNextEpisodes")=="true": json_query2 = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "tvshowid": %d, "sort": {"method":"episode"}, "filter": {"and": [ {"field": "playcount", "operator": "lessthan", "value":"1"}, {"field": "season", "operator": "greaterthan", "value": "0"} ]}, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "streamdetails", "firstaired", "runtime", "writer", "dateadded", "lastplayed" ], "limits":{"end":1}}, "id": "1"}' %item['tvshowid']) else: json_query2 = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "tvshowid": %d, "sort": {"method":"episode"}, "filter": {"field": "playcount", "operator": "lessthan", "value":"1"}, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "streamdetails", "firstaired", "runtime", "writer", "dateadded", "lastplayed" ], "limits":{"end":1}}, "id": "1"}' %item['tvshowid']) diff --git a/resources/lib/KodiMonitor.py b/resources/lib/KodiMonitor.py index 24b08a3b..10369321 100644 --- a/resources/lib/KodiMonitor.py +++ b/resources/lib/KodiMonitor.py @@ -15,7 +15,6 @@ from PlayUtils import PlayUtils from DownloadUtils import DownloadUtils from PlaybackUtils import PlaybackUtils -addon = xbmcaddon.Addon(id='plugin.video.emby') class Kodi_Monitor(xbmc.Monitor): @@ -34,7 +33,7 @@ class Kodi_Monitor(xbmc.Monitor): WINDOW = self.WINDOW downloadUtils = DownloadUtils() #player started playing an item - - if ("Playlist.OnAdd" in method or "Player.OnPlay" in method) and addon.getSetting('useDirectPaths')=='true': + if ("Playlist.OnAdd" in method or "Player.OnPlay" in method) and utils.settings('useDirectPaths')=='true': jsondata = json.loads(data) if jsondata != None: diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 642e0503..e56ff584 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -43,8 +43,8 @@ class LibrarySync(threading.Thread): addonName = clientInfo.getAddonName() - doIncrementalSync = False updateItems = [] + userdataItems = [] removeItems = [] def __init__(self, *args): @@ -59,28 +59,27 @@ class LibrarySync(threading.Thread): def FullLibrarySync(self,manualRun=False): - addon = xbmcaddon.Addon(id='plugin.video.emby') startupDone = WINDOW.getProperty("startup") == "done" - syncInstallRunDone = addon.getSetting("SyncInstallRunDone") == "true" - performMusicSync = addon.getSetting("enableMusicSync") == "true" - dbSyncIndication = addon.getSetting("dbSyncIndication") == "true" + syncInstallRunDone = utils.settings("SyncInstallRunDone") == "true" + performMusicSync = utils.settings("enableMusicSync") == "true" + dbSyncIndication = utils.settings("dbSyncIndication") == "true" ### BUILD VIDEO NODES LISTING ### VideoNodes().buildVideoNodesListing() ### CREATE SOURCES ### - if addon.getSetting("Sources") != "true": + if utils.settings("Sources") != "true": # Only create sources once self.logMsg("Sources.xml created.", 0) utils.createSources() - addon.setSetting("Sources", "true") + utils.settings("Sources", "true") # just do a incremental sync if that is what is required - if(addon.getSetting("useIncSync") == "true" and addon.getSetting("SyncInstallRunDone") == "true") and manualRun == False: + if(utils.settings("useIncSync") == "true" and utils.settings("SyncInstallRunDone") == "true") and manualRun == False: utils.logMsg("Sync Database", "Using incremental sync instead of full sync useIncSync=True)", 0) du = DownloadUtils() - lastSync = addon.getSetting("LastIncrenetalSync") + lastSync = utils.settings("LastIncrenetalSync") if(lastSync == None or len(lastSync) == 0): lastSync = "2010-01-01T00:00:00Z" utils.logMsg("Sync Database", "Incremental Sync Setting Last Run Time Loaded : " + lastSync, 0) @@ -103,8 +102,10 @@ class LibrarySync(threading.Thread): LibrarySync().update_items(changedItems) LibrarySync().user_data_update(userChanges) + self.SaveLastSync() + return True - + #set some variable to check if this is the first run WINDOW.setProperty("SyncDatabaseRunning", "true") @@ -128,7 +129,10 @@ class LibrarySync(threading.Thread): cursor = connection.cursor() #Add the special emby table - cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER)") + cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER, kodi_file_id INTEGER)") + try: + cursor.execute("ALTER TABLE emby ADD COLUMN kodi_file_id INTEGER") + except: pass connection.commit() # sync movies @@ -156,7 +160,10 @@ class LibrarySync(threading.Thread): cursor = connection.cursor() #Add the special emby table - cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER)") + cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER, kodi_file_id INTEGER)") + try: + cursor.execute("ALTER TABLE emby ADD COLUMN kodi_file_id INTEGER") + except: pass connection.commit() self.MusicFullSync(connection,cursor,pDialog) @@ -164,12 +171,12 @@ class LibrarySync(threading.Thread): # set the install done setting if(syncInstallRunDone == False and completed): - addon = xbmcaddon.Addon(id='plugin.video.emby') #force a new instance of the addon - addon.setSetting("SyncInstallRunDone", "true") + utils.settings("SyncInstallRunDone", "true") self.SaveLastSync() # Commit all DB changes at once and Force refresh the library xbmc.executebuiltin("UpdateLibrary(video)") + #xbmc.executebuiltin("UpdateLibrary(music)") # set prop to show we have run for the first time WINDOW.setProperty("startup", "done") @@ -189,10 +196,9 @@ class LibrarySync(threading.Thread): def SaveLastSync(self): # save last sync time - addon = xbmcaddon.Addon(id='plugin.video.emby') lastSync = (datetime.utcnow() - timedelta(minutes=5)).strftime('%Y-%m-%dT%H:%M:%SZ') - utils.logMsg("Sync Database", "Incremental Sync Setting Last Run Time Saved : " + lastSync, 0) - addon.setSetting("LastIncrenetalSync", lastSync) + self.logMsg("Sync Database, Incremental Sync Setting Last Run Time Saved: %s" % lastSync, 1) + utils.settings("LastIncrenetalSync", lastSync) def MoviesFullSync(self,connection,cursor, pDialog): @@ -587,9 +593,8 @@ class LibrarySync(threading.Thread): if startupDone: #this will only perform sync for items received by the websocket - addon = xbmcaddon.Addon(id='plugin.video.emby') - dbSyncIndication = addon.getSetting("dbSyncIndication") == "true" - performMusicSync = addon.getSetting("enableMusicSync") == "true" + dbSyncIndication = utils.settings("dbSyncIndication") == "true" + performMusicSync = utils.settings("enableMusicSync") == "true" WINDOW.setProperty("SyncDatabaseRunning", "true") #show the progress dialog @@ -689,11 +694,11 @@ class LibrarySync(threading.Thread): itemType = MBitem.get('Type', "") if "MusicArtist" in itemType: - WriteKodiMusicDB().addOrUpdateArtistToKodiLibrary(MBitem,connection, cursor) + WriteKodiMusicDB().addOrUpdateArtistToKodiLibrary(MBitem, connection, cursor) if "MusicAlbum" in itemType: - WriteKodiMusicDB().addOrUpdateAlbumToKodiLibrary(MBitem,connection, cursor) + WriteKodiMusicDB().addOrUpdateAlbumToKodiLibrary(MBitem, connection, cursor) if "Audio" in itemType: - WriteKodiMusicDB().addOrUpdateSongToKodiLibrary(MBitem,connection, cursor) + WriteKodiMusicDB().addOrUpdateSongToKodiLibrary(MBitem, connection, cursor) connection.commit() cursor.close() @@ -766,10 +771,7 @@ class LibrarySync(threading.Thread): connection = connectionmusic cursor = cursormusic #Process music library - addon = xbmcaddon.Addon() - if addon.getSetting('enableMusicSync') == "true": - connection = utils.KodiSQL("music") - cursor = connection.cursor() + if utils.settings('enableMusicSync') == "true": for item in music: self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteItemFromKodiLibrary (musiclibrary): " + item, 0) @@ -786,6 +788,61 @@ class LibrarySync(threading.Thread): doUtils.downloadUrl(url, type = "DELETE") xbmc.executebuiltin("Container.Refresh") + def setUserdata(self, listItems): + # We need to sort between video and music database + video = [] + music = [] + # Database connection to myVideosXX.db + connectionvideo = utils.KodiSQL() + cursorvideo = connectionvideo.cursor() + # Database connection to myMusicXX.db + connectionmusic = utils.KodiSQL('music') + cursormusic = connectionmusic.cursor() + + for userdata in listItems: + itemId = userdata['ItemId'] + + cursorvideo.execute("SELECT media_type FROM emby WHERE emby_id = ?", (itemId,)) + try: # Search video database + self.logMsg("Check video database.", 1) + mediatype = cursorvideo.fetchone()[0] + video.append(userdata) + except: + cursormusic.execute("SELECT media_type FROM emby WHERE emby_id = ?", (itemId,)) + try: # Search music database + self.logMsg("Check the music database.", 1) + mediatype = cursormusic.fetchone()[0] + music.append(userdata) + except: self.logMsg("Item %s is not found in Kodi database." % itemId, 2) + + if len(video) > 0: + connection = connectionvideo + cursor = cursorvideo + # Process the userdata update for video library + for userdata in video: + WriteKodiVideoDB().updateUserdata(userdata, connection, cursor) + + connection.commit() + xbmc.executebuiltin("UpdateLibrary(video)") + # Close connection + cursorvideo.close() + + '''if len(music) > 0: + connection = connectionmusic + cursor = cursormusic + #Process music library + musicenabled = utils.settings('enableMusicSync') == "true" + # Process the userdata update for music library + if musicenabled: + for userdata in music: + WriteKodiMusicDB().updateUserdata(userdata, connection, cursor) + + connection.commit() + xbmc.executebuiltin("UpdateLibrary(music)")''' + # Close connection + cursormusic.close() + self.SaveLastSync() + def remove_items(self, itemsRemoved): # websocket client self.removeItems.extend(itemsRemoved) @@ -798,12 +855,7 @@ class LibrarySync(threading.Thread): def user_data_update(self, userDataList): # websocket client - for userData in userDataList: - itemId = userData.get("ItemId") - if(itemId != None): - self.updateItems.append(itemId) - if(len(self.updateItems) > 0): - self.logMsg("Doing UserDataChanged : Processing Updated : " + str(self.updateItems), 0) + self.userdataItems.extend(userDataList) def ShouldStop(self): @@ -851,13 +903,21 @@ class LibrarySync(threading.Thread): libSync = self.FullLibrarySync() self.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Finished) " + str(libSync), 0) + + if len(self.updateItems) > 0: # Add or update items self.logMsg("Processing items: %s" % (str(self.updateItems)), 1) listItems = self.updateItems self.updateItems = [] self.IncrementalSync(listItems) - self.SaveLastSync() + + if len(self.userdataItems) > 0: + # Process userdata changes only + self.logMsg("Processing items: %s" % (str(self.userdataItems)), 1) + listItems = self.userdataItems + self.userdataItems = [] + self.setUserdata(listItems) if len(self.removeItems) > 0: # Remove item from Kodi library @@ -865,7 +925,6 @@ class LibrarySync(threading.Thread): listItems = self.removeItems self.removeItems = [] self.removefromDB(listItems) - self.SaveLastSync() if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. We should exit diff --git a/resources/lib/PlayUtils.py b/resources/lib/PlayUtils.py index 985bbf2a..2a282d96 100644 --- a/resources/lib/PlayUtils.py +++ b/resources/lib/PlayUtils.py @@ -21,12 +21,8 @@ class PlayUtils(): clientInfo = ClientInformation() addonName = clientInfo.getAddonName() - addon = xbmcaddon.Addon() WINDOW = xbmcgui.Window(10000) - audioPref = addon.getSetting('Audiopref') - subsPref = addon.getSetting('Subspref') - def __init__(self): self.__dict__ = self._shared_state @@ -70,9 +66,8 @@ class PlayUtils(): def isDirectPlay(self, result, dialog=False): # Requirements for Direct play: # FileSystem, Accessible path - self.addon = xbmcaddon.Addon() - playhttp = self.addon.getSetting('playFromStream') + playhttp = utils.settings('playFromStream') # User forcing to play via HTTP instead of SMB if playhttp == "true": self.logMsg("Can't direct play: Play from HTTP is enabled.", 1) @@ -98,7 +93,7 @@ class PlayUtils(): resp = dialog.select('Warning: Unable to direct play.', ['Play from HTTP', 'Play from HTTP and remember next time.']) if resp == 1: # Remember next time - self.addon.setSetting('playFromStream', "true") + utils.settings('playFromStream', "true") elif resp < 0: # User decided not to proceed. self.logMsg("User cancelled HTTP selection dialog.", 1) @@ -109,7 +104,6 @@ class PlayUtils(): def directPlay(self, result): - addon = self.addon try: try: playurl = result[u'MediaSources'][0][u'Path'] @@ -128,8 +122,8 @@ class PlayUtils(): # Network - SMB protocol if "\\\\" in playurl: - smbuser = addon.getSetting('smbusername') - smbpass = addon.getSetting('smbpassword') + smbuser = utils.settings('smbusername') + smbpass = utils.settings('smbpassword') # Network share if smbuser: playurl = playurl.replace("\\\\", "smb://%s:%s@" % (smbuser, smbpass)) @@ -238,7 +232,7 @@ class PlayUtils(): def getVideoBitRate(self): # get the addon video quality - videoQuality = self.addon.getSetting('videoBitRate') + videoQuality = utils.settings('videoBitRate') if (videoQuality == "0"): return 664 diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index b6a85329..f61510e7 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -16,11 +16,10 @@ from ReadKodiDB import ReadKodiDB from ReadEmbyDB import ReadEmbyDB import Utils as utils from API import API -import Utils as utils import os import xbmcvfs -addon = xbmcaddon.Addon(id='plugin.video.emby') +addon = xbmcaddon.Addon() addondir = xbmc.translatePath(addon.getAddonInfo('profile')) WINDOW = xbmcgui.Window( 10000 ) @@ -54,7 +53,7 @@ class PlaybackUtils(): # BOOKMARK - RESUME POINT timeInfo = API().getTimeInfo(result) - jumpBackSec = int(addon.getSetting("resumeJumpBack")) + jumpBackSec = int(utils.settings("resumeJumpBack")) seekTime = round(float(timeInfo.get('ResumeTime')), 6) if seekTime > jumpBackSec: # To avoid negative bookmark diff --git a/resources/lib/Player.py b/resources/lib/Player.py index e1b79ff6..89c3c611 100644 --- a/resources/lib/Player.py +++ b/resources/lib/Player.py @@ -33,8 +33,6 @@ class Player( xbmc.Player ): ws = WebSocketThread() addonName = clientInfo.getAddonName() - addonId = clientInfo.getAddonId() - addon = xbmcaddon.Addon(id=addonId) WINDOW = xbmcgui.Window(10000) @@ -73,7 +71,6 @@ class Player( xbmc.Player ): if(len(self.played_information) == 0): return - addonSettings = xbmcaddon.Addon(id='plugin.video.emby') self.logMsg("emby Service -> played_information : " + str(self.played_information)) for item_url in self.played_information: @@ -107,9 +104,9 @@ class Player( xbmc.Player ): self.stopPlayback(data) offerDelete=False - if data.get("Type") == "Episode" and addonSettings.getSetting("offerDeleteTV")=="true": + if data.get("Type") == "Episode" and utils.settings("offerDeleteTV")=="true": offerDelete = True - elif data.get("Type") == "Movie" and addonSettings.getSetting("offerDeleteMovies")=="true": + elif data.get("Type") == "Movie" and utils.settings("offerDeleteMovies")=="true": offerDelete = True if percentComplete > .80 and offerDelete == True: @@ -258,7 +255,6 @@ class Player( xbmc.Player ): def onPlayBackStarted( self ): # Will be called when xbmc starts playing a file WINDOW = xbmcgui.Window(10000) - addon = self.addon xbmcplayer = self.xbmcplayer self.stopAll() diff --git a/resources/lib/UserClient.py b/resources/lib/UserClient.py index c1f04aff..1764591e 100644 --- a/resources/lib/UserClient.py +++ b/resources/lib/UserClient.py @@ -29,8 +29,7 @@ class UserClient(threading.Thread): KodiMonitor = KodiMonitor.Kodi_Monitor() addonName = clientInfo.getAddonName() - addonId = clientInfo.getAddonId() - addon = xbmcaddon.Addon(id=addonId) + addon = xbmcaddon.Addon() WINDOW = xbmcgui.Window(10000) stopClient = False @@ -57,8 +56,7 @@ class UserClient(threading.Thread): def getUsername(self): - addon = xbmcaddon.Addon(id=self.addonId) - username = addon.getSetting('username') + username = utils.settings('username') if (username == ""): self.logMsg("No username saved.", 2) @@ -69,7 +67,7 @@ class UserClient(threading.Thread): def getLogLevel(self): try: - logLevel = int(self.addon.getSetting('logLevel')) + logLevel = int(utils.settings('logLevel')) except: logLevel = 0 @@ -79,7 +77,7 @@ class UserClient(threading.Thread): username = self.getUsername() w_userId = self.WINDOW.getProperty('userId%s' % username) - s_userId = self.addon.getSetting('userId%s' % username) + s_userId = utils.settings('userId%s' % username) # Verify the window property if (w_userId != ""): @@ -97,13 +95,12 @@ class UserClient(threading.Thread): def getServer(self, prefix=True): # For https support - addon = xbmcaddon.Addon(id=self.addonId) - HTTPS = addon.getSetting('https') - host = addon.getSetting('ipaddress') - port = addon.getSetting('port') + HTTPS = utils.settings('https') + host = utils.settings('ipaddress') + port = utils.settings('port') # Alternate host - if addon.getSetting('altip') == "true": - host = addon.getSetting('secondipaddress') + if utils.settings('altip') == "true": + host = utils.settings('secondipaddress') server = host + ":" + port @@ -127,7 +124,7 @@ class UserClient(threading.Thread): username = self.getUsername() w_token = self.WINDOW.getProperty('accessToken%s' % username) - s_token = self.addon.getSetting('accessToken') + s_token = utils.settings('accessToken') # Verify the window property if (w_token != ""): @@ -144,7 +141,7 @@ class UserClient(threading.Thread): def getSSLverify(self): # Verify host certificate - s_sslverify = self.addon.getSetting('sslverify') + s_sslverify = utils.settings('sslverify') if s_sslverify == "true": return True @@ -153,7 +150,7 @@ class UserClient(threading.Thread): def getSSL(self): # Client side certificate - s_cert = self.addon.getSetting('sslcert') + s_cert = utils.settings('sslcert') if s_cert == "None": return None @@ -165,22 +162,10 @@ class UserClient(threading.Thread): player = Player() server = self.getServer() userId = self.getUserId() - addon = self.addon url = "{server}/mediabrowser/Users/{UserId}?format=json" result = self.doUtils.downloadUrl(url) - audio = result[u'Configuration'].get(u'AudioLanguagePreference', "default") - subs = result[u'Configuration'].get(u'SubtitleLanguagePreference', "default") - addon.setSetting('Audiopref', audio) - addon.setSetting('Subspref', subs) - - # Set the setting in Player - player.setAudioSubsPref(audio.encode('utf-8'), subs.encode('utf-8')) - - self.logMsg("Audio preference: %s" % audio, 2) - self.logMsg("Subtitles preference: %s" % subs, 2) - # Set user image for skin display self.WINDOW.setProperty("EmbyUserImage",API().getUserArtwork(result,"Primary")) @@ -279,7 +264,7 @@ class UserClient(threading.Thread): username = self.getUsername() server = self.getServer() - addondir = xbmc.translatePath(self.addon.getAddonInfo('profile')) + addondir = xbmc.translatePath(self.addon.getAddonInfo('profile')).decode('utf-8') hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir) # If there's no settings.xml @@ -351,8 +336,8 @@ class UserClient(threading.Thread): self.currUser = username xbmcgui.Dialog().notification("Emby server", "Welcome %s!" % self.currUser) userId = result[u'User'][u'Id'] - addon.setSetting("accessToken", accessToken) - addon.setSetting("userId%s" % username, userId) + utils.settings("accessToken", accessToken) + utils.settings("userId%s" % username, userId) self.logMsg("User Authenticated: %s" % accessToken) self.loadCurrUser(authenticated=True) self.WINDOW.setProperty("Server_status", "") @@ -360,8 +345,8 @@ class UserClient(threading.Thread): return else: self.logMsg("User authentication failed.") - addon.setSetting("accessToken", "") - addon.setSetting("userId%s" % username, "") + utils.settings("accessToken", "") + utils.settings("userId%s" % username, "") xbmcgui.Dialog().ok("Error connecting", "Invalid username or password.") # Give two attempts at entering password @@ -380,7 +365,7 @@ class UserClient(threading.Thread): self.logMsg("Reset UserClient authentication.", 1) if (self.currToken != None): # In case of 401, removed saved token - self.addon.setSetting("accessToken", "") + utils.settings("accessToken", "") self.WINDOW.setProperty("accessToken%s" % username, "") self.currToken = None self.logMsg("User token has been removed.", 1) @@ -396,8 +381,6 @@ class UserClient(threading.Thread): while not self.KodiMonitor.abortRequested(): - # Get the latest addon settings - self.addon = xbmcaddon.Addon(id=self.addonId) # Verify the log level currLogLevel = self.getLogLevel() if self.logLevel != currLogLevel: @@ -447,7 +430,8 @@ class UserClient(threading.Thread): if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. We should exit break - + + self.doUtils.stopSession() self.logMsg("|---- UserClient Stopped ----|", 0) def stopClient(self): diff --git a/resources/lib/Utils.py b/resources/lib/Utils.py index ea54954f..37886706 100644 --- a/resources/lib/Utils.py +++ b/resources/lib/Utils.py @@ -20,6 +20,7 @@ import unicodedata from API import API from PlayUtils import PlayUtils from DownloadUtils import DownloadUtils + downloadUtils = DownloadUtils() addon = xbmcaddon.Addon() language = addon.getLocalizedString @@ -184,7 +185,7 @@ def createSources(): '' ) -def settings(setting, value=""): +def settings(setting, value = None): # Get or add addon setting addon = xbmcaddon.Addon() if value: @@ -230,8 +231,13 @@ def normalize_nodes(text): text = unicodedata.normalize('NFKD', unicode(text, 'utf-8')).encode('ascii', 'ignore') return text + +def reloadProfile(): + # Useful to reload the add-on without restarting Kodi. + profile = xbmc.getInfoLabel('System.ProfileName') + xbmc.executebuiltin("LoadProfile(%s)" % profile) - + def reset(): WINDOW = xbmcgui.Window( 10000 ) @@ -251,11 +257,18 @@ def reset(): for file in allFiles: if file.startswith("emby"): xbmcvfs.delete(path + file) + + settings('SyncInstallRunDone', "false") # Ask if user information should be deleted too. return_user = xbmcgui.Dialog().yesno("Warning", "Reset all Emby Addon settings?") if return_user == 1: WINDOW.setProperty('deletesettings', "true") + addon = xbmcaddon.Addon() + addondir = xbmc.translatePath(addon.getAddonInfo('profile')).decode('utf-8') + dataPath = "%ssettings.xml" % addondir + xbmcvfs.delete(dataPath) + logMsg("EMBY", "Deleting: settings.xml", 1) # first stop any db sync WINDOW.setProperty("SyncDatabaseShouldStop", "true") @@ -283,7 +296,7 @@ def reset(): connection.commit() cursor.close() - if addon.getSetting("enableMusicSync") == "true": + if settings('enableMusicSync') == "true": # delete video db table data print "Doing Music DB Reset" connection = KodiSQL("music") @@ -299,8 +312,13 @@ def reset(): # reset the install run flag - WINDOW.setProperty("SyncInstallRunDone", "false") + #settings('SyncInstallRunDone', "false") + #WINDOW.setProperty("SyncInstallRunDone", "false") dialog = xbmcgui.Dialog() + # Reload would work instead of restart since the add-on is a service. + #dialog.ok('Emby Reset', 'Database reset has completed, Kodi will now restart to apply the changes.') + #WINDOW.clearProperty("SyncDatabaseShouldStop") + #reloadProfile() dialog.ok('Emby Reset', 'Database reset has completed, Kodi will now restart to apply the changes.') xbmc.executebuiltin("RestartApp") \ No newline at end of file diff --git a/resources/lib/VideoNodes.py b/resources/lib/VideoNodes.py index dea0e5c2..57772d09 100644 --- a/resources/lib/VideoNodes.py +++ b/resources/lib/VideoNodes.py @@ -18,7 +18,7 @@ import Utils as utils from ReadEmbyDB import ReadEmbyDB WINDOW = xbmcgui.Window(10000) -addonSettings = xbmcaddon.Addon(id='plugin.video.emby') +addonSettings = xbmcaddon.Addon() language = addonSettings.getLocalizedString class VideoNodes(): diff --git a/resources/lib/WebSocketClient.py b/resources/lib/WebSocketClient.py index 938eadf4..5f15f924 100644 --- a/resources/lib/WebSocketClient.py +++ b/resources/lib/WebSocketClient.py @@ -79,7 +79,6 @@ class WebSocketThread(threading.Thread): def on_message(self, ws, message): WINDOW = xbmcgui.Window(10000) - addon = xbmcaddon.Addon() self.logMsg("Message: %s" % message, 1) result = json.loads(message) @@ -223,13 +222,13 @@ class WebSocketThread(threading.Thread): xbmcgui.Dialog().notification(header, text, icon="special://home/addons/plugin.video.emby/icon.png", time=4000) elif command == "SendString": string = arguments['String'] - text = '{"jsonrpc": "2.0", "method": "Input.SendText", "params": { "text": "%s", "done": false }, "id": 0}' % string + text = '{"jsonrpc": "2.0", "method": "Input.SendText", "params": { "text": "%s", "done": false }, "id": 0}' % string result = xbmc.executeJSONRPC(text) else: self.logMsg("Unknown command.", 1) elif messageType == "ServerRestarting": - if addon.getSetting('supressRestartMsg') == "true": + if utils.settings('supressRestartMsg') == "true": xbmcgui.Dialog().notification("Emby server", "Server is restarting.", icon="special://home/addons/plugin.video.emby/icon.png") def on_error(self, ws, error): diff --git a/resources/lib/WriteKodiMusicDB.py b/resources/lib/WriteKodiMusicDB.py index 8e776fdb..989e65bf 100644 --- a/resources/lib/WriteKodiMusicDB.py +++ b/resources/lib/WriteKodiMusicDB.py @@ -26,7 +26,6 @@ class WriteKodiMusicDB(): textureCache = TextureCache() kodiversion = int(xbmc.getInfoLabel("System.BuildVersion")[:2]) - addon = xbmcaddon.Addon() addonName = ClientInformation().getAddonName() WINDOW = xbmcgui.Window(10000) @@ -34,7 +33,7 @@ class WriteKodiMusicDB(): userid = WINDOW.getProperty('userId%s' % username) server = WINDOW.getProperty('server%s' % username) - directpath = addon.getSetting('useDirectPaths') == "true" + directpath = utils.settings('useDirectPaths') == "true" def logMsg(self, msg, lvl = 1): diff --git a/resources/lib/WriteKodiVideoDB.py b/resources/lib/WriteKodiVideoDB.py index ffe51e29..8ed04020 100644 --- a/resources/lib/WriteKodiVideoDB.py +++ b/resources/lib/WriteKodiVideoDB.py @@ -26,7 +26,6 @@ class WriteKodiVideoDB(): doUtils = DownloadUtils() kodiversion = int(xbmc.getInfoLabel("System.BuildVersion")[:2]) - addon = xbmcaddon.Addon() addonName = ClientInformation().getAddonName() WINDOW = xbmcgui.Window(10000) @@ -34,7 +33,7 @@ class WriteKodiVideoDB(): userid = WINDOW.getProperty('userId%s' % username) server = WINDOW.getProperty('server%s' % username) - directpath = addon.getSetting('useDirectPaths') == "true" + directpath = utils.settings('useDirectPaths') == "true" def logMsg(self, msg, lvl = 1): @@ -73,7 +72,6 @@ class WriteKodiVideoDB(): def addOrUpdateMovieToKodiLibrary(self, embyId, connection, cursor, viewTag): - addon = self.addon MBitem = ReadEmbyDB().getFullItem(embyId) if not MBitem: @@ -222,8 +220,8 @@ class WriteKodiVideoDB(): self.AddTagToMedia(movieid, viewTag, "movie", cursor) # Create the reference in emby table - query = "INSERT INTO emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)" - cursor.execute(query, (embyId, movieid, "movie", checksum)) + query = "INSERT INTO emby(emby_id, kodi_id, kodi_file_id, media_type, checksum) values(?, ?, ?, ?, ?)" + cursor.execute(query, (embyId, movieid, fileid, "movie", checksum)) # Update or insert actors @@ -260,7 +258,7 @@ class WriteKodiVideoDB(): # Set resume point and round to 6th decimal resume = round(float(timeInfo.get('ResumeTime')), 6) total = round(float(timeInfo.get('TotalTime')), 6) - jumpback = int(addon.getSetting('resumeJumpBack')) + jumpback = int(utils.settings('resumeJumpBack')) if resume > jumpback: # To avoid negative bookmark resume = resume - jumpback @@ -268,7 +266,6 @@ class WriteKodiVideoDB(): def addOrUpdateMusicVideoToKodiLibrary( self, embyId ,connection, cursor): - addon = xbmcaddon.Addon(id='plugin.video.emby') WINDOW = xbmcgui.Window(10000) username = WINDOW.getProperty('currUser') userid = WINDOW.getProperty('userId%s' % username) @@ -433,7 +430,6 @@ class WriteKodiVideoDB(): def addOrUpdateTvShowToKodiLibrary(self, embyId, connection, cursor, viewTag ): - addon = self.addon MBitem = ReadEmbyDB().getFullItem(embyId) if not MBitem: @@ -571,7 +567,6 @@ class WriteKodiVideoDB(): def addOrUpdateEpisodeToKodiLibrary(self, embyId, showid, connection, cursor): - addon = self.addon MBitem = ReadEmbyDB().getFullItem(embyId) if not MBitem: @@ -708,8 +703,8 @@ class WriteKodiVideoDB(): cursor.execute(query, (episodeid, fileid, title, plot, rating, writer, premieredate, runtime, director, season, episode, title, showid, "-1", "-1")) # Create the reference in emby table - query = "INSERT INTO emby(emby_id, kodi_id, media_type, checksum, parent_id) values(?, ?, ?, ?, ?)" - cursor.execute(query, (embyId, episodeid, "episode", checksum, showid)) + query = "INSERT INTO emby(emby_id, kodi_id, kodi_file_id, media_type, checksum, parent_id) values(?, ?, ?, ?, ?, ?)" + cursor.execute(query, (embyId, episodeid, fileid, "episode", checksum, showid)) # Update or insert actors self.AddPeopleToMedia(episodeid, MBitem.get('People'), "episode", connection, cursor) @@ -723,7 +718,7 @@ class WriteKodiVideoDB(): # Set resume point and round to 6th decimal resume = round(float(timeInfo.get('ResumeTime')), 6) total = round(float(timeInfo.get('TotalTime')), 6) - jumpback = int(addon.getSetting('resumeJumpBack')) + jumpback = int(utils.settings('resumeJumpBack')) if resume > jumpback: # To avoid negative bookmark resume = resume - jumpback diff --git a/service.py b/service.py index a5ca821d..042d0505 100644 --- a/service.py +++ b/service.py @@ -10,8 +10,8 @@ import xbmc import xbmcgui import xbmcvfs -addon_ = xbmcaddon.Addon(id='plugin.video.emby') -addon_path = addon_.getAddonInfo('path').decode('utf-8') +_addon = xbmcaddon.Addon(id='plugin.video.emby') +addon_path = _addon.getAddonInfo('path').decode('utf-8') base_resource_path = xbmc.translatePath(os.path.join(addon_path, 'resources', 'lib')).decode('utf-8') sys.path.append(base_resource_path) @@ -90,7 +90,6 @@ class Service(): def ServiceEntryPoint(self): WINDOW = self.WINDOW - addon = xbmcaddon.Addon() # Server auto-detect ConnectionManager().checkServer() @@ -106,9 +105,6 @@ class Service(): while not self.KodiMonitor.abortRequested(): - # Refresh with the latest addon settings - addon = xbmcaddon.Addon() - # Before proceeding, need to make sure: # 1. Server is online # 2. User is set @@ -153,7 +149,7 @@ class Service(): else: # Start up events self.warn_auth = True - if addon.getSetting('supressConnectMsg') == "false": + if utils.settings('supressConnectMsg') == "false": if self.welcome_msg: # Reset authentication warnings self.welcome_msg = False @@ -236,16 +232,6 @@ class Service(): if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. We should exit break - - # If user reset library database. - if WINDOW.getProperty('SyncInstallRunDone') == "false": - addon.setSetting('SyncInstallRunDone', "false") - # If user delete Emby settings - if WINDOW.getProperty('deletesettings') == "true": - addondir = xbmc.translatePath(addon.getAddonInfo('profile')).decode('utf-8') - dataPath = "%ssettings.xml" % addondir - xbmcvfs.delete(dataPath) - self.logMsg("Deleting: settings.xml", 1) if (self.newWebSocketThread is not None): ws.stopClient()