Merge branch 'develop'

This commit is contained in:
tomkat83 2016-03-10 10:47:41 +01:00
commit 3d4e51e587
10 changed files with 199 additions and 47 deletions

View file

@ -7,13 +7,13 @@
**Installation in Kodi** **Installation in Kodi**
1. You might want to uninstall everything else Plex related first, e.g. PlexBMC and PlexBMC Helper. Starting with a fresh Kodi install might be a good idea. Be sure to use a "normal", unmodded Skin in Kodi. 1. You might want to uninstall everything else Plex related first, e.g. PlexBMC and PlexBMC Helper. Starting with a fresh Kodi install might be a good idea. Be sure to use a "normal", unmodded Skin in Kodi.
If you're updating, you might also want to do a complete reset of the plugin: Settings -> Advanced -> "Performe full DB reset". Choose "Yes" for everything. If you're updating, you might also want to do a complete reset of the plugin: Settings -> Advanced -> "Perform full DB reset". Choose "Yes" for all questions.
2. Simply fire up Kodi and Install from ZIP from here on. 2. Simply fire up Kodi and Install from ZIP from here on.
3. Install the 2 needed dependencies first (be sure to NOT download the sources but the additional release files): https://github.com/croneter/plugin.video.plexkodiconnect.tvshows/releases/tag/1.0.0 and https://github.com/croneter/plugin.video.plexkodiconnect.movies/releases/tag/1.0.0 3. Install the 2 needed dependencies first (be sure to NOT download the sources but the additional release files): https://github.com/croneter/plugin.video.plexkodiconnect.tvshows/releases/ and https://github.com/croneter/plugin.video.plexkodiconnect.movies/releases/
5. Then install PlexKodiConnect, again the additional release file from here: https://github.com/croneter/PlexKodiConnect/releases/ 5. Then install PlexKodiConnect, again the additional release file from here: https://github.com/croneter/PlexKodiConnect/releases/
6. Within a few seconds you should be prompted to log into plex.tv. This is mandatory for Plex Home, otherwise you can skip. If nothing happens, try to restart Kodi 6. Within a few seconds you should be prompted to log into plex.tv. This is mandatory for Plex Home, otherwise you can skip. If nothing happens, try to restart Kodi
7. Once you're succesfully authenticated to your Plex server, the initial sync will start. 7. Once you're succesfully authenticated to your Plex server, the initial sync will start.
8. The first sync of the Plex server to local Kodi database may take a LONG time. With my setup (~400 movies, ~600 episodes, couple of Test music albums and a very powerful NAS), sync take approximately 5 minutes. 8. The first sync of the Plex server to local Kodi database may take a LONG time. With my setup (~400 movies, ~600 episodes, couple of Test music albums and a very powerful NAS), sync takes approximately 5 minutes.
9. Once the full sync is done, you can browse your media in Kodi, syncs will be automatically done in the background. 9. Once the full sync is done, you can browse your media in Kodi, syncs will be automatically done in the background.
10. Restart! 10. Restart!
@ -62,6 +62,8 @@ Guess what, this is BETA. Currently these features are working:
- Pictures - Pictures
- Watch Later - Watch Later
- Music Videos - Music Videos
- Playlists
- Play directly from SMB paths ("\\\\server\\Plex\\movie.mkv" on Windows) instead of HTTP ("192.168.1.1:32400")
- TV Shows Theme Music (ultra-low prio) - TV Shows Theme Music (ultra-low prio)

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="1.0.5" version="1.0.6"
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,10 @@
version 1.0.6
- Enable traceback and dump XMLs of failed PMS items in the log for lib sync
- Optimize notifications for library syncs
- Manually trigger full library scan from settings
- Merge with MediaBrowser/master up until db4cb448b0e4fd82662f8b82a800d8da8ea33688
version 1.0.5 version 1.0.5
- Catch exceptions in itemtypes and log them - Catch exceptions in itemtypes and log them
- Slightly increased download timeouts - Slightly increased download timeouts

View file

