diff --git a/addon.xml b/addon.xml index 0f0d86f9..185e4df6 100644 --- a/addon.xml +++ b/addon.xml @@ -1,7 +1,7 @@ diff --git a/changelog.txt b/changelog.txt index 14c2e746..e1149bd3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +version 2.1.0 +- Add a throttle (automatically adjust the number of items requested at once) to prevent crashing during the initial sync +- Do not update the video library when there's a music-only update + version 2.0.3 - Add new retention time option that the latest server Sync plugin uses to help determine if full sync or inc sync should be used. - Add control over new content pop up display time. You will find the settings under Extras > Enable new content notification diff --git a/default.py b/default.py index 631344ba..dc77c997 100644 --- a/default.py +++ b/default.py @@ -100,6 +100,14 @@ class Main: if mode == "settings": xbmc.executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)') elif mode in ("manualsync", "repair"): + if utils.window('emby_online') != "true": + # Server is not online, do not run the sync + xbmcgui.Dialog().ok(heading="Emby for Kodi", + line1=("Unable to run the sync, the add-on is not " + "connected to the Emby server.")) + utils.logMsg("EMBY", "Not connected to the emby server.", 1) + return + if utils.window('emby_dbScan') != "true": import librarysync lib = librarysync.LibrarySync() diff --git a/resources/lib/itemtypes.py b/resources/lib/itemtypes.py index dd7cb3db..a233822f 100644 --- a/resources/lib/itemtypes.py +++ b/resources/lib/itemtypes.py @@ -85,6 +85,7 @@ class Items(object): 'Audio': Music } + update_videolibrary = False total = 0 for item in items: total += len(items[item]) @@ -120,6 +121,7 @@ class Items(object): # Music is not enabled, do not proceed with itemtype continue else: + update_videolibrary = True items_process = itemtypes[itemtype](embycursor, kodicursor) if itemtype == "Movie": @@ -214,10 +216,11 @@ class Items(object): if musicconn is not None: # close connection for special types + self.logMsg("Updating music database.", 1) musicconn.commit() musiccursor.close() - return True + return (True, update_videolibrary) def contentPop(self, name, time=5000): xbmcgui.Dialog().notification( diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index 4f61db5a..f779784b 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -1016,6 +1016,117 @@ class LibrarySync(threading.Thread): return True + # Reserved for websocket_client.py and fast start + def triage_items(self, process, items): + + processlist = { + + 'added': self.addedItems, + 'update': self.updateItems, + 'userdata': self.userdataItems, + 'remove': self.removeItems + } + if items: + if process == "userdata": + itemids = [] + for item in items: + itemids.append(item['ItemId']) + items = itemids + + self.logMsg("Queue %s: %s" % (process, items), 1) + processlist[process].extend(items) + + def incrementalSync(self): + + embyconn = utils.kodiSQL('emby') + embycursor = embyconn.cursor() + kodiconn = utils.kodiSQL('video') + kodicursor = kodiconn.cursor() + emby = self.emby + emby_db = embydb.Embydb_Functions(embycursor) + pDialog = None + update_embydb = False + + if self.refresh_views: + # Received userconfig update + self.refresh_views = False + self.maintainViews(embycursor, kodicursor) + self.forceLibraryUpdate = True + update_embydb = True + + if self.addedItems or self.updateItems or self.userdataItems or self.removeItems: + # Only present dialog if we are going to process items + pDialog = self.progressDialog('Incremental sync') + + + process = { + + 'added': self.addedItems, + 'update': self.updateItems, + 'userdata': self.userdataItems, + 'remove': self.removeItems + } + types = ['added', 'update', 'userdata', 'remove'] + for type in types: + + if process[type] and utils.window('emby_kodiScan') != "true": + + listItems = list(process[type]) + del process[type][:] # Reset class list + + items_process = itemtypes.Items(embycursor, kodicursor) + update = False + + # Prepare items according to process type + if type == "added": + items = emby.sortby_mediatype(listItems) + + elif type in ("userdata", "remove"): + items = emby_db.sortby_mediaType(listItems, unsorted=False) + + else: + items = emby_db.sortby_mediaType(listItems) + if items.get('Unsorted'): + sorted_items = emby.sortby_mediatype(items['Unsorted']) + doupdate = items_process.itemsbyId(sorted_items, "added", pDialog) + if doupdate: + embyupdate, kodiupdate_video = doupdate + if embyupdate: + update_embydb = True + if kodiupdate_video: + self.forceLibraryUpdate = True + del items['Unsorted'] + + doupdate = items_process.itemsbyId(items, type, pDialog) + if doupdate: + embyupdate, kodiupdate_video = doupdate + if embyupdate: + update_embydb = True + if kodiupdate_video: + self.forceLibraryUpdate = True + + if update_embydb: + update_embydb = False + self.logMsg("Updating emby database.", 1) + embyconn.commit() + self.saveLastSync() + + if self.forceLibraryUpdate: + # Force update the Kodi library + self.forceLibraryUpdate = False + self.dbCommit(kodiconn) + + self.logMsg("Updating video library.", 1) + utils.window('emby_kodiScan', value="true") + xbmc.executebuiltin('UpdateLibrary(video)') + + if pDialog: + pDialog.close() + + kodicursor.close() + embycursor.close() + + def compareDBVersion(self, current, minimum): # It returns True is database is up to date. False otherwise. self.logMsg("current: %s minimum: %s" % (current, minimum), 1) diff --git a/resources/lib/read_embyserver.py b/resources/lib/read_embyserver.py index 378f3e02..6e808a7a 100644 --- a/resources/lib/read_embyserver.py +++ b/resources/lib/read_embyserver.py @@ -2,6 +2,8 @@ ################################################################################################# +import xbmc + import utils import downloadutils @@ -15,7 +17,7 @@ class Read_EmbyServer(): def __init__(self): - self.doUtils = downloadutils.DownloadUtils() + self.doUtils = downloadutils.DownloadUtils().downloadUrl self.userId = utils.window('emby_currUser') self.server = utils.window('emby_server%s' % self.userId) @@ -30,7 +32,7 @@ class Read_EmbyServer(): item = {} url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid - result = self.doUtils.downloadUrl(url) + result = self.doUtils(url) if result: item = result @@ -49,7 +51,7 @@ class Read_EmbyServer(): 'Ids': ",".join(itemlist), 'Fields': "Etag" } - result = self.doUtils.downloadUrl(url, parameters=params) + result = self.doUtils(url, parameters=params) if result: items.extend(result['Items']) @@ -76,7 +78,7 @@ class Read_EmbyServer(): "MediaSources" ) } - result = self.doUtils.downloadUrl(url, parameters=params) + result = self.doUtils(url, parameters=params) if result: items.extend(result['Items']) @@ -86,7 +88,7 @@ class Read_EmbyServer(): # Returns ancestors using embyId viewId = None url = "{server}/emby/Items/%s/Ancestors?UserId={UserId}&format=json" % itemid - result = self.doUtils.downloadUrl(url) + result = self.doUtils(url) for view in result: @@ -138,7 +140,7 @@ class Read_EmbyServer(): "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers") } - return doUtils.downloadUrl(url, parameters=params) + return doUtils(url, parameters=params) def getTvChannels(self): doUtils = self.doUtils @@ -152,7 +154,7 @@ class Read_EmbyServer(): "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers") } - return doUtils.downloadUrl(url, parameters=params) + return doUtils(url, parameters=params) def getTvRecordings(self, groupid): doUtils = self.doUtils @@ -168,7 +170,7 @@ class Read_EmbyServer(): "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers") } - return doUtils.downloadUrl(url, parameters=params) + return doUtils(url, parameters=params) def getSection(self, parentid, itemtype=None, sortby="SortName", basic=False, dialog=None): @@ -191,7 +193,7 @@ class Read_EmbyServer(): 'Recursive': True, 'Limit': 1 } - result = doUtils.downloadUrl(url, parameters=params) + result = doUtils(url, parameters=params) try: total = result['TotalRecordCount'] items['TotalRecordCount'] = total @@ -233,14 +235,16 @@ class Read_EmbyServer(): "MediaSources" ) result = doUtils(url, parameters=params) - - if result == "": - # Something happened to the connection. + try: + items['Items'].extend(result['Items']) + except TypeError: + # Something happened to the connection if not throttled: throttled = True self.logMsg("Throttle activated.", 1) - elif jump == highestjump: - # We already adjusted to highestjump, but it failed. Reset value + + if jump == highestjump: + # We already tried with the highestjump, but it failed. Reset value. self.logMsg("Reset highest value.", 1) highestjump = 0 @@ -248,25 +252,24 @@ class Read_EmbyServer(): if highestjump: throttled = False jump = highestjump + self.logMsg("Throttle deactivated.", 1) else: - jump = int(jump/2) + jump = int(jump/4) + self.logMsg("Set jump limit to recover: %s" % jump, 1) - self.logMsg("Set jump limit to recover: %s" % jump) retry = 0 while utils.window('emby_online') != "true": # Wait server to come back online if retry == 3: - self.logMsg("Server never came back online.") + self.logMsg("Unable to reconnect to server. Abort process.", 1) return - + retry += 1 if xbmc.Monitor().waitForAbort(1): # Abort was requested while waiting. return - else: - xbmc.Monitor().waitForAbort(3) else: - items['Items'].extend(result['Items']) + # Request succeeded index += jump if dialog: @@ -278,20 +281,15 @@ class Read_EmbyServer(): highestjump = jump if throttled: - # We needed to adjust the number, keep increasing until. - if jump < highestjump: - # Found a number that already works, use it. - throttled = False - jump = highestjump - self.logMsg("Throttle deactivated with jump limit set to: %s" % jump, 1) - else: - # keep increasing until the connection times out again - increment = int(jump*0.33) - if not increment: # Incase the increment is 0 - increment += 10 + # We needed to adjust the number of item requested. + # keep increasing until the connection times out again + # to find the highest value + increment = int(jump*0.33) + if not increment: # Incase the increment is 0 + increment = 10 - jump += increment - self.logMsg("Increase jump limit to: %s" % jump, 1) + jump += increment + self.logMsg("Increase jump limit to: %s" % jump, 1) return items def getViews(self, type, root=False): @@ -305,7 +303,7 @@ class Read_EmbyServer(): else: # Views ungrouped url = "{server}/emby/Users/{UserId}/Items?Sortby=SortName&format=json" - result = doUtils.downloadUrl(url) + result = doUtils(url) try: items = result['Items'] @@ -330,7 +328,7 @@ class Read_EmbyServer(): # Assumed missing is mixed then. if itemtype is None: url = "{server}/emby/Library/MediaFolders?format=json" - result = doUtils.downloadUrl(url) + result = doUtils(url) for folder in result['Items']: if itemId == folder['Id']: @@ -398,7 +396,7 @@ class Read_EmbyServer(): 'IsVirtualUnaired': False, 'Fields': "Etag" } - result = self.doUtils.downloadUrl(url, parameters=params) + result = self.doUtils(url, parameters=params) if result: items = result @@ -438,7 +436,7 @@ class Read_EmbyServer(): 'Recursive': True, 'Limit': 1 } - result = doUtils.downloadUrl(url, parameters=params) + result = doUtils(url, parameters=params) try: total = result['TotalRecordCount'] items['TotalRecordCount'] = total @@ -468,7 +466,7 @@ class Read_EmbyServer(): "AirTime,DateCreated,MediaStreams,People,ProviderIds,Overview" ) } - result = doUtils.downloadUrl(url, parameters=params) + result = doUtils(url, parameters=params) items['Items'].extend(result['Items']) index += jump @@ -510,7 +508,7 @@ class Read_EmbyServer(): } url = "{server}/emby/Videos/%s/AdditionalParts?UserId={UserId}&format=json" % itemId - result = self.doUtils.downloadUrl(url) + result = self.doUtils(url) if result: items = result