add first support for music library sync

This commit is contained in:
Marcel van der Veldt 2015-05-08 00:04:40 +02:00
parent 87681ee850
commit 8839b3b323
7 changed files with 760 additions and 13 deletions

View file

@ -332,7 +332,7 @@ class API():
if(data.get("ImageTags") != None and data.get("ImageTags").get(type) != None): if(data.get("ImageTags") != None and data.get("ImageTags").get(type) != None):
imageTag = data.get("ImageTags").get(type) imageTag = data.get("ImageTags").get(type)
if (data.get("Type") == "Episode" or data.get("Type") == "Season") and type=="Logo": if (data.get("Type") == "Episode" or data.get("Type") == "Season" or data.get("Type") == "MusicAlbum") and type=="Logo":
imageTag = data.get("ParentLogoImageTag") imageTag = data.get("ParentLogoImageTag")
if (data.get("Type") == "Episode" or data.get("Type") == "Season") and type=="Art": if (data.get("Type") == "Episode" or data.get("Type") == "Season") and type=="Art":
imageTag = data.get("ParentArtImageTag") imageTag = data.get("ParentArtImageTag")

View file

@ -22,6 +22,7 @@ from DownloadUtils import DownloadUtils
from ReadEmbyDB import ReadEmbyDB from ReadEmbyDB import ReadEmbyDB
from ReadKodiDB import ReadKodiDB from ReadKodiDB import ReadKodiDB
from WriteKodiVideoDB import WriteKodiVideoDB from WriteKodiVideoDB import WriteKodiVideoDB
from WriteKodiMusicDB import WriteKodiMusicDB
from VideoNodes import VideoNodes from VideoNodes import VideoNodes
addondir = xbmc.translatePath(xbmcaddon.Addon(id='plugin.video.emby').getAddonInfo('profile')) addondir = xbmc.translatePath(xbmcaddon.Addon(id='plugin.video.emby').getAddonInfo('profile'))
@ -40,6 +41,7 @@ class LibrarySync():
startupDone = WINDOW.getProperty("startup") == "done" startupDone = WINDOW.getProperty("startup") == "done"
syncInstallRunDone = addon.getSetting("SyncInstallRunDone") == "true" syncInstallRunDone = addon.getSetting("SyncInstallRunDone") == "true"
performMusicSync = addon.getSetting("enableMusicSync") == "true"
dbSyncIndication = addon.getSetting("dbSyncIndication") == "true" dbSyncIndication = addon.getSetting("dbSyncIndication") == "true"
WINDOW.setProperty("SyncDatabaseRunning", "true") WINDOW.setProperty("SyncDatabaseRunning", "true")
@ -56,7 +58,15 @@ class LibrarySync():
try: try:
completed = True completed = True
connection = utils.KodiSQL()
### BUILD VIDEO NODES LISTING ###
VideoNodes().buildVideoNodesListing()
### PROCESS VIDEO LIBRARY ###
#create the sql connection to video db
connection = utils.KodiSQL("video")
cursor = connection.cursor() cursor = connection.cursor()
#Add the special emby table #Add the special emby table
@ -64,9 +74,6 @@ class LibrarySync():
cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER)") cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER)")
connection.commit() connection.commit()
### BUILD VIDEO NODES LISTING ###
VideoNodes().buildVideoNodesListing()
# sync movies # sync movies
self.MoviesFullSync(connection,cursor,pDialog) self.MoviesFullSync(connection,cursor,pDialog)
@ -82,6 +89,23 @@ class LibrarySync():
# sync musicvideos # sync musicvideos
self.MusicVideosFullSync(connection,cursor,pDialog) self.MusicVideosFullSync(connection,cursor,pDialog)
#close sql connection
cursor.close()
### PROCESS MUSIC LIBRARY ###
if performMusicSync:
#create the sql connection to music db
connection = utils.KodiSQL("music")
cursor = connection.cursor()
#Add the special emby table
if not startupDone:
cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER)")
connection.commit()
self.MusicFullSync(connection,cursor,pDialog)
cursor.close()
# set the install done setting # set the install done setting
if(syncInstallRunDone == False and completed): if(syncInstallRunDone == False and completed):
addon = xbmcaddon.Addon(id='plugin.video.emby') #force a new instance of the addon addon = xbmcaddon.Addon(id='plugin.video.emby') #force a new instance of the addon
@ -97,7 +121,6 @@ class LibrarySync():
WINDOW.setProperty("SyncDatabaseRunning", "false") WINDOW.setProperty("SyncDatabaseRunning", "false")
utils.logMsg("Sync DB", "syncDatabase Exiting", 0) utils.logMsg("Sync DB", "syncDatabase Exiting", 0)
cursor.close()
if(pDialog != None): if(pDialog != None):
pDialog.close() pDialog.close()
@ -336,6 +359,149 @@ class LibrarySync():
WINDOW.setProperty(kodiId,"deleted") WINDOW.setProperty(kodiId,"deleted")
WriteKodiVideoDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) WriteKodiVideoDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
def MusicFullSync(self, connection,cursor, pDialog):
self.ProcessMusicArtists(connection,cursor,pDialog)
self.ProcessMusicAlbums(connection,cursor,pDialog)
self.ProcessMusicSongs(connection,cursor,pDialog)
### commit all changes to database ###
connection.commit()
def ProcessMusicSongs(self,connection,cursor,pDialog):
allKodiSongIds = list()
allEmbySongIds = list()
allEmbySongs = ReadEmbyDB().getMusicSongs()
allKodiSongs = ReadKodiDB().getKodiMusicSongs(connection, cursor)
for kodisong in allKodiSongs:
allKodiSongIds.append(kodisong[1])
total = len(allEmbySongs) + 1
count = 1
#### PROCESS SONGS ADDS AND UPDATES ###
for item in allEmbySongs:
if (self.ShouldStop()):
return False
allEmbySongIds.append(item["Id"])
if(pDialog != None):
progressTitle = "Processing Music Songs (" + str(count) + " of " + str(total) + ")"
pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle)
count += 1
kodiSong = None
for kodisong in allKodiSongs:
if kodisong[1] == item["Id"]:
kodiSong = kodisong
if kodiSong == None:
WriteKodiMusicDB().addOrUpdateSongToKodiLibrary(item["Id"],connection, cursor)
else:
if kodiSong[2] != API().getChecksum(item):
WriteKodiMusicDB().addOrUpdateSongToKodiLibrary(item["Id"],connection, cursor)
#### PROCESS DELETES #####
allEmbySongIds = set(allEmbySongIds)
for kodiId in allKodiSongIds:
if not kodiId in allEmbySongIds:
WINDOW.setProperty(kodiId,"deleted")
WriteKodiMusicDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
def ProcessMusicArtists(self,connection,cursor,pDialog):
allKodiArtistIds = list()
allEmbyArtistIds = list()
allEmbyArtists = ReadEmbyDB().getMusicArtists()
allKodiArtists = ReadKodiDB().getKodiMusicArtists(connection, cursor)
for kodiartist in allKodiArtists:
allKodiArtistIds.append(kodiartist[1])
total = len(allEmbyArtists) + 1
count = 1
#### PROCESS SONGS ADDS AND UPDATES ###
for item in allEmbyArtists:
if (self.ShouldStop()):
return False
allEmbyArtistIds.append(item["Id"])
if(pDialog != None):
progressTitle = "Processing Music Artists (" + str(count) + " of " + str(total) + ")"
pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle)
count += 1
kodiArtist = None
for kodiartist in allKodiArtists:
if kodiartist[1] == item["Id"]:
kodiArtist = kodiartist
if kodiArtist == None:
WriteKodiMusicDB().addOrUpdateArtistToKodiLibrary(item["Id"],connection, cursor)
else:
if kodiArtist[2] != API().getChecksum(item):
WriteKodiMusicDB().addOrUpdateArtistToKodiLibrary(item["Id"],connection, cursor)
#### PROCESS DELETES #####
allEmbyArtistIds = set(allEmbyArtistIds)
for kodiId in allKodiArtistIds:
if not kodiId in allEmbyArtistIds:
WINDOW.setProperty(kodiId,"deleted")
WriteKodiMusicDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
def ProcessMusicAlbums(self,connection,cursor,pDialog):
allKodiAlbumIds = list()
allEmbyAlbumIds = list()
allEmbyAlbums = ReadEmbyDB().getMusicAlbums()
allKodiAlbums = ReadKodiDB().getKodiMusicAlbums(connection, cursor)
for kodialbum in allKodiAlbums:
allKodiAlbumIds.append(kodialbum[1])
total = len(allEmbyAlbums) + 1
count = 1
#### PROCESS SONGS ADDS AND UPDATES ###
for item in allEmbyAlbums:
if (self.ShouldStop()):
return False
allEmbyAlbumIds.append(item["Id"])
if(pDialog != None):
progressTitle = "Processing Music Albums (" + str(count) + " of " + str(total) + ")"
pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle)
count += 1
kodiAlbum = None
for kodialbum in allKodiAlbums:
if kodialbum[1] == item["Id"]:
kodiAlbum = kodialbum
if kodiAlbum == None:
WriteKodiMusicDB().addOrUpdateAlbumToKodiLibrary(item["Id"],connection, cursor)
else:
if kodiAlbum[2] != API().getChecksum(item):
WriteKodiMusicDB().addOrUpdateAlbumToKodiLibrary(item["Id"],connection, cursor)
#### PROCESS DELETES #####
allEmbyAlbumIds = set(allEmbyAlbumIds)
for kodiId in allKodiAlbumIds:
if not kodiId in allEmbyAlbumIds:
WINDOW.setProperty(kodiId,"deleted")
WriteKodiMusicDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
def IncrementalSync(self, itemList): def IncrementalSync(self, itemList):
#this will only perform sync for items received by the websocket #this will only perform sync for items received by the websocket
@ -349,7 +515,7 @@ class LibrarySync():
pDialog = xbmcgui.DialogProgressBG() pDialog = xbmcgui.DialogProgressBG()
pDialog.create('Emby for Kodi', 'Performing incremental sync...') pDialog.create('Emby for Kodi', 'Performing incremental sync...')
connection = utils.KodiSQL() connection = utils.KodiSQL("video")
cursor = connection.cursor() cursor = connection.cursor()
try: try:
@ -407,9 +573,25 @@ class LibrarySync():
### commit all changes to database ### ### commit all changes to database ###
connection.commit() connection.commit()
cursor.close()
### PROCESS MUSIC LIBRARY ###
if performMusicSync:
connection = utils.KodiSQL("music")
cursor = connection.cursor()
for item in itemList:
MBitem = ReadEmbyDB().getItem(item)
if MBitem["Type"] == "MusicArtist":
WriteKodiMusicDB().addOrUpdateArtistToKodiLibrary(MBitem["Id"],connection, cursor)
if MBitem["Type"] == "MusicAlbum":
WriteKodiMusicDB().addOrUpdateAlbumToKodiLibraryToKodiLibrary(MBitem["Id"],connection, cursor)
if MBitem["Type"] == "Audio":
WriteKodiMusicDB().addOrUpdateSongToKodiLibraryToKodiLibrary(MBitem["Id"],connection, cursor)
connection.commit()
cursor.close()
finally: finally:
cursor.close()
xbmc.executebuiltin("UpdateLibrary(video)") xbmc.executebuiltin("UpdateLibrary(video)")
WINDOW.setProperty("SyncDatabaseRunning", "false") WINDOW.setProperty("SyncDatabaseRunning", "false")

