# -*- coding: utf-8 -*- ################################################################################################# # WriteKodiMusicDB ################################################################################################# import sqlite3 from datetime import datetime from ntpath import split as ntsplit import xbmc import xbmcgui import xbmcaddon from ClientInformation import ClientInformation import Utils as utils from API import API from PlayUtils import PlayUtils from ReadKodiDB import ReadKodiDB from ReadEmbyDB import ReadEmbyDB from TextureCache import TextureCache class WriteKodiMusicDB(): textureCache = TextureCache() kodiversion = int(xbmc.getInfoLabel("System.BuildVersion")[:2]) addon = xbmcaddon.Addon() addonName = ClientInformation().getAddonName() WINDOW = xbmcgui.Window(10000) username = WINDOW.getProperty('currUser') userid = WINDOW.getProperty('userId%s' % username) server = WINDOW.getProperty('server%s' % username) directpath = addon.getSetting('useDirectPaths') == "true" def logMsg(self, msg, lvl = 1): className = self.__class__.__name__ utils.logMsg("%s %s" % (self.addonName, className), msg, int(lvl)) def addOrUpdateArtistToKodiLibrary(self, embyId, connection, cursor): MBitem = ReadEmbyDB().getFullItem(embyId) if not MBitem: self.logMsg("ADD or UPDATE artist to Kodi library FAILED!, Id: %s" %(embyId), 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 cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (embyId,)) try: artistid = cursor.fetchone()[0] except: artistid = None ##### The artist details ##### lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S') dateadded = API().getDateCreated(MBitem) checksum = API().getChecksum(MBitem) name = MBitem['Name'] musicBrainzId = API().getProvider(MBitem, "musicBrainzArtist") genres = " / ".join(MBitem.get('Genres')) bio = API().getOverview(MBitem) # Associate artwork thumb = API().getArtwork(MBitem, "Primary") if thumb: thumb = "%s" % thumb fanart = API().getArtwork(MBitem, "Backdrop") if fanart: fanart = "%s" % fanart # Safety check 1: does the artist already exist? cursor.execute("SELECT idArtist FROM artist WHERE strArtist = ?", (name,)) try: artistid = cursor.fetchone()[0] except: pass # Safety check 2: does the MusicBrainzArtistId already exist? cursor.execute("SELECT idArtist FROM artist WHERE strMusicBrainzArtistID = ?", (musicBrainzId,)) try: artistid = cursor.fetchone()[0] except: pass ##### UPDATE THE ARTIST ##### if artistid: self.logMsg("UPDATE artist to Kodi library, Id: %s - Artist: %s" % (embyId, name), 1) query = "UPDATE artist SET strArtist = ?, strMusicBrainzArtistID = ?, strGenres = ?, strBiography = ?, strImage = ?, strFanart = ?, lastScraped = ?, dateadded = ? WHERE idArtist = ?" cursor.execute(query, (name, musicBrainzId, genres, bio, thumb, fanart, lastScraped, dateadded, artistid)) # Update the checksum in emby table query = "UPDATE emby SET checksum = ? WHERE emby_id = ?" cursor.execute(query, (checksum, embyId)) ##### OR ADD THE ARTIST ##### else: self.logMsg("ADD artist to Kodi library, Id: %s - Artist: %s" % (embyId, name), 1) # Create the artist cursor.execute("select coalesce(max(idArtist),0) as artistid from artist") artistid = cursor.fetchone()[0] + 1 query = "INSERT INTO artist(idArtist, strArtist, strMusicBrainzArtistID, strGenres, strBiography, strImage, strFanart, lastScraped, dateAdded) values(?, ?, ?, ?, ?, ?, ?, ?, ?)" cursor.execute(query, (artistid, name, musicBrainzId, genres, bio, thumb, fanart, lastScraped, dateadded)) # Create the reference in emby table query = "INSERT INTO emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)" cursor.execute(query, (embyId, artistid, "artist", checksum)) # Update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), artistid, "artist", "thumb", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), artistid, "artist", "poster", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Banner"), artistid, "artist", "banner", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Logo"), artistid, "artist", "clearlogo", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Art"), artistid, "artist", "clearart", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Thumb"), artistid, "artist", "landscape", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Disc"), artistid, "artist", "discart", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Backdrop"), artistid, "artist", "fanart", cursor) def addOrUpdateAlbumToKodiLibrary(self, embyId, connection, cursor): kodiVersion = self.kodiversion MBitem = ReadEmbyDB().getFullItem(embyId) # 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 cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (embyId,)) try: albumid = cursor.fetchone()[0] except: albumid = None genres = MBitem.get('Genres') ##### The album details ##### lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S') dateadded = API().getDateCreated(MBitem) checksum = API().getChecksum(MBitem) name = MBitem['Name'] musicBrainzId = API().getProvider(MBitem, "musicBrainzAlbum") year = MBitem.get('ProductionYear') genre = " / ".join(genres) bio = API().getOverview(MBitem) MBartists = [] for item in MBitem['AlbumArtists']: MBartists.append(item['Name']) artists = " / ".join(MBartists) # Associate the artwork thumb = API().getArtwork(MBitem, "Primary") if thumb: thumb = "%s" % thumb ##### UPDATE THE ALBUM ##### if albumid: self.logMsg("UPDATE album to Kodi library, Id: %s - Title: %s" % (embyId, name), 1) if kodiVersion == 15 or kodiVersion == 16: # Kodi Isengard query = "UPDATE album SET strAlbum = ?, strMusicBrainzAlbumID = ?, strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?, lastScraped = ?, dateAdded = ?, strReleaseType = ? WHERE idAlbum = ?" cursor.execute(query, (name, musicBrainzId, artists, year, genre, bio, thumb, lastScraped, dateadded, "album", albumid)) else: # Kodi Gotham and Helix query = "UPDATE album SET strAlbum = ?, strMusicBrainzAlbumID = ?, strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?, lastScraped = ?, dateAdded = ? WHERE idAlbum = ?" cursor.execute(query, (name, musicBrainzId, artists, year, genre, bio, thumb, lastScraped, dateadded, albumid)) # Update the checksum in emby table query = "UPDATE emby SET checksum = ? WHERE emby_id = ?" cursor.execute(query, (checksum, embyId)) ##### OR ADD THE ALBUM ##### else: self.logMsg("ADD album to Kodi library, Id: %s - Title: %s" % (embyId, name), 1) # Safety check: does the strMusicBrainzAlbumID already exist? cursor.execute("SELECT idAlbum FROM album WHERE strMusicBrainzAlbumID = ?", (musicBrainzId,)) try: albumid = cursor.fetchone()[0] except: # Create the album cursor.execute("select coalesce(max(idAlbum),0) as albumid from album") albumid = cursor.fetchone()[0] + 1 if kodiVersion == 15 or kodiVersion == 16: # Kodi Isengard query = "INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID, strArtists, iYear, strGenres, strReview, strImage, lastScraped, dateAdded, strReleaseType) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" cursor.execute(query, (albumid, name, musicBrainzId, artists, year, genre, bio, thumb, lastScraped, dateadded, "album")) else: # Kodi Gotham and Helix query = "INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID, strArtists, iYear, strGenres, strReview, strImage, lastScraped, dateAdded) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" cursor.execute(query, (albumid, name, musicBrainzId, artists, year, genre, bio, thumb, lastScraped, dateadded)) # Create the reference in emby table query = "INSERT INTO emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)" cursor.execute(query, (embyId, albumid, "album", checksum)) # Add genres self.AddGenresToMedia(albumid, genres, "album", cursor) # Update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), albumid, "album", "thumb", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "BoxRear"), albumid, "album", "poster", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Banner"), albumid, "album", "banner", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Logo"), albumid, "album", "clearlogo", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Art"), albumid, "album", "clearart", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Thumb"), albumid, "album", "landscape", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Disc"), albumid, "album", "discart", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Backdrop"), albumid, "album", "fanart", cursor) # Link album to artists if MBartists: album_artists = MBitem['AlbumArtists'] elif MBitem.get('ArtistItems'): album_artists = MBitem['ArtistItems'] for artist in album_artists: cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (artist['Id'],)) try: artistid = cursor.fetchone()[0] except: pass else: query = "INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist) values(?, ?, ?)" cursor.execute(query, (artistid, albumid, artist['Name'])) # Update discography query = "INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear) values(?, ?, ?)" cursor.execute(query, (artistid, name, str(year))) def addOrUpdateSongToKodiLibrary(self, embyId, connection, cursor): kodiVersion = self.kodiversion MBitem = ReadEmbyDB().getFullItem(embyId) # 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 cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (embyId,)) try: songid = cursor.fetchone()[0] except: songid = None timeInfo = API().getTimeInfo(MBitem) userData = API().getUserData(MBitem) genres = MBitem.get('Genres') ##### The song details ##### playcount = userData.get('PlayCount') lastplayed = userData.get('LastPlayedDate') dateadded = API().getDateCreated(MBitem) checksum = API().getChecksum(MBitem) name = MBitem['Name'] musicBrainzId = API().getProvider(MBitem, "musicBrainzTrackId") genre = " / ".join(genres) artists = " / ".join(MBitem.get('Artists')) track = MBitem.get('IndexNumber') year = MBitem.get('ProductionYear') bio = API().getOverview(MBitem) duration = timeInfo.get('TotalTime') # Get the path and filename playurl = PlayUtils().directPlay(MBitem) try: path, filename = ntsplit(playurl) if "/" in playurl: path = "%s/" % path elif "\\" in playurl: path = "%s\\" % path except: # playurl returned false - using server streaming path, because could not figure out plugin paths for music DB playurl = PlayUtils().directstream(MBitem, self.server, embyId, "Audio") filename = "stream.mp3" path = playurl.replace(filename, "") # Validate the path in database cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?", (path,)) try: pathid = cursor.fetchone()[0] except: cursor.execute("select coalesce(max(idPath),0) as pathid from path") pathid = cursor.fetchone()[0] + 1 query = "INSERT INTO path(idPath, strPath) values(?, ?)" cursor.execute(query, (pathid, path)) # Get the album cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (MBitem.get("AlbumId"),)) try: albumid = cursor.fetchone()[0] except: # No album found, create a single's album cursor.execute("select coalesce(max(idAlbum),0) as albumid from album") albumid = cursor.fetchone()[0] + 1 if kodiVersion == 15 or kodiVersion == 16: # Kodi Isengard query = "INSERT INTO album(idAlbum, strArtists, strGenres, iYear, dateAdded, strReleaseType) values(?, ?, ?, ?, ?, ?)" cursor.execute(query, (albumid, artists, genre, year, dateadded, "single")) else: # Kodi Gotham and Helix query = "INSERT INTO album(idAlbum, strArtists, strGenres, iYear, dateAdded) values(?, ?, ?, ?, ?)" cursor.execute(query, (albumid, artists, genre, year, dateadded)) # Link album to artists for artist in MBitem['ArtistItems']: cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (artist['Id'],)) try: artistid = cursor.fetchone()[0] except: pass else: query = "INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist) values(?, ?, ?)" cursor.execute(query, (artistid, albumid, artist['Name'])) ##### UPDATE THE SONG ##### if songid: self.logMsg("UPDATE song to Kodi library, Id: %s - Title: %s" % (embyId, name), 1) query = "UPDATE song SET idAlbum = ?, strArtists = ?, strGenres = ?, strTitle = ?, iTrack = ?, iDuration = ?, iYear = ?, strFilename = ?, strMusicBrainzTrackID = ?, iTimesPlayed = ?, lastplayed = ? WHERE idSong = ?" cursor.execute(query, (albumid, artists, genre, name, track, duration, year, filename, musicBrainzId, playcount, lastplayed, songid)) # Update the checksum in emby table query = "UPDATE emby SET checksum = ? WHERE emby_id = ?" cursor.execute(query, (checksum, embyId)) ##### OR ADD THE SONG ##### else: self.logMsg("ADD song to Kodi library, Id: %s - Title: %s" % (embyId, name), 1) # Create the song cursor.execute("select coalesce(max(idSong),0) as songid from song") songid = cursor.fetchone()[0] + 1 query = "INSERT INTO song(idSong, idAlbum, idPath, strArtists, strGenres, strTitle, iTrack, iDuration, iYear, strFileName, strMusicBrainzTrackID, iTimesPlayed, lastplayed) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" cursor.execute(query, (songid, albumid, pathid, artists, genre, name, track, duration, year, filename, musicBrainzId, playcount, lastplayed)) # Create the reference in emby table query = "INSERT INTO emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)" cursor.execute(query, (embyId, songid, "song", checksum)) # Add genres self.AddGenresToMedia(songid, genres, "song", cursor) # Link song to album if albumid: query = "INSERT OR REPLACE INTO albuminfosong(idAlbumInfoSong, idAlbumInfo, iTrack, strTitle, iDuration) values(?, ?, ?, ?, ?)" cursor.execute(query, (songid, albumid, track, name, duration)) # Link song to artist for artist in MBitem.get('ArtistItems'): cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (artist['Id'],)) try: artistid = cursor.fetchone()[0] except: pass else: query = "INSERT OR REPLACE INTO song_artist(idArtist, idSong, strArtist) values(?, ?, ?)" cursor.execute(query, (artistid, songid, artist['Name'])) # Update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), songid, "song", "thumb", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), songid, "song", "poster", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Banner"), songid, "song", "banner", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Logo"), songid, "song", "clearlogo", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Art"), songid, "song", "clearart", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Thumb"), songid, "song", "landscape", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Disc"), songid, "song", "discart", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Backdrop"), songid, "song", "fanart", cursor) def deleteItemFromKodiLibrary(self, id, connection, cursor): cursor.execute("SELECT kodi_id, media_type FROM emby WHERE emby_id=?", (id,)) try: result = cursor.fetchone() kodi_id = result[0] media_type = result[1] except: pass else: if "artist" in media_type: self.logMsg("Deleting artist from Kodi library, Id: %s" % id, 1) cursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodi_id,)) elif "song" in media_type: self.logMsg("Deleting song from Kodi library, Id: %s" % id, 1) cursor.execute("DELETE FROM song WHERE idSong = ?", (kodi_id,)) elif "album" in media_type: self.logMsg("Deleting album from Kodi library, Id: %s" % id, 1) cursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodi_id,)) # Delete the record in emby table cursor.execute("DELETE FROM emby WHERE emby_id = ?", (id,)) def addOrUpdateArt(self, imageUrl, kodiId, mediaType, imageType, cursor): if imageUrl: cacheimage = False cursor.execute("SELECT url FROM art WHERE media_id = ? AND media_type = ? AND type = ?", (kodiId, mediaType, imageType,)) try: url = cursor.fetchone()[0] except: # Image does not exists cacheimage = True self.logMsg("Adding Art Link for kodiId: %s (%s)" % (kodiId, imageUrl), 1) query = "INSERT INTO art(media_id, media_type, type, url) values(?, ?, ?, ?)" cursor.execute(query, (kodiId, mediaType, imageType, imageUrl)) else: if url != imageUrl: cacheimage = True self.logMsg("Updating Art Link for kodiId: %s (%s) -> (%s)" % (kodiId, url, imageUrl), 1) query = "UPDATE art SET url = ? WHERE media_id = ? and media_type = ? and type = ?" cursor.execute(query, (imageUrl, kodiId, mediaType, imageType)) # Cache fanart textures in Kodi texture cache if cacheimage and "fanart" in imageType: self.textureCache.CacheTexture(imageUrl) def AddGenresToMedia(self, id, genres, mediatype, cursor): if genres: for genre in genres: cursor.execute("SELECT idGenre as idGenre FROM genre WHERE strGenre = ?", (genre,)) try: idGenre = cursor.fetchone()[0] except: # Create the genre cursor.execute("select coalesce(max(idGenre),0) as idGenre from genre") idGenre = cursor.fetchone()[0] + 1 query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)" cursor.execute(query, (idGenre, genre)) finally: # Assign the genre to item if "album" in mediatype: query = "INSERT OR REPLACE INTO album_genre(idGenre, idAlbum) values(?, ?)" cursor.execute(query, (idGenre, id)) elif "song" in mediatype: query = "INSERT OR REPLACE INTO song_genre(idGenre, idSong) values(?, ?)" cursor.execute(query, (idGenre, id))