Merge remote-tracking branch 'MediaBrowser/master' into develop
This commit is contained in:
commit
c98e7ad60c
7 changed files with 526 additions and 170 deletions
|
@ -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.1.79"
|
version="1.1.80"
|
||||||
provider-name="croneter">
|
provider-name="croneter">
|
||||||
<requires>
|
<requires>
|
||||||
<import addon="xbmc.python" version="2.1.0"/>
|
<import addon="xbmc.python" version="2.1.0"/>
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
version 1.1.80
|
||||||
|
- Add refresh for video nodes
|
||||||
|
- Fix for home videos (being unable to back out of the menu). Running refresh playlists/nodes will fix this.
|
||||||
|
- Fix to music, causing sync to crash
|
||||||
|
|
||||||
version 1.1.76
|
version 1.1.76
|
||||||
- Add music rating system
|
- Add music rating system
|
||||||
- Add home videos as a dynamic plugin entry (requires a reset)
|
- Add home videos as a dynamic plugin entry (requires a reset)
|
||||||
|
|
|
@ -106,7 +106,7 @@ class Main:
|
||||||
import librarysync
|
import librarysync
|
||||||
lib = librarysync.LibrarySync()
|
lib = librarysync.LibrarySync()
|
||||||
if mode == "manualsync":
|
if mode == "manualsync":
|
||||||
lib.fullSync(manualrun=True)
|
librarysync.ManualSync()
|
||||||
else:
|
else:
|
||||||
lib.fullSync(repair=True)
|
lib.fullSync(repair=True)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -112,15 +112,15 @@ def doMainListing():
|
||||||
addDirectoryItem("Live Tv Recordings (experimental)", "plugin://plugin.video.plexkodiconnect/?mode=browsecontent&type=recordings&folderid=root")
|
addDirectoryItem("Live Tv Recordings (experimental)", "plugin://plugin.video.plexkodiconnect/?mode=browsecontent&type=recordings&folderid=root")
|
||||||
|
|
||||||
# some extra entries for settings and stuff. TODO --> localize the labels
|
# some extra entries for settings and stuff. TODO --> localize the labels
|
||||||
addDirectoryItem("Network credentials", "plugin://plugin.video.plexkodiconnect/?mode=passwords")
|
addDirectoryItem("Network credentials", "plugin://plugin.video.emby/?mode=passwords")
|
||||||
addDirectoryItem("Settings", "plugin://plugin.video.plexkodiconnect/?mode=settings")
|
addDirectoryItem("Settings", "plugin://plugin.video.emby/?mode=settings")
|
||||||
addDirectoryItem("Add user to session", "plugin://plugin.video.plexkodiconnect/?mode=adduser")
|
addDirectoryItem("Add user to session", "plugin://plugin.video.emby/?mode=adduser")
|
||||||
addDirectoryItem("Refresh Emby playlists", "plugin://plugin.video.plexkodiconnect/?mode=refreshplaylist")
|
addDirectoryItem("Refresh Emby playlists/nodes", "plugin://plugin.video.emby/?mode=refreshplaylist")
|
||||||
addDirectoryItem("Perform manual sync", "plugin://plugin.video.plexkodiconnect/?mode=manualsync")
|
addDirectoryItem("Perform manual sync", "plugin://plugin.video.emby/?mode=manualsync")
|
||||||
addDirectoryItem("Repair local database (force update all content)", "plugin://plugin.video.plexkodiconnect/?mode=repair")
|
addDirectoryItem("Repair local database (force update all content)", "plugin://plugin.video.emby/?mode=repair")
|
||||||
addDirectoryItem("Perform local database reset (full resync)", "plugin://plugin.video.plexkodiconnect/?mode=reset")
|
addDirectoryItem("Perform local database reset (full resync)", "plugin://plugin.video.emby/?mode=reset")
|
||||||
addDirectoryItem("Cache all images to Kodi texture cache", "plugin://plugin.video.plexkodiconnect/?mode=texturecache")
|
addDirectoryItem("Cache all images to Kodi texture cache", "plugin://plugin.video.emby/?mode=texturecache")
|
||||||
addDirectoryItem("Sync Emby Theme Media to Kodi", "plugin://plugin.video.plexkodiconnect/?mode=thememedia")
|
addDirectoryItem("Sync Emby Theme Media to Kodi", "plugin://plugin.video.emby/?mode=thememedia")
|
||||||
|
|
||||||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||||
|
|
||||||
|
@ -412,19 +412,22 @@ def refreshPlaylist():
|
||||||
try:
|
try:
|
||||||
# First remove playlists
|
# First remove playlists
|
||||||
utils.deletePlaylists()
|
utils.deletePlaylists()
|
||||||
|
# Remove video nodes
|
||||||
|
utils.deleteNodes()
|
||||||
# Refresh views
|
# Refresh views
|
||||||
lib.refreshViews()
|
lib.refreshViews()
|
||||||
dialog.notification(
|
dialog.notification(
|
||||||
heading="Emby for Kodi",
|
heading="Emby for Kodi",
|
||||||
message="Emby playlist refreshed",
|
message="Emby playlists/nodes refreshed",
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
||||||
time=1000,
|
time=1000,
|
||||||
sound=False)
|
sound=False)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
utils.logMsg("EMBY", "Refresh playlist failed: %s" % e, 1)
|
utils.logMsg("EMBY", "Refresh playlists/nodes failed: %s" % e, 1)
|
||||||
dialog.notification(
|
dialog.notification(
|
||||||
heading="Emby for Kodi",
|
heading="Emby for Kodi",
|
||||||
message="Emby playlist refresh failed",
|
message="Emby playlists/nodes refresh failed",
|
||||||
icon=xbmcgui.NOTIFICATION_ERROR,
|
icon=xbmcgui.NOTIFICATION_ERROR,
|
||||||
time=1000,
|
time=1000,
|
||||||
sound=False)
|
sound=False)
|
||||||
|
|
|
@ -1833,6 +1833,7 @@ class Music(Items):
|
||||||
track = disc*2**16 + tracknumber
|
track = disc*2**16 + tracknumber
|
||||||
year = item.get('ProductionYear')
|
year = item.get('ProductionYear')
|
||||||
duration = API.getRuntime()
|
duration = API.getRuntime()
|
||||||
|
rating = userdata['UserRating']
|
||||||
|
|
||||||
#if enabled, try to get the rating from file and/or emby
|
#if enabled, try to get the rating from file and/or emby
|
||||||
if not self.directstream:
|
if not self.directstream:
|
||||||
|
@ -1840,7 +1841,6 @@ class Music(Items):
|
||||||
else:
|
else:
|
||||||
hasEmbeddedCover = False
|
hasEmbeddedCover = False
|
||||||
comment = API.getOverview()
|
comment = API.getOverview()
|
||||||
rating = userdata['UserRating']
|
|
||||||
|
|
||||||
|
|
||||||
##### GET THE FILE AND PATH #####
|
##### GET THE FILE AND PATH #####
|
||||||
|
|
|
@ -403,9 +403,9 @@ class LibrarySync(threading.Thread):
|
||||||
# musicconn = utils.kodiSQL('music')
|
# musicconn = utils.kodiSQL('music')
|
||||||
# musiccursor = musicconn.cursor()
|
# musiccursor = musicconn.cursor()
|
||||||
|
|
||||||
# startTime = datetime.now()
|
# startTime = datetime.now()
|
||||||
# completed = self.music(embycursor, musiccursor, pDialog, compare=manualrun)
|
# completed = self.music(embycursor, musiccursor, pDialog)
|
||||||
# if not completed:
|
# if not completed:
|
||||||
|
|
||||||
# utils.window('emby_dbScan', clear=True)
|
# utils.window('emby_dbScan', clear=True)
|
||||||
|
|
||||||
|
@ -428,6 +428,7 @@ class LibrarySync(threading.Thread):
|
||||||
elapsedtotal = datetime.now() - starttotal
|
elapsedtotal = datetime.now() - starttotal
|
||||||
|
|
||||||
utils.window('emby_dbScan', clear=True)
|
utils.window('emby_dbScan', clear=True)
|
||||||
|
utils.window('emby_initialScan', clear=True)
|
||||||
xbmcgui.Dialog().notification(
|
xbmcgui.Dialog().notification(
|
||||||
heading=self.addonName,
|
heading=self.addonName,
|
||||||
message="%s completed in: %s" %
|
message="%s completed in: %s" %
|
||||||
|
@ -778,7 +779,6 @@ class LibrarySync(threading.Thread):
|
||||||
"""
|
"""
|
||||||
Updates ALL plex elements' view status ('watched' or 'unwatched') and
|
Updates ALL plex elements' view status ('watched' or 'unwatched') and
|
||||||
also updates resume times.
|
also updates resume times.
|
||||||
|
|
||||||
This is done by downloading one XML for ALL elements with viewId
|
This is done by downloading one XML for ALL elements with viewId
|
||||||
"""
|
"""
|
||||||
starttotal = datetime.now()
|
starttotal = datetime.now()
|
||||||
|
@ -795,7 +795,7 @@ class LibrarySync(threading.Thread):
|
||||||
self.logMsg("Syncing userdata for itemtype %s and viewid %s took "
|
self.logMsg("Syncing userdata for itemtype %s and viewid %s took "
|
||||||
"%s seconds" % (itemType, viewId, elapsedtotal), 0)
|
"%s seconds" % (itemType, viewId, elapsedtotal), 0)
|
||||||
|
|
||||||
def musicvideos(self, embycursor, kodicursor, pdialog, compare=False):
|
def musicvideos(self, embycursor, kodicursor, pdialog):
|
||||||
# Get musicvideos from emby
|
# Get musicvideos from emby
|
||||||
emby = self.emby
|
emby = self.emby
|
||||||
emby_db = embydb.Embydb_Functions(embycursor)
|
emby_db = embydb.Embydb_Functions(embycursor)
|
||||||
|
@ -804,16 +804,6 @@ class LibrarySync(threading.Thread):
|
||||||
views = emby_db.getView_byType('musicvideos')
|
views = emby_db.getView_byType('musicvideos')
|
||||||
self.logMsg("Media folders: %s" % views, 1)
|
self.logMsg("Media folders: %s" % views, 1)
|
||||||
|
|
||||||
if compare:
|
|
||||||
# Pull the list of musicvideos in Kodi
|
|
||||||
try:
|
|
||||||
all_kodimvideos = dict(emby_db.getChecksum('MusicVideo'))
|
|
||||||
except ValueError:
|
|
||||||
all_kodimvideos = {}
|
|
||||||
|
|
||||||
all_embymvideosIds = set()
|
|
||||||
updatelist = []
|
|
||||||
|
|
||||||
for view in views:
|
for view in views:
|
||||||
|
|
||||||
if self.shouldStop():
|
if self.shouldStop():
|
||||||
|
@ -828,38 +818,10 @@ class LibrarySync(threading.Thread):
|
||||||
heading="Emby for Kodi",
|
heading="Emby for Kodi",
|
||||||
message="Gathering musicvideos from view: %s..." % viewName)
|
message="Gathering musicvideos from view: %s..." % viewName)
|
||||||
|
|
||||||
if compare:
|
# Initial or repair sync
|
||||||
# Manual sync
|
all_embymvideos = emby.getMusicVideos(viewId, dialog=pdialog)
|
||||||
if pdialog:
|
total = all_embymvideos['TotalRecordCount']
|
||||||
pdialog.update(
|
embymvideos = all_embymvideos['Items']
|
||||||
heading="Emby for Kodi",
|
|
||||||
message="Comparing musicvideos from view: %s..." % viewName)
|
|
||||||
|
|
||||||
all_embymvideos = emby.getMusicVideos(viewId, basic=True, dialog=pdialog)
|
|
||||||
for embymvideo in all_embymvideos['Items']:
|
|
||||||
|
|
||||||
if self.shouldStop():
|
|
||||||
return False
|
|
||||||
|
|
||||||
API = api.API(embymvideo)
|
|
||||||
itemid = embymvideo['Id']
|
|
||||||
all_embymvideosIds.add(itemid)
|
|
||||||
|
|
||||||
|
|
||||||
if all_kodimvideos.get(itemid) != API.getChecksum():
|
|
||||||
# Only update if musicvideo is not in Kodi or checksum is different
|
|
||||||
updatelist.append(itemid)
|
|
||||||
|
|
||||||
self.logMsg("MusicVideos to update for %s: %s" % (viewName, updatelist), 1)
|
|
||||||
embymvideos = emby.getFullItems(updatelist)
|
|
||||||
total = len(updatelist)
|
|
||||||
del updatelist[:]
|
|
||||||
else:
|
|
||||||
# Initial or repair sync
|
|
||||||
all_embymvideos = emby.getMusicVideos(viewId, dialog=pdialog)
|
|
||||||
total = all_embymvideos['TotalRecordCount']
|
|
||||||
embymvideos = all_embymvideos['Items']
|
|
||||||
|
|
||||||
|
|
||||||
if pdialog:
|
if pdialog:
|
||||||
pdialog.update(heading="Processing %s / %s items" % (viewName, total))
|
pdialog.update(heading="Processing %s / %s items" % (viewName, total))
|
||||||
|
@ -878,15 +840,6 @@ class LibrarySync(threading.Thread):
|
||||||
mvideos.add_update(embymvideo, viewName, viewId)
|
mvideos.add_update(embymvideo, viewName, viewId)
|
||||||
else:
|
else:
|
||||||
self.logMsg("MusicVideos finished.", 2)
|
self.logMsg("MusicVideos finished.", 2)
|
||||||
|
|
||||||
##### PROCESS DELETES #####
|
|
||||||
if compare:
|
|
||||||
# Manual sync, process deletes
|
|
||||||
for kodimvideo in all_kodimvideos:
|
|
||||||
if kodimvideo not in all_embymvideosIds:
|
|
||||||
mvideos.remove(kodimvideo)
|
|
||||||
else:
|
|
||||||
self.logMsg("MusicVideos compare finished.", 1)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -993,7 +946,6 @@ class LibrarySync(threading.Thread):
|
||||||
for view in views:
|
for view in views:
|
||||||
self.PlexUpdateWatched(view['id'], itemType)
|
self.PlexUpdateWatched(view['id'], itemType)
|
||||||
|
|
||||||
##### PROCESS DELETES #####
|
|
||||||
if self.compare:
|
if self.compare:
|
||||||
# Manual sync, process deletes
|
# Manual sync, process deletes
|
||||||
with itemtypes.TVShows() as TVShow:
|
with itemtypes.TVShows() as TVShow:
|
||||||
|
@ -1003,34 +955,12 @@ class LibrarySync(threading.Thread):
|
||||||
self.logMsg("%s sync is finished." % itemType, 1)
|
self.logMsg("%s sync is finished." % itemType, 1)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def music(self, embycursor, kodicursor, pdialog, compare=False):
|
def music(self, embycursor, kodicursor, pdialog):
|
||||||
# Get music from emby
|
# Get music from emby
|
||||||
emby = self.emby
|
emby = self.emby
|
||||||
emby_db = embydb.Embydb_Functions(embycursor)
|
emby_db = embydb.Embydb_Functions(embycursor)
|
||||||
music = itemtypes.Music(embycursor, kodicursor)
|
music = itemtypes.Music(embycursor, kodicursor)
|
||||||
|
|
||||||
if compare:
|
|
||||||
# Pull the list of movies and boxsets in Kodi
|
|
||||||
try:
|
|
||||||
all_kodiartists = dict(emby_db.getChecksum('MusicArtist'))
|
|
||||||
except ValueError:
|
|
||||||
all_kodiartists = {}
|
|
||||||
|
|
||||||
try:
|
|
||||||
all_kodialbums = dict(emby_db.getChecksum('MusicAlbum'))
|
|
||||||
except ValueError:
|
|
||||||
all_kodialbums = {}
|
|
||||||
|
|
||||||
try:
|
|
||||||
all_kodisongs = dict(emby_db.getChecksum('Audio'))
|
|
||||||
except ValueError:
|
|
||||||
all_kodisongs = {}
|
|
||||||
|
|
||||||
all_embyartistsIds = set()
|
|
||||||
all_embyalbumsIds = set()
|
|
||||||
all_embysongsIds = set()
|
|
||||||
updatelist = []
|
|
||||||
|
|
||||||
process = {
|
process = {
|
||||||
|
|
||||||
'artists': [emby.getArtists, music.add_updateArtist],
|
'artists': [emby.getArtists, music.add_updateArtist],
|
||||||
|
@ -1041,47 +971,9 @@ class LibrarySync(threading.Thread):
|
||||||
for type in types:
|
for type in types:
|
||||||
|
|
||||||
if pdialog:
|
if pdialog:
|
||||||
pass
|
all_embyitems = process[type][0](dialog=pdialog)
|
||||||
if compare:
|
total = all_embyitems['TotalRecordCount']
|
||||||
# Manual Sync
|
embyitems = all_embyitems['Items']
|
||||||
if pdialog:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if type != "artists":
|
|
||||||
all_embyitems = process[type][0](basic=True, dialog=pdialog)
|
|
||||||
else:
|
|
||||||
all_embyitems = process[type][0](dialog=pdialog)
|
|
||||||
for embyitem in all_embyitems['Items']:
|
|
||||||
|
|
||||||
if self.shouldStop():
|
|
||||||
return False
|
|
||||||
|
|
||||||
API = api.API(embyitem)
|
|
||||||
itemid = embyitem['Id']
|
|
||||||
if type == "artists":
|
|
||||||
all_embyartistsIds.add(itemid)
|
|
||||||
if all_kodiartists.get(itemid) != API.getChecksum():
|
|
||||||
# Only update if artist is not in Kodi or checksum is different
|
|
||||||
updatelist.append(itemid)
|
|
||||||
elif type == "albums":
|
|
||||||
all_embyalbumsIds.add(itemid)
|
|
||||||
if all_kodialbums.get(itemid) != API.getChecksum():
|
|
||||||
# Only update if album is not in Kodi or checksum is different
|
|
||||||
updatelist.append(itemid)
|
|
||||||
else:
|
|
||||||
all_embysongsIds.add(itemid)
|
|
||||||
if all_kodisongs.get(itemid) != API.getChecksum():
|
|
||||||
# Only update if songs is not in Kodi or checksum is different
|
|
||||||
updatelist.append(itemid)
|
|
||||||
|
|
||||||
self.logMsg("%s to update: %s" % (type, updatelist), 1)
|
|
||||||
embyitems = emby.getFullItems(updatelist)
|
|
||||||
total = len(updatelist)
|
|
||||||
del updatelist[:]
|
|
||||||
else:
|
|
||||||
all_embyitems = process[type][0](dialog=pdialog)
|
|
||||||
total = all_embyitems['TotalRecordCount']
|
|
||||||
embyitems = all_embyitems['Items']
|
|
||||||
|
|
||||||
if pdialog:
|
if pdialog:
|
||||||
pass
|
pass
|
||||||
|
@ -1102,27 +994,6 @@ class LibrarySync(threading.Thread):
|
||||||
else:
|
else:
|
||||||
self.logMsg("%s finished." % type, 2)
|
self.logMsg("%s finished." % type, 2)
|
||||||
|
|
||||||
##### PROCESS DELETES #####
|
|
||||||
if compare:
|
|
||||||
# Manual sync, process deletes
|
|
||||||
for kodiartist in all_kodiartists:
|
|
||||||
if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None:
|
|
||||||
music.remove(kodiartist)
|
|
||||||
else:
|
|
||||||
self.logMsg("Artist compare finished.", 1)
|
|
||||||
|
|
||||||
for kodialbum in all_kodialbums:
|
|
||||||
if kodialbum not in all_embyalbumsIds:
|
|
||||||
music.remove(kodialbum)
|
|
||||||
else:
|
|
||||||
self.logMsg("Albums compare finished.", 1)
|
|
||||||
|
|
||||||
for kodisong in all_kodisongs:
|
|
||||||
if kodisong not in all_embysongsIds:
|
|
||||||
music.remove(kodisong)
|
|
||||||
else:
|
|
||||||
self.logMsg("Songs compare finished.", 1)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Reserved for websocket_client.py and fast start
|
# Reserved for websocket_client.py and fast start
|
||||||
|
@ -1368,3 +1239,475 @@ class LibrarySync(threading.Thread):
|
||||||
def resumeThread(self):
|
def resumeThread(self):
|
||||||
self.suspend_thread = False
|
self.suspend_thread = False
|
||||||
self.logMsg("Resuming thread...", 0)
|
self.logMsg("Resuming thread...", 0)
|
||||||
|
|
||||||
|
|
||||||
|
class ManualSync(LibrarySync):
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
LibrarySync.__init__(self)
|
||||||
|
self.fullSync(manualrun=True)
|
||||||
|
|
||||||
|
|
||||||
|
def movies(self, embycursor, kodicursor, pdialog):
|
||||||
|
# Get movies from emby
|
||||||
|
emby = self.emby
|
||||||
|
emby_db = embydb.Embydb_Functions(embycursor)
|
||||||
|
movies = itemtypes.Movies(embycursor, kodicursor)
|
||||||
|
|
||||||
|
views = emby_db.getView_byType('movies')
|
||||||
|
views += emby_db.getView_byType('mixed')
|
||||||
|
self.logMsg("Media folders: %s" % views, 1)
|
||||||
|
|
||||||
|
# Pull the list of movies and boxsets in Kodi
|
||||||
|
try:
|
||||||
|
all_kodimovies = dict(emby_db.getChecksum('Movie'))
|
||||||
|
except ValueError:
|
||||||
|
all_kodimovies = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
all_kodisets = dict(emby_db.getChecksum('BoxSet'))
|
||||||
|
except ValueError:
|
||||||
|
all_kodisets = {}
|
||||||
|
|
||||||
|
all_embymoviesIds = set()
|
||||||
|
all_embyboxsetsIds = set()
|
||||||
|
updatelist = []
|
||||||
|
|
||||||
|
##### PROCESS MOVIES #####
|
||||||
|
for view in views:
|
||||||
|
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Get items per view
|
||||||
|
viewId = view['id']
|
||||||
|
viewName = view['name']
|
||||||
|
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(
|
||||||
|
heading="Emby for Kodi",
|
||||||
|
message="Comparing movies from view: %s..." % viewName)
|
||||||
|
|
||||||
|
all_embymovies = emby.getMovies(viewId, basic=True, dialog=pdialog)
|
||||||
|
for embymovie in all_embymovies['Items']:
|
||||||
|
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
API = api.API(embymovie)
|
||||||
|
itemid = embymovie['Id']
|
||||||
|
all_embymoviesIds.add(itemid)
|
||||||
|
|
||||||
|
|
||||||
|
if all_kodimovies.get(itemid) != API.getChecksum():
|
||||||
|
# Only update if movie is not in Kodi or checksum is different
|
||||||
|
updatelist.append(itemid)
|
||||||
|
|
||||||
|
self.logMsg("Movies to update for %s: %s" % (viewName, updatelist), 1)
|
||||||
|
embymovies = emby.getFullItems(updatelist)
|
||||||
|
total = len(updatelist)
|
||||||
|
del updatelist[:]
|
||||||
|
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(heading="Processing %s / %s items" % (viewName, total))
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for embymovie in embymovies:
|
||||||
|
# Process individual movies
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
title = embymovie['Name']
|
||||||
|
if pdialog:
|
||||||
|
percentage = int((float(count) / float(total))*100)
|
||||||
|
pdialog.update(percentage, message=title)
|
||||||
|
count += 1
|
||||||
|
movies.add_update(embymovie, viewName, viewId)
|
||||||
|
|
||||||
|
##### PROCESS BOXSETS #####
|
||||||
|
|
||||||
|
boxsets = emby.getBoxset(dialog=pdialog)
|
||||||
|
embyboxsets = []
|
||||||
|
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(
|
||||||
|
heading="Emby for Kodi",
|
||||||
|
message="Comparing boxsets...")
|
||||||
|
|
||||||
|
for boxset in boxsets['Items']:
|
||||||
|
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Boxset has no real userdata, so using etag to compare
|
||||||
|
checksum = boxset['Etag']
|
||||||
|
itemid = boxset['Id']
|
||||||
|
all_embyboxsetsIds.add(itemid)
|
||||||
|
|
||||||
|
if all_kodisets.get(itemid) != checksum:
|
||||||
|
# Only update if boxset is not in Kodi or checksum is different
|
||||||
|
updatelist.append(itemid)
|
||||||
|
embyboxsets.append(boxset)
|
||||||
|
|
||||||
|
self.logMsg("Boxsets to update: %s" % updatelist, 1)
|
||||||
|
total = len(updatelist)
|
||||||
|
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(heading="Processing Boxsets / %s items" % total)
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for boxset in embyboxsets:
|
||||||
|
# Process individual boxset
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
title = boxset['Name']
|
||||||
|
if pdialog:
|
||||||
|
percentage = int((float(count) / float(total))*100)
|
||||||
|
pdialog.update(percentage, message=title)
|
||||||
|
count += 1
|
||||||
|
movies.add_updateBoxset(boxset)
|
||||||
|
|
||||||
|
##### PROCESS DELETES #####
|
||||||
|
|
||||||
|
for kodimovie in all_kodimovies:
|
||||||
|
if kodimovie not in all_embymoviesIds:
|
||||||
|
movies.remove(kodimovie)
|
||||||
|
else:
|
||||||
|
self.logMsg("Movies compare finished.", 1)
|
||||||
|
|
||||||
|
for boxset in all_kodisets:
|
||||||
|
if boxset not in all_embyboxsetsIds:
|
||||||
|
movies.remove(boxset)
|
||||||
|
else:
|
||||||
|
self.logMsg("Boxsets compare finished.", 1)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def musicvideos(self, embycursor, kodicursor, pdialog):
|
||||||
|
# Get musicvideos from emby
|
||||||
|
emby = self.emby
|
||||||
|
emby_db = embydb.Embydb_Functions(embycursor)
|
||||||
|
mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
|
||||||
|
|
||||||
|
views = emby_db.getView_byType('musicvideos')
|
||||||
|
self.logMsg("Media folders: %s" % views, 1)
|
||||||
|
|
||||||
|
# Pull the list of musicvideos in Kodi
|
||||||
|
try:
|
||||||
|
all_kodimvideos = dict(emby_db.getChecksum('MusicVideo'))
|
||||||
|
except ValueError:
|
||||||
|
all_kodimvideos = {}
|
||||||
|
|
||||||
|
all_embymvideosIds = set()
|
||||||
|
updatelist = []
|
||||||
|
|
||||||
|
for view in views:
|
||||||
|
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Get items per view
|
||||||
|
viewId = view['id']
|
||||||
|
viewName = view['name']
|
||||||
|
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(
|
||||||
|
heading="Emby for Kodi",
|
||||||
|
message="Comparing musicvideos from view: %s..." % viewName)
|
||||||
|
|
||||||
|
all_embymvideos = emby.getMusicVideos(viewId, basic=True, dialog=pdialog)
|
||||||
|
for embymvideo in all_embymvideos['Items']:
|
||||||
|
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
API = api.API(embymvideo)
|
||||||
|
itemid = embymvideo['Id']
|
||||||
|
all_embymvideosIds.add(itemid)
|
||||||
|
|
||||||
|
|
||||||
|
if all_kodimvideos.get(itemid) != API.getChecksum():
|
||||||
|
# Only update if musicvideo is not in Kodi or checksum is different
|
||||||
|
updatelist.append(itemid)
|
||||||
|
|
||||||
|
self.logMsg("MusicVideos to update for %s: %s" % (viewName, updatelist), 1)
|
||||||
|
embymvideos = emby.getFullItems(updatelist)
|
||||||
|
total = len(updatelist)
|
||||||
|
del updatelist[:]
|
||||||
|
|
||||||
|
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(heading="Processing %s / %s items" % (viewName, total))
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for embymvideo in embymvideos:
|
||||||
|
# Process individual musicvideo
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
title = embymvideo['Name']
|
||||||
|
if pdialog:
|
||||||
|
percentage = int((float(count) / float(total))*100)
|
||||||
|
pdialog.update(percentage, message=title)
|
||||||
|
count += 1
|
||||||
|
mvideos.add_update(embymvideo, viewName, viewId)
|
||||||
|
|
||||||
|
##### PROCESS DELETES #####
|
||||||
|
|
||||||
|
for kodimvideo in all_kodimvideos:
|
||||||
|
if kodimvideo not in all_embymvideosIds:
|
||||||
|
mvideos.remove(kodimvideo)
|
||||||
|
else:
|
||||||
|
self.logMsg("MusicVideos compare finished.", 1)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def tvshows(self, embycursor, kodicursor, pdialog):
|
||||||
|
# Get shows from emby
|
||||||
|
emby = self.emby
|
||||||
|
emby_db = embydb.Embydb_Functions(embycursor)
|
||||||
|
tvshows = itemtypes.TVShows(embycursor, kodicursor)
|
||||||
|
|
||||||
|
views = emby_db.getView_byType('tvshows')
|
||||||
|
views += emby_db.getView_byType('mixed')
|
||||||
|
self.logMsg("Media folders: %s" % views, 1)
|
||||||
|
|
||||||
|
# Pull the list of tvshows and episodes in Kodi
|
||||||
|
try:
|
||||||
|
all_koditvshows = dict(emby_db.getChecksum('Series'))
|
||||||
|
except ValueError:
|
||||||
|
all_koditvshows = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
all_kodiepisodes = dict(emby_db.getChecksum('Episode'))
|
||||||
|
except ValueError:
|
||||||
|
all_kodiepisodes = {}
|
||||||
|
|
||||||
|
all_embytvshowsIds = set()
|
||||||
|
all_embyepisodesIds = set()
|
||||||
|
updatelist = []
|
||||||
|
|
||||||
|
|
||||||
|
for view in views:
|
||||||
|
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Get items per view
|
||||||
|
viewId = view['id']
|
||||||
|
viewName = view['name']
|
||||||
|
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(
|
||||||
|
heading="Emby for Kodi",
|
||||||
|
message="Comparing tvshows from view: %s..." % viewName)
|
||||||
|
|
||||||
|
all_embytvshows = emby.getShows(viewId, basic=True, dialog=pdialog)
|
||||||
|
for embytvshow in all_embytvshows['Items']:
|
||||||
|
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
API = api.API(embytvshow)
|
||||||
|
itemid = embytvshow['Id']
|
||||||
|
all_embytvshowsIds.add(itemid)
|
||||||
|
|
||||||
|
|
||||||
|
if all_koditvshows.get(itemid) != API.getChecksum():
|
||||||
|
# Only update if movie is not in Kodi or checksum is different
|
||||||
|
updatelist.append(itemid)
|
||||||
|
|
||||||
|
self.logMsg("TVShows to update for %s: %s" % (viewName, updatelist), 1)
|
||||||
|
embytvshows = emby.getFullItems(updatelist)
|
||||||
|
total = len(updatelist)
|
||||||
|
del updatelist[:]
|
||||||
|
|
||||||
|
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(heading="Processing %s / %s items" % (viewName, total))
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for embytvshow in embytvshows:
|
||||||
|
# Process individual show
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
itemid = embytvshow['Id']
|
||||||
|
title = embytvshow['Name']
|
||||||
|
if pdialog:
|
||||||
|
percentage = int((float(count) / float(total))*100)
|
||||||
|
pdialog.update(percentage, message=title)
|
||||||
|
count += 1
|
||||||
|
tvshows.add_update(embytvshow, viewName, viewId)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Get all episodes in view
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(
|
||||||
|
heading="Emby for Kodi",
|
||||||
|
message="Comparing episodes from view: %s..." % viewName)
|
||||||
|
|
||||||
|
all_embyepisodes = emby.getEpisodes(viewId, basic=True, dialog=pdialog)
|
||||||
|
for embyepisode in all_embyepisodes['Items']:
|
||||||
|
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
API = api.API(embyepisode)
|
||||||
|
itemid = embyepisode['Id']
|
||||||
|
all_embyepisodesIds.add(itemid)
|
||||||
|
|
||||||
|
if all_kodiepisodes.get(itemid) != API.getChecksum():
|
||||||
|
# Only update if movie is not in Kodi or checksum is different
|
||||||
|
updatelist.append(itemid)
|
||||||
|
|
||||||
|
self.logMsg("Episodes to update for %s: %s" % (viewName, updatelist), 1)
|
||||||
|
embyepisodes = emby.getFullItems(updatelist)
|
||||||
|
total = len(updatelist)
|
||||||
|
del updatelist[:]
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for episode in embyepisodes:
|
||||||
|
|
||||||
|
# Process individual episode
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
title = episode['SeriesName']
|
||||||
|
episodetitle = episode['Name']
|
||||||
|
if pdialog:
|
||||||
|
percentage = int((float(count) / float(total))*100)
|
||||||
|
pdialog.update(percentage, message="%s - %s" % (title, episodetitle))
|
||||||
|
count += 1
|
||||||
|
tvshows.add_updateEpisode(episode)
|
||||||
|
|
||||||
|
##### PROCESS DELETES #####
|
||||||
|
|
||||||
|
for koditvshow in all_koditvshows:
|
||||||
|
if koditvshow not in all_embytvshowsIds:
|
||||||
|
tvshows.remove(koditvshow)
|
||||||
|
else:
|
||||||
|
self.logMsg("TVShows compare finished.", 1)
|
||||||
|
|
||||||
|
for kodiepisode in all_kodiepisodes:
|
||||||
|
if kodiepisode not in all_embyepisodesIds:
|
||||||
|
tvshows.remove(kodiepisode)
|
||||||
|
else:
|
||||||
|
self.logMsg("Episodes compare finished.", 1)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def music(self, embycursor, kodicursor, pdialog):
|
||||||
|
# Get music from emby
|
||||||
|
emby = self.emby
|
||||||
|
emby_db = embydb.Embydb_Functions(embycursor)
|
||||||
|
music = itemtypes.Music(embycursor, kodicursor)
|
||||||
|
|
||||||
|
# Pull the list of artists, albums, songs
|
||||||
|
try:
|
||||||
|
all_kodiartists = dict(emby_db.getChecksum('MusicArtist'))
|
||||||
|
except ValueError:
|
||||||
|
all_kodiartists = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
all_kodialbums = dict(emby_db.getChecksum('MusicAlbum'))
|
||||||
|
except ValueError:
|
||||||
|
all_kodialbums = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
all_kodisongs = dict(emby_db.getChecksum('Audio'))
|
||||||
|
except ValueError:
|
||||||
|
all_kodisongs = {}
|
||||||
|
|
||||||
|
all_embyartistsIds = set()
|
||||||
|
all_embyalbumsIds = set()
|
||||||
|
all_embysongsIds = set()
|
||||||
|
updatelist = []
|
||||||
|
|
||||||
|
process = {
|
||||||
|
|
||||||
|
'artists': [emby.getArtists, music.add_updateArtist],
|
||||||
|
'albums': [emby.getAlbums, music.add_updateAlbum],
|
||||||
|
'songs': [emby.getSongs, music.add_updateSong]
|
||||||
|
}
|
||||||
|
types = ['artists', 'albums', 'songs']
|
||||||
|
for type in types:
|
||||||
|
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(
|
||||||
|
heading="Emby for Kodi",
|
||||||
|
message="Comparing %s..." % type)
|
||||||
|
|
||||||
|
if type != "artists":
|
||||||
|
all_embyitems = process[type][0](basic=True, dialog=pdialog)
|
||||||
|
else:
|
||||||
|
all_embyitems = process[type][0](dialog=pdialog)
|
||||||
|
for embyitem in all_embyitems['Items']:
|
||||||
|
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
API = api.API(embyitem)
|
||||||
|
itemid = embyitem['Id']
|
||||||
|
if type == "artists":
|
||||||
|
all_embyartistsIds.add(itemid)
|
||||||
|
if all_kodiartists.get(itemid) != API.getChecksum():
|
||||||
|
# Only update if artist is not in Kodi or checksum is different
|
||||||
|
updatelist.append(itemid)
|
||||||
|
elif type == "albums":
|
||||||
|
all_embyalbumsIds.add(itemid)
|
||||||
|
if all_kodialbums.get(itemid) != API.getChecksum():
|
||||||
|
# Only update if album is not in Kodi or checksum is different
|
||||||
|
updatelist.append(itemid)
|
||||||
|
else:
|
||||||
|
all_embysongsIds.add(itemid)
|
||||||
|
if all_kodisongs.get(itemid) != API.getChecksum():
|
||||||
|
# Only update if songs is not in Kodi or checksum is different
|
||||||
|
updatelist.append(itemid)
|
||||||
|
|
||||||
|
self.logMsg("%s to update: %s" % (type, updatelist), 1)
|
||||||
|
embyitems = emby.getFullItems(updatelist)
|
||||||
|
total = len(updatelist)
|
||||||
|
del updatelist[:]
|
||||||
|
|
||||||
|
if pdialog:
|
||||||
|
pdialog.update(heading="Processing %s / %s items" % (type, total))
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for embyitem in embyitems:
|
||||||
|
# Process individual item
|
||||||
|
if self.shouldStop():
|
||||||
|
return False
|
||||||
|
|
||||||
|
title = embyitem['Name']
|
||||||
|
if pdialog:
|
||||||
|
percentage = int((float(count) / float(total))*100)
|
||||||
|
pdialog.update(percentage, message=title)
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
process[type][1](embyitem)
|
||||||
|
|
||||||
|
##### PROCESS DELETES #####
|
||||||
|
|
||||||
|
for kodiartist in all_kodiartists:
|
||||||
|
if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None:
|
||||||
|
music.remove(kodiartist)
|
||||||
|
else:
|
||||||
|
self.logMsg("Artist compare finished.", 1)
|
||||||
|
|
||||||
|
for kodialbum in all_kodialbums:
|
||||||
|
if kodialbum not in all_embyalbumsIds:
|
||||||
|
music.remove(kodialbum)
|
||||||
|
else:
|
||||||
|
self.logMsg("Albums compare finished.", 1)
|
||||||
|
|
||||||
|
for kodisong in all_kodisongs:
|
||||||
|
if kodisong not in all_embysongsIds:
|
||||||
|
music.remove(kodisong)
|
||||||
|
else:
|
||||||
|
self.logMsg("Songs compare finished.", 1)
|
||||||
|
|
||||||
|
return True
|
|
@ -74,17 +74,17 @@ def window(property, value=None, clear=False, windowid=10000):
|
||||||
WINDOW = xbmcgui.Window(windowid)
|
WINDOW = xbmcgui.Window(windowid)
|
||||||
|
|
||||||
#setproperty accepts both string and unicode but utf-8 strings are adviced by kodi devs because some unicode can give issues
|
#setproperty accepts both string and unicode but utf-8 strings are adviced by kodi devs because some unicode can give issues
|
||||||
if isinstance(property, unicode):
|
'''if isinstance(property, unicode):
|
||||||
property = property.encode("utf-8")
|
property = property.encode("utf-8")
|
||||||
if isinstance(value, unicode):
|
if isinstance(value, unicode):
|
||||||
value = value.encode("utf-8")
|
value = value.encode("utf-8")'''
|
||||||
|
|
||||||
if clear:
|
if clear:
|
||||||
WINDOW.clearProperty(property)
|
WINDOW.clearProperty(property)
|
||||||
elif value is not None:
|
elif value is not None:
|
||||||
WINDOW.setProperty(property, value)
|
WINDOW.setProperty(property, value)
|
||||||
else: #getproperty returns string so convert to unicode
|
else: #getproperty returns string so convert to unicode
|
||||||
return WINDOW.getProperty(property).decode("utf-8")
|
return WINDOW.getProperty(property)#.decode("utf-8")
|
||||||
|
|
||||||
def settings(setting, value=None):
|
def settings(setting, value=None):
|
||||||
# Get or add addon setting
|
# Get or add addon setting
|
||||||
|
@ -170,15 +170,7 @@ def reset():
|
||||||
deletePlaylists()
|
deletePlaylists()
|
||||||
|
|
||||||
# Clean up the video nodes
|
# Clean up the video nodes
|
||||||
import shutil
|
deleteNodes()
|
||||||
path = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
|
|
||||||
dirs, files = xbmcvfs.listdir(path)
|
|
||||||
for dir in dirs:
|
|
||||||
if dir.decode('utf-8').startswith('Emby'):
|
|
||||||
shutil.rmtree("%s%s" % (path, dir.decode('utf-8')))
|
|
||||||
for file in files:
|
|
||||||
if file.decode('utf-8').startswith('emby'):
|
|
||||||
xbmcvfs.delete("%s%s" % (path, file.decode('utf-8')))
|
|
||||||
|
|
||||||
# Wipe the kodi databases
|
# Wipe the kodi databases
|
||||||
logMsg("EMBY", "Resetting the Kodi video database.")
|
logMsg("EMBY", "Resetting the Kodi video database.")
|
||||||
|
@ -532,4 +524,17 @@ def deletePlaylists():
|
||||||
dirs, files = xbmcvfs.listdir(path)
|
dirs, files = xbmcvfs.listdir(path)
|
||||||
for file in files:
|
for file in files:
|
||||||
if file.decode('utf-8').startswith('Emby'):
|
if file.decode('utf-8').startswith('Emby'):
|
||||||
xbmcvfs.delete("%s%s" % (path, file))
|
xbmcvfs.delete("%s%s" % (path, file))
|
||||||
|
|
||||||
|
def deleteNodes():
|
||||||
|
|
||||||
|
# Clean up video nodes
|
||||||
|
import shutil
|
||||||
|
path = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
|
||||||
|
dirs, files = xbmcvfs.listdir(path)
|
||||||
|
for dir in dirs:
|
||||||
|
if dir.decode('utf-8').startswith('Emby'):
|
||||||
|
shutil.rmtree("%s%s" % (path, dir.decode('utf-8')))
|
||||||
|
for file in files:
|
||||||
|
if file.decode('utf-8').startswith('emby'):
|
||||||
|
xbmcvfs.delete("%s%s" % (path, file.decode('utf-8')))
|
Loading…
Reference in a new issue