View file

@ -66,6 +66,82 @@ class ReadEmbyDB():
return result return result
def getMusicArtists(self, itemList = []):
result = None
doUtils = DownloadUtils()
#only get basic info for our sync-compares
url = "{server}/Artists?Fields=Name,CumulativeRunTimeTicks,Etag&Recursive=true&format=json"
jsonData = doUtils.downloadUrl(url)
if (jsonData == ""):
return result
if (jsonData[u'Items'] != ""):
result = jsonData[u'Items']
# Work around to only return items from the given list
if (result != None and len(result) > 0 and len(itemList) > 0):
newResult = []
for item in result:
if (item[u'Id'] in itemList):
newResult.append(item)
result = newResult
return result
def getMusicSongs(self, itemList = []):
result = None
doUtils = DownloadUtils()
#only get basic info for our sync-compares
url = "{server}/mediabrowser/Users/{UserId}/Items?Fields=Name,CumulativeRunTimeTicks,Etag&Recursive=true&IncludeItemTypes=Audio&format=json"
jsonData = doUtils.downloadUrl(url)
if (jsonData == ""):
return result
if (jsonData[u'Items'] != ""):
result = jsonData[u'Items']
# Work around to only return items from the given list
if (result != None and len(result) > 0 and len(itemList) > 0):
newResult = []
for item in result:
if (item[u'Id'] in itemList):
newResult.append(item)
result = newResult
return result
def getMusicAlbums(self, itemList = []):
result = None
doUtils = DownloadUtils()
#only get basic info for our sync-compares
url = "{server}/mediabrowser/Users/{UserId}/Items?Fields=Name,CumulativeRunTimeTicks,Etag&Recursive=true&IncludeItemTypes=MusicAlbum&format=json"
jsonData = doUtils.downloadUrl(url)
if (jsonData == ""):
return result
if (jsonData[u'Items'] != ""):
result = jsonData[u'Items']
# Work around to only return items from the given list
if (result != None and len(result) > 0 and len(itemList) > 0):
newResult = []
for item in result:
if (item[u'Id'] in itemList):
newResult.append(item)
result = newResult
return result
def getItem(self, id): def getItem(self, id):
result = None result = None

View file

@ -61,4 +61,23 @@ class ReadKodiDB():
else: else:
return None return None
def getKodiMusicArtists(self, connection, cursor):
#returns all artists in Kodi db
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='artist'")
allartists = cursor.fetchall()
#this will return a list with tuples of all items returned from the database
return allartists
def getKodiMusicAlbums(self, connection, cursor):
#returns all artists in Kodi db
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='album'")
allalbums = cursor.fetchall()
#this will return a list with tuples of all items returned from the database
return allalbums
def getKodiMusicSongs(self, connection, cursor):
#returns all songs in Kodi db
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='song'")
allsongs = cursor.fetchall()
#this will return a list with tuples of all items returned from the database
return allsongs

View file

@ -48,12 +48,18 @@ def convertEncoding(data):
except: except:
return data return data
def KodiSQL(): def KodiSQL(type="video"):
connection = sqlite3.connect(getKodiDBPath())
if type == "music":
dbPath = getKodiMusicDBPath()
else:
dbPath = getKodiVideoDBPath()
connection = sqlite3.connect(dbPath)
return connection return connection
def getKodiDBPath(): def getKodiVideoDBPath():
if xbmc.getInfoLabel("System.BuildVersion").startswith("13"): if xbmc.getInfoLabel("System.BuildVersion").startswith("13"):
#gotham #gotham
dbVersion = "78" dbVersion = "78"
@ -68,6 +74,22 @@ def getKodiDBPath():
return dbPath return dbPath
def getKodiMusicDBPath():
if xbmc.getInfoLabel("System.BuildVersion").startswith("13"):
#gotham
dbVersion = "48"
if xbmc.getInfoLabel("System.BuildVersion").startswith("15"):
#isengard
dbVersion = "52"
else:
#helix
dbVersion = "48"
dbPath = xbmc.translatePath("special://profile/Database/MyMusic" + dbVersion + ".db")
return dbPath
def checkAuthentication(): def checkAuthentication():
#check authentication #check authentication
if addonSettings.getSetting('username') != "" and addonSettings.getSetting('ipaddress') != "": if addonSettings.getSetting('username') != "" and addonSettings.getSetting('ipaddress') != "":