@ -51,6 +51,7 @@ if __name__ == '__main__':
embycursor = embyconn.cursor() embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
item = emby_db.getItem_byKodiId(itemid, itemtype) item = emby_db.getItem_byKodiId(itemid, itemtype)
embycursor.close()
if item: embyid = item[0] if item: embyid = item[0]
logMsg("Contextmenu opened for embyid: %s - itemtype: %s" %(embyid,itemtype)) logMsg("Contextmenu opened for embyid: %s - itemtype: %s" %(embyid,itemtype))

View file

@ -8,6 +8,7 @@ import urlparse
import xbmc import xbmc
import xbmcaddon import xbmcaddon
import xbmcgui
################################################################################################# #################################################################################################
@ -66,7 +67,8 @@ class Main:
'companion': entrypoint.plexCompanion, 'companion': entrypoint.plexCompanion,
'switchuser': entrypoint.switchPlexUser, 'switchuser': entrypoint.switchPlexUser,
'deviceid': entrypoint.resetDeviceId, 'deviceid': entrypoint.resetDeviceId,
'reConnect': entrypoint.reConnect 'reConnect': entrypoint.reConnect,
'delete': entrypoint.deleteItem
} }
if "/extrafanart" in sys.argv[0]: if "/extrafanart" in sys.argv[0]:
@ -108,7 +110,18 @@ 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"):
entrypoint.RunLibScan(mode) if utils.window('emby_online') != "true":
# Server is not online, do not run the sync
xbmcgui.Dialog().ok(heading="PlexKodiConnect",
line1=("Unable to run the sync, the add-on is not "
"connected to the Emby server."))
utils.logMsg("PLEX", "Not connected to the emby server.", 1)
return
else:
utils.logMsg("PLEX", "Requesting full library scan", 1)
utils.window('plex_runLibScan', value="full")
elif mode == "texturecache": elif mode == "texturecache":
import artwork import artwork
artwork.Artwork().FullTextureCacheSync() artwork.Artwork().FullTextureCacheSync()

View file

@ -405,5 +405,7 @@
<string id="39404">Startup syncing process failed repeatedly. Try restarting Kodi. Stopping Sync for now.</string> <string id="39404">Startup syncing process failed repeatedly. Try restarting Kodi. Stopping Sync for now.</string>
<string id="39405">Plex playlists/nodes refreshed</string> <string id="39405">Plex playlists/nodes refreshed</string>
<string id="39406">Plex playlists/nodes refresh failed</string> <string id="39406">Plex playlists/nodes refresh failed</string>
<string id="39407">Full library sync finished</string>
<string id="39408">Sync had to skip some items because they could not be processed. Please post your Kodi logs to the Plex forum.</string>
</strings> </strings>

View file

@ -337,5 +337,7 @@
<string id="39404">Der Startup Synchronisations-Prozess der Plex Bibliotheken ist mehrmals fehlgeschlagen. Bitte Kodi neu starten. Synch wird jetzt gestoppt.</string> <string id="39404">Der Startup Synchronisations-Prozess der Plex Bibliotheken ist mehrmals fehlgeschlagen. Bitte Kodi neu starten. Synch wird jetzt gestoppt.</string>
<string id="39405">Plex Playlisten/Nodes aktualisiert</string> <string id="39405">Plex Playlisten/Nodes aktualisiert</string>
<string id="39406">Plex Playlisten/Nodes Aktualisierung fehlgeschlagen</string> <string id="39406">Plex Playlisten/Nodes Aktualisierung fehlgeschlagen</string>
<string id="39407">Plex Bibliotheken aktualisiert</string>
<string id="39408">Einige Plex Einträge mussten übersprungen werden, da sie nicht verarbeitet werden konnten. Bitte teilen Sie Ihr Kodi log im Plex Forum.</string>
</strings> </strings>

View file

@ -285,6 +285,56 @@ def resetDeviceId():
line1=language(33033)) line1=language(33033))
xbmc.executebuiltin('RestartApp') xbmc.executebuiltin('RestartApp')
##### Delete Item
def deleteItem():
# Serves as a keymap action
if xbmc.getInfoLabel('ListItem.Property(embyid)'): # If we already have the embyid
embyid = xbmc.getInfoLabel('ListItem.Property(embyid)')
else:
dbid = xbmc.getInfoLabel('ListItem.DBID')
itemtype = xbmc.getInfoLabel('ListItem.DBTYPE')
if not itemtype:
if xbmc.getCondVisibility('Container.Content(albums)'):
itemtype = "album"
elif xbmc.getCondVisibility('Container.Content(artists)'):
itemtype = "artist"
elif xbmc.getCondVisibility('Container.Content(songs)'):
itemtype = "song"
elif xbmc.getCondVisibility('Container.Content(pictures)'):
itemtype = "picture"
else:
utils.logMsg("EMBY delete", "Unknown type, unable to proceed.", 1)
return
embyconn = utils.kodiSQL('emby')
embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor)
item = emby_db.getItem_byKodiId(dbid, itemtype)
embycursor.close()
try:
embyid = item[0]
except TypeError:
utils.logMsg("EMBY delete", "Unknown embyId, unable to proceed.", 1)
return
if utils.settings('skipContextMenu') != "true":
resp = xbmcgui.Dialog().yesno(
heading="Confirm delete",
line1=("Delete file from Emby Server? This will "
"also delete the file(s) from disk!"))
if not resp:
utils.logMsg("EMBY delete", "User skipped deletion for: %s." % embyid, 1)
return
doUtils = downloadutils.DownloadUtils()
url = "{server}/emby/Items/%s?format=json" % embyid
utils.logMsg("EMBY delete", "Deleting request: %s" % embyid, 0)
doUtils.downloadUrl(url, type="DELETE")
##### ADD ADDITIONAL USERS ##### ##### ADD ADDITIONAL USERS #####
def addUser(): def addUser():

View file

@ -287,10 +287,18 @@ class Movies(Items):
try: try:
self.run_add_update(item, viewtag, viewid) self.run_add_update(item, viewtag, viewid)
except Exception as e: except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for movies has crashed for item %s. ' self.logMsg('itemtypes.py for movies has crashed for item %s. '
'Error:' % item.attrib.get('ratingKey', None), -1) 'Error:' % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1) self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now # skip this item for now
return return
@ -920,10 +928,18 @@ class TVShows(Items):
try: try:
self.run_add_update(item, viewtag, viewid) self.run_add_update(item, viewtag, viewid)
except Exception as e: except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for tv show has crashed for item %s. ' self.logMsg('itemtypes.py for tv show has crashed for item %s. '
'Error:' % item.attrib.get('ratingKey', None), -1) 'Error:' % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1) self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now # skip this item for now
return return
@ -1117,10 +1133,18 @@ class TVShows(Items):
try: try:
self.run_add_updateSeason(item, viewtag, viewid) self.run_add_updateSeason(item, viewtag, viewid)
except Exception as e: except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for tv seasons has crashed for item %s. ' self.logMsg('itemtypes.py for tv seasons has crashed for item %s. '
'Error:' % item.attrib.get('ratingKey', None), -1) 'Error:' % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1) self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now # skip this item for now
return return
@ -1162,10 +1186,18 @@ class TVShows(Items):
try: try:
self.run_add_updateEpisode(item, viewtag, viewid) self.run_add_updateEpisode(item, viewtag, viewid)
except Exception as e: except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for tv episode has crashed for item %s. ' self.logMsg('itemtypes.py for tv episode has crashed for item %s. '
'Error:' % item.attrib.get('ratingKey', None), -1) 'Error:' % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1) self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now # skip this item for now
return return
@ -1642,11 +1674,19 @@ class Music(Items):
try: try:
self.run_add_updateArtist(item, viewtag, viewid, artisttype) self.run_add_updateArtist(item, viewtag, viewid, artisttype)
except Exception as e: except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for music artist has crashed for ' self.logMsg('itemtypes.py for music artist has crashed for '
'item %s. Error:' 'item %s. Error:'
% item.attrib.get('ratingKey', None), -1) % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1) self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now # skip this item for now
return return
@ -1738,11 +1778,19 @@ class Music(Items):
try: try:
self.run_add_updateAlbum(item, viewtag, viewid) self.run_add_updateAlbum(item, viewtag, viewid)
except Exception as e: except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for music album has crashed for ' self.logMsg('itemtypes.py for music album has crashed for '
'item %s. Error:' 'item %s. Error:'
% item.attrib.get('ratingKey', None), -1) % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1) self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now # skip this item for now
return return
@ -1936,11 +1984,19 @@ class Music(Items):
try: try:
self.run_add_updateSong(item, viewtag, viewid) self.run_add_updateSong(item, viewtag, viewid)
except Exception as e: except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for music song has crashed for ' self.logMsg('itemtypes.py for music song has crashed for '
'item %s. Error:' 'item %s. Error:'
% item.attrib.get('ratingKey', None), -1) % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1) self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now # skip this item for now
return return

