Plex Music!
Playing does not work yet, but Lib sync is up
This commit is contained in:
parent
f162b6ea8a
commit
bcbbb1b42f
6 changed files with 421 additions and 455 deletions
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
@ -410,10 +406,6 @@ class Artwork():
|
|||
# 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((
|
||||
|
||||
"UPDATE art",
|
||||
|
|
|
@ -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'):
|
||||
|
@ -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 = "<thumb>%s</thumb>" % 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 = "<thumb>%s</thumb>" % 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)
|
||||
kodicursor.execute("select coalesce(max(idSong),0) from song")
|
||||
songid = kodicursor.fetchone()[0] + 1
|
||||
|
||||
##### The song details #####
|
||||
# The song details #####
|
||||
checksum = API.getChecksum()
|
||||
dateadded = API.getDateCreated()
|
||||
userdata = API.getUserData()
|
||||
|
@ -1825,85 +1836,65 @@ 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()
|
||||
comment = None
|
||||
|
||||
|
||||
##### GET THE FILE AND PATH #####
|
||||
# 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)
|
||||
|
||||
|
@ -1912,7 +1903,8 @@ class Music(Items):
|
|||
|
||||
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:
|
||||
|
@ -1965,8 +1957,6 @@ 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,14 +1967,17 @@ 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 = (
|
||||
'''
|
||||
|
@ -1995,7 +1988,6 @@ class Music(Items):
|
|||
'''
|
||||
)
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue