mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2024-12-25 02:06:09 +00:00
add first support for music library sync
This commit is contained in:
parent
87681ee850
commit
8839b3b323
7 changed files with 760 additions and 13 deletions
|
@ -332,7 +332,7 @@ class API():
|
|||
if(data.get("ImageTags") != None and data.get("ImageTags").get(type) != None):
|
||||
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")
|
||||
if (data.get("Type") == "Episode" or data.get("Type") == "Season") and type=="Art":
|
||||
imageTag = data.get("ParentArtImageTag")
|
||||
|
|
|
@ -22,6 +22,7 @@ from DownloadUtils import DownloadUtils
|
|||
from ReadEmbyDB import ReadEmbyDB
|
||||
from ReadKodiDB import ReadKodiDB
|
||||
from WriteKodiVideoDB import WriteKodiVideoDB
|
||||
from WriteKodiMusicDB import WriteKodiMusicDB
|
||||
from VideoNodes import VideoNodes
|
||||
|
||||
addondir = xbmc.translatePath(xbmcaddon.Addon(id='plugin.video.emby').getAddonInfo('profile'))
|
||||
|
@ -40,6 +41,7 @@ class LibrarySync():
|
|||
|
||||
startupDone = WINDOW.getProperty("startup") == "done"
|
||||
syncInstallRunDone = addon.getSetting("SyncInstallRunDone") == "true"
|
||||
performMusicSync = addon.getSetting("enableMusicSync") == "true"
|
||||
dbSyncIndication = addon.getSetting("dbSyncIndication") == "true"
|
||||
WINDOW.setProperty("SyncDatabaseRunning", "true")
|
||||
|
||||
|
@ -56,16 +58,21 @@ class LibrarySync():
|
|||
|
||||
try:
|
||||
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()
|
||||
|
||||
#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()
|
||||
|
||||
### BUILD VIDEO NODES LISTING ###
|
||||
VideoNodes().buildVideoNodesListing()
|
||||
|
||||
# sync movies
|
||||
self.MoviesFullSync(connection,cursor,pDialog)
|
||||
|
@ -82,6 +89,23 @@ class LibrarySync():
|
|||
# sync musicvideos
|
||||
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
|
||||
if(syncInstallRunDone == False and completed):
|
||||
addon = xbmcaddon.Addon(id='plugin.video.emby') #force a new instance of the addon
|
||||
|
@ -97,7 +121,6 @@ class LibrarySync():
|
|||
WINDOW.setProperty("SyncDatabaseRunning", "false")
|
||||
utils.logMsg("Sync DB", "syncDatabase Exiting", 0)
|
||||
|
||||
cursor.close()
|
||||
|
||||
if(pDialog != None):
|
||||
pDialog.close()
|
||||
|
@ -336,6 +359,149 @@ class LibrarySync():
|
|||
WINDOW.setProperty(kodiId,"deleted")
|
||||
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):
|
||||
#this will only perform sync for items received by the websocket
|
||||
|
@ -349,7 +515,7 @@ class LibrarySync():
|
|||
pDialog = xbmcgui.DialogProgressBG()
|
||||
pDialog.create('Emby for Kodi', 'Performing incremental sync...')
|
||||
|
||||
connection = utils.KodiSQL()
|
||||
connection = utils.KodiSQL("video")
|
||||
cursor = connection.cursor()
|
||||
|
||||
try:
|
||||
|
@ -407,9 +573,25 @@ class LibrarySync():
|
|||
|
||||
### commit all changes to database ###
|
||||
connection.commit()
|
||||
|
||||
finally:
|
||||
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:
|
||||
|
||||
xbmc.executebuiltin("UpdateLibrary(video)")
|
||||
WINDOW.setProperty("SyncDatabaseRunning", "false")
|
||||
|
||||
|
|
|
@ -65,7 +65,83 @@ class ReadEmbyDB():
|
|||
result = newResult
|
||||
|
||||
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):
|
||||
|
||||
result = None
|
||||
|
|
|
@ -61,4 +61,23 @@ class ReadKodiDB():
|
|||
else:
|
||||
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
|
|
@ -48,12 +48,18 @@ def convertEncoding(data):
|
|||
except:
|
||||
return data
|
||||
|
||||
def KodiSQL():
|
||||
connection = sqlite3.connect(getKodiDBPath())
|
||||
def KodiSQL(type="video"):
|
||||
|
||||
if type == "music":
|
||||
dbPath = getKodiMusicDBPath()
|
||||
else:
|
||||
dbPath = getKodiVideoDBPath()
|
||||
|
||||
connection = sqlite3.connect(dbPath)
|
||||
|
||||
return connection
|
||||
|
||||
def getKodiDBPath():
|
||||
def getKodiVideoDBPath():
|
||||
if xbmc.getInfoLabel("System.BuildVersion").startswith("13"):
|
||||
#gotham
|
||||
dbVersion = "78"
|
||||
|
@ -68,6 +74,22 @@ def getKodiDBPath():
|
|||
|
||||
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():
|
||||
#check authentication
|
||||
if addonSettings.getSetting('username') != "" and addonSettings.getSetting('ipaddress') != "":
|
||||
|
|
447
resources/lib/WriteKodiMusicDB.py
Normal file
447
resources/lib/WriteKodiMusicDB.py
Normal 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
|
||||
|
||||
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
<category label="Sync Options">
|
||||
<!-- <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="enableMusicSync" type="bool" label="Enable Music Library Sync (experimental!)" default="false" visible="true" enable="true" />
|
||||
</category>
|
||||
<category label="Playback"> <!-- Extra Sync options -->
|
||||
<setting id="smbusername" type="text" label="30007" default="" visible="true" enable="true" />
|
||||
|
|
Loading…
Reference in a new issue