fixed all properties for movieobjects

added actors to database
fixed the library detection to more failsafe
This commit is contained in:
Marcel van der Veldt 2015-03-14 18:23:45 +01:00
parent 7b45de29e1
commit e2d6bd6c43
3 changed files with 141 additions and 85 deletions

View file

@ -7,24 +7,24 @@ class API():
def getPeople(self, item): def getPeople(self, item):
# Process People # Process People
director='' director=[]
writer='' writer=[]
cast=[] cast=[]
people = item.get("People") people = item.get("People")
if(people != None): if(people != None):
for person in people: for person in people:
if(person.get("Type") == "Director"): if(person.get("Type") == "Director"):
director = director + person.get("Name") + ' ' director.append(person.get("Name"))
if(person.get("Type") == "Writing"): if(person.get("Type") == "Writing"):
writer = person.get("Name") writer.append(person.get("Name"))
if(person.get("Type") == "Writer"): if(person.get("Type") == "Writer"):
writer = person.get("Name") writer.append(person.get("Name"))
if(person.get("Type") == "Actor"): if(person.get("Type") == "Actor"):
Name = person.get("Name") Name = person.get("Name")
Role = person.get("Role") Role = person.get("Role")
if Role == None: if Role == None:
Role = '' Role = ''
cast.append(Name) cast.append(Name)
return {'Director' : director, return {'Director' : director,
'Writer' : writer, 'Writer' : writer,
'Cast' : cast 'Cast' : cast
@ -60,19 +60,17 @@ class API():
'ResumeTime' : str(resume) 'ResumeTime' : str(resume)
} }
def getStudio(self, item): def getStudios(self, item):
# Process Studio # Process Studio
studio = "" studios = []
if item.get("SeriesStudio") != None and item.get("SeriesStudio") != '': if item.get("SeriesStudio") != None and item.get("SeriesStudio") != '':
studio = item.get("SeriesStudio") studios.append(item.get("SeriesStudio"))
if studio == "": else:
studios = item.get("Studios") if(item.get("Studios") != None):
if(studios != None): for studio_string in item.get("Studios"):
for studio_string in studios: temp=studio_string.get("Name").encode('utf-8')
if studio=="": #Just take the first one studios.append(temp)
temp=studio_string.get("Name") return studios
studio=temp.encode('utf-8')
return studio
def getMediaStreams(self, item, mediaSources=False): def getMediaStreams(self, item, mediaSources=False):
# Process MediaStreams # Process MediaStreams

View file

@ -85,14 +85,11 @@ class LibrarySync():
if kodiItem != None: if kodiItem != None:
if kodiItem['playcount'] != int(userData.get("PlayCount")): if kodiItem['playcount'] != int(userData.get("PlayCount")):
xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": %i, "playcount": %i}, "id": 1 }' %(kodiItem['movieid'], int(userData.get("PlayCount")))) xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": %i, "playcount": %i}, "id": 1 }' %(kodiItem['movieid'], int(userData.get("PlayCount"))))
kodiresume = int(round(kodiItem['resume'].get("position"))) kodiresume = int(round(kodiItem['resume'].get("position")))
resume = int(round(float(timeInfo.get("ResumeTime"))))*60 resume = int(round(float(timeInfo.get("ResumeTime"))))*60
total = int(round(float(timeInfo.get("TotalTime"))))*60 total = int(round(float(timeInfo.get("TotalTime"))))*60
if kodiresume != resume: if kodiresume != resume:
print "kodiresume -->" + str(kodiresume)
print "mb3_resume -->" + str(resume)
print "total -->" + str(total)
self.setKodiResumePoint(kodiItem['movieid'],resume,total) self.setKodiResumePoint(kodiItem['movieid'],resume,total)
WINDOW.clearProperty("librarysync") WINDOW.clearProperty("librarysync")
@ -100,7 +97,7 @@ class LibrarySync():
def getMovies(self, fullinfo = False): def getMovies(self, fullinfo = False):
result = None result = None
if fullinfo: if fullinfo:
url = server + '/mediabrowser/Users/' + userid + '/Items?&SortBy=SortName&Fields=Path,Genres,Studios,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Movie&format=json&ImageTypeLimit=1' url = server + '/mediabrowser/Users/' + userid + '/Items?&SortBy=SortName&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Movie&format=json&ImageTypeLimit=1'
else: else:
url = server + '/mediabrowser/Users/' + userid + '/Items?&SortBy=SortName&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Movie&format=json&ImageTypeLimit=1' url = server + '/mediabrowser/Users/' + userid + '/Items?&SortBy=SortName&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Movie&format=json&ImageTypeLimit=1'
@ -138,6 +135,7 @@ class LibrarySync():
userData=API().getUserData(MBitem) userData=API().getUserData(MBitem)
people = API().getPeople(MBitem) people = API().getPeople(MBitem)
genre = API().getGenre(MBitem) genre = API().getGenre(MBitem)
studios = API().getStudios(MBitem)
mediaStreams=API().getMediaStreams(MBitem) mediaStreams=API().getMediaStreams(MBitem)
thumbPath = downloadUtils.getArtwork(MBitem, "Primary") thumbPath = downloadUtils.getArtwork(MBitem, "Primary")
@ -147,6 +145,7 @@ class LibrarySync():
#update artwork #update artwork
self.updateArtWork(KodiItem,"poster", downloadUtils.getArtwork(MBitem, "poster"),"movie") self.updateArtWork(KodiItem,"poster", downloadUtils.getArtwork(MBitem, "poster"),"movie")
self.updateArtWork(KodiItem,"clearlogo", downloadUtils.getArtwork(MBitem, "Logo"),"movie") self.updateArtWork(KodiItem,"clearlogo", downloadUtils.getArtwork(MBitem, "Logo"),"movie")
self.updateArtWork(KodiItem,"clearart", downloadUtils.getArtwork(MBitem, "Art"),"movie")
self.updateArtWork(KodiItem,"banner", downloadUtils.getArtwork(MBitem, "Banner"),"movie") self.updateArtWork(KodiItem,"banner", downloadUtils.getArtwork(MBitem, "Banner"),"movie")
self.updateArtWork(KodiItem,"landscape", downloadUtils.getArtwork(MBitem, "Thumb"),"movie") self.updateArtWork(KodiItem,"landscape", downloadUtils.getArtwork(MBitem, "Thumb"),"movie")
self.updateArtWork(KodiItem,"discart", downloadUtils.getArtwork(MBitem, "Disc"),"movie") self.updateArtWork(KodiItem,"discart", downloadUtils.getArtwork(MBitem, "Disc"),"movie")
@ -156,10 +155,31 @@ class LibrarySync():
duration = (int(timeInfo.get('Duration'))*60) duration = (int(timeInfo.get('Duration'))*60)
self.updateProperty(KodiItem,"runtime",duration,"movie") self.updateProperty(KodiItem,"runtime",duration,"movie")
self.updateProperty(KodiItem,"year",MBitem.get("ProductionYear"),"movie") self.updateProperty(KodiItem,"year",MBitem.get("ProductionYear"),"movie")
self.updateProperty(KodiItem,"writer",MBitem.get("Writer"),"movie")
self.updateProperty(KodiItem,"mpaa",MBitem.get("OfficialRating"),"movie") self.updateProperty(KodiItem,"mpaa",MBitem.get("OfficialRating"),"movie")
self.updateProperty(KodiItem,"rating",MBitem.get("CommunityRating"),"movie")
if MBitem.get("CriticRating") != None:
self.updateProperty(KodiItem,"rating",int(MBitem.get("CriticRating"))/10,"movie")
self.updateProperty(KodiItem,"plotoutline",MBitem.get("ShortOverview"),"movie")
self.updateProperty(KodiItem,"set",MBitem.get("TmdbCollectionName"),"movie")
self.updateProperty(KodiItem,"sorttitle",MBitem.get("SortName"),"movie")
if MBitem.get("ProviderIds") != None:
if MBitem.get("ProviderIds").get("Imdb") != None:
self.updateProperty(KodiItem,"imdbnumber",MBitem.get("ProviderIds").get("Imdb"),"movie")
# FIXME --> Taglines not returned by MB3 server !?
if MBitem.get("TagLines") != None:
self.updateProperty(KodiItem,"tagline",MBitem.get("TagLines")[0],"movie")
self.updatePropertyArray(KodiItem,"writer",people.get("Writer"),"movie")
self.updatePropertyArray(KodiItem,"director",people.get("Director"),"movie")
self.updatePropertyArray(KodiItem,"genre",MBitem.get("Genres"),"movie")
self.updatePropertyArray(KodiItem,"studio",studios,"movie")
# FIXME --> ProductionLocations not returned by MB3 server !?
self.updatePropertyArray(KodiItem,"country",MBitem.get("ProductionLocations"),"movie")
#trailer link #trailer link
trailerUrl = None trailerUrl = None
if MBitem.get("LocalTrailerCount") != None and MBitem.get("LocalTrailerCount") > 0: if MBitem.get("LocalTrailerCount") != None and MBitem.get("LocalTrailerCount") > 0:
@ -168,13 +188,13 @@ class LibrarySync():
trailerItem = json.loads(jsonData) trailerItem = json.loads(jsonData)
trailerUrl = "plugin://plugin.video.mb3sync/?id=" + trailerItem[0].get("Id") + '&mode=play' trailerUrl = "plugin://plugin.video.mb3sync/?id=" + trailerItem[0].get("Id") + '&mode=play'
self.updateProperty(KodiItem,"trailer",trailerUrl,"movie") self.updateProperty(KodiItem,"trailer",trailerUrl,"movie")
#update genres
self.updateGenres(KodiItem,MBitem.get("Genres"),"movie")
#update strm file - TODO: only update strm when path has changed #update strm file - TODO: only update strm when path has changed
self.createSTRM(MBitem["Id"]) self.createSTRM(MBitem["Id"])
#add actors
self.AddActorsToMedia(KodiItem,MBitem.get("People"),"movie")
#create nfo file if not exists #create nfo file if not exists
nfoFile = os.path.join(movieLibrary,MBitem["Id"],MBitem["Id"] + ".nfo") nfoFile = os.path.join(movieLibrary,MBitem["Id"],MBitem["Id"] + ".nfo")
if not xbmcvfs.exists(nfoFile): if not xbmcvfs.exists(nfoFile):
@ -215,13 +235,14 @@ class LibrarySync():
method = "VideoLibrary.SetMovieDetails" method = "VideoLibrary.SetMovieDetails"
if propertyValue != KodiItem[propertyName]: if propertyValue != KodiItem[propertyName]:
if type(propertyValue) is int: if propertyValue != None:
xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "%s", "params": { "movieid": %i, "%s": %i}, "id": 1 }' %(method,KodiItem['movieid'], propertyName, propertyValue)) if type(propertyValue) is int:
else: xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "%s", "params": { "movieid": %i, "%s": %i}, "id": 1 }' %(method,KodiItem['movieid'], propertyName, propertyValue))
xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "%s", "params": { "movieid": %i, "%s": "%s"}, "id": 1 }' %(method,KodiItem['movieid'], propertyName, propertyValue)) else:
xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "%s", "params": { "movieid": %i, "%s": "%s"}, "id": 1 }' %(method,KodiItem['movieid'], propertyName, propertyValue.encode('utf-8')))
# adds or updates the genres on the videofile in Kodi database # adds or updates the property-array on the videofile in Kodi database
def updateGenres(self,KodiItem,genreCollection,fileType="movie"): def updatePropertyArray(self,KodiItem,propertyName,propertyCollection,fileType="movie"):
if fileType == "tvshow": if fileType == "tvshow":
method = "VideoLibrary.SetTVShowDetails" method = "VideoLibrary.SetTVShowDetails"
elif fileType == "episode": elif fileType == "episode":
@ -232,17 +253,16 @@ class LibrarySync():
method = "VideoLibrary.SetMovieDetails" method = "VideoLibrary.SetMovieDetails"
pendingChanges = False pendingChanges = False
if genreCollection != None: if propertyCollection != None:
currentgenres = set(KodiItem["genre"]) currentvalues = set(KodiItem[propertyName])
genrestring = "" genrestring = ""
for genre in genreCollection: for item in propertyCollection:
if not genre in currentgenres: if not item in currentvalues:
pendingChanges = True pendingChanges = True
json_genres = json.dumps(genreCollection) json_array = json.dumps(propertyCollection)
if pendingChanges: if pendingChanges:
print genreCollection xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "%s", "params": { "movieid": %i, "%s": %s}, "id": 1 }' %(method,KodiItem['movieid'],propertyName,json_array))
xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "%s", "params": { "movieid": %i, "genre": %s}, "id": 1 }' %(method,KodiItem['movieid'],json_genres))
def createSTRM(self,id): def createSTRM(self,id):
@ -349,8 +369,53 @@ class LibrarySync():
connection.commit() connection.commit()
cursor.close() cursor.close()
def AddActorsToMedia(self, KodiItem, people, mediatype):
#use sqlite to set add the actors while json api doesn't support this yet
#todo --> submit PR to kodi team to get this added to the jsonrpc api
id = KodiItem["movieid"]
dbPath = xbmc.translatePath("special://userdata/Database/MyVideos90.db")
connection = sqlite3.connect(dbPath)
cursor = connection.cursor()
currentcast = list()
if KodiItem["cast"] != None:
for cast in KodiItem["cast"]:
currentcast.append(cast["name"])
if(people != None):
for person in people:
if(person.get("Type") == "Actor"):
if person.get("Name") not in currentcast:
Name = person.get("Name")
Role = person.get("Role")
actorid = None
Thumb = downloadUtils.imageUrl(person.get("Id"), "Primary", 0, 400, 400)
cursor.execute("SELECT idActor as actorid FROM actors WHERE strActor = ?",(Name,))
result = cursor.fetchone()
if result != None:
actorid = result[0]
if actorid == None:
cursor.execute("select coalesce(max(idActor),0) as actorid from actors")
actorid = cursor.fetchone()[0]
actorid = actorid + 1
peoplesql="insert into actors(idActor, strActor, strThumb) values(?, ?, ?)"
cursor.execute(peoplesql, (actorid,Name,Thumb))
if mediatype == "movie":
peoplesql="INSERT OR REPLACE into actorlinkmovie(idActor, idMovie, strRole, iOrder) values(?, ?, ?, ?)"
if mediatype == "tvshow":
peoplesql="INSERT OR REPLACE into actorlinktvshow(idActor, idShow, strRole, iOrder) values(?, ?, ?, ?)"
if mediatype == "episode":
peoplesql="INSERT OR REPLACE into actorlinkepisode(idActor, idEpisode, strRole, iOrder) values(?, ?, ?, ?)"
cursor.execute(peoplesql, (actorid,id,Role,None))
connection.commit()
cursor.close()
def getKodiMovie(self, id): def getKodiMovie(self, id):
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "filter": {"operator": "contains", "field": "path", "value": "' + id + '"}, "properties" : ["art", "rating", "thumbnail", "resume", "runtime", "year", "genre", "cast", "trailer", "country", "studio", "set", "mpaa", "tagline", "plotoutline","plot", "writer", "playcount", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMovies"}') json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "filter": {"operator": "contains", "field": "path", "value": "' + id + '"}, "properties" : ["art", "rating", "thumbnail", "resume", "runtime", "year", "genre", "cast", "trailer", "country", "studio", "set", "imdbnumber", "mpaa", "tagline", "plotoutline","plot", "sorttitle", "director", "writer", "playcount", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMovies"}')
jsonobject = json.loads(json_response.decode('utf-8','replace')) jsonobject = json.loads(json_response.decode('utf-8','replace'))
movie = None movie = None

