2015-03-14 08:24:59 +11:00
|
|
|
#################################################################################################
|
|
|
|
# LibrarySync
|
|
|
|
#################################################################################################
|
|
|
|
|
|
|
|
import xbmc
|
|
|
|
import xbmcgui
|
|
|
|
import xbmcaddon
|
|
|
|
import xbmcvfs
|
|
|
|
import json
|
2015-03-14 11:46:54 +11:00
|
|
|
import sqlite3
|
2015-03-17 04:51:49 +11:00
|
|
|
import inspect
|
2015-03-14 08:24:59 +11:00
|
|
|
import threading
|
|
|
|
import urllib
|
|
|
|
from datetime import datetime, timedelta, time
|
2015-05-01 21:30:21 +10:00
|
|
|
from itertools import chain
|
2015-03-14 08:24:59 +11:00
|
|
|
import urllib2
|
|
|
|
import os
|
2015-03-14 09:39:35 +11:00
|
|
|
|
2015-03-14 08:24:59 +11:00
|
|
|
from API import API
|
|
|
|
import Utils as utils
|
|
|
|
from DownloadUtils import DownloadUtils
|
2015-03-18 04:51:45 +11:00
|
|
|
from ReadEmbyDB import ReadEmbyDB
|
2015-03-18 05:41:26 +11:00
|
|
|
from ReadKodiDB import ReadKodiDB
|
2015-03-18 06:02:42 +11:00
|
|
|
from WriteKodiDB import WriteKodiDB
|
2015-03-14 08:24:59 +11:00
|
|
|
|
2015-03-26 04:37:21 +11:00
|
|
|
addondir = xbmc.translatePath(xbmcaddon.Addon(id='plugin.video.emby').getAddonInfo('profile'))
|
2015-03-14 08:24:59 +11:00
|
|
|
dataPath = os.path.join(addondir,"library")
|
2015-03-15 09:33:16 +11:00
|
|
|
movieLibrary = os.path.join(dataPath,'movies')
|
|
|
|
tvLibrary = os.path.join(dataPath,'tvshows')
|
2015-03-14 08:24:59 +11:00
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
WINDOW = xbmcgui.Window( 10000 )
|
|
|
|
|
2015-03-14 08:24:59 +11:00
|
|
|
class LibrarySync():
|
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
def FullLibrarySync(self):
|
|
|
|
|
2015-03-27 11:16:45 +11:00
|
|
|
#set some variable to check if this is the first run
|
2015-03-26 04:37:21 +11:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-05-02 19:56:31 +10:00
|
|
|
|
2015-03-27 11:16:45 +11:00
|
|
|
startupDone = WINDOW.getProperty("startup") == "done"
|
|
|
|
syncInstallRunDone = addon.getSetting("SyncInstallRunDone") == "true"
|
2015-05-03 03:49:39 +10:00
|
|
|
dbSyncIndication = addon.getSetting("dbSyncIndication") == "true"
|
2015-04-03 19:39:16 +11:00
|
|
|
WINDOW.setProperty("SyncDatabaseRunning", "true")
|
2015-03-27 11:16:45 +11:00
|
|
|
|
2015-05-03 03:49:39 +10:00
|
|
|
|
|
|
|
#show the progress dialog
|
|
|
|
pDialog = None
|
|
|
|
if (syncInstallRunDone == False or dbSyncIndication):
|
|
|
|
pDialog = xbmcgui.DialogProgressBG()
|
|
|
|
pDialog.create('Emby for Kodi', 'Performing full sync')
|
|
|
|
|
2015-04-03 19:39:16 +11:00
|
|
|
if(WINDOW.getProperty("SyncDatabaseShouldStop") == "true"):
|
|
|
|
utils.logMsg("Sync Database", "Can not start SyncDatabaseShouldStop=True", 0)
|
|
|
|
return True
|
|
|
|
|
|
|
|
try:
|
|
|
|
completed = True
|
2015-04-05 03:20:48 +10:00
|
|
|
connection = utils.KodiSQL()
|
|
|
|
cursor = connection.cursor()
|
2015-05-01 21:30:21 +10:00
|
|
|
|
2015-05-02 11:47:05 +10:00
|
|
|
#Add the special emby table
|
|
|
|
if not startupDone:
|
2015-05-02 10:26:06 +10:00
|
|
|
cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT, kodi_id INTEGER, media_type TEXT, checksum TEXT, parent_id INTEGER)")
|
2015-05-01 21:30:21 +10:00
|
|
|
connection.commit()
|
|
|
|
|
2015-04-03 19:39:16 +11:00
|
|
|
# sync movies
|
2015-05-02 19:56:31 +10:00
|
|
|
self.MoviesFullSync(connection,cursor,pDialog)
|
2015-05-03 03:49:39 +10:00
|
|
|
|
|
|
|
if (self.ShouldStop()):
|
|
|
|
return False
|
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
#sync Tvshows and episodes
|
2015-05-02 19:56:31 +10:00
|
|
|
self.TvShowsFullSync(connection,cursor,pDialog)
|
2015-05-01 21:30:21 +10:00
|
|
|
|
2015-04-03 19:39:16 +11:00
|
|
|
# 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")
|
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
# Force refresh the library
|
|
|
|
xbmc.executebuiltin("UpdateLibrary(video)")
|
|
|
|
|
2015-04-03 19:39:16 +11:00
|
|
|
# set prop to show we have run for the first time
|
|
|
|
WINDOW.setProperty("startup", "done")
|
|
|
|
|
|
|
|
finally:
|
|
|
|
WINDOW.setProperty("SyncDatabaseRunning", "false")
|
2015-04-05 09:59:15 +10:00
|
|
|
utils.logMsg("Sync DB", "syncDatabase Exiting", 0)
|
2015-04-05 03:20:48 +10:00
|
|
|
cursor.close()
|
2015-05-02 19:56:31 +10:00
|
|
|
|
|
|
|
if(pDialog != None):
|
|
|
|
pDialog.close()
|
|
|
|
|
2015-03-19 07:34:52 +11:00
|
|
|
return True
|
2015-05-01 21:30:21 +10:00
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
def MoviesFullSync(self,connection,cursor, pDialog):
|
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
views = ReadEmbyDB().getCollections("movies")
|
|
|
|
|
|
|
|
allKodiMovieIds = list()
|
|
|
|
allEmbyMovieIds = list()
|
|
|
|
|
|
|
|
for view in views:
|
2015-03-19 02:47:55 +11:00
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
allEmbyMovies = ReadEmbyDB().getMovies(view.get('id'))
|
2015-05-01 21:30:21 +10:00
|
|
|
allKodiMovies = ReadKodiDB().getKodiMovies(connection, cursor)
|
2015-05-02 11:47:05 +10:00
|
|
|
|
|
|
|
for kodimovie in allKodiMovies:
|
|
|
|
allKodiMovieIds.append(kodimovie[1])
|
2015-05-02 19:56:31 +10:00
|
|
|
|
|
|
|
total = len(allEmbyMovies) + 1
|
|
|
|
count = 1
|
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
#### PROCESS ADDS AND UPDATES ###
|
2015-05-02 19:56:31 +10:00
|
|
|
for item in allEmbyMovies:
|
2015-05-03 03:49:39 +10:00
|
|
|
|
|
|
|
if (self.ShouldStop()):
|
|
|
|
return False
|
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
if not item.get('IsFolder'):
|
|
|
|
allEmbyMovieIds.append(item["Id"])
|
2015-03-19 02:47:55 +11:00
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
if(pDialog != None):
|
|
|
|
progressTitle = "Processing " + view.get('title') + " (" + str(count) + " of " + str(total) + ")"
|
|
|
|
pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle)
|
2015-05-02 20:51:46 +10:00
|
|
|
count += 1
|
2015-05-02 19:56:31 +10:00
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
kodiMovie = None
|
|
|
|
for kodimovie in allKodiMovies:
|
|
|
|
if kodimovie[1] == item["Id"]:
|
|
|
|
kodiMovie = kodimovie
|
|
|
|
|
|
|
|
if kodiMovie == None:
|
|
|
|
WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title'))
|
|
|
|
else:
|
2015-05-02 19:56:31 +10:00
|
|
|
if kodiMovie[2] != API().getChecksum(item):
|
2015-05-01 21:30:21 +10:00
|
|
|
WriteKodiDB().addOrUpdateMovieToKodiLibrary(item["Id"],connection, cursor, view.get('title'))
|
|
|
|
|
2015-05-02 20:51:46 +10:00
|
|
|
#### PROCESS DELETES #####
|
|
|
|
allEmbyMovieIds = set(allEmbyMovieIds)
|
|
|
|
for kodiId in allKodiMovieIds:
|
|
|
|
if not kodiId in allEmbyMovieIds:
|
|
|
|
WINDOW.setProperty(kodiId,"deleted")
|
|
|
|
WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
|
2015-05-01 21:30:21 +10:00
|
|
|
|
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
def TvShowsFullSync(self,connection,cursor,pDialog):
|
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
views = ReadEmbyDB().getCollections("tvshows")
|
2015-03-19 04:00:38 +11:00
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
allKodiTvShowIds = list()
|
|
|
|
allEmbyTvShowIds = list()
|
2015-05-02 11:47:05 +10:00
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
for view in views:
|
2015-03-20 19:15:06 +11:00
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
allEmbyTvShows = ReadEmbyDB().getTvShows(view.get('id'))
|
|
|
|
allKodiTvShows = ReadKodiDB().getKodiTvShows(connection, cursor)
|
2015-05-02 11:47:05 +10:00
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
total = len(allEmbyTvShows) + 1
|
|
|
|
count = 1
|
|
|
|
|
2015-05-02 11:47:05 +10:00
|
|
|
for kodishow in allKodiTvShows:
|
|
|
|
allKodiTvShowIds.append(kodishow[1])
|
|
|
|
|
2015-04-16 10:44:43 +10:00
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
#### TVSHOW: PROCESS ADDS AND UPDATES ###
|
|
|
|
for item in allEmbyTvShows:
|
2015-05-03 03:49:39 +10:00
|
|
|
|
|
|
|
if (self.ShouldStop()):
|
|
|
|
return False
|
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
if item.get('IsFolder') and item.get('RecursiveItemCount') != 0:
|
|
|
|
allEmbyTvShowIds.append(item["Id"])
|
2015-03-19 08:38:02 +11:00
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
if(pDialog != None):
|
|
|
|
progressTitle = "Processing " + view.get('title') + " (" + str(count) + " of " + str(total) + ")"
|
|
|
|
pDialog.update(0, "Emby for Kodi - Running Sync", progressTitle)
|
2015-05-02 20:51:46 +10:00
|
|
|
count += 1
|
2015-05-02 19:56:31 +10:00
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
#build a list with all Id's and get the existing entry (if exists) in Kodi DB
|
|
|
|
kodiShow = None
|
|
|
|
for kodishow in allKodiTvShows:
|
|
|
|
if kodishow[1] == item["Id"]:
|
|
|
|
kodiShow = kodishow
|
|
|
|
|
|
|
|
if kodiShow == None:
|
|
|
|
# Tv show doesn't exist in Kodi yet so proceed and add it
|
2015-05-02 22:57:43 +10:00
|
|
|
WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title'))
|
2015-05-01 21:30:21 +10:00
|
|
|
else:
|
|
|
|
# If there are changes to the item, perform a full sync of the item
|
2015-05-02 19:56:31 +10:00
|
|
|
if kodiShow[2] != API().getChecksum(item):
|
2015-05-01 21:30:21 +10:00
|
|
|
WriteKodiDB().addOrUpdateTvShowToKodiLibrary(item["Id"],connection, cursor, view.get('title'))
|
2015-04-05 07:48:02 +10:00
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
#### PROCESS EPISODES ######
|
2015-05-02 22:57:43 +10:00
|
|
|
self.EpisodesFullSync(connection,cursor,item["Id"])
|
2015-05-01 21:30:21 +10:00
|
|
|
|
2015-05-02 20:51:46 +10:00
|
|
|
#### TVSHOW: PROCESS DELETES #####
|
|
|
|
allEmbyTvShowIds = set(allEmbyTvShowIds)
|
|
|
|
for kodiId in allKodiTvShowIds:
|
|
|
|
if not kodiId in allEmbyTvShowIds:
|
|
|
|
WINDOW.setProperty(kodiId,"deleted")
|
|
|
|
WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
|
2015-05-01 21:30:21 +10:00
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
|
2015-05-02 22:57:43 +10:00
|
|
|
def EpisodesFullSync(self,connection,cursor,showId):
|
2015-05-01 21:30:21 +10:00
|
|
|
|
|
|
|
WINDOW = xbmcgui.Window( 10000 )
|
|
|
|
|
|
|
|
allKodiEpisodeIds = list()
|
|
|
|
allEmbyEpisodeIds = list()
|
2015-03-19 04:00:38 +11:00
|
|
|
|
2015-05-02 22:57:43 +10:00
|
|
|
#get the kodi parent id
|
|
|
|
cursor.execute("SELECT kodi_id FROM emby WHERE emby_id=?",(showId,))
|
|
|
|
kodiShowId = cursor.fetchone()[0]
|
|
|
|
|
|
|
|
allEmbyEpisodes = ReadEmbyDB().getEpisodes(showId)
|
2015-05-01 21:30:21 +10:00
|
|
|
allKodiEpisodes = ReadKodiDB().getKodiEpisodes(connection, cursor, kodiShowId)
|
2015-05-02 11:47:05 +10:00
|
|
|
|
|
|
|
for kodiepisode in allKodiEpisodes:
|
|
|
|
allKodiEpisodeIds.append(kodiepisode[1])
|
2015-05-01 21:30:21 +10:00
|
|
|
|
|
|
|
#### EPISODES: PROCESS ADDS AND UPDATES ###
|
|
|
|
for item in allEmbyEpisodes:
|
2015-05-03 03:49:39 +10:00
|
|
|
|
|
|
|
if (self.ShouldStop()):
|
|
|
|
return False
|
|
|
|
|
2015-05-01 21:30:21 +10:00
|
|
|
allEmbyEpisodeIds.append(item["Id"])
|
|
|
|
|
2015-05-02 11:47:05 +10:00
|
|
|
#get the existing entry (if exists) in Kodi DB
|
2015-05-01 21:30:21 +10:00
|
|
|
kodiEpisode = None
|
|
|
|
for kodiepisode in allKodiEpisodes:
|
|
|
|
if kodiepisode[1] == item["Id"]:
|
|
|
|
kodiEpisode = kodiepisode
|
|
|
|
|
|
|
|
if kodiEpisode == None:
|
|
|
|
# Episode doesn't exist in Kodi yet so proceed and add it
|
|
|
|
WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor)
|
|
|
|
else:
|
|
|
|
# If there are changes to the item, perform a full sync of the item
|
2015-05-02 19:56:31 +10:00
|
|
|
if kodiEpisode[2] != API().getChecksum(item):
|
2015-05-02 22:57:43 +10:00
|
|
|
print "previous checksum--> " + kodiEpisode[2]
|
|
|
|
print "new checksum--> " + API().getChecksum(item)
|
2015-05-02 05:15:43 +10:00
|
|
|
WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(item["Id"], kodiShowId, connection, cursor)
|
2015-05-01 21:30:21 +10:00
|
|
|
|
|
|
|
#### EPISODES: PROCESS DELETES #####
|
|
|
|
allEmbyEpisodeIds = set(allEmbyEpisodeIds)
|
|
|
|
for kodiId in allKodiEpisodeIds:
|
2015-05-02 11:47:05 +10:00
|
|
|
if (not kodiId in allEmbyEpisodeIds):
|
2015-05-01 21:30:21 +10:00
|
|
|
WINDOW.setProperty(kodiId,"deleted")
|
2015-05-02 19:56:31 +10:00
|
|
|
WriteKodiDB().deleteItemFromKodiLibrary(kodiId, connection, cursor)
|
2015-03-19 04:00:38 +11:00
|
|
|
|
2015-03-22 00:31:30 +11:00
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
def IncrementalSync(self, itemList):
|
|
|
|
#this will only perform sync for items received by the websocket
|
2015-05-03 03:49:39 +10:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
|
|
|
dbSyncIndication = addon.getSetting("dbSyncIndication") == "true"
|
|
|
|
WINDOW.setProperty("SyncDatabaseRunning", "true")
|
2015-03-22 00:31:30 +11:00
|
|
|
|
2015-05-03 03:49:39 +10:00
|
|
|
#show the progress dialog
|
|
|
|
pDialog = None
|
|
|
|
if (dbSyncIndication):
|
|
|
|
pDialog = xbmcgui.DialogProgressBG()
|
|
|
|
pDialog.create('Emby for Kodi', 'Performing incremental sync...')
|
2015-03-22 00:31:30 +11:00
|
|
|
|
2015-05-02 19:56:31 +10:00
|
|
|
connection = utils.KodiSQL()
|
|
|
|
cursor = connection.cursor()
|
2015-03-22 00:31:30 +11:00
|
|
|
|
2015-05-02 20:51:46 +10:00
|
|
|
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:
|
2015-03-22 00:31:30 +11:00
|
|
|
|
2015-05-02 20:51:46 +10:00
|
|
|
MBitem = ReadEmbyDB().getItem(item)
|
|
|
|
if MBitem["Type"] == "Episode":
|
2015-05-02 21:47:04 +10:00
|
|
|
|
2015-05-02 20:51:46 +10:00
|
|
|
#get the tv show
|
|
|
|
cursor.execute("SELECT kodi_id FROM emby WHERE media_type='tvshow' AND emby_id=?", (MBitem["SeriesId"],))
|
2015-05-02 21:47:04 +10:00
|
|
|
result = cursor.fetchone()
|
2015-05-02 20:51:46 +10:00
|
|
|
if result:
|
|
|
|
kodi_show_id = result[0]
|
|
|
|
else:
|
|
|
|
kodi_show_id = None
|
2015-05-02 21:47:04 +10:00
|
|
|
|
2015-05-02 20:51:46 +10:00
|
|
|
if kodi_show_id:
|
2015-05-02 21:47:04 +10:00
|
|
|
WriteKodiDB().addOrUpdateEpisodeToKodiLibrary(MBitem["Id"], kodi_show_id, connection, cursor)
|
2015-05-02 20:51:46 +10:00
|
|
|
finally:
|
|
|
|
cursor.close()
|
2015-05-02 21:47:04 +10:00
|
|
|
xbmc.executebuiltin("UpdateLibrary(video)")
|
2015-05-03 03:49:39 +10:00
|
|
|
WINDOW.setProperty("SyncDatabaseRunning", "false")
|
2015-05-02 19:56:31 +10:00
|
|
|
|
2015-05-02 20:51:46 +10:00
|
|
|
#close the progress dialog
|
2015-05-02 19:56:31 +10:00
|
|
|
if(pDialog != None):
|
|
|
|
pDialog.close()
|
|
|
|
|
2015-05-03 03:49:39 +10:00
|
|
|
def ShouldStop(self):
|
|
|
|
|
|
|
|
if(xbmc.abortRequested):
|
2015-03-16 14:10:41 +11:00
|
|
|
return True
|
2015-04-03 19:39:16 +11:00
|
|
|
|
|
|
|
if(WINDOW.getProperty("SyncDatabaseShouldStop") == "true"):
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
2015-03-17 04:51:49 +11:00
|
|
|
|
2015-03-16 04:14:23 +11:00
|
|
|
|
|
|
|
|
|
|
|
|