Merge remote-tracking branch 'MediaBrowser/master' into develop

This commit is contained in:
tomkat83 2016-02-10 09:09:36 +01:00
commit 9d50e8ef30
6 changed files with 166 additions and 42 deletions

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.plexkodiconnect" <addon id="plugin.video.plexkodiconnect"
name="PlexKodiConnect" name="PlexKodiConnect"
version="2.0.4" version="2.1.0"
provider-name="croneter"> provider-name="croneter">
<requires> <requires>
<import addon="xbmc.python" version="2.1.0"/> <import addon="xbmc.python" version="2.1.0"/>

View file

@ -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 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 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 - Add control over new content pop up display time. You will find the settings under Extras > Enable new content notification

View file

@ -100,6 +100,14 @@ class Main:
if mode == "settings": if mode == "settings":
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)') xbmc.executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
elif mode in ("manualsync", "repair"): 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": if utils.window('emby_dbScan') != "true":
import librarysync import librarysync
lib = librarysync.LibrarySync() lib = librarysync.LibrarySync()

View file

@ -85,6 +85,7 @@ class Items(object):
'Audio': Music 'Audio': Music
} }
update_videolibrary = False
total = 0 total = 0
for item in items: for item in items:
total += len(items[item]) total += len(items[item])
@ -120,6 +121,7 @@ class Items(object):
# Music is not enabled, do not proceed with itemtype # Music is not enabled, do not proceed with itemtype
continue continue
else: else:
update_videolibrary = True
items_process = itemtypes[itemtype](embycursor, kodicursor) items_process = itemtypes[itemtype](embycursor, kodicursor)
if itemtype == "Movie": if itemtype == "Movie":
@ -214,10 +216,11 @@ class Items(object):
if musicconn is not None: if musicconn is not None:
# close connection for special types # close connection for special types
self.logMsg("Updating music database.", 1)
musicconn.commit() musicconn.commit()
musiccursor.close() musiccursor.close()
return True return (True, update_videolibrary)
def contentPop(self, name, time=5000): def contentPop(self, name, time=5000):
xbmcgui.Dialog().notification( xbmcgui.Dialog().notification(

View file

@ -1016,6 +1016,117 @@ class LibrarySync(threading.Thread):
return True 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): def compareDBVersion(self, current, minimum):
# It returns True is database is up to date. False otherwise. # It returns True is database is up to date. False otherwise.
self.logMsg("current: %s minimum: %s" % (current, minimum), 1) self.logMsg("current: %s minimum: %s" % (current, minimum), 1)

View file

@ -2,6 +2,8 @@
################################################################################################# #################################################################################################
import xbmc
import utils import utils
import downloadutils import downloadutils
@ -15,7 +17,7 @@ class Read_EmbyServer():
def __init__(self): def __init__(self):
self.doUtils = downloadutils.DownloadUtils() self.doUtils = downloadutils.DownloadUtils().downloadUrl
self.userId = utils.window('emby_currUser') self.userId = utils.window('emby_currUser')
self.server = utils.window('emby_server%s' % self.userId) self.server = utils.window('emby_server%s' % self.userId)
@ -30,7 +32,7 @@ class Read_EmbyServer():
item = {} item = {}
url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid
result = self.doUtils.downloadUrl(url) result = self.doUtils(url)
if result: if result:
item = result item = result
@ -49,7 +51,7 @@ class Read_EmbyServer():
'Ids': ",".join(itemlist), 'Ids': ",".join(itemlist),
'Fields': "Etag" 'Fields': "Etag"
} }
result = self.doUtils.downloadUrl(url, parameters=params) result = self.doUtils(url, parameters=params)
if result: if result:
items.extend(result['Items']) items.extend(result['Items'])
@ -76,7 +78,7 @@ class Read_EmbyServer():
"MediaSources" "MediaSources"
) )
} }
result = self.doUtils.downloadUrl(url, parameters=params) result = self.doUtils(url, parameters=params)
if result: if result:
items.extend(result['Items']) items.extend(result['Items'])
@ -86,7 +88,7 @@ class Read_EmbyServer():
# Returns ancestors using embyId # Returns ancestors using embyId
viewId = None viewId = None
url = "{server}/emby/Items/%s/Ancestors?UserId={UserId}&format=json" % itemid url = "{server}/emby/Items/%s/Ancestors?UserId={UserId}&format=json" % itemid
result = self.doUtils.downloadUrl(url) result = self.doUtils(url)
for view in result: for view in result:
@ -138,7 +140,7 @@ class Read_EmbyServer():
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers") "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
} }
return doUtils.downloadUrl(url, parameters=params) return doUtils(url, parameters=params)
def getTvChannels(self): def getTvChannels(self):
doUtils = self.doUtils doUtils = self.doUtils
@ -152,7 +154,7 @@ class Read_EmbyServer():
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers") "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
} }
return doUtils.downloadUrl(url, parameters=params) return doUtils(url, parameters=params)
def getTvRecordings(self, groupid): def getTvRecordings(self, groupid):
doUtils = self.doUtils doUtils = self.doUtils
@ -168,7 +170,7 @@ class Read_EmbyServer():
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers") "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): def getSection(self, parentid, itemtype=None, sortby="SortName", basic=False, dialog=None):
@ -191,7 +193,7 @@ class Read_EmbyServer():
'Recursive': True, 'Recursive': True,
'Limit': 1 'Limit': 1
} }
result = doUtils.downloadUrl(url, parameters=params) result = doUtils(url, parameters=params)
try: try:
total = result['TotalRecordCount'] total = result['TotalRecordCount']
items['TotalRecordCount'] = total items['TotalRecordCount'] = total
@ -233,14 +235,16 @@ class Read_EmbyServer():
"MediaSources" "MediaSources"
) )
result = doUtils(url, parameters=params) result = doUtils(url, parameters=params)
try:
if result == "": items['Items'].extend(result['Items'])
# Something happened to the connection. except TypeError:
# Something happened to the connection
if not throttled: if not throttled:
throttled = True throttled = True
self.logMsg("Throttle activated.", 1) 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) self.logMsg("Reset highest value.", 1)
highestjump = 0 highestjump = 0
@ -248,15 +252,16 @@ class Read_EmbyServer():
if highestjump: if highestjump:
throttled = False throttled = False
jump = highestjump jump = highestjump
self.logMsg("Throttle deactivated.", 1)
else: 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 retry = 0
while utils.window('emby_online') != "true": while utils.window('emby_online') != "true":
# Wait server to come back online # Wait server to come back online
if retry == 3: if retry == 3:
self.logMsg("Server never came back online.") self.logMsg("Unable to reconnect to server. Abort process.", 1)
return return
retry += 1 retry += 1
@ -264,9 +269,7 @@ class Read_EmbyServer():
# Abort was requested while waiting. # Abort was requested while waiting.
return return
else: else:
xbmc.Monitor().waitForAbort(3) # Request succeeded
else:
items['Items'].extend(result['Items'])
index += jump index += jump
if dialog: if dialog:
@ -278,17 +281,12 @@ class Read_EmbyServer():
highestjump = jump highestjump = jump
if throttled: if throttled:
# We needed to adjust the number, keep increasing until. # We needed to adjust the number of item requested.
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 # keep increasing until the connection times out again
# to find the highest value
increment = int(jump*0.33) increment = int(jump*0.33)
if not increment: # Incase the increment is 0 if not increment: # Incase the increment is 0
increment += 10 increment = 10
jump += increment jump += increment
self.logMsg("Increase jump limit to: %s" % jump, 1) self.logMsg("Increase jump limit to: %s" % jump, 1)
@ -305,7 +303,7 @@ class Read_EmbyServer():
else: # Views ungrouped else: # Views ungrouped
url = "{server}/emby/Users/{UserId}/Items?Sortby=SortName&format=json" url = "{server}/emby/Users/{UserId}/Items?Sortby=SortName&format=json"
result = doUtils.downloadUrl(url) result = doUtils(url)
try: try:
items = result['Items'] items = result['Items']
@ -330,7 +328,7 @@ class Read_EmbyServer():
# Assumed missing is mixed then. # Assumed missing is mixed then.
if itemtype is None: if itemtype is None:
url = "{server}/emby/Library/MediaFolders?format=json" url = "{server}/emby/Library/MediaFolders?format=json"
result = doUtils.downloadUrl(url) result = doUtils(url)
for folder in result['Items']: for folder in result['Items']:
if itemId == folder['Id']: if itemId == folder['Id']:
@ -398,7 +396,7 @@ class Read_EmbyServer():
'IsVirtualUnaired': False, 'IsVirtualUnaired': False,
'Fields': "Etag" 'Fields': "Etag"
} }
result = self.doUtils.downloadUrl(url, parameters=params) result = self.doUtils(url, parameters=params)
if result: if result:
items = result items = result
@ -438,7 +436,7 @@ class Read_EmbyServer():
'Recursive': True, 'Recursive': True,
'Limit': 1 'Limit': 1
} }
result = doUtils.downloadUrl(url, parameters=params) result = doUtils(url, parameters=params)
try: try:
total = result['TotalRecordCount'] total = result['TotalRecordCount']
items['TotalRecordCount'] = total items['TotalRecordCount'] = total
@ -468,7 +466,7 @@ class Read_EmbyServer():
"AirTime,DateCreated,MediaStreams,People,ProviderIds,Overview" "AirTime,DateCreated,MediaStreams,People,ProviderIds,Overview"
) )
} }
result = doUtils.downloadUrl(url, parameters=params) result = doUtils(url, parameters=params)
items['Items'].extend(result['Items']) items['Items'].extend(result['Items'])
index += jump index += jump
@ -510,7 +508,7 @@ class Read_EmbyServer():
} }
url = "{server}/emby/Videos/%s/AdditionalParts?UserId={UserId}&format=json" % itemId url = "{server}/emby/Videos/%s/AdditionalParts?UserId={UserId}&format=json" % itemId
result = self.doUtils.downloadUrl(url) result = self.doUtils(url)
if result: if result:
items = result items = result