View file

@ -42,39 +42,22 @@ def logMsg(title, msg, level = 1):
def checkKodiSources(): def checkKodiSources():
print "All sources in Kodi -->"
addon = xbmcaddon.Addon(id='plugin.video.mb3sync') addon = xbmcaddon.Addon(id='plugin.video.mb3sync')
addondir = xbmc.translatePath( addon.getAddonInfo('profile') ) addondir = xbmc.translatePath( addon.getAddonInfo('profile') )
dataPath = os.path.join(addondir,"library\\")
movieLibrary = os.path.join(dataPath,'movies\\')
tvLibrary = os.path.join(dataPath,'tvshows\\')
dataPath = os.path.join(addondir,"library") rebootRequired = False
movieLibrary = os.path.join(dataPath,'movies')
tvLibrary = os.path.join(dataPath,'tvshows')
if not xbmcvfs.exists(dataPath): if not xbmcvfs.exists(dataPath):
xbmcvfs.mkdir(dataPath) xbmcvfs.mkdir(dataPath)
if not xbmcvfs.exists(movieLibrary): if not xbmcvfs.exists(movieLibrary):
xbmcvfs.mkdir(movieLibrary) xbmcvfs.mkdir(movieLibrary)
rebootRequired = addKodiSource("mediabrowser_movies",movieLibrary,"movies")
if not xbmcvfs.exists(tvLibrary): if not xbmcvfs.exists(tvLibrary):
xbmcvfs.mkdir(tvLibrary) xbmcvfs.mkdir(tvLibrary)
rebootRequired = addKodiSource("mediabrowser_tvshows",tvLibrary,"tvshows")
allKodiSources = list()
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "Files.GetSources", "params": { "media": "video"}, "id": 1 }')
jsonobject = json.loads(json_response.decode('utf-8','replace'))
if(jsonobject.has_key('result')):
result = jsonobject['result']
if(result.has_key('sources')):
for source in result["sources"]:
allKodiSources.append(source["label"])
allKodiSources = set(allKodiSources)
rebootRequired = False
if not "mediabrowser_movies" in allKodiSources:
rebootRequired = addKodiSource("mediabrowser_movies",movieLibrary,"movies")
if not "mediabrowser_tvshows" in allKodiSources:
rebootRequired = addKodiSource("mediabrowser_tvshows",tvLibrary,"tvshows")
if rebootRequired: if rebootRequired:
ret = xbmcgui.Dialog().yesno(heading="MediaBrowser Sync service", line1="A restart of Kodi is needed to apply changes. After the reboot you need to manually assign the MediaBrowser sources to your library. See documentation. Do you want to reboot now ?") ret = xbmcgui.Dialog().yesno(heading="MediaBrowser Sync service", line1="A restart of Kodi is needed to apply changes. After the reboot you need to manually assign the MediaBrowser sources to your library. See documentation. Do you want to reboot now ?")
if ret: if ret:
@ -85,19 +68,25 @@ def addKodiSource(name, path, type):
#return boolean wether a manual reboot is required. #return boolean wether a manual reboot is required.
#todo: Do feature request with Kodi team to get support for adding a source by the json API #todo: Do feature request with Kodi team to get support for adding a source by the json API
dbPath = xbmc.translatePath("special://userdata/Database/MyVideos90.db") dbPath = xbmc.translatePath("special://userdata/Database/MyVideos90.db")
error = False
if xbmcvfs.exists(dbPath): if xbmcvfs.exists(dbPath):
connection = sqlite3.connect(dbPath) try:
cursor = connection.cursor( ) connection = sqlite3.connect(dbPath)
cursor.execute("select coalesce(max(idPath),0) as pathId from path") cursor = connection.cursor( )
pathId = cursor.fetchone()[0] cursor.execute("select coalesce(max(idPath),0) as pathId from path")
pathId = pathId + 1 pathId = cursor.fetchone()[0]
pathsql="insert into path(idPath, strPath, strContent, strScraper, strHash, scanRecursive) values(?, ?, ?, ?, ?, ?)" pathId = pathId + 1
cursor.execute(pathsql, (pathId,path + "\\",type,"metadata.local",None,2147483647)) pathsql="insert into path(idPath, strPath, strContent, strScraper, strHash, scanRecursive) values(?, ?, ?, ?, ?, ?)"
connection.commit() cursor.execute(pathsql, (pathId,path + "\\",type,"metadata.local",None,2147483647))
cursor.close() connection.commit()
cursor.close()
return False except:
error = True
else: else:
error = True
if error:
# if adding to the database failed, manually add it to sources.xml # if adding to the database failed, manually add it to sources.xml
sourcesFile = xbmc.translatePath( "special://profile/sources.xml" ) sourcesFile = xbmc.translatePath( "special://profile/sources.xml" )
if xbmcvfs.exists(sourcesFile): if xbmcvfs.exists(sourcesFile):
@ -115,7 +104,11 @@ def addKodiSource(name, path, type):
SubElement(source, "name").text = name SubElement(source, "name").text = name
SubElement(source, "path").text = path SubElement(source, "path").text = path
tree.write(sourcesFile) tree.write(sourcesFile)
#return bool that reboot is needed and manual add of path to kodi
return True return True
else:
#return false that no reboot is needed
return False