View file

@ -70,7 +70,7 @@ class ThreadedGetMetadata(Thread):
# Did not receive a valid XML - skip that item for now # Did not receive a valid XML - skip that item for now
self.logMsg("Could not get metadata for %s. " self.logMsg("Could not get metadata for %s. "
"Skipping that item for now" "Skipping that item for now"
% updateItem['itemId'], -1) % updateItem['itemId'], 0)
# Increase BOTH counters - since metadata won't be processed # Increase BOTH counters - since metadata won't be processed
with lock: with lock:
getMetadataCount += 1 getMetadataCount += 1
@ -223,8 +223,8 @@ class LibrarySync(Thread):
self.user = userclient.UserClient() self.user = userclient.UserClient()
self.emby = embyserver.Read_EmbyServer() self.emby = embyserver.Read_EmbyServer()
self.vnodes = videonodes.VideoNodes() self.vnodes = videonodes.VideoNodes()
self.syncThreadNumber = int(utils.settings('syncThreadNumber'))
self.syncThreadNumber = int(utils.settings('syncThreadNumber'))
self.installSyncDone = True if \ self.installSyncDone = True if \
utils.settings('SyncInstallRunDone') == 'true' else False utils.settings('SyncInstallRunDone') == 'true' else False
self.showDbSync = True if \ self.showDbSync = True if \
@ -236,18 +236,30 @@ class LibrarySync(Thread):
Thread.__init__(self) Thread.__init__(self)
def showKodiNote(self, message, forced=False): def showKodiNote(self, message, forced=False, icon="plex"):
""" """
Shows a Kodi popup, if user selected to do so. Pass message in unicode Shows a Kodi popup, if user selected to do so. Pass message in unicode
or string or string
icon: "plex": shows Plex icon
"error": shows Kodi error icon
""" """
if not (self.showDbSync or forced): if not (self.showDbSync or forced):
return return
if icon == "plex":
xbmcgui.Dialog().notification( xbmcgui.Dialog().notification(
heading=self.addonName, heading=self.addonName,
message=message, message=message,
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
time=5000,
sound=False) sound=False)
elif icon == "error":
xbmcgui.Dialog().notification(
heading=self.addonName,
message=message,
icon=xbmcgui.NOTIFICATION_ERROR,
time=7000,
sound=True)
def fastSync(self): def fastSync(self):
""" """
@ -307,7 +319,8 @@ class LibrarySync(Thread):
elif self.updatelist[0]['itemType'] == 'Music': elif self.updatelist[0]['itemType'] == 'Music':
self.updateKodiMusicLib = True self.updateKodiMusicLib = True
self.GetAndProcessXMLs( self.GetAndProcessXMLs(
PlexFunctions.GetItemClassFromType(plexType)) PlexFunctions.GetItemClassFromType(plexType),
showProgress=False)
self.updatelist = [] self.updatelist = []
# Update userdata # Update userdata
@ -327,6 +340,10 @@ class LibrarySync(Thread):
# Reset and return # Reset and return
self.allPlexElementsId = {} self.allPlexElementsId = {}
# Show warning if itemtypes.py crashed at some point
if utils.window('plex_scancrashed') == 'true':
xbmcgui.Dialog().ok(self.addonName, self.__language__(39408))
utils.window('plex_scancrashed', clear=True)
return True return True
def saveLastSync(self): def saveLastSync(self):
@ -400,6 +417,10 @@ class LibrarySync(Thread):
utils.window('emby_initialScan', clear=True) utils.window('emby_initialScan', clear=True)
xbmc.executebuiltin('InhibitIdleShutdown(false)') xbmc.executebuiltin('InhibitIdleShutdown(false)')
utils.setScreensaver(value=screensaver) utils.setScreensaver(value=screensaver)
# Show warning if itemtypes.py crashed at some point
if utils.window('plex_scancrashed') == 'true':
xbmcgui.Dialog().ok(self.addonName, self.__language__(39408))
utils.window('plex_scancrashed', clear=True)
return True return True
def processView(self, folderItem, kodi_db, emby_db, totalnodes): def processView(self, folderItem, kodi_db, emby_db, totalnodes):
@ -698,7 +719,7 @@ class LibrarySync(Thread):
'viewId': viewId, 'viewId': viewId,
'title': title}) 'title': title})
def GetAndProcessXMLs(self, itemType): def GetAndProcessXMLs(self, itemType, showProgress=True):
""" """
Downloads all XMLs for itemType (e.g. Movies, TV-Shows). Processes them Downloads all XMLs for itemType (e.g. Movies, TV-Shows). Processes them
by then calling itemtypes.<itemType>() by then calling itemtypes.<itemType>()
@ -706,6 +727,7 @@ class LibrarySync(Thread):
Input: Input:
itemType: 'Movies', 'TVShows', ... itemType: 'Movies', 'TVShows', ...
self.updatelist self.updatelist
showProgress If False, NEVER shows sync progress
""" """
# Some logging, just in case. # Some logging, just in case.
self.logMsg("self.updatelist: %s" % self.updatelist, 2) self.logMsg("self.updatelist: %s" % self.updatelist, 2)
@ -750,6 +772,7 @@ class LibrarySync(Thread):
threads.append(thread) threads.append(thread)
self.logMsg("Processing thread spawned", 1) self.logMsg("Processing thread spawned", 1)
# Start one thread to show sync progress # Start one thread to show sync progress
if showProgress:
if self.showDbSync: if self.showDbSync:
dialog = xbmcgui.DialogProgressBG() dialog = xbmcgui.DialogProgressBG()
thread = ThreadedShowSyncInfo( thread = ThreadedShowSyncInfo(
@ -1229,6 +1252,8 @@ class LibrarySync(Thread):
fullSync(manualrun=True) fullSync(manualrun=True)
window('emby_dbScan', clear=True) window('emby_dbScan', clear=True)
count = 0 count = 0
# Full library sync finished
self.showKodiNote(string(39407), forced=True)
# Reset views was requested from somewhere else # Reset views was requested from somewhere else
elif window('plex_runLibScan') == "views": elif window('plex_runLibScan') == "views":
log('Refresh playlist and nodes requested, starting', 0) log('Refresh playlist and nodes requested, starting', 0)
@ -1244,22 +1269,14 @@ class LibrarySync(Thread):
# Ran successfully # Ran successfully
log("Refresh playlists/nodes completed", 0) log("Refresh playlists/nodes completed", 0)
# "Plex playlists/nodes refreshed" # "Plex playlists/nodes refreshed"
dialog.notification( self.showKodiNote(string(39405), forced=True)
heading=self.addonName,
message=string(39405),
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
time=3000,
sound=True)
else: else:
# Failed # Failed
log("Refresh playlists/nodes failed", -1) log("Refresh playlists/nodes failed", -1)
# "Plex playlists/nodes refresh failed" # "Plex playlists/nodes refresh failed"
dialog.notification( self.showKodiNote(string(39406),
heading=self.addonName, forced=True,
message=string(39406), icon="error")
icon=xbmcgui.NOTIFICATION_ERROR,
time=3000,
sound=True)
window('emby_dbScan', clear=True) window('emby_dbScan', clear=True)
elif enableBackgroundSync: elif enableBackgroundSync:
# Run full lib scan approx every 30min # Run full lib scan approx every 30min
@ -1269,6 +1286,8 @@ class LibrarySync(Thread):
log('Running background full lib scan', 0) log('Running background full lib scan', 0)
fullSync(manualrun=True) fullSync(manualrun=True)
window('emby_dbScan', clear=True) window('emby_dbScan', clear=True)
# Full library sync finished
self.showKodiNote(string(39407), forced=False)
# Run fast sync otherwise (ever second or so) # Run fast sync otherwise (ever second or so)
else: else:
window('emby_dbScan', value="true") window('emby_dbScan', value="true")