From 8a990ba217bf055b943fecd0a3ee14a243c66ba2 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 1 May 2015 13:30:21 +0200 Subject: [PATCH 01/66] first work on the transition to use kodi db for all actions --- resources/lib/LibrarySync.py | 690 ++++++-------------------- resources/lib/ReadEmbyDB.py | 51 +- resources/lib/ReadKodiDB.py | 122 ++--- resources/lib/Utils.py | 2 +- resources/lib/WriteKodiDB.py | 905 +++++++++++------------------------ service.py | 4 +- 6 files changed, 464 insertions(+), 1310 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index b6135af4..d95d2989 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -12,6 +12,7 @@ import inspect import threading import urllib from datetime import datetime, timedelta, time +from itertools import chain import urllib2 import os @@ -47,23 +48,21 @@ class LibrarySync(): completed = True connection = utils.KodiSQL() cursor = connection.cursor() + + #TEMP --> add new columns + try: + cursor.execute("alter table movie ADD COLUMN 'embyId' TEXT") + cursor.execute("alter table tvshow ADD COLUMN 'embyId' TEXT") + cursor.execute("alter table episode ADD COLUMN 'embyId' TEXT") + cursor.execute("alter table musicvideo ADD COLUMN 'embyId' TEXT") + connection.commit() + except: pass + # sync movies - if(syncInstallRunDone == False): # on first install run do a full sync with model progress dialog - completed = completed and self.TvShowsSync(connection, cursor,True, True) - completed = completed and self.MoviesSync(connection, cursor,True, True) - completed = completed and self.MusicVideosSync(True, True,connection , cursor) - elif(startupDone == False): # on first run after startup do a inc then a full sync - self.TvShowsSync(connection, cursor,False, False) - self.MoviesSync(connection, cursor,False, False) - self.MusicVideosSync(False, False, connection,cursor) - self.TvShowsSync(connection, cursor,True, False) - self.MoviesSync(connection, cursor,True, False) - self.MusicVideosSync(True, False,connection,cursor) - else: # on scheduled sync do a full sync - self.TvShowsSync(connection, cursor,True, False) - self.MoviesSync(connection, cursor,True, False) - self.MusicVideosSync(True, False,connection,cursor) - + self.MoviesSync(connection,cursor,True) + #sync Tvshows and episodes + self.TvShowsSync(connection,cursor,True) + # set the install done setting if(syncInstallRunDone == False and completed): addon = xbmcaddon.Addon(id='plugin.video.emby') #force a new instance of the addon @@ -78,540 +77,145 @@ class LibrarySync(): cursor.close() return True - - def MoviesSync(self,connection, cursor, fullsync, installFirstRun,itemList = []): + + def MoviesSync(self,connection,cursor,installFirstRun,itemList = []): + + pDialog = xbmcgui.DialogProgressBG() + pDialog.create('Sync DB', 'Sync Movies') + + views = ReadEmbyDB().getCollections("movies") + + allKodiMovieIds = list() + allEmbyMovieIds = list() + + for view in views: + + allMB3Movies = ReadEmbyDB().getMovies(view.get('id')) + allKodiMovies = ReadKodiDB().getKodiMovies(connection, cursor) + #### PROCESS ADDS AND UPDATES ### + for item in allMB3Movies: + + if not item.get('IsFolder'): + allEmbyMovieIds.append(item["Id"]) + + kodiMovie = None + for kodimovie in allKodiMovies: + allKodiMovieIds.append(kodimovie[1]) + if kodimovie[1] == item["Id"]: + kodiMovie = kodimovie + + if kodiMovie == None: + allKodiMovieIds.append(item["Id"]) + WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + else: + # TODO --> compare with eTag + if kodiMovie[2] != item["Name"] or item["Id"] in itemList: + WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + + #### PROCESS DELETES ##### + allEmbyMovieIds = set(allEmbyMovieIds) + for kodiId in allKodiMovieIds: + if not kodiId in allEmbyMovieIds: + WINDOW.setProperty(kodiId,"deleted") + WriteKodiDB().deleteMovieFromKodiLibrary(kodiId, connection, cursor) + + if(pDialog != None): + pDialog.close() + + def TvShowsSync(self,connection,cursor,installFirstRun,itemList = []): + + pDialog = xbmcgui.DialogProgressBG() + pDialog.create('Sync DB', 'Sync TV Shows') + + views = ReadEmbyDB().getCollections("tvshows") + + allKodiTvShowIds = list() + allEmbyTvShowIds = list() + + for view in views: + + allEmbyTvShows = ReadEmbyDB().getTvShows(view.get('id')) + allKodiTvShows = ReadKodiDB().getKodiTvShows(connection, cursor) + + #### TVSHOW: PROCESS ADDS AND UPDATES ### + for item in allEmbyTvShows: + + if item.get('IsFolder') and item.get('RecursiveItemCount') != 0: + allEmbyTvShowIds.append(item["Id"]) + + #build a list with all Id's and get the existing entry (if exists) in Kodi DB + kodiShow = None + for kodishow in allKodiTvShows: + allKodiTvShowIds.append(kodishow[1]) + if kodishow[1] == item["Id"]: + kodiShow = kodishow + + if kodiShow == None: + # Tv show doesn't exist in Kodi yet so proceed and add it + allKodiTvShowIds.append(item["Id"]) + kodiId = WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + else: + kodiId = kodishow[0] + # If there are changes to the item, perform a full sync of the item + if kodiShow[2] != item["Name"] or item["Id"] in itemList: + WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + + #### PROCESS EPISODES ###### + self.EpisodesSync(connection,cursor,installFirstRun, item["Id"], kodiId, itemList) + + #### TVSHOW: PROCESS DELETES ##### + allEmbyTvShowIds = set(allEmbyTvShowIds) + for kodiId in allKodiTvShowIds: + if not kodiId in allEmbyTvShowIds: + WINDOW.setProperty(kodiId,"deleted") + WriteKodiDB().deleteTvShowFromKodiLibrary(kodiId, connection, cursor) + + if(pDialog != None): + pDialog.close() + + + def EpisodesSync(self,connection,cursor,installFirstRun, embyShowId, kodiShowId, itemList = []): + WINDOW = xbmcgui.Window( 10000 ) - pDialog = None - startedSync = datetime.today() - try: - addon = xbmcaddon.Addon(id='plugin.video.emby') - dbSyncIndication = addon.getSetting("dbSyncIndication") - - if(installFirstRun or dbSyncIndication == "Dialog Progress"): - pDialog = xbmcgui.DialogProgress() - elif(dbSyncIndication == "BG Progress"): - pDialog = xbmcgui.DialogProgressBG() - - if(pDialog != None): - pDialog.create('Sync DB', 'Sync DB') - - totalItemsAdded = 0 - totalItemsUpdated = 0 - totalItemsDeleted = 0 - - allEmbyMovieIds = list() - - views = ReadEmbyDB().getCollections("movies") - viewCount = len(views) - viewCurrent = 1 - progressTitle = "" - - for view in views: - - #process new movies - allMB3Movies = ReadEmbyDB().getMovies(id = view.get('id'), fullinfo=True, fullSync = fullsync, itemList = itemList) - allKodiIds = set(ReadKodiDB().getKodiMoviesIds(True)) - - if(self.ShouldStop(pDialog)): - return False - - if(allMB3Movies == None): - return False - - if(pDialog != None): - progressTitle = "Sync DB : Processing " + view.get('title') + " " + str(viewCurrent) + " of " + str(viewCount) - pDialog.update(0, progressTitle) - total = len(allMB3Movies) + 1 - count = 1 - - for item in allMB3Movies: - - if not item.get('IsFolder'): - allEmbyMovieIds.append(item["Id"]) - item['Tag'] = [] - item['Tag'].append(view.get('title')) - - if item["Id"] not in allKodiIds: - WriteKodiDB().addMovieToKodiLibrary(item,connection, cursor) - totalItemsAdded += 1 - - if(self.ShouldStop(pDialog)): - return False - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, "Adding Movie: " + str(count)) - count += 1 - - if(self.ShouldStop(pDialog)): - return False - - if(pDialog != None): - progressTitle = "Sync DB : Processing " + view.get('title') + " " + str(viewCurrent) + " of " + str(viewCount) - pDialog.update(0, progressTitle, "") - total = len(allMB3Movies) + 1 - count = 1 - - #process updates - allKodiMovies = ReadKodiDB().getKodiMovies(True) - for item in allMB3Movies: - - if not item.get('IsFolder'): - item['Tag'] = [] - item['Tag'].append(view.get('title')) - - if allKodiMovies != None: - kodimovie = allKodiMovies.get(item["Id"], None) - else: - kodimovie = None - - userData = API().getUserData(item) - - if(kodimovie != None): - updated = WriteKodiDB().updateMovieToKodiLibrary_Batched(item, kodimovie, connection, cursor) - if(updated): - totalItemsUpdated += 1 - - if(self.ShouldStop(pDialog)): - return False - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, "Updating Movie: " + str(count)) - count += 1 - - viewCurrent += 1 - - # process box sets - TODO cope with movies removed from a set - if fullsync: - - if(pDialog != None): - progressTitle = "Sync DB : BoxSets" - pDialog.update(0, progressTitle, "Retrieving Boxset List") - - utils.logMsg("Sync Movies", "BoxSet Sync Started", 1) - boxsets = ReadEmbyDB().getBoxSets() - - if(pDialog != None): - total = len(boxsets) + 1 - count = 1 - - for boxset in boxsets: - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, "Updating BoxSet: " + str(count) + " of " + str(total)) - count += 1 - if(self.ShouldStop(pDialog)): - return False - boxsetMovies = ReadEmbyDB().getMoviesInBoxSet(boxset["Id"]) - WriteKodiDB().addBoxsetToKodiLibrary(boxset,connection, cursor) - - for boxsetMovie in boxsetMovies: - if(self.ShouldStop(pDialog)): - return False - WriteKodiDB().updateBoxsetToKodiLibrary(boxsetMovie,boxset) - - utils.logMsg("Sync Movies", "BoxSet Sync Finished", 1) - - if(pDialog != None): - progressTitle = "Removing Deleted Items" - pDialog.update(0, progressTitle, "") - - if(self.ShouldStop(pDialog)): - return False - - # process any deletes only at fullsync - if fullsync: - allKodiIds = ReadKodiDB().getKodiMoviesIds(True) - allEmbyMovieIds = set(allEmbyMovieIds) - for kodiId in allKodiIds: - if not kodiId in allEmbyMovieIds: - WINDOW.setProperty(kodiId,"deleted") - WriteKodiDB().deleteMovieFromKodiLibrary(kodiId) - totalItemsDeleted += 1 - - if(self.ShouldStop(pDialog)): - return False - - # display notification if set up - notificationString = "" - if(totalItemsAdded > 0): - notificationString += "Added:" + str(totalItemsAdded) + " " - if(totalItemsUpdated > 0): - notificationString += "Updated:" + str(totalItemsUpdated) + " " - if(totalItemsDeleted > 0): - notificationString += "Deleted:" + str(totalItemsDeleted) + " " - - timeTaken = datetime.today() - startedSync - timeTakenString = str(int(timeTaken.seconds / 60)) + ":" + str(timeTaken.seconds % 60) - utils.logMsg("Sync Movies", "Finished " + timeTakenString + " " + notificationString, 0) - - if(dbSyncIndication == "Notify OnChange" and notificationString != ""): - notificationString = "(" + timeTakenString + ") " + notificationString - xbmc.executebuiltin("XBMC.Notification(Movie Sync: " + notificationString + ",)") - elif(dbSyncIndication == "Notify OnFinish"): - if(notificationString == ""): - notificationString = "Done" - notificationString = "(" + timeTakenString + ") " + notificationString - xbmc.executebuiltin("XBMC.Notification(Movie Sync: " + notificationString + ",)") - - finally: - if(pDialog != None): - pDialog.close() + allKodiEpisodeIds = list() + allEmbyEpisodeIds = list() - return True + allEmbyEpisodes = ReadEmbyDB().getEpisodes(embyShowId) + allKodiEpisodes = ReadKodiDB().getKodiEpisodes(connection, cursor, kodiShowId) + + #### EPISODES: PROCESS ADDS AND UPDATES ### + for item in allEmbyEpisodes: + + allEmbyEpisodeIds.append(item["Id"]) + + #build a list with all Id's and get the existing entry (if exists) in Kodi DB + kodiEpisode = None + for kodiepisode in allKodiEpisodes: + allKodiEpisodeIds.append(kodiepisode[1]) + if kodiepisode[1] == item["Id"]: + kodiEpisode = kodiepisode + + if kodiEpisode == None: + # Episode doesn't exist in Kodi yet so proceed and add it + allKodiEpisodeIds.append(item["Id"]) + WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor) + else: + # If there are changes to the item, perform a full sync of the item + if kodiEpisode[2] != item["Name"] or item["Id"] in itemList: + WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"], kodiShowId, connection, cursor) - def TvShowsSync(self, connection, cursor ,fullsync, installFirstRun, itemList = []): + #### EPISODES: PROCESS DELETES ##### + allEmbyEpisodeIds = set(allEmbyEpisodeIds) + print allEmbyEpisodeIds + for kodiId in allKodiEpisodeIds: + if not kodiId in allEmbyEpisodeIds: + WINDOW.setProperty(kodiId,"deleted") + print "deleting ???-->" + kodiId + #WriteKodiDB().deleteEpisodeFromKodiLibrary(kodiId, connection, cursor) - addon = xbmcaddon.Addon(id='plugin.video.emby') - WINDOW = xbmcgui.Window( 10000 ) - pDialog = None - startedSync = datetime.today() - - try: - dbSyncIndication = addon.getSetting("dbSyncIndication") - - if(installFirstRun or dbSyncIndication == "Dialog Progress"): - pDialog = xbmcgui.DialogProgress() - elif(dbSyncIndication == "BG Progress"): - pDialog = xbmcgui.DialogProgressBG() - - if(pDialog != None): - pDialog.create('Sync DB', 'Sync DB') - - totalItemsAdded = 0 - totalItemsUpdated = 0 - totalItemsDeleted = 0 - allTVShows = list() - allMB3EpisodeIds = list() #for use with deletions - allKodiEpisodeIds = [] # for use with deletions - - views = ReadEmbyDB().getCollections("tvshows") - viewCount = len(views) - viewCurrent = 1 - progressTitle = "" - for view in views: - - progressTitle = "Sync DB : Processing " + view.get('title') + " " + str(viewCurrent) + " of " + str(viewCount) - - # incremental sync --> new episodes only - if fullsync == False: - - latestMBEpisodes = ReadEmbyDB().getLatestEpisodes(fullinfo = True, itemList = itemList) - utils.logMsg("Sync TV", "Inc Sync Started on : " + str(len(latestMBEpisodes)) + " : " + str(itemList), 1) - - if latestMBEpisodes != None: - allKodiTvShowsIds = set(ReadKodiDB().getKodiTvShowsIds(True)) - - # get included TV Shows - showList = [] - for episode in latestMBEpisodes: - if(episode["SeriesId"] not in showList): - showList.append(episode["SeriesId"]) - - utils.logMsg("Incremental TV Sync", "Included TV Show List : " + str(showList), 0) - - if(pDialog != None): - pDialog.update(0, progressTitle) - total = len(showList) + 1 - count = 1 - - # process included TV Shows - for showID in showList: - - embyTvShow = ReadEmbyDB().getFullItem(showID) - - if(showID not in allKodiTvShowsIds): - utils.logMsg("Incremental TV Sync", "Adding TV Show : " + embyTvShow.get("Name"), 1) - WriteKodiDB().addTVShowToKodiLibrary(embyTvShow, connection, cursor) - - kodiTvShow = ReadKodiDB().getKodiTVShow(showID) - utils.logMsg("Incremental TV Sync", "Updating TV Show : " + embyTvShow.get("Name"), 1) - WriteKodiDB().updateTVShowToKodiLibrary(embyTvShow, kodiTvShow, connection, cursor) - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, "Processing TV Shows : " + str(count)) - count += 1 - - if(pDialog != None): - pDialog.update(0, progressTitle) - total = len(latestMBEpisodes) + 1 - count = 1 - - # process new episodes - for episode in latestMBEpisodes: - if(self.ShouldStop(pDialog)): - return False - - WriteKodiDB().addEpisodeToKodiLibrary(episode, connection, cursor) - progressAction = "Adding" - totalItemsAdded += 1 - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, progressAction + " Episode: " + str(count)) - count += 1 - - #process updates - if(pDialog != None): - progressTitle = "Sync DB : Processing Episodes" - pDialog.update(0, progressTitle) - total = len(latestMBEpisodes) + 1 - count = 1 - - for episode in latestMBEpisodes: - if(self.ShouldStop(pDialog)): - return False - allKodiTVShows = ReadKodiDB().getKodiTvShows(False) - kodishow = allKodiTVShows.get(episode["SeriesId"],None) - kodiEpisodes = ReadKodiDB().getKodiEpisodes(kodishow["tvshowid"],True,True) - - if(self.ShouldStop(pDialog)): - return False - - userData = API().getUserData(episode) - - if kodiEpisodes != None: - KodiItem = kodiEpisodes.get(episode.get("Id"), None) - if(KodiItem != None): - WriteKodiDB().updateEpisodeToKodiLibrary(episode, KodiItem, connection, cursor) - - if(self.ShouldStop(pDialog)): - return False - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, "Updating Episode: " + str(count)) - count += 1 - - - # full sync --> Tv shows and Episodes - if fullsync: - viewTVShows = list() - tvShowData = ReadEmbyDB().getTVShows(id = view.get('id') , fullinfo = True, fullSync = True) - allKodiIds = set(ReadKodiDB().getKodiTvShowsIds(True)) - - if(self.ShouldStop(pDialog)): - return False - - if (tvShowData == None): - return False - - if(pDialog != None): - progressTitle = "Sync DB : Processing TV Shows" - pDialog.update(0, progressTitle) - total = len(tvShowData) + 1 - count = 1 - - # add TV Shows - for item in tvShowData: - if item.get('IsFolder') and item.get('RecursiveItemCount') != 0: - allTVShows.append(item["Id"]) - viewTVShows.append(item["Id"]) - item['Tag'] = [] - item['Tag'].append(view.get('title')) - progMessage = "Processing" - if item["Id"] not in allKodiIds: - WriteKodiDB().addTVShowToKodiLibrary(item,connection, cursor) - totalItemsAdded += 1 - - if(self.ShouldStop(pDialog)): - return False - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, "Adding Tv Show: " + str(count)) - count += 1 - - if(pDialog != None): - progressTitle = "Sync DB : Processing TV Shows" - pDialog.update(0, progressTitle, "") - total = len(viewTVShows) + 1 - count = 1 - - # update TV Shows - allKodiTVShows = ReadKodiDB().getKodiTvShows(True) - for item in tvShowData: - if item.get('IsFolder'): - item['Tag'] = [] - item['Tag'].append(view.get('title')) - if allKodiTVShows != None: - kodishow = allKodiTVShows.get(item["Id"],None) - else: - kodishow = None - - if(kodishow != None): - updated = WriteKodiDB().updateTVShowToKodiLibrary(item,kodishow,connection, cursor) - if(updated): - totalItemsUpdated += 1 - - if(self.ShouldStop(pDialog)): - return False - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, "Updating Tv Show: " + str(count)) - count += 1 - - - # do episode adds - allEpisodes = list() - showTotal = len(viewTVShows) - showCurrent = 1 - for tvshow in viewTVShows: - - episodeData = ReadEmbyDB().getEpisodes(tvshow,True) - if episodeData != None: - - if(self.ShouldStop(pDialog)): - return False - - if(pDialog != None): - progressTitle = "Sync DB : Processing Tv Show " + str(showCurrent) + " of " + str(showTotal) - pDialog.update(0, progressTitle) - total = len(episodeData) + 1 - count = 0 - - for item in episodeData: - - if(self.ShouldStop(pDialog)): - return False - - progressAction = "Adding" - WriteKodiDB().addEpisodeToKodiLibrary(item, connection, cursor) - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, progressAction + " Episode: " + str(count)) - count += 1 - - showCurrent += 1 - - # do episode updates - showCurrent = 1 - for tvshow in viewTVShows: - episodeData = ReadEmbyDB().getEpisodes(tvshow,True) - - kodiEpisodes = None - allKodiTVShows = ReadKodiDB().getKodiTvShows(False) - if allKodiTVShows != None: - kodishow = allKodiTVShows.get(tvshow,None) - if kodishow != None: - kodiEpisodes = ReadKodiDB().getKodiEpisodes(kodishow["tvshowid"],True,True) - - if(self.ShouldStop(pDialog)): - return False - - if(pDialog != None): - progressTitle = "Sync DB : Processing Tv Show " + str(showCurrent) + " of " + str(showTotal) - pDialog.update(0, progressTitle) - total = len(episodeData) + 1 - count = 0 - - #we have to compare the lists somehow - for item in episodeData: - #add episodeId to the list of all episodes for use later on the deletes - allMB3EpisodeIds.append(item["Id"]) - - matchFound = False - - userData = API().getUserData(item) - - if kodiEpisodes != None: - KodiItem = kodiEpisodes.get(item.get("Id"), None) - if(KodiItem != None): - updated = WriteKodiDB().updateEpisodeToKodiLibrary(item, KodiItem, connection, cursor) - if(updated): - totalItemsUpdated += 1 - - if(self.ShouldStop(pDialog)): - return False - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, "Updating Episode: " + str(count)) - count += 1 - - - #add all kodi episodes to a list with episodes for use later on to delete episodes - #the mediabrowser ID is set as uniqueID in the NFO... for some reason this has key 'unknown' in the json response - if kodishow != None: - show = ReadKodiDB().getKodiEpisodes(kodishow["tvshowid"],False,False) - if show != None: - for episode in show: - dict = {'episodeid': str(episode["uniqueid"]["unknown"]),'tvshowid': tvshow} - allKodiEpisodeIds.append(dict) - - showCurrent += 1 - - if(pDialog != None): - progressTitle = "Removing Deleted Items" - pDialog.update(0, progressTitle) - - if(self.ShouldStop(pDialog)): - return False - - # DELETES -- EPISODES - # process any deletes only at fullsync - allMB3EpisodeIdsSet = set(allMB3EpisodeIds) - for episode in allKodiEpisodeIds: - if episode.get('episodeid') not in allMB3EpisodeIdsSet: - WINDOW.setProperty("embyid" + str(episode.get('episodeid')),"deleted") - WriteKodiDB().deleteEpisodeFromKodiLibrary(episode.get('episodeid'),episode.get('tvshowid')) - totalItemsDeleted += 1 - - # DELETES -- TV SHOWS - if fullsync: - allKodiShows = ReadKodiDB().getKodiTvShowsIds(True) - allMB3TVShows = set(allTVShows) - for show in allKodiShows: - if not show in allMB3TVShows: - WriteKodiDB().deleteTVShowFromKodiLibrary(show) - totalItemsDeleted += 1 - - if(self.ShouldStop(pDialog)): - return False - - # display notification if set up - notificationString = "" - if(totalItemsAdded > 0): - notificationString += "Added:" + str(totalItemsAdded) + " " - if(totalItemsUpdated > 0): - notificationString += "Updated:" + str(totalItemsUpdated) + " " - if(totalItemsDeleted > 0): - notificationString += "Deleted:" + str(totalItemsDeleted) + " " - - timeTaken = datetime.today() - startedSync - timeTakenString = str(int(timeTaken.seconds / 60)) + ":" + str(timeTaken.seconds % 60) - utils.logMsg("Sync Episodes", "Finished " + timeTakenString + " " + notificationString, 0) - - if(dbSyncIndication == "Notify OnChange" and notificationString != ""): - notificationString = "(" + timeTakenString + ") " + notificationString - xbmc.executebuiltin("XBMC.Notification(Episode Sync: " + notificationString + ",)") - elif(dbSyncIndication == "Notify OnFinish"): - if(notificationString == ""): - notificationString = "Done" - notificationString = "(" + timeTakenString + ") " + notificationString - xbmc.executebuiltin("XBMC.Notification(Episode Sync: " + notificationString + ",)") - - finally: - if(pDialog != None): - pDialog.close() - - return True def MusicVideosSync(self, fullsync, installFirstRun,connection, cursor): diff --git a/resources/lib/ReadEmbyDB.py b/resources/lib/ReadEmbyDB.py index 4d80455c..23773820 100644 --- a/resources/lib/ReadEmbyDB.py +++ b/resources/lib/ReadEmbyDB.py @@ -6,30 +6,22 @@ import xbmc import xbmcgui import xbmcaddon + + from DownloadUtils import DownloadUtils addon = xbmcaddon.Addon(id='plugin.video.emby') class ReadEmbyDB(): - def getMovies(self, id, fullinfo = False, fullSync = True, itemList = []): + def getMovies(self, id): result = None doUtils = DownloadUtils() - - if fullSync: - sortstring = "&SortBy=SortName" - else: - if(len(itemList) > 0): # if we want a certain list specify it - #sortstring = "&Ids=" + ",".join(itemList) - sortstring = "" # work around for now until ParetnId and Id work together - else: # just get the last 20 created items - sortstring = "&Limit=20&SortBy=DateCreated" - - if fullinfo: - url = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s%s&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Movie&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % (id, sortstring) - else: - url = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Movie&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % (id, sortstring) + + #only get basic info for our sync-compares + sortstring = "&SortBy=SortName" + url = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Movie&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % (id, sortstring) jsonData = doUtils.downloadUrl(url) if (jsonData == ""): @@ -37,14 +29,6 @@ class ReadEmbyDB(): if (jsonData[u'Items'] != ""): result = jsonData[u'Items'] - - # work around for now until ParetnId and Id work together - 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 @@ -98,20 +82,14 @@ class ReadEmbyDB(): return result - def getTVShows(self, id, fullinfo = False, fullSync = False): + def getTvShows(self, id): result = None doUtils = DownloadUtils() - - if not fullSync: - sortstring = "&Limit=20&SortBy=DateCreated" - else: - sortstring = "&SortBy=SortName" - if fullinfo: - url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s%s&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1" % (id, sortstring) - else: - url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1" % (id, sortstring) + #only get basic info for our sync-compares + sortstring = "&SortBy=SortName" + url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1" % (id, sortstring) jsonData = doUtils.downloadUrl(url) if (jsonData == ""): @@ -138,15 +116,12 @@ class ReadEmbyDB(): return result - def getEpisodes(self, showId, fullinfo = False): + def getEpisodes(self, showId): result = None doUtils = DownloadUtils() - if fullinfo: - url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&IsVirtualUnaired=false&IsMissing=False&SortBy=SortName&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % showId - else: - url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&IsVirtualUnaired=false&IsMissing=False&SortBy=SortName&Fields=Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % showId + url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&IsVirtualUnaired=false&IsMissing=False&SortBy=SortName&Fields=Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % showId jsonData = doUtils.downloadUrl(url) if (jsonData == ""): diff --git a/resources/lib/ReadKodiDB.py b/resources/lib/ReadKodiDB.py index f5acdb26..14b0872a 100644 --- a/resources/lib/ReadKodiDB.py +++ b/resources/lib/ReadKodiDB.py @@ -30,71 +30,38 @@ class ReadKodiDB(): movies = result['movies'] movie = movies[0] for item in movies: - if item["imdbnumber"] == id: + if id in item["file"]: movie = item break return movie def getEmbyIdByKodiId(self, kodiid, type): - #returns the emby id by search on kodi id - xbmc.sleep(sleepVal) - embyId = None - json_response = None + connection = utils.KodiSQL() + cursor = connection.cursor() if type == "movie": - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovieDetails", "params": { "movieid": %d, "properties" : ["imdbnumber","file"] }, "id": "libMovies"}' %kodiid) + cursor.execute("SELECT embyId as embyId FROM movie WHERE idMovie = ?",(kodiid,)) if type == "episode": - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodeDetails", "params": {"episodeid": %d, "properties": ["file","uniqueid"]}, "id": 1}' %kodiid) + cursor.execute("SELECT embyId as embyId FROM episode WHERE idEpisode = ?",(kodiid,)) if type == "musicvideo": - connection = utils.KodiSQL() - cursor = connection.cursor() - cursor.execute("SELECT c23 as MBid FROM musicvideo WHERE idMVideo = ?",(kodiid,)) - result = cursor.fetchone() - cursor.close() - if result != None: - embyId = result[0] + cursor.execute("SELECT embyId as embyId FROM musicvideo WHERE idMVideo = ?",(kodiid,)) + if type == "tvshow": + cursor.execute("SELECT embyId as embyId FROM tvshow WHERE idShow = ?",(kodiid,)) - if json_response != None: - jsonobject = json.loads(json_response.decode('utf-8','replace')) - if(jsonobject.has_key('result')): - result = jsonobject['result'] - resulttype = type + "details" - if(result.has_key(resulttype)): - item = result[resulttype] - if type == "movie": - if item.has_key('imdbnumber'): - embyId = item['imdbnumber'] - if type == "episode": - if item.has_key('uniqueid'): - if item['uniqueid'].has_key('unknown'): - embyId = item["uniqueid"]["unknown"] + result = cursor.fetchone() + cursor.close() + if result != None: + embyId = result[0] return embyId - def getKodiMovies(self,fullInfo = False): + def getKodiMovies(self, connection, cursor): #returns all movies in Kodi db - xbmc.sleep(sleepVal) - if fullInfo: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "properties" : ["art", "rating", "thumbnail", "fanart", "resume", "runtime", "year", "genre", "cast", "trailer", "country", "lastplayed", "studio", "set", "imdbnumber", "mpaa", "tagline", "plotoutline","plot", "sorttitle", "director", "writer", "playcount", "tag", "file"] }, "id": "libMovies"}') - else: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "properties" : ["resume", "playcount", "imdbnumber", "lastplayed", "file"] }, "id": "libMovies"}') - jsonobject = json.loads(json_response.decode('utf-8','replace')) - movies = None - - if(jsonobject.has_key('result')): - result = jsonobject['result'] - if(result.has_key('movies')): - movies = result['movies'] - - kodiMovieMap = None - if(movies != None and len(movies) > 0): - kodiMovieMap = {} - for kodimovie in movies: - key = kodimovie["imdbnumber"] #extract the id from the imdbnumber - kodiMovieMap[key] = kodimovie - - return kodiMovieMap + cursor.execute("SELECT idMovie, embyId, c00 FROM movie") + allmovies = cursor.fetchall() + #this will return a list with tuples of all items returned from the database + return allmovies def getKodiMoviesIds(self,returnMB3Ids = False): # returns a list of movieIds or MB3 Id's from all movies currently in the Kodi library @@ -132,29 +99,11 @@ class ReadKodiDB(): return allKodiTvShowsIds - def getKodiTvShows(self,fullInfo = False): - #returns all tvshows in Kodi db inserted by MB - xbmc.sleep(sleepVal) - if fullInfo: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "properties": ["art", "genre", "plot", "mpaa", "cast", "studio", "sorttitle", "title", "originaltitle", "imdbnumber", "year", "premiered", "rating", "thumbnail", "playcount", "lastplayed", "file", "fanart", "tag"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libTvShows"}') - else: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "properties": ["sorttitle", "title", "playcount", "lastplayed", "imdbnumber", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libTvShows"}') - jsonobject = json.loads(json_response.decode('utf-8','replace')) - tvshows = None - - if(jsonobject.has_key('result')): - result = jsonobject['result'] - if(result.has_key('tvshows')): - tvshows = result['tvshows'] - - kodiShowMap = None - if(tvshows != None and len(tvshows) > 0): - kodiShowMap = {} - for kodishow in tvshows: - key = kodishow["imdbnumber"] #extract the id from the imdb number - kodiShowMap[key] = kodishow - - return kodiShowMap + def getKodiTvShows(self, connection, cursor): + cursor.execute("SELECT idShow, embyId, c00 FROM tvshow") + allshows = cursor.fetchall() + #this will return a list with tuples of all items returned from the database + return allshows def getKodiTVShow(self, id): xbmc.sleep(sleepVal) @@ -171,28 +120,11 @@ class ReadKodiDB(): break return tvshow - def getKodiEpisodes(self, KodiTvShowId, fullInfo = True, returnmap = True): - xbmc.sleep(sleepVal) - episodes = None - if fullInfo: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, "properties": ["title", "playcount", "plot", "season", "episode", "showtitle", "file", "lastplayed", "rating", "resume", "art", "streamdetails", "firstaired", "runtime", "writer", "cast", "director", "dateadded", "uniqueid", "thumbnail", "fanart"], "sort": {"method": "episode"}}, "id": 1}' %KodiTvShowId) - else: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, "properties": ["title", "playcount", "season", "episode", "lastplayed", "resume","file","uniqueid"], "sort": {"method": "episode"}}, "id": 1}' %KodiTvShowId) - jsonobject = json.loads(json_response.decode('utf-8','replace')) - episodes = None - if(jsonobject.has_key('result')): - result = jsonobject['result'] - if(result.has_key('episodes')): - episodes = result['episodes'] - if returnmap: - episodeMap = None - if(episodes != None): - episodeMap = {} - for KodiItem in episodes: - episodeMap[KodiItem["uniqueid"]["unknown"]] = KodiItem - return episodeMap - else: - return episodes + def getKodiEpisodes(self, connection, cursor, showid): + cursor.execute("SELECT idEpisode, embyId, c00 FROM episode WHERE idShow = ?", (showid,)) + allepisodes = cursor.fetchall() + #this will return a list with tuples of all items returned from the database + return allepisodes def getKodiEpisodeByMbItem(self, episodeid, tvshowid): episode = None diff --git a/resources/lib/Utils.py b/resources/lib/Utils.py index 4f47b77f..a9da6b5c 100644 --- a/resources/lib/Utils.py +++ b/resources/lib/Utils.py @@ -53,7 +53,7 @@ def convertEncoding(data): def KodiSQL(): connection = sqlite3.connect(getKodiDBPath()) - + return connection def getKodiDBPath(): diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index b46ccb44..d2cf5421 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -43,107 +43,7 @@ class WriteKodiDB(): else: downloadUtils.downloadUrl(watchedurl, type="DELETE") - def updateMovieToKodiLibrary_Batched(self, MBitem, KodiItem,connection, cursor): - addon = xbmcaddon.Addon(id='plugin.video.emby') - WINDOW = xbmcgui.Window(10000) - username = WINDOW.getProperty('currUser') - server = WINDOW.getProperty('server%s' % username) - - downloadUtils = DownloadUtils() - - timeInfo = API().getTimeInfo(MBitem) - userData=API().getUserData(MBitem) - people = API().getPeople(MBitem) - genre = API().getGenre(MBitem) - studios = API().getStudios(MBitem) - mediaStreams=API().getMediaStreams(MBitem) - - thumbPath = API().getArtwork(MBitem, "Primary") - - params = list() - - self.getArtworkParam_Batched(KodiItem, MBitem, params) - - #set Filename - playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) - self.setKodiFilename(KodiItem["movieid"], KodiItem["file"], playurl, "movie", MBitem["Id"], connection, cursor) - - #update common properties - if KodiItem["runtime"] == 0: - self.getPropertyParam_Batched(KodiItem, "runtime", (int(timeInfo.get('Duration'))*60), params) - self.getPropertyParam_Batched(KodiItem, "year", MBitem.get("ProductionYear"), params) - self.getPropertyParam_Batched(KodiItem, "mpaa", MBitem.get("OfficialRating"), params) - self.getPropertyParam_Batched(KodiItem, "lastplayed", userData.get("LastPlayedDate"), params) - self.getPropertyParamArray_Batched(KodiItem, "tag", MBitem.get("Tag"), params) - - if MBitem.get("CommunityRating") != None: - self.getPropertyParam_Batched(KodiItem, "rating", Decimal(format(MBitem.get("CommunityRating"),'.1f')), params) - - self.getPropertyParam_Batched(KodiItem, "plot", MBitem.get("Overview"), params) - self.getPropertyParam_Batched(KodiItem, "plotoutline", MBitem.get("ShortOverview"), params) - self.getPropertyParam_Batched(KodiItem, "set", MBitem.get("TmdbCollectionName"), params) - self.getPropertyParam_Batched(KodiItem, "sorttitle", MBitem.get("SortName"), params) - - if MBitem.get("ProviderIds") != None: - if MBitem.get("ProviderIds").get("Imdb") != None: - self.getPropertyParam_Batched(KodiItem, "imdbnumber", MBitem.get("ProviderIds").get("Imdb"), params) - - # FIXME --> Taglines not returned by MB3 server !? - if MBitem.get("TagLines") != None: - self.getPropertyParam_Batched(KodiItem, "tagline", MBitem.get("TagLines")[0], params) - - self.getPropertyParamArray_Batched(KodiItem, "writer", people.get("Writer"), params) - self.getPropertyParamArray_Batched(KodiItem, "director", people.get("Director"), params) - self.getPropertyParamArray_Batched(KodiItem, "genre", MBitem.get("Genres"), params) - - if(studios != None): - for x in range(0, len(studios)): - studios[x] = studios[x].replace("/", "&") - self.getPropertyParamArray_Batched(KodiItem, "studio", studios, params) - - # FIXME --> ProductionLocations not returned by MB3 server !? - self.getPropertyParamArray_Batched(KodiItem, "country", MBitem.get("ProductionLocations"), params) - - #trailer link - trailerUrl = None - if MBitem.get("LocalTrailerCount") != None and MBitem.get("LocalTrailerCount") > 0: - itemTrailerUrl = "{server}/mediabrowser/Users/{UserId}/Items/%s/LocalTrailers?format=json" % MBitem.get("Id") - jsonData = downloadUtils.downloadUrl(itemTrailerUrl) - if (jsonData != ""): - trailerItem = jsonData - if trailerItem[0][u'LocationType'] == "FileSystem": - trailerUrl = PlayUtils().getPlayUrl(server, trailerItem[0][u'Id'], trailerItem[0]) - trailerUrl = utils.convertEncoding(trailerUrl) - self.getPropertyParam_Batched(KodiItem, "trailer", trailerUrl, params) - - - changes = False - # if there were movies changes then send the update via JSONRPC - if(len(params) > 0): - changes |= True - utils.logMsg("UpdateMovieParams", str(params), level = 2) - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": %i, %s}, "id": 1 }' - paramString = "" - paramLen = len(params) - for x in range(0, paramLen): - param = params[x] - paramString += param - if(x < paramLen-1): - paramString += ", " - jsoncommand = jsoncommand %(KodiItem['movieid'], paramString) - utils.logMsg("executeJSONRPC : ", jsoncommand, level = 2) - xbmc.sleep(sleepVal) - result = xbmc.executeJSONRPC(jsoncommand.encode("utf-8")) - - #add actors - changes |= self.AddActorsToMedia(KodiItem,MBitem.get("People"), "movie", connection, cursor) - - if(changes): - utils.logMsg("Updated item to Kodi Library", MBitem["Id"] + " - " + MBitem["Name"], level=0) - - return changes - def updateMusicVideoToKodiLibrary_Batched(self, MBitem, KodiItem): addon = xbmcaddon.Addon(id='plugin.video.emby') port = addon.getSetting('port') @@ -201,74 +101,6 @@ class WriteKodiDB(): if(changes): utils.logMsg("Updated musicvideo to Kodi Library", MBitem["Id"] + " - " + MBitem["Name"], level=0) - def updateTVShowToKodiLibrary( self, MBitem, KodiItem,connection, cursor ): - - addon = xbmcaddon.Addon(id='plugin.video.emby') - port = addon.getSetting('port') - host = addon.getSetting('ipaddress') - server = host + ":" + port - downloadUtils = DownloadUtils() - - timeInfo = API().getTimeInfo(MBitem) - userData=API().getUserData(MBitem) - people = API().getPeople(MBitem) - genre = API().getGenre(MBitem) - studios = API().getStudios(MBitem) - mediaStreams=API().getMediaStreams(MBitem) - - thumbPath = API().getArtwork(MBitem, "Primary") - - changes = False - - #set Filename - playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) - #make sure that the path always ends with a slash - playurl = playurl + "/" - self.setKodiFilename(KodiItem["tvshowid"], KodiItem["file"], playurl, "tvshow", MBitem["Id"], connection, cursor) - - #update/check all artwork - changes |= self.updateArtWork(KodiItem,MBitem) - - #update common properties - if MBitem.get("PremiereDate") != None: - premieredatelist = (MBitem.get("PremiereDate")).split("T") - premieredate = premieredatelist[0] - changes |= self.updateProperty(KodiItem,"premiered",premieredate,"tvshow") - - changes |= self.updatePropertyArray(KodiItem,"tag",MBitem.get("Tag"),"tvshow") - changes |= self.updateProperty(KodiItem,"mpaa",MBitem.get("OfficialRating"),"tvshow") - changes |= self.updateProperty(KodiItem,"lastplayed",MBitem.get("LastPlayedDate"),"tvshow") - - if MBitem.get("CommunityRating") != None: - changes |= self.updateProperty(KodiItem,"rating",Decimal(format(MBitem.get("CommunityRating"),'.1f')),"tvshow") - - changes |= self.updateProperty(KodiItem,"sorttitle",utils.convertEncoding(MBitem["SortName"]),"tvshow") - changes |= self.updateProperty(KodiItem,"title",utils.convertEncoding(MBitem["Name"]),"tvshow") - changes |= self.updateProperty(KodiItem,"plot",utils.convertEncoding(API().getOverview(MBitem)),"tvshow") - - # we use this to store the Emby ID so make sure we use that - changes |= self.updateProperty(KodiItem, "imdbnumber", MBitem.get("Id"), "tvshow") - - changes |= self.updatePropertyArray(KodiItem,"genre",MBitem.get("Genres"),"tvshow") - - if(studios != None): - for x in range(0, len(studios)): - studios[x] = studios[x].replace("/", "&") - changes |= self.updatePropertyArray(KodiItem,"studio",studios,"tvshow") - - # FIXME --> ProductionLocations not returned by MB3 server !? - changes |= self.updatePropertyArray(KodiItem, "country", MBitem.get("ProductionLocations"), "tvshow") - - #add actors - changes |= self.AddActorsToMedia(KodiItem,MBitem.get("People"),"tvshow", connection, cursor) - - #update season details - self.updateSeasons(MBitem, KodiItem,connection, cursor) - - if changes: - utils.logMsg("Updated item to Kodi Library", MBitem["Id"] + " - " + MBitem["Name"]) - - return changes def updateEpisodeToKodiLibrary( self, MBitem, KodiItem, connection, cursor ): addon = xbmcaddon.Addon(id='plugin.video.emby') @@ -288,48 +120,7 @@ class WriteKodiDB(): #update/check all artwork changes |= self.updateArtWork(KodiItem,MBitem) - #set Filename (will update the filename in db if changed) - playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) - changes |= self.setKodiFilename(KodiItem["episodeid"], KodiItem["file"], playurl, "episode", MBitem["Id"], connection, cursor) - - #update common properties - if KodiItem["runtime"] == 0: - changes |= self.updateProperty(KodiItem,"runtime",(int(timeInfo.get('Duration'))*60),"episode") - changes |= self.updateProperty(KodiItem,"lastplayed",userData.get("LastPlayedDate"),"episode") - - if MBitem.get("PremiereDate") != None: - premieredatelist = (MBitem.get("PremiereDate")).split("T") - premieredate = premieredatelist[0] - premieretime = premieredatelist[1].split(".")[0] - firstaired = premieredate + " " + premieretime - # for Helix we use the whole time string, for kodi 15 we have to change to only the datestring - # see: http://forum.kodi.tv/showthread.php?tid=218743 - if KodiItem["firstaired"] != premieredate: - changes |= self.updateProperty(KodiItem,"firstaired",firstaired,"episode") - - if MBitem.get("CommunityRating") != None: - changes |= self.updateProperty(KodiItem,"rating",Decimal(format(MBitem.get("CommunityRating"),'.1f')),"episode") - - if MBitem.get("ParentIndexNumber") != None: - season = int(MBitem.get("ParentIndexNumber")) - changes |= self.updateProperty(KodiItem,"season",season,"episode") - # removed for now as setting c15 and c16 to -1 just shows specials in the special folder only - #if(season == 0): - # changes |= self.setSpecialAirsDetails(MBitem, KodiItem, connection, cursor) - - if MBitem.get("IndexNumber") != None: - episode = int(MBitem.get("IndexNumber")) - changes |= self.updateProperty(KodiItem,"episode",episode,"episode") - - #plot = utils.convertEncoding(API().getOverview(MBitem)) - plot = MBitem.get("Overview") - if(plot != None): - changes |= self.updateProperty(KodiItem,"plot",plot,"episode") - - title = utils.convertEncoding(MBitem["Name"]) - changes |= self.updateProperty(KodiItem,"title",title,"episode") - changes |= self.updatePropertyArray(KodiItem,"writer",people.get("Writer"),"episode") - changes |= self.updatePropertyArray(KodiItem,"director",people.get("Director"),"episode") + addOrUpdateEpisodeToKodiLibrary(MBitem, connection, cursor) #add actors changes |= self.AddActorsToMedia(KodiItem,MBitem.get("People"),"episode", connection, cursor) @@ -597,23 +388,50 @@ class WriteKodiDB(): return pendingChanges - def addMovieToKodiLibrary( self, MBitem ,connection, cursor): - #adds a movie to Kodi by directly inserting it to the DB while there is no addmovie available on the json API - #TODO: PR at Kodi team for a addMovie endpoint on their API + def addOrUpdateMovieToKodiLibrary( self, embyId ,connection, cursor, viewTag): 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 idMovie FROM movie WHERE embyId = ?",(MBitem["Id"],)) + result = cursor.fetchone() + if result != None: + movieid = result[0] + else: + movieid = None + timeInfo = API().getTimeInfo(MBitem) userData=API().getUserData(MBitem) - playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) - playurl = utils.convertEncoding(playurl) + #### The movie details ######### + runtime = int(timeInfo.get('Duration'))*60 + plot = utils.convertEncoding(API().getOverview(MBitem)) + title = utils.convertEncoding(MBitem["Name"]) + sorttitle = utils.convertEncoding(MBitem["SortName"]) + year = MBitem.get("ProductionYear") + rating = MBitem.get("CommunityRating") + + if MBitem.get("ShortOverview") != None: + shortplot = utils.convertEncoding(MBitem.get("ShortOverview")) + else: + shortplot = None + + trailerUrl = None + if MBitem.get("LocalTrailerCount") != None and MBitem.get("LocalTrailerCount") > 0: + itemTrailerUrl = "%s/mediabrowser/Users/%s/Items/%s/LocalTrailers?format=json" % (server, userid, MBitem.get("Id")) + jsonData = downloadUtils.downloadUrl(itemTrailerUrl) + if(jsonData != ""): + trailerItem = jsonData + trailerUrl = "plugin://plugin.video.emby/mode=play?id=" + trailerItem[0][u'Id'] if MBitem.get("DateCreated") != None: dateadded = MBitem["DateCreated"].replace("T"," ") @@ -621,14 +439,11 @@ class WriteKodiDB(): else: dateadded = None - # we need to store both the path and the filename seperately in the kodi db so we split them up - if "\\" in playurl: - filename = playurl.rsplit("\\",1)[-1] - path = playurl.replace(filename,"") - elif "/" in playurl: - filename = playurl.rsplit("/",1)[-1] - path = playurl.replace(filename,"") - + #### ADD OR UPDATE THE FILE AND PATH ########### + #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY + path = "plugin://plugin.video.emby/movies/" + filename = "plugin://plugin.video.emby/movies/?id=" MBitem["Id"] + "&mode=play" + #create the path cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) result = cursor.fetchone() @@ -656,44 +471,29 @@ class WriteKodiDB(): fileid = fileid + 1 pathsql="insert into files(idFile, idPath, strFilename, playCount, lastPlayed, dateAdded) values(?, ?, ?, ?, ?, ?)" cursor.execute(pathsql, (fileid,pathid,filename,playcount,userData.get("LastPlayedDate"),dateadded)) - - runtime = int(timeInfo.get('Duration'))*60 - plot = utils.convertEncoding(API().getOverview(MBitem)) - title = utils.convertEncoding(MBitem["Name"]) - sorttitle = utils.convertEncoding(MBitem["SortName"]) - year = MBitem.get("ProductionYear") - rating = MBitem.get("CommunityRating") - if MBitem.get("ShortOverview") != None: - shortplot = utils.convertEncoding(MBitem.get("ShortOverview")) + + ##### ADD THE MOVIE ############ + if movieid == None: + #create the movie + cursor.execute("select coalesce(max(idMovie),0) as movieid from movie") + movieid = cursor.fetchone()[0] + movieid = movieid + 1 + pathsql="insert into movie(idMovie, idFile, c00, c01, c02, c05, c07, c10, c11, c16, c19, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (movieid, fileid, title, plot, shortplot, rating, year, sorttitle, runtime, title, trailerUrl, MBitem["Id"])) + + #### UPDATE THE MOVIE ##### else: - shortplot = None + pathsql="update movie SET c00 = ?, c01 = ?, c02 = ?, c05 = ?, c07 = ?, c10 = ?, c11 = ?, c16 = ?, c19 = ?, embyId= ? WHERE idMovie = ?" + cursor.execute(pathsql, (title, plot, shortplot, rating, year, sorttitle, runtime, title, trailerUrl, MBitem["Id"], movieid)) - trailerUrl = None - if MBitem.get("LocalTrailerCount") != None and MBitem.get("LocalTrailerCount") > 0: - itemTrailerUrl = "%s/mediabrowser/Users/%s/Items/%s/LocalTrailers?format=json" % (server, userid, MBitem.get("Id")) - jsonData = downloadUtils.downloadUrl(itemTrailerUrl) - if(jsonData != ""): - trailerItem = jsonData - if trailerItem[0][u'LocationType'] == "FileSystem": - trailerUrl = PlayUtils().getPlayUrl(server, trailerItem[0][u'Id'], trailerItem[0]) - trailerUrl = utils.convertEncoding(trailerUrl) + #update or insert actors + self.AddActorsToMedia(movieid,MBitem.get("People"),"movie", connection, cursor) - #create the movie - cursor.execute("select coalesce(max(idMovie),0) as movieid from movie") - movieid = cursor.fetchone()[0] - movieid = movieid + 1 - pathsql="insert into movie(idMovie, idFile, c00, c01, c02, c05, c07, c09, c10, c11, c16, c19) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - - cursor.execute(pathsql, (movieid, fileid, title, plot, shortplot, rating, year, MBitem["Id"], sorttitle, runtime, title, trailerUrl)) - - try: - connection.commit() - utils.logMsg("Emby","Added movie to Kodi Library",MBitem["Id"] + " - " + MBitem["Name"]) - except: - utils.logMsg("Emby","Error adding movie to Kodi Library",MBitem["Id"] + " - " + MBitem["Name"]) - actionPerformed = False - + #commit changes and return the id + connection.commit() + return movieid + def addMusicVideoToKodiLibrary( self, MBitem, connection, cursor ): #adds a musicvideo to Kodi by directly inserting it to connectionthe DB while there is no addMusicVideo available on the json API @@ -716,13 +516,8 @@ class WriteKodiDB(): else: dateadded = None - # we need to store both the path and the filename seperately in the kodi db so we split them up - if "\\" in playurl: - filename = playurl.rsplit("\\",1)[-1] - path = playurl.replace(filename,"") - elif "/" in playurl: - filename = playurl.rsplit("/",1)[-1] - path = playurl.replace(filename,"") + path = "plugin://plugin.video.emby/musicvideos/" + filename = "plugin://plugin.video.emby/musicvideos/?mode=play&id=" + MBitem["Id"] #create the path cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) @@ -770,17 +565,20 @@ class WriteKodiDB(): utils.logMsg("Emby","Error adding musicvideo to Kodi Library",MBitem["Id"] + " - " + MBitem["Name"]) actionPerformed = False - def addEpisodeToKodiLibrary(self, MBitem, connection, cursor): + def addOrUpdateEpisodeToKodiLibrary(self, embyId, showid, connection, cursor): - #adds a Episode to Kodi by directly inserting it to the DB while there is no addEpisode available on the json API - #TODO: PR at Kodi team for a addEpisode endpoint on their API + # If the episode 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 - # first check the episode is not already in the DB using the Emby ID which is stored in c20 - cursor.execute("SELECT idEpisode FROM episode WHERE c20 = ?",(MBitem["Id"],)) + MBitem = ReadEmbyDB().getFullItem(embyId) + + cursor.execute("SELECT idEpisode FROM episode WHERE embyId = ?",(MBitem["Id"],)) result = cursor.fetchone() if result != None: utils.logMsg("Emby", "Episode already exists in DB : " + MBitem["Id"] + " - " + MBitem["Name"], 2) - return + episodeid = result[0] + else: + episodeid = None addon = xbmcaddon.Addon(id='plugin.video.emby') port = addon.getSetting('port') @@ -790,83 +588,7 @@ class WriteKodiDB(): timeInfo = API().getTimeInfo(MBitem) userData=API().getUserData(MBitem) - playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) - playurl = utils.convertEncoding(playurl) - - if MBitem.get("DateCreated") != None: - dateadded = MBitem["DateCreated"].replace("T"," ") - dateadded = dateadded.split(".")[0] - else: - dateadded = None - - if userData.get("LastPlayedDate") != None: - lastplayed = userData.get("LastPlayedDate") - else: - lastplayed = None - - # we need to store both the path and the filename seperately in the kodi db so we split them up - if "\\" in playurl: - filename = playurl.rsplit("\\",1)[-1] - path = playurl.replace(filename,"") - elif "/" in playurl: - filename = playurl.rsplit("/",1)[-1] - path = playurl.replace(filename,"") - - #create the new path - return id if already exists - cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) - result = cursor.fetchone() - if result != None: - pathid = result[0] - if result == None: - cursor.execute("select coalesce(max(idPath),0) as pathid from path") - pathid = cursor.fetchone()[0] - pathid = pathid + 1 - pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" - cursor.execute(pathsql, (pathid,path,None,None,1)) - - playcount = None - if userData.get("PlayCount") == "1": - playcount = 1 - - #create the file if not exists - cursor.execute("SELECT idFile as fileid FROM files WHERE strFilename = ? and idPath = ?",(filename,pathid,)) - result = cursor.fetchone() - if result != None: - fileid = result[0] - if result == None: - cursor.execute("select coalesce(max(idFile),0) as fileid from files") - fileid = cursor.fetchone()[0] - fileid = fileid + 1 - sql="INSERT OR REPLACE into files(idFile, idPath, strFilename, playCount, lastPlayed, dateAdded) values(?, ?, ?, ?, ?, ?)" - cursor.execute(sql, (fileid,pathid,filename,playcount,lastplayed,dateadded)) - - #get the showid - cursor.execute("SELECT idShow as showid FROM tvshow WHERE c12 = ?",(MBitem["SeriesId"],)) - result = cursor.fetchone() - showid = -1 - if(result == None): - utils.logMsg("Emby","Error adding episode to Kodi Library, couldn't find show - ID: " + MBitem["Id"] + " - " + MBitem["Name"]) - actionPerformed = False - return False - else: - showid = result[0] - - # check season - season = 0 - if MBitem.get("ParentIndexNumber") != None: - season = int(MBitem.get("ParentIndexNumber")) - else: - utils.logMsg("Emby","Error adding episode to Kodi Library, no ParentIndexNumber - ID: " + MBitem["Id"] + " - " + MBitem["Name"]) - return False - - cursor.execute("SELECT idSeason FROM seasons WHERE idShow = ? and season = ?",(showid, season)) - result = cursor.fetchone() - if(result == None): - utils.logMsg("Emby","Error adding episode to Kodi Library, season does not exist - ShowId: " + str(showid) + " SeasonNo: " + str(season) + " EmbyId: " + MBitem["Id"] + " Name: " + MBitem["Name"]) - actionPerformed = False - return False - - # build info + ###### episode properties ################ episode = 0 if MBitem.get("IndexNumber") != None: episode = int(MBitem.get("IndexNumber")) @@ -881,25 +603,93 @@ class WriteKodiDB(): else: premieredate = None - #create the episode - cursor.execute("select coalesce(max(idEpisode),0) as episodeid from episode") - episodeid = cursor.fetchone()[0] - episodeid = episodeid + 1 - pathsql = "INSERT into episode(idEpisode, idFile, c00, c01, c03, c05, c09, c20, c12, c13, c14, idShow, c15, c16) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (episodeid, fileid, title, plot, rating, premieredate, runtime, MBitem["Id"], season, episode, title, showid, "-1", "-1")) + if MBitem.get("DateCreated") != None: + dateadded = MBitem["DateCreated"].replace("T"," ") + dateadded = dateadded.split(".")[0] + else: + dateadded = None + + if userData.get("LastPlayedDate") != None: + lastplayed = userData.get("LastPlayedDate") + else: + lastplayed = None + + playcount = None + if userData.get("PlayCount") == "1": + playcount = 1 + + #### ADD OR UPDATE THE FILE AND PATH ########### + #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY + path = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/" + filename = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/?id=" MBitem["Id"] + "&mode=play" + + #create the new path - return id if already exists + cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) + result = cursor.fetchone() + if result != None: + pathid = result[0] + if result == None: + cursor.execute("select coalesce(max(idPath),0) as pathid from path") + pathid = cursor.fetchone()[0] + pathid = pathid + 1 + pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" + cursor.execute(pathsql, (pathid,path,None,None,1)) + + #create the file if not exists + cursor.execute("SELECT idFile as fileid FROM files WHERE strFilename = ? and idPath = ?",(filename,pathid,)) + result = cursor.fetchone() + if result != None: + fileid = result[0] + if result == None: + cursor.execute("select coalesce(max(idFile),0) as fileid from files") + fileid = cursor.fetchone()[0] + fileid = fileid + 1 + sql="INSERT OR REPLACE into files(idFile, idPath, strFilename, playCount, lastPlayed, dateAdded) values(?, ?, ?, ?, ?, ?)" + cursor.execute(sql, (fileid,pathid,filename,playcount,lastplayed,dateadded)) + + # safety check: check season first + season = 0 + if MBitem.get("ParentIndexNumber") != None: + season = int(MBitem.get("ParentIndexNumber")) + else: + utils.logMsg("Emby","SKIP adding episode to Kodi Library, no ParentIndexNumber - ID: " + MBitem["Id"] + " - " + MBitem["Name"]) + return False + + cursor.execute("SELECT idSeason FROM seasons WHERE idShow = ? and season = ?",(showid, season)) + result = cursor.fetchone() + if(result == None): + #update seasons first + self.updateSeasons(MBitem["SeriesId"], showid, connection, cursor) + + # ADD EPISODE TO KODI + if episodeid == None: + + #create the episode + cursor.execute("select coalesce(max(idEpisode),0) as episodeid from episode") + episodeid = cursor.fetchone()[0] + episodeid = episodeid + 1 + pathsql = "INSERT into episode(idEpisode, idFile, c00, c01, c03, c05, c09, c12, c13, c14, idShow, c15, c16, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (episodeid, fileid, title, plot, rating, premieredate, runtime, season, episode, title, showid, "-1", "-1", MBitem["Id"])) + + # UPDATE THE EPISODE IN KODI (for now, we just send in all data) + else: + pathsql = "UPDATE episode SET c00 = ?, c01 = ?, c03 = ?, c05 = ?, c09 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, embyId = ? WHERE idEpisode = ?" + cursor.execute(pathsql, title, plot, rating, premieredate, runtime, season, episode, title, MBitem["Id"], episodeid) + + #update or insert actors + self.AddActorsToMedia(episodeid,MBitem.get("People"),"episode", connection, cursor) try: connection.commit() - utils.logMsg("Emby","Added episode to Kodi Library - ID: " + MBitem["Id"] + " - " + MBitem["Name"]) + utils.logMsg("Emby","Added or updated episode to Kodi Library - ID: " + MBitem["Id"] + " - " + MBitem["Name"]) except: - utils.logMsg("Emby","Error adding episode to Kodi Library - ID: " + MBitem["Id"] + " - " + MBitem["Name"]) + utils.logMsg("Emby","Error adding/updating episode to Kodi Library - ID: " + MBitem["Id"] + " - " + MBitem["Name"]) actionPerformed = False - def deleteMovieFromKodiLibrary(self, id ): - kodiItem = ReadKodiDB().getKodiMovie(id) - utils.logMsg("deleting movie from Kodi library",id) - if kodiItem != None: - xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.RemoveMovie", "params": { "movieid": %i}, "id": 1 }' %(kodiItem["movieid"])) + def deleteMovieFromKodiLibrary(self, id, connection, cursor ): + utils.logMsg("deleting movie from Kodi library --> ",id) + cursor.execute("DELETE FROM movie WHERE embyId = ?", (id,)) + connection.commit() def deleteMusicVideoFromKodiLibrary(self, id ): utils.logMsg("deleting musicvideo from Kodi library",id) @@ -907,129 +697,120 @@ class WriteKodiDB(): if kodiItem != None: xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.RemoveMusicVideo", "params": { "musicvideoid": %i}, "id": 1 }' %(kodiItem["musicvideoid"])) - def deleteEpisodeFromKodiLibrary(self, episodeid, tvshowid ): - utils.logMsg("deleting episode from Kodi library",episodeid) - episode = ReadKodiDB().getKodiEpisodeByMbItem(episodeid, tvshowid) - if episode != None: - WINDOW = xbmcgui.Window( 10000 ) - xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.RemoveEpisode", "params": { "episodeid": %i}, "id": 1 }' %(episode["episodeid"])) - - utils.logMsg("episode deleted succesfully!",episodeid) - else: - utils.logMsg("episode not found in kodi DB",episodeid) - - def deleteEpisodeFromKodiLibraryByMbId(self, id ): - utils.logMsg("deleting episode from Kodi library", id) - kodiItem = ReadKodiDB().getKodiEpisodeByMbItemEx(id) - if kodiItem != None: - xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.RemoveEpisode", "params": { "episodeid": %i}, "id": 1 }' %(kodiItem["episodeid"])) - utils.logMsg("episode deleted succesfully!", id) - else: - utils.logMsg("episode not found in kodi DB", id) - - def addTVShowToKodiLibrary( self, MBitem, connection, cursor ): - #adds a Tvshow to Kodi by directly inserting it to the DB while there is no addTvShow available on the json API - #TODO: PR at Kodi team for a addTvShow endpoint on their API + def deleteEpisodeFromKodiLibrary(self, id, connection, cursor ): + utils.logMsg("deleting episode from Kodi library --> ",id) + cursor.execute("DELETE FROM episode WHERE embyId = ?", (id,)) + connection.commit() + + def addOrUpdateTvShowToKodiLibrary( self, embyId, connection, cursor, viewTag ): addon = xbmcaddon.Addon(id='plugin.video.emby') port = addon.getSetting('port') host = addon.getSetting('ipaddress') server = host + ":" + port + MBitem = ReadEmbyDB().getFullItem(embyId) + timeInfo = API().getTimeInfo(MBitem) userData=API().getUserData(MBitem) thumbPath = API().getArtwork(MBitem, "Primary") - playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) - #make sure that the path always ends with a slash - path = utils.convertEncoding(playurl + "/") + # 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 idMovie FROM movie WHERE embyId = ?",(MBitem["Id"],)) + result = cursor.fetchone() + if result != None: + showid = result[0] + else: + showid = None + + #### TV SHOW DETAILS ######### if MBitem.get("DateCreated") != None: dateadded = MBitem["DateCreated"].replace("T"," ") dateadded = dateadded.replace(".0000000Z","") else: dateadded = None - - #create the tv show path - cursor.execute("select coalesce(max(idPath),0) as pathid from path") - pathid = cursor.fetchone()[0] - pathid = pathid + 1 - pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" - cursor.execute(pathsql, (pathid,path,None,None,1)) - #create toplevel path as monitored source - needed for things like actors and stuff to work (no clue why) - if "\\" in path: - toplevelpathstr = path.rsplit("\\",2)[1] - toplevelpath = path.replace(toplevelpathstr + "\\","") - elif "/" in path: - toplevelpathstr = path.rsplit("/",2)[1] - toplevelpath = path.replace(toplevelpathstr + "/","") - cursor.execute("SELECT idPath as tlpathid FROM path WHERE strPath = ?",(toplevelpath,)) - result = cursor.fetchone() - if result == None: - cursor.execute("select coalesce(max(idPath),0) as tlpathid from path") - tlpathid = cursor.fetchone()[0] - tlpathid = pathid + 1 - pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" - cursor.execute(pathsql, (tlpathid,toplevelpath,"tvshows","metadata.local",1)) + path = "plugin://plugin.video.emby/tvshows/" + MBitem["Id"] + "/" - - runtime = int(timeInfo.get('Duration'))*60 - plot = utils.convertEncoding(API().getOverview(MBitem)) - title = utils.convertEncoding(MBitem["Name"]) - sorttitle = utils.convertEncoding(MBitem["SortName"]) - rating = MBitem.get("CommunityRating") - #create the tvshow - cursor.execute("select coalesce(max(idShow),0) as showid from tvshow") - showid = cursor.fetchone()[0] - showid = pathid + 1 - pathsql="insert into tvshow(idShow, c00, c01, c04, c09, c12, c15) values(?, ?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (showid, title, plot, rating, title, MBitem["Id"], sorttitle)) + #### ADD THE TV SHOW TO KODI ############## + if showid == None: + #create toplevel path as monitored source - needed for things like actors and stuff to work (no clue why) + toplevelpath = "plugin://plugin.video.emby/tvshows/" + cursor.execute("SELECT idPath as tlpathid FROM path WHERE strPath = ?",(toplevelpath,)) + result = cursor.fetchone() + if result == None: + cursor.execute("select coalesce(max(idPath),0) as tlpathid from path") + tlpathid = cursor.fetchone()[0] + tlpathid = tlpathid + 1 + pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" + cursor.execute(pathsql, (tlpathid,toplevelpath,"tvshows","metadata.local",1)) + else: + tlpathid = result[0] + + #create the tv show path + cursor.execute("select coalesce(max(idPath),0) as pathid from path") + pathid = cursor.fetchone()[0] + pathid = pathid + 1 + pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate, idParentPath) values(?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (pathid,path,None,None,1,tlpathid)) + + runtime = int(timeInfo.get('Duration'))*60 + plot = utils.convertEncoding(API().getOverview(MBitem)) + title = utils.convertEncoding(MBitem["Name"]) + sorttitle = utils.convertEncoding(MBitem["SortName"]) + rating = MBitem.get("CommunityRating") + + #create the tvshow + cursor.execute("select coalesce(max(idShow),0) as showid from tvshow") + showid = cursor.fetchone()[0] + showid = pathid + 1 + pathsql="insert into tvshow(idShow, c00, c01, c04, c09, c15, embyId) values(?, ?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (showid, title, plot, rating, title, sorttitle, MBitem["Id"])) + + #link the path + pathsql="insert into tvshowlinkpath(idShow,idPath) values(?, ?)" + cursor.execute(pathsql, (showid,pathid)) - #link the path - pathsql="insert into tvshowlinkpath(idShow,idPath) values(?, ?)" - cursor.execute(pathsql, (showid,pathid)) - - try: - connection.commit() - utils.logMsg("Emby","Added TV Show to Kodi Library: " + MBitem["Id"] + " - " + MBitem["Name"]) - except: - utils.logMsg("Emby","Error adding tvshow to Kodi Library: " + MBitem["Id"] + " - " + MBitem["Name"]) - actionPerformed = False + #### UPDATE THE TV SHOW ############# + else: + pathsql="UPDATE tvshow SET (c00 = ?, c01 = ?, c04 = ?, c09 = ?, c15 = ?, embyId = ? WHERE idShow = ?" + cursor.execute(pathsql, title, plot, rating, title, sorttitle, MBitem["Id"], showid) + + #update or insert actors + self.AddActorsToMedia(showid,MBitem.get("People"),"tvshow", connection, cursor) - def deleteTVShowFromKodiLibrary(self, id): - xbmc.sleep(sleepVal) - kodiItem = ReadKodiDB().getKodiTVShow(id) - utils.logMsg("deleting tvshow from Kodi library ", "Emby ID : " + id) - - if kodiItem != None: - utils.logMsg("deleting tvshow from Kodi library ", str(kodiItem)) - kodiId = kodiItem["tvshowid"] - utils.logMsg("deleting tvshow from Kodi library ", "Kodi ID : " + str(kodiId)) - xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.RemoveTVShow", "params": { "tvshowid": %i}, "id": 1 }' %(kodiId)) + #update season details + self.updateSeasons(MBitem["Id"], showid, connection, cursor) + + #commit changes and return the id + connection.commit() + return showid + + def deleteTVShowFromKodiLibrary(self, id, connection, cursor): + utils.logMsg("deleting tvshow from Kodi library --> ",id) + cursor.execute("DELETE FROM tvshow WHERE embyId = ?", (id,)) + connection.commit() - def updateSeasons(self,MBitem, KodiItem, connection, cursor): - #use sqlite to set the season details because no method in API available for this - tvshowid = KodiItem["tvshowid"] - - #connection = utils.KodiSQL() - #cursor = connection.cursor() + def updateSeasons(self,embyTvShowId, kodiTvShowId, connection, cursor): - seasonData = ReadEmbyDB().getTVShowSeasons(MBitem["Id"]) + seasonData = ReadEmbyDB().getTVShowSeasons(embyTvShowId) if seasonData != None: for season in seasonData: seasonNum = season.get("IndexNumber") if seasonNum != None and seasonNum >= 0 and seasonNum <= 1000: - cursor.execute("SELECT idSeason as seasonid FROM seasons WHERE idShow = ? and season = ?",(tvshowid, seasonNum)) + cursor.execute("SELECT idSeason as seasonid FROM seasons WHERE idShow = ? and season = ?",(kodiTvShowId, seasonNum)) result = cursor.fetchone() if result == None: #create the season cursor.execute("select coalesce(max(idSeason),0) as seasonid from seasons") seasonid = cursor.fetchone()[0] seasonid = seasonid + 1 - cursor.execute("INSERT into seasons(idSeason, idShow, season) values(?, ?, ?)", (seasonid, tvshowid, seasonNum)) + cursor.execute("INSERT into seasons(idSeason, idShow, season) values(?, ?, ?)", (seasonid, kodiTvShowId, seasonNum)) else: seasonid = result[0] @@ -1043,7 +824,6 @@ class WriteKodiDB(): imageUrl = API().getArtwork(season, "Banner") self.updateSeasonArt(imageUrl, seasonid, "banner", cursor) - connection.commit() def updateSeasonArt(self, imageUrl, seasonid, imageType, cursor): updateDone = False @@ -1129,136 +909,9 @@ class WriteKodiDB(): return changes ''' - - def setKodiFilename(self, id, oldFileName, newFileName, fileType, mbId, connection, cursor): - #use sqlite to set the filename in DB -- needed to avoid problems with resumepoints etc - #return True if any action is performed, False if no action is performed - #todo --> submit PR to kodi team to get this added to the jsonrpc api - #todo --> extend support for musicvideos - - actionPerformed = False - - oldFileName = utils.convertEncoding(oldFileName) - newFileName = utils.convertEncoding(newFileName) - - # this is required to make sure the paths match - oldFileName = oldFileName.replace("\\", "/") - - # only perform changes if the path actually differs - if oldFileName != newFileName: - - # xbmc.sleep(sleepVal) - #connection = utils.KodiSQL() - #cursor = connection.cursor() - utils.logMsg("Emby","setting filename in kodi db..." + fileType + ": " + str(id)) - utils.logMsg("Emby","old filename -->" + oldFileName) - utils.logMsg("Emby","new filename -->" + newFileName) - - ######### PROCESS TV SHOW ############ - if fileType == "tvshow": - - if newFileName.startswith("http"): - newFileName = "plugin://plugin.video.emby/" - - #for tvshows we only store the path in DB - cursor.execute("SELECT idPath as pathid FROM tvshowlinkpath WHERE idShow = ?",(id,)) - result = cursor.fetchone() - pathid = result[0] - cursor.execute("UPDATE path SET strPath = ?, noUpdate = ?, idParentPath = ? WHERE idPath = ?", (newFileName,1,None,pathid)) - - else: - # we need to store both the path and the filename seperately in the kodi db so we split them up - - if newFileName.startswith("http"): - #transcoding or play from stream - path = "plugin://plugin.video.emby/" - filename = "plugin://plugin.video.emby/?id=" + mbId + "&mode=play" - - else: - # direct play - if "\\" in newFileName: - filename = newFileName.rsplit("\\",1)[-1] - path = newFileName.replace(filename,"") - elif "/" in newFileName: - filename = newFileName.rsplit("/",1)[-1] - path = newFileName.replace(filename,"") - - - ######### PROCESS EPISODE ############ - if fileType == "episode": - - #get the file and the current path id - cursor.execute("SELECT idFile as fileid FROM episode WHERE idEpisode = ?",(id,)) - result = cursor.fetchone() - fileid = result[0] - - #create the new path - return id if already exists - cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) - result = cursor.fetchone() - if result != None: - pathid = result[0] - if result == None: - cursor.execute("select coalesce(max(idPath),0) as pathid from path") - pathid = cursor.fetchone()[0] - pathid = pathid + 1 - pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" - cursor.execute(pathsql, (pathid,path,None,None,1)) - - #set the new path and filename to the episode - cursor.execute("UPDATE files SET idPath = ?, strFilename = ? WHERE idFile = ?", (pathid,filename,fileid)) - - ######### PROCESS MOVIE ############ - if fileType == "movie": - cursor.execute("SELECT idFile as fileid FROM movie WHERE idMovie = ?",(id,)) - result = cursor.fetchone() - fileid = result[0] - #write the new filename to the DB - cursor.execute("UPDATE files SET strFilename = ? WHERE idFile = ?", (filename,fileid)) - #set the new path - cursor.execute("SELECT idPath as pathid FROM files WHERE idFile = ?",(fileid,)) - result = cursor.fetchone() - pathid = result[0] - cursor.execute("UPDATE path SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?, idParentPath = ? WHERE idPath = ?", (path, "movies", "metadata.local", 1, None, pathid)) - - try: - connection.commit() - actionPerformed = True - except: - utils.logMsg("Emby","Error setting filename in kodi db for: " + fileType + ": " + str(id)) - actionPerformed = False - - return actionPerformed - - def AddActorsToMedia(self, KodiItem, people, mediatype, connection, cursor): - #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 - + def AddActorsToMedia(self, id, people, mediatype, connection, cursor): downloadUtils = DownloadUtils() - if mediatype == "movie": - id = KodiItem["movieid"] - if mediatype == "tvshow": - id = KodiItem["tvshowid"] - if mediatype == "episode": - id = KodiItem["episodeid"] - - currentcast = list() - if KodiItem["cast"] != None: - for cast in KodiItem["cast"]: - currentcast.append(cast["name"]) - - needsUpdate = False - if(people != None): - for person in people: - if(person.get("Type") == "Actor"): - if person.get("Name") not in currentcast: - needsUpdate = True - break - - if(needsUpdate == False): - return False - - utils.logMsg("AddActorsToMedia", "List needs updating") kodiVersion = 14 if xbmc.getInfoLabel("System.BuildVersion").startswith("15"): @@ -1267,61 +920,53 @@ class WriteKodiDB(): if(people != None): for person in people: if(person.get("Type") == "Actor"): - if person.get("Name") not in currentcast: - utils.logMsg("AddActorsToMedia", "Processing : " + person.get("Name")) - Name = person.get("Name") - Role = person.get("Role") - actorid = None - Thumb = downloadUtils.imageUrl(person.get("Id"), "Primary", 0, 400, 400) + utils.logMsg("AddActorsToMedia", "Processing : " + person.get("Name")) + Name = person.get("Name") + Role = person.get("Role") + actorid = None + Thumb = downloadUtils.imageUrl(person.get("Id"), "Primary", 0, 400, 400) + if kodiVersion == 15: + # Kodi Isengard database # + if Thumb != None: + Thumb = "" + Thumb + "" + cursor.execute("SELECT actor_id as actorid FROM actor WHERE name = ?",(Name,)) + else: + # Kodi Gotham or Helix database # + cursor.execute("SELECT idActor as actorid FROM actors WHERE strActor = ?",(Name,)) + result = cursor.fetchone() + if result != None: + actorid = result[0] + if actorid == None: if kodiVersion == 15: # Kodi Isengard database # - if Thumb != None: - Thumb = "" + Thumb + "" - cursor.execute("SELECT actor_id as actorid FROM actor WHERE name = ?",(Name,)) + cursor.execute("select coalesce(max(actor_id),0) as actorid from actor") + actorid = cursor.fetchone()[0] + actorid = actorid + 1 + peoplesql="insert into actor(actor_id, name, art_urls) values(?, ?, ?)" else: # Kodi Gotham or Helix database # - cursor.execute("SELECT idActor as actorid FROM actors WHERE strActor = ?",(Name,)) - result = cursor.fetchone() - if result != None: - actorid = result[0] - if actorid == None: - if kodiVersion == 15: - # Kodi Isengard database # - cursor.execute("select coalesce(max(actor_id),0) as actorid from actor") - actorid = cursor.fetchone()[0] - actorid = actorid + 1 - peoplesql="insert into actor(actor_id, name, art_urls) values(?, ?, ?)" - else: - # Kodi Gotham or Helix database # - 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 kodiVersion == 15: - # Kodi Isengard database # - peoplesql="INSERT OR REPLACE into actor_link(actor_id, media_id, media_type, role, cast_order) values(?, ?, ?, ?, ?)" - cursor.execute(peoplesql, (actorid, id, mediatype, Role, None)) - else: - # Kodi Gotham or Helix database # - 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() - - return True - + 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 kodiVersion == 15: + # Kodi Isengard database # + peoplesql="INSERT OR REPLACE into actor_link(actor_id, media_id, media_type, role, cast_order) values(?, ?, ?, ?, ?)" + cursor.execute(peoplesql, (actorid, id, mediatype, Role, None)) + else: + # Kodi Gotham or Helix database # + 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)) + + def addBoxsetToKodiLibrary(self, boxset, connection, cursor): - #use sqlite to set add the set - #connection = utils.KodiSQL() - #cursor = connection.cursor() strSet = boxset["Name"] # check if exists @@ -1365,7 +1010,7 @@ class WriteKodiDB(): if result != None: setid = result[0] connection.commit() - #cursor.close() + return True diff --git a/service.py b/service.py index 55c8b664..72d4e045 100644 --- a/service.py +++ b/service.py @@ -115,12 +115,10 @@ class Service(): self.logMsg("Doing_Db_Sync: syncDatabase (Started)") libSync = librarySync.syncDatabase() self.logMsg("Doing_Db_Sync: syncDatabase (Finished) " + str(libSync)) - countSync = librarySync.updatePlayCounts() - self.logMsg("Doing_Db_Sync: updatePlayCounts (Finished) " + str(countSync)) # Force refresh newly set thumbnails xbmc.executebuiltin("UpdateLibrary(video)") - if(libSync and countSync): + if(libSync): startupComplete = True else: if self.KodiMonitor.waitForAbort(10): From adf85204ee9dabfd3050c327b40a78f6d33686e6 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 1 May 2015 13:57:24 +0200 Subject: [PATCH 02/66] added artwork to sync --- resources/lib/WriteKodiDB.py | 52 +++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index d2cf5421..85781236 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -442,7 +442,7 @@ class WriteKodiDB(): #### ADD OR UPDATE THE FILE AND PATH ########### #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY path = "plugin://plugin.video.emby/movies/" - filename = "plugin://plugin.video.emby/movies/?id=" MBitem["Id"] + "&mode=play" + filename = "plugin://plugin.video.emby/movies/?id=" + MBitem["Id"] + "&mode=play" #create the path cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) @@ -490,6 +490,16 @@ class WriteKodiDB(): #update or insert actors self.AddActorsToMedia(movieid,MBitem.get("People"),"movie", connection, cursor) + #update artwork + self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), movieid, "movie", "thumb", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), movieid, "movie", "poster", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Banner"), movieid, "movie", "banner", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Logo"), movieid, "movie", "clearlogo", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Art"), movieid, "movie", "clearart", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Thumb"), movieid, "movie", "landscape", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Disc"), movieid, "movie", "discart", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Backdrop"), movieid, "movie", "fanart", cursor) + #commit changes and return the id connection.commit() return movieid @@ -621,7 +631,7 @@ class WriteKodiDB(): #### ADD OR UPDATE THE FILE AND PATH ########### #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY path = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/" - filename = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/?id=" MBitem["Id"] + "&mode=play" + filename = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/?id=" + MBitem["Id"] + "&mode=play" #create the new path - return id if already exists cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) @@ -679,6 +689,9 @@ class WriteKodiDB(): #update or insert actors self.AddActorsToMedia(episodeid,MBitem.get("People"),"episode", connection, cursor) + #update artwork + self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), episodeid, "episode", "thumb", cursor) + try: connection.commit() utils.logMsg("Emby","Added or updated episode to Kodi Library - ID: " + MBitem["Id"] + " - " + MBitem["Name"]) @@ -784,6 +797,16 @@ class WriteKodiDB(): #update or insert actors self.AddActorsToMedia(showid,MBitem.get("People"),"tvshow", connection, cursor) + #update artwork + self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), showid, "tvshow", "thumb", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), showid, "tvshow", "poster", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Banner"), showid, "tvshow", "banner", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Logo"), showid, "tvshow", "clearlogo", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Art"), showid, "tvshow", "clearart", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Thumb"), showid, "tvshow", "landscape", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Disc"), showid, "tvshow", "discart", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Backdrop"), showid, "tvshow", "fanart", cursor) + #update season details self.updateSeasons(MBitem["Id"], showid, connection, cursor) @@ -816,32 +839,29 @@ class WriteKodiDB(): #update artwork imageUrl = API().getArtwork(season, "Thumb") - self.updateSeasonArt(imageUrl, seasonid, "landscape", cursor) + self.addOrUpdateArt(imageUrl, seasonid, "season", "landscape", cursor) imageUrl = API().getArtwork(season, "Primary") - self.updateSeasonArt(imageUrl, seasonid, "poster", cursor) + self.addOrUpdateArt(imageUrl, seasonid, "season", "poster", cursor) imageUrl = API().getArtwork(season, "Banner") - self.updateSeasonArt(imageUrl, seasonid, "banner", cursor) + self.addOrUpdateArt(imageUrl, seasonid, "season", "banner", cursor) - def updateSeasonArt(self, imageUrl, seasonid, imageType, cursor): + 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 = ?", (seasonid, "season", imageType)) + 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("SeasonArt", "Adding Art Link for SeasonId: " + str(seasonid) + " (" + imageUrl + ")") - cursor.execute("INSERT INTO art(media_id, media_type, type, url) values(?, ?, ?, ?)", (seasonid, "season", imageType, imageUrl)) - updateDone = True + utils.logMsg("SeasonArt", "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("SeasonArt", "Updating Art Link for SeasonId: " + str(seasonid) + " (" + url + ") -> (" + imageUrl + ")") - cursor.execute("UPDATE art set url = ? WHERE media_id = ? AND media_type = ? AND type = ?", (imageUrl, seasonid, "season", imageType)) - updateDone = True - - return updateDone + utils.logMsg("SeasonArt", "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 setKodiResumePoint(self, id, resume_seconds, total_seconds, fileType): #use sqlite to set the resume point while json api doesn't support this yet From 409832ead43809881d3e248a0671f993f426a69a Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 1 May 2015 14:06:31 +0200 Subject: [PATCH 03/66] small fix --- resources/lib/WriteKodiDB.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 85781236..72263c9e 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -854,12 +854,12 @@ class WriteKodiDB(): 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("SeasonArt", "Adding Art Link for kodiId: " + str(kodiId) + " (" + imageUrl + ")") + 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("SeasonArt", "Updating Art Link for kodiId: " + str(kodiId) + " (" + 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)) From b6176210971e8aa452635a3527d5c87db0edee2f Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 1 May 2015 16:58:20 +0200 Subject: [PATCH 04/66] finalized all properties to the database syncs cleanup of some code --- resources/lib/WriteKodiDB.py | 920 +++++++++++++++-------------------- 1 file changed, 384 insertions(+), 536 deletions(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 72263c9e..f0ea5149 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -44,350 +44,6 @@ class WriteKodiDB(): downloadUtils.downloadUrl(watchedurl, type="DELETE") - def updateMusicVideoToKodiLibrary_Batched(self, MBitem, KodiItem): - addon = xbmcaddon.Addon(id='plugin.video.emby') - port = addon.getSetting('port') - host = addon.getSetting('ipaddress') - server = host + ":" + port - #downloadUtils = DownloadUtils() - #userid = downloadUtils.getUserId() - - timeInfo = API().getTimeInfo(MBitem) - userData=API().getUserData(MBitem) - people = API().getPeople(MBitem) - genre = API().getGenre(MBitem) - studios = API().getStudios(MBitem) - mediaStreams=API().getMediaStreams(MBitem) - - thumbPath = API().getArtwork(MBitem, "Primary") - - params = list() - - self.getArtworkParam_Batched(KodiItem, MBitem, params) - - #update common properties - if KodiItem["runtime"] == None: - self.getPropertyParam_Batched(KodiItem, "runtime", (int(timeInfo.get('Duration'))*60), params) - self.getPropertyParam_Batched(KodiItem, "year", MBitem.get("ProductionYear"), params) - self.getPropertyParamArray_Batched(KodiItem, "director", people.get("Director"), params) - self.getPropertyParamArray_Batched(KodiItem, "genre", MBitem.get("Genres"), params) - self.getPropertyParamArray_Batched(KodiItem, "artist", MBitem.get("Artist"), params) - self.getPropertyParamArray_Batched(KodiItem, "album", MBitem.get("Album"), params) - self.getPropertyParam_Batched(KodiItem, "lastplayed", userData.get("LastPlayedDate"), params) - - if(studios != None): - for x in range(0, len(studios)): - studios[x] = studios[x].replace("/", "&") - self.getPropertyParamArray_Batched(KodiItem, "studio", studios, params) - - changes = False - # if there were movies changes then send the update via JSONRPC - if(len(params) > 0): - changes |= True - utils.logMsg("UpdateMovieParams", str(params), level = 2) - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMusicVideoDetails", "params": { "musicvideoid": %i, %s}, "id": 1 }' - paramString = "" - paramLen = len(params) - for x in range(0, paramLen): - param = params[x] - paramString += param - if(x < paramLen-1): - paramString += ", " - jsoncommand = jsoncommand %(KodiItem['musicvideoid'], paramString) - utils.logMsg("executeJSONRPC : ", jsoncommand, level = 2) - xbmc.sleep(sleepVal) - result = xbmc.executeJSONRPC(jsoncommand.encode("utf-8")) - - if(changes): - utils.logMsg("Updated musicvideo to Kodi Library", MBitem["Id"] + " - " + MBitem["Name"], level=0) - - - def updateEpisodeToKodiLibrary( self, MBitem, KodiItem, connection, cursor ): - addon = xbmcaddon.Addon(id='plugin.video.emby') - port = addon.getSetting('port') - host = addon.getSetting('ipaddress') - server = host + ":" + port - - timeInfo = API().getTimeInfo(MBitem) - people = API().getPeople(MBitem) - genre = API().getGenre(MBitem) - studios = API().getStudios(MBitem) - mediaStreams=API().getMediaStreams(MBitem) - userData=API().getUserData(MBitem) - - changes = False - - #update/check all artwork - changes |= self.updateArtWork(KodiItem,MBitem) - - addOrUpdateEpisodeToKodiLibrary(MBitem, connection, cursor) - - #add actors - changes |= self.AddActorsToMedia(KodiItem,MBitem.get("People"),"episode", connection, cursor) - - if changes: - utils.logMsg("Updated item to Kodi Library", MBitem["Id"] + " - " + MBitem["Name"]) - - return changes - - def getArtworkParam_Batched(self, KodiItem, MBitem, params): - - - item_type=str(MBitem.get("Type")) - - ''' - if item_type == "Series": - id = KodiItem['tvshowid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetTVShowDetails", "params": { "tvshowid": %i, "art": %s}, "id": 1 }' - elif item_type == "Episode": - # episodes don't have any artwork - they derrive this from the tv show - return False - elif item_type == "MusicVideo": - id = KodiItem['musicvideoid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMusicVideoDetails", "params": { musicvideoid": %i, "art": %s}, "id": 1 }' - elif item_type == "Movie": - id = KodiItem['movieid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": %i, "art": %s}, "id": 1 }' - ''' - - #update artwork - changes = False - - artwork = {} - artwork["poster"] = API().getArtwork(MBitem, "Primary") - - if(item_type != "Episode"): - artwork["banner"] = API().getArtwork(MBitem, "Banner") - artwork["clearlogo"] = API().getArtwork(MBitem, "Logo") - artwork["clearart"] = API().getArtwork(MBitem, "Art") - artwork["landscape"] = API().getArtwork(MBitem, "Thumb") - artwork["discart"] = API().getArtwork(MBitem, "Disc") - artwork["fanart"] = API().getArtwork(MBitem, "Backdrop") - - for art in artwork: - if artwork.get(art) != "": - if KodiItem["art"].has_key(art): - curValue = urllib.unquote(KodiItem['art'][art]).decode('utf8') - if not artwork.get(art) in curValue: - KodiItem["art"][art] = artwork.get(art) - changes = True - else: - KodiItem["art"][art] = artwork.get(art) - changes = True - - if len(KodiItem["art"]) == 0: - changes = False - - if changes: - json_array = json.dumps(KodiItem["art"]) - params.append("\"art\": " + json_array) - #result = xbmc.executeJSONRPC(jsoncommand %(id, json_array)) - return changes - - # adds or updates artwork to the given Kodi file in database - def updateArtWork(self,KodiItem,MBitem): - item_type=str(MBitem.get("Type")) - - if item_type == "Series": - id = KodiItem['tvshowid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetTVShowDetails", "params": { "tvshowid": %i, "art": %s}, "id": 1 }' - elif item_type == "Episode": - id = KodiItem['episodeid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetEpisodeDetails", "params": { "episodeid": %i, "art": %s}, "id": 1 }' - elif item_type == "MusicVideo": - id = KodiItem['musicvideoid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMusicVideoDetails", "params": { musicvideoid": %i, "art": %s}, "id": 1 }' - elif item_type == "Movie": - id = KodiItem['movieid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": %i, "art": %s}, "id": 1 }' - - #update artwork - changes = False - - artwork = {} - artwork["thumb"] = API().getArtwork(MBitem, "Primary") - - if(item_type != "Episode"): - artwork["poster"] = API().getArtwork(MBitem, "Primary") - artwork["banner"] = API().getArtwork(MBitem, "Banner") - artwork["clearlogo"] = API().getArtwork(MBitem, "Logo") - artwork["clearart"] = API().getArtwork(MBitem, "Art") - artwork["landscape"] = API().getArtwork(MBitem, "Thumb") - artwork["discart"] = API().getArtwork(MBitem, "Disc") - artwork["fanart"] = API().getArtwork(MBitem, "Backdrop") - - for art in artwork: - if artwork.get(art) != "": - if KodiItem["art"].has_key(art): - curValue = urllib.unquote(KodiItem['art'][art]).decode('utf8') - if not artwork.get(art) in curValue: - KodiItem["art"][art] = artwork.get(art) - changes = True - else: - KodiItem["art"][art] = artwork.get(art) - changes = True - - if len(KodiItem["art"]) == 0: - changes = False - - if changes: - json_array = json.dumps(KodiItem["art"]) - result = xbmc.executeJSONRPC(jsoncommand %(id, json_array)) - return changes - - def getPropertyParam_Batched(self,KodiItem, propertyName, propertyValue, params, forced = False): - - ''' - if fileType == "tvshow": - id = KodiItem['tvshowid'] - jsoncommand_i = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetTVShowDetails", "params": { "tvshowid": %i, "%s": %i}, "id": 1 }' - jsoncommand_s = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetTVShowDetails", "params": { "tvshowid": %i, "%s": "%s"}, "id": 1 }' - elif fileType == "episode": - id = KodiItem['episodeid'] - jsoncommand_i = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetEpisodeDetails", "params": { "episodeid": %i, "%s": %i}, "id": 1 }' - jsoncommand_s = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetEpisodeDetails", "params": { "episodeid": %i, "%s": "%s"}, "id": 1 }' - elif fileType == "musicvideo": - id = KodiItem['musicvideoid'] - jsoncommand_i = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMusicVideoDetails", "params": { "musicvideoid": %i, "%s": %i}, "id": 1 }' - jsoncommand_s = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMusicVideoDetails", "params": { "musicvideoid": %i, "%s": "%s"}, "id": 1 }' - elif fileType == "movie": - id = KodiItem['movieid'] - jsoncommand_i = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": %i, "%s": %i}, "id": 1 }' - jsoncommand_s = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": %i, "%s": "%s"}, "id": 1 }' - ''' - - changes = False - if ((propertyValue != KodiItem[propertyName]) or forced): - if propertyValue != None: - if type(propertyValue) is int: - #xbmc.sleep(sleepVal) - utils.logMsg("Emby","updating property..." + str(propertyName)) - utils.logMsg("Emby","kodi value:" + str(KodiItem[propertyName]) + " MB value: " + str(propertyValue)) - params.append("\"" + propertyName + "\": " + str(propertyValue)) - #xbmc.executeJSONRPC(jsoncommand_i %(id, propertyName, propertyValue)) - changes = True - elif type(propertyValue) is Decimal: - #extra compare decimals as int (rounded) - if int(propertyValue) != int(KodiItem[propertyName]): - utils.logMsg("Emby","updating property..." + str(propertyName)) - utils.logMsg("Emby","kodi value:" + str(KodiItem[propertyName]) + " MB value: " + str(propertyValue)) - params.append("\"" + propertyName + "\": " + str(propertyValue)) - changes = True - else: - #xbmc.sleep(sleepVal) - propValue = json.dumps(propertyValue) - utils.logMsg("Emby","updating property..." + str(propertyName)) - utils.logMsg("Emby","kodi value:" + KodiItem[propertyName] + " MB value: " + propValue) - params.append("\"" + propertyName + "\": " + propValue) - #xbmc.executeJSONRPC(jsoncommand_s %(id, propertyName, propertyValue.encode('utf-8'))) - changes = True - - return changes - - # adds or updates the given property on the videofile in Kodi database - def updateProperty(self,KodiItem,propertyName,propertyValue,fileType,forced=False): - if fileType == "tvshow": - id = KodiItem['tvshowid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetTVShowDetails", "params": { "tvshowid": %i, "%s": %s}, "id": 1 }' - elif fileType == "episode": - id = KodiItem['episodeid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetEpisodeDetails", "params": { "episodeid": %i, "%s": %s}, "id": 1 }' - elif fileType == "musicvideo": - id = KodiItem['musicvideoid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMusicVideoDetails", "params": { "musicvideoid": %i, "%s": %s}, "id": 1 }' - elif fileType == "movie": - id = KodiItem['movieid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": %i, "%s": %s}, "id": 1 }' - - changes = False - if ((propertyValue != KodiItem[propertyName]) or forced): - if propertyValue != None: - if type(propertyValue) is int: - xbmc.sleep(sleepVal) - utils.logMsg("Emby","updating property..." + str(propertyName)) - utils.logMsg("Emby","kodi value:" + str(KodiItem[propertyName]) + " MB value: " + str(propertyValue)) - xbmc.executeJSONRPC(jsoncommand %(id, propertyName, propertyValue)) - changes = True - elif type(propertyValue) is Decimal: - #extra compare decimals as int (rounded) - if int(propertyValue) != int(KodiItem[propertyName]): - xbmc.sleep(sleepVal) - utils.logMsg("Emby","updating property..." + str(propertyName)) - utils.logMsg("Emby","kodi value:" + str(KodiItem[propertyName]) + " MB value: " + str(propertyValue)) - xbmc.executeJSONRPC(jsoncommand %(id, propertyName, propertyValue)) - changes = True - else: - xbmc.sleep(sleepVal) - propValue = json.dumps(propertyValue) - utils.logMsg("Emby","updating property..." + str(propertyName)) - utils.logMsg("Emby","kodi value:" + KodiItem[propertyName] + " MB value: " + propValue) - xbmc.executeJSONRPC(jsoncommand %(id, propertyName, propValue)) - changes = True - - return changes - - def getPropertyParamArray_Batched(self, KodiItem, propertyName, propertyCollection, params): - ''' - if fileType == "tvshow": - id = KodiItem['tvshowid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetTVShowDetails", "params": { "tvshowid": %i, "%s": %s}, "id": 1 }' - elif fileType == "episode": - id = KodiItem['episodeid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetEpisodeDetails", "params": { "episodeid": %i, "%s": %s}, "id": 1 }' - elif fileType == "musicvideo": - id = KodiItem['musicvideoid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMusicVideoDetails", "params": { "musicvideoid": %i, "%s": %s}, "id": 1 }' - elif fileType == "movie": - id = KodiItem['movieid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": %i, "%s": %s}, "id": 1 }' - ''' - - pendingChanges = False - if propertyCollection != None: - currentvalues = set(KodiItem[propertyName]) - for item in propertyCollection: - if not item in currentvalues: - pendingChanges = True - json_array = json.dumps(propertyCollection) - - if pendingChanges: - #xbmc.sleep(sleepVal) - utils.logMsg("Emby","updating propertyarray... Name:" + str(propertyName) + " Current:" + str(currentvalues) + " New:" + str(json_array)) - params.append("\"" + propertyName + "\": " + json_array) - #xbmc.executeJSONRPC(jsoncommand %(id,propertyName,json_array)) - - return pendingChanges - - # adds or updates the property-array on the videofile in Kodi database - def updatePropertyArray(self,KodiItem,propertyName,propertyCollection,fileType): - if fileType == "tvshow": - id = KodiItem['tvshowid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetTVShowDetails", "params": { "tvshowid": %i, "%s": %s}, "id": 1 }' - elif fileType == "episode": - id = KodiItem['episodeid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetEpisodeDetails", "params": { "episodeid": %i, "%s": %s}, "id": 1 }' - elif fileType == "musicvideo": - id = KodiItem['musicvideoid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMusicVideoDetails", "params": { "musicvideoid": %i, "%s": %s}, "id": 1 }' - elif fileType == "movie": - id = KodiItem['movieid'] - jsoncommand = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": { "movieid": %i, "%s": %s}, "id": 1 }' - - pendingChanges = False - if (propertyCollection != None and KodiItem.get(propertyName) != None): - currentvalues = set(KodiItem[propertyName]) - for item in propertyCollection: - if not item in currentvalues: - pendingChanges = True - json_array = json.dumps(propertyCollection) - - if pendingChanges: - xbmc.sleep(sleepVal) - utils.logMsg("Emby","updating propertyarray... Name:" + str(propertyName) + " Current:" + str(currentvalues) + " New:" + str(json_array)) - xbmc.executeJSONRPC(jsoncommand %(id,propertyName,json_array)) - - return pendingChanges - def addOrUpdateMovieToKodiLibrary( self, embyId ,connection, cursor, viewTag): addon = xbmcaddon.Addon(id='plugin.video.emby') @@ -411,6 +67,7 @@ class WriteKodiDB(): timeInfo = API().getTimeInfo(MBitem) userData=API().getUserData(MBitem) + people = API().getPeople(MBitem) #### The movie details ######### runtime = int(timeInfo.get('Duration'))*60 @@ -419,6 +76,18 @@ class WriteKodiDB(): sorttitle = utils.convertEncoding(MBitem["SortName"]) year = MBitem.get("ProductionYear") rating = MBitem.get("CommunityRating") + mpaa = MBitem.get("OfficialRating") + genres = MBitem.get("Genres") + genre = " / ".join(genres) + studios = API().getStudios(MBitem) + studio = " / ".join(studios) + writer = " / ".join(people.get("Writer")) + director = " / ".join(people.get("Director")) + + imdb = None + if MBitem.get("ProviderIds"): + if MBitem.get("ProviderIds").get("Imdb"): + imdb = MBitem.get("ProviderIds").get("Imdb") if MBitem.get("ShortOverview") != None: shortplot = utils.convertEncoding(MBitem.get("ShortOverview")) @@ -439,10 +108,14 @@ class WriteKodiDB(): else: dateadded = None + playcount = None + if userData.get("PlayCount") == "1": + playcount = 1 + #### ADD OR UPDATE THE FILE AND PATH ########### #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY - path = "plugin://plugin.video.emby/movies/" - filename = "plugin://plugin.video.emby/movies/?id=" + MBitem["Id"] + "&mode=play" + path = "plugin://plugin.video.emby/" + filename = "plugin://plugin.video.emby/?id=%s&mode=play" % MBitem["Id"] #create the path cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) @@ -455,11 +128,7 @@ class WriteKodiDB(): pathid = pathid + 1 pathsql = "insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" cursor.execute(pathsql, (pathid,path,"movies","metadata.local",1)) - - playcount = None - if userData.get("PlayCount") == "1": - playcount = 1 - + #create the file if not exists cursor.execute("SELECT idFile as fileid FROM files WHERE strFilename = ? and idPath = ?",(filename,pathid,)) result = cursor.fetchone() @@ -479,16 +148,19 @@ class WriteKodiDB(): cursor.execute("select coalesce(max(idMovie),0) as movieid from movie") movieid = cursor.fetchone()[0] movieid = movieid + 1 - pathsql="insert into movie(idMovie, idFile, c00, c01, c02, c05, c07, c10, c11, c16, c19, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (movieid, fileid, title, plot, shortplot, rating, year, sorttitle, runtime, title, trailerUrl, MBitem["Id"])) - + pathsql="insert into movie(idMovie, idFile, c00, c01, c02, c05, c06, c07, c09, c10, c11, c12, c14, c15, c16, c18, c19, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (movieid, fileid, title, plot, shortplot, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio, trailerUrl, MBitem["Id"])) + + #add the viewtag + self.AddTagToMedia(movieid, viewTag, "movie", cursor) + #### UPDATE THE MOVIE ##### else: - pathsql="update movie SET c00 = ?, c01 = ?, c02 = ?, c05 = ?, c07 = ?, c10 = ?, c11 = ?, c16 = ?, c19 = ?, embyId= ? WHERE idMovie = ?" - cursor.execute(pathsql, (title, plot, shortplot, rating, year, sorttitle, runtime, title, trailerUrl, MBitem["Id"], movieid)) + pathsql="update movie SET c00 = ?, c01 = ?, c02 = ?, c05 = ?, c06 = ?, c07 = ?, c09 = ? c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?, c16 = ?, c18 = ?, c19 = ?, embyId= ? WHERE idMovie = ?" + cursor.execute(pathsql, (title, plot, shortplot, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio, trailerUrl, MBitem["Id"], movieid)) #update or insert actors - self.AddActorsToMedia(movieid,MBitem.get("People"),"movie", connection, cursor) + self.AddPeopleToMedia(movieid,MBitem.get("People"),"movie", connection, cursor) #update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), movieid, "movie", "thumb", cursor) @@ -500,10 +172,136 @@ class WriteKodiDB(): self.addOrUpdateArt(API().getArtwork(MBitem, "Disc"), movieid, "movie", "discart", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Backdrop"), movieid, "movie", "fanart", cursor) + #update genres + self.AddGenresToMedia(movieid, genres, "movie", cursor) + + #update studios + self.AddStudiosToMedia(movieid, studios, "movie", cursor) + #commit changes and return the id connection.commit() return movieid + def addOrUpdateTvShowToKodiLibrary( self, embyId, connection, cursor, viewTag ): + + addon = xbmcaddon.Addon(id='plugin.video.emby') + port = addon.getSetting('port') + host = addon.getSetting('ipaddress') + server = host + ":" + port + + MBitem = ReadEmbyDB().getFullItem(embyId) + + timeInfo = API().getTimeInfo(MBitem) + userData=API().getUserData(MBitem) + + thumbPath = API().getArtwork(MBitem, "Primary") + + # 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 idMovie FROM movie WHERE embyId = ?",(MBitem["Id"],)) + result = cursor.fetchone() + if result != None: + showid = result[0] + else: + showid = None + + #### TV SHOW DETAILS ######### + + genres = MBitem.get("Genres") + genre = " / ".join(genres) + studios = API().getStudios(MBitem) + studio = " / ".join(studios) + mpaa = MBitem.get("OfficialRating") + + if MBitem.get("DateCreated") != None: + dateadded = MBitem["DateCreated"].replace("T"," ") + dateadded = dateadded.replace(".0000000Z","") + else: + dateadded = None + + if MBitem.get("PremiereDate") != None: + premieredatelist = (MBitem.get("PremiereDate")).split("T") + premieredate = premieredatelist[0] + else: + premieredate = None + + path = "plugin://plugin.video.emby/tvshows/" + MBitem["Id"] + "/" + + + #### ADD THE TV SHOW TO KODI ############## + if showid == None: + #create toplevel path as monitored source - needed for things like actors and stuff to work (no clue why) + toplevelpath = "plugin://plugin.video.emby/tvshows/" + cursor.execute("SELECT idPath as tlpathid FROM path WHERE strPath = ?",(toplevelpath,)) + result = cursor.fetchone() + if result == None: + cursor.execute("select coalesce(max(idPath),0) as tlpathid from path") + tlpathid = cursor.fetchone()[0] + tlpathid = tlpathid + 1 + pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" + cursor.execute(pathsql, (tlpathid,toplevelpath,"tvshows","metadata.local",1)) + else: + tlpathid = result[0] + + #create the tv show path + cursor.execute("select coalesce(max(idPath),0) as pathid from path") + pathid = cursor.fetchone()[0] + pathid = pathid + 1 + pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate, idParentPath) values(?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (pathid,path,None,None,1,tlpathid)) + + runtime = int(timeInfo.get('Duration'))*60 + plot = utils.convertEncoding(API().getOverview(MBitem)) + title = utils.convertEncoding(MBitem["Name"]) + sorttitle = utils.convertEncoding(MBitem["SortName"]) + rating = MBitem.get("CommunityRating") + + #create the tvshow + cursor.execute("select coalesce(max(idShow),0) as showid from tvshow") + showid = cursor.fetchone()[0] + showid = pathid + 1 + pathsql="insert into tvshow(idShow, c00, c01, c04, c05, c08, c09, c13, c14, c15, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (showid, title, plot, rating, premieredate, genre, title, mpaa, studio, sorttitle, MBitem["Id"])) + + #link the path + pathsql="insert into tvshowlinkpath(idShow,idPath) values(?, ?)" + cursor.execute(pathsql, (showid,pathid)) + + #add the viewtag + self.AddTagToMedia(showid, viewTag, "tvshow", cursor) + + #### UPDATE THE TV SHOW ############# + else: + pathsql="UPDATE tvshow SET (c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?, c13 = ?, c14 = ?, c15 = ?, embyId = ? WHERE idShow = ?" + cursor.execute(pathsql, title, plot, rating, premieredate, title, genre, mpaa, studio, sorttitle, MBitem["Id"], showid) + + #update or insert people + self.AddPeopleToMedia(showid,MBitem.get("People"),"tvshow", connection, cursor) + + #update genres + self.AddGenresToMedia(movieid, genres, "tvshow", cursor) + + #update studios + self.AddStudiosToMedia(movieid, studios, "tvshow", cursor) + + #update artwork + self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), showid, "tvshow", "thumb", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), showid, "tvshow", "poster", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Banner"), showid, "tvshow", "banner", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Logo"), showid, "tvshow", "clearlogo", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Art"), showid, "tvshow", "clearart", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Thumb"), showid, "tvshow", "landscape", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Disc"), showid, "tvshow", "discart", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Backdrop"), showid, "tvshow", "fanart", cursor) + + #update season details + self.updateSeasons(MBitem["Id"], showid, connection, cursor) + + #commit changes and return the id + connection.commit() + return showid + def addMusicVideoToKodiLibrary( self, MBitem, connection, cursor ): #adds a musicvideo to Kodi by directly inserting it to connectionthe DB while there is no addMusicVideo available on the json API @@ -597,6 +395,7 @@ class WriteKodiDB(): timeInfo = API().getTimeInfo(MBitem) userData=API().getUserData(MBitem) + people = API().getPeople(MBitem) ###### episode properties ################ episode = 0 @@ -607,6 +406,9 @@ class WriteKodiDB(): plot = utils.convertEncoding(API().getOverview(MBitem)) title = utils.convertEncoding(MBitem["Name"]) rating = MBitem.get("CommunityRating") + writer = " / ".join(people.get("Writer")) + director = " / ".join(people.get("Director")) + if MBitem.get("PremiereDate") != None: premieredatelist = (MBitem.get("PremiereDate")).split("T") premieredate = premieredatelist[0] @@ -678,16 +480,16 @@ class WriteKodiDB(): cursor.execute("select coalesce(max(idEpisode),0) as episodeid from episode") episodeid = cursor.fetchone()[0] episodeid = episodeid + 1 - pathsql = "INSERT into episode(idEpisode, idFile, c00, c01, c03, c05, c09, c12, c13, c14, idShow, c15, c16, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (episodeid, fileid, title, plot, rating, premieredate, runtime, season, episode, title, showid, "-1", "-1", MBitem["Id"])) + pathsql = "INSERT into episode(idEpisode, idFile, c00, c01, c03, c04, c05, c09, c10, c12, c13, c14, idShow, c15, c16, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (episodeid, fileid, title, plot, rating, writer, premieredate, runtime, director, season, episode, title, showid, "-1", "-1", MBitem["Id"])) # UPDATE THE EPISODE IN KODI (for now, we just send in all data) else: - pathsql = "UPDATE episode SET c00 = ?, c01 = ?, c03 = ?, c05 = ?, c09 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, embyId = ? WHERE idEpisode = ?" - cursor.execute(pathsql, title, plot, rating, premieredate, runtime, season, episode, title, MBitem["Id"], episodeid) + pathsql = "UPDATE episode SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, embyId = ? WHERE idEpisode = ?" + cursor.execute(pathsql, title, plot, rating, writer, premieredate, runtime, director, season, episode, title, MBitem["Id"], episodeid) #update or insert actors - self.AddActorsToMedia(episodeid,MBitem.get("People"),"episode", connection, cursor) + self.AddPeopleToMedia(episodeid,MBitem.get("People"),"episode", connection, cursor) #update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), episodeid, "episode", "thumb", cursor) @@ -714,106 +516,7 @@ class WriteKodiDB(): utils.logMsg("deleting episode from Kodi library --> ",id) cursor.execute("DELETE FROM episode WHERE embyId = ?", (id,)) connection.commit() - - def addOrUpdateTvShowToKodiLibrary( self, embyId, connection, cursor, viewTag ): - - addon = xbmcaddon.Addon(id='plugin.video.emby') - port = addon.getSetting('port') - host = addon.getSetting('ipaddress') - server = host + ":" + port - - MBitem = ReadEmbyDB().getFullItem(embyId) - - timeInfo = API().getTimeInfo(MBitem) - userData=API().getUserData(MBitem) - - thumbPath = API().getArtwork(MBitem, "Primary") - - # 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 idMovie FROM movie WHERE embyId = ?",(MBitem["Id"],)) - result = cursor.fetchone() - if result != None: - showid = result[0] - else: - showid = None - - #### TV SHOW DETAILS ######### - - if MBitem.get("DateCreated") != None: - dateadded = MBitem["DateCreated"].replace("T"," ") - dateadded = dateadded.replace(".0000000Z","") - else: - dateadded = None - - path = "plugin://plugin.video.emby/tvshows/" + MBitem["Id"] + "/" - - - #### ADD THE TV SHOW TO KODI ############## - if showid == None: - #create toplevel path as monitored source - needed for things like actors and stuff to work (no clue why) - toplevelpath = "plugin://plugin.video.emby/tvshows/" - cursor.execute("SELECT idPath as tlpathid FROM path WHERE strPath = ?",(toplevelpath,)) - result = cursor.fetchone() - if result == None: - cursor.execute("select coalesce(max(idPath),0) as tlpathid from path") - tlpathid = cursor.fetchone()[0] - tlpathid = tlpathid + 1 - pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" - cursor.execute(pathsql, (tlpathid,toplevelpath,"tvshows","metadata.local",1)) - else: - tlpathid = result[0] - - #create the tv show path - cursor.execute("select coalesce(max(idPath),0) as pathid from path") - pathid = cursor.fetchone()[0] - pathid = pathid + 1 - pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate, idParentPath) values(?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (pathid,path,None,None,1,tlpathid)) - - runtime = int(timeInfo.get('Duration'))*60 - plot = utils.convertEncoding(API().getOverview(MBitem)) - title = utils.convertEncoding(MBitem["Name"]) - sorttitle = utils.convertEncoding(MBitem["SortName"]) - rating = MBitem.get("CommunityRating") - - #create the tvshow - cursor.execute("select coalesce(max(idShow),0) as showid from tvshow") - showid = cursor.fetchone()[0] - showid = pathid + 1 - pathsql="insert into tvshow(idShow, c00, c01, c04, c09, c15, embyId) values(?, ?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (showid, title, plot, rating, title, sorttitle, MBitem["Id"])) - - #link the path - pathsql="insert into tvshowlinkpath(idShow,idPath) values(?, ?)" - cursor.execute(pathsql, (showid,pathid)) - - #### UPDATE THE TV SHOW ############# - else: - pathsql="UPDATE tvshow SET (c00 = ?, c01 = ?, c04 = ?, c09 = ?, c15 = ?, embyId = ? WHERE idShow = ?" - cursor.execute(pathsql, title, plot, rating, title, sorttitle, MBitem["Id"], showid) - - #update or insert actors - self.AddActorsToMedia(showid,MBitem.get("People"),"tvshow", connection, cursor) - - #update artwork - self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), showid, "tvshow", "thumb", cursor) - self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), showid, "tvshow", "poster", cursor) - self.addOrUpdateArt(API().getArtwork(MBitem, "Banner"), showid, "tvshow", "banner", cursor) - self.addOrUpdateArt(API().getArtwork(MBitem, "Logo"), showid, "tvshow", "clearlogo", cursor) - self.addOrUpdateArt(API().getArtwork(MBitem, "Art"), showid, "tvshow", "clearart", cursor) - self.addOrUpdateArt(API().getArtwork(MBitem, "Thumb"), showid, "tvshow", "landscape", cursor) - self.addOrUpdateArt(API().getArtwork(MBitem, "Disc"), showid, "tvshow", "discart", cursor) - self.addOrUpdateArt(API().getArtwork(MBitem, "Backdrop"), showid, "tvshow", "fanart", cursor) - - #update season details - self.updateSeasons(MBitem["Id"], showid, connection, cursor) - - #commit changes and return the id - connection.commit() - return showid - + def deleteTVShowFromKodiLibrary(self, id, connection, cursor): utils.logMsg("deleting tvshow from Kodi library --> ",id) cursor.execute("DELETE FROM tvshow WHERE embyId = ?", (id,)) @@ -846,8 +549,7 @@ class WriteKodiDB(): imageUrl = API().getArtwork(season, "Banner") self.addOrUpdateArt(imageUrl, seasonid, "season", "banner", cursor) - - + def addOrUpdateArt(self, imageUrl, kodiId, mediaType, imageType, cursor): updateDone = False if imageUrl: @@ -861,7 +563,6 @@ class WriteKodiDB(): 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 setKodiResumePoint(self, id, resume_seconds, total_seconds, fileType): #use sqlite to set the resume point while json api doesn't support this yet @@ -890,47 +591,7 @@ class WriteKodiDB(): connection.commit() cursor.close() - ''' - # removed for now as setting c15 and c16 to -1 looks like it just shows specials in the special folder only - def setSpecialAirsDetails(self, MBitem, KodiItem, connection, cursor): - - changes = False - - cursor.execute("SELECT c15, c16 FROM episode WHERE idEpisode = ?",(KodiItem["episodeid"],)) - result = cursor.fetchone() - if(result != None): - - c15 = -1 - c16 = -1 - - if(result[0] != None and result[0] != "" and result[0] != "None"): - c15 = int(result[0]) - if(result[1] != None and result[1] != "" and result[1] != "None"): - c16 = int(result[1]) - - airsBeforeSeasonNumber = MBitem.get("AirsBeforeSeasonNumber") - airsBeforeEpisodeNumber = MBitem.get("AirsBeforeEpisodeNumber") - #AirsAfterSeasonNumber - - if(airsBeforeSeasonNumber == None): - airsBeforeSeasonNumber = 0 - - if(airsBeforeEpisodeNumber == None): - airsBeforeEpisodeNumber = 0 - - if(airsBeforeSeasonNumber != None and airsBeforeEpisodeNumber != None): - if(airsBeforeSeasonNumber != c15 or airsBeforeEpisodeNumber != c16): - utils.logMsg("Emby","Special_Airs_Info Kodi: " + str(c15) + " " + str(c16)) - utils.logMsg("Emby","Special_Airs_Info Emby : " + str(airsBeforeSeasonNumber) + " " + str(airsBeforeEpisodeNumber)) - sql = "UPDATE episode set c15 = ?, c16 = ? WHERE idEpisode = ?" - cursor.execute(sql, (airsBeforeSeasonNumber, airsBeforeEpisodeNumber, KodiItem["episodeid"])) - connection.commit() - changes = True - - return changes - ''' - - def AddActorsToMedia(self, id, people, mediatype, connection, cursor): + def AddPeopleToMedia(self, id, people, mediatype, connection, cursor): downloadUtils = DownloadUtils() kodiVersion = 14 @@ -939,42 +600,46 @@ class WriteKodiDB(): if(people != None): for person in people: - if(person.get("Type") == "Actor"): - utils.logMsg("AddActorsToMedia", "Processing : " + person.get("Name")) - Name = person.get("Name") - Role = person.get("Role") - actorid = None - Thumb = downloadUtils.imageUrl(person.get("Id"), "Primary", 0, 400, 400) + + Name = person.get("Name") + + actorid = None + Thumb = downloadUtils.imageUrl(person.get("Id"), "Primary", 0, 400, 400) + if kodiVersion == 15: + # Kodi Isengard database # + if Thumb != None: + Thumb = "" + Thumb + "" + cursor.execute("SELECT actor_id as actorid FROM actor WHERE name = ?",(Name,)) + else: + # Kodi Gotham or Helix database # + cursor.execute("SELECT idActor as actorid FROM actors WHERE strActor = ?",(Name,)) + result = cursor.fetchone() + if result != None: + actorid = result[0] + if actorid == None: if kodiVersion == 15: # Kodi Isengard database # - if Thumb != None: - Thumb = "" + Thumb + "" - cursor.execute("SELECT actor_id as actorid FROM actor WHERE name = ?",(Name,)) + cursor.execute("select coalesce(max(actor_id),0) as actorid from actor") + actorid = cursor.fetchone()[0] + actorid = actorid + 1 + peoplesql="insert into actor(actor_id, name, art_urls) values(?, ?, ?)" else: # Kodi Gotham or Helix database # - cursor.execute("SELECT idActor as actorid FROM actors WHERE strActor = ?",(Name,)) - result = cursor.fetchone() - if result != None: - actorid = result[0] - if actorid == None: - if kodiVersion == 15: - # Kodi Isengard database # - cursor.execute("select coalesce(max(actor_id),0) as actorid from actor") - actorid = cursor.fetchone()[0] - actorid = actorid + 1 - peoplesql="insert into actor(actor_id, name, art_urls) values(?, ?, ?)" - else: - # Kodi Gotham or Helix database # - 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)) + 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(?, ?, ?)" + utils.logMsg("AddPeopleToMedia", "Processing : " + person.get("Name")) + cursor.execute(peoplesql, (actorid,Name,Thumb)) + + #### ACTORS ###### + if(person.get("Type") == "Actor"): + Role = person.get("Role") if kodiVersion == 15: # Kodi Isengard database # - peoplesql="INSERT OR REPLACE into actor_link(actor_id, media_id, media_type, role, cast_order) values(?, ?, ?, ?, ?)" - cursor.execute(peoplesql, (actorid, id, mediatype, Role, None)) + peoplesql="INSERT OR REPLACE into actor_link(actor_id, media_id, media_type) values(?, ?, ?)" + cursor.execute(peoplesql, (actorid, id, mediatype)) else: # Kodi Gotham or Helix database # if mediatype == "movie": @@ -984,8 +649,191 @@ class WriteKodiDB(): if mediatype == "episode": peoplesql="INSERT OR REPLACE into actorlinkepisode(idActor, idEpisode, strRole, iOrder) values(?, ?, ?, ?)" cursor.execute(peoplesql, (actorid,id,Role,None)) + + #### DIRECTORS ###### + if(person.get("Type") == "Director"): + + if kodiVersion == 15: + # Kodi Isengard database # + peoplesql="INSERT OR REPLACE into director_link(actor_id, media_id, media_type) values(?, ?, ?)" + cursor.execute(peoplesql, (actorid, id, mediatype)) + else: + # Kodi Gotham or Helix database # + if mediatype == "movie": + peoplesql="INSERT OR REPLACE into directorlinkmovie(idDirector, idMovie) values(?, ?)" + if mediatype == "tvshow": + peoplesql="INSERT OR REPLACE into directorlinktvshow(idDirector, idShow) values(?, ?)" + if mediatype == "musicvideo": + peoplesql="INSERT OR REPLACE into directorlinkmusicvideo(idDirector, idMVideo) values(?, ?)" + cursor.execute(peoplesql, (actorid,id)) + + #### WRITERS ###### + if(person.get("Type") == "Writing" or person.get("Type") == "Writer"): + + if kodiVersion == 15: + # Kodi Isengard database # + peoplesql="INSERT OR REPLACE into writer_link(actor_id, media_id, media_type) values(?, ?, ?)" + cursor.execute(peoplesql, (actorid, id, mediatype)) + else: + # Kodi Gotham or Helix database # + if mediatype == "movie": + peoplesql="INSERT OR REPLACE into writerlinkmovie(idWriter, idMovie) values(?, ?)" + if mediatype == "episode": + peoplesql="INSERT OR REPLACE into writerlinkepisode(idWriter, idEpisode) values(?, ?)" + cursor.execute(peoplesql, (actorid,id)) - + def AddGenresToMedia(self, id, genres, mediatype, cursor): + + if genres: + + kodiVersion = 14 + if xbmc.getInfoLabel("System.BuildVersion").startswith("15"): + kodiVersion = 15 + + for genre in genres: + + if kodiVersion == 15: + genre_id = None + cursor.execute("SELECT genre_id as genre_id FROM genre WHERE name = ?",(genre,)) + result = cursor.fetchone() + if result != None: + genre_id = result[0] + #create genre + if genre_id == None: + cursor.execute("select coalesce(max(genre_id),0) as genre_id from genre") + genre_id = cursor.fetchone()[0] + genre_id = genre_id + 1 + sql="insert into genre(genre_id, name) values(?, ?)" + cursor.execute(sql, (genre_id,genre)) + + #assign genre to item + utils.logMsg("AddGenresToMedia", "Processing : " + genre) + sql="INSERT OR REPLACE into genre_link(genre_id, media_id, media_type) values(?, ?, ?)" + cursor.execute(sql, (genre_id, id, mediatype)) + + else: + 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 + utils.logMsg("AddGenresToMedia", "Processing : " + genre) + if mediatype == "movie": + sql="INSERT OR REPLACE into genrelinkmovie(idGenre, idMovie) values(?, ?)" + if mediatype == "tvshow": + sql="INSERT OR REPLACE into genrelinktvshow(idGenre, idShow) values(?, ?)" + if mediatype == "episode": + sql="INSERT OR REPLACE into genrelinkepisode(idGenre, idEpisode) values(?, ?)" + cursor.execute(sql, (idGenre,id)) + + def AddStudiosToMedia(self, id, studios, mediatype, cursor): + + if studios: + + kodiVersion = 14 + if xbmc.getInfoLabel("System.BuildVersion").startswith("15"): + kodiVersion = 15 + + for studio in studios: + + if kodiVersion == 15: + studio_id = None + cursor.execute("SELECT studio_id as studio_id FROM studio WHERE name = ?",(studio,)) + result = cursor.fetchone() + if result != None: + studio_id = result[0] + #create studio + if studio_id == None: + cursor.execute("select coalesce(max(studio_id),0) as studio_id from studio") + studio_id = cursor.fetchone()[0] + studio_id = studio_id + 1 + sql="insert into studio(studio_id, name) values(?, ?)" + cursor.execute(sql, (studio_id,studio)) + + #assign studio to item + utils.logMsg("AddstudiosToMedia", "Processing : " + studio) + sql="INSERT OR REPLACE into studio_link(studio_id, media_id, media_type) values(?, ?, ?)" + cursor.execute(sql, (studio_id, id, mediatype)) + + else: + idstudio = None + cursor.execute("SELECT idstudio as idstudio FROM studio WHERE strstudio = ?",(studio,)) + result = cursor.fetchone() + if result != None: + idstudio = result[0] + #create studio + if idstudio == None: + cursor.execute("select coalesce(max(idstudio),0) as idstudio from studio") + idstudio = cursor.fetchone()[0] + idstudio = idstudio + 1 + sql="insert into studio(idstudio, strstudio) values(?, ?)" + cursor.execute(sql, (idstudio,studio)) + + #assign studio to item + utils.logMsg("AddstudiosToMedia", "Processing : " + studio) + if mediatype == "movie": + sql="INSERT OR REPLACE into studiolinkmovie(idstudio, idMovie) values(?, ?)" + if mediatype == "tvshow": + sql="INSERT OR REPLACE into studiolinktvshow(idstudio, idShow) values(?, ?)" + if mediatype == "episode": + sql="INSERT OR REPLACE into studiolinkepisode(idstudio, idEpisode) values(?, ?)" + cursor.execute(sql, (idstudio,id)) + + def AddTagToMedia(self, id, tag, mediatype, cursor): + + if tag: + + kodiVersion = 14 + if xbmc.getInfoLabel("System.BuildVersion").startswith("15"): + kodiVersion = 15 + + if kodiVersion == 15: + tag_id = None + cursor.execute("SELECT tag_id as tag_id FROM tag WHERE name = ?",(tag,)) + result = cursor.fetchone() + if result != None: + tag_id = result[0] + #create tag + if tag_id == None: + cursor.execute("select coalesce(max(tag_id),0) as tag_id from tag") + tag_id = cursor.fetchone()[0] + tag_id = tag_id + 1 + sql="insert into tag(tag_id, name) values(?, ?)" + cursor.execute(sql, (tag_id,tag)) + + #assign tag to item + utils.logMsg("AddTagToMedia", "Processing : " + tag) + sql="INSERT OR REPLACE into tag_link(tag_id, media_id, media_type) values(?, ?, ?)" + cursor.execute(sql, (tag_id, id, mediatype)) + + else: + idTag = None + cursor.execute("SELECT idTag as idTag FROM tag WHERE strTag = ?",(genre,)) + result = cursor.fetchone() + if result != None: + idTag = result[0] + #create idTag + if idTag == None: + cursor.execute("select coalesce(max(idTag),0) as idTag from tag") + idTag = cursor.fetchone()[0] + idTag = idTag + 1 + sql="insert into tag(idTag, strTag) values(?, ?)" + cursor.execute(sql, (idTag,tag)) + + #assign tag to item + utils.logMsg("AddTagToMedia", "Processing : " + tag) + sql="INSERT OR REPLACE into taglinks(idTag, idMedia, media_type) values(?, ?, ?)" + cursor.execute(sql, (idTag, id, mediatype)) + def addBoxsetToKodiLibrary(self, boxset, connection, cursor): strSet = boxset["Name"] From a8235061e19bab342ddc5885ed873b3739f3a98d Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 1 May 2015 17:13:22 +0200 Subject: [PATCH 05/66] fixed some typo errors --- resources/lib/WriteKodiDB.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index f0ea5149..bfdd7cab 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -261,7 +261,7 @@ class WriteKodiDB(): cursor.execute("select coalesce(max(idShow),0) as showid from tvshow") showid = cursor.fetchone()[0] showid = pathid + 1 - pathsql="insert into tvshow(idShow, c00, c01, c04, c05, c08, c09, c13, c14, c15, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + pathsql="insert into tvshow(idShow, c00, c01, c04, c05, c08, c09, c13, c14, c15, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" cursor.execute(pathsql, (showid, title, plot, rating, premieredate, genre, title, mpaa, studio, sorttitle, MBitem["Id"])) #link the path @@ -280,10 +280,10 @@ class WriteKodiDB(): self.AddPeopleToMedia(showid,MBitem.get("People"),"tvshow", connection, cursor) #update genres - self.AddGenresToMedia(movieid, genres, "tvshow", cursor) + self.AddGenresToMedia(showid, genres, "tvshow", cursor) #update studios - self.AddStudiosToMedia(movieid, studios, "tvshow", cursor) + self.AddStudiosToMedia(showid, studios, "tvshow", cursor) #update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), showid, "tvshow", "thumb", cursor) @@ -817,7 +817,7 @@ class WriteKodiDB(): else: idTag = None - cursor.execute("SELECT idTag as idTag FROM tag WHERE strTag = ?",(genre,)) + cursor.execute("SELECT idTag as idTag FROM tag WHERE strTag = ?",(tag,)) result = cursor.fetchone() if result != None: idTag = result[0] From e77d5c7c532720996a8e38577d649c4da15c2a76 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 1 May 2015 18:32:13 +0200 Subject: [PATCH 06/66] some more fixes --- default.py | 3 ++- resources/lib/WriteKodiDB.py | 13 +++++++++---- service.py | 13 ++++++++----- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/default.py b/default.py index 300619d7..ef97285d 100644 --- a/default.py +++ b/default.py @@ -27,7 +27,8 @@ except: id=None if mode != None and mode == "play": - PlaybackUtils().PLAY(id) + #PlaybackUtils().PLAY(id) + WINDOW.setProperty('GUIPLAY', str(id)) # set window prop elif sys.argv[1] == "reset": utils.reset() else: diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index bfdd7cab..26727583 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -43,7 +43,6 @@ class WriteKodiDB(): else: downloadUtils.downloadUrl(watchedurl, type="DELETE") - def addOrUpdateMovieToKodiLibrary( self, embyId ,connection, cursor, viewTag): addon = xbmcaddon.Addon(id='plugin.video.emby') @@ -100,7 +99,7 @@ class WriteKodiDB(): jsonData = downloadUtils.downloadUrl(itemTrailerUrl) if(jsonData != ""): trailerItem = jsonData - trailerUrl = "plugin://plugin.video.emby/mode=play?id=" + trailerItem[0][u'Id'] + trailerUrl = "plugin://plugin.video.emby/?id=%s&mode=play" % trailerItem[0][u'Id'] if MBitem.get("DateCreated") != None: dateadded = MBitem["DateCreated"].replace("T"," ") @@ -644,11 +643,13 @@ class WriteKodiDB(): # Kodi Gotham or Helix database # if mediatype == "movie": peoplesql="INSERT OR REPLACE into actorlinkmovie(idActor, idMovie, strRole, iOrder) values(?, ?, ?, ?)" + cursor.execute(peoplesql, (actorid,id,Role,None)) if mediatype == "tvshow": peoplesql="INSERT OR REPLACE into actorlinktvshow(idActor, idShow, strRole, iOrder) values(?, ?, ?, ?)" + cursor.execute(peoplesql, (actorid,id,Role,None)) if mediatype == "episode": peoplesql="INSERT OR REPLACE into actorlinkepisode(idActor, idEpisode, strRole, iOrder) values(?, ?, ?, ?)" - cursor.execute(peoplesql, (actorid,id,Role,None)) + cursor.execute(peoplesql, (actorid,id,Role,None)) #### DIRECTORS ###### if(person.get("Type") == "Director"): @@ -665,6 +666,8 @@ class WriteKodiDB(): peoplesql="INSERT OR REPLACE into directorlinktvshow(idDirector, idShow) values(?, ?)" if mediatype == "musicvideo": peoplesql="INSERT OR REPLACE into directorlinkmusicvideo(idDirector, idMVideo) values(?, ?)" + if mediatype == "episode": + peoplesql="INSERT OR REPLACE into directorlinkepisode(idDirector, idEpisode) values(?, ?)" cursor.execute(peoplesql, (actorid,id)) #### WRITERS ###### @@ -678,9 +681,11 @@ class WriteKodiDB(): # Kodi Gotham or Helix database # if mediatype == "movie": peoplesql="INSERT OR REPLACE into writerlinkmovie(idWriter, idMovie) values(?, ?)" + cursor.execute(peoplesql, (actorid,id)) if mediatype == "episode": peoplesql="INSERT OR REPLACE into writerlinkepisode(idWriter, idEpisode) values(?, ?)" - cursor.execute(peoplesql, (actorid,id)) + cursor.execute(peoplesql, (actorid,id)) + def AddGenresToMedia(self, id, genres, mediatype, cursor): diff --git a/service.py b/service.py index 72d4e045..4c84511d 100644 --- a/service.py +++ b/service.py @@ -19,6 +19,7 @@ from ConnectionManager import ConnectionManager from ClientInformation import ClientInformation from WebSocketClient import WebSocketThread from UserClient import UserClient +from PlaybackUtils import PlaybackUtils librarySync = LibrarySync() @@ -53,11 +54,8 @@ class Service(): lastProgressUpdate = datetime.today() startupComplete = False - #interval_FullSync = 600 - #interval_IncrementalSync = 300 - - #cur_seconds_fullsync = interval_FullSync - #cur_seconds_incrsync = interval_IncrementalSync + WINDOW = xbmcgui.Window(10000) + user = UserClient() player = Player() @@ -70,6 +68,11 @@ class Service(): if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. We should exit break + + if WINDOW.getProperty("GUIPLAY") != "": + id = WINDOW.getProperty("GUIPLAY") + WINDOW.setProperty("GUIPLAY", "") + PlaybackUtils().PLAY(id) if xbmc.Player().isPlaying(): try: From 70182edf0ebac714d651417c1ba4841b6424e3f4 Mon Sep 17 00:00:00 2001 From: im85288 Date: Fri, 1 May 2015 20:13:15 +0100 Subject: [PATCH 07/66] fix for update path - takes 2 parameters --- resources/lib/WriteKodiDB.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 26727583..c718297c 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -485,7 +485,7 @@ class WriteKodiDB(): # UPDATE THE EPISODE IN KODI (for now, we just send in all data) else: pathsql = "UPDATE episode SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, embyId = ? WHERE idEpisode = ?" - cursor.execute(pathsql, title, plot, rating, writer, premieredate, runtime, director, season, episode, title, MBitem["Id"], episodeid) + cursor.execute(pathsql, (title, plot, rating, writer, premieredate, runtime, director, season, episode, title, "-1", "-1", MBitem["Id"], episodeid)) #update or insert actors self.AddPeopleToMedia(episodeid,MBitem.get("People"),"episode", connection, cursor) From 392863fa933685a1e926583cd8c8ff543fef516f Mon Sep 17 00:00:00 2001 From: im85288 Date: Fri, 1 May 2015 20:15:43 +0100 Subject: [PATCH 08/66] update episode rather than tv show --- resources/lib/LibrarySync.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index d95d2989..a0363d02 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -204,7 +204,7 @@ class LibrarySync(): else: # If there are changes to the item, perform a full sync of the item if kodiEpisode[2] != item["Name"] or item["Id"] in itemList: - WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"], kodiShowId, connection, cursor) + WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor) #### EPISODES: PROCESS DELETES ##### allEmbyEpisodeIds = set(allEmbyEpisodeIds) From ecd1fad09f648103025eca5c9b1553754fe5dac6 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Fri, 1 May 2015 22:14:00 +0200 Subject: [PATCH 09/66] revert to old method for file access while sorting out the plugin approach --- resources/lib/Utils.py | 2 +- resources/lib/WriteKodiDB.py | 60 +++++++++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/resources/lib/Utils.py b/resources/lib/Utils.py index a9da6b5c..578a5cae 100644 --- a/resources/lib/Utils.py +++ b/resources/lib/Utils.py @@ -62,7 +62,7 @@ def getKodiDBPath(): dbVersion = "78" if xbmc.getInfoLabel("System.BuildVersion").startswith("15"): #isengard - dbVersion = "91" + dbVersion = "92" else: #helix dbVersion = "90" diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 26727583..dd778dd1 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -113,9 +113,21 @@ class WriteKodiDB(): #### ADD OR UPDATE THE FILE AND PATH ########### #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY - path = "plugin://plugin.video.emby/" + path = "plugin://plugin.video.emby/?id=%s&mode=play" % MBitem["Id"] filename = "plugin://plugin.video.emby/?id=%s&mode=play" % MBitem["Id"] + playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) + playurl = utils.convertEncoding(playurl) + + # we need to store both the path and the filename seperately in the kodi db so we split them up + if "\\" in playurl: + filename = playurl.rsplit("\\",1)[-1] + path = playurl.replace(filename,"") + elif "/" in playurl: + filename = playurl.rsplit("/",1)[-1] + path = playurl.replace(filename,"") + + #create the path cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) result = cursor.fetchone() @@ -227,11 +239,28 @@ class WriteKodiDB(): path = "plugin://plugin.video.emby/tvshows/" + MBitem["Id"] + "/" + playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) + #make sure that the path always ends with a slash + path = utils.convertEncoding(playurl + "/") + #### ADD THE TV SHOW TO KODI ############## if showid == None: + + #create the tv show path + cursor.execute("select coalesce(max(idPath),0) as pathid from path") + pathid = cursor.fetchone()[0] + pathid = pathid + 1 + pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" + cursor.execute(pathsql, (pathid,path,None,None,1)) + #create toplevel path as monitored source - needed for things like actors and stuff to work (no clue why) - toplevelpath = "plugin://plugin.video.emby/tvshows/" + if "\\" in path: + toplevelpathstr = path.rsplit("\\",2)[1] + toplevelpath = path.replace(toplevelpathstr + "\\","") + elif "/" in path: + toplevelpathstr = path.rsplit("/",2)[1] + toplevelpath = path.replace(toplevelpathstr + "/","") cursor.execute("SELECT idPath as tlpathid FROM path WHERE strPath = ?",(toplevelpath,)) result = cursor.fetchone() if result == None: @@ -240,16 +269,8 @@ class WriteKodiDB(): tlpathid = tlpathid + 1 pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" cursor.execute(pathsql, (tlpathid,toplevelpath,"tvshows","metadata.local",1)) - else: - tlpathid = result[0] - - #create the tv show path - cursor.execute("select coalesce(max(idPath),0) as pathid from path") - pathid = cursor.fetchone()[0] - pathid = pathid + 1 - pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate, idParentPath) values(?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (pathid,path,None,None,1,tlpathid)) - + + runtime = int(timeInfo.get('Duration'))*60 plot = utils.convertEncoding(API().getOverview(MBitem)) title = utils.convertEncoding(MBitem["Name"]) @@ -259,7 +280,7 @@ class WriteKodiDB(): #create the tvshow cursor.execute("select coalesce(max(idShow),0) as showid from tvshow") showid = cursor.fetchone()[0] - showid = pathid + 1 + showid = showid + 1 pathsql="insert into tvshow(idShow, c00, c01, c04, c05, c08, c09, c13, c14, c15, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" cursor.execute(pathsql, (showid, title, plot, rating, premieredate, genre, title, mpaa, studio, sorttitle, MBitem["Id"])) @@ -434,6 +455,18 @@ class WriteKodiDB(): path = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/" filename = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/?id=" + MBitem["Id"] + "&mode=play" + playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) + playurl = utils.convertEncoding(playurl) + + # we need to store both the path and the filename seperately in the kodi db so we split them up + if "\\" in playurl: + filename = playurl.rsplit("\\",1)[-1] + path = playurl.replace(filename,"") + elif "/" in playurl: + filename = playurl.rsplit("/",1)[-1] + path = playurl.replace(filename,"") + + #create the new path - return id if already exists cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) result = cursor.fetchone() @@ -686,7 +719,6 @@ class WriteKodiDB(): peoplesql="INSERT OR REPLACE into writerlinkepisode(idWriter, idEpisode) values(?, ?)" cursor.execute(peoplesql, (actorid,id)) - def AddGenresToMedia(self, id, genres, mediatype, cursor): if genres: From b4dd9f58bd458d2ea1f465a912cf1c97556aa9c3 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 02:26:06 +0200 Subject: [PATCH 10/66] fixed the plugin path for playback --- resources/lib/API.py | 19 ++- resources/lib/LibrarySync.py | 271 +-------------------------------- resources/lib/PlaybackUtils.py | 24 +-- resources/lib/ReadKodiDB.py | 221 ++------------------------- resources/lib/WriteKodiDB.py | 166 +++++++++----------- 5 files changed, 119 insertions(+), 582 deletions(-) diff --git a/resources/lib/API.py b/resources/lib/API.py index 50e5587b..05fd237b 100644 --- a/resources/lib/API.py +++ b/resources/lib/API.py @@ -118,7 +118,24 @@ class API(): 'width' : width, 'aspectratio' : str(aspectfloat) } - + + def getChecksum(self, item): + #TODO --> use the etags or serverside checksum for this + # for now we just add some fields to a string + checksum = "" + userData = item.get("UserData") + if(userData != None): + checksum += str(userData.get("Played")) + checksum += str(userData.get("IsFavorite")) + if userData.get('UnplayedItemCount') != None: + checksum += str(userData.get("UnplayedItemCount")) + if userData.get('LastPlayedDate') != None: + checksum += str(userData.get("LastPlayedDate")) + if userData.get('PlaybackPositionTicks') != None: + checksum += str(userData.get("PlaybackPositionTicks")) + + return checksum + def getUserData(self, item): userData = item.get("UserData") resumeTime = 0 diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index a0363d02..114e00e2 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -51,10 +51,7 @@ class LibrarySync(): #TEMP --> add new columns try: - cursor.execute("alter table movie ADD COLUMN 'embyId' TEXT") - cursor.execute("alter table tvshow ADD COLUMN 'embyId' TEXT") - cursor.execute("alter table episode ADD COLUMN 'embyId' TEXT") - cursor.execute("alter table musicvideo ADD COLUMN 'embyId' TEXT") + cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER)") connection.commit() except: pass @@ -109,8 +106,7 @@ class LibrarySync(): allKodiMovieIds.append(item["Id"]) WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) else: - # TODO --> compare with eTag - if kodiMovie[2] != item["Name"] or item["Id"] in itemList: + if kodiMovie[2] != API().getChecksum(item) or item["Id"] in itemList: WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) #### PROCESS DELETES ##### @@ -158,7 +154,7 @@ class LibrarySync(): else: kodiId = kodishow[0] # If there are changes to the item, perform a full sync of the item - if kodiShow[2] != item["Name"] or item["Id"] in itemList: + if kodiShow[2] != API().getChecksum(item) or item["Id"] in itemList: WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) #### PROCESS EPISODES ###### @@ -203,18 +199,17 @@ class LibrarySync(): WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor) else: # If there are changes to the item, perform a full sync of the item - if kodiEpisode[2] != item["Name"] or item["Id"] in itemList: + if kodiEpisode[2] != API().getChecksum(item) or item["Id"] in itemList: WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor) #### EPISODES: PROCESS DELETES ##### allEmbyEpisodeIds = set(allEmbyEpisodeIds) print allEmbyEpisodeIds for kodiId in allKodiEpisodeIds: + print "kodiId-->" + kodiId if not kodiId in allEmbyEpisodeIds: WINDOW.setProperty(kodiId,"deleted") - print "deleting ???-->" + kodiId - #WriteKodiDB().deleteEpisodeFromKodiLibrary(kodiId, connection, cursor) - + WriteKodiDB().deleteEpisodeFromKodiLibrary(kodiId, connection, cursor) def MusicVideosSync(self, fullsync, installFirstRun,connection, cursor): @@ -328,260 +323,6 @@ class LibrarySync(): return True - def updatePlayCounts(self): - #update all playcounts from MB3 to Kodi library - - addon = xbmcaddon.Addon(id='plugin.video.emby') - WINDOW = xbmcgui.Window( 10000 ) - pDialog = None - startedSync = datetime.today() - processMovies = True - processTvShows = True - - if(WINDOW.getProperty("SyncDatabaseShouldStop") == "true"): - utils.logMsg("Sync PlayCount", "Can not start SyncDatabaseShouldStop=True", 0) - return True - - if(WINDOW.getProperty("updatePlayCounts_Running") == "true"): - utils.logMsg("Sync PlayCount", "updatePlayCounts Already Running", 0) - return False - - WINDOW.setProperty("updatePlayCounts_Running", "true") - - try: - playCountSyncIndication = addon.getSetting("playCountSyncIndication") - playCountSyncFirstRun = addon.getSetting("SyncFirstCountsRunDone") - - if(playCountSyncFirstRun != "true" or playCountSyncIndication == "Dialog Progress"): - pDialog = xbmcgui.DialogProgress() - elif(playCountSyncIndication == "BG Progress"): - pDialog = xbmcgui.DialogProgressBG() - - if(pDialog != None): - pDialog.create('Sync PlayCounts', 'Sync PlayCounts') - - totalCountsUpdated = 0 - totalPositionsUpdated = 0 - - #process movies - if processMovies: - if(pDialog != None): - pDialog.update(0, "Processing Movies", "") - - views = ReadEmbyDB().getCollections("movies") - viewCount = len(views) - viewCurrent = 1 - for view in views: - allMB3Movies = ReadEmbyDB().getMovies(view.get('id'), fullinfo = False, fullSync = True) - allKodiMovies = ReadKodiDB().getKodiMovies(False) - - if(self.ShouldStop(pDialog)): - return False - - if(allMB3Movies != None and allKodiMovies != None): - - if(pDialog != None): - progressTitle = "Sync PlayCounts: Processing " + view.get('title') + " " + str(viewCurrent) + " of " + str(viewCount) - pDialog.update(0, progressTitle) - totalCount = len(allMB3Movies) + 1 - count = 1 - - for item in allMB3Movies: - - if not item.get('IsFolder'): - kodiItem = allKodiMovies.get(item["Id"], None) - - userData = API().getUserData(item) - timeInfo = API().getTimeInfo(item) - - if kodiItem != None: - kodiresume = int(round(kodiItem['resume'].get("position"))) - resume = int(round(float(timeInfo.get("ResumeTime"))))*60 - total = int(round(float(timeInfo.get("TotalTime"))))*60 - if kodiresume != resume: - WriteKodiDB().setKodiResumePoint(kodiItem['movieid'],resume,total,"movie") - totalPositionsUpdated += 1 - updated = WriteKodiDB().updateProperty(kodiItem,"playcount",int(userData.get("PlayCount")), "movie") - updated |= WriteKodiDB().updateProperty(kodiItem,"lastplayed",userData.get("LastPlayedDate"), "movie") - if(updated): - totalCountsUpdated += 1 - - if(self.ShouldStop(pDialog)): - return False - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(totalCount)) * 100)) - pDialog.update(percentage, progressTitle, "Updating Movie: " + str(count)) - count += 1 - - viewCurrent += 1 - - #process Tv shows - if processTvShows: - if(pDialog != None): - pDialog.update(0, "Processing TV Episodes", "") - views = ReadEmbyDB().getCollections("tvshows") - viewCount = len(views) - viewCurrent = 1 - progressTitle = "" - for view in views: - - tvshowData = ReadEmbyDB().getTVShows(id = view.get('id'), fullinfo = False, fullSync = True) - - if(self.ShouldStop(pDialog)): - return False - - if (tvshowData != None): - - showTotal = len(tvshowData) - showCurrent = 1 - - for item in tvshowData: - - episodeData = ReadEmbyDB().getEpisodes(item["Id"], False) - allKodiTVShows = ReadKodiDB().getKodiTvShows(False) - kodishow = allKodiTVShows.get(item["Id"],None) - if kodishow != None: - kodiEpisodes = ReadKodiDB().getKodiEpisodes(kodishow["tvshowid"],False,True) - else: - kodiEpisodes = None - - if (episodeData != None): - if(pDialog != None): - progressTitle = "Sync PlayCounts: Processing TV Show " + str(showCurrent) + " of " + str(showTotal) - pDialog.update(0, progressTitle) - totalCount = len(episodeData) + 1 - count = 1 - - for episode in episodeData: - - kodiItem = None - matchFound = False - if kodiEpisodes != None: - kodiItem = kodiEpisodes.get(episode.get("Id"), None) - - userData=API().getUserData(episode) - timeInfo = API().getTimeInfo(episode) - - - if kodiItem != None: - WINDOW = xbmcgui.Window( 10000 ) - WINDOW.setProperty("episodeid" + str(kodiItem['episodeid']), episode.get('Name') + ";;" + episode.get('Id')) - WINDOW.setProperty(episode.get('Id'), "episode;;" + str(kodishow["tvshowid"]) + ";;" +str(kodiItem['episodeid'])) - kodiresume = int(round(kodiItem['resume'].get("position"))) - resume = int(round(float(timeInfo.get("ResumeTime"))))*60 - total = int(round(float(timeInfo.get("TotalTime"))))*60 - if kodiresume != resume: - WriteKodiDB().setKodiResumePoint(kodiItem['episodeid'],resume,total,"episode") - totalPositionsUpdated += 1 - - updated = WriteKodiDB().updateProperty(kodiItem,"playcount",int(userData.get("PlayCount")),"episode") - updated |= WriteKodiDB().updateProperty(kodiItem,"lastplayed",userData.get("LastPlayedDate"), "episode") - if(updated): - totalCountsUpdated += 1 - - if(self.ShouldStop(pDialog)): - return False - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(totalCount)) * 100)) - pDialog.update(percentage, progressTitle, "Updating Episode: " + str(count)) - count += 1 - - showCurrent += 1 - - if(playCountSyncFirstRun != "true"): - addon = xbmcaddon.Addon(id='plugin.video.emby') - addon.setSetting("SyncFirstCountsRunDone", "true") - - # display notification if set up - notificationString = "" - if(totalPositionsUpdated > 0): - notificationString += "Pos:" + str(totalPositionsUpdated) + " " - if(totalCountsUpdated > 0): - notificationString += "Counts:" + str(totalCountsUpdated) + " " - - timeTaken = datetime.today() - startedSync - timeTakenString = str(int(timeTaken.seconds / 60)) + ":" + str(timeTaken.seconds % 60) - utils.logMsg("Sync PlayCount", "Finished " + timeTakenString + " " + notificationString, 0) - - if(playCountSyncIndication == "Notify OnChange" and notificationString != ""): - notificationString = "(" + timeTakenString + ") " + notificationString - xbmc.executebuiltin("XBMC.Notification(PlayCount Sync: " + notificationString + ",)") - elif(playCountSyncIndication == "Notify OnFinish"): - if(notificationString == ""): - notificationString = "Done" - notificationString = "(" + timeTakenString + ") " + notificationString - xbmc.executebuiltin("XBMC.Notification(PlayCount Sync: " + notificationString + ",)") - - finally: - WINDOW.setProperty("updatePlayCounts_Running", "false") - if(pDialog != None): - pDialog.close() - - return True - - def updatePlayCount(self, itemID): - #update playcount of the itemID from MB3 to Kodi library - - addon = xbmcaddon.Addon(id='plugin.video.emby') - WINDOW = xbmcgui.Window( 10000 ) - - embyItem = ReadEmbyDB().getItem(itemID) - if(embyItem == None): - return False - - type = embyItem.get("Type") - - #process movie - if type == 'Movie': - kodiItem = ReadKodiDB().getKodiMovie(itemID) - - if(kodiItem == None): - return False - - if(self.ShouldStop(None)): - return False - - userData = API().getUserData(embyItem) - timeInfo = API().getTimeInfo(embyItem) - - kodiresume = int(round(kodiItem['resume'].get("position"))) - resume = int(round(float(timeInfo.get("ResumeTime"))))*60 - total = int(round(float(timeInfo.get("TotalTime"))))*60 - if kodiresume != resume: - WriteKodiDB().setKodiResumePoint(kodiItem['movieid'],resume,total,"movie") - #write property forced will refresh the item in the list so playcount change is immediately visible - WriteKodiDB().updateProperty(kodiItem,"playcount",int(userData.get("PlayCount")),"movie",True) - WriteKodiDB().updateProperty(kodiItem,"lastplayed",userData.get("LastPlayedDate"), "movie") - - if(self.ShouldStop(None)): - return False - - #process episode - elif type == 'Episode': - if(self.ShouldStop(None)): - return False - - kodiItem = ReadKodiDB().getKodiEpisodeByMbItem(embyItem["Id"], embyItem["SeriesId"]) - - userData = API().getUserData(embyItem) - timeInfo = API().getTimeInfo(embyItem) - - if kodiItem != None: - kodiresume = int(round(kodiItem['resume'].get("position"))) - resume = int(round(float(timeInfo.get("ResumeTime"))))*60 - total = int(round(float(timeInfo.get("TotalTime"))))*60 - if kodiresume != resume: - WriteKodiDB().setKodiResumePoint(kodiItem['episodeid'],resume,total,"episode") - #write property forced will refresh the item in the list so playcount change is immediately visible - WriteKodiDB().updateProperty(kodiItem,"playcount",int(userData.get("PlayCount")),"episode",True) - WriteKodiDB().updateProperty(kodiItem,"lastplayed",userData.get("LastPlayedDate"), "episode") - - return True - def ShouldStop(self, prog): if(prog != None and type(prog) == xbmcgui.DialogProgress): diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index bad30609..0447c415 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -52,17 +52,17 @@ class PlaybackUtils(): seekTime = 0 #get the resume point from Kodi DB for a Movie - kodiItem = ReadKodiDB().getKodiMovie(id) - if kodiItem != None: - seekTime = int(round(kodiItem['resume'].get("position"))) - else: - #get the resume point from Kodi DB for an episode - episodeItem = ReadEmbyDB().getItem(id) - if episodeItem != None and str(episodeItem["Type"]) == "Episode": - kodiItem = ReadKodiDB().getKodiEpisodeByMbItem(id,episodeItem["SeriesId"]) - if kodiItem != None: - seekTime = int(round(kodiItem['resume'].get("position"))) - + # kodiItem = ReadKodiDB().getKodiMovie(id) + # if kodiItem != None: + # seekTime = int(round(kodiItem['resume'].get("position"))) + # else: + # #get the resume point from Kodi DB for an episode + # episodeItem = ReadEmbyDB().getItem(id) + # if episodeItem != None and str(episodeItem["Type"]) == "Episode": + # kodiItem = ReadKodiDB().getKodiEpisodeByMbItem(id,episodeItem["SeriesId"]) + # if kodiItem != None: + # seekTime = int(round(kodiItem['resume'].get("position"))) + playurl = PlayUtils().getPlayUrl(server, id, result) isStrmFile = False @@ -137,7 +137,7 @@ class PlaybackUtils(): if isStrmFile: xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) else: - xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) + #xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) if(addon.getSetting("addExtraPlaybackArt") == "true"): utils.logMsg("PLAY", "Doing second xbmc.Player().play to add extra art") xbmc.Player().play(playurl,listItem) diff --git a/resources/lib/ReadKodiDB.py b/resources/lib/ReadKodiDB.py index 14b0872a..9909f4f9 100644 --- a/resources/lib/ReadKodiDB.py +++ b/resources/lib/ReadKodiDB.py @@ -16,229 +16,28 @@ import Utils as utils sleepVal = 15 class ReadKodiDB(): - - def getKodiMovie(self, id): - #returns a single movie from Kodi db selected on MB item ID - xbmc.sleep(sleepVal) - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "properties" : ["art", "rating", "thumbnail", "fanart", "resume", "runtime", "year", "genre", "cast", "trailer", "country", "studio", "set", "imdbnumber", "mpaa", "tagline", "plotoutline","plot", "sorttitle", "director", "lastplayed", "writer", "playcount", "tag", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMovies"}') - jsonobject = json.loads(json_response.decode('utf-8','replace')) - movie = None - if(jsonobject.has_key('result')): - result = jsonobject['result'] - if(result.has_key('movies')): - movies = result['movies'] - movie = movies[0] - for item in movies: - if id in item["file"]: - movie = item - break - return movie - - def getEmbyIdByKodiId(self, kodiid, type): - embyId = None - connection = utils.KodiSQL() - cursor = connection.cursor() - - if type == "movie": - cursor.execute("SELECT embyId as embyId FROM movie WHERE idMovie = ?",(kodiid,)) - if type == "episode": - cursor.execute("SELECT embyId as embyId FROM episode WHERE idEpisode = ?",(kodiid,)) - if type == "musicvideo": - cursor.execute("SELECT embyId as embyId FROM musicvideo WHERE idMVideo = ?",(kodiid,)) - if type == "tvshow": - cursor.execute("SELECT embyId as embyId FROM tvshow WHERE idShow = ?",(kodiid,)) - - result = cursor.fetchone() - cursor.close() - if result != None: - embyId = result[0] - - return embyId - + def getKodiMovies(self, connection, cursor): #returns all movies in Kodi db - cursor.execute("SELECT idMovie, embyId, c00 FROM movie") + cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='movie'") allmovies = cursor.fetchall() #this will return a list with tuples of all items returned from the database return allmovies - - def getKodiMoviesIds(self,returnMB3Ids = False): - # returns a list of movieIds or MB3 Id's from all movies currently in the Kodi library - allKodiMovies = self.getKodiMovies(False) - - if(allKodiMovies == None): - return list() - - if(returnMB3Ids): - allKodiMovieIds = list(allKodiMovies.keys()) - return allKodiMovieIds - else: - allKodiMovieIds = list() - for kodimovie in allKodiMovies.values(): - id = str(kodimovie["movieid"]) - allKodiMovieIds.append(id) - - return allKodiMovieIds - - def getKodiTvShowsIds(self,returnMB3Ids = False): - # returns a list of tvshowIds or MB3 Id's from all tvshows currently in the Kodi library - allKodiTvShows = self.getKodiTvShows(False) - - if allKodiTvShows == None: - return list() - - if(returnMB3Ids): - allKodiTvShowsIds = list(allKodiTvShows.keys()) - return allKodiTvShowsIds - else: - allKodiTvShowsIds = list() - for kodishow in allKodiTvShows.values(): - id = str(kodishow["tvshowid"]) - allKodiTvShowsIds.append(id) - - return allKodiTvShowsIds def getKodiTvShows(self, connection, cursor): - cursor.execute("SELECT idShow, embyId, c00 FROM tvshow") + cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='tvshow'") allshows = cursor.fetchall() #this will return a list with tuples of all items returned from the database return allshows - - def getKodiTVShow(self, id): - xbmc.sleep(sleepVal) - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "properties": ["art", "genre", "plot", "mpaa", "cast", "studio", "sorttitle", "title", "originaltitle", "imdbnumber", "year", "lastplayed", "premiered", "rating", "thumbnail", "playcount", "file", "fanart", "tag"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libTvShows"}') - jsonobject = json.loads(json_response.decode('utf-8','replace')) - tvshow = None - if(jsonobject.has_key('result')): - result = jsonobject['result'] - if(result.has_key('tvshows')): - tvshows = result['tvshows'] - for show in tvshows: - if show["imdbnumber"] == id: - tvshow = show - break - return tvshow - - def getKodiEpisodes(self, connection, cursor, showid): - cursor.execute("SELECT idEpisode, embyId, c00 FROM episode WHERE idShow = ?", (showid,)) + + def getKodiEpisodes(self, connection, cursor, showid=None): + + if showid == None: + cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type=?",("episode",)) + else: + cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type=? AND parent_id=?",("episode", showid)) allepisodes = cursor.fetchall() #this will return a list with tuples of all items returned from the database return allepisodes - def getKodiEpisodeByMbItem(self, episodeid, tvshowid): - episode = None - tvshow = self.getKodiTVShow(tvshowid) - - if tvshow != None: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": ' + str(tvshow['tvshowid']) + ', "properties": ["playcount","season", "resume", "episode", "lastplayed", "uniqueid", "file"], "sort": {"method": "episode"}}, "id": 1}') - jsonobject = json.loads(json_response.decode('utf-8','replace')) - if(jsonobject.has_key('result')): - result = jsonobject['result'] - if(result.has_key('episodes')): - episodes = result['episodes'] - for ep in episodes: - if ep["uniqueid"]["unknown"] == episodeid: - episode = ep - break - - return episode - - def getKodiEpisodeByMbItemEx(self, id): - connection = utils.KodiSQL() - cursor = connection.cursor() - cursor.execute("SELECT idEpisode FROM episode WHERE c20 = ?", (id,)) - result = cursor.fetchone() - kodiId = None - if result != None: - kodiId = result[0] - cursor.close() - - episode = None - if(kodiId != None): - print "Kodi Episode ID : " + str(kodiId) - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodeDetails", "params": {"episodeid": %d, "properties": ["playcount", "season", "resume", "episode", "lastplayed", "uniqueid", "file"]}, "id": 1}' %kodiId) - #json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodeDetails", "params": {"episodeid": ' + str(kodiId) + ', "properties": ["playcount", "season", "resume", "episode", "lastplayed", "uniqueid", "file"], "sort": {"method": "episode"}}, "id": 1}') - jsonobject = json.loads(json_response.decode('utf-8','replace')) - print "Kodi_Item: " + str(jsonobject) - if(jsonobject.has_key("result")): - result = jsonobject["result"] - if(result.has_key("episodedetails")): - episode = result["episodedetails"] - - return episode - - def getKodiMusicVideo(self, id): - #returns a single musicvideo from Kodi db selected on MB item ID - xbmc.sleep(sleepVal) - #get the mediabrowser ID from DB - connection = utils.KodiSQL() - cursor = connection.cursor() - cursor.execute("SELECT idMVideo as musicvideoid FROM musicvideo WHERE c23 = ?",(id,)) - result = cursor.fetchone() - musicvideoid = None - if result != None: - musicvideoid = result[0] - cursor.close() - - musicvideo = None - - if musicvideoid != None: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMusicVideosDetails", "params": { "musicvideoid": ' + musicvideoid + ', "properties" : ["art", "thumbnail", "fanart", "resume", "runtime", "year", "genre", "studio", "artist", "album", "track","plot", "director", "playcount", "lastplayed", "tag", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMusicVideos"}') - jsonobject = json.loads(json_response.decode('utf-8','replace')) - musicvideo = None - - if(jsonobject.has_key('result')): - result = jsonobject['result'] - if(result.has_key('musicvideodetails')): - musicvideo = result['musicvideodetails'] - - return musicvideo - - def getKodiMusicVideos(self,fullInfo = False): - #returns all musicvideos in Kodi db inserted by MB - xbmc.sleep(sleepVal) - if fullInfo: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMusicVideos", "params": { "properties" : ["art", "thumbnail", "fanart", "resume", "runtime", "year", "genre", "studio", "artist", "album", "track", "lastplayed", "plot", "director", "playcount", "tag", "file"] }, "id": "libMusicVideos"}') - else: - json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMusicVideos", "params": { "properties" : ["resume", "playcount", "lastplayed", "file", "track"] }, "id": "libMusicVideos"}') - jsonobject = json.loads(json_response.decode('utf-8','replace')) - musicvideos = None - if(jsonobject.has_key('result')): - result = jsonobject['result'] - if(result.has_key('musicvideos')): - musicvideos = result['musicvideos'] - - kodiMusicVideoMap = None - if(musicvideos != None and len(musicvideos) > 0): - kodiMusicVideoMap = {} - connection = utils.KodiSQL() - cursor = connection.cursor() - for kodivideo in musicvideos: - cursor.execute("SELECT c23 as MBid FROM musicvideo WHERE idMVideo = ?",(kodivideo["musicvideoid"],)) - result = cursor.fetchone() - if result != None: - key = result[0] - kodiMusicVideoMap[key] = kodivideo - - cursor.close() - return kodiMusicVideoMap - - def getKodiMusicVideoIds(self,returnMB3Ids = False): - # returns a list of movieIds or MB3 Id's from all movies currently in the Kodi library - allKodiMusicVideos = self.getKodiMusicVideos(False) - - if(allKodiMusicVideos == None): - return list() - - if(returnMB3Ids): - allKodiMusicVideoIds = list(allKodiMusicVideos.keys()) - return allKodiMusicVideoIds - else: - allKodiMusicVideoIds = list() - for kodivideo in allKodiMusicVideos.values(): - id = str(kodivideo["musicvideoid"]) - allKodiMusicVideoIds.append(id) - - return allKodiMusicVideoIds - \ No newline at end of file diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index ff4dc30e..fddc62e7 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -57,7 +57,7 @@ class WriteKodiDB(): # 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 idMovie FROM movie WHERE embyId = ?",(MBitem["Id"],)) + cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?",(MBitem["Id"],)) result = cursor.fetchone() if result != None: movieid = result[0] @@ -99,7 +99,7 @@ class WriteKodiDB(): jsonData = downloadUtils.downloadUrl(itemTrailerUrl) if(jsonData != ""): trailerItem = jsonData - trailerUrl = "plugin://plugin.video.emby/?id=%s&mode=play" % trailerItem[0][u'Id'] + trailerUrl = "plugin://plugin.video.emby/trailer/?id=%s&mode=play" % trailerItem[0][u'Id'] if MBitem.get("DateCreated") != None: dateadded = MBitem["DateCreated"].replace("T"," ") @@ -113,21 +113,9 @@ class WriteKodiDB(): #### ADD OR UPDATE THE FILE AND PATH ########### #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY - path = "plugin://plugin.video.emby/?id=%s&mode=play" % MBitem["Id"] - filename = "plugin://plugin.video.emby/?id=%s&mode=play" % MBitem["Id"] + path = "plugin://plugin.video.emby/movies/" + filename = "plugin://plugin.video.emby/movies/?id=%s&mode=play" % MBitem["Id"] - playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) - playurl = utils.convertEncoding(playurl) - - # we need to store both the path and the filename seperately in the kodi db so we split them up - if "\\" in playurl: - filename = playurl.rsplit("\\",1)[-1] - path = playurl.replace(filename,"") - elif "/" in playurl: - filename = playurl.rsplit("/",1)[-1] - path = playurl.replace(filename,"") - - #create the path cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) result = cursor.fetchone() @@ -159,16 +147,23 @@ class WriteKodiDB(): cursor.execute("select coalesce(max(idMovie),0) as movieid from movie") movieid = cursor.fetchone()[0] movieid = movieid + 1 - pathsql="insert into movie(idMovie, idFile, c00, c01, c02, c05, c06, c07, c09, c10, c11, c12, c14, c15, c16, c18, c19, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (movieid, fileid, title, plot, shortplot, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio, trailerUrl, MBitem["Id"])) + pathsql="insert into movie(idMovie, idFile, c00, c01, c02, c05, c06, c07, c09, c10, c11, c12, c14, c15, c16, c18, c19) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (movieid, fileid, title, plot, shortplot, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio, trailerUrl)) #add the viewtag self.AddTagToMedia(movieid, viewTag, "movie", cursor) + #create the reference in emby table + pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)" + cursor.execute(pathsql, (MBitem["Id"], movieid, "movie", API().getChecksum(MBitem))) + #### UPDATE THE MOVIE ##### else: - pathsql="update movie SET c00 = ?, c01 = ?, c02 = ?, c05 = ?, c06 = ?, c07 = ?, c09 = ? c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?, c16 = ?, c18 = ?, c19 = ?, embyId= ? WHERE idMovie = ?" - cursor.execute(pathsql, (title, plot, shortplot, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio, trailerUrl, MBitem["Id"], movieid)) + pathsql="update movie SET c00 = ?, c01 = ?, c02 = ?, c05 = ?, c06 = ?, c07 = ?, c09 = ? c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?, c16 = ?, c18 = ?, c19 = ? WHERE idMovie = ?" + cursor.execute(pathsql, (title, plot, shortplot, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio, trailerUrl, movieid)) + + #update the checksum in emby table + cursor.execute("UPDATE emby SET checksum = ? WHERE emby_id = ?", (API().getChecksum(MBitem),MBitem["Id"])) #update or insert actors self.AddPeopleToMedia(movieid,MBitem.get("People"),"movie", connection, cursor) @@ -185,10 +180,15 @@ class WriteKodiDB(): #update genres self.AddGenresToMedia(movieid, genres, "movie", cursor) - + #update studios self.AddStudiosToMedia(movieid, studios, "movie", cursor) + #set resume point + resume = int(round(float(timeInfo.get("ResumeTime"))))*60 + total = int(round(float(timeInfo.get("TotalTime"))))*60 + self.setKodiResumePoint(fileid, resume, total, cursor) + #commit changes and return the id connection.commit() return movieid @@ -210,7 +210,7 @@ class WriteKodiDB(): # 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 idMovie FROM movie WHERE embyId = ?",(MBitem["Id"],)) + cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?",(MBitem["Id"],)) result = cursor.fetchone() if result != None: showid = result[0] @@ -237,12 +237,7 @@ class WriteKodiDB(): else: premieredate = None - path = "plugin://plugin.video.emby/tvshows/" + MBitem["Id"] + "/" - - playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) - #make sure that the path always ends with a slash - path = utils.convertEncoding(playurl + "/") - + path = "plugin://plugin.video.emby/tvshows/" + MBitem["Id"] + "/" #### ADD THE TV SHOW TO KODI ############## if showid == None: @@ -255,12 +250,7 @@ class WriteKodiDB(): cursor.execute(pathsql, (pathid,path,None,None,1)) #create toplevel path as monitored source - needed for things like actors and stuff to work (no clue why) - if "\\" in path: - toplevelpathstr = path.rsplit("\\",2)[1] - toplevelpath = path.replace(toplevelpathstr + "\\","") - elif "/" in path: - toplevelpathstr = path.rsplit("/",2)[1] - toplevelpath = path.replace(toplevelpathstr + "/","") + toplevelpath = "plugin://plugin.video.emby/" cursor.execute("SELECT idPath as tlpathid FROM path WHERE strPath = ?",(toplevelpath,)) result = cursor.fetchone() if result == None: @@ -281,8 +271,12 @@ class WriteKodiDB(): cursor.execute("select coalesce(max(idShow),0) as showid from tvshow") showid = cursor.fetchone()[0] showid = showid + 1 - pathsql="insert into tvshow(idShow, c00, c01, c04, c05, c08, c09, c13, c14, c15, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (showid, title, plot, rating, premieredate, genre, title, mpaa, studio, sorttitle, MBitem["Id"])) + pathsql="insert into tvshow(idShow, c00, c01, c04, c05, c08, c09, c13, c14, c15) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (showid, title, plot, rating, premieredate, genre, title, mpaa, studio, sorttitle)) + + #create the reference in emby table + pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)" + cursor.execute(pathsql, (MBitem["Id"], showid, "tvshow", API().getChecksum(MBitem))) #link the path pathsql="insert into tvshowlinkpath(idShow,idPath) values(?, ?)" @@ -293,8 +287,11 @@ class WriteKodiDB(): #### UPDATE THE TV SHOW ############# else: - pathsql="UPDATE tvshow SET (c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?, c13 = ?, c14 = ?, c15 = ?, embyId = ? WHERE idShow = ?" - cursor.execute(pathsql, title, plot, rating, premieredate, title, genre, mpaa, studio, sorttitle, MBitem["Id"], showid) + pathsql="UPDATE tvshow SET (c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?, c13 = ?, c14 = ?, c15 = ? WHERE idShow = ?" + cursor.execute(pathsql, title, plot, rating, premieredate, title, genre, mpaa, studio, sorttitle, showid) + + #update the checksum in emby table + cursor.execute("UPDATE emby SET checksum = ? WHERE emby_id = ?", (API().getChecksum(MBitem), MBitem["Id"])) #update or insert people self.AddPeopleToMedia(showid,MBitem.get("People"),"tvshow", connection, cursor) @@ -304,7 +301,7 @@ class WriteKodiDB(): #update studios self.AddStudiosToMedia(showid, studios, "tvshow", cursor) - + #update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), showid, "tvshow", "thumb", cursor) self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), showid, "tvshow", "poster", cursor) @@ -399,11 +396,9 @@ class WriteKodiDB(): # If the item doesn't exist, we'll add it to the database MBitem = ReadEmbyDB().getFullItem(embyId) - - cursor.execute("SELECT idEpisode FROM episode WHERE embyId = ?",(MBitem["Id"],)) + cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?",(MBitem["Id"],)) result = cursor.fetchone() if result != None: - utils.logMsg("Emby", "Episode already exists in DB : " + MBitem["Id"] + " - " + MBitem["Name"], 2) episodeid = result[0] else: episodeid = None @@ -455,18 +450,6 @@ class WriteKodiDB(): path = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/" filename = "plugin://plugin.video.emby/tvshows/" + MBitem["SeriesId"] + "/?id=" + MBitem["Id"] + "&mode=play" - playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) - playurl = utils.convertEncoding(playurl) - - # we need to store both the path and the filename seperately in the kodi db so we split them up - if "\\" in playurl: - filename = playurl.rsplit("\\",1)[-1] - path = playurl.replace(filename,"") - elif "/" in playurl: - filename = playurl.rsplit("/",1)[-1] - path = playurl.replace(filename,"") - - #create the new path - return id if already exists cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) result = cursor.fetchone() @@ -512,30 +495,40 @@ class WriteKodiDB(): cursor.execute("select coalesce(max(idEpisode),0) as episodeid from episode") episodeid = cursor.fetchone()[0] episodeid = episodeid + 1 - pathsql = "INSERT into episode(idEpisode, idFile, c00, c01, c03, c04, c05, c09, c10, c12, c13, c14, idShow, c15, c16, embyId) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (episodeid, fileid, title, plot, rating, writer, premieredate, runtime, director, season, episode, title, showid, "-1", "-1", MBitem["Id"])) + pathsql = "INSERT into episode(idEpisode, idFile, c00, c01, c03, c04, c05, c09, c10, c12, c13, c14, idShow, c15, c16) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (episodeid, fileid, title, plot, rating, writer, premieredate, runtime, director, season, episode, title, showid, "-1", "-1")) + + #create the reference in emby table + pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum, parent_id) values(?, ?, ?, ?, ?)" + cursor.execute(pathsql, (MBitem["Id"], episodeid, "episode", API().getChecksum(MBitem), showid)) # UPDATE THE EPISODE IN KODI (for now, we just send in all data) else: - pathsql = "UPDATE episode SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?, embyId = ? WHERE idEpisode = ?" - cursor.execute(pathsql, (title, plot, rating, writer, premieredate, runtime, director, season, episode, title, "-1", "-1", MBitem["Id"], episodeid)) + pathsql = "UPDATE episode SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ? WHERE idEpisode = ?" + cursor.execute(pathsql, (title, plot, rating, writer, premieredate, runtime, director, season, episode, title, "-1", "-1", episodeid)) + + #update the checksum in emby table + cursor.execute("UPDATE emby SET checksum = ? WHERE emby_id = ?", (API().getChecksum(MBitem), MBitem["Id"])) #update or insert actors self.AddPeopleToMedia(episodeid,MBitem.get("People"),"episode", connection, cursor) + #set resume point + resume = int(round(float(timeInfo.get("ResumeTime"))))*60 + total = int(round(float(timeInfo.get("TotalTime"))))*60 + self.setKodiResumePoint(fileid, resume, total, cursor) + #update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), episodeid, "episode", "thumb", cursor) - try: - connection.commit() - utils.logMsg("Emby","Added or updated episode to Kodi Library - ID: " + MBitem["Id"] + " - " + MBitem["Name"]) - except: - utils.logMsg("Emby","Error adding/updating episode to Kodi Library - ID: " + MBitem["Id"] + " - " + MBitem["Name"]) - actionPerformed = False - + #commit changes + connection.commit() + def deleteMovieFromKodiLibrary(self, id, connection, cursor ): utils.logMsg("deleting movie from Kodi library --> ",id) - cursor.execute("DELETE FROM movie WHERE embyId = ?", (id,)) + cursor.execute("SELECT kodi_id FROM emby WHERE emby_id=?", (id,)) + kodi_id = cursor.fetchone()[0] + cursor.execute("DELETE FROM movie WHERE idMovie = ?", (kodi_id,)) connection.commit() def deleteMusicVideoFromKodiLibrary(self, id ): @@ -546,12 +539,16 @@ class WriteKodiDB(): def deleteEpisodeFromKodiLibrary(self, id, connection, cursor ): utils.logMsg("deleting episode from Kodi library --> ",id) - cursor.execute("DELETE FROM episode WHERE embyId = ?", (id,)) + cursor.execute("SELECT kodi_id FROM emby WHERE emby_id=?", (id,)) + kodi_id = cursor.fetchone()[0] + cursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodi_id,)) connection.commit() def deleteTVShowFromKodiLibrary(self, id, connection, cursor): utils.logMsg("deleting tvshow from Kodi library --> ",id) - cursor.execute("DELETE FROM tvshow WHERE embyId = ?", (id,)) + cursor.execute("SELECT kodi_id FROM emby WHERE emby_id=?", (id,)) + kodi_id = cursor.fetchone()[0] + cursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodi_id,)) connection.commit() def updateSeasons(self,embyTvShowId, kodiTvShowId, connection, cursor): @@ -596,33 +593,16 @@ class WriteKodiDB(): 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 setKodiResumePoint(self, id, resume_seconds, total_seconds, fileType): - #use sqlite to set the resume point while json api doesn't support this yet - #todo --> submit PR to kodi team to get this added to the jsonrpc api - - utils.logMsg("Emby","setting resume point in kodi db..." + fileType + ": " + str(id)) - xbmc.sleep(sleepVal) - connection = utils.KodiSQL() - cursor = connection.cursor( ) - - if fileType == "episode": - cursor.execute("SELECT idFile as fileidid FROM episode WHERE idEpisode = ?",(id,)) - result = cursor.fetchone() - fileid = result[0] - if fileType == "movie": - cursor.execute("SELECT idFile as fileidid FROM movie WHERE idMovie = ?",(id,)) - result = cursor.fetchone() - fileid = result[0] + def setKodiResumePoint(self, fileid, resume_seconds, total_seconds, cursor): cursor.execute("delete FROM bookmark WHERE idFile = ?", (fileid,)) - cursor.execute("select coalesce(max(idBookmark),0) as bookmarkId from bookmark") - bookmarkId = cursor.fetchone()[0] - bookmarkId = bookmarkId + 1 - bookmarksql="insert into bookmark(idBookmark, idFile, timeInSeconds, totalTimeInSeconds, thumbNailImage, player, playerState, type) values(?, ?, ?, ?, ?, ?, ?, ?)" - cursor.execute(bookmarksql, (bookmarkId,fileid,resume_seconds,total_seconds,None,"DVDPlayer",None,1)) - connection.commit() - cursor.close() - + if resume_seconds != 0: + cursor.execute("select coalesce(max(idBookmark),0) as bookmarkId from bookmark") + bookmarkId = cursor.fetchone()[0] + bookmarkId = bookmarkId + 1 + bookmarksql="insert into bookmark(idBookmark, idFile, timeInSeconds, totalTimeInSeconds, thumbNailImage, player, playerState, type) values(?, ?, ?, ?, ?, ?, ?, ?)" + cursor.execute(bookmarksql, (bookmarkId,fileid,resume_seconds,total_seconds,None,"DVDPlayer",None,1)) + def AddPeopleToMedia(self, id, people, mediatype, connection, cursor): downloadUtils = DownloadUtils() From 42c7256f54caccc46668e34150a978af5f721f48 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 02:57:58 +0200 Subject: [PATCH 11/66] added streamdetails --- resources/lib/API.py | 6 +++--- resources/lib/WriteKodiDB.py | 21 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/resources/lib/API.py b/resources/lib/API.py index 05fd237b..738eb48d 100644 --- a/resources/lib/API.py +++ b/resources/lib/API.py @@ -99,8 +99,8 @@ class API(): for mediaStream in MediaStreams: if(mediaStream.get("Type") == "Video"): videocodec = mediaStream.get("Codec") - height = str(mediaStream.get("Height")) - width = str(mediaStream.get("Width")) + height = int(mediaStream.get("Height")) + width = int(mediaStream.get("Width")) aspectratio = mediaStream.get("AspectRatio") if aspectratio != None and len(aspectratio) >= 3: try: @@ -116,7 +116,7 @@ class API(): 'audiocodec' : audiocodec, 'height' : height, 'width' : width, - 'aspectratio' : str(aspectfloat) + 'aspectratio' : aspectfloat } def getChecksum(self, item): diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index fddc62e7..6e47a853 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -157,6 +157,9 @@ class WriteKodiDB(): pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)" cursor.execute(pathsql, (MBitem["Id"], movieid, "movie", API().getChecksum(MBitem))) + #add streamdetails + self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) + #### UPDATE THE MOVIE ##### else: pathsql="update movie SET c00 = ?, c01 = ?, c02 = ?, c05 = ?, c06 = ?, c07 = ?, c09 = ? c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?, c16 = ?, c18 = ?, c19 = ? WHERE idMovie = ?" @@ -501,6 +504,9 @@ class WriteKodiDB(): #create the reference in emby table pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum, parent_id) values(?, ?, ?, ?, ?)" cursor.execute(pathsql, (MBitem["Id"], episodeid, "episode", API().getChecksum(MBitem), showid)) + + #add streamdetails + self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) # UPDATE THE EPISODE IN KODI (for now, we just send in all data) else: @@ -850,7 +856,20 @@ class WriteKodiDB(): utils.logMsg("AddTagToMedia", "Processing : " + tag) sql="INSERT OR REPLACE into taglinks(idTag, idMedia, media_type) values(?, ?, ?)" cursor.execute(sql, (idTag, id, mediatype)) - + + def AddStreamDetailsToMedia(self, streamdetails, fileid, cursor): + + #first remove any existing entries + cursor.execute("delete FROM streamdetails WHERE idFile = ?", (fileid,)) + if streamdetails: + #video details + sql="insert into streamdetails(idFile, iStreamType, strVideoCodec, fVideoAspect, iVideoWidth, iVideoHeight) values(?, ?, ?, ?, ?, ?)" + cursor.execute(sql, (fileid,0,streamdetails.get("videocodec"),streamdetails.get("aspectratio"),streamdetails.get("width"),streamdetails.get("height"))) + #audio details + sql="insert into streamdetails(idFile, iStreamType, strAudioCodec, iAudioChannels) values(?, ?, ?, ?)" + cursor.execute(sql, (fileid,1,streamdetails.get("audiocodec"),streamdetails.get("channels"))) + + def addBoxsetToKodiLibrary(self, boxset, connection, cursor): strSet = boxset["Name"] From 6d191fef1d518ea823fd0bd9f0fd3884f1bba8b9 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 03:47:05 +0200 Subject: [PATCH 12/66] fixed some small issues --- resources/lib/LibrarySync.py | 29 +++++++++++++++-------------- resources/lib/WriteKodiDB.py | 19 ++++++++++++------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 114e00e2..11a3498e 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -49,11 +49,10 @@ class LibrarySync(): connection = utils.KodiSQL() cursor = connection.cursor() - #TEMP --> add new columns - try: + #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() - except: pass # sync movies self.MoviesSync(connection,cursor,True) @@ -89,6 +88,9 @@ class LibrarySync(): allMB3Movies = ReadEmbyDB().getMovies(view.get('id')) allKodiMovies = ReadKodiDB().getKodiMovies(connection, cursor) + + for kodimovie in allKodiMovies: + allKodiMovieIds.append(kodimovie[1]) #### PROCESS ADDS AND UPDATES ### for item in allMB3Movies: @@ -98,12 +100,10 @@ class LibrarySync(): kodiMovie = None for kodimovie in allKodiMovies: - allKodiMovieIds.append(kodimovie[1]) if kodimovie[1] == item["Id"]: kodiMovie = kodimovie if kodiMovie == None: - allKodiMovieIds.append(item["Id"]) WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) else: if kodiMovie[2] != API().getChecksum(item) or item["Id"] in itemList: @@ -128,11 +128,15 @@ class LibrarySync(): allKodiTvShowIds = list() allEmbyTvShowIds = list() - + for view in views: allEmbyTvShows = ReadEmbyDB().getTvShows(view.get('id')) allKodiTvShows = ReadKodiDB().getKodiTvShows(connection, cursor) + + for kodishow in allKodiTvShows: + allKodiTvShowIds.append(kodishow[1]) + #### TVSHOW: PROCESS ADDS AND UPDATES ### for item in allEmbyTvShows: @@ -143,13 +147,11 @@ class LibrarySync(): #build a list with all Id's and get the existing entry (if exists) in Kodi DB kodiShow = None for kodishow in allKodiTvShows: - allKodiTvShowIds.append(kodishow[1]) if kodishow[1] == item["Id"]: kodiShow = kodishow if kodiShow == None: # Tv show doesn't exist in Kodi yet so proceed and add it - allKodiTvShowIds.append(item["Id"]) kodiId = WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) else: kodiId = kodishow[0] @@ -180,22 +182,23 @@ class LibrarySync(): allEmbyEpisodes = ReadEmbyDB().getEpisodes(embyShowId) allKodiEpisodes = ReadKodiDB().getKodiEpisodes(connection, cursor, kodiShowId) + + for kodiepisode in allKodiEpisodes: + allKodiEpisodeIds.append(kodiepisode[1]) #### EPISODES: PROCESS ADDS AND UPDATES ### for item in allEmbyEpisodes: allEmbyEpisodeIds.append(item["Id"]) - #build a list with all Id's and get the existing entry (if exists) in Kodi DB + #get the existing entry (if exists) in Kodi DB kodiEpisode = None for kodiepisode in allKodiEpisodes: - allKodiEpisodeIds.append(kodiepisode[1]) if kodiepisode[1] == item["Id"]: kodiEpisode = kodiepisode if kodiEpisode == None: # Episode doesn't exist in Kodi yet so proceed and add it - allKodiEpisodeIds.append(item["Id"]) WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor) else: # If there are changes to the item, perform a full sync of the item @@ -204,10 +207,8 @@ class LibrarySync(): #### EPISODES: PROCESS DELETES ##### allEmbyEpisodeIds = set(allEmbyEpisodeIds) - print allEmbyEpisodeIds for kodiId in allKodiEpisodeIds: - print "kodiId-->" + kodiId - if not kodiId in allEmbyEpisodeIds: + if (not kodiId in allEmbyEpisodeIds): WINDOW.setProperty(kodiId,"deleted") WriteKodiDB().deleteEpisodeFromKodiLibrary(kodiId, connection, cursor) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 6e47a853..9580b7b0 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -26,17 +26,22 @@ class WriteKodiDB(): def updatePlayCountFromKodi(self, id, type, playcount=0): #when user marks item watched from kodi interface update this in MB3 - xbmc.sleep(sleepVal) - utils.logMsg("Emby", "updatePlayCountFromKodi Called") - mb3Id = ReadKodiDB().getEmbyIdByKodiId(id, type) + 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(mb3Id != None): + if(emby_id != None): addon = xbmcaddon.Addon(id='plugin.video.emby') downloadUtils = DownloadUtils() - - watchedurl = "{server}/mediabrowser/Users/{UserId}/PlayedItems/%s" % mb3Id + + #FIXME --> This is no longer working ??!! + watchedurl = "{server}/mediabrowser/Users/{UserId}/PlayedItems/%s" % emby_id utils.logMsg("Emby","watchedurl -->" + watchedurl) if playcount != 0: downloadUtils.downloadUrl(watchedurl, postBody="", type="POST") @@ -162,7 +167,7 @@ class WriteKodiDB(): #### UPDATE THE MOVIE ##### else: - pathsql="update movie SET c00 = ?, c01 = ?, c02 = ?, c05 = ?, c06 = ?, c07 = ?, c09 = ? c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?, c16 = ?, c18 = ?, c19 = ? WHERE idMovie = ?" + pathsql="update movie SET c00 = ?, c01 = ?, c02 = ?, c05 = ?, c06 = ?, c07 = ?, c09 = ?, c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?, c16 = ?, c18 = ?, c19 = ? WHERE idMovie = ?" cursor.execute(pathsql, (title, plot, shortplot, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio, trailerUrl, movieid)) #update the checksum in emby table From 2eac7bbcb485822f396344050a570aa395f817da Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 04:01:52 +0200 Subject: [PATCH 13/66] fixed updates from websocket --- resources/lib/DownloadUtils.py | 4 ++-- resources/lib/WebSocketClient.py | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py index 92410b2c..479da4d6 100644 --- a/resources/lib/DownloadUtils.py +++ b/resources/lib/DownloadUtils.py @@ -11,8 +11,8 @@ from ClientInformation import ClientInformation from requests.packages.urllib3.exceptions import InsecureRequestWarning # Disable requests logging -requests.packages.urllib3.disable_warnings(InsecureRequestWarning) -logging.getLogger("requests").setLevel(logging.WARNING) +# requests.packages.urllib3.disable_warnings(InsecureRequestWarning) +# logging.getLogger("requests").setLevel(logging.WARNING) class DownloadUtils(): diff --git a/resources/lib/WebSocketClient.py b/resources/lib/WebSocketClient.py index e09e105a..148d1658 100644 --- a/resources/lib/WebSocketClient.py +++ b/resources/lib/WebSocketClient.py @@ -180,12 +180,15 @@ class WebSocketThread(threading.Thread): def remove_items(self, itemsRemoved): for item in itemsRemoved: + connection = utils.KodiSQL() + cursor = connection.cursor() self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteEpisodeFromKodiLibraryByMbId: " + item, 0) - WriteKodiDB().deleteEpisodeFromKodiLibraryByMbId(item) + WriteKodiDB().deleteEpisodeFromKodiLibrary(item, connection, cursor) self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteMovieFromKodiLibrary: " + item, 0) - WriteKodiDB().deleteMovieFromKodiLibrary(item) + WriteKodiDB().deleteMovieFromKodiLibrary(item, connection, cursor) self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteMusicVideoFromKodiLibrary: " + item, 0) - WriteKodiDB().deleteMusicVideoFromKodiLibrary(item) + WriteKodiDB().deleteMusicVideoFromKodiLibrary(item, connection, cursor) + cursor.close() def update_items(self, itemsToUpdate): # doing adds and updates @@ -193,8 +196,8 @@ class WebSocketThread(threading.Thread): self.logMsg("Message : Doing LibraryChanged : Processing Added and Updated : " + str(itemsToUpdate), 0) connection = utils.KodiSQL() cursor = connection.cursor() - LibrarySync().MoviesSync(connection, cursor, fullsync = False, installFirstRun = False, itemList = itemsToUpdate) - LibrarySync().TvShowsSync(connection, cursor, fullsync = False, installFirstRun = False, itemList = itemsToUpdate) + LibrarySync().MoviesSync(connection, cursor, False, itemsToUpdate) + LibrarySync().TvShowsSync(connection, cursor, False, itemsToUpdate) cursor.close() def user_data_update(self, userDataList): From d93f5044b314f55fcd446342bc55a8c00192f0f0 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 11:56:31 +0200 Subject: [PATCH 14/66] cleaned sync code - added progress fixed background sync with websocket --- resources/lib/LibrarySync.py | 226 +++++++++++++------------------ resources/lib/ReadEmbyDB.py | 52 +++++-- resources/lib/WebSocketClient.py | 22 ++- resources/lib/WriteKodiDB.py | 48 +++---- service.py | 4 +- 5 files changed, 160 insertions(+), 192 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 11a3498e..b542d9b8 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -28,13 +28,19 @@ dataPath = os.path.join(addondir,"library") movieLibrary = os.path.join(dataPath,'movies') tvLibrary = os.path.join(dataPath,'tvshows') +WINDOW = xbmcgui.Window( 10000 ) + class LibrarySync(): - def syncDatabase(self): + def FullLibrarySync(self): + + #show the progress dialog + pDialog = xbmcgui.DialogProgressBG() + pDialog.create('Emby for Kodi', 'Performing full sync') #set some variable to check if this is the first run addon = xbmcaddon.Addon(id='plugin.video.emby') - WINDOW = xbmcgui.Window( 10000 ) + startupDone = WINDOW.getProperty("startup") == "done" syncInstallRunDone = addon.getSetting("SyncInstallRunDone") == "true" @@ -55,15 +61,20 @@ class LibrarySync(): connection.commit() # sync movies - self.MoviesSync(connection,cursor,True) + self.MoviesFullSync(connection,cursor,pDialog) #sync Tvshows and episodes - self.TvShowsSync(connection,cursor,True) + self.TvShowsFullSync(connection,cursor,pDialog) # set the install done setting if(syncInstallRunDone == False and completed): addon = xbmcaddon.Addon(id='plugin.video.emby') #force a new instance of the addon addon.setSetting("SyncInstallRunDone", "true") + # Force refresh the library + xbmc.executebuiltin("UpdateLibrary(video)") + xbmc.executebuiltin("Container.Refresh") + xbmc.executebuiltin("Container.Update") + # set prop to show we have run for the first time WINDOW.setProperty("startup", "done") @@ -71,14 +82,14 @@ class LibrarySync(): WINDOW.setProperty("SyncDatabaseRunning", "false") utils.logMsg("Sync DB", "syncDatabase Exiting", 0) cursor.close() - + + if(pDialog != None): + pDialog.close() + return True - def MoviesSync(self,connection,cursor,installFirstRun,itemList = []): - - pDialog = xbmcgui.DialogProgressBG() - pDialog.create('Sync DB', 'Sync Movies') - + def MoviesFullSync(self,connection,cursor, pDialog): + views = ReadEmbyDB().getCollections("movies") allKodiMovieIds = list() @@ -86,18 +97,26 @@ class LibrarySync(): for view in views: - allMB3Movies = ReadEmbyDB().getMovies(view.get('id')) + allEmbyMovies = ReadEmbyDB().getMovies(view.get('id')) allKodiMovies = ReadKodiDB().getKodiMovies(connection, cursor) for kodimovie in allKodiMovies: allKodiMovieIds.append(kodimovie[1]) - + + total = len(allEmbyMovies) + 1 + count = 1 + #### PROCESS ADDS AND UPDATES ### - for item in allMB3Movies: + for item in allEmbyMovies: if not item.get('IsFolder'): allEmbyMovieIds.append(item["Id"]) + if(pDialog != None): + progressTitle = "Processing " + view.get('title') + " (" + str(count) + " of " + str(total) + ")" + pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle) + count = 1 + kodiMovie = None for kodimovie in allKodiMovies: if kodimovie[1] == item["Id"]: @@ -106,7 +125,7 @@ class LibrarySync(): if kodiMovie == None: WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) else: - if kodiMovie[2] != API().getChecksum(item) or item["Id"] in itemList: + if kodiMovie[2] != API().getChecksum(item): WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) #### PROCESS DELETES ##### @@ -114,16 +133,11 @@ class LibrarySync(): for kodiId in allKodiMovieIds: if not kodiId in allEmbyMovieIds: WINDOW.setProperty(kodiId,"deleted") - WriteKodiDB().deleteMovieFromKodiLibrary(kodiId, connection, cursor) + WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) - if(pDialog != None): - pDialog.close() - def TvShowsSync(self,connection,cursor,installFirstRun,itemList = []): - - pDialog = xbmcgui.DialogProgressBG() - pDialog.create('Sync DB', 'Sync TV Shows') - + def TvShowsFullSync(self,connection,cursor,pDialog): + views = ReadEmbyDB().getCollections("tvshows") allKodiTvShowIds = list() @@ -134,6 +148,9 @@ class LibrarySync(): allEmbyTvShows = ReadEmbyDB().getTvShows(view.get('id')) allKodiTvShows = ReadKodiDB().getKodiTvShows(connection, cursor) + total = len(allEmbyTvShows) + 1 + count = 1 + for kodishow in allKodiTvShows: allKodiTvShowIds.append(kodishow[1]) @@ -144,6 +161,11 @@ class LibrarySync(): if item.get('IsFolder') and item.get('RecursiveItemCount') != 0: allEmbyTvShowIds.append(item["Id"]) + if(pDialog != None): + progressTitle = "Processing " + view.get('title') + " (" + str(count) + " of " + str(total) + ")" + pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle) + count = 1 + #build a list with all Id's and get the existing entry (if exists) in Kodi DB kodiShow = None for kodishow in allKodiTvShows: @@ -156,24 +178,21 @@ class LibrarySync(): else: kodiId = kodishow[0] # If there are changes to the item, perform a full sync of the item - if kodiShow[2] != API().getChecksum(item) or item["Id"] in itemList: + if kodiShow[2] != API().getChecksum(item): WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) #### PROCESS EPISODES ###### - self.EpisodesSync(connection,cursor,installFirstRun, item["Id"], kodiId, itemList) + self.EpisodesFullSync(connection,cursor,item["Id"], kodiId) #### TVSHOW: PROCESS DELETES ##### allEmbyTvShowIds = set(allEmbyTvShowIds) for kodiId in allKodiTvShowIds: if not kodiId in allEmbyTvShowIds: WINDOW.setProperty(kodiId,"deleted") - WriteKodiDB().deleteTvShowFromKodiLibrary(kodiId, connection, cursor) + WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) - if(pDialog != None): - pDialog.close() - - - def EpisodesSync(self,connection,cursor,installFirstRun, embyShowId, kodiShowId, itemList = []): + + def EpisodesFullSync(self,connection,cursor,embyShowId, kodiShowId): WINDOW = xbmcgui.Window( 10000 ) @@ -202,7 +221,7 @@ class LibrarySync(): WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor) else: # If there are changes to the item, perform a full sync of the item - if kodiEpisode[2] != API().getChecksum(item) or item["Id"] in itemList: + if kodiEpisode[2] != API().getChecksum(item): WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor) #### EPISODES: PROCESS DELETES ##### @@ -210,120 +229,58 @@ class LibrarySync(): for kodiId in allKodiEpisodeIds: if (not kodiId in allEmbyEpisodeIds): WINDOW.setProperty(kodiId,"deleted") - WriteKodiDB().deleteEpisodeFromKodiLibrary(kodiId, connection, cursor) - + WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) - def MusicVideosSync(self, fullsync, installFirstRun,connection, cursor): - - addon = xbmcaddon.Addon(id='plugin.video.emby') - WINDOW = xbmcgui.Window( 10000 ) - pDialog = None - - try: - dbSyncIndication = addon.getSetting("dbSyncIndication") - - if(installFirstRun or dbSyncIndication == "Dialog Progress"): - pDialog = xbmcgui.DialogProgress() - elif(dbSyncIndication == "BG Progress"): - pDialog = xbmcgui.DialogProgressBG() - - if(pDialog != None): - pDialog.create('Sync DB', 'Sync DB') - - allEmbyMusicVideoIds = list() - progressTitle = "" - - #process new musicvideos - allMB3MusicVideos = ReadEmbyDB().getMusicVideos(True, fullsync) - allKodiIds = set(ReadKodiDB().getKodiMusicVideoIds(True)) + def IncrementalSync(self, itemList): + #this will only perform sync for items received by the websocket - if(self.ShouldStop(pDialog)): - return False + pDialog = xbmcgui.DialogProgressBG() + pDialog.create('Emby for Kodi', 'Performing incremental sync...') - if(allMB3MusicVideos == None): - return False + connection = utils.KodiSQL() + cursor = connection.cursor() - if(pDialog != None): - progressTitle = "Sync DB : Processing Musicvideos" - pDialog.update(0, progressTitle) - total = len(allMB3MusicVideos) + 1 - count = 1 - - for item in allMB3MusicVideos: - - if not item.get('IsFolder'): - allEmbyMusicVideoIds.append(item["Id"]) + #### PROCESS MOVIES #### + views = ReadEmbyDB().getCollections("movies") + for view in views: + allEmbyMovies = ReadEmbyDB().getMovies(view.get('id'), itemList) + for item in allEmbyMovies: - if item["Id"] not in allKodiIds: - WriteKodiDB().addMusicVideoToKodiLibrary(item, connection, cursor) + if not item.get('IsFolder'): + WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) - if(self.ShouldStop(pDialog)): - return False - - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, "Adding Musicvideo: " + str(count)) - count += 1 - - if(self.ShouldStop(pDialog)): - return False - - if(pDialog != None): - progressTitle = "Sync DB : Processing musicvideos" - pDialog.update(0, progressTitle, "") - total = len(allMB3MusicVideos) + 1 - count = 1 - - #process updates - allKodiMusicVideos = ReadKodiDB().getKodiMusicVideos(True) - for item in allMB3MusicVideos: - - if not item.get('IsFolder'): + #### PROCESS TV SHOWS #### + views = ReadEmbyDB().getCollections("tvshows") + for view in views: + allEmbyTvShows = ReadEmbyDB().getTvShows(view.get('id'),itemList) + for item in allEmbyTvShows: + if item.get('IsFolder') and item.get('RecursiveItemCount') != 0: + kodiId = WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) - if allKodiMusicVideos != None: - kodimusicvideo = allKodiMusicVideos.get(item["Id"], None) - else: - kodimusicvideo = None - - if(kodimusicvideo != None): - WriteKodiDB().updateMusicVideoToKodiLibrary_Batched(item, kodimusicvideo) - - if(self.ShouldStop(pDialog)): - return False + #### PROCESS EPISODES ###### + for item in itemList: - # update progress bar - if(pDialog != None): - percentage = int(((float(count) / float(total)) * 100)) - pDialog.update(percentage, progressTitle, "Updating MusicVideo: " + str(count)) - count += 1 - + MBitem = ReadEmbyDB().getItem(item) + + if MBitem["Type"] == "Episode": - if(pDialog != None): - progressTitle = "Removing Deleted Items" - pDialog.update(0, progressTitle, "") - - if(self.ShouldStop(pDialog)): - return False - - # process any deletes only at fullsync - if fullsync: - allKodiIds = ReadKodiDB().getKodiMusicVideoIds(True) - allEmbyMusicVideoIds = set(allEmbyMusicVideoIds) - for kodiId in allKodiIds: - if not kodiId in allEmbyMusicVideoIds: - WriteKodiDB().deleteMusicVideoFromKodiLibrary(kodiId) - - if(self.ShouldStop(pDialog)): - return False - - finally: - if(pDialog != None): - pDialog.close() + #get the tv show + cursor.execute("SELECT kodi_id FROM emby WHERE media_type='tvshow' AND emby_id=?", (MBitem["SeriesId"],)) + result = cursor.fetchall() + if result: + kodi_show_id = result[0] + else: + kodi_show_id = None + + if kodi_show_id: + WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodi_show_id, connection, cursor) - return True - + + cursor.close() + if(pDialog != None): + pDialog.close() + def ShouldStop(self, prog): if(prog != None and type(prog) == xbmcgui.DialogProgress): @@ -333,7 +290,6 @@ class LibrarySync(): if(xbmc.Player().isPlaying() or xbmc.abortRequested): return True - WINDOW = xbmcgui.Window( 10000 ) if(WINDOW.getProperty("SyncDatabaseShouldStop") == "true"): return True diff --git a/resources/lib/ReadEmbyDB.py b/resources/lib/ReadEmbyDB.py index 23773820..3385e4ec 100644 --- a/resources/lib/ReadEmbyDB.py +++ b/resources/lib/ReadEmbyDB.py @@ -14,7 +14,7 @@ addon = xbmcaddon.Addon(id='plugin.video.emby') class ReadEmbyDB(): - def getMovies(self, id): + def getMovies(self, id, itemList = []): result = None doUtils = DownloadUtils() @@ -30,22 +30,24 @@ class ReadEmbyDB(): 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 getMusicVideos(self, fullinfo = False, fullSync = True): + def getMusicVideos(self, id, itemList = []): result = None doUtils = DownloadUtils() - if not fullSync: - sortstring = "&Limit=20&SortBy=DateCreated" - else: - sortstring = "&SortBy=SortName" - - if fullinfo: - url = "{server}/mediabrowser/Users/{UserId}/items?%s&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&format=json&ImageTypeLimit=1" % sortstring - else: - url = "{server}/mediabrowser/Users/{UserId}/items?%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % sortstring + #only get basic info for our sync-compares + sortstring = "&SortBy=SortName" + url = "{server}/mediabrowser/Users/{UserId}/items?%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % sortstring jsonData = doUtils.downloadUrl(url) if (jsonData == ""): @@ -53,6 +55,14 @@ class ReadEmbyDB(): 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 @@ -82,7 +92,7 @@ class ReadEmbyDB(): return result - def getTvShows(self, id): + def getTvShows(self, id, itemList = []): result = None doUtils = DownloadUtils() @@ -97,6 +107,14 @@ class ReadEmbyDB(): 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 @@ -116,7 +134,7 @@ class ReadEmbyDB(): return result - def getEpisodes(self, showId): + def getEpisodes(self, showId, itemList = []): result = None doUtils = DownloadUtils() @@ -129,6 +147,14 @@ class ReadEmbyDB(): 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 diff --git a/resources/lib/WebSocketClient.py b/resources/lib/WebSocketClient.py index 148d1658..72d513df 100644 --- a/resources/lib/WebSocketClient.py +++ b/resources/lib/WebSocketClient.py @@ -20,6 +20,7 @@ from DownloadUtils import DownloadUtils from PlaybackUtils import PlaybackUtils from LibrarySync import LibrarySync from WriteKodiDB import WriteKodiDB +from ReadEmbyDB import ReadEmbyDB pendingUserDataList = [] pendingItemsToRemove = [] @@ -183,31 +184,24 @@ class WebSocketThread(threading.Thread): connection = utils.KodiSQL() cursor = connection.cursor() self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteEpisodeFromKodiLibraryByMbId: " + item, 0) - WriteKodiDB().deleteEpisodeFromKodiLibrary(item, connection, cursor) - self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteMovieFromKodiLibrary: " + item, 0) - WriteKodiDB().deleteMovieFromKodiLibrary(item, connection, cursor) - self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteMusicVideoFromKodiLibrary: " + item, 0) - WriteKodiDB().deleteMusicVideoFromKodiLibrary(item, connection, cursor) + WriteKodiDB().deleteItemFromKodiLibrary(item, connection, cursor) cursor.close() def update_items(self, itemsToUpdate): # doing adds and updates if(len(itemsToUpdate) > 0): self.logMsg("Message : Doing LibraryChanged : Processing Added and Updated : " + str(itemsToUpdate), 0) - connection = utils.KodiSQL() - cursor = connection.cursor() - LibrarySync().MoviesSync(connection, cursor, False, itemsToUpdate) - LibrarySync().TvShowsSync(connection, cursor, False, itemsToUpdate) - cursor.close() + LibrarySync().IncrementalSync(itemsToUpdate) def user_data_update(self, userDataList): - + itemsToUpdate = list() for userData in userDataList: - self.logMsg("Message : Doing UserDataChanged : UserData : " + str(userData), 0) itemId = userData.get("ItemId") if(itemId != None): - self.logMsg("Message : Doing UserDataChanged : calling updatePlayCount with ID : " + str(itemId), 0) - LibrarySync().updatePlayCount(itemId) + itemsToUpdate.append(itemId) + if(len(itemsToUpdate) > 0): + self.logMsg("Message : Doing UserDataChanged : Processing Updated : " + str(itemsToUpdate), 0) + LibrarySync().IncrementalSync(itemsToUpdate) def on_error(self, ws, error): self.logMsg("Error : " + str(error)) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 9580b7b0..edf6dd6e 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -535,33 +535,27 @@ class WriteKodiDB(): #commit changes connection.commit() - def deleteMovieFromKodiLibrary(self, id, connection, cursor ): - utils.logMsg("deleting movie from Kodi library --> ",id) - cursor.execute("SELECT kodi_id FROM emby WHERE emby_id=?", (id,)) - kodi_id = cursor.fetchone()[0] - cursor.execute("DELETE FROM movie WHERE idMovie = ?", (kodi_id,)) - connection.commit() - - def deleteMusicVideoFromKodiLibrary(self, id ): - utils.logMsg("deleting musicvideo from Kodi library",id) - kodiItem = ReadKodiDB().getKodiMusicVideo(id) - if kodiItem != None: - xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.RemoveMusicVideo", "params": { "musicvideoid": %i}, "id": 1 }' %(kodiItem["musicvideoid"])) - - def deleteEpisodeFromKodiLibrary(self, id, connection, cursor ): - utils.logMsg("deleting episode from Kodi library --> ",id) - cursor.execute("SELECT kodi_id FROM emby WHERE emby_id=?", (id,)) - kodi_id = cursor.fetchone()[0] - cursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodi_id,)) - connection.commit() - - def deleteTVShowFromKodiLibrary(self, id, connection, cursor): - utils.logMsg("deleting tvshow from Kodi library --> ",id) - cursor.execute("SELECT kodi_id FROM emby WHERE emby_id=?", (id,)) - kodi_id = cursor.fetchone()[0] - cursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodi_id,)) - connection.commit() - + 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,)) + connection.commit() + def updateSeasons(self,embyTvShowId, kodiTvShowId, connection, cursor): seasonData = ReadEmbyDB().getTVShowSeasons(embyTvShowId) diff --git a/service.py b/service.py index 4c84511d..9baa934e 100644 --- a/service.py +++ b/service.py @@ -116,11 +116,9 @@ class Service(): #full sync if(startupComplete == False): self.logMsg("Doing_Db_Sync: syncDatabase (Started)") - libSync = librarySync.syncDatabase() + libSync = librarySync.FullLibrarySync() self.logMsg("Doing_Db_Sync: syncDatabase (Finished) " + str(libSync)) - # Force refresh newly set thumbnails - xbmc.executebuiltin("UpdateLibrary(video)") if(libSync): startupComplete = True else: From cabcdd5e90233df4b51f2deb7e553d77845a8b31 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 12:10:57 +0200 Subject: [PATCH 15/66] fixed some typos --- resources/lib/WriteKodiDB.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index edf6dd6e..04b92163 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -232,6 +232,11 @@ class WriteKodiDB(): studios = API().getStudios(MBitem) studio = " / ".join(studios) mpaa = MBitem.get("OfficialRating") + runtime = int(timeInfo.get('Duration'))*60 + plot = utils.convertEncoding(API().getOverview(MBitem)) + title = utils.convertEncoding(MBitem["Name"]) + sorttitle = utils.convertEncoding(MBitem["SortName"]) + rating = MBitem.get("CommunityRating") if MBitem.get("DateCreated") != None: dateadded = MBitem["DateCreated"].replace("T"," ") @@ -267,13 +272,6 @@ class WriteKodiDB(): tlpathid = tlpathid + 1 pathsql="insert into path(idPath, strPath, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" cursor.execute(pathsql, (tlpathid,toplevelpath,"tvshows","metadata.local",1)) - - - runtime = int(timeInfo.get('Duration'))*60 - plot = utils.convertEncoding(API().getOverview(MBitem)) - title = utils.convertEncoding(MBitem["Name"]) - sorttitle = utils.convertEncoding(MBitem["SortName"]) - rating = MBitem.get("CommunityRating") #create the tvshow cursor.execute("select coalesce(max(idShow),0) as showid from tvshow") @@ -296,7 +294,7 @@ class WriteKodiDB(): #### UPDATE THE TV SHOW ############# else: pathsql="UPDATE tvshow SET (c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?, c13 = ?, c14 = ?, c15 = ? WHERE idShow = ?" - cursor.execute(pathsql, title, plot, rating, premieredate, title, genre, mpaa, studio, sorttitle, showid) + cursor.execute(pathsql, (title, plot, rating, premieredate, title, genre, mpaa, studio, sorttitle, showid)) #update the checksum in emby table cursor.execute("UPDATE emby SET checksum = ? WHERE emby_id = ?", (API().getChecksum(MBitem), MBitem["Id"])) From 61c6fedc194fc5e8d89ffe54292388f6551b06bc Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 12:22:53 +0200 Subject: [PATCH 16/66] some more typos --- resources/lib/WriteKodiDB.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 04b92163..b50ba2c2 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -293,7 +293,7 @@ class WriteKodiDB(): #### UPDATE THE TV SHOW ############# else: - pathsql="UPDATE tvshow SET (c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?, c13 = ?, c14 = ?, c15 = ? WHERE idShow = ?" + pathsql="UPDATE tvshow SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?, c13 = ?, c14 = ?, c15 = ? WHERE idShow = ?" cursor.execute(pathsql, (title, plot, rating, premieredate, title, genre, mpaa, studio, sorttitle, showid)) #update the checksum in emby table From 8c6b90923e1a04e0c95ee79c77449d0cb96ad5e1 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 12:51:46 +0200 Subject: [PATCH 17/66] fixed some errors --- resources/lib/LibrarySync.py | 98 +++++++++++++++++++----------------- resources/lib/WriteKodiDB.py | 14 +++++- 2 files changed, 63 insertions(+), 49 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index b542d9b8..0baa13d8 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -64,6 +64,7 @@ class LibrarySync(): self.MoviesFullSync(connection,cursor,pDialog) #sync Tvshows and episodes self.TvShowsFullSync(connection,cursor,pDialog) + # set the install done setting if(syncInstallRunDone == False and completed): @@ -115,7 +116,7 @@ class LibrarySync(): if(pDialog != None): progressTitle = "Processing " + view.get('title') + " (" + str(count) + " of " + str(total) + ")" pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle) - count = 1 + count += 1 kodiMovie = None for kodimovie in allKodiMovies: @@ -128,12 +129,12 @@ class LibrarySync(): if kodiMovie[2] != API().getChecksum(item): WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) - #### PROCESS DELETES ##### - allEmbyMovieIds = set(allEmbyMovieIds) - for kodiId in allKodiMovieIds: - if not kodiId in allEmbyMovieIds: - WINDOW.setProperty(kodiId,"deleted") - WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) + #### PROCESS DELETES ##### + allEmbyMovieIds = set(allEmbyMovieIds) + for kodiId in allKodiMovieIds: + if not kodiId in allEmbyMovieIds: + WINDOW.setProperty(kodiId,"deleted") + WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) def TvShowsFullSync(self,connection,cursor,pDialog): @@ -164,7 +165,7 @@ class LibrarySync(): if(pDialog != None): progressTitle = "Processing " + view.get('title') + " (" + str(count) + " of " + str(total) + ")" pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle) - count = 1 + count += 1 #build a list with all Id's and get the existing entry (if exists) in Kodi DB kodiShow = None @@ -184,12 +185,12 @@ class LibrarySync(): #### PROCESS EPISODES ###### self.EpisodesFullSync(connection,cursor,item["Id"], kodiId) - #### TVSHOW: PROCESS DELETES ##### - allEmbyTvShowIds = set(allEmbyTvShowIds) - for kodiId in allKodiTvShowIds: - if not kodiId in allEmbyTvShowIds: - WINDOW.setProperty(kodiId,"deleted") - WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) + #### TVSHOW: PROCESS DELETES ##### + allEmbyTvShowIds = set(allEmbyTvShowIds) + for kodiId in allKodiTvShowIds: + if not kodiId in allEmbyTvShowIds: + WINDOW.setProperty(kodiId,"deleted") + WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) def EpisodesFullSync(self,connection,cursor,embyShowId, kodiShowId): @@ -241,43 +242,46 @@ class LibrarySync(): connection = utils.KodiSQL() cursor = connection.cursor() - #### PROCESS MOVIES #### - views = ReadEmbyDB().getCollections("movies") - for view in views: - allEmbyMovies = ReadEmbyDB().getMovies(view.get('id'), itemList) - for item in allEmbyMovies: + try: + #### PROCESS MOVIES #### + views = ReadEmbyDB().getCollections("movies") + for view in views: + allEmbyMovies = ReadEmbyDB().getMovies(view.get('id'), itemList) + for item in allEmbyMovies: + + if not item.get('IsFolder'): + WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + + #### PROCESS TV SHOWS #### + views = ReadEmbyDB().getCollections("tvshows") + for view in views: + allEmbyTvShows = ReadEmbyDB().getTvShows(view.get('id'),itemList) + for item in allEmbyTvShows: + if item.get('IsFolder') and item.get('RecursiveItemCount') != 0: + kodiId = WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + + #### PROCESS EPISODES ###### + for item in itemList: - if not item.get('IsFolder'): - WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + MBitem = ReadEmbyDB().getItem(item) + print MBitem + if MBitem["Type"] == "Episode": - #### PROCESS TV SHOWS #### - views = ReadEmbyDB().getCollections("tvshows") - for view in views: - allEmbyTvShows = ReadEmbyDB().getTvShows(view.get('id'),itemList) - for item in allEmbyTvShows: - if item.get('IsFolder') and item.get('RecursiveItemCount') != 0: - kodiId = WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + #get the tv show + cursor.execute("SELECT kodi_id FROM emby WHERE media_type='tvshow' AND emby_id=?", (MBitem["SeriesId"],)) + result = cursor.fetchall() + if result: + kodi_show_id = result[0] + else: + kodi_show_id = None + print "show id not found!" - #### PROCESS EPISODES ###### - for item in itemList: - - MBitem = ReadEmbyDB().getItem(item) - - if MBitem["Type"] == "Episode": - - #get the tv show - cursor.execute("SELECT kodi_id FROM emby WHERE media_type='tvshow' AND emby_id=?", (MBitem["SeriesId"],)) - result = cursor.fetchall() - if result: - kodi_show_id = result[0] - else: - kodi_show_id = None - - if kodi_show_id: - WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodi_show_id, connection, cursor) + if kodi_show_id: + WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodi_show_id, connection, cursor) + finally: + cursor.close() - - cursor.close() + #close the progress dialog if(pDialog != None): pDialog.close() diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index b50ba2c2..070f35e5 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -147,7 +147,10 @@ class WriteKodiDB(): ##### ADD THE MOVIE ############ - if movieid == None: + if movieid == None: + + utils.logMsg("ADD movie to Kodi library","Id: %s - Title: %s" % (embyId, title)) + #create the movie cursor.execute("select coalesce(max(idMovie),0) as movieid from movie") movieid = cursor.fetchone()[0] @@ -167,6 +170,7 @@ class WriteKodiDB(): #### UPDATE THE MOVIE ##### else: + utils.logMsg("UPDATE movie to Kodi library","Id: %s - Title: %s" % (embyId, title)) pathsql="update movie SET c00 = ?, c01 = ?, c02 = ?, c05 = ?, c06 = ?, c07 = ?, c09 = ?, c10 = ?, c11 = ?, c12 = ?, c14 = ?, c15 = ?, c16 = ?, c18 = ?, c19 = ? WHERE idMovie = ?" cursor.execute(pathsql, (title, plot, shortplot, rating, writer, year, imdb, sorttitle, runtime, mpaa, genre, director, title, studio, trailerUrl, movieid)) @@ -255,6 +259,8 @@ class WriteKodiDB(): #### ADD THE TV SHOW TO KODI ############## if showid == None: + utils.logMsg("ADD tvshow to Kodi library","Id: %s - Title: %s" % (embyId, title)) + #create the tv show path cursor.execute("select coalesce(max(idPath),0) as pathid from path") pathid = cursor.fetchone()[0] @@ -293,6 +299,8 @@ class WriteKodiDB(): #### UPDATE THE TV SHOW ############# else: + utils.logMsg("UPDATE tvshow to Kodi library","Id: %s - Title: %s" % (embyId, title)) + pathsql="UPDATE tvshow SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?, c13 = ?, c14 = ?, c15 = ? WHERE idShow = ?" cursor.execute(pathsql, (title, plot, rating, premieredate, title, genre, mpaa, studio, sorttitle, showid)) @@ -496,7 +504,7 @@ class WriteKodiDB(): # ADD EPISODE TO KODI if episodeid == None: - + utils.logMsg("ADD episode to Kodi library","Id: %s - Title: %s" % (embyId, title)) #create the episode cursor.execute("select coalesce(max(idEpisode),0) as episodeid from episode") episodeid = cursor.fetchone()[0] @@ -513,6 +521,8 @@ class WriteKodiDB(): # UPDATE THE EPISODE IN KODI (for now, we just send in all data) else: + utils.logMsg("UPDATE episode to Kodi library","Id: %s - Title: %s" % (embyId, title)) + pathsql = "UPDATE episode SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?, c10 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ? WHERE idEpisode = ?" cursor.execute(pathsql, (title, plot, rating, writer, premieredate, runtime, director, season, episode, title, "-1", "-1", episodeid)) From fc2f158ad07799b7cb99f010af88dcf7aecef169 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 13:47:04 +0200 Subject: [PATCH 18/66] fixed IncrementalSync typo --- resources/lib/LibrarySync.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 0baa13d8..7e356342 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -64,7 +64,6 @@ class LibrarySync(): self.MoviesFullSync(connection,cursor,pDialog) #sync Tvshows and episodes self.TvShowsFullSync(connection,cursor,pDialog) - # set the install done setting if(syncInstallRunDone == False and completed): @@ -264,22 +263,23 @@ class LibrarySync(): for item in itemList: MBitem = ReadEmbyDB().getItem(item) - print MBitem if MBitem["Type"] == "Episode": - + #get the tv show cursor.execute("SELECT kodi_id FROM emby WHERE media_type='tvshow' AND emby_id=?", (MBitem["SeriesId"],)) - result = cursor.fetchall() + result = cursor.fetchone() if result: kodi_show_id = result[0] else: kodi_show_id = None - print "show id not found!" - + if kodi_show_id: - WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodi_show_id, connection, cursor) + WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(MBitem["Id"], kodi_show_id, connection, cursor) finally: cursor.close() + xbmc.executebuiltin("UpdateLibrary(video)") + xbmc.executebuiltin("Container.Refresh") + xbmc.executebuiltin("Container.Update") #close the progress dialog if(pDialog != None): From 6e9983edba25107d4f344a673233e3fb3f8d54b5 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 14:02:31 +0200 Subject: [PATCH 19/66] added playcount to the sync --- resources/lib/WriteKodiDB.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 070f35e5..a852b022 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -112,7 +112,7 @@ class WriteKodiDB(): else: dateadded = None - playcount = None + playcount = 0 if userData.get("PlayCount") == "1": playcount = 1 @@ -144,7 +144,9 @@ class WriteKodiDB(): fileid = fileid + 1 pathsql="insert into files(idFile, idPath, strFilename, playCount, lastPlayed, dateAdded) values(?, ?, ?, ?, ?, ?)" cursor.execute(pathsql, (fileid,pathid,filename,playcount,userData.get("LastPlayedDate"),dateadded)) - + else: + pathsql="update files SET playCount = ?, lastPlayed = ? WHERE idFile = ?" + cursor.execute(pathsql, (playcount,userData.get("LastPlayedDate"), fileid)) ##### ADD THE MOVIE ############ if movieid == None: @@ -487,6 +489,9 @@ class WriteKodiDB(): fileid = fileid + 1 sql="INSERT OR REPLACE into files(idFile, idPath, strFilename, playCount, lastPlayed, dateAdded) values(?, ?, ?, ?, ?, ?)" cursor.execute(sql, (fileid,pathid,filename,playcount,lastplayed,dateadded)) + else: + pathsql="update files SET playCount = ?, lastPlayed = ? WHERE idFile = ?" + cursor.execute(pathsql, (playcount,userData.get("LastPlayedDate"), fileid)) # safety check: check season first season = 0 From a05bdeb8446672f3254fa8a915fa23189b180118 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 14:57:43 +0200 Subject: [PATCH 20/66] fixed issue with episode sync --- resources/lib/LibrarySync.py | 15 ++++++++++----- resources/lib/ReadKodiDB.py | 1 + resources/lib/WriteKodiDB.py | 5 ++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 7e356342..c53fdcc3 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -174,15 +174,14 @@ class LibrarySync(): if kodiShow == None: # Tv show doesn't exist in Kodi yet so proceed and add it - kodiId = WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) else: - kodiId = kodishow[0] # If there are changes to the item, perform a full sync of the item if kodiShow[2] != API().getChecksum(item): WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title')) #### PROCESS EPISODES ###### - self.EpisodesFullSync(connection,cursor,item["Id"], kodiId) + self.EpisodesFullSync(connection,cursor,item["Id"]) #### TVSHOW: PROCESS DELETES ##### allEmbyTvShowIds = set(allEmbyTvShowIds) @@ -192,14 +191,18 @@ class LibrarySync(): WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) - def EpisodesFullSync(self,connection,cursor,embyShowId, kodiShowId): + def EpisodesFullSync(self,connection,cursor,showId): WINDOW = xbmcgui.Window( 10000 ) allKodiEpisodeIds = list() allEmbyEpisodeIds = list() - allEmbyEpisodes = ReadEmbyDB().getEpisodes(embyShowId) + #get the kodi parent id + cursor.execute("SELECT kodi_id FROM emby WHERE emby_id=?",(showId,)) + kodiShowId = cursor.fetchone()[0] + + allEmbyEpisodes = ReadEmbyDB().getEpisodes(showId) allKodiEpisodes = ReadKodiDB().getKodiEpisodes(connection, cursor, kodiShowId) for kodiepisode in allKodiEpisodes: @@ -222,6 +225,8 @@ class LibrarySync(): else: # If there are changes to the item, perform a full sync of the item if kodiEpisode[2] != API().getChecksum(item): + print "previous checksum--> " + kodiEpisode[2] + print "new checksum--> " + API().getChecksum(item) WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor) #### EPISODES: PROCESS DELETES ##### diff --git a/resources/lib/ReadKodiDB.py b/resources/lib/ReadKodiDB.py index 9909f4f9..f0fc70ec 100644 --- a/resources/lib/ReadKodiDB.py +++ b/resources/lib/ReadKodiDB.py @@ -37,6 +37,7 @@ class ReadKodiDB(): cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type=?",("episode",)) else: cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type=? AND parent_id=?",("episode", showid)) + allepisodes = cursor.fetchall() #this will return a list with tuples of all items returned from the database return allepisodes diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index a852b022..7666a4c9 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -333,7 +333,6 @@ class WriteKodiDB(): #commit changes and return the id connection.commit() - return showid def addMusicVideoToKodiLibrary( self, MBitem, connection, cursor ): @@ -567,6 +566,10 @@ class WriteKodiDB(): 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,)) + connection.commit() def updateSeasons(self,embyTvShowId, kodiTvShowId, connection, cursor): From d489375ab2119953ab9b6b4b5e9cc02aebf0d057 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 15:59:48 +0200 Subject: [PATCH 21/66] fixed manual mark watched --- resources/lib/WriteKodiDB.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 7666a4c9..c047ab4b 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -39,12 +39,11 @@ class WriteKodiDB(): addon = xbmcaddon.Addon(id='plugin.video.emby') downloadUtils = DownloadUtils() - - #FIXME --> This is no longer working ??!! + watchedurl = "{server}/mediabrowser/Users/{UserId}/PlayedItems/%s" % emby_id utils.logMsg("Emby","watchedurl -->" + watchedurl) if playcount != 0: - downloadUtils.downloadUrl(watchedurl, postBody="", type="POST") + downloadUtils.downloadUrl(watchedurl, type="POST") else: downloadUtils.downloadUrl(watchedurl, type="DELETE") From e6784de347775baf1d65d936c59a309330aae910 Mon Sep 17 00:00:00 2001 From: im85288 Date: Sat, 2 May 2015 15:34:59 +0100 Subject: [PATCH 22/66] use the etag when available --- resources/lib/API.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/resources/lib/API.py b/resources/lib/API.py index 738eb48d..6f297024 100644 --- a/resources/lib/API.py +++ b/resources/lib/API.py @@ -120,19 +120,23 @@ class API(): } def getChecksum(self, item): - #TODO --> use the etags or serverside checksum for this - # for now we just add some fields to a string + # use the etags or serverside checksum for this if available + # else just add some fields to a string checksum = "" - userData = item.get("UserData") - if(userData != None): - checksum += str(userData.get("Played")) - checksum += str(userData.get("IsFavorite")) - if userData.get('UnplayedItemCount') != None: - checksum += str(userData.get("UnplayedItemCount")) - if userData.get('LastPlayedDate') != None: - checksum += str(userData.get("LastPlayedDate")) - if userData.get('PlaybackPositionTicks') != None: - checksum += str(userData.get("PlaybackPositionTicks")) + + if item.get("Etag") != None: + checksum = item.get("Etag") + else: + userData = item.get("UserData") + if(userData != None): + checksum += str(userData.get("Played")) + checksum += str(userData.get("IsFavorite")) + if userData.get('UnplayedItemCount') != None: + checksum += str(userData.get("UnplayedItemCount")) + if userData.get('LastPlayedDate') != None: + checksum += str(userData.get("LastPlayedDate")) + if userData.get('PlaybackPositionTicks') != None: + checksum += str(userData.get("PlaybackPositionTicks")) return checksum From 88b31ae5c4a5a2c31f79de4b73f0ffe4778eb0f3 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 16:49:47 +0200 Subject: [PATCH 23/66] fixed playback --- default.py | 4 ++- resources/lib/KodiMonitor.py | 45 ++++++---------------------------- resources/lib/PlaybackUtils.py | 17 ++++--------- resources/lib/Player.py | 4 +-- resources/lib/ReadKodiDB.py | 12 +++++++++ resources/lib/WriteKodiDB.py | 8 ++---- 6 files changed, 32 insertions(+), 58 deletions(-) diff --git a/default.py b/default.py index ef97285d..cc912b84 100644 --- a/default.py +++ b/default.py @@ -27,8 +27,10 @@ except: id=None if mode != None and mode == "play": + pass #PlaybackUtils().PLAY(id) - WINDOW.setProperty('GUIPLAY', str(id)) # set window prop + #WINDOW.setProperty('GUIPLAY', str(id)) # set window prop + #xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, None) elif sys.argv[1] == "reset": utils.reset() else: diff --git a/resources/lib/KodiMonitor.py b/resources/lib/KodiMonitor.py index 9accd533..7251e444 100644 --- a/resources/lib/KodiMonitor.py +++ b/resources/lib/KodiMonitor.py @@ -13,6 +13,7 @@ from WriteKodiDB import WriteKodiDB from ReadKodiDB import ReadKodiDB from PlayUtils import PlayUtils from DownloadUtils import DownloadUtils +from PlaybackUtils import PlaybackUtils class Kodi_Monitor(xbmc.Monitor): def __init__(self, *args, **kwargs): @@ -28,7 +29,7 @@ class Kodi_Monitor(xbmc.Monitor): downloadUtils = DownloadUtils() print "onNotification:" + method + ":" + sender + ":" + str(data) #player started playing an item - - if method == "Player.OnPlay": + if method == "Playlist.OnAdd": print "playlist onadd is called" jsondata = json.loads(data) if jsondata != None: @@ -37,7 +38,10 @@ class Kodi_Monitor(xbmc.Monitor): id = jsondata.get("item").get("id") type = jsondata.get("item").get("type") embyid = ReadKodiDB().getEmbyIdByKodiId(id,type) - + + print "id --> " + str(id) + print "type --> " + type + print "emby_id --> " + embyid if embyid != None: WINDOW = xbmcgui.Window( 10000 ) @@ -49,41 +53,8 @@ class Kodi_Monitor(xbmc.Monitor): url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % embyid result = downloadUtils.downloadUrl(url) - userData = result[u'UserData'] - - playurl = PlayUtils().getPlayUrl(server, embyid, result) - - watchedurl = "%s/mediabrowser/Users/%s/PlayedItems/%s" % (server, userid, embyid) - positionurl = "%s/mediabrowser/Users/%s/PlayingItems/%s" % (server, userid, embyid) - deleteurl = "%s/mediabrowser/Items/%s" % (server, embyid) - - # set the current playing info - WINDOW.setProperty(playurl+"watchedurl", watchedurl) - WINDOW.setProperty(playurl+"positionurl", positionurl) - WINDOW.setProperty(playurl+"deleteurl", "") - WINDOW.setProperty(playurl+"deleteurl", deleteurl) - if result[u'Type']=="Episode": - WINDOW.setProperty(playurl+"refresh_id", result[u'SeriesId']) - else: - WINDOW.setProperty(playurl+"refresh_id", embyid) - - WINDOW.setProperty(playurl+"runtimeticks", str(result[u'RunTimeTicks'])) - WINDOW.setProperty(playurl+"type", result[u'Type']) - WINDOW.setProperty(playurl+"item_id", embyid) - - if PlayUtils().isDirectPlay(result) == True: - playMethod = "DirectPlay" - else: - playMethod = "Transcode" - - WINDOW.setProperty(playurl+"playmethod", playMethod) - - mediaSources = result[u'MediaSources'] - if(mediaSources != None): - if mediaSources[0].get('DefaultAudioStreamIndex') != None: - WINDOW.setProperty(playurl+"AudioStreamIndex", str(mediaSources[0][u'DefaultAudioStreamIndex'])) - if mediaSources[0].get('DefaultSubtitleStreamIndex') != None: - WINDOW.setProperty(playurl+"SubtitleStreamIndex", str(mediaSources[0][u'DefaultSubtitleStreamIndex'])) + #launch playbackutils + PlaybackUtils().PLAY(result) if method == "VideoLibrary.OnUpdate": jsondata = json.loads(data) diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index 0447c415..7dd15e18 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -35,7 +35,7 @@ class PlaybackUtils(): def __init__(self, *args): pass - def PLAY(self, id): + def PLAY(self, result): xbmc.log("PLAY Called") WINDOW = xbmcgui.Window(10000) @@ -43,11 +43,9 @@ class PlaybackUtils(): userid = WINDOW.getProperty('userId%s' % username) server = WINDOW.getProperty('server%s' % username) - url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % id - result = self.downloadUtils.downloadUrl(url) - + id = result["Id"] - userData = result[u'UserData'] + userData = result['UserData'] resume_result = 0 seekTime = 0 @@ -134,13 +132,8 @@ class PlaybackUtils(): #this launches the playback #artwork only works with both resolvedurl and player command - if isStrmFile: - xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) - else: - #xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) - if(addon.getSetting("addExtraPlaybackArt") == "true"): - utils.logMsg("PLAY", "Doing second xbmc.Player().play to add extra art") - xbmc.Player().play(playurl,listItem) + #xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) + xbmc.Player().play(playurl,listItem) def setArt(self, list,name,path): if name=='thumb' or name=='fanart_image' or name=='small_poster' or name=='tiny_poster' or name == "medium_landscape" or name=='medium_poster' or name=='small_fanartimage' or name=='medium_fanartimage' or name=='fanart_noindicators': diff --git a/resources/lib/Player.py b/resources/lib/Player.py index e7526cb2..d1de762b 100644 --- a/resources/lib/Player.py +++ b/resources/lib/Player.py @@ -90,9 +90,9 @@ class Player( xbmc.Player ): self.logMsg("emby Service -> Percent Complete:" + str(percentComplete) + " Mark Played At:" + str(markPlayedAt)) self.stopPlayback(data) - if(refresh_id != None): + #if(refresh_id != None): #report updates playcount and resume status to Kodi and MB3 - librarySync.updatePlayCount(item_id) + #librarySync.updatePlayCount(item_id) self.played_information.clear() diff --git a/resources/lib/ReadKodiDB.py b/resources/lib/ReadKodiDB.py index f0fc70ec..65438303 100644 --- a/resources/lib/ReadKodiDB.py +++ b/resources/lib/ReadKodiDB.py @@ -42,3 +42,15 @@ class ReadKodiDB(): #this will return a list with tuples of all items returned from the database return allepisodes + def getEmbyIdByKodiId(self, id, type, connection=None, cursor=None): + if not connection: + connection = utils.KodiSQL() + cursor = connection.cursor() + cursor.execute("SELECT emby_id FROM emby WHERE media_type=? AND kodi_id=?",(type,id)) + result = cursor.fetchone() + if result: + return result[0] + else: + return None + + \ No newline at end of file diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index c047ab4b..9b8ff80b 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -25,7 +25,7 @@ sleepVal = 20 class WriteKodiDB(): def updatePlayCountFromKodi(self, id, type, playcount=0): - #when user marks item watched from kodi interface update this in MB3 + #when user marks item watched from kodi interface update this in Emby utils.logMsg("Emby", "updatePlayCountFromKodi Called") connection = utils.KodiSQL() @@ -37,11 +37,8 @@ class WriteKodiDB(): if(emby_id != None): addon = xbmcaddon.Addon(id='plugin.video.emby') - downloadUtils = DownloadUtils() - watchedurl = "{server}/mediabrowser/Users/{UserId}/PlayedItems/%s" % emby_id - utils.logMsg("Emby","watchedurl -->" + watchedurl) if playcount != 0: downloadUtils.downloadUrl(watchedurl, type="POST") else: @@ -882,8 +879,7 @@ class WriteKodiDB(): #audio details sql="insert into streamdetails(idFile, iStreamType, strAudioCodec, iAudioChannels) values(?, ?, ?, ?)" cursor.execute(sql, (fileid,1,streamdetails.get("audiocodec"),streamdetails.get("channels"))) - - + def addBoxsetToKodiLibrary(self, boxset, connection, cursor): strSet = boxset["Name"] From f6cd5c97444976385bf1ea9864c27d7b5768e037 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 17:49:29 +0200 Subject: [PATCH 24/66] changed playback a bit --- default.py | 6 ++-- resources/lib/DownloadUtils.py | 14 +++++---- resources/lib/KodiMonitor.py | 53 ++++++++++++++++++++++++++++++++-- resources/lib/PlaybackUtils.py | 18 +----------- service.py | 14 +++++++-- 5 files changed, 74 insertions(+), 31 deletions(-) diff --git a/default.py b/default.py index cc912b84..fdecf1a4 100644 --- a/default.py +++ b/default.py @@ -27,10 +27,8 @@ except: id=None if mode != None and mode == "play": - pass - #PlaybackUtils().PLAY(id) - #WINDOW.setProperty('GUIPLAY', str(id)) # set window prop - #xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, None) + xbmcplugin.endOfDirectory(int(sys.argv[1]),True,False,True) + WINDOW.setProperty('GUIPLAY', str(id)) # set window prop elif sys.argv[1] == "reset": utils.reset() else: diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py index 479da4d6..22165188 100644 --- a/resources/lib/DownloadUtils.py +++ b/resources/lib/DownloadUtils.py @@ -149,19 +149,23 @@ class DownloadUtils(): self.logMsg("=== ENTER downloadUrl ===", 2) - WINDOW = self.WINDOW + WINDOW = xbmcgui.Window( 10000 ) timeout = self.timeout default_link = "" + + username = WINDOW.getProperty('currUser') + userId = WINDOW.getProperty('userId%s' % username) + server = WINDOW.getProperty('server%s' % username) + url = url.replace("{server}", server, 1) + url = url.replace("{UserId}", userId, 1) + #url = "%s&api_key=%s" % (url, self.token) # If user is authenticated if (authenticate): # Get requests session s = self.s # Replace for the real values and append api_key - url = url.replace("{server}", self.server, 1) - url = url.replace("{UserId}", self.userId, 1) - #url = "%s&api_key=%s" % (url, self.token) - + self.logMsg("URL: %s" % url, 2) # Prepare request if type == "GET": diff --git a/resources/lib/KodiMonitor.py b/resources/lib/KodiMonitor.py index 7251e444..988bb1df 100644 --- a/resources/lib/KodiMonitor.py +++ b/resources/lib/KodiMonitor.py @@ -53,8 +53,57 @@ class Kodi_Monitor(xbmc.Monitor): url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % embyid result = downloadUtils.downloadUrl(url) - #launch playbackutils - PlaybackUtils().PLAY(result) + userData = result[u'UserData'] + + playurl = PlayUtils().getPlayUrl(server, embyid, result) + thumbPath = API().getArtwork(result, "Primary") + + watchedurl = "%s/mediabrowser/Users/%s/PlayedItems/%s" % (server, userid, embyid) + positionurl = "%s/mediabrowser/Users/%s/PlayingItems/%s" % (server, userid, embyid) + deleteurl = "%s/mediabrowser/Items/%s" % (server, embyid) + + listItem = xbmcgui.ListItem(path=playurl, iconImage=thumbPath, thumbnailImage=thumbPath) + self.setListItemProps(server, id, listItem, result) + + # Can not play virtual items + if (result.get("LocationType") == "Virtual"): + xbmcgui.Dialog().ok(self.language(30128), self.language(30129)) + + # set the current playing info + WINDOW.setProperty(playurl+"watchedurl", watchedurl) + WINDOW.setProperty(playurl+"positionurl", positionurl) + WINDOW.setProperty(playurl+"deleteurl", "") + WINDOW.setProperty(playurl+"deleteurl", deleteurl) + if result[u'Type']=="Episode": + WINDOW.setProperty(playurl+"refresh_id", result[u'SeriesId']) + else: + WINDOW.setProperty(playurl+"refresh_id", embyid) + + WINDOW.setProperty(playurl+"runtimeticks", str(result[u'RunTimeTicks'])) + WINDOW.setProperty(playurl+"type", result[u'Type']) + WINDOW.setProperty(playurl+"item_id", embyid) + + if PlayUtils().isDirectPlay(result) == True: + playMethod = "DirectPlay" + else: + playMethod = "Transcode" + + WINDOW.setProperty(playurl+"playmethod", playMethod) + + if result.get("Type")=="Episode": + WINDOW.setProperty(playurl+"refresh_id", result.get("SeriesId")) + else: + WINDOW.setProperty(playurl+"refresh_id", id) + + mediaSources = result[u'MediaSources'] + if(mediaSources != None): + if mediaSources[0].get('DefaultAudioStreamIndex') != None: + WINDOW.setProperty(playurl+"AudioStreamIndex", str(mediaSources[0][u'DefaultAudioStreamIndex'])) + if mediaSources[0].get('DefaultSubtitleStreamIndex') != None: + WINDOW.setProperty(playurl+"SubtitleStreamIndex", str(mediaSources[0][u'DefaultSubtitleStreamIndex'])) + + # start the playback + PlaybackUtils().PLAY(id) if method == "VideoLibrary.OnUpdate": jsondata = json.loads(data) diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index 7dd15e18..6ebf465e 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -62,22 +62,8 @@ class PlaybackUtils(): # seekTime = int(round(kodiItem['resume'].get("position"))) playurl = PlayUtils().getPlayUrl(server, id, result) - - isStrmFile = False thumbPath = API().getArtwork(result, "Primary") - #workaround for when the file to play is a strm file itself - if playurl.endswith(".strm"): - isStrmFile = True - tempPath = os.path.join(addondir,"library","temp.strm") - xbmcvfs.copy(playurl, tempPath) - sfile = open(tempPath, 'r') - playurl = sfile.readline() - sfile.close() - xbmcvfs.delete(tempPath) - WINDOW.setProperty("virtualstrm", id) - WINDOW.setProperty("virtualstrmtype", result.get("Type")) - listItem = xbmcgui.ListItem(path=playurl, iconImage=thumbPath, thumbnailImage=thumbPath) self.setListItemProps(server, id, listItem, result) @@ -130,9 +116,7 @@ class PlaybackUtils(): if mediaSources[0].get('DefaultSubtitleStreamIndex') != None: WINDOW.setProperty(playurl+"SubtitleStreamIndex", str(mediaSources[0].get('DefaultSubtitleStreamIndex'))) - #this launches the playback - #artwork only works with both resolvedurl and player command - #xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) + #launch the playback xbmc.Player().play(playurl,listItem) def setArt(self, list,name,path): diff --git a/service.py b/service.py index 9baa934e..c8f57a03 100644 --- a/service.py +++ b/service.py @@ -68,11 +68,19 @@ class Service(): if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. We should exit break - + + #detection that file needs to be playback if WINDOW.getProperty("GUIPLAY") != "": + downloadUtils = DownloadUtils() id = WINDOW.getProperty("GUIPLAY") WINDOW.setProperty("GUIPLAY", "") - PlaybackUtils().PLAY(id) + WINDOW = xbmcgui.Window( 10000 ) + username = WINDOW.getProperty('currUser') + userid = WINDOW.getProperty('userId%s' % username) + server = WINDOW.getProperty('server%s' % username) + url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % id + result = downloadUtils.downloadUrl(url) + PlaybackUtils().PLAY(result) if xbmc.Player().isPlaying(): try: @@ -122,7 +130,7 @@ class Service(): if(libSync): startupComplete = True else: - if self.KodiMonitor.waitForAbort(10): + if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. We should exit break WebSocketThread().processPendingActions() From ba5211dcb85168a829af5fc005bccef9cbd35fc9 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 18:04:32 +0200 Subject: [PATCH 25/66] fixed resume dialog --- resources/lib/KodiMonitor.py | 74 +--------------------------------- resources/lib/PlaybackUtils.py | 14 ++----- 2 files changed, 4 insertions(+), 84 deletions(-) diff --git a/resources/lib/KodiMonitor.py b/resources/lib/KodiMonitor.py index 988bb1df..42208475 100644 --- a/resources/lib/KodiMonitor.py +++ b/resources/lib/KodiMonitor.py @@ -31,79 +31,7 @@ class Kodi_Monitor(xbmc.Monitor): #player started playing an item - if method == "Playlist.OnAdd": print "playlist onadd is called" - jsondata = json.loads(data) - if jsondata != None: - if jsondata.has_key("item"): - if jsondata.get("item").has_key("id") and jsondata.get("item").has_key("type"): - id = jsondata.get("item").get("id") - type = jsondata.get("item").get("type") - embyid = ReadKodiDB().getEmbyIdByKodiId(id,type) - - print "id --> " + str(id) - print "type --> " + type - print "emby_id --> " + embyid - if embyid != None: - - WINDOW = xbmcgui.Window( 10000 ) - - username = WINDOW.getProperty('currUser') - userid = WINDOW.getProperty('userId%s' % username) - server = WINDOW.getProperty('server%s' % username) - - url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % embyid - result = downloadUtils.downloadUrl(url) - - userData = result[u'UserData'] - - playurl = PlayUtils().getPlayUrl(server, embyid, result) - thumbPath = API().getArtwork(result, "Primary") - - watchedurl = "%s/mediabrowser/Users/%s/PlayedItems/%s" % (server, userid, embyid) - positionurl = "%s/mediabrowser/Users/%s/PlayingItems/%s" % (server, userid, embyid) - deleteurl = "%s/mediabrowser/Items/%s" % (server, embyid) - - listItem = xbmcgui.ListItem(path=playurl, iconImage=thumbPath, thumbnailImage=thumbPath) - self.setListItemProps(server, id, listItem, result) - - # Can not play virtual items - if (result.get("LocationType") == "Virtual"): - xbmcgui.Dialog().ok(self.language(30128), self.language(30129)) - - # set the current playing info - WINDOW.setProperty(playurl+"watchedurl", watchedurl) - WINDOW.setProperty(playurl+"positionurl", positionurl) - WINDOW.setProperty(playurl+"deleteurl", "") - WINDOW.setProperty(playurl+"deleteurl", deleteurl) - if result[u'Type']=="Episode": - WINDOW.setProperty(playurl+"refresh_id", result[u'SeriesId']) - else: - WINDOW.setProperty(playurl+"refresh_id", embyid) - - WINDOW.setProperty(playurl+"runtimeticks", str(result[u'RunTimeTicks'])) - WINDOW.setProperty(playurl+"type", result[u'Type']) - WINDOW.setProperty(playurl+"item_id", embyid) - - if PlayUtils().isDirectPlay(result) == True: - playMethod = "DirectPlay" - else: - playMethod = "Transcode" - - WINDOW.setProperty(playurl+"playmethod", playMethod) - - if result.get("Type")=="Episode": - WINDOW.setProperty(playurl+"refresh_id", result.get("SeriesId")) - else: - WINDOW.setProperty(playurl+"refresh_id", id) - - mediaSources = result[u'MediaSources'] - if(mediaSources != None): - if mediaSources[0].get('DefaultAudioStreamIndex') != None: - WINDOW.setProperty(playurl+"AudioStreamIndex", str(mediaSources[0][u'DefaultAudioStreamIndex'])) - if mediaSources[0].get('DefaultSubtitleStreamIndex') != None: - WINDOW.setProperty(playurl+"SubtitleStreamIndex", str(mediaSources[0][u'DefaultSubtitleStreamIndex'])) - - # start the playback - PlaybackUtils().PLAY(id) + if method == "VideoLibrary.OnUpdate": jsondata = json.loads(data) diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index 6ebf465e..13b05629 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -49,17 +49,9 @@ class PlaybackUtils(): resume_result = 0 seekTime = 0 - #get the resume point from Kodi DB for a Movie - # kodiItem = ReadKodiDB().getKodiMovie(id) - # if kodiItem != None: - # seekTime = int(round(kodiItem['resume'].get("position"))) - # else: - # #get the resume point from Kodi DB for an episode - # episodeItem = ReadEmbyDB().getItem(id) - # if episodeItem != None and str(episodeItem["Type"]) == "Episode": - # kodiItem = ReadKodiDB().getKodiEpisodeByMbItem(id,episodeItem["SeriesId"]) - # if kodiItem != None: - # seekTime = int(round(kodiItem['resume'].get("position"))) + if userData.get("PlaybackPositionTicks") != 0: + reasonableTicks = int(userData.get("PlaybackPositionTicks")) / 1000 + seekTime = reasonableTicks / 10000 playurl = PlayUtils().getPlayUrl(server, id, result) thumbPath = API().getArtwork(result, "Primary") From bc09e570fd11c9a7d6bcfb693f22760c54a5921d Mon Sep 17 00:00:00 2001 From: im85288 Date: Sat, 2 May 2015 17:16:33 +0100 Subject: [PATCH 26/66] revert etag use as the API does not currently return the etag when getting a collection of items (eg all episodes of a tv show). --- resources/lib/API.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/resources/lib/API.py b/resources/lib/API.py index 6f297024..151963b8 100644 --- a/resources/lib/API.py +++ b/resources/lib/API.py @@ -124,19 +124,19 @@ class API(): # else just add some fields to a string checksum = "" - if item.get("Etag") != None: - checksum = item.get("Etag") - else: - userData = item.get("UserData") - if(userData != None): - checksum += str(userData.get("Played")) - checksum += str(userData.get("IsFavorite")) - if userData.get('UnplayedItemCount') != None: - checksum += str(userData.get("UnplayedItemCount")) - if userData.get('LastPlayedDate') != None: - checksum += str(userData.get("LastPlayedDate")) - if userData.get('PlaybackPositionTicks') != None: - checksum += str(userData.get("PlaybackPositionTicks")) + #if item.get("Etag") != None: + #checksum = item.get("Etag") + #else: + userData = item.get("UserData") + if(userData != None): + checksum += str(userData.get("Played")) + checksum += str(userData.get("IsFavorite")) + if userData.get('UnplayedItemCount') != None: + checksum += str(userData.get("UnplayedItemCount")) + if userData.get('LastPlayedDate') != None: + checksum += str(userData.get("LastPlayedDate")) + if userData.get('PlaybackPositionTicks') != None: + checksum += str(userData.get("PlaybackPositionTicks")) return checksum From 367b658a290e7c4fb0492b52cf07a92f0cd99367 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 18:36:06 +0200 Subject: [PATCH 27/66] some more changes to the playback --- default.py | 3 ++- resources/lib/Player.py | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/default.py b/default.py index fdecf1a4..3205abf2 100644 --- a/default.py +++ b/default.py @@ -27,7 +27,8 @@ except: id=None if mode != None and mode == "play": - xbmcplugin.endOfDirectory(int(sys.argv[1]),True,False,True) + listItem = xbmcgui.ListItem(path="") + xbmcplugin.setResolvedUrl (int(sys.argv[1]), True, listItem) WINDOW.setProperty('GUIPLAY', str(id)) # set window prop elif sys.argv[1] == "reset": utils.reset() diff --git a/resources/lib/Player.py b/resources/lib/Player.py index d1de762b..d82a86ef 100644 --- a/resources/lib/Player.py +++ b/resources/lib/Player.py @@ -204,7 +204,11 @@ class Player( xbmc.Player ): self.stopAll() if xbmcplayer.isPlaying(): - currentFile = xbmcplayer.getPlayingFile() + + currentFile = "" + try: + currentFile = xbmcplayer.getPlayingFile() + except: pass self.logMsg("onPlayBackStarted: %s" % currentFile, 0) # we may need to wait until the info is available From 3d77a9dd3ac7ee3b7dcbdee39ad53136cceaa029 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 19:49:39 +0200 Subject: [PATCH 28/66] fixed progress dialog and added shouldstop event --- resources/lib/LibrarySync.py | 57 +++++++++++++++++++++++------------- resources/settings.xml | 5 +--- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index c53fdcc3..1adc1b64 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -34,18 +34,21 @@ class LibrarySync(): def FullLibrarySync(self): - #show the progress dialog - pDialog = xbmcgui.DialogProgressBG() - pDialog.create('Emby for Kodi', 'Performing full sync') - #set some variable to check if this is the first run addon = xbmcaddon.Addon(id='plugin.video.emby') - startupDone = WINDOW.getProperty("startup") == "done" syncInstallRunDone = addon.getSetting("SyncInstallRunDone") == "true" + dbSyncIndication = addon.getSetting("dbSyncIndication") == "true" WINDOW.setProperty("SyncDatabaseRunning", "true") + + #show the progress dialog + pDialog = None + if (syncInstallRunDone == False or dbSyncIndication): + pDialog = xbmcgui.DialogProgressBG() + pDialog.create('Emby for Kodi', 'Performing full sync') + if(WINDOW.getProperty("SyncDatabaseShouldStop") == "true"): utils.logMsg("Sync Database", "Can not start SyncDatabaseShouldStop=True", 0) return True @@ -62,6 +65,10 @@ class LibrarySync(): # sync movies self.MoviesFullSync(connection,cursor,pDialog) + + if (self.ShouldStop()): + return False + #sync Tvshows and episodes self.TvShowsFullSync(connection,cursor,pDialog) @@ -72,8 +79,6 @@ class LibrarySync(): # Force refresh the library xbmc.executebuiltin("UpdateLibrary(video)") - xbmc.executebuiltin("Container.Refresh") - xbmc.executebuiltin("Container.Update") # set prop to show we have run for the first time WINDOW.setProperty("startup", "done") @@ -108,7 +113,10 @@ class LibrarySync(): #### PROCESS ADDS AND UPDATES ### for item in allEmbyMovies: - + + if (self.ShouldStop()): + return False + if not item.get('IsFolder'): allEmbyMovieIds.append(item["Id"]) @@ -157,7 +165,10 @@ class LibrarySync(): #### TVSHOW: PROCESS ADDS AND UPDATES ### for item in allEmbyTvShows: - + + if (self.ShouldStop()): + return False + if item.get('IsFolder') and item.get('RecursiveItemCount') != 0: allEmbyTvShowIds.append(item["Id"]) @@ -210,7 +221,10 @@ class LibrarySync(): #### EPISODES: PROCESS ADDS AND UPDATES ### for item in allEmbyEpisodes: - + + if (self.ShouldStop()): + return False + allEmbyEpisodeIds.append(item["Id"]) #get the existing entry (if exists) in Kodi DB @@ -239,9 +253,15 @@ class LibrarySync(): def IncrementalSync(self, itemList): #this will only perform sync for items received by the websocket + addon = xbmcaddon.Addon(id='plugin.video.emby') + dbSyncIndication = addon.getSetting("dbSyncIndication") == "true" + WINDOW.setProperty("SyncDatabaseRunning", "true") - pDialog = xbmcgui.DialogProgressBG() - pDialog.create('Emby for Kodi', 'Performing incremental sync...') + #show the progress dialog + pDialog = None + if (dbSyncIndication): + pDialog = xbmcgui.DialogProgressBG() + pDialog.create('Emby for Kodi', 'Performing incremental sync...') connection = utils.KodiSQL() cursor = connection.cursor() @@ -283,20 +303,15 @@ class LibrarySync(): finally: cursor.close() xbmc.executebuiltin("UpdateLibrary(video)") - xbmc.executebuiltin("Container.Refresh") - xbmc.executebuiltin("Container.Update") + WINDOW.setProperty("SyncDatabaseRunning", "false") #close the progress dialog if(pDialog != None): pDialog.close() - def ShouldStop(self, prog): - - if(prog != None and type(prog) == xbmcgui.DialogProgress): - if(prog.iscanceled() == True): - return True - - if(xbmc.Player().isPlaying() or xbmc.abortRequested): + def ShouldStop(self): + + if(xbmc.abortRequested): return True if(WINDOW.getProperty("SyncDatabaseShouldStop") == "true"): diff --git a/resources/settings.xml b/resources/settings.xml index ff9d43aa..58975d29 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -12,12 +12,9 @@ - - - - + From 96e50a3d1e74d341760b13356465db1aa4c73194 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 22:02:06 +0200 Subject: [PATCH 29/66] added musicvideo supporr --- resources/lib/LibrarySync.py | 66 ++++++++++++++-- resources/lib/ReadEmbyDB.py | 2 +- resources/lib/ReadKodiDB.py | 9 ++- resources/lib/WriteKodiDB.py | 145 +++++++++++++++++++++++++++++++++-- 4 files changed, 209 insertions(+), 13 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 1adc1b64..37f43533 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -67,11 +67,17 @@ class LibrarySync(): self.MoviesFullSync(connection,cursor,pDialog) if (self.ShouldStop()): - return False + return False #sync Tvshows and episodes self.TvShowsFullSync(connection,cursor,pDialog) - + + if (self.ShouldStop()): + return False + + # sync musicvideos + self.MusicVideosFullSync(connection,cursor,pDialog) + # set the install done setting if(syncInstallRunDone == False and completed): addon = xbmcaddon.Addon(id='plugin.video.emby') #force a new instance of the addon @@ -143,7 +149,52 @@ class LibrarySync(): WINDOW.setProperty(kodiId,"deleted") WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) - + def MusicVideosFullSync(self,connection,cursor, pDialog): + + allKodiMusicvideoIds = list() + allEmbyMusicvideoIds = list() + + allEmbyMusicvideos = ReadEmbyDB().getMusicVideos() + allKodiMusicvideos = ReadKodiDB().getKodiMusicVideos(connection, cursor) + + for kodivideo in allKodiMusicvideos: + allKodiMusicvideoIds.append(kodivideo[1]) + + total = len(allEmbyMusicvideos) + 1 + count = 1 + + #### PROCESS ADDS AND UPDATES ### + for item in allEmbyMusicvideos: + + if (self.ShouldStop()): + return False + + if not item.get('IsFolder'): + allEmbyMusicvideoIds.append(item["Id"]) + + if(pDialog != None): + progressTitle = "Processing MusicVideos (" + str(count) + " of " + str(total) + ")" + pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle) + count += 1 + + kodiVideo = None + for kodivideo in allKodiMusicvideos: + if kodivideo[1] == item["Id"]: + kodiVideo = kodivideo + + if kodiVideo == None: + WriteKodiDB().addOrUpdateMusicVideoToKodiLibrary(item["Id"],connection, cursor) + else: + if kodiVideo[2] != API().getChecksum(item): + WriteKodiDB().addOrUpdateMusicVideoToKodiLibrary(item["Id"],connection, cursor) + + #### PROCESS DELETES ##### + allEmbyMusicvideoIds = set(allEmbyMusicvideoIds) + for kodiId in allKodiMusicvideoIds: + if not kodiId in allEmbyMusicvideoIds: + WINDOW.setProperty(kodiId,"deleted") + WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) + def TvShowsFullSync(self,connection,cursor,pDialog): views = ReadEmbyDB().getCollections("tvshows") @@ -200,7 +251,6 @@ class LibrarySync(): if not kodiId in allEmbyTvShowIds: WINDOW.setProperty(kodiId,"deleted") WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) - def EpisodesFullSync(self,connection,cursor,showId): @@ -250,7 +300,6 @@ class LibrarySync(): WINDOW.setProperty(kodiId,"deleted") WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) - def IncrementalSync(self, itemList): #this will only perform sync for items received by the websocket addon = xbmcaddon.Addon(id='plugin.video.emby') @@ -300,6 +349,13 @@ class LibrarySync(): if kodi_show_id: WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(MBitem["Id"], kodi_show_id, connection, cursor) + + #### PROCESS MUSICVIDEOS #### + allEmbyMusicvideos = ReadEmbyDB().getMusicVideos(itemList) + for item in allEmbyMusicvideos: + if not item.get('IsFolder'): + WriteKodiDB().addOrUpdateMusicVideoToKodiLibrary(item["Id"],connection, cursor) + finally: cursor.close() xbmc.executebuiltin("UpdateLibrary(video)") diff --git a/resources/lib/ReadEmbyDB.py b/resources/lib/ReadEmbyDB.py index 3385e4ec..c2817115 100644 --- a/resources/lib/ReadEmbyDB.py +++ b/resources/lib/ReadEmbyDB.py @@ -40,7 +40,7 @@ class ReadEmbyDB(): return result - def getMusicVideos(self, id, itemList = []): + def getMusicVideos(self, itemList = []): result = None doUtils = DownloadUtils() diff --git a/resources/lib/ReadKodiDB.py b/resources/lib/ReadKodiDB.py index 65438303..14c8c53a 100644 --- a/resources/lib/ReadKodiDB.py +++ b/resources/lib/ReadKodiDB.py @@ -24,7 +24,14 @@ class ReadKodiDB(): allmovies = cursor.fetchall() #this will return a list with tuples of all items returned from the database return allmovies - + + def getKodiMusicVideos(self, connection, cursor): + #returns all musicvideos in Kodi db + cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='musicvideo'") + allvideos = cursor.fetchall() + #this will return a list with tuples of all items returned from the database + return allvideos + def getKodiTvShows(self, connection, cursor): cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='tvshow'") allshows = cursor.fetchall() diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 9b8ff80b..153826bb 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -203,6 +203,142 @@ class WriteKodiDB(): connection.commit() return movieid + def addOrUpdateMusicVideoToKodiLibrary( 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: + idMVideo = result[0] + else: + idMVideo = None + + timeInfo = API().getTimeInfo(MBitem) + userData=API().getUserData(MBitem) + people = API().getPeople(MBitem) + + #### The video details ######### + runtime = int(timeInfo.get('Duration'))*60 + plot = utils.convertEncoding(API().getOverview(MBitem)) + title = utils.convertEncoding(MBitem["Name"]) + year = MBitem.get("ProductionYear") + genres = MBitem.get("Genres") + genre = " / ".join(genres) + studios = API().getStudios(MBitem) + studio = " / ".join(studios) + director = " / ".join(people.get("Director")) + artist = MBitem.get("Artist") + album = MBitem.get("Album") + track = MBitem.get("Track") + + if MBitem.get("DateCreated") != None: + dateadded = MBitem["DateCreated"].replace("T"," ") + dateadded = dateadded.replace(".0000000Z","") + else: + dateadded = None + + playcount = 0 + if userData.get("PlayCount") == "1": + playcount = 1 + + #### ADD OR UPDATE THE FILE AND PATH ########### + #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY + path = "plugin://plugin.video.emby/musicvideos/" + filename = "plugin://plugin.video.emby/musicvideos/?id=%s&mode=play" % MBitem["Id"] + + #create 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, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" + cursor.execute(pathsql, (pathid,path,"musicvideos","metadata.local",1)) + + #create the file if not exists + cursor.execute("SELECT idFile as fileid FROM files WHERE strFilename = ? and idPath = ?",(filename,pathid,)) + result = cursor.fetchone() + if result != None: + fileid = result[0] + if result == None: + cursor.execute("select coalesce(max(idFile),0) as fileid from files") + fileid = cursor.fetchone()[0] + fileid = fileid + 1 + pathsql="insert into files(idFile, idPath, strFilename, playCount, lastPlayed, dateAdded) values(?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (fileid,pathid,filename,playcount,userData.get("LastPlayedDate"),dateadded)) + else: + pathsql="update files SET playCount = ?, lastPlayed = ? WHERE idFile = ?" + cursor.execute(pathsql, (playcount,userData.get("LastPlayedDate"), fileid)) + + ##### ADD THE VIDEO ############ + if idMVideo == None: + + utils.logMsg("ADD musicvideo to Kodi library","Id: %s - Title: %s" % (embyId, title)) + + #create the video + cursor.execute("select coalesce(max(idMVideo),0) as idMVideo from musicvideo") + idMVideo = cursor.fetchone()[0] + idMVideo = idMVideo + 1 + pathsql="insert into musicvideo(idMVideo, idFile, c00, c04, c05, c06, c07, c08, c09, c10, c11, c12) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + cursor.execute(pathsql, (idMVideo, fileid, title, runtime, director, studio, year, plot, album, artist, genre, track)) + + #create the reference in emby table + pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)" + cursor.execute(pathsql, (MBitem["Id"], idMVideo, "musicvideo", API().getChecksum(MBitem))) + + #add streamdetails + self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) + + #### UPDATE THE VIDEO ##### + else: + utils.logMsg("UPDATE musicvideo to Kodi library","Id: %s - Title: %s" % (embyId, title)) + pathsql="update musicvideo SET c00 = ?, c04 = ?, c05 = ?, c06 = ?, c07 = ?, c08 = ?, c09 = ?, c10 = ?, c11 = ?, c12 = ? WHERE idMVideo = ?" + cursor.execute(pathsql, (title, runtime, director, studio, year, plot, album, artist, genre, track, idMVideo)) + + #update the checksum in emby table + cursor.execute("UPDATE emby SET checksum = ? WHERE emby_id = ?", (API().getChecksum(MBitem),MBitem["Id"])) + + #update or insert actors + self.AddPeopleToMedia(idMVideo,MBitem.get("People"),"musicvideo", connection, cursor) + + #update artwork + self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), idMVideo, "musicvideo", "thumb", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), idMVideo, "musicvideo", "poster", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Banner"), idMVideo, "musicvideo", "banner", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Logo"), idMVideo, "musicvideo", "clearlogo", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Art"), idMVideo, "musicvideo", "clearart", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Thumb"), idMVideo, "musicvideo", "landscape", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Disc"), idMVideo, "musicvideo", "discart", cursor) + self.addOrUpdateArt(API().getArtwork(MBitem, "Backdrop"), idMVideo, "musicvideo", "fanart", cursor) + + #update genres + self.AddGenresToMedia(idMVideo, genres, "musicvideo", cursor) + + #update studios + self.AddStudiosToMedia(idMVideo, studios, "musicvideo", cursor) + + #set resume point + resume = int(round(float(timeInfo.get("ResumeTime"))))*60 + total = int(round(float(timeInfo.get("TotalTime"))))*60 + self.setKodiResumePoint(fileid, resume, total, cursor) + + #commit changes and return the id + connection.commit() + def addOrUpdateTvShowToKodiLibrary( self, embyId, connection, cursor, viewTag ): addon = xbmcaddon.Addon(id='plugin.video.emby') @@ -739,9 +875,9 @@ class WriteKodiDB(): genre_id = genre_id + 1 sql="insert into genre(genre_id, name) values(?, ?)" cursor.execute(sql, (genre_id,genre)) + utils.logMsg("AddGenresToMedia", "Processing : " + genre) #assign genre to item - utils.logMsg("AddGenresToMedia", "Processing : " + genre) sql="INSERT OR REPLACE into genre_link(genre_id, media_id, media_type) values(?, ?, ?)" cursor.execute(sql, (genre_id, id, mediatype)) @@ -760,7 +896,6 @@ class WriteKodiDB(): cursor.execute(sql, (idGenre,genre)) #assign genre to item - utils.logMsg("AddGenresToMedia", "Processing : " + genre) if mediatype == "movie": sql="INSERT OR REPLACE into genrelinkmovie(idGenre, idMovie) values(?, ?)" if mediatype == "tvshow": @@ -792,9 +927,9 @@ class WriteKodiDB(): studio_id = studio_id + 1 sql="insert into studio(studio_id, name) values(?, ?)" cursor.execute(sql, (studio_id,studio)) + utils.logMsg("AddstudiosToMedia", "Processing : " + studio) #assign studio to item - utils.logMsg("AddstudiosToMedia", "Processing : " + studio) sql="INSERT OR REPLACE into studio_link(studio_id, media_id, media_type) values(?, ?, ?)" cursor.execute(sql, (studio_id, id, mediatype)) @@ -813,7 +948,6 @@ class WriteKodiDB(): cursor.execute(sql, (idstudio,studio)) #assign studio to item - utils.logMsg("AddstudiosToMedia", "Processing : " + studio) if mediatype == "movie": sql="INSERT OR REPLACE into studiolinkmovie(idstudio, idMovie) values(?, ?)" if mediatype == "tvshow": @@ -843,9 +977,9 @@ class WriteKodiDB(): tag_id = tag_id + 1 sql="insert into tag(tag_id, name) values(?, ?)" cursor.execute(sql, (tag_id,tag)) + utils.logMsg("AddTagToMedia", "Adding tag: " + tag) #assign tag to item - utils.logMsg("AddTagToMedia", "Processing : " + tag) sql="INSERT OR REPLACE into tag_link(tag_id, media_id, media_type) values(?, ?, ?)" cursor.execute(sql, (tag_id, id, mediatype)) @@ -864,7 +998,6 @@ class WriteKodiDB(): cursor.execute(sql, (idTag,tag)) #assign tag to item - utils.logMsg("AddTagToMedia", "Processing : " + tag) sql="INSERT OR REPLACE into taglinks(idTag, idMedia, media_type) values(?, ?, ?)" cursor.execute(sql, (idTag, id, mediatype)) From e637af1b78906e2c7c598a81406c0c42a7fd4571 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 22:25:08 +0200 Subject: [PATCH 30/66] small fixes for musicvideo support --- resources/lib/WriteKodiDB.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 153826bb..8079c8d8 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -213,7 +213,7 @@ class WriteKodiDB(): 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 @@ -238,7 +238,7 @@ class WriteKodiDB(): studios = API().getStudios(MBitem) studio = " / ".join(studios) director = " / ".join(people.get("Director")) - artist = MBitem.get("Artist") + artist = " / ".join(MBitem.get("Artists")) album = MBitem.get("Album") track = MBitem.get("Track") @@ -901,7 +901,9 @@ class WriteKodiDB(): if mediatype == "tvshow": sql="INSERT OR REPLACE into genrelinktvshow(idGenre, idShow) values(?, ?)" if mediatype == "episode": - sql="INSERT OR REPLACE into genrelinkepisode(idGenre, idEpisode) values(?, ?)" + return + if mediatype == "musicvideo": + sql="INSERT OR REPLACE into genrelinkmusicvideo(idGenre, idMVideo) values(?, ?)" cursor.execute(sql, (idGenre,id)) def AddStudiosToMedia(self, id, studios, mediatype, cursor): From 02dbb3222712eb575be080c7503bc7b01e731214 Mon Sep 17 00:00:00 2001 From: xnappo Date: Sat, 2 May 2015 15:34:55 -0500 Subject: [PATCH 31/66] Minor fix for TV shows progress Count was wrong due to empty shows. --- resources/lib/LibrarySync.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 37f43533..4d67237e 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -220,14 +220,14 @@ class LibrarySync(): if (self.ShouldStop()): return False + if(pDialog != None): + progressTitle = "Processing " + view.get('title') + " (" + str(count) + " of " + str(total) + ")" + pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle) + count += 1 + if item.get('IsFolder') and item.get('RecursiveItemCount') != 0: allEmbyTvShowIds.append(item["Id"]) - if(pDialog != None): - progressTitle = "Processing " + view.get('title') + " (" + str(count) + " of " + str(total) + ")" - pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle) - count += 1 - #build a list with all Id's and get the existing entry (if exists) in Kodi DB kodiShow = None for kodishow in allKodiTvShows: From 383fb37ca3c4348ce4908e3ed1f7fe082f3470d6 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 2 May 2015 22:46:12 +0200 Subject: [PATCH 32/66] perform all database commits at once instead of 1 by 1 --- resources/lib/LibrarySync.py | 16 +++++++++++++++- resources/lib/WebSocketClient.py | 7 ++++--- resources/lib/WriteKodiDB.py | 21 --------------------- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 37f43533..645b4775 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -83,7 +83,7 @@ class LibrarySync(): addon = xbmcaddon.Addon(id='plugin.video.emby') #force a new instance of the addon addon.setSetting("SyncInstallRunDone", "true") - # Force refresh the library + # Commit all DB changes at once and Force refresh the library xbmc.executebuiltin("UpdateLibrary(video)") # set prop to show we have run for the first time @@ -92,6 +92,7 @@ class LibrarySync(): finally: WINDOW.setProperty("SyncDatabaseRunning", "false") utils.logMsg("Sync DB", "syncDatabase Exiting", 0) + cursor.close() if(pDialog != None): @@ -148,6 +149,9 @@ class LibrarySync(): if not kodiId in allEmbyMovieIds: WINDOW.setProperty(kodiId,"deleted") WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) + + ### commit all changes to database ### + connection.commit() def MusicVideosFullSync(self,connection,cursor, pDialog): @@ -194,6 +198,9 @@ class LibrarySync(): if not kodiId in allEmbyMusicvideoIds: WINDOW.setProperty(kodiId,"deleted") WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) + + ### commit all changes to database ### + connection.commit() def TvShowsFullSync(self,connection,cursor,pDialog): @@ -251,6 +258,9 @@ class LibrarySync(): if not kodiId in allEmbyTvShowIds: WINDOW.setProperty(kodiId,"deleted") WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) + + ### commit all changes to database ### + connection.commit() def EpisodesFullSync(self,connection,cursor,showId): @@ -299,6 +309,7 @@ class LibrarySync(): if (not kodiId in allEmbyEpisodeIds): WINDOW.setProperty(kodiId,"deleted") WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor) + def IncrementalSync(self, itemList): #this will only perform sync for items received by the websocket @@ -355,6 +366,9 @@ class LibrarySync(): for item in allEmbyMusicvideos: if not item.get('IsFolder'): WriteKodiDB().addOrUpdateMusicVideoToKodiLibrary(item["Id"],connection, cursor) + + ### commit all changes to database ### + connection.commit() finally: cursor.close() diff --git a/resources/lib/WebSocketClient.py b/resources/lib/WebSocketClient.py index 72d513df..cb0308b3 100644 --- a/resources/lib/WebSocketClient.py +++ b/resources/lib/WebSocketClient.py @@ -180,12 +180,13 @@ class WebSocketThread(threading.Thread): self.update_items(itemsToUpdate) def remove_items(self, itemsRemoved): + connection = utils.KodiSQL() + cursor = connection.cursor() for item in itemsRemoved: - connection = utils.KodiSQL() - cursor = connection.cursor() self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteEpisodeFromKodiLibraryByMbId: " + item, 0) WriteKodiDB().deleteItemFromKodiLibrary(item, connection, cursor) - cursor.close() + connection.commit() + cursor.close() def update_items(self, itemsToUpdate): # doing adds and updates diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 8079c8d8..eaa402e3 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -199,9 +199,6 @@ class WriteKodiDB(): total = int(round(float(timeInfo.get("TotalTime"))))*60 self.setKodiResumePoint(fileid, resume, total, cursor) - #commit changes and return the id - connection.commit() - return movieid def addOrUpdateMusicVideoToKodiLibrary( self, embyId ,connection, cursor): @@ -335,9 +332,6 @@ class WriteKodiDB(): resume = int(round(float(timeInfo.get("ResumeTime"))))*60 total = int(round(float(timeInfo.get("TotalTime"))))*60 self.setKodiResumePoint(fileid, resume, total, cursor) - - #commit changes and return the id - connection.commit() def addOrUpdateTvShowToKodiLibrary( self, embyId, connection, cursor, viewTag ): @@ -463,8 +457,6 @@ class WriteKodiDB(): #update season details self.updateSeasons(MBitem["Id"], showid, connection, cursor) - #commit changes and return the id - connection.commit() def addMusicVideoToKodiLibrary( self, MBitem, connection, cursor ): @@ -530,12 +522,6 @@ class WriteKodiDB(): pathsql="insert into musicvideo(idMVideo, idFile, c00, c04, c08, c23) values(?, ?, ?, ?, ?, ?)" cursor.execute(pathsql, (musicvideoid, fileid, title, runtime, plot, MBitem["Id"])) - try: - connection.commit() - utils.logMsg("Emby","Added musicvideo to Kodi Library",MBitem["Id"] + " - " + MBitem["Name"]) - except: - utils.logMsg("Emby","Error adding musicvideo to Kodi Library",MBitem["Id"] + " - " + MBitem["Name"]) - actionPerformed = False def addOrUpdateEpisodeToKodiLibrary(self, embyId, showid, connection, cursor): @@ -675,9 +661,6 @@ class WriteKodiDB(): #update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), episodeid, "episode", "thumb", cursor) - - #commit changes - connection.commit() def deleteItemFromKodiLibrary(self, id, connection, cursor ): @@ -701,8 +684,6 @@ class WriteKodiDB(): #delete the record in emby table cursor.execute("DELETE FROM emby WHERE emby_id = ?", (id,)) - - connection.commit() def updateSeasons(self,embyTvShowId, kodiTvShowId, connection, cursor): @@ -1058,8 +1039,6 @@ class WriteKodiDB(): result = cursor.fetchone() if result != None: setid = result[0] - connection.commit() - return True From 210b0831c766e73dc865924588a65993bb3e232a Mon Sep 17 00:00:00 2001 From: im85288 Date: Sat, 2 May 2015 22:14:04 +0100 Subject: [PATCH 33/66] use etag for checksum --- resources/lib/API.py | 26 +++++++++++++------------- resources/lib/ReadEmbyDB.py | 16 ++++++++-------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/resources/lib/API.py b/resources/lib/API.py index 151963b8..6f297024 100644 --- a/resources/lib/API.py +++ b/resources/lib/API.py @@ -124,19 +124,19 @@ class API(): # else just add some fields to a string checksum = "" - #if item.get("Etag") != None: - #checksum = item.get("Etag") - #else: - userData = item.get("UserData") - if(userData != None): - checksum += str(userData.get("Played")) - checksum += str(userData.get("IsFavorite")) - if userData.get('UnplayedItemCount') != None: - checksum += str(userData.get("UnplayedItemCount")) - if userData.get('LastPlayedDate') != None: - checksum += str(userData.get("LastPlayedDate")) - if userData.get('PlaybackPositionTicks') != None: - checksum += str(userData.get("PlaybackPositionTicks")) + if item.get("Etag") != None: + checksum = item.get("Etag") + else: + userData = item.get("UserData") + if(userData != None): + checksum += str(userData.get("Played")) + checksum += str(userData.get("IsFavorite")) + if userData.get('UnplayedItemCount') != None: + checksum += str(userData.get("UnplayedItemCount")) + if userData.get('LastPlayedDate') != None: + checksum += str(userData.get("LastPlayedDate")) + if userData.get('PlaybackPositionTicks') != None: + checksum += str(userData.get("PlaybackPositionTicks")) return checksum diff --git a/resources/lib/ReadEmbyDB.py b/resources/lib/ReadEmbyDB.py index c2817115..f436d365 100644 --- a/resources/lib/ReadEmbyDB.py +++ b/resources/lib/ReadEmbyDB.py @@ -21,7 +21,7 @@ class ReadEmbyDB(): #only get basic info for our sync-compares sortstring = "&SortBy=SortName" - url = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Movie&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % (id, sortstring) + url = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s%s&Fields=CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=Movie&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % (id, sortstring) jsonData = doUtils.downloadUrl(url) if (jsonData == ""): @@ -47,7 +47,7 @@ class ReadEmbyDB(): #only get basic info for our sync-compares sortstring = "&SortBy=SortName" - url = "{server}/mediabrowser/Users/{UserId}/items?%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % sortstring + url = "{server}/mediabrowser/Users/{UserId}/items?%s&Fields=CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % sortstring jsonData = doUtils.downloadUrl(url) if (jsonData == ""): @@ -99,7 +99,7 @@ class ReadEmbyDB(): #only get basic info for our sync-compares sortstring = "&SortBy=SortName" - url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1" % (id, sortstring) + url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s%s&Fields=CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1" % (id, sortstring) jsonData = doUtils.downloadUrl(url) if (jsonData == ""): @@ -139,7 +139,7 @@ class ReadEmbyDB(): result = None doUtils = DownloadUtils() - url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&IsVirtualUnaired=false&IsMissing=False&SortBy=SortName&Fields=Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % showId + url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&IsVirtualUnaired=false&IsMissing=False&SortBy=SortName&Fields=Name,SortName,CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % showId jsonData = doUtils.downloadUrl(url) if (jsonData == ""): @@ -168,9 +168,9 @@ class ReadEmbyDB(): limitString = "Ids=" + ",".join(itemList) + "&" if fullinfo: - url = "{server}/mediabrowser/Users/{UserId}/Items?%sIsVirtualUnaired=false&IsMissing=False&Fields=ParentId,Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % limitString + url = "{server}/mediabrowser/Users/{UserId}/Items?%sIsVirtualUnaired=false&IsMissing=False&Fields=ParentId,Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % limitString else: - url = "{server}/mediabrowser/Users/{UserId}/Items?%sIsVirtualUnaired=false&IsMissing=False&Fields=ParentId,Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % limitString + url = "{server}/mediabrowser/Users/{UserId}/Items?%sIsVirtualUnaired=false&IsMissing=False&Fields=ParentId,Name,SortName,CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % limitString jsonData = doUtils.downloadUrl(url) if (jsonData == ""): @@ -260,7 +260,7 @@ class ReadEmbyDB(): result = None doUtils = DownloadUtils() - url = "{server}/mediabrowser/Users/{UserId}/Items?SortBy=SortName&IsVirtualUnaired=false&IsMissing=False&Fields=Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=BoxSet&format=json&ImageTypeLimit=1" + url = "{server}/mediabrowser/Users/{UserId}/Items?SortBy=SortName&IsVirtualUnaired=false&IsMissing=False&Fields=Name,SortName,CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Ascending&IncludeItemTypes=BoxSet&format=json&ImageTypeLimit=1" jsonData = doUtils.downloadUrl(url) if (jsonData == ""): @@ -276,7 +276,7 @@ class ReadEmbyDB(): result = None doUtils = DownloadUtils() - url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&Fields=ItemCounts&format=json&ImageTypeLimit=1" % boxsetId + url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&Fields=ItemCounts,Etag&format=json&ImageTypeLimit=1" % boxsetId jsonData = doUtils.downloadUrl(url) if (jsonData == ""): From 8e3a22e0e8b58183963042516b025bc38dc95a8e Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sat, 2 May 2015 16:40:30 -0500 Subject: [PATCH 34/66] Launch playback via default.py I've commented out the resume dialog. If we actually need it then it can be readded. --- default.py | 24 ++++++----- resources/lib/DownloadUtils.py | 74 +++++++++++++++++++++++++--------- resources/lib/PlaybackUtils.py | 12 ++++-- 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/default.py b/default.py index 3205abf2..0fd50f31 100644 --- a/default.py +++ b/default.py @@ -12,24 +12,26 @@ cwd = addonSettings.getAddonInfo('path') BASE_RESOURCE_PATH = xbmc.translatePath( os.path.join( cwd, 'resources', 'lib' ) ) sys.path.append(BASE_RESOURCE_PATH) -WINDOW = xbmcgui.Window( 10000 ) +WINDOW = xbmcgui.Window(10000) import Utils as utils from PlaybackUtils import PlaybackUtils +from DownloadUtils import DownloadUtils try: - params=utils.get_params(sys.argv[2]) - mode = params.get('mode',"") - id = params.get('id',"") + params = utils.get_params(sys.argv[2]) + mode = params['mode'] + id = params['id'] except: - params={} - mode=None - id=None + params = {} + mode = None + +if mode == "play": + # Play items via plugin://plugin.video.emby/ + url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % id + result = DownloadUtils().downloadUrl(url) + item = PlaybackUtils().PLAY(result, setup="default") -if mode != None and mode == "play": - listItem = xbmcgui.ListItem(path="") - xbmcplugin.setResolvedUrl (int(sys.argv[1]), True, listItem) - WINDOW.setProperty('GUIPLAY', str(id)) # set window prop elif sys.argv[1] == "reset": utils.reset() else: diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py index 22165188..d1504cba 100644 --- a/resources/lib/DownloadUtils.py +++ b/resources/lib/DownloadUtils.py @@ -99,9 +99,12 @@ class DownloadUtils(): header = self.getHeader() # If user enabled host certificate verification - if self.sslverify: - verify = True + try: + verify = self.sslverify cert = self.sslclient + except: + self.logMsg("Could not load SSL settings.", 1) + pass # Start session self.s = requests.Session() @@ -149,31 +152,62 @@ class DownloadUtils(): self.logMsg("=== ENTER downloadUrl ===", 2) - WINDOW = xbmcgui.Window( 10000 ) + WINDOW = self.WINDOW timeout = self.timeout default_link = "" - - username = WINDOW.getProperty('currUser') - userId = WINDOW.getProperty('userId%s' % username) - server = WINDOW.getProperty('server%s' % username) - url = url.replace("{server}", server, 1) - url = url.replace("{UserId}", userId, 1) - #url = "%s&api_key=%s" % (url, self.token) # If user is authenticated if (authenticate): # Get requests session - s = self.s - # Replace for the real values and append api_key + try: + s = self.s + # Replace for the real values and append api_key + url = url.replace("{server}", self.server, 1) + url = url.replace("{UserId}", self.userId, 1) + #url = "%s&api_key=%s" % (url, self.token) - self.logMsg("URL: %s" % url, 2) - # Prepare request - if type == "GET": - r = s.get(url, json=postBody, timeout=timeout) - elif type == "POST": - r = s.post(url, json=postBody, timeout=timeout) - elif type == "DELETE": - r = s.delete(url, json=postBody, timeout=timeout) + self.logMsg("URL: %s" % url, 2) + # Prepare request + if type == "GET": + r = s.get(url, json=postBody, timeout=timeout) + elif type == "POST": + r = s.post(url, json=postBody, timeout=timeout) + elif type == "DELETE": + r = s.delete(url, json=postBody, timeout=timeout) + + except AttributeError: + + # Get user information + self.username = WINDOW.getProperty('currUser') + self.userId = WINDOW.getProperty('userId%s' % self.username) + self.server = WINDOW.getProperty('server%s' % self.username) + self.token = WINDOW.getProperty('accessToken%s' % self.username) + header = self.getHeader() + verifyssl = False + cert = None + + # IF user enables ssl verification + try: + if self.addon.getSetting('sslverify') == "true": + verifyssl = True + if self.addon.getSetting('sslcert') != "None": + cert = self.addon.getSetting('sslcert') + except: + self.logMsg("Could not load SSL settings.", 1) + pass + + # Replace for the real values and append api_key + url = url.replace("{server}", self.server, 1) + url = url.replace("{UserId}", self.userId, 1) + + self.logMsg("URL: %s" % url, 2) + # Prepare request + if type == "GET": + r = requests.get(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl) + elif type == "POST": + r = requests.post(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl) + elif type == "DELETE": + r = requests.delete(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl) # If user is not authenticated elif not authenticate: diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index 13b05629..796b8c3e 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -35,7 +35,7 @@ class PlaybackUtils(): def __init__(self, *args): pass - def PLAY(self, result): + def PLAY(self, result, setup="service"): xbmc.log("PLAY Called") WINDOW = xbmcgui.Window(10000) @@ -73,7 +73,7 @@ class PlaybackUtils(): WINDOW.setProperty(playurl+"deleteurl", "") WINDOW.setProperty(playurl+"deleteurl", deleteurl) - if seekTime != 0: + '''if seekTime != 0: displayTime = str(datetime.timedelta(seconds=seekTime)) display_list = [ self.language(30106) + ' ' + displayTime, self.language(30107)] resumeScreen = xbmcgui.Dialog() @@ -83,7 +83,7 @@ class PlaybackUtils(): else: WINDOW.clearProperty(playurl+"seektime") else: - WINDOW.clearProperty(playurl+"seektime") + WINDOW.clearProperty(playurl+"seektime")''' if result.get("Type")=="Episode": WINDOW.setProperty(playurl+"refresh_id", result.get("SeriesId")) @@ -109,7 +109,11 @@ class PlaybackUtils(): WINDOW.setProperty(playurl+"SubtitleStreamIndex", str(mediaSources[0].get('DefaultSubtitleStreamIndex'))) #launch the playback - xbmc.Player().play(playurl,listItem) + if setup == "service": + xbmc.Player().play(playurl,listItem) + elif setup == "default": + listItem = xbmcgui.ListItem(path=playurl) + xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) def setArt(self, list,name,path): if name=='thumb' or name=='fanart_image' or name=='small_poster' or name=='tiny_poster' or name == "medium_landscape" or name=='medium_poster' or name=='small_fanartimage' or name=='medium_fanartimage' or name=='fanart_noindicators': From d69e474f3eb785ba4e7ca3d779c641953a1caa56 Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sat, 2 May 2015 16:43:44 -0500 Subject: [PATCH 35/66] Follow up for playback --- service.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/service.py b/service.py index c8f57a03..ab7e37f3 100644 --- a/service.py +++ b/service.py @@ -69,19 +69,6 @@ class Service(): # Abort was requested while waiting. We should exit break - #detection that file needs to be playback - if WINDOW.getProperty("GUIPLAY") != "": - downloadUtils = DownloadUtils() - id = WINDOW.getProperty("GUIPLAY") - WINDOW.setProperty("GUIPLAY", "") - WINDOW = xbmcgui.Window( 10000 ) - username = WINDOW.getProperty('currUser') - userid = WINDOW.getProperty('userId%s' % username) - server = WINDOW.getProperty('server%s' % username) - url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % id - result = downloadUtils.downloadUrl(url) - PlaybackUtils().PLAY(result) - if xbmc.Player().isPlaying(): try: playTime = xbmc.Player().getTime() From 812e3090a55bf7bca82dc309df1f5f6228b15de8 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 00:44:35 +0200 Subject: [PATCH 36/66] added support for 3d format in streamdetails --- resources/lib/API.py | 5 ++++- resources/lib/WriteKodiDB.py | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/resources/lib/API.py b/resources/lib/API.py index 6f297024..85f16956 100644 --- a/resources/lib/API.py +++ b/resources/lib/API.py @@ -84,6 +84,7 @@ class API(): width = '' aspectratio = '1:1' aspectfloat = 1.85 + Video3DFormat = '' if mediaSources == True: mediaSources = item.get("MediaSources") @@ -102,6 +103,7 @@ class API(): height = int(mediaStream.get("Height")) width = int(mediaStream.get("Width")) aspectratio = mediaStream.get("AspectRatio") + Video3DFormat = item.get("Video3DFormat") if aspectratio != None and len(aspectratio) >= 3: try: aspectwidth,aspectheight = aspectratio.split(':') @@ -116,7 +118,8 @@ class API(): 'audiocodec' : audiocodec, 'height' : height, 'width' : width, - 'aspectratio' : aspectfloat + 'aspectratio' : aspectfloat, + '3dformat' : Video3DFormat } def getChecksum(self, item): diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index eaa402e3..cc65050f 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -162,10 +162,7 @@ class WriteKodiDB(): #create the reference in emby table pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)" cursor.execute(pathsql, (MBitem["Id"], movieid, "movie", API().getChecksum(MBitem))) - - #add streamdetails - self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) - + #### UPDATE THE MOVIE ##### else: utils.logMsg("UPDATE movie to Kodi library","Id: %s - Title: %s" % (embyId, title)) @@ -194,6 +191,9 @@ class WriteKodiDB(): #update studios self.AddStudiosToMedia(movieid, studios, "movie", cursor) + #add streamdetails + self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) + #set resume point resume = int(round(float(timeInfo.get("ResumeTime"))))*60 total = int(round(float(timeInfo.get("TotalTime"))))*60 @@ -297,9 +297,6 @@ class WriteKodiDB(): pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)" cursor.execute(pathsql, (MBitem["Id"], idMVideo, "musicvideo", API().getChecksum(MBitem))) - #add streamdetails - self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) - #### UPDATE THE VIDEO ##### else: utils.logMsg("UPDATE musicvideo to Kodi library","Id: %s - Title: %s" % (embyId, title)) @@ -328,6 +325,9 @@ class WriteKodiDB(): #update studios self.AddStudiosToMedia(idMVideo, studios, "musicvideo", cursor) + #add streamdetails + self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) + #set resume point resume = int(round(float(timeInfo.get("ResumeTime"))))*60 total = int(round(float(timeInfo.get("TotalTime"))))*60 @@ -637,9 +637,6 @@ class WriteKodiDB(): #create the reference in emby table pathsql = "INSERT into emby(emby_id, kodi_id, media_type, checksum, parent_id) values(?, ?, ?, ?, ?)" cursor.execute(pathsql, (MBitem["Id"], episodeid, "episode", API().getChecksum(MBitem), showid)) - - #add streamdetails - self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) # UPDATE THE EPISODE IN KODI (for now, we just send in all data) else: @@ -659,6 +656,9 @@ class WriteKodiDB(): total = int(round(float(timeInfo.get("TotalTime"))))*60 self.setKodiResumePoint(fileid, resume, total, cursor) + #add streamdetails + self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) + #update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), episodeid, "episode", "thumb", cursor) @@ -990,8 +990,8 @@ class WriteKodiDB(): cursor.execute("delete FROM streamdetails WHERE idFile = ?", (fileid,)) if streamdetails: #video details - sql="insert into streamdetails(idFile, iStreamType, strVideoCodec, fVideoAspect, iVideoWidth, iVideoHeight) values(?, ?, ?, ?, ?, ?)" - cursor.execute(sql, (fileid,0,streamdetails.get("videocodec"),streamdetails.get("aspectratio"),streamdetails.get("width"),streamdetails.get("height"))) + sql="insert into streamdetails(idFile, iStreamType, strVideoCodec, fVideoAspect, iVideoWidth, iVideoHeight, strStereoMode) values(?, ?, ?, ?, ?, ?, ?)" + cursor.execute(sql, (fileid,0,streamdetails.get("videocodec"),streamdetails.get("aspectratio"),streamdetails.get("width"),streamdetails.get("height"),streamdetails.get("3dformat"))) #audio details sql="insert into streamdetails(idFile, iStreamType, strAudioCodec, iAudioChannels) values(?, ?, ?, ?)" cursor.execute(sql, (fileid,1,streamdetails.get("audiocodec"),streamdetails.get("channels"))) From 91a73128b181e9a576ebaed2f654b1f0b4df0a89 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 01:46:11 +0200 Subject: [PATCH 37/66] changed checksum to use both userdata and etag to detect changes added favotite shows and movies tags --- resources/lib/API.py | 27 +++++----- resources/lib/WriteKodiDB.py | 102 ++++++++++------------------------- 2 files changed, 41 insertions(+), 88 deletions(-) diff --git a/resources/lib/API.py b/resources/lib/API.py index 85f16956..3239f60b 100644 --- a/resources/lib/API.py +++ b/resources/lib/API.py @@ -123,23 +123,22 @@ class API(): } def getChecksum(self, item): - # use the etags or serverside checksum for this if available - # else just add some fields to a string + # use the etags checksum for this if available + # AND the userdata checksum = "" if item.get("Etag") != None: checksum = item.get("Etag") - else: userData = item.get("UserData") - if(userData != None): - checksum += str(userData.get("Played")) - checksum += str(userData.get("IsFavorite")) - if userData.get('UnplayedItemCount') != None: - checksum += str(userData.get("UnplayedItemCount")) - if userData.get('LastPlayedDate') != None: - checksum += str(userData.get("LastPlayedDate")) - if userData.get('PlaybackPositionTicks') != None: - checksum += str(userData.get("PlaybackPositionTicks")) + if(userData != None): + checksum += str(userData.get("Played")) + checksum += str(userData.get("IsFavorite")) + if userData.get('UnplayedItemCount') != None: + checksum += str(userData.get("UnplayedItemCount")) + if userData.get('LastPlayedDate') != None: + checksum += str(userData.get("LastPlayedDate")) + if userData.get('PlaybackPositionTicks') != None: + checksum += str(userData.get("PlaybackPositionTicks")) return checksum @@ -152,9 +151,9 @@ class API(): else: watched="False" if userData.get("IsFavorite") == True: - favorite="True" + favorite=True else: - favorite="False" + favorite=False if(userData.get("Played") == True): playcount="1" else: diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index cc65050f..eacfb0d5 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -194,6 +194,12 @@ class WriteKodiDB(): #add streamdetails self.AddStreamDetailsToMedia(API().getMediaStreams(MBitem), fileid, cursor) + #add to favorites tag --> todo translated label for favorites ? + if userData.get("Favorite"): + self.AddTagToMedia(movieid, "Favorite movies", "movie", cursor) + else: + self.AddTagToMedia(movieid, "Favorite movies", "movie", cursor, True) + #set resume point resume = int(round(float(timeInfo.get("ResumeTime"))))*60 total = int(round(float(timeInfo.get("TotalTime"))))*60 @@ -421,7 +427,7 @@ class WriteKodiDB(): #link the path pathsql="insert into tvshowlinkpath(idShow,idPath) values(?, ?)" cursor.execute(pathsql, (showid,pathid)) - + #add the viewtag self.AddTagToMedia(showid, viewTag, "tvshow", cursor) @@ -443,6 +449,12 @@ class WriteKodiDB(): #update studios self.AddStudiosToMedia(showid, studios, "tvshow", cursor) + + #add to favorites tag --> todo translated label for favorites ? + if userData.get("Favorite"): + self.AddTagToMedia(showid, "Favorite tvshows", "tvshow", cursor) + else: + self.AddTagToMedia(showid, "Favorite tvshows", "tvshow", cursor, True) #update artwork self.addOrUpdateArt(API().getArtwork(MBitem, "Primary"), showid, "tvshow", "thumb", cursor) @@ -457,72 +469,6 @@ class WriteKodiDB(): #update season details self.updateSeasons(MBitem["Id"], showid, connection, cursor) - - def addMusicVideoToKodiLibrary( self, MBitem, connection, cursor ): - - #adds a musicvideo to Kodi by directly inserting it to connectionthe DB while there is no addMusicVideo available on the json API - #TODO: PR at Kodi team for a addMusicVideo endpoint on their API - - addon = xbmcaddon.Addon(id='plugin.video.emby') - port = addon.getSetting('port') - host = addon.getSetting('ipaddress') - server = host + ":" + port - - timeInfo = API().getTimeInfo(MBitem) - userData=API().getUserData(MBitem) - - playurl = PlayUtils().getPlayUrl(server, MBitem["Id"], MBitem) - playurl = utils.convertEncoding(playurl) - - if MBitem.get("DateCreated") != None: - dateadded = MBitem["DateCreated"].replace("T"," ") - dateadded = dateadded.replace(".0000000Z","") - else: - dateadded = None - - path = "plugin://plugin.video.emby/musicvideos/" - filename = "plugin://plugin.video.emby/musicvideos/?mode=play&id=" + MBitem["Id"] - - #create 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, strContent, strScraper, noUpdate) values(?, ?, ?, ?, ?)" - cursor.execute(pathsql, (pathid,path,"movies","metadata.local",1)) - - playcount = None - if userData.get("PlayCount") == "1": - playcount = 1 - - #create the file if not exists - cursor.execute("SELECT idFile as fileid FROM files WHERE strFilename = ?",(filename,)) - result = cursor.fetchone() - if result != None: - fileid = result[0] - if result == None: - cursor.execute("select coalesce(max(idFile),0) as fileid from files") - fileid = cursor.fetchone()[0] - fileid = fileid + 1 - pathsql="insert into files(idFile, idPath, strFilename, playCount, lastPlayed, dateAdded) values(?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (fileid,pathid,filename,playcount,userData.get("LastPlayedDate"),dateadded)) - - runtime = int(timeInfo.get('Duration'))*60 - plot = utils.convertEncoding(API().getOverview(MBitem)) - title = utils.convertEncoding(MBitem["Name"]) - - #create the musicvideo - cursor.execute("select coalesce(max(idMVideo),0) as musicvideoid from musicvideo") - musicvideoid = cursor.fetchone()[0] - musicvideoid = musicvideoid + 1 - pathsql="insert into musicvideo(idMVideo, idFile, c00, c04, c08, c23) values(?, ?, ?, ?, ?, ?)" - cursor.execute(pathsql, (musicvideoid, fileid, title, runtime, plot, MBitem["Id"])) - - def addOrUpdateEpisodeToKodiLibrary(self, embyId, showid, connection, cursor): # If the episode already exist in the local Kodi DB we'll perform a full item update @@ -939,7 +885,7 @@ class WriteKodiDB(): sql="INSERT OR REPLACE into studiolinkepisode(idstudio, idEpisode) values(?, ?)" cursor.execute(sql, (idstudio,id)) - def AddTagToMedia(self, id, tag, mediatype, cursor): + def AddTagToMedia(self, id, tag, mediatype, cursor, doRemove=False): if tag: @@ -962,9 +908,13 @@ class WriteKodiDB(): cursor.execute(sql, (tag_id,tag)) utils.logMsg("AddTagToMedia", "Adding tag: " + tag) - #assign tag to item - sql="INSERT OR REPLACE into tag_link(tag_id, media_id, media_type) values(?, ?, ?)" - cursor.execute(sql, (tag_id, id, mediatype)) + #assign tag to item + if doRemove: + sql="DELETE FROM tag_link WHERE media_id = ? AND media_type = ? AND tag_id = ?" + cursor.execute(sql, (id, mediatype, tag_id)) + else: + sql="INSERT OR REPLACE into tag_link(tag_id, media_id, media_type) values(?, ?, ?)" + cursor.execute(sql, (tag_id, id, mediatype)) else: idTag = None @@ -980,9 +930,13 @@ class WriteKodiDB(): sql="insert into tag(idTag, strTag) values(?, ?)" cursor.execute(sql, (idTag,tag)) - #assign tag to item - sql="INSERT OR REPLACE into taglinks(idTag, idMedia, media_type) values(?, ?, ?)" - cursor.execute(sql, (idTag, id, mediatype)) + #assign tag to item + if doRemove: + sql="DELETE FROM taglinks WHERE idMedia = ? AND media_type = ? AND idTag = ?" + cursor.execute(sql, (id, mediatype, idTag)) + else: + sql="INSERT OR REPLACE into taglinks(idTag, idMedia, media_type) values(?, ?, ?)" + cursor.execute(sql, (idTag, id, mediatype)) def AddStreamDetailsToMedia(self, streamdetails, fileid, cursor): From 654dd71b26219c342dfc369a6a9db637f77bdfa8 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 01:59:08 +0200 Subject: [PATCH 38/66] minor fix for musicvideo support --- resources/lib/WriteKodiDB.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index eacfb0d5..93cf7eeb 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -879,6 +879,8 @@ class WriteKodiDB(): #assign studio to item if mediatype == "movie": sql="INSERT OR REPLACE into studiolinkmovie(idstudio, idMovie) values(?, ?)" + if mediatype == "musicvideo": + sql="INSERT OR REPLACE into studiolinkusicvideo(idstudio, idMVideo) values(?, ?)" if mediatype == "tvshow": sql="INSERT OR REPLACE into studiolinktvshow(idstudio, idShow) values(?, ?)" if mediatype == "episode": From 3b6d08cd2e2f3e7a1f1275d1852a12cf53e2f573 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 02:01:15 +0200 Subject: [PATCH 39/66] damn typo --- resources/lib/WriteKodiDB.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 93cf7eeb..96c42b2d 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -880,7 +880,7 @@ class WriteKodiDB(): if mediatype == "movie": sql="INSERT OR REPLACE into studiolinkmovie(idstudio, idMovie) values(?, ?)" if mediatype == "musicvideo": - sql="INSERT OR REPLACE into studiolinkusicvideo(idstudio, idMVideo) values(?, ?)" + sql="INSERT OR REPLACE into studiolinkmusicvideo(idstudio, idMVideo) values(?, ?)" if mediatype == "tvshow": sql="INSERT OR REPLACE into studiolinktvshow(idstudio, idShow) values(?, ?)" if mediatype == "episode": From cb663913a00e02f65ddc8a2c09c6e570c28618bb Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sat, 2 May 2015 21:06:09 -0500 Subject: [PATCH 40/66] Fix sessionId bug --- resources/lib/DownloadUtils.py | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py index d1504cba..a9e8f974 100644 --- a/resources/lib/DownloadUtils.py +++ b/resources/lib/DownloadUtils.py @@ -67,26 +67,19 @@ class DownloadUtils(): def postCapabilities(self, deviceId): - # Get sessionId - url = "{server}/mediabrowser/Sessions?DeviceId=%s&format=json" % deviceId - result = self.downloadUrl(url) - # sessionId result - self.logMsg("Session result: %s" % result, 2) - self.sessionId = result[0][u'Id'] - self.WINDOW.setProperty('sessionId%s' % self.username, self.sessionId) + # Post settings to session + url = "{server}/mediabrowser/Sessions/Capabilities/Full" + data = { + 'PlayableMediaTypes': "Audio,Video", + 'SupportedCommands': "Play,Playstate,SendString,DisplayMessage,PlayNext", + 'SupportsMediaControl': True + } - # Settings for capabilities - playableMediaTypes = "Audio,Video" - supportedCommands = "Play,Playstate,SendString,DisplayMessage,PlayNext" - - # Post settings to sessionId - url = "{server}/mediabrowser/Sessions/Capabilities?Id=%s&PlayableMediaTypes=%s&SupportedCommands=%s&SupportsMediaControl=True" % (self.sessionId, playableMediaTypes, supportedCommands) - data = {} self.logMsg("Capabilities URL: %s" % url, 2) self.logMsg("PostData: %s" % data, 2) - self.downloadUrl(url, postBody=data, type="POST") - self.logMsg("Posted capabilities to sessionId: %s" % self.sessionId, 1) + result = self.downloadUrl(url, postBody=data, type="POST") + self.logMsg("Posted capabilities to %s" % self.server, 1) def startSession(self): From d0e2b7c3d67db6f51eb0659a00d2c110e3fca083 Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sat, 2 May 2015 21:26:01 -0500 Subject: [PATCH 41/66] Revert "Fix sessionId bug" This reverts commit cb663913a00e02f65ddc8a2c09c6e570c28618bb. --- resources/lib/DownloadUtils.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py index a9e8f974..d1504cba 100644 --- a/resources/lib/DownloadUtils.py +++ b/resources/lib/DownloadUtils.py @@ -67,19 +67,26 @@ class DownloadUtils(): def postCapabilities(self, deviceId): - # Post settings to session - url = "{server}/mediabrowser/Sessions/Capabilities/Full" - data = { - 'PlayableMediaTypes': "Audio,Video", - 'SupportedCommands': "Play,Playstate,SendString,DisplayMessage,PlayNext", - 'SupportsMediaControl': True - } + # Get sessionId + url = "{server}/mediabrowser/Sessions?DeviceId=%s&format=json" % deviceId + result = self.downloadUrl(url) + # sessionId result + self.logMsg("Session result: %s" % result, 2) + self.sessionId = result[0][u'Id'] + self.WINDOW.setProperty('sessionId%s' % self.username, self.sessionId) + # Settings for capabilities + playableMediaTypes = "Audio,Video" + supportedCommands = "Play,Playstate,SendString,DisplayMessage,PlayNext" + + # Post settings to sessionId + url = "{server}/mediabrowser/Sessions/Capabilities?Id=%s&PlayableMediaTypes=%s&SupportedCommands=%s&SupportsMediaControl=True" % (self.sessionId, playableMediaTypes, supportedCommands) + data = {} self.logMsg("Capabilities URL: %s" % url, 2) self.logMsg("PostData: %s" % data, 2) - result = self.downloadUrl(url, postBody=data, type="POST") - self.logMsg("Posted capabilities to %s" % self.server, 1) + self.downloadUrl(url, postBody=data, type="POST") + self.logMsg("Posted capabilities to sessionId: %s" % self.sessionId, 1) def startSession(self): From 60390a2f244fc676a47e306668d3208d4271304c Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sat, 2 May 2015 21:28:24 -0500 Subject: [PATCH 42/66] Fix sessionId bug --- resources/lib/DownloadUtils.py | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py index d1504cba..6fb71152 100644 --- a/resources/lib/DownloadUtils.py +++ b/resources/lib/DownloadUtils.py @@ -67,26 +67,22 @@ class DownloadUtils(): def postCapabilities(self, deviceId): - # Get sessionId - url = "{server}/mediabrowser/Sessions?DeviceId=%s&format=json" % deviceId - result = self.downloadUrl(url) - # sessionId result - self.logMsg("Session result: %s" % result, 2) - self.sessionId = result[0][u'Id'] - self.WINDOW.setProperty('sessionId%s' % self.username, self.sessionId) + # Post settings to session + url = "{server}/mediabrowser/Sessions/Capabilities/Full" + data = { + 'PlayableMediaTypes': "Audio,Video", + 'SupportedCommands': "Play,Playstate,SendString,DisplayMessage,PlayNext", + 'SupportsMediaControl': True + } - # Settings for capabilities - playableMediaTypes = "Audio,Video" - supportedCommands = "Play,Playstate,SendString,DisplayMessage,PlayNext" - - # Post settings to sessionId - url = "{server}/mediabrowser/Sessions/Capabilities?Id=%s&PlayableMediaTypes=%s&SupportedCommands=%s&SupportsMediaControl=True" % (self.sessionId, playableMediaTypes, supportedCommands) - data = {} self.logMsg("Capabilities URL: %s" % url, 2) self.logMsg("PostData: %s" % data, 2) - self.downloadUrl(url, postBody=data, type="POST") - self.logMsg("Posted capabilities to sessionId: %s" % self.sessionId, 1) + try: + self.downloadUrl(url, postBody=data, type="POST") + self.logMsg("Posted capabilities to %s" % self.server, 1) + except: + self.logMsg("Posted capabilities failed.") def startSession(self): @@ -104,7 +100,6 @@ class DownloadUtils(): cert = self.sslclient except: self.logMsg("Could not load SSL settings.", 1) - pass # Start session self.s = requests.Session() From 38d0d1c02bf4e8aec651f999efe37661ea2f827b Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sun, 3 May 2015 00:27:43 -0500 Subject: [PATCH 43/66] Added server online check --- resources/lib/DownloadUtils.py | 161 +++++++++++++++-------------- resources/lib/UserClient.py | 16 +-- resources/lib/WebSocketClient.py | 21 +++- service.py | 170 +++++++++++++++++++------------ 4 files changed, 211 insertions(+), 157 deletions(-) diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py index 6fb71152..0cc5f497 100644 --- a/resources/lib/DownloadUtils.py +++ b/resources/lib/DownloadUtils.py @@ -151,87 +151,86 @@ class DownloadUtils(): timeout = self.timeout default_link = "" - # If user is authenticated - if (authenticate): - # Get requests session - try: - s = self.s - # Replace for the real values and append api_key - url = url.replace("{server}", self.server, 1) - url = url.replace("{UserId}", self.userId, 1) - #url = "%s&api_key=%s" % (url, self.token) - - self.logMsg("URL: %s" % url, 2) - # Prepare request - if type == "GET": - r = s.get(url, json=postBody, timeout=timeout) - elif type == "POST": - r = s.post(url, json=postBody, timeout=timeout) - elif type == "DELETE": - r = s.delete(url, json=postBody, timeout=timeout) - - except AttributeError: - - # Get user information - self.username = WINDOW.getProperty('currUser') - self.userId = WINDOW.getProperty('userId%s' % self.username) - self.server = WINDOW.getProperty('server%s' % self.username) - self.token = WINDOW.getProperty('accessToken%s' % self.username) - header = self.getHeader() - verifyssl = False - cert = None - - # IF user enables ssl verification - try: - if self.addon.getSetting('sslverify') == "true": - verifyssl = True - if self.addon.getSetting('sslcert') != "None": - cert = self.addon.getSetting('sslcert') - except: - self.logMsg("Could not load SSL settings.", 1) - pass - - # Replace for the real values and append api_key - url = url.replace("{server}", self.server, 1) - url = url.replace("{UserId}", self.userId, 1) - - self.logMsg("URL: %s" % url, 2) - # Prepare request - if type == "GET": - r = requests.get(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl) - elif type == "POST": - r = requests.post(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl) - elif type == "DELETE": - r = requests.delete(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl) - - # If user is not authenticated - elif not authenticate: - - self.logMsg("URL: %s" % url, 1) - header = self.getHeader(authenticate=False) - verifyssl = False - - # If user enables ssl verification - try: - verifyssl = self.sslverify - except AttributeError: - pass - - # Prepare request - if type == "GET": - r = requests.get(url, json=postBody, headers=header, timeout=timeout, verify=verifyssl) - elif type == "POST": - r = requests.post(url, json=postBody, headers=header, timeout=timeout, verify=verifyssl) - - # Process the response try: - r.raise_for_status() + # If user is authenticated + if (authenticate): + # Get requests session + try: + s = self.s + # Replace for the real values and append api_key + url = url.replace("{server}", self.server, 1) + url = url.replace("{UserId}", self.userId, 1) + #url = "%s&api_key=%s" % (url, self.token) + + self.logMsg("URL: %s" % url, 2) + # Prepare request + if type == "GET": + r = s.get(url, json=postBody, timeout=timeout) + elif type == "POST": + r = s.post(url, json=postBody, timeout=timeout) + elif type == "DELETE": + r = s.delete(url, json=postBody, timeout=timeout) + + except AttributeError: + + # Get user information + self.username = WINDOW.getProperty('currUser') + self.userId = WINDOW.getProperty('userId%s' % self.username) + self.server = WINDOW.getProperty('server%s' % self.username) + self.token = WINDOW.getProperty('accessToken%s' % self.username) + header = self.getHeader() + verifyssl = False + cert = None + + # IF user enables ssl verification + try: + if self.addon.getSetting('sslverify') == "true": + verifyssl = True + if self.addon.getSetting('sslcert') != "None": + cert = self.addon.getSetting('sslcert') + except: + self.logMsg("Could not load SSL settings.", 1) + pass + + # Replace for the real values and append api_key + url = url.replace("{server}", self.server, 1) + url = url.replace("{UserId}", self.userId, 1) + + self.logMsg("URL: %s" % url, 2) + # Prepare request + if type == "GET": + r = requests.get(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl) + elif type == "POST": + r = requests.post(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl) + elif type == "DELETE": + r = requests.delete(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl) + + # If user is not authenticated + elif not authenticate: + + self.logMsg("URL: %s" % url, 2) + header = self.getHeader(authenticate=False) + verifyssl = False + + # If user enables ssl verification + try: + verifyssl = self.sslverify + except AttributeError: + pass + + # Prepare request + if type == "GET": + r = requests.get(url, json=postBody, headers=header, timeout=timeout, verify=verifyssl) + elif type == "POST": + r = requests.post(url, json=postBody, headers=header, timeout=timeout, verify=verifyssl) + + # Process the response if r.status_code == 204: - # No response in body + # No body in the response self.logMsg("====== 204 Success ======", 2) return default_link - # Response code 200 + elif r.status_code == requests.codes.ok: try: # UTF-8 - JSON object @@ -240,13 +239,19 @@ class DownloadUtils(): return r except: self.logMsg("Unable to convert the response for: %s" % url, 1) + else: + r.raise_for_status() return default_link # TO REVIEW EXCEPTIONS except requests.exceptions.ConnectionError as e: - self.logMsg("Server unreachable at: %s" % url, 0) - self.logMsg(e, 1) + # Make the addon aware of status + if WINDOW.getProperty("Server_online") != "false": + self.logMsg("Server unreachable at: %s" % url, 0) + self.logMsg(e, 2) + WINDOW.setProperty("Server_online", "false") + pass except requests.exceptions.ConnectTimeout as e: self.logMsg("Server timeout at: %s" % url, 0) diff --git a/resources/lib/UserClient.py b/resources/lib/UserClient.py index 31a78f64..2bef61f0 100644 --- a/resources/lib/UserClient.py +++ b/resources/lib/UserClient.py @@ -45,17 +45,17 @@ class UserClient(threading.Thread): def __init__(self, *args): self.__dict__ = self._shared_state - self.className = self.__class__.__name__ - threading.Thread.__init__(self, *args) def logMsg(self, msg, lvl=1): - utils.logMsg("%s %s" % (self.addonName, self.className), str(msg), int(lvl)) + className = self.__class__.__name__ + utils.logMsg("%s %s" % (self.addonName, className), str(msg), int(lvl)) def getUsername(self): - username = self.addon.getSetting('username') + addon = xbmcaddon.Addon(id=self.addonId) + username = addon.getSetting('username') if (username == ""): self.logMsg("No username saved.", 2) @@ -90,7 +90,7 @@ class UserClient(threading.Thread): def getServer(self, prefix=True): # For https support - addon = self.addon + addon = xbmcaddon.Addon(id=self.addonId) HTTPS = addon.getSetting('https') host = addon.getSetting('ipaddress') port = addon.getSetting('port') @@ -161,6 +161,9 @@ class UserClient(threading.Thread): if (result != ""): users = result + else: + # Server connection failed + return False return users @@ -226,9 +229,6 @@ class UserClient(threading.Thread): users = self.getPublicUsers() password = "" - '''if users == "": - self.WINDOW.setProperty("Server_status", "Stop") - return''' # Find user in list for user in users: name = user[u'Name'] diff --git a/resources/lib/WebSocketClient.py b/resources/lib/WebSocketClient.py index cb0308b3..53667181 100644 --- a/resources/lib/WebSocketClient.py +++ b/resources/lib/WebSocketClient.py @@ -205,11 +205,15 @@ class WebSocketThread(threading.Thread): LibrarySync().IncrementalSync(itemsToUpdate) def on_error(self, ws, error): - self.logMsg("Error : " + str(error)) + if "10061" in str(error): + # Server is offline + pass + else: + self.logMsg("Error: %s" % error, 1) #raise def on_close(self, ws): - self.logMsg("Closed") + self.logMsg("Closed", 2) def on_open(self, ws): pass @@ -243,12 +247,19 @@ class WebSocketThread(threading.Thread): self.client.on_open = self.on_open while not self.KodiMonitor.abortRequested(): - self.logMsg("Client Starting") + self.client.run_forever() - if(self.keepRunning): - self.logMsg("Client Needs To Restart") + + if (self.keepRunning): + # Server is not online + if WINDOW.getProperty("Server_online") == "true": + self.logMsg("Server is unreachable.", 1) + WINDOW.setProperty("Server_online", "false") + xbmcgui.Dialog().notification("Error connecting", "Server is unreachable.") + if self.KodiMonitor.waitForAbort(5): break + self.logMsg("Thread Exited") diff --git a/service.py b/service.py index ab7e37f3..80395ad4 100644 --- a/service.py +++ b/service.py @@ -31,7 +31,10 @@ class Service(): clientInfo = ClientInformation() addonName = clientInfo.getAddonName() - className = None + WINDOW = xbmcgui.Window(10000) + + warn_auth = True + server_online = True def __init__(self, *args ): self.KodiMonitor = KodiMonitor.Kodi_Monitor() @@ -41,21 +44,21 @@ class Service(): self.logMsg("======== START %s ========" % addonName, 0) self.logMsg("KODI Version: %s" % xbmc.getInfoLabel("System.BuildVersion"), 0) self.logMsg("%s Version: %s" % (addonName, self.clientInfo.getVersion()), 0) + self.logMsg("Platform: %s" % (self.clientInfo.getPlatform()), 0) def logMsg(self, msg, lvl=1): - self.className = self.__class__.__name__ - utils.logMsg("%s %s" % (self.addonName, self.className), str(msg), int(lvl)) + className = self.__class__.__name__ + utils.logMsg("%s %s" % (self.addonName, className), str(msg), int(lvl)) def ServiceEntryPoint(self): - ConnectionManager().checkServer() - - lastProgressUpdate = datetime.today() - - startupComplete = False - WINDOW = xbmcgui.Window(10000) + WINDOW = self.WINDOW + WINDOW.setProperty("Server_online", "") + ConnectionManager().checkServer() + lastProgressUpdate = datetime.today() + startupComplete = False user = UserClient() player = Player() @@ -68,67 +71,101 @@ class Service(): if self.KodiMonitor.waitForAbort(1): # Abort was requested while waiting. We should exit break - - if xbmc.Player().isPlaying(): - try: - playTime = xbmc.Player().getTime() - totalTime = xbmc.Player().getTotalTime() - currentFile = xbmc.Player().getPlayingFile() - if(player.played_information.get(currentFile) != None): - player.played_information[currentFile]["currentPosition"] = playTime - - # send update - td = datetime.today() - lastProgressUpdate - secDiff = td.seconds - if(secDiff > 3): - try: - player.reportPlayback() - except Exception, msg: - self.logMsg("Exception reporting progress: %s" % msg) - pass - lastProgressUpdate = datetime.today() - # only try autoplay when there's 20 seconds or less remaining and only once! - if (totalTime - playTime <= 20 and (lastFile==None or lastFile!=currentFile)): - lastFile = currentFile - player.autoPlayPlayback() - - except Exception, e: - self.logMsg("Exception in Playback Monitor Service: %s" % e) - pass - else: - if (self.newUserClient == None): - self.newUserClient = "Started" - user.start() - # background worker for database sync - if (user.currUser != None): - - # Correctly launch the websocket, if user manually launches the add-on - if (self.newWebSocketThread == None): - self.newWebSocketThread = "Started" - ws.start() - - #full sync - if(startupComplete == False): - self.logMsg("Doing_Db_Sync: syncDatabase (Started)") - libSync = librarySync.FullLibrarySync() - self.logMsg("Doing_Db_Sync: syncDatabase (Finished) " + str(libSync)) + if WINDOW.getProperty('Server_online') == "true": + # Server is online + if xbmc.Player().isPlaying(): + try: + playTime = xbmc.Player().getTime() + totalTime = xbmc.Player().getTotalTime() + currentFile = xbmc.Player().getPlayingFile() - if(libSync): - startupComplete = True - else: - if self.KodiMonitor.waitForAbort(1): - # Abort was requested while waiting. We should exit - break - WebSocketThread().processPendingActions() - + if(player.played_information.get(currentFile) != None): + player.played_information[currentFile]["currentPosition"] = playTime + + # send update + td = datetime.today() - lastProgressUpdate + secDiff = td.seconds + if(secDiff > 3): + try: + player.reportPlayback() + except Exception, msg: + self.logMsg("Exception reporting progress: %s" % msg) + pass + lastProgressUpdate = datetime.today() + # only try autoplay when there's 20 seconds or less remaining and only once! + if (totalTime - playTime <= 20 and (lastFile==None or lastFile!=currentFile)): + lastFile = currentFile + player.autoPlayPlayback() + + except Exception, e: + self.logMsg("Exception in Playback Monitor Service: %s" % e) + pass else: - self.logMsg("Not authenticated yet", 0) + # background worker for database sync + if (user.currUser != None): + self.warn_auth = True + + # Correctly launch the websocket, if user manually launches the add-on + if (self.newWebSocketThread == None): + self.newWebSocketThread = "Started" + ws.start() + + #full sync + if (startupComplete == False): + self.logMsg("Doing_Db_Sync: syncDatabase (Started)") + libSync = librarySync.FullLibrarySync() + self.logMsg("Doing_Db_Sync: syncDatabase (Finished) " + str(libSync)) + + if (libSync): + startupComplete = True + else: + if self.KodiMonitor.waitForAbort(1): + # Abort was requested while waiting. We should exit + break + WebSocketThread().processPendingActions() + + else: + if self.warn_auth: + self.logMsg("Not authenticated yet.", 1) + self.warn_auth = False + else: + # Wait until server becomes online or shut down is requested + while not self.KodiMonitor.abortRequested(): - self.logMsg("stopping Service", 0) + if user.getServer() == "": + pass + elif not user.getPublicUsers(): + # Server is not online, suppress future warning + if self.server_online: + WINDOW.setProperty("Server_online", "false") + self.logMsg("Server is offline.", 1) + xbmcgui.Dialog().notification("Error connecting", "%s Server is unreachable." % self.addonName) + self.server_online = False + else: + # Server is online + if not self.server_online: + # Server was not online when Kodi started. + # Wait for server to be fully established. + if self.KodiMonitor.waitForAbort(5): + # Abort was requested while waiting. + break + self.server_online = True + self.logMsg("Server is online and ready.", 1) + xbmcgui.Dialog().notification("Connection successful", "%s Server is online." % self.addonName, time=2000) + WINDOW.setProperty("Server_online", "true") + + # Server is online, proceed. + if (self.newUserClient == None): + self.newUserClient = "Started" + user.start() + break + + if self.KodiMonitor.waitForAbort(1): + # Abort was requested while waiting. + break # If user reset library database. - WINDOW = xbmcgui.Window(10000) if WINDOW.getProperty("SyncInstallRunDone") == "false": addon = xbmcaddon.Addon('plugin.video.emby') addon.setSetting("SyncInstallRunDone", "false") @@ -137,8 +174,9 @@ class Service(): ws.stopClient() if (self.newUserClient != None): - user.stopClient() - + user.stopClient() + + self.logMsg("======== STOP %s ========" % self.addonName, 0) #start the service Service().ServiceEntryPoint() From 6cb5fd12a14596047a515e6582c3357949f89157 Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sun, 3 May 2015 01:06:44 -0500 Subject: [PATCH 44/66] logging for report progress Moved to debug --- resources/lib/Player.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/Player.py b/resources/lib/Player.py index d82a86ef..8da0df1e 100644 --- a/resources/lib/Player.py +++ b/resources/lib/Player.py @@ -176,7 +176,7 @@ class Player( xbmc.Player ): postdata['SubtitleStreamIndex'] = subtitleindex postdata = json.dumps(postdata) - self.logMsg("Report: %s" % postdata) + self.logMsg("Report: %s" % postdata, 2) self.ws.sendProgressUpdate(postdata) def onPlayBackPaused( self ): From 4b9cae3f2f0685cf03fec023cf73170be222aeda Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sun, 3 May 2015 02:24:23 -0500 Subject: [PATCH 45/66] Handle revoked token --- resources/lib/DownloadUtils.py | 1 + resources/lib/PlaybackUtils.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/lib/DownloadUtils.py b/resources/lib/DownloadUtils.py index 0cc5f497..390a9d2d 100644 --- a/resources/lib/DownloadUtils.py +++ b/resources/lib/DownloadUtils.py @@ -268,6 +268,7 @@ class DownloadUtils(): # Tell UserClient token has been revoked. WINDOW.setProperty("Server_status", "401") self.logMsg("HTTP Error: %s" % e, 0) + xbmcgui.Dialog().notification("Error connecting", "Unauthorized.", xbmcgui.NOTIFICATION_ERROR) elif (r.status_code == 301) or (r.status_code == 302): # Redirects diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index 796b8c3e..000b5c91 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -43,7 +43,10 @@ class PlaybackUtils(): userid = WINDOW.getProperty('userId%s' % username) server = WINDOW.getProperty('server%s' % username) - id = result["Id"] + try: + id = result["Id"] + except: + return userData = result['UserData'] resume_result = 0 From 6f5ae66c548cf2080a0292ef754f9781ce2203b7 Mon Sep 17 00:00:00 2001 From: im85288 Date: Sun, 3 May 2015 13:44:23 +0100 Subject: [PATCH 46/66] added initial box set support --- resources/lib/LibrarySync.py | 37 ++++++++++++++++++++++++ resources/lib/WriteKodiDB.py | 56 ++++++++++++++++++++++++++++++++---- 2 files changed, 88 insertions(+), 5 deletions(-) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index a453a4b2..5e8cb15e 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -142,6 +142,31 @@ class LibrarySync(): else: if kodiMovie[2] != API().getChecksum(item): WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + + + + #### PROCESS BOX SETS ##### + if(pDialog != None): + utils.logMsg("Sync Movies", "BoxSet Sync Started", 1) + boxsets = ReadEmbyDB().getBoxSets() + + total = len(boxsets) + 1 + count = 1 + for boxset in boxsets: + progressTitle = "Processing BoxSets"+ " (" + str(count) + " of " + str(total) + ")" + pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle) + count += 1 + if(self.ShouldStop()): + return False + boxsetMovies = ReadEmbyDB().getMoviesInBoxSet(boxset["Id"]) + WriteKodiDB().addBoxsetToKodiLibrary(boxset,connection, cursor) + + for boxsetMovie in boxsetMovies: + if(self.ShouldStop()): + return False + WriteKodiDB().updateBoxsetToKodiLibrary(boxsetMovie,boxset, connection, cursor) + + utils.logMsg("Sync Movies", "BoxSet Sync Finished", 1) #### PROCESS DELETES ##### allEmbyMovieIds = set(allEmbyMovieIds) @@ -335,7 +360,19 @@ class LibrarySync(): if not item.get('IsFolder'): WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title')) + + + #### PROCESS BOX SETS ##### + boxsets = ReadEmbyDB().getBoxSets() + + for boxset in boxsets: + boxsetMovies = ReadEmbyDB().getMoviesInBoxSet(boxset["Id"]) + WriteKodiDB().addBoxsetToKodiLibrary(boxset,connection, cursor) + + for boxsetMovie in boxsetMovies: + WriteKodiDB().updateBoxsetToKodiLibrary(boxsetMovie,boxset, connection, cursor) + #### PROCESS TV SHOWS #### views = ReadEmbyDB().getCollections("tvshows") for view in views: diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 96c42b2d..3cdd8951 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -992,15 +992,61 @@ class WriteKodiDB(): setssql="INSERT INTO sets (idSet, strSet) values(?, ?)" cursor.execute(setssql, (None,strSet)) #if OK: + cursor.execute("SELECT idSet FROM sets WHERE strSet = ?", (strSet,)) + result = cursor.fetchone() if result != None: setid = result[0] + + currentsetartsql = "SELECT type, url FROM art where media_type = ? and media_id = ? and url != ''" + cursor.execute(currentsetartsql, ("set", setid)) + existing_type_map = {} + rows = cursor.fetchall() + for row in rows: + existing_type_map[row[0] ] = row[1] + + artwork = {} + artwork["poster"] = API().getArtwork(boxset, "Primary") + artwork["banner"] = API().getArtwork(boxset, "Banner") + artwork["clearlogo"] = API().getArtwork(boxset, "Logo") + artwork["clearart"] = API().getArtwork(boxset, "Art") + artwork["landscape"] = API().getArtwork(boxset, "Thumb") + artwork["discart"] = API().getArtwork(boxset, "Disc") + artwork["fanart"] = API().getArtwork(boxset, "Backdrop") + + art_types = ['poster','fanart','landscape','clearlogo','clearart','banner','discart'] + for update_type in art_types: + if ( update_type in existing_type_map ): + if ( existing_type_map[update_type] != artwork[update_type] ) and artwork[update_type] != '': + setupdateartsql = "UPDATE art SET url = ? where media_type = ? and media_id = ? and type = ?" + cursor.execute(setupdateartsql,(artwork[update_type],"set",setid,update_type)) + elif artwork[update_type] != '': + setartsql = "INSERT INTO art(media_id, media_type, type, url) VALUES(?,?,?,?)" + cursor.execute(setartsql,(setid,"set",update_type,artwork[update_type])) return True - def updateBoxsetToKodiLibrary(self, boxsetmovie, boxset): + def updateBoxsetToKodiLibrary(self, boxsetmovie, boxset, connection, cursor): strSet = boxset["Name"] - kodiMovie = ReadKodiDB().getKodiMovie(boxsetmovie["Id"]) - if kodiMovie != None: - WriteKodiDB().updateProperty(kodiMovie,"set",strSet,"movie",True) - \ No newline at end of file + cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?",(boxsetmovie["Id"],)) + result = cursor.fetchone() + if result != None: + movieid = result[0] + else: + movieid = None + if movieid != None: + # check if exists + cursor.execute("SELECT idSet FROM sets WHERE strSet = ?", (strSet,)) + result = cursor.fetchone() + setid = None + if result != None: + setid = result[0] + + pathsql="update movie SET idSet = ? WHERE idMovie = ?" + cursor.execute(pathsql, (setid, movieid)) + + #update the checksum in emby table + cursor.execute("UPDATE emby SET checksum = ? WHERE emby_id = ?", (API().getChecksum(boxsetmovie),boxsetmovie["Id"])) + + + \ No newline at end of file From e91d2ff2a7925b4d4f286aefe2cc43541f72d8cf Mon Sep 17 00:00:00 2001 From: im85288 Date: Sun, 3 May 2015 14:45:13 +0100 Subject: [PATCH 47/66] resolve artwork issue for widgets --- resources/lib/PlaybackUtils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index 000b5c91..103c4f4f 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -115,8 +115,9 @@ class PlaybackUtils(): if setup == "service": xbmc.Player().play(playurl,listItem) elif setup == "default": - listItem = xbmcgui.ListItem(path=playurl) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) + #artwork only works from widgets with both resolvedurl and player command + xbmc.Player().play(playurl,listItem) def setArt(self, list,name,path): if name=='thumb' or name=='fanart_image' or name=='small_poster' or name=='tiny_poster' or name == "medium_landscape" or name=='medium_poster' or name=='small_fanartimage' or name=='medium_fanartimage' or name=='fanart_noindicators': From 76691ea687c552eec9d84924a1b5f59e380b1c75 Mon Sep 17 00:00:00 2001 From: xnappo Date: Sun, 3 May 2015 09:42:37 -0500 Subject: [PATCH 48/66] Fixes for user views in case we decide to use them --- resources/lib/ReadEmbyDB.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/lib/ReadEmbyDB.py b/resources/lib/ReadEmbyDB.py index f436d365..edd24e2f 100644 --- a/resources/lib/ReadEmbyDB.py +++ b/resources/lib/ReadEmbyDB.py @@ -246,13 +246,13 @@ class ReadEmbyDB(): Name = view[u'Name'] total = str(view[u'ChildCount']) - type = view[u'CollectionType'] - if type == None: - type = "None" # User may not have declared the type - if type == type: + itemtype = view[u'CollectionType'] + if itemtype == None: + itemtype = "movies" # User may not have declared the type + if itemtype == type: collections.append( {'title' : Name, - 'type' : type, - 'id' : view[u'Id']}) + 'type' : type, + 'id' : view[u'Id']}) return collections def getBoxSets(self): From 7a2d0d2ef78afd2178da40b14ab1fff9a88a11df Mon Sep 17 00:00:00 2001 From: xnappo Date: Sun, 3 May 2015 10:05:26 -0500 Subject: [PATCH 49/66] Add sync on wakeup --- resources/lib/KodiMonitor.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/lib/KodiMonitor.py b/resources/lib/KodiMonitor.py index 42208475..a3be00a5 100644 --- a/resources/lib/KodiMonitor.py +++ b/resources/lib/KodiMonitor.py @@ -11,6 +11,7 @@ import json import Utils as utils from WriteKodiDB import WriteKodiDB from ReadKodiDB import ReadKodiDB +from LibrarySync import LibrarySync from PlayUtils import PlayUtils from DownloadUtils import DownloadUtils from PlaybackUtils import PlaybackUtils @@ -45,6 +46,11 @@ class Kodi_Monitor(xbmc.Monitor): utils.logMsg("MB# Sync","Kodi_Monitor--> VideoLibrary.OnUpdate : " + str(data),2) WriteKodiDB().updatePlayCountFromKodi(item, type, playcount) - + if method == "System.OnWake": + xbmc.sleep(10000) #Allow network to wake up + utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Started)",1) + utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Finished) " + str(libSync),1) + + From 08ea50bdcae2eceebbc686b8048c1346a8f7aaeb Mon Sep 17 00:00:00 2001 From: xnappo Date: Sun, 3 May 2015 10:19:02 -0500 Subject: [PATCH 50/66] Missed a line somehow. --- resources/lib/KodiMonitor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lib/KodiMonitor.py b/resources/lib/KodiMonitor.py index a3be00a5..a2e789aa 100644 --- a/resources/lib/KodiMonitor.py +++ b/resources/lib/KodiMonitor.py @@ -49,6 +49,7 @@ class Kodi_Monitor(xbmc.Monitor): if method == "System.OnWake": xbmc.sleep(10000) #Allow network to wake up utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Started)",1) + libSync = LibrarySync().FullLibrarySync() utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Finished) " + str(libSync),1) From 72ca06e41727fdd982dc668b82bb8845371b31db Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 17:39:12 +0200 Subject: [PATCH 51/66] add support for native extrafanart --- default.py | 55 +++++++++++++++++++++++++++++++++++- resources/lib/WriteKodiDB.py | 8 +++--- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/default.py b/default.py index 0fd50f31..cc6bc0bd 100644 --- a/default.py +++ b/default.py @@ -2,6 +2,7 @@ import xbmcaddon import xbmcplugin import xbmc import xbmcgui +import xbmcvfs import os import threading import json @@ -12,11 +13,14 @@ cwd = addonSettings.getAddonInfo('path') BASE_RESOURCE_PATH = xbmc.translatePath( os.path.join( cwd, 'resources', 'lib' ) ) sys.path.append(BASE_RESOURCE_PATH) + WINDOW = xbmcgui.Window(10000) import Utils as utils from PlaybackUtils import PlaybackUtils from DownloadUtils import DownloadUtils +from ReadEmbyDB import ReadEmbyDB +from API import API try: params = utils.get_params(sys.argv[2]) @@ -32,8 +36,57 @@ if mode == "play": result = DownloadUtils().downloadUrl(url) item = PlaybackUtils().PLAY(result, setup="default") + +#get extrafanart for listitem - this will only be used for skins that actually call the listitem's path + fanart dir... +elif "extrafanart" in sys.argv[0]: + itemPath = "" + embyId = "" + + try: + #only do this if the listitem has actually changed + itemPath = xbmc.getInfoLabel("ListItem.FileNameAndPath") + + if not itemPath: + itemPath = xbmc.getInfoLabel("ListItem.Path") + + if ("/tvshows/" in itemPath or "/musicvideos/" in itemPath or "/movies/" in itemPath): + embyId = itemPath.split("/")[-2] + + #we need to store the images locally for this to work because of the caching system in xbmc + fanartDir = xbmc.translatePath("special://thumbnails/emby/" + embyId + "/") + + if not xbmcvfs.exists(fanartDir): + #download the images to the cache directory + xbmcvfs.mkdir(fanartDir) + item = ReadEmbyDB().getFullItem(embyId) + if item != None: + if item.has_key("BackdropImageTags"): + if(len(item["BackdropImageTags"]) > 1): + totalbackdrops = len(item["BackdropImageTags"]) + for index in range(1,totalbackdrops): + backgroundUrl = API().getArtwork(item, "Backdrop",str(index)) + fanartFile = os.path.join(fanartDir,"fanart" + str(index) + ".jpg") + li = xbmcgui.ListItem(str(index), path=fanartFile) + xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=fanartFile, listitem=li) + xbmcvfs.copy(backgroundUrl,fanartFile) + + else: + #use existing cached images + dirs, files = xbmcvfs.listdir(fanartDir) + count = 1 + for file in files: + count +=1 + li = xbmcgui.ListItem(file, path=os.path.join(fanartDir,file)) + xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=os.path.join(fanartDir,file), listitem=li) + except: + pass + + #always do endofdirectory to prevent errors in the logs + xbmcplugin.endOfDirectory(int(sys.argv[1])) + + elif sys.argv[1] == "reset": utils.reset() -else: +else: xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)') diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 96c42b2d..825e23af 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -114,8 +114,8 @@ class WriteKodiDB(): #### ADD OR UPDATE THE FILE AND PATH ########### #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY - path = "plugin://plugin.video.emby/movies/" - filename = "plugin://plugin.video.emby/movies/?id=%s&mode=play" % MBitem["Id"] + path = "plugin://plugin.video.emby/movies/%s/" % MBitem["Id"] + filename = "plugin://plugin.video.emby/movies/%s/?id=%s&mode=play" % (MBitem["Id"],MBitem["Id"]) #create the path cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) @@ -257,8 +257,8 @@ class WriteKodiDB(): #### ADD OR UPDATE THE FILE AND PATH ########### #### NOTE THAT LASTPLAYED AND PLAYCOUNT ARE STORED AT THE FILE ENTRY - path = "plugin://plugin.video.emby/musicvideos/" - filename = "plugin://plugin.video.emby/musicvideos/?id=%s&mode=play" % MBitem["Id"] + path = "plugin://plugin.video.emby/musicvideos/%s/" % MBitem["Id"] + filename = "plugin://plugin.video.emby/musicvideos/%s/?id=%s&mode=play" % (MBitem["Id"], MBitem["Id"]) #create the path cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?",(path,)) From c8e43125718b2b918000721201aa9766f9f6e7a5 Mon Sep 17 00:00:00 2001 From: xnappo Date: Sun, 3 May 2015 10:39:30 -0500 Subject: [PATCH 52/66] More fixes to make 'getViewCollections' work --- resources/lib/ReadEmbyDB.py | 56 ++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/resources/lib/ReadEmbyDB.py b/resources/lib/ReadEmbyDB.py index edd24e2f..20577e20 100644 --- a/resources/lib/ReadEmbyDB.py +++ b/resources/lib/ReadEmbyDB.py @@ -226,33 +226,43 @@ class ReadEmbyDB(): doUtils = DownloadUtils() viewsUrl = "{server}/mediabrowser/Users/{UserId}/Views?format=json&ImageTypeLimit=1" - jsonData = doUtils.downloadUrl(viewsUrl) + result = doUtils.downloadUrl(viewsUrl) collections=[] - if (jsonData != ""): - views = views[u'Items'] + if (result == ""): + return [] + + result = result[u'Items'] - for view in views: - if (view[u'Type'] == 'UserView'): # Need to grab the real main node - newViewsUrl = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s&SortBy=SortName&SortOrder=Ascending&format=json&ImageTypeLimit=1" % view[u'Id'] - jsonData = doUtils.downloadUrl(newViewsUrl) - if (jsonData != ""): - newViews = newViews[u'Items'] - for newView in newViews: - # There are multiple nodes in here like 'Latest', 'NextUp' - below we grab the full node. - if newView[u'CollectionType'] == "MovieMovies" or newView[u'CollectionType'] == "TvShowSeries": - view=newView - if (view[u'ChildCount'] != 0): - Name = view[u'Name'] - - total = str(view[u'ChildCount']) + for view in result: + if (view[u'Type'] == 'UserView'): # Need to grab the real main node + newViewsUrl = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s&SortBy=SortName&SortOrder=Ascending&format=json&ImageTypeLimit=1" % view[u'Id'] + newViews = doUtils.downloadUrl(newViewsUrl) + if (result == ""): + return [] + newViews = newViews[u'Items'] + print str(newViews) + for newView in newViews: + # There are multiple nodes in here like 'Latest', 'NextUp' - below we grab the full node. + if newView[u'CollectionType'] != None: + if newView[u'CollectionType'] == "MovieMovies" or newView[u'CollectionType'] == "TvShowSeries": + view=newView + if (view[u'ChildCount'] != 0): + Name = view[u'Name'] + + total = str(view[u'ChildCount']) + try: itemtype = view[u'CollectionType'] - if itemtype == None: - itemtype = "movies" # User may not have declared the type - if itemtype == type: - collections.append( {'title' : Name, - 'type' : type, - 'id' : view[u'Id']}) + except: + itemtype = "movies" + if itemtype == "MovieMovies": + itemtype = "movies" + if itemtype == "TvShowSeries": + itemtype = "tvshows" + if itemtype == type: + collections.append( {'title' : Name, + 'type' : type, + 'id' : view[u'Id']}) return collections def getBoxSets(self): From cef2b67eba1d88fce35b83b8e0e137fcd2c1f9d1 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 18:02:53 +0200 Subject: [PATCH 53/66] only use the additional play when launched from widget (home active) --- resources/lib/PlaybackUtils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index 103c4f4f..8c179949 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -117,7 +117,8 @@ class PlaybackUtils(): elif setup == "default": xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) #artwork only works from widgets with both resolvedurl and player command - xbmc.Player().play(playurl,listItem) + if xbmc.getCondVisibility("Window.IsActive(home)"): + xbmc.Player().play(playurl,listItem) def setArt(self, list,name,path): if name=='thumb' or name=='fanart_image' or name=='small_poster' or name=='tiny_poster' or name == "medium_landscape" or name=='medium_poster' or name=='small_fanartimage' or name=='medium_fanartimage' or name=='fanart_noindicators': From 4d9c845fd30a4d59832a0d74caa60bc43489f93d Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 18:08:07 +0200 Subject: [PATCH 54/66] show the additional resume dialog if launched from a widget --- resources/lib/PlaybackUtils.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index 8c179949..b6851ddf 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -76,17 +76,19 @@ class PlaybackUtils(): WINDOW.setProperty(playurl+"deleteurl", "") WINDOW.setProperty(playurl+"deleteurl", deleteurl) - '''if seekTime != 0: - displayTime = str(datetime.timedelta(seconds=seekTime)) - display_list = [ self.language(30106) + ' ' + displayTime, self.language(30107)] - resumeScreen = xbmcgui.Dialog() - resume_result = resumeScreen.select(self.language(30105), display_list) - if resume_result == 0: - WINDOW.setProperty(playurl+"seektime", str(seekTime)) + #show the additional resume dialog if launched from a widget + if xbmc.getCondVisibility("Window.IsActive(home)"): + if seekTime != 0: + displayTime = str(datetime.timedelta(seconds=seekTime)) + display_list = [ self.language(30106) + ' ' + displayTime, self.language(30107)] + resumeScreen = xbmcgui.Dialog() + resume_result = resumeScreen.select(self.language(30105), display_list) + if resume_result == 0: + WINDOW.setProperty(playurl+"seektime", str(seekTime)) + else: + WINDOW.clearProperty(playurl+"seektime") else: WINDOW.clearProperty(playurl+"seektime") - else: - WINDOW.clearProperty(playurl+"seektime")''' if result.get("Type")=="Episode": WINDOW.setProperty(playurl+"refresh_id", result.get("SeriesId")) From 8de2eecdcf0d33e3640879714647795d84ff3d95 Mon Sep 17 00:00:00 2001 From: im85288 Date: Sun, 3 May 2015 17:26:04 +0100 Subject: [PATCH 55/66] fixed autoplay episodes --- resources/lib/Player.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/resources/lib/Player.py b/resources/lib/Player.py index 8da0df1e..56d0838f 100644 --- a/resources/lib/Player.py +++ b/resources/lib/Player.py @@ -138,6 +138,10 @@ class Player( xbmc.Player ): self.logMsg("reportPlayback Called", 2) xbmcplayer = self.xbmcplayer + + if not xbmcplayer.isPlaying(): + self.logMsg("reportPlayback: Not playing anything so returning", 0) + return currentFile = xbmcplayer.getPlayingFile() data = self.played_information.get(currentFile) @@ -325,14 +329,11 @@ class Player( xbmc.Player ): def autoPlayPlayback(self): currentFile = xbmc.Player().getPlayingFile() data = self.played_information.get(currentFile) - # only report playback if emby has initiated the playback (item_id has value) if(data != None and data.get("item_id") != None): addonSettings = xbmcaddon.Addon(id='plugin.video.emby') - item_id = data.get("item_id") type = data.get("Type") - # if its an episode see if autoplay is enabled if addonSettings.getSetting("autoPlaySeason")=="true" and type=="Episode": WINDOW = xbmcgui.Window( 10000 ) @@ -347,8 +348,10 @@ class Player( xbmc.Player ): seasonId = MB3Episode["SeasonId"] url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&ImageTypeLimit=1&Limit=1&SortBy=SortName&SortOrder=Ascending&Filters=IsUnPlayed&IncludeItemTypes=Episode&IsVirtualUnaired=false&Recursive=true&IsMissing=False&format=json" % seasonId jsonData = self.doUtils.downloadUrl(url) + if(jsonData != ""): - seasonData = json.loads(jsonData) + seasonData = jsonData + if seasonData.get("Items") != None: item = seasonData.get("Items")[0] pDialog.create("Auto Play next episode", str(item.get("ParentIndexNumber")) + "x" + str(item.get("IndexNumber")) + ". " + item["Name"] + " found","Cancel to stop automatic play") @@ -369,5 +372,5 @@ class Player( xbmc.Player ): xbmc.sleep(500) playTime = xbmc.Player().getTime() totalTime = xbmc.Player().getTotalTime() - + PlaybackUtils().PLAYAllEpisodes(seasonData.get("Items")) \ No newline at end of file From f80e099b0cdbe57fdb931b3bd060de7444421b66 Mon Sep 17 00:00:00 2001 From: im85288 Date: Sun, 3 May 2015 19:19:25 +0100 Subject: [PATCH 56/66] remove play from http option at scan time --- resources/lib/ConnectionManager.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/lib/ConnectionManager.py b/resources/lib/ConnectionManager.py index f91722d2..0d8bb036 100644 --- a/resources/lib/ConnectionManager.py +++ b/resources/lib/ConnectionManager.py @@ -116,12 +116,12 @@ class ConnectionManager(): return # Option to play from http - setPlayback = xbmcgui.Dialog().yesno("Playback option", "Play your files using HTTP?") - if setPlayback == 1: - self.logMsg("Playback will be set using HTTP.", 1) - addon.setSetting("playFromStream", "true") - else: - self.logMsg("Playback will be set using SMB.", 1) + #setPlayback = xbmcgui.Dialog().yesno("Playback option", "Play your files using HTTP?") + #if setPlayback == 1: + #self.logMsg("Playback will be set using HTTP.", 1) + #addon.setSetting("playFromStream", "true") + #else: + #self.logMsg("Playback will be set using SMB.", 1) def getServerDetails(self): From dd54cb27f38ea586cd37652b6c44d06110e1845a Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 20:30:24 +0200 Subject: [PATCH 57/66] first work on the video nodes stuff --- resources/lib/KodiMonitor.py | 7 +- resources/lib/ReadKodiDB.py | 4 - resources/lib/WriteKodiDB.py | 141 ++++++++++++++++++++++++++++++++++- 3 files changed, 141 insertions(+), 11 deletions(-) diff --git a/resources/lib/KodiMonitor.py b/resources/lib/KodiMonitor.py index a2e789aa..be4688ef 100644 --- a/resources/lib/KodiMonitor.py +++ b/resources/lib/KodiMonitor.py @@ -28,12 +28,7 @@ class Kodi_Monitor(xbmc.Monitor): def onNotification (self,sender,method,data): addon = xbmcaddon.Addon(id='plugin.video.emby') downloadUtils = DownloadUtils() - print "onNotification:" + method + ":" + sender + ":" + str(data) - #player started playing an item - - if method == "Playlist.OnAdd": - print "playlist onadd is called" - - + if method == "VideoLibrary.OnUpdate": jsondata = json.loads(data) if jsondata != None: diff --git a/resources/lib/ReadKodiDB.py b/resources/lib/ReadKodiDB.py index 14c8c53a..ff41ae02 100644 --- a/resources/lib/ReadKodiDB.py +++ b/resources/lib/ReadKodiDB.py @@ -11,10 +11,6 @@ import os import Utils as utils - -#sleepval is used to throttle the calls to the xbmc json API -sleepVal = 15 - class ReadKodiDB(): diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index afce017a..4735e32d 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -20,7 +20,10 @@ from ReadEmbyDB import ReadEmbyDB from API import API import Utils as utils -sleepVal = 20 +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 class WriteKodiDB(): @@ -909,6 +912,7 @@ class WriteKodiDB(): sql="insert into tag(tag_id, name) values(?, ?)" cursor.execute(sql, (tag_id,tag)) utils.logMsg("AddTagToMedia", "Adding tag: " + tag) + self.addVideoNodesForTag(tag, mediatype) #assign tag to item if doRemove: @@ -931,6 +935,8 @@ class WriteKodiDB(): idTag = idTag + 1 sql="insert into tag(idTag, strTag) values(?, ?)" cursor.execute(sql, (idTag,tag)) + utils.logMsg("AddTagToMedia", "Adding tag: " + tag) + self.addVideoNodesForTag(tag, mediatype) #assign tag to item if doRemove: @@ -1026,6 +1032,139 @@ class WriteKodiDB(): return True + def addVideoNodesForTag(self, tagname, type): + + utils.logMsg("addVideoNodesForTag", "Creating nodes for tag: " + tagname) + libraryPath = xbmc.translatePath("special://userdata/library/video/emby/") + + if type == "movie": + type = "movies" + elif type == "tvshow": + type = "tvshows" + else: + return + + if not xbmcvfs.exists(libraryPath): + #create root node + xbmcvfs.mkdir(libraryPath) + nodefile = os.path.join(libraryPath, "index.xml") + root = Element("node", {"order":"1"}) + SubElement(root, "label").text = "Emby" + SubElement(root, "icon").text = "DefaultMovies.png" + try: + ET.ElementTree(root).write(nodefile, xml_declaration=True) + except: + ET.ElementTree(root).write(nodefile) + + #tagpath + libraryPath = xbmc.translatePath("special://userdata/library/video/emby/%s/" %tagname) + + if not xbmcvfs.exists(libraryPath): + #create tag node - index + xbmcvfs.mkdir(libraryPath) + nodefile = os.path.join(libraryPath, "index.xml") + root = Element("node", {"order":"1"}) + SubElement(root, "label").text = tagname + SubElement(root, "icon").text = "DefaultMovies.png" + try: + ET.ElementTree(root).write(nodefile, xml_declaration=True) + except: + ET.ElementTree(root).write(nodefile) + + #create tag node - all items + nodefile = os.path.join(libraryPath, tagname + "_all.xml") + root = Element("node", {"order":"1", "type":"filter"}) + SubElement(root, "label").text = tagname + SubElement(root, "match").text = "all" + SubElement(root, "content").text = type + SubElement(root, "icon").text = "DefaultMovies.png" + Rule = SubElement(root, "rule", {"field":"tag","operator":"is"}) + SubElement(Rule, "value").text = tagname + try: + ET.ElementTree(root).write(nodefile, xml_declaration=True) + except: + ET.ElementTree(root).write(nodefile) + + #create tag node - recent items + nodefile = os.path.join(libraryPath, tagname + "_recent.xml") + root = Element("node", {"order":"2", "type":"filter"}) + SubElement(root, "label").text = tagname + " - Recently added" + SubElement(root, "match").text = "all" + SubElement(root, "content").text = type + SubElement(root, "icon").text = "DefaultMovies.png" + Rule = SubElement(root, "rule", {"field":"tag","operator":"is"}) + SubElement(Rule, "value").text = tagname + SubElement(root, "order", {"direction":"descending"}).text = "dateadded" + #set limit to 25 --> currently hardcoded --> TODO: add a setting for this ? + SubElement(root, "limit").text = "25" + #exclude watched items --> currently hardcoded --> TODO: add a setting for this ? + Rule2 = SubElement(root, "rule", {"field":"playcount","operator":"is"}) + SubElement(Rule2, "value").text = "0" + + try: + ET.ElementTree(root).write(nodefile, xml_declaration=True) + except: + ET.ElementTree(root).write(nodefile) + + #create tag node - inprogress items + nodefile = os.path.join(libraryPath, tagname + "_progress.xml") + root = Element("node", {"order":"3", "type":"filter"}) + SubElement(root, "label").text = tagname + " - In progress" + SubElement(root, "match").text = "all" + SubElement(root, "content").text = type + SubElement(root, "icon").text = "DefaultMovies.png" + Rule = SubElement(root, "rule", {"field":"tag","operator":"is"}) + SubElement(Rule, "value").text = tagname + #set limit to 25 --> currently hardcoded --> TODO: add a setting for this ? + SubElement(root, "limit").text = "25" + Rule2 = SubElement(root, "rule", {"field":"inprogress","operator":"true"}) + + try: + ET.ElementTree(root).write(nodefile, xml_declaration=True) + except: + ET.ElementTree(root).write(nodefile) + + #add some additional nodes for episodes + if type == "tvshows": + #create tag node - recent episodes + nodefile = os.path.join(libraryPath, tagname + "_recent_episodes.xml") + root = Element("node", {"order":"3", "type":"filter"}) + SubElement(root, "label").text = tagname + " - Recently added episodes" + SubElement(root, "match").text = "all" + SubElement(root, "content").text = "episodes" + SubElement(root, "icon").text = "DefaultMovies.png" + Rule = SubElement(root, "rule", {"field":"tag","operator":"is"}) + SubElement(Rule, "value").text = tagname + SubElement(root, "order", {"direction":"descending"}).text = "dateadded" + #set limit to 25 --> currently hardcoded --> TODO: add a setting for this ? + SubElement(root, "limit").text = "25" + #exclude watched items --> currently hardcoded --> TODO: add a setting for this ? + Rule2 = SubElement(root, "rule", {"field":"playcount","operator":"is"}) + SubElement(Rule2, "value").text = "0" + + try: + ET.ElementTree(root).write(nodefile, xml_declaration=True) + except: + ET.ElementTree(root).write(nodefile) + + #create tag node - inprogress items + nodefile = os.path.join(libraryPath, tagname + "_progress_episodes.xml") + root = Element("node", {"order":"4", "type":"filter"}) + SubElement(root, "label").text = tagname + " - In progress episodes" + SubElement(root, "match").text = "all" + SubElement(root, "content").text = "episodes" + SubElement(root, "icon").text = "DefaultMovies.png" + Rule = SubElement(root, "rule", {"field":"tag","operator":"is"}) + SubElement(Rule, "value").text = tagname + #set limit to 25 --> currently hardcoded --> TODO: add a setting for this ? + SubElement(root, "limit").text = "25" + Rule2 = SubElement(root, "rule", {"field":"inprogress","operator":"true"}) + + try: + ET.ElementTree(root).write(nodefile, xml_declaration=True) + except: + ET.ElementTree(root).write(nodefile) + def updateBoxsetToKodiLibrary(self, boxsetmovie, boxset, connection, cursor): strSet = boxset["Name"] cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?",(boxsetmovie["Id"],)) From f56b154a83d307cf9223d856a67b46e4ff6bee02 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 23:11:06 +0200 Subject: [PATCH 58/66] fixed default nodes and create node dirs if not existing --- resources/lib/WriteKodiDB.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 4735e32d..b738fb0c 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -1035,6 +1035,15 @@ class WriteKodiDB(): def addVideoNodesForTag(self, tagname, type): utils.logMsg("addVideoNodesForTag", "Creating nodes for tag: " + tagname) + + # the library path doesn't exist on all systems + if not xbmcvfs.exists("special://userdata/library/"): + xbmcvfs.mkdir("special://userdata/library") + if not xbmcvfs.exists("special://userdata/library/video/"): + #we need to copy over the default items + import shutil + shutil.copytree(xbmc.translatePath("special://xbmc/system/library/video"), xbmc.translatePath("special://userdata/library/video")) + libraryPath = xbmc.translatePath("special://userdata/library/video/emby/") if type == "movie": From 5b03f6549daef52991f9e8a6f36d3f443ad9a7e7 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 23:50:36 +0200 Subject: [PATCH 59/66] don't add the emby videonodes in a parent folder because it causes issues with video node editor and skinshortcuts addons --- resources/lib/WriteKodiDB.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index b738fb0c..58115a62 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -1052,21 +1052,9 @@ class WriteKodiDB(): type = "tvshows" else: return - - if not xbmcvfs.exists(libraryPath): - #create root node - xbmcvfs.mkdir(libraryPath) - nodefile = os.path.join(libraryPath, "index.xml") - root = Element("node", {"order":"1"}) - SubElement(root, "label").text = "Emby" - SubElement(root, "icon").text = "DefaultMovies.png" - try: - ET.ElementTree(root).write(nodefile, xml_declaration=True) - except: - ET.ElementTree(root).write(nodefile) - + #tagpath - libraryPath = xbmc.translatePath("special://userdata/library/video/emby/%s/" %tagname) + libraryPath = xbmc.translatePath("special://userdata/library/video/%s/Emby - " %tagname) if not xbmcvfs.exists(libraryPath): #create tag node - index From 5ec53e032636468194449a72dbfd30fb787fe137 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 23:52:40 +0200 Subject: [PATCH 60/66] stupid typo --- resources/lib/WriteKodiDB.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 58115a62..d6c776c7 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -1054,7 +1054,7 @@ class WriteKodiDB(): return #tagpath - libraryPath = xbmc.translatePath("special://userdata/library/video/%s/Emby - " %tagname) + libraryPath = xbmc.translatePath("special://userdata/library/video/Emby - %s/" %tagname) if not xbmcvfs.exists(libraryPath): #create tag node - index From c2c5743611dc199f04fb3c154b54f49abc2534ed Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sun, 3 May 2015 23:55:49 +0200 Subject: [PATCH 61/66] also prefix the label --- resources/lib/WriteKodiDB.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index d6c776c7..2cd24d02 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -1061,7 +1061,7 @@ class WriteKodiDB(): xbmcvfs.mkdir(libraryPath) nodefile = os.path.join(libraryPath, "index.xml") root = Element("node", {"order":"1"}) - SubElement(root, "label").text = tagname + SubElement(root, "label").text = "Emby - " + tagname SubElement(root, "icon").text = "DefaultMovies.png" try: ET.ElementTree(root).write(nodefile, xml_declaration=True) From 552a9a30bd6a8f8ce57c9887201d4dc905d52df1 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Mon, 4 May 2015 00:04:10 +0200 Subject: [PATCH 62/66] sort the "all" nodes by title --- resources/lib/WriteKodiDB.py | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 2cd24d02..1da2e140 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -1075,6 +1075,7 @@ class WriteKodiDB(): SubElement(root, "match").text = "all" SubElement(root, "content").text = type SubElement(root, "icon").text = "DefaultMovies.png" + SubElement(root, "order", {"direction":"ascending"}).text = "sorttitle" Rule = SubElement(root, "rule", {"field":"tag","operator":"is"}) SubElement(Rule, "value").text = tagname try: From 501adb6e3ca82062efdf36270aa79f53981483d4 Mon Sep 17 00:00:00 2001 From: xnappo Date: Sun, 3 May 2015 18:04:24 -0500 Subject: [PATCH 63/66] Fix up date added --- resources/lib/WriteKodiDB.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 1da2e140..467d52c8 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -108,6 +108,7 @@ class WriteKodiDB(): if MBitem.get("DateCreated") != None: dateadded = MBitem["DateCreated"].replace("T"," ") dateadded = dateadded.replace(".0000000Z","") + dateadded = dateadded.split(".")[0] else: dateadded = None @@ -251,6 +252,7 @@ class WriteKodiDB(): if MBitem.get("DateCreated") != None: dateadded = MBitem["DateCreated"].replace("T"," ") dateadded = dateadded.replace(".0000000Z","") + dateadded = dateadded.split(".")[0] else: dateadded = None @@ -382,6 +384,7 @@ class WriteKodiDB(): if MBitem.get("DateCreated") != None: dateadded = MBitem["DateCreated"].replace("T"," ") dateadded = dateadded.replace(".0000000Z","") + dateadded = dateadded.split(".")[0] else: dateadded = None From 20e3d9d7acfa34b66789ea5bae8bc8783121a294 Mon Sep 17 00:00:00 2001 From: angelblue05 Date: Sun, 3 May 2015 18:09:16 -0500 Subject: [PATCH 64/66] Follow up for dateAdded --- resources/lib/WriteKodiDB.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/resources/lib/WriteKodiDB.py b/resources/lib/WriteKodiDB.py index 467d52c8..7ce70520 100644 --- a/resources/lib/WriteKodiDB.py +++ b/resources/lib/WriteKodiDB.py @@ -106,9 +106,7 @@ class WriteKodiDB(): trailerUrl = "plugin://plugin.video.emby/trailer/?id=%s&mode=play" % trailerItem[0][u'Id'] if MBitem.get("DateCreated") != None: - dateadded = MBitem["DateCreated"].replace("T"," ") - dateadded = dateadded.replace(".0000000Z","") - dateadded = dateadded.split(".")[0] + dateadded = MBitem["DateCreated"].split('.')[0].replace('T', " ") else: dateadded = None @@ -250,9 +248,7 @@ class WriteKodiDB(): track = MBitem.get("Track") if MBitem.get("DateCreated") != None: - dateadded = MBitem["DateCreated"].replace("T"," ") - dateadded = dateadded.replace(".0000000Z","") - dateadded = dateadded.split(".")[0] + dateadded = MBitem["DateCreated"].split('.')[0].replace('T', " ") else: dateadded = None @@ -382,9 +378,7 @@ class WriteKodiDB(): rating = MBitem.get("CommunityRating") if MBitem.get("DateCreated") != None: - dateadded = MBitem["DateCreated"].replace("T"," ") - dateadded = dateadded.replace(".0000000Z","") - dateadded = dateadded.split(".")[0] + dateadded = MBitem["DateCreated"].split('.')[0].replace('T', " ") else: dateadded = None From 657c8131120d2dd402f416883dbc7bfc608be59c Mon Sep 17 00:00:00 2001 From: im85288 Date: Mon, 4 May 2015 14:39:29 +0100 Subject: [PATCH 65/66] add back disable coverart option --- resources/settings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/settings.xml b/resources/settings.xml index 58975d29..b1305123 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -24,6 +24,9 @@ + + + From 1f846b13029388dcc7aed9da4c188a23808f6aa2 Mon Sep 17 00:00:00 2001 From: im85288 Date: Mon, 4 May 2015 17:34:05 +0100 Subject: [PATCH 66/66] playback from home widgets does not need the setresolvedurl method called along with xbmc.play --- resources/lib/PlaybackUtils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/lib/PlaybackUtils.py b/resources/lib/PlaybackUtils.py index b6851ddf..4dae984a 100644 --- a/resources/lib/PlaybackUtils.py +++ b/resources/lib/PlaybackUtils.py @@ -117,10 +117,11 @@ class PlaybackUtils(): if setup == "service": xbmc.Player().play(playurl,listItem) elif setup == "default": - xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) - #artwork only works from widgets with both resolvedurl and player command + #artwork only works from widgets (home screen) with player command as there is no listitem selected if xbmc.getCondVisibility("Window.IsActive(home)"): xbmc.Player().play(playurl,listItem) + else: + xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) def setArt(self, list,name,path): if name=='thumb' or name=='fanart_image' or name=='small_poster' or name=='tiny_poster' or name == "medium_landscape" or name=='medium_poster' or name=='small_fanartimage' or name=='medium_fanartimage' or name=='fanart_noindicators':