View file

@ -0,0 +1,447 @@
#################################################################################################
# WriteKodiVideoDB
#################################################################################################
import xbmc
import xbmcgui
import xbmcaddon
import xbmcvfs
import json
import urllib
import sqlite3
import os
from decimal import Decimal
from DownloadUtils import DownloadUtils
from PlayUtils import PlayUtils
from ReadKodiDB import ReadKodiDB
from ReadEmbyDB import ReadEmbyDB
from API import API
import Utils as utils
from xml.etree.ElementTree import Element, SubElement, Comment, tostring
from xml.etree import ElementTree
from xml.dom import minidom
import xml.etree.cElementTree as ET
addon = xbmcaddon.Addon(id='plugin.video.emby')
addondir = xbmc.translatePath(addon.getAddonInfo('profile'))
dataPath = os.path.join(addondir,",musicfiles")
class WriteKodiMusicDB():
def updatePlayCountFromKodi(self, id, type, playcount=0):
#when user marks item watched from kodi interface update this in Emby
utils.logMsg("Emby", "updatePlayCountFromKodi Called")
connection = utils.KodiSQL()
cursor = connection.cursor()
cursor.execute("SELECT emby_id FROM emby WHERE media_type=? AND kodi_id=?",(type,id))
emby_id = cursor.fetchone()[0]
cursor.close
if(emby_id != None):
addon = xbmcaddon.Addon(id='plugin.video.emby')
downloadUtils = DownloadUtils()
watchedurl = "{server}/mediabrowser/Users/{UserId}/PlayedItems/%s" % emby_id
if playcount != 0:
downloadUtils.downloadUrl(watchedurl, type="POST")
else:
downloadUtils.downloadUrl(watchedurl, type="DELETE")
def addOrUpdateArtistToKodiLibrary( self, embyId ,connection, cursor):
addon = xbmcaddon.Addon(id='plugin.video.emby')
WINDOW = xbmcgui.Window(10000)
username = WINDOW.getProperty('currUser')
userid = WINDOW.getProperty('userId%s' % username)
server = WINDOW.getProperty('server%s' % username)
downloadUtils = DownloadUtils()
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 = ?",(MBitem["Id"],))
result = cursor.fetchone()
if result != None:
artistid = result[0]
else:
artistid = None
#### The artist details #########
name = utils.convertEncoding(MBitem["Name"])
musicBrainsId = None
if MBitem.get("ProviderIds"):
if MBitem.get("ProviderIds").get("MusicBrainzArtist"):
musicBrainsId = MBitem.get("ProviderIds").get("MusicBrainzArtist")
genres = " / ".join(MBitem.get("Genres"))
bio = utils.convertEncoding(API().getOverview(MBitem))
dateadded = None
if MBitem.get("DateCreated"):
dateadded = MBitem["DateCreated"].split('.')[0].replace('T', " ")
#safety check: does the musicbrainzartistId already exist?
cursor.execute("SELECT idArtist FROM artist WHERE strMusicBrainzArtistID = ?",(musicBrainsId,))
result = cursor.fetchone()
if result != None:
artistid = result[0]
else:
artistid = None
##### ADD THE ARTIST ############
if artistid == None:
utils.logMsg("ADD artist to Kodi library","Id: %s - Title: %s" % (embyId, name))
#create the artist
cursor.execute("select coalesce(max(idArtist),0) as artistid from artist")
artistid = cursor.fetchone()[0]
artistid = artistid + 1
pathsql="insert into artist(idArtist, strArtist, strMusicBrainzArtistID, strGenres, strBiography, dateAdded) values(?, ?, ?, ?, ?, ?)"
cursor.execute(pathsql, (artistid, name, musicBrainsId, genres, bio, dateadded))
#create the reference in emby table
pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)"
cursor.execute(pathsql, (MBitem["Id"], artistid, "artist", API().getChecksum(MBitem)))
#### UPDATE THE ARTIST #####
else:
utils.logMsg("UPDATE artist to Kodi library","Id: %s - Title: %s" % (embyId, name))
pathsql="update artist SET strArtist = ?, strMusicBrainzArtistID = ?, strGenres = ?, strBiography = ?, dateAdded = ? WHERE idArtist = ?"
cursor.execute(pathsql, (name, musicBrainsId, genres, bio, dateadded, artistid))
#update the checksum in emby table
cursor.execute("UPDATE emby SET checksum = ? WHERE emby_id = ?", (API().getChecksum(MBitem),MBitem["Id"]))
#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, isSingle=False):
addon = xbmcaddon.Addon(id='plugin.video.emby')
WINDOW = xbmcgui.Window(10000)
username = WINDOW.getProperty('currUser')
userid = WINDOW.getProperty('userId%s' % username)
server = WINDOW.getProperty('server%s' % username)
downloadUtils = DownloadUtils()
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 = ?",(MBitem["Id"],))
result = cursor.fetchone()
if result != None:
albumid = result[0]
else:
albumid = None
#### The album details #########
name = utils.convertEncoding(MBitem["Name"])
MBartists = []
for item in MBitem.get("AlbumArtists"):
MBartists.append(item["Name"])
artists = " / ".join(MBartists)
year = MBitem.get("ProductionYear")
musicBrainsId = None
if MBitem.get("ProviderIds"):
if MBitem.get("ProviderIds").get("MusicBrainzAlbum"):
musicBrainsId = MBitem.get("ProviderIds").get("MusicBrainzAlbum")
genres = " / ".join(MBitem.get("Genres"))
bio = utils.convertEncoding(API().getOverview(MBitem))
dateadded = None
if MBitem.get("DateCreated"):
dateadded = MBitem["DateCreated"].split('.')[0].replace('T', " ")
if isSingle:
releasetype = "single"
name = None
else:
releasetype = "album"
##### ADD THE ALBUM ############
if albumid == None:
utils.logMsg("ADD album to Kodi library","Id: %s - Title: %s" % (embyId, name))
#create the album
cursor.execute("select coalesce(max(idAlbum),0) as albumid from album")
albumid = cursor.fetchone()[0]
albumid = albumid + 1
pathsql="insert into album(idAlbum, strAlbum, strMusicBrainzAlbumID, strArtists, iYear, strGenres, dateAdded) values(?, ?, ?, ?, ?, ?, ?)"
cursor.execute(pathsql, (albumid, name, musicBrainsId, artists, year, genres, dateadded))
#create the reference in emby table
pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)"
cursor.execute(pathsql, (MBitem["Id"], albumid, "album", API().getChecksum(MBitem)))
#### UPDATE THE ALBUM #####
else:
utils.logMsg("UPDATE album to Kodi library","Id: %s - Title: %s" % (embyId, name))
pathsql="update album SET strAlbum = ?, strMusicBrainzAlbumID = ?, strArtists = ?, strGenres = ?, iYear = ?, dateAdded = ? WHERE idAlbum = ?"
cursor.execute(pathsql, (name, musicBrainsId, artists, genres, year, dateadded, albumid))
#update the checksum in emby table
cursor.execute("UPDATE emby SET checksum = ? WHERE emby_id = ?", (API().getChecksum(MBitem),MBitem["Id"]))
#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 artist
artistid = None
for artist in MBitem.get("AlbumArtists"):
cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?",(artist["Id"],))
result = cursor.fetchone()
if result:
artistid = result[0]
sql="INSERT OR REPLACE into album_artist(idArtist, idAlbum, strArtist) values(?, ?, ?)"
cursor.execute(sql, (artistid, albumid, artist["Name"]))
#update discography
sql="INSERT OR REPLACE into discography(idArtist, strAlbum, strYear) values(?, ?, ?)"
cursor.execute(sql, (artistid, name, str(year)))
#return the album id
return albumid
def addOrUpdateSongToKodiLibrary( self, embyId ,connection, cursor):
addon = xbmcaddon.Addon(id='plugin.video.emby')
WINDOW = xbmcgui.Window(10000)
username = WINDOW.getProperty('currUser')
userid = WINDOW.getProperty('userId%s' % username)
server = WINDOW.getProperty('server%s' % username)
downloadUtils = DownloadUtils()
MBitem = ReadEmbyDB().getFullItem(embyId)
timeInfo = API().getTimeInfo(MBitem)
userData=API().getUserData(MBitem)
# 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 = ?",(MBitem["Id"],))
result = cursor.fetchone()
if result != None:
songid = result[0]
else:
songid = None
#### The song details #########
name = utils.convertEncoding(MBitem["Name"])
musicBrainzId = None
if MBitem.get("ProviderIds"):
if MBitem.get("ProviderIds").get("MusicBrainzTrackId"):
musicBrainzId = MBitem.get("ProviderIds").get("MusicBrainzTrackId")
genres = " / ".join(MBitem.get("Genres"))
artists = " / ".join(MBitem.get("Artists"))
track = MBitem.get("IndexNumber")
duration = int(timeInfo.get('Duration'))*60
year = MBitem.get("ProductionYear")
bio = utils.convertEncoding(API().getOverview(MBitem))
dateadded = None
if MBitem.get("DateCreated"):
dateadded = MBitem["DateCreated"].split('.')[0].replace('T', " ")
if userData.get("LastPlayedDate") != None:
lastplayed = userData.get("LastPlayedDate")
else:
lastplayed = None
playcount = None
if userData.get("PlayCount"):
playcount = int(userData.get("PlayCount"))
#get the album
albumid = None
if MBitem.get("AlbumId"):
cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?",(MBitem.get("AlbumId"),))
result = cursor.fetchone()
if result:
albumid = result[0]
if not albumid:
#no album = single in kodi, we need to create a single album for that
albumid = self.addOrUpdateAlbumToKodiLibrary(MBitem["Id"],connection, cursor, True)
playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem)
#for transcoding we need to create a fake strm file because I couldn't figure out how to set a http or plugin path in the music DB
if playurl.startswith("http"):
#create fake strm file
filename = item["Id"] + ".strm"
path = dataPath
strmFile = os.path.join(dataPath,filename)
text_file = open(strmFile, "w")
text_file.writelines(playurl)
text_file.close()
else:
#use the direct file path
if "\\" in playurl:
filename = playurl.rsplit("\\",1)[-1]
path = playurl.replace(filename,"")
elif "/" in playurl:
filename = playurl.rsplit("/",1)[-1]
path = playurl.replace(filename,"")
#get the path
cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,))
result = cursor.fetchone()
if result != None:
pathid = result[0]
else:
cursor.execute("select coalesce(max(idPath),0) as pathid from path")
pathid = cursor.fetchone()[0]
pathid = pathid + 1
pathsql = "insert into path(idPath, strPath) values(?, ?)"
cursor.execute(pathsql, (pathid,path))
##### ADD THE SONG ############
if songid == None:
utils.logMsg("ADD song to Kodi library","Id: %s - Title: %s" % (embyId, name))
#create the song
cursor.execute("select coalesce(max(idSong),0) as songid from song")
songid = cursor.fetchone()[0]
songid = songid + 1
pathsql="insert into song(idSong, idAlbum, idPath, strArtists, strGenres, strTitle, iTrack, iDuration, iYear, strFileName, strMusicBrainzTrackID, iTimesPlayed, lastplayed) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
cursor.execute(pathsql, (songid, albumid, pathid, artists, genres, name, track, duration, year, filename, musicBrainzId, playcount, lastplayed))
#create the reference in emby table
pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)"
cursor.execute(pathsql, (MBitem["Id"], songid, "song", API().getChecksum(MBitem)))
#### UPDATE THE SONG #####
else:
utils.logMsg("UPDATE song to Kodi library","Id: %s - Title: %s" % (embyId, name))
pathsql="update song SET idAlbum=?, strArtists=?, strGenres=?, strTitle=?, iTrack=?, iDuration=?, iYear=?, strFileName=?, strMusicBrainzTrackID=?, iTimesPlayed=?, lastplayed=? WHERE idSong = ?"
cursor.execute(pathsql, (albumid, artists, genres, name, track, duration, year, filename, musicBrainzId, playcount, lastplayed, songid))
#update the checksum in emby table
cursor.execute("UPDATE emby SET checksum = ? WHERE emby_id = ?", (API().getChecksum(MBitem),MBitem["Id"]))
#add genres
self.AddGenresToMedia(songid, MBitem.get("Genres"), "song", cursor)
#link song to album
if albumid:
sql="INSERT OR REPLACE into albuminfosong(idAlbumInfoSong, idAlbumInfo, iTrack, strTitle, iDuration) values(?, ?, ?, ?, ?)"
cursor.execute(sql, (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"],))
result = cursor.fetchone()
if result:
artistid = result[0]
sql="INSERT OR REPLACE into song_artist(idArtist, idSong, strArtist) values(?, ?, ?)"
cursor.execute(sql, (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,))
result = cursor.fetchone()
if result:
kodi_id = result[0]
media_type = result[1]
if media_type == "movie":
utils.logMsg("deleting movie from Kodi library --> ",id)
cursor.execute("DELETE FROM movie WHERE idMovie = ?", (kodi_id,))
if media_type == "episode":
utils.logMsg("deleting episode from Kodi library --> ",id)
cursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodi_id,))
if media_type == "tvshow":
utils.logMsg("deleting tvshow from Kodi library --> ",id)
cursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodi_id,))
if media_type == "musicvideo":
utils.logMsg("deleting musicvideo from Kodi library --> ",id)
cursor.execute("DELETE FROM musicvideo WHERE idMVideo = ?", (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):
updateDone = False
if imageUrl:
cursor.execute("SELECT url FROM art WHERE media_id = ? AND media_type = ? AND type = ?", (kodiId, mediaType, imageType))
result = cursor.fetchone()
if(result == None):
utils.logMsg("ArtworkSync", "Adding Art Link for kodiId: " + str(kodiId) + " (" + imageUrl + ")")
cursor.execute("INSERT INTO art(media_id, media_type, type, url) values(?, ?, ?, ?)", (kodiId, mediaType, imageType, imageUrl))
else:
url = result[0];
if(url != imageUrl):
utils.logMsg("ArtworkSync", "Updating Art Link for kodiId: " + str(kodiId) + " (" + url + ") -> (" + imageUrl + ")")
cursor.execute("UPDATE art set url = ? WHERE media_id = ? AND media_type = ? AND type = ?", (imageUrl, kodiId, mediaType, imageType))
def AddGenresToMedia(self, id, genres, mediatype, cursor):
if genres:
for genre in genres:
idGenre = None
cursor.execute("SELECT idGenre as idGenre FROM genre WHERE strGenre = ?",(genre,))
result = cursor.fetchone()
if result != None:
idGenre = result[0]
#create genre
if idGenre == None:
cursor.execute("select coalesce(max(idGenre),0) as idGenre from genre")
idGenre = cursor.fetchone()[0]
idGenre = idGenre + 1
sql="insert into genre(idGenre, strGenre) values(?, ?)"
cursor.execute(sql, (idGenre,genre))
#assign genre to item
if mediatype == "album":
sql="INSERT OR REPLACE into album_genre(idGenre, idAlbum) values(?, ?)"
cursor.execute(sql, (idGenre,id))
elif mediatype == "song":
sql="INSERT OR REPLACE into song_genre(idGenre, idSong) values(?, ?)"
cursor.execute(sql, (idGenre,id))
else:
return

View file

@ -18,6 +18,7 @@
<category label="Sync Options"> <category label="Sync Options">
<!-- <setting id="syncMovieBoxSets" type="bool" label="30238" default="true" visible="true" enable="true" /> --> <!-- <setting id="syncMovieBoxSets" type="bool" label="30238" default="true" visible="true" enable="true" /> -->
<setting id="dbSyncIndication" type="bool" label="30241" default="false" visible="true" enable="true" /> <setting id="dbSyncIndication" type="bool" label="30241" default="false" visible="true" enable="true" />
<setting id="enableMusicSync" type="bool" label="Enable Music Library Sync (experimental!)" default="false" visible="true" enable="true" />
</category> </category>
<category label="Playback"> <!-- Extra Sync options --> <category label="Playback"> <!-- Extra Sync options -->
<setting id="smbusername" type="text" label="30007" default="" visible="true" enable="true" /> <setting id="smbusername" type="text" label="30007" default="" visible="true" enable="true" />