diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index 5d21ae98..860c48eb 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -1420,8 +1420,8 @@ class API(): # localtime = time.strftime('%H:%M', date_time) # return localtime + ' ' + localdate try: - DATEFORMAT = xbmc.getRegion('dateshort') - TIMEFORMAT = xbmc.getRegion('meridiem') + # DATEFORMAT = xbmc.getRegion('dateshort') + # TIMEFORMAT = xbmc.getRegion('meridiem') date_time = time.localtime(float(stamp)) localdate = time.strftime('%Y-%m-%d %H:%M:%S', date_time) except: @@ -1447,7 +1447,7 @@ class API(): """ Returns the Plex key such as '246922' as a string """ - return self.item.attrib.get('ratingKey', '') + return self.item.attrib.get('ratingKey', None) def getKey(self): """ @@ -1491,7 +1491,7 @@ class API(): try: playcount = int(item['viewCount']) - except KeyError: + except: playcount = None if playcount: @@ -1499,9 +1499,14 @@ class API(): try: lastPlayedDate = self.DateToKodi(int(item['lastViewedAt'])) - except KeyError: + except: lastPlayedDate = None + try: + userrating = int(item['userRating']) + except: + userrating = None + resume, runtime = self.getRuntime() return { 'Favorite': favorite, @@ -1510,7 +1515,8 @@ class API(): 'LastPlayedDate': lastPlayedDate, 'Resume': resume, 'Runtime': runtime, - 'Rating': rating + 'Rating': rating, + 'UserRating': userrating } def getPeople(self): diff --git a/resources/lib/PlexFunctions.py b/resources/lib/PlexFunctions.py index 1a5b9333..c95457b8 100644 --- a/resources/lib/PlexFunctions.py +++ b/resources/lib/PlexFunctions.py @@ -3,10 +3,8 @@ from urllib import urlencode from ast import literal_eval from urlparse import urlparse, parse_qs import re -import json from xbmcaddon import Addon -import xbmc import downloadutils from utils import logMsg, settings @@ -35,7 +33,10 @@ def GetItemClassFromType(itemType): 'movie': 'Movies', 'episodes': 'TVShows', 'episode': 'TVShows', - 'show': 'TVShows' + 'show': 'TVShows', + 'artist': 'Music', + 'album': 'Music', + 'track': 'Music' } return classes[itemType] @@ -97,7 +98,10 @@ def GetMethodFromPlexType(plexType): 'movie': 'add_update', 'episode': 'add_updateEpisode', 'show': 'add_update', - 'season': 'add_updateSeason' + 'season': 'add_updateSeason', + 'track': 'add_updateSong', + 'album': 'add_updateAlbum', + 'artist': 'add_updateArtist' } return methods[plexType] @@ -199,17 +203,22 @@ def GetAllPlexChildren(key): return xml -def GetPlexSectionResults(viewId, headerOptions={}): +def GetPlexSectionResults(viewId, args=None): """ Returns a list (XML API dump) of all Plex items in the Plex section with key = viewId. + Input: + args: optional dict to be urlencoded + Returns None if something went wrong """ result = [] url = "{server}/library/sections/%s/all" % viewId - result = downloadutils.DownloadUtils().downloadUrl( - url, headerOptions=headerOptions) + if args: + url += "?" + urlencode(args) + + result = downloadutils.DownloadUtils().downloadUrl(url) try: result.tag diff --git a/resources/lib/artwork.py b/resources/lib/artwork.py index 1b039b30..f77022fd 100644 --- a/resources/lib/artwork.py +++ b/resources/lib/artwork.py @@ -270,8 +270,6 @@ class Artwork(): def CacheTexture(self, url): # Cache a single image url to the texture cache if url and self.enableTextureCache: - self.logMsg("Processing: %s" % url, 2) - if(self.imageCacheLimitThreads == 0 or self.imageCacheLimitThreads == None): #Add image to texture cache by simply calling it at the http endpoint @@ -389,8 +387,6 @@ class Artwork(): except TypeError: # Add the artwork cacheimage = True - self.logMsg("Adding Art Link for kodiId: %s (%s)" % (kodiId, imageUrl), 2) - query = ( ''' INSERT INTO art(media_id, media_type, type, url) @@ -409,10 +405,6 @@ class Artwork(): imageType in ("fanart", "poster")): # Delete current entry before updating with the new one self.deleteCachedArtwork(url) - - self.logMsg( - "Updating Art url for %s kodiId: %s (%s) -> (%s)" - % (imageType, kodiId, url, imageUrl), 1) query = ' '.join(( diff --git a/resources/lib/itemtypes.py b/resources/lib/itemtypes.py index d8a677d2..091063f2 100644 --- a/resources/lib/itemtypes.py +++ b/resources/lib/itemtypes.py @@ -19,6 +19,7 @@ import kodidb_functions as kodidb import read_embyserver as embyserver import musicutils as musicutils import PlexAPI +from PlexFunctions import GetPlexMetadata ################################################################################################## @@ -26,13 +27,15 @@ import PlexAPI @utils.logging class Items(object): """ - Items to be called with "with Items as xxx:" to ensure that __enter__ + Items to be called with "with Items() as xxx:" to ensure that __enter__ method is called (opens db connections) + + Input: + kodiType: optional argument; e.g. 'video' or 'music' """ def __init__(self): self.doUtils = downloadutils.DownloadUtils() - self.kodiversion = int(xbmc.getInfoLabel("System.BuildVersion")[:2]) self.directpath = utils.settings('useDirectPaths') == "1" self.music_enabled = utils.settings('enableMusic') == "true" @@ -283,7 +286,6 @@ class Movies(Items): self.add_updateBoxset(boxset) def add_update(self, item, viewtag=None, viewid=None): - self.logMsg("Entering add_update", 1) # Process single movie kodicursor = self.kodicursor emby_db = self.emby_db @@ -291,7 +293,8 @@ class Movies(Items): artwork = self.artwork API = PlexAPI.API(item) - # If the item already exist in the local Kodi DB we'll perform a full item update + # If the item already exist in the local Kodi DB we'll perform a full + # item update # If the item doesn't exist, we'll add it to the database update_item = True itemid = API.getRatingKey() @@ -306,16 +309,14 @@ class Movies(Items): pathid = emby_dbitem[2] except TypeError: - update_item = False - self.logMsg("movieid: %s not found." % itemid, 2) # movieid + update_item = False kodicursor.execute("select coalesce(max(idMovie),0) from movie") movieid = kodicursor.fetchone()[0] + 1 if not viewtag or not viewid: # Get view tag from emby viewtag, viewid, mediatype = self.emby.getView_embyId(itemid) - self.logMsg("View tag found: %s" % viewtag, 2) # fileId information checksum = API.getChecksum() @@ -349,7 +350,6 @@ class Movies(Items): studio = studios[0] except IndexError: studio = None - self.logMsg("Retrieved metadata for %s" % itemid, 2) # Find one trailer trailer = None @@ -470,33 +470,24 @@ class Movies(Items): # Process cast people = API.getPeopleList() kodi_db.addPeople(movieid, people, "movie") - self.logMsg('People added', 2) # Process genres kodi_db.addGenres(movieid, genres, "movie") - self.logMsg('Genres added', 2) # Process artwork allartworks = API.getAllArtwork() - self.logMsg('Artwork processed', 2) artwork.addArtwork(allartworks, movieid, "movie", kodicursor) - self.logMsg('Artwork added', 2) # Process stream details streams = API.getMediaStreams() - self.logMsg('Streames processed', 2) kodi_db.addStreams(fileid, streams, runtime) - self.logMsg('Streames added', 2) # Process studios kodi_db.addStudios(movieid, studios, "movie") - self.logMsg('Studios added', 2) # Process tags: view, emby tags tags = [viewtag] # tags.extend(item['Tags']) # if userdata['Favorite']: # tags.append("Favorite movies") kodi_db.addTags(movieid, tags, "movie") - self.logMsg('Tags added', 2) # Process playstates kodi_db.addPlaystate(fileid, resume, runtime, playcount, dateplayed) - self.logMsg('Done processing %s' % itemid, 2) def remove(self, itemid): # Remove movieid, fileid, emby reference @@ -900,11 +891,6 @@ class TVShows(Items): artwork = self.artwork API = PlexAPI.API(item) - # if utils.settings('syncEmptyShows') == "false" and not item['RecursiveItemCount']: - # self.logMsg("Skipping empty show: %s" % item['Name'], 1) - # return - # If the item already exist in the local Kodi DB we'll perform a full item update - # If the item doesn't exist, we'll add it to the database update_item = True itemid = API.getRatingKey() if not itemid: @@ -917,8 +903,6 @@ class TVShows(Items): except TypeError: update_item = False - self.logMsg("View tag found: %s" % viewtag, 2) - # fileId information checksum = API.getChecksum() @@ -937,7 +921,7 @@ class TVShows(Items): except IndexError: studio = None - ##### GET THE FILE AND PATH ##### + # GET THE FILE AND PATH ##### playurl = API.getKey() if self.directpath: @@ -971,8 +955,7 @@ class TVShows(Items): toplevelpath = "plugin://plugin.video.plexkodiconnect.tvshows/" path = "%s%s/" % (toplevelpath, itemid) - - ##### UPDATE THE TVSHOW ##### + # UPDATE THE TVSHOW ##### if update_item: self.logMsg("UPDATE tvshow itemid: %s - Title: %s" % (itemid, title), 1) @@ -1066,6 +1049,9 @@ class TVShows(Items): API = PlexAPI.API(item) showid = viewid itemid = API.getRatingKey() + if not itemid: + self.logMsg('Error getting itemid for season, skipping', -1) + return kodicursor = self.kodicursor emby_db = self.emby_db kodi_db = self.kodi_db @@ -1078,16 +1064,12 @@ class TVShows(Items): emby_dbitem = emby_db.getItem_byId(itemid) try: embyDbItemId = emby_dbitem[0] - self.logMsg("Updating Season: %s" % itemid, 2) except TypeError: update_item = False - self.logMsg("Season: %s not found." % itemid, 2) # Process artwork allartworks = API.getAllArtwork() artwork.addArtwork(allartworks, seasonid, "season", kodicursor) - self.logMsg("Updated season %s, Plex Id: %s of Plex show Id: %s" % ( - seasonnum, itemid, showid), 2) if update_item: # Update a reference: checksum in emby table @@ -1108,20 +1090,21 @@ class TVShows(Items): artwork = self.artwork API = PlexAPI.API(item) - # If the item already exist in the local Kodi DB we'll perform a full item update + # If the item already exist in the local Kodi DB we'll perform a full + # item update # If the item doesn't exist, we'll add it to the database update_item = True itemid = API.getRatingKey() + if not itemid: + self.logMsg('Error getting itemid for episode, skipping', -1) + return emby_dbitem = emby_db.getItem_byId(itemid) - self.logMsg("Processing episode with Plex Id: %s" % itemid, 2) try: episodeid = emby_dbitem[0] fileid = emby_dbitem[1] pathid = emby_dbitem[2] - except TypeError: update_item = False - self.logMsg("episodeid: %s not found." % itemid, 2) # episodeid kodicursor.execute("select coalesce(max(idEpisode),0) from episode") episodeid = kodicursor.fetchone()[0] + 1 @@ -1145,12 +1128,8 @@ class TVShows(Items): resume, runtime = API.getRuntime() premieredate = API.getPremiereDate() - self.logMsg("Retrieved metadata for %s" % itemid, 2) - # episode details seriesId, seriesName, season, episode = API.getEpisodeDetails() - self.logMsg("Got episode details: %s %s: s%se%s" - % (seriesId, seriesName, season, episode), 2) if season is None: if item.get('AbsoluteEpisodeNumber'): @@ -1171,7 +1150,7 @@ class TVShows(Items): airsBeforeSeason = "-1" airsBeforeEpisode = "-1" # Append multi episodes to title - # if item.get('IndexNumberEnd'): + # if item.get('IndexNumberEnd'): # title = "| %02d | %s" % (item['IndexNumberEnd'], title) # Get season id @@ -1190,11 +1169,9 @@ class TVShows(Items): # self.logMsg("Skipping: %s. Unable to add series: %s." % (itemid, seriesId), -1) self.logMsg("Parent tvshow now found, skip item", 2) return False - self.logMsg("showid: %s" % showid, 2) seasonid = kodi_db.addSeason(showid, season) - self.logMsg("seasonid: %s" % seasonid, 2) - ##### GET THE FILE AND PATH ##### + # GET THE FILE AND PATH ##### playurl = API.getKey() filename = playurl @@ -1235,7 +1212,7 @@ class TVShows(Items): } filename = "%s?%s" % (path, urllib.urlencode(params)) - ##### UPDATE THE EPISODE ##### + # UPDATE THE EPISODE ##### if update_item: self.logMsg("UPDATE episode itemid: %s" % (itemid), 1) @@ -1484,12 +1461,11 @@ class TVShows(Items): kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,)) self.logMsg("Removed episode: %s." % kodiid, 2) + class Music(Items): - - def __init__(self, embycursor, musiccursor): - - Items.__init__(self, embycursor, musiccursor) + def __init__(self): + Items.__init__(self) self.directstream = utils.settings('streamMusic') == "true" self.enableimportsongrating = utils.settings('enableImportSongRating') == "true" @@ -1498,6 +1474,20 @@ class Music(Items): self.userid = utils.window('emby_currUser') self.server = utils.window('emby_server%s' % self.userid) + def __enter__(self): + """ + OVERWRITE this method, because we need to open another DB. + Open DB connections and cursors + """ + self.embyconn = utils.kodiSQL('emby') + self.embycursor = self.embyconn.cursor() + # Here it is, not 'video' but 'music' + self.kodiconn = utils.kodiSQL('music') + self.kodicursor = self.kodiconn.cursor() + self.emby_db = embydb.Embydb_Functions(self.embycursor) + self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor) + return self + def added(self, items, pdialog): total = len(items) @@ -1545,38 +1535,37 @@ class Music(Items): if not pdialog and self.contentmsg: self.contentPop(title, self.newmusic_time) - def add_updateArtist(self, item, artisttype="MusicArtist"): - # Process a single artist - kodiversion = self.kodiversion + def add_updateArtist(self, item, viewtag=None, viewid=None, + artisttype="MusicArtist"): kodicursor = self.kodicursor emby_db = self.emby_db kodi_db = self.kodi_db artwork = self.artwork - API = api.API(item) + API = PlexAPI.API(item) update_item = True - itemid = item['Id'] + itemid = API.getRatingKey() emby_dbitem = emby_db.getItem_byId(itemid) try: artistid = emby_dbitem[0] except TypeError: update_item = False - self.logMsg("artistid: %s not found." % itemid, 2) - ##### The artist details ##### + # The artist details ##### lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S') dateadded = API.getDateCreated() checksum = API.getChecksum() - name = item['Name'] - musicBrainzId = API.getProvider('MusicBrainzArtist') - genres = " / ".join(item.get('Genres')) - bio = API.getOverview() + name, sortname = API.getTitle() + # musicBrainzId = API.getProvider('MusicBrainzArtist') + musicBrainzId = None + genres = API.joinList(API.getGenres()) + bio = API.getPlot() # Associate artwork - artworks = artwork.getAllArtwork(item, parentInfo=True) + artworks = API.getAllArtwork(parentInfo=True) thumb = artworks['Primary'] - backdrops = artworks['Backdrop'] # List + backdrops = artworks['Backdrop'] # List if thumb: thumb = "%s" % thumb @@ -1585,22 +1574,24 @@ class Music(Items): else: fanart = "" - - ##### UPDATE THE ARTIST ##### + # UPDATE THE ARTIST ##### if update_item: - self.logMsg("UPDATE artist itemid: %s - Name: %s" % (itemid, name), 1) + self.logMsg("UPDATE artist itemid: %s - Name: %s" + % (itemid, name), 1) # Update the checksum in emby table emby_db.updateReference(itemid, checksum) - ##### OR ADD THE ARTIST ##### + # OR ADD THE ARTIST ##### else: self.logMsg("ADD artist itemid: %s - Name: %s" % (itemid, name), 1) - # safety checks: It looks like Emby supports the same artist multiple times. - # Kodi doesn't allow that. In case that happens we just merge the artist entries. + # safety checks: It looks like Emby supports the same artist + # multiple times. + # Kodi doesn't allow that. In case that happens we just merge the + # artist entries. artistid = kodi_db.addArtist(name, musicBrainzId) # Create the reference in emby table - emby_db.addReference(itemid, artistid, artisttype, "artist", checksum=checksum) - + emby_db.addReference( + itemid, artistid, artisttype, "artist", checksum=checksum) # Process the artist if self.kodiversion in (16, 17): @@ -1611,7 +1602,8 @@ class Music(Items): "lastScraped = ?", "WHERE idArtist = ?" )) - kodicursor.execute(query, (genres, bio, thumb, fanart, lastScraped, artistid)) + kodicursor.execute(query, (genres, bio, thumb, fanart, + lastScraped, artistid)) else: query = ' '.join(( @@ -1621,73 +1613,79 @@ class Music(Items): "WHERE idArtist = ?" )) kodicursor.execute(query, (genres, bio, thumb, fanart, lastScraped, - dateadded, artistid)) - + dateadded, artistid)) # Update artwork artwork.addArtwork(artworks, artistid, "artist", kodicursor) - def add_updateAlbum(self, item): - # Process a single artist - emby = self.emby + def add_updateAlbum(self, item, viewtag=None, viewid=None): kodiversion = self.kodiversion kodicursor = self.kodicursor emby_db = self.emby_db kodi_db = self.kodi_db artwork = self.artwork - API = api.API(item) + API = PlexAPI.API(item) update_item = True - itemid = item['Id'] + itemid = API.getRatingKey() + if not itemid: + self.logMsg('Error processing Album, skipping', -1) + return emby_dbitem = emby_db.getItem_byId(itemid) try: albumid = emby_dbitem[0] except TypeError: + # Albumid not found update_item = False - self.logMsg("albumid: %s not found." % itemid, 2) - ##### The album details ##### + # The album details ##### lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S') dateadded = API.getDateCreated() userdata = API.getUserData() checksum = API.getChecksum() - name = item['Name'] - musicBrainzId = API.getProvider('MusicBrainzAlbum') - year = item.get('ProductionYear') - genres = item.get('Genres') - genre = " / ".join(genres) - bio = API.getOverview() + name, sorttitle = API.getTitle() + # musicBrainzId = API.getProvider('MusicBrainzAlbum') + musicBrainzId = None + year = API.getYear() + genres = API.getGenres() + genre = API.joinList(genres) + bio = API.getPlot() rating = userdata['UserRating'] - artists = item['AlbumArtists'] - if not artists: - artists = item['ArtistItems'] - artistname = [] - for artist in artists: - artistname.append(artist['Name']) - artistname = " / ".join(artistname) + # artists = item['AlbumArtists'] + # if not artists: + # artists = item['ArtistItems'] + # artistname = [] + # for artist in artists: + # artistname.append(artist['Name']) + artistname = item.attrib.get('parentTitle') + if not artistname: + artistname = item.attrib.get('originalTitle') # Associate artwork - artworks = artwork.getAllArtwork(item, parentInfo=True) + artworks = API.getAllArtwork(parentInfo=True) thumb = artworks['Primary'] if thumb: thumb = "%s" % thumb - ##### UPDATE THE ALBUM ##### + # UPDATE THE ALBUM ##### if update_item: - self.logMsg("UPDATE album itemid: %s - Name: %s" % (itemid, name), 1) + self.logMsg("UPDATE album itemid: %s - Name: %s" + % (itemid, name), 1) # Update the checksum in emby table emby_db.updateReference(itemid, checksum) - ##### OR ADD THE ALBUM ##### + # OR ADD THE ALBUM ##### else: self.logMsg("ADD album itemid: %s - Name: %s" % (itemid, name), 1) - # safety checks: It looks like Emby supports the same artist multiple times. - # Kodi doesn't allow that. In case that happens we just merge the artist entries. + # safety checks: It looks like Emby supports the same artist + # multiple times. + # Kodi doesn't allow that. In case that happens we just merge the + # artist entries. albumid = kodi_db.addAlbum(name, musicBrainzId) # Create the reference in emby table - emby_db.addReference(itemid, albumid, "MusicAlbum", "album", checksum=checksum) - + emby_db.addReference( + itemid, albumid, "MusicAlbum", "album", checksum=checksum) # Process the album info if kodiversion == 17: @@ -1699,8 +1697,8 @@ class Music(Items): "iUserrating = ?, lastScraped = ?, strReleaseType = ?", "WHERE idAlbum = ?" )) - kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped, - "album", albumid)) + kodicursor.execute(query, (artistname, year, genre, bio, thumb, + rating, lastScraped, "album", albumid)) elif kodiversion == 16: # Kodi Jarvis query = ' '.join(( @@ -1710,8 +1708,8 @@ class Music(Items): "iRating = ?, lastScraped = ?, strReleaseType = ?", "WHERE idAlbum = ?" )) - kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped, - "album", albumid)) + kodicursor.execute(query, (artistname, year, genre, bio, thumb, + rating, lastScraped, "album", albumid)) elif kodiversion == 15: # Kodi Isengard query = ' '.join(( @@ -1721,8 +1719,9 @@ class Music(Items): "iRating = ?, lastScraped = ?, dateAdded = ?, strReleaseType = ?", "WHERE idAlbum = ?" )) - kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped, - dateadded, "album", albumid)) + kodicursor.execute(query, (artistname, year, genre, bio, thumb, + rating, lastScraped, dateadded, + "album", albumid)) else: # Kodi Helix query = ' '.join(( @@ -1732,92 +1731,104 @@ class Music(Items): "iRating = ?, lastScraped = ?, dateAdded = ?", "WHERE idAlbum = ?" )) - kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped, - dateadded, albumid)) + kodicursor.execute(query, (artistname, year, genre, bio, thumb, + rating, lastScraped, dateadded, + albumid)) # Associate the parentid for emby reference - parentId = item.get('ParentId') + parentId = item.attrib.get('parentRatingKey') if parentId is not None: emby_dbartist = emby_db.getItem_byId(parentId) try: artistid = emby_dbartist[0] except TypeError: - # Artist does not exist in emby database. - artist = emby.getItem(parentId) + self.logMsg('Artist %s does not exist in emby database' + % parentId, 1) + artist = GetPlexMetadata(parentId) # Item may not be an artist, verification necessary. - if artist['Type'] == "MusicArtist": - # Update with the parentId, for remove reference - emby_db.addReference(parentId, parentId, "MusicArtist", "artist") - emby_db.updateParentId(itemid, parentId) + if artist: + if artist[0].attrib.get('type') == "artist": + # Update with the parentId, for remove reference + emby_db.addReference( + parentId, parentId, "MusicArtist", "artist") + emby_db.updateParentId(itemid, parentId) else: # Update emby reference with the artistid emby_db.updateParentId(itemid, artistid) # Assign main artists to album - for artist in artists: - artistname = artist['Name'] - artistId = artist['Id'] - emby_dbartist = emby_db.getItem_byId(artistId) - try: - artistid = emby_dbartist[0] - except TypeError: - # Artist does not exist in emby database, create the reference - artist = emby.getItem(artistId) - self.add_updateArtist(artist, artisttype="AlbumArtist") + # Plex unfortunately only supports 1 artist :-( + artistId = parentId + emby_dbartist = emby_db.getItem_byId(artistId) + try: + artistid = emby_dbartist[0] + except TypeError: + # Artist does not exist in emby database, create the reference + self.logMsg('Artist %s does not exist in emby database' + % artistId, 1) + artist = GetPlexMetadata(artistId) + if artist: + self.add_updateArtist(artist[0], artisttype="AlbumArtist") emby_dbartist = emby_db.getItem_byId(artistId) artistid = emby_dbartist[0] - else: - # Best take this name over anything else. - query = "UPDATE artist SET strArtist = ? WHERE idArtist = ?" - kodicursor.execute(query, (artistname, artistid,)) + else: + # Best take this name over anything else. + query = "UPDATE artist SET strArtist = ? WHERE idArtist = ?" + kodicursor.execute(query, (artistname, artistid,)) + self.logMsg("UPDATE artist: strArtist: %s, idArtist: %s" + % (artistname, artistid), 1) - # Add artist to album - query = ( - ''' - INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist) + # Add artist to album + query = ( + ''' + INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist) - VALUES (?, ?, ?) - ''' - ) - kodicursor.execute(query, (artistid, albumid, artistname)) - # Update discography - query = ( - ''' - INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear) - - VALUES (?, ?, ?) - ''' - ) - kodicursor.execute(query, (artistid, name, year)) - # Update emby reference with parentid - emby_db.updateParentId(artistId, albumid) + VALUES (?, ?, ?) + ''' + ) + kodicursor.execute(query, (artistid, albumid, artistname)) + # Update discography + query = ( + ''' + INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear) + VALUES (?, ?, ?) + ''' + ) + kodicursor.execute(query, (artistid, name, year)) + # Update emby reference with parentid + emby_db.updateParentId(artistId, albumid) # Add genres kodi_db.addMusicGenres(albumid, genres, "album") # Update artwork artwork.addArtwork(artworks, albumid, "album", kodicursor) - def add_updateSong(self, item): + def add_updateSong(self, item, viewtag=None, viewid=None): # Process single song kodiversion = self.kodiversion kodicursor = self.kodicursor emby_db = self.emby_db kodi_db = self.kodi_db artwork = self.artwork - API = api.API(item) + API = PlexAPI.API(item) update_item = True - itemid = item['Id'] + itemid = API.getRatingKey() + if not itemid: + self.logMsg('Error processing Song; skipping', -1) + return emby_dbitem = emby_db.getItem_byId(itemid) try: songid = emby_dbitem[0] pathid = emby_dbitem[2] albumid = emby_dbitem[3] except TypeError: + # Songid not found update_item = False - self.logMsg("songid: %s not found." % itemid, 2) - - ##### The song details ##### + kodicursor.execute("select coalesce(max(idSong),0) from song") + songid = kodicursor.fetchone()[0] + 1 + + # The song details ##### checksum = API.getChecksum() dateadded = API.getDateCreated() userdata = API.getUserData() @@ -1825,94 +1836,75 @@ class Music(Items): dateplayed = userdata['LastPlayedDate'] # item details - title = item['Name'] - musicBrainzId = API.getProvider('MusicBrainzTrackId') - genres = item.get('Genres') - genre = " / ".join(genres) - artists = " / ".join(item['Artists']) - tracknumber = item.get('IndexNumber', 0) - disc = item.get('ParentIndexNumber', 1) + title, sorttitle = API.getTitle() + # musicBrainzId = API.getProvider('MusicBrainzTrackId') + musicBrainzId = None + genres = API.getGenres() + genre = API.joinList(genres) + artists = item.attrib.get('grandparentTitle') + tracknumber = int(item.attrib.get('index', 0)) + disc = int(item.attrib.get('parentIndex', 1)) if disc == 1: track = tracknumber else: track = disc*2**16 + tracknumber - year = item.get('ProductionYear') - duration = API.getRuntime() + year = API.getYear() + resume, duration = API.getRuntime() rating = userdata['UserRating'] - #if enabled, try to get the rating from file and/or emby - if not self.directstream: - rating, comment, hasEmbeddedCover = musicutils.getAdditionalSongTags(itemid, rating, API, kodicursor, emby_db, self.enableimportsongrating, self.enableexportsongrating, self.enableupdatesongrating) - else: - hasEmbeddedCover = False - comment = API.getOverview() - - - ##### GET THE FILE AND PATH ##### + comment = None + + # Plex works a bit differently if self.directstream: - path = "%s/emby/Audio/%s/" % (self.server, itemid) - filename = "stream.mp3" + paths = "%s%s" % (self.server, item[0][0][0].attrib.get('key')) + paths = paths.rsplit('/', 1) + path = paths[0] + filename = paths[1] else: - playurl = API.getKey() + path = "plugin://plugin.video.plexkodiconnect.movies/" + filename = API.getKey() + params = { + 'filename': filename, + 'id': itemid, + 'dbid': songid, + 'mode': "play" + } + filename = "%s?%s" % (path, urllib.urlencode(params)) - if "\\" in playurl: - # Local path - filename = playurl.rsplit("\\", 1)[1] - else: # Network share - filename = playurl.rsplit("/", 1)[1] - - # Direct paths is set the Kodi way - if utils.window('emby_pathverified') != "true" and not xbmcvfs.exists(playurl): - # Validate the path is correct with user intervention - utils.window('emby_directPath', clear=True) - resp = xbmcgui.Dialog().yesno( - heading="Can't validate path", - line1=( - "Kodi can't locate file: %s. Verify the path. " - "You may to verify your network credentials in the " - "add-on settings or use the emby path substitution " - "to format your path correctly. Stop syncing?" - % playurl)) - if resp: - utils.window('emby_shouldStop', value="true") - return False - - path = playurl.replace(filename, "") - utils.window('emby_pathverified', value="true") - - ##### UPDATE THE SONG ##### + # UPDATE THE SONG ##### if update_item: - self.logMsg("UPDATE song itemid: %s - Title: %s" % (itemid, title), 1) - + self.logMsg("UPDATE song itemid: %s - Title: %s" + % (itemid, title), 1) # Update path query = "UPDATE path SET strPath = ? WHERE idPath = ?" kodicursor.execute(query, (path, pathid)) # Update the song entry query = ' '.join(( - "UPDATE song", "SET idAlbum = ?, strArtists = ?, strGenres = ?, strTitle = ?, iTrack = ?,", "iDuration = ?, iYear = ?, strFilename = ?, iTimesPlayed = ?, lastplayed = ?,", "rating = ?, comment = ?", "WHERE idSong = ?" )) - kodicursor.execute(query, (albumid, artists, genre, title, track, duration, year, - filename, playcount, dateplayed, rating, comment, songid)) + kodicursor.execute(query, (albumid, artists, genre, title, track, + duration, year, filename, playcount, + dateplayed, rating, comment, songid)) # Update the checksum in emby table emby_db.updateReference(itemid, checksum) - - ##### OR ADD THE SONG ##### + + # OR ADD THE SONG ##### else: self.logMsg("ADD song itemid: %s - Title: %s" % (itemid, title), 1) - + # Add path pathid = kodi_db.addPath(path) try: # Get the album - emby_dbalbum = emby_db.getItem_byId(item['AlbumId']) + emby_dbalbum = emby_db.getItem_byId( + item.attrib.get('parentRatingKey')) albumid = emby_dbalbum[0] except KeyError: # No album Id associated to the song. @@ -1921,8 +1913,8 @@ class Music(Items): except TypeError: # No album found. Let's create it self.logMsg("Album database entry missing.", 1) - emby_albumId = item['AlbumId'] - album = self.emby.getItem(emby_albumId) + emby_albumId = item.attrib.get('parentRatingKey') + album = GetPlexMetadata(emby_albumId) self.add_updateAlbum(album) emby_dbalbum = emby_db.getItem_byId(emby_albumId) try: @@ -1963,10 +1955,8 @@ class Music(Items): ''' ) kodicursor.execute(query, (albumid, genre, year, dateadded)) - + # Create the song entry - kodicursor.execute("select coalesce(max(idSong),0) from song") - songid = kodicursor.fetchone()[0] + 1 query = ( ''' INSERT INTO song( @@ -1977,25 +1967,27 @@ class Music(Items): VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''' ) - kodicursor.execute(query, (songid, albumid, pathid, artists, genre, title, track, - duration, year, filename, musicBrainzId, playcount, dateplayed, rating)) + kodicursor.execute( + query, (songid, albumid, pathid, artists, genre, title, track, + duration, year, filename, musicBrainzId, playcount, + dateplayed, rating)) # Create the reference in emby table - emby_db.addReference(itemid, songid, "Audio", "song", pathid=pathid, parentid=albumid, + emby_db.addReference( + itemid, songid, "Audio", "song", pathid=pathid, + parentid=albumid, checksum=checksum) - # Link song to album query = ( ''' INSERT OR REPLACE INTO albuminfosong( idAlbumInfoSong, idAlbumInfo, iTrack, strTitle, iDuration) - + VALUES (?, ?, ?, ?, ?) ''' ) kodicursor.execute(query, (songid, albumid, track, title, duration)) - # Verify if album has artists addArtist = False query = ' '.join(( @@ -2009,112 +2001,59 @@ class Music(Items): if result and result[0] == "": addArtist = True - if item['AlbumArtists']: - album_artists = item['AlbumArtists'] - else: - album_artists = item['ArtistItems'] + # if item['AlbumArtists']: + # album_artists = item['AlbumArtists'] + # else: + # album_artists = item['ArtistItems'] # Link song to artist - artists_name = [] - for artist in album_artists: - artist_name = artist['Name'] - artists_name.append(artist_name) - emby_dbartist = emby_db.getItem_byId(artist['Id']) - try: - artistid = emby_dbartist[0] - except: pass - else: + artist_name = item.attrib.get('grandparentTitle') + emby_dbartist = emby_db.getItem_byId( + item.attrib.get('grandparentRatingKey')) + try: + artistid = emby_dbartist[0] + except: + pass + else: + query = ( + ''' + INSERT OR REPLACE INTO song_artist(idArtist, idSong, strArtist) + + VALUES (?, ?, ?) + ''' + ) + kodicursor.execute(query, (artistid, songid, artist_name)) + + if addArtist: query = ( ''' - INSERT OR REPLACE INTO song_artist(idArtist, idSong, strArtist) + INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist) VALUES (?, ?, ?) ''' ) - kodicursor.execute(query, (artistid, songid, artist_name)) + kodicursor.execute(query, (artistid, albumid, artist_name)) - if addArtist: - query = ( - ''' - INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist) - - VALUES (?, ?, ?) - ''' - ) - kodicursor.execute(query, (artistid, albumid, artist_name)) - else: - if addArtist: - artists_onalbum = " / ".join(artists_name) - if kodiversion in (16, 17): - # Kodi Jarvis, Krypton - query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?" - kodicursor.execute(query, (artists_onalbum, albumid)) - elif kodiversion == 15: - # Kodi Isengard - query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?" - kodicursor.execute(query, (artists_onalbum, albumid)) - else: - # Kodi Helix - query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?" - kodicursor.execute(query, (artists_onalbum, albumid)) + if addArtist: + if kodiversion in (16, 17): + # Kodi Jarvis, Krypton + query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?" + kodicursor.execute(query, (artist_name, albumid)) + elif kodiversion == 15: + # Kodi Isengard + query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?" + kodicursor.execute(query, (artist_name, albumid)) + else: + # Kodi Helix + query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?" + kodicursor.execute(query, (artist_name, albumid)) # Add genres kodi_db.addMusicGenres(songid, genres, "song") # Update artwork - allart = artwork.getAllArtwork(item, parentInfo=True) - if hasEmbeddedCover: - allart["Primary"] = "image://music@" + artwork.single_urlencode( playurl ) + allart = API.getAllArtwork(parentInfo=True) artwork.addArtwork(allart, songid, "song", kodicursor) - def updateUserdata(self, item): - # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks - # Poster with progress bar - kodicursor = self.kodicursor - emby_db = self.emby_db - kodi_db = self.kodi_db - API = api.API(item) - - # Get emby information - itemid = item['Id'] - checksum = API.getChecksum() - userdata = API.getUserData() - runtime = API.getRuntime() - rating = userdata['UserRating'] - - # Get Kodi information - emby_dbitem = emby_db.getItem_byId(itemid) - try: - kodiid = emby_dbitem[0] - mediatype = emby_dbitem[4] - self.logMsg("Update playstate for %s: %s" % (mediatype, item['Name']), 1) - except TypeError: - return - - if mediatype == "song": - - #should we ignore this item ? - #happens when userdata updated by ratings method - if utils.window("ignore-update-%s" %itemid): - utils.window("ignore-update-%s" %itemid,clear=True) - return - - # Process playstates - playcount = userdata['PlayCount'] - dateplayed = userdata['LastPlayedDate'] - - #process item ratings - rating, comment, hasEmbeddedCover = musicutils.getAdditionalSongTags(itemid, rating, API, kodicursor, emby_db, self.enableimportsongrating, self.enableexportsongrating, self.enableupdatesongrating) - - query = "UPDATE song SET iTimesPlayed = ?, lastplayed = ?, rating = ? WHERE idSong = ?" - kodicursor.execute(query, (playcount, dateplayed, rating, kodiid)) - - elif mediatype == "album": - # Process playstates - query = "UPDATE album SET iRating = ? WHERE idAlbum = ?" - kodicursor.execute(query, (rating, kodiid)) - - emby_db.updateReference(itemid, checksum) - def remove(self, itemid): # Remove kodiid, fileid, pathid, emby reference emby_db = self.emby_db diff --git a/resources/lib/kodidb_functions.py b/resources/lib/kodidb_functions.py index 0e0a7ac8..f4697738 100644 --- a/resources/lib/kodidb_functions.py +++ b/resources/lib/kodidb_functions.py @@ -740,7 +740,6 @@ class Kodidb_Functions(): cursor.execute(query, (kodiid, mediatype)) # Add tags - self.logMsg("Adding Tags: %s" % tags, 2) for tag in tags: self.addTag(kodiid, tag, mediatype) diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index 8517368f..f5c9d8fa 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -20,7 +20,6 @@ import read_embyserver as embyserver import userclient import videonodes -import PlexAPI import PlexFunctions ############################################################################### @@ -125,9 +124,14 @@ class ThreadedProcessMetadata(Thread): with lock: # Get the one child entry in the xml and process for child in plexitem: - itemSubFkt(child, - viewtag=viewName, - viewid=viewId) + if method == 'add_updateAlbum': + item.add_updateAlbum(child, + viewtag=viewName, + viewid=viewId) + else: + itemSubFkt(child, + viewtag=viewName, + viewid=viewId) # Keep track of where we are at processMetadataCount += 1 processingViewName = title @@ -219,6 +223,8 @@ class LibrarySync(Thread): utils.settings('SyncInstallRunDone') == 'true' else False self.showDbSync = True if \ utils.settings('dbSyncIndicator') == 'true' else False + self.enableMusic = True if utils.settings('enableMusic') == "true" \ + else False Thread.__init__(self) @@ -250,6 +256,13 @@ class LibrarySync(Thread): Using /library/recentlyAdded is NOT working as changes to lib items are not reflected + + This will NOT remove items from Kodi db that were removed from the PMS + (happens only during fullsync) + + Currently, ALL items returned by the PMS (because they've just been + edited by the PMS or have been watched) will be processed. This will + probably happen several times. """ self.compare = True # Get last sync time @@ -262,29 +275,22 @@ class LibrarySync(Thread): # Set new timestamp NOW because sync might take a while self.saveLastSync() - # Get all PMS items already saved in Kodi + # Original idea: Get all PMS items already saved in Kodi # Also get checksums of every Plex items already saved in Kodi - allKodiElementsId = {} - with embydb.GetEmbyDB() as emby_db: - for itemtype in PlexFunctions.EmbyItemtypes(): - try: - allKodiElementsId.update( - dict(emby_db.getChecksum(itemtype))) - except ValueError: - pass - - self.allKodiElementsId = allKodiElementsId + # NEW idea: process every item returned by the PMS + self.allKodiElementsId = {} # Run through views and get latest changed elements using time diff - self.updatelist = [] - self.allPlexElementsId = {} self.updateKodiVideoLib = False + self.updateKodiMusicLib = False for view in self.views: + self.updatelist = [] if self.threadStopped(): return True # Get items per view items = PlexFunctions.GetAllPlexLeaves( view['id'], updatedAt=lastSync) + # Just skip item if something went wrong if not items: continue # Get one itemtype, because they're the same in the PMS section @@ -299,21 +305,28 @@ class LibrarySync(Thread): if self.updatelist: if self.updatelist[0]['itemType'] in ['Movies', 'TVShows']: self.updateKodiVideoLib = True + elif self.updatelist[0]['itemType'] == 'Music': + self.updateKodiMusicLib = True self.GetAndProcessXMLs( PlexFunctions.GetItemClassFromType(plexType)) self.updatelist = [] + # Update userdata for view in self.views: self.PlexUpdateWatched( view['id'], PlexFunctions.GetItemClassFromType(view['itemtype']), lastViewedAt=lastSync) + # Let Kodi update the library now (artwork and userdata) if self.updateKodiVideoLib: self.logMsg("Doing Kodi Video Lib update", 2) xbmc.executebuiltin('UpdateLibrary(video)') + if self.updateKodiMusicLib: + self.logMsg("Doing Kodi Music Lib update", 2) + xbmc.executebuiltin('UpdateLibrary(music)') + # Reset and return - self.allKodiElementsId = {} self.allPlexElementsId = {} return True @@ -346,7 +359,6 @@ class LibrarySync(Thread): def fullSync(self, manualrun=False, repair=False): # Only run once when first setting up. Can be run manually. self.compare = manualrun or repair - music_enabled = utils.settings('enableMusic') == "true" # Add sources utils.sourcesXML() @@ -367,18 +379,12 @@ class LibrarySync(Thread): # Set views self.maintainViews() - # Sync video library - # process = { - - # 'movies': self.movies, - # 'musicvideos': self.musicvideos, - # 'tvshows': self.tvshows - # } - process = { 'movies': self.PlexMovies, - 'tvshows': self.PlexTVShows + 'tvshows': self.PlexTVShows, } + if self.enableMusic: + process['music'] = self.PlexMusic for itemtype in process: startTime = datetime.now() @@ -391,33 +397,12 @@ class LibrarySync(Thread): "SyncDatabase (finished %s in: %s)" % (itemtype, str(elapsedTime).split('.')[0]), 1) - # # sync music - # if music_enabled: - - # musicconn = utils.kodiSQL('music') - # musiccursor = musicconn.cursor() - - # startTime = datetime.now() - # completed = self.music(embycursor, musiccursor, pDialog) - # if not completed: - - # utils.window('emby_dbScan', clear=True) - - # embycursor.close() - # musiccursor.close() - # return False - # else: - # musicconn.commit() - # embyconn.commit() - # elapsedTime = datetime.now() - startTime - # self.logMsg( - # "SyncDatabase (finished music in: %s)" - # % (str(elapsedTime).split('.')[0]), 1) - # musiccursor.close() - + # Let kodi update the views in any case xbmc.executebuiltin('UpdateLibrary(video)') - elapsedtotal = datetime.now() - starttotal + if self.enableMusic: + xbmc.executebuiltin('UpdateLibrary(music)') + elapsedtotal = datetime.now() - starttotal utils.window('emby_initialScan', clear=True) self.showKodiNote("%s completed in: %s" % (message, str(elapsedtotal).split('.')[0])) @@ -429,7 +414,8 @@ class LibrarySync(Thread): folder = folderItem.attrib mediatype = folder['type'] # Only process supported formats - if mediatype not in ['movie', 'show']: + supportedMedia = ['movie', 'show'] + if mediatype not in supportedMedia: return folderid = folder['key'] @@ -565,11 +551,24 @@ class LibrarySync(Thread): # update views for all: self.views = emby_db.getAllViewInfo() + # Append music views only to self.views (no custom views otherwise) + if self.enableMusic: + for folderItem in result: + if folderItem.attrib['type'] == 'artist': + entry = { + 'id': folderItem.attrib['key'], + 'name': folderItem.attrib['title'], + 'itemtype': 'artist' + } + self.views.append(entry) + self.logMsg("views saved: %s" % self.views, 1) def GetUpdatelist(self, xml, itemType, method, viewName, viewId, dontCheck=False): """ + THIS METHOD NEEDS TO BE FAST! => e.g. no API calls + Adds items to self.updatelist as well as self.allPlexElementsId dict Input: @@ -599,13 +598,13 @@ class LibrarySync(Thread): if self.compare or not dontCheck: # Manual sync for item in xml: + itemId = item.attrib.get('ratingKey') # Skipping items 'title=All episodes' without a 'ratingKey' - if not item.attrib.get('ratingKey', False): + if not itemId: continue - API = PlexAPI.API(item) - itemId = API.getRatingKey() - title, sorttitle = API.getTitle() - plex_checksum = API.getChecksum() + title = item.attrib.get('title', 'Missing Title Name') + plex_checksum = ("K%s%s" + % (itemId, item.attrib.get('updatedAt', ''))) self.allPlexElementsId[itemId] = plex_checksum kodi_checksum = self.allKodiElementsId.get(itemId) if kodi_checksum != plex_checksum: @@ -620,13 +619,13 @@ class LibrarySync(Thread): else: # Initial or repair sync: get all Plex movies for item in xml: - # Only look at valid items = Plex library items - if not item.attrib.get('ratingKey', False): + itemId = item.attrib.get('ratingKey') + # Skipping items 'title=All episodes' without a 'ratingKey' + if not itemId: continue - API = PlexAPI.API(item) - itemId = API.getRatingKey() - title, sorttitle = API.getTitle() - plex_checksum = API.getChecksum() + title = item.attrib.get('title', 'Missing Title Name') + plex_checksum = ("K%s%s" + % (itemId, item.attrib.get('updatedAt', ''))) self.allPlexElementsId[itemId] = plex_checksum self.updatelist.append({'itemId': itemId, 'itemType': itemType, @@ -856,25 +855,14 @@ class LibrarySync(Thread): self.allKodiElementsId = {} if self.compare: with embydb.GetEmbyDB() as emby_db: - # Get movies from Plex server # Pull the list of TV shows already in Kodi - try: - all_koditvshows = dict(emby_db.getChecksum('Series')) - self.allKodiElementsId.update(all_koditvshows) - except ValueError: - pass - # Same for seasons - try: - all_kodiseasons = dict(emby_db.getChecksum('Season')) - self.allKodiElementsId.update(all_kodiseasons) - except ValueError: - pass - # Same for the episodes (sub-element of shows/series) - try: - all_kodiepisodes = dict(emby_db.getChecksum('Episode')) - self.allKodiElementsId.update(all_kodiepisodes) - except ValueError: - pass + for kind in ('Series', 'Season', 'Episode'): + try: + elements = dict(emby_db.getChecksum(kind)) + self.allKodiElementsId.update(elements) + # Yet empty/not yet synched + except ValueError: + pass ##### PROCESS TV Shows ##### self.updatelist = [] @@ -965,51 +953,84 @@ class LibrarySync(Thread): self.logMsg("%s sync is finished." % itemType, 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) + def PlexMusic(self): + itemType = 'Music' - process = { + views = [x for x in self.views if x['itemtype'] == 'artist'] + self.logMsg("Media folders for %s: %s" % (itemType, views), 1) - 'artists': [emby.getArtists, music.add_updateArtist], - 'albums': [emby.getAlbums, music.add_updateAlbum], - 'songs': [emby.getSongs, music.add_updateSong] + methods = { + 'MusicArtist': 'add_updateArtist', + 'MusicAlbum': 'add_updateAlbum', + 'Audio': 'add_updateSong' + } + urlArgs = { + 'MusicArtist': {'type': 8}, + 'MusicAlbum': {'type': 9}, + 'Audio': {'type': 10} } - types = ['artists', 'albums', 'songs'] - for type in types: - if pdialog: - pdialog.update( - heading="Emby for Kodi", - message="Gathering %s..." % type) - - all_embyitems = process[type][0](dialog=pdialog) - total = all_embyitems['TotalRecordCount'] - embyitems = all_embyitems['Items'] - - if pdialog: - pdialog.update(heading="Processing %s / %s items" % (type, total)) - - count = 0 - for embyitem in embyitems: - # Process individual item - if self.threadStopped(): - 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) - else: - self.logMsg("%s finished." % type, 2) + # Process artist, then album and tracks last + for kind in ('MusicArtist', 'MusicAlbum', 'Audio'): + if self.threadStopped(): + return True + self.logMsg("Start processing music %s" % kind, 1) + self.ProcessMusic( + views, kind, urlArgs[kind], methods[kind]) + self.logMsg("Processing of music %s done" % kind, 1) + self.GetAndProcessXMLs(itemType) + self.logMsg("GetAndProcessXMLs for music %s completed" % kind, 1) + # reset stuff + self.allKodiElementsId = {} + self.allPlexElementsId = {} + self.updatelist = [] + self.logMsg("%s sync is finished." % itemType, 1) return True + def ProcessMusic(self, views, kind, urlArgs, method): + self.allKodiElementsId = {} + self.allPlexElementsId = {} + self.updatelist = [] + + # Get a list of items already existing in Kodi db + if self.compare: + with embydb.GetEmbyDB() as emby_db: + # Pull the list of items already in Kodi + try: + elements = dict(emby_db.getChecksum(kind)) + self.allKodiElementsId.update(elements) + # Yet empty/nothing yet synched + except ValueError: + pass + + for view in views: + if self.threadStopped(): + return True + # Get items per view + viewId = view['id'] + viewName = view['name'] + itemsXML = PlexFunctions.GetPlexSectionResults( + viewId, args=urlArgs) + if not itemsXML: + self.logMsg("Error downloading xml for view %s" + % viewId, -1) + continue + # Populate self.updatelist and self.allPlexElementsId + self.GetUpdatelist(itemsXML, + 'Music', + method, + viewName, + viewId) + + # Remove items from Kodi db? + if self.compare: + # Manual sync, process deletes + with itemtypes.Music() as Music: + for item in self.allKodiElementsId: + if item not in self.allPlexElementsId: + Music.remove(item) + 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)