diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py
index 1973daad..e58a6a10 100644
--- a/resources/lib/PlexAPI.py
+++ b/resources/lib/PlexAPI.py
@@ -845,6 +845,7 @@ class PlexAPI():
"""
plexToken = utils.settings('plexToken')
users = self.MyPlexListHomeUsers(plexToken)
+ url = ''
# If an error is encountered, set to False
if not users:
self.logMsg("Could not get userlist from plex.tv.", 1)
@@ -1188,12 +1189,15 @@ class PlexAPI():
mediatype String or list of strings with possible values
'movie', 'show', 'artist', 'photo'
Output:
- Collection containing only mediatype. List with entry of the form:
+ List with an entry of the form:
{
'name': xxx Plex title for the media section
'type': xxx Plex type: 'movie', 'show', 'artist', 'photo'
- 'id': xxx Plex unique key for the section
+ 'id': xxx Plex unique key for the section (1, 2, 3...)
+ 'uuid': xxx Other unique Plex key, e.g.
+ 74aec9f2-a312-4723-9436-de2ea43843c1
}
+ Returns an empty list if nothing is found.
"""
collections = []
url = "{server}/library/sections"
@@ -1208,17 +1212,19 @@ class PlexAPI():
if contentType in mediatype:
name = item['title']
contentId = item['key']
+ uuid = item['uuid']
collections.append({
'name': name,
'type': contentType,
- 'id': str(contentId)
+ 'id': str(contentId),
+ 'uuid': uuid
})
return collections
def GetPlexSectionResults(self, viewId):
"""
- Returns a list (raw API dump) of all Plex movies in the Plex section
- with key = viewId.
+ Returns a list (raw JSON API dump) of all Plex items in the Plex
+ section with key = viewId.
"""
result = []
url = "{server}/library/sections/%s/all" % viewId
@@ -1226,10 +1232,17 @@ class PlexAPI():
try:
result = jsondata['_children']
except KeyError:
- self.logMsg("Error retrieving all movies for section %s" % viewId, 1)
+ self.logMsg("Error retrieving all items for Plex section %s" % viewId, 1)
pass
return result
+ def GetPlexSubitems(self, key):
+ """
+ Returns a list (raw JSON API dump) of all Plex subitems for the key.
+ (e.g. key=/library/metadata/194853/children pointing to a season)
+ """
+
+
def GetPlexMetadata(self, key):
"""
Returns raw API metadata for key.
diff --git a/resources/lib/itemtypes.py b/resources/lib/itemtypes.py
index 6c80fe64..581f9613 100644
--- a/resources/lib/itemtypes.py
+++ b/resources/lib/itemtypes.py
@@ -26,12 +26,7 @@ import PlexAPI
class Items(object):
-
- def __init__(self, embycursor, kodicursor):
-
- self.embycursor = embycursor
- self.kodicursor = kodicursor
-
+ def __init__(self):
self.clientInfo = clientinfo.ClientInfo()
self.addonName = self.clientInfo.getAddonName()
self.doUtils = downloadutils.DownloadUtils()
@@ -40,11 +35,28 @@ class Items(object):
self.directpath = utils.settings('useDirectPaths') == "1"
self.music_enabled = utils.settings('enableMusic') == "true"
self.contentmsg = utils.settings('newContent') == "true"
-
+
self.artwork = artwork.Artwork()
self.emby = embyserver.Read_EmbyServer()
- self.emby_db = embydb.Embydb_Functions(embycursor)
- self.kodi_db = kodidb.Kodidb_Functions(kodicursor)
+
+ def __enter__(self):
+ self.embyconn = utils.kodiSQL('emby')
+ self.embycursor = self.embyconn.cursor()
+ self.kodiconn = utils.kodiSQL('video')
+ self.kodicursor = self.kodiconn.cursor()
+ self.emby_db = embydb.Embydb_Functions(self.embycursor)
+ self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ """
+ Make sure DB changes are committed and connection to DB is closed.
+ """
+ self.embyconn.commit()
+ self.kodiconn.commit()
+ self.embyconn.close()
+ self.kodiconn.close()
+ return self
def logMsg(self, msg, lvl=1):
@@ -230,10 +242,6 @@ class Items(object):
class Movies(Items):
-
- def __init__(self, embycursor, kodicursor):
- Items.__init__(self, embycursor, kodicursor)
-
def added(self, items, pdialog):
total = len(items)
@@ -265,7 +273,6 @@ class Movies(Items):
count += 1
self.add_updateBoxset(boxset)
-
def add_update(self, item, viewtag=None, viewid=None):
# Process single movie
kodicursor = self.kodicursor
@@ -296,6 +303,7 @@ class Movies(Items):
kodicursor.execute("select coalesce(max(idMovie),0) from movie")
movieid = kodicursor.fetchone()[0] + 1
+
# if not viewtag or not viewid:
# # Get view tag from emby
# viewtag, viewid, mediatype = self.emby.getView_embyId(itemid)
diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py
index c358182d..73baf691 100644
--- a/resources/lib/librarysync.py
+++ b/resources/lib/librarysync.py
@@ -2,9 +2,8 @@
##################################################################################################
-import sqlite3
import threading
-from datetime import datetime, timedelta, time
+from datetime import datetime, timedelta
import xbmc
import xbmcgui
@@ -22,10 +21,171 @@ import userclient
import videonodes
import PlexAPI
+import Queue
+import time
##################################################################################################
+class ThreadedGetMetadata(threading.Thread):
+ """
+ Threaded download of Plex XML metadata for a certain library item.
+ Fills the out_queue with the downloaded etree XML objects
+
+ Input:
+ queue Queue.Queue() object that you'll need to fill up
+ with Plex itemIds
+ out_queue Queue.Queue() object where this thread will store
+ the downloaded metadata XMLs as etree objects
+ lock threading.Lock(), used for counting where we are
+ userStop Handle to a function where True is used to stop
+ this Thread
+ """
+ def __init__(self, queue, out_queue, lock, userStop):
+ self.queue = queue
+ self.out_queue = out_queue
+ self.lock = lock
+ self.userStop = userStop
+ self._shouldstop = threading.Event()
+ threading.Thread.__init__(self)
+
+ def run(self):
+ plx = PlexAPI.PlexAPI()
+ global getMetadataCount
+ while self.stopped() is False:
+ # grabs Plex item from queue
+ try:
+ itemId = self.queue.get(block=False)
+ # Empty queue
+ except:
+ continue
+ # Download Metadata
+ plexElement = plx.GetPlexMetadata(itemId)
+ # place item into out queue
+ self.out_queue.put(plexElement)
+ # Keep track of where we are at
+ with self.lock:
+ getMetadataCount += 1
+ # signals to queue job is done
+ self.queue.task_done()
+
+ def stopThread(self):
+ self._shouldstop.set()
+
+ def stopped(self):
+ return self._shouldstop.isSet() or self.userStop()
+
+
+class ThreadedProcessMetadata(threading.Thread):
+ """
+ Not yet implemented - if ever. Only to be called by ONE thread!
+ Processes the XML metadata in the queue
+
+ Input:
+ queue: Queue.Queue() object that you'll need to fill up with
+ the downloaded XML eTree objects
+ data = {
+ 'itemType': as used to call functions in itemtypes.py
+ e.g. 'Movies' => itemtypes.Movies()
+ 'viewName' Plex str for library view (e.g. 'Movies')
+ 'viewId' Plex Id to identifiy the library view
+ }
+ lock: threading.Lock(), used for counting where we are
+ userStop Handle to a function where True is used to stop this Thread
+ """
+ def __init__(self, queue, data, lock, userStop):
+ self.queue = queue
+ self.lock = lock
+ self.data = data
+ self.userStop = userStop
+ self._shouldstop = threading.Event()
+ threading.Thread.__init__(self)
+
+ def run(self):
+ # Constructs the method name, e.g. itemtypes.Movies
+ itemFkt = getattr(itemtypes, self.data['itemType'])
+ viewName = self.data['viewName']
+ viewId = self.data['viewId']
+ global processMetadataCount
+ with itemFkt() as item:
+ while self.stopped() is False:
+ # grabs item from queue
+ try:
+ plexitem = self.queue.get(block=False)
+ # Empty queue
+ except:
+ continue
+ # Do the work; lock to be sure we've only got 1 Thread
+ with self.lock:
+ item.add_update(
+ plexitem,
+ viewtag=viewName,
+ viewid=viewId
+ )
+ # Keep track of where we are at
+ processMetadataCount += 1
+ # signals to queue job is done
+ self.queue.task_done()
+
+ def stopThread(self):
+ self._shouldstop.set()
+
+ def stopped(self):
+ return self._shouldstop.isSet() or self.userStop()
+
+
+class ThreadedShowSyncInfo(threading.Thread):
+ """
+ Threaded class to show the Kodi statusbar of the metadata download.
+
+ Input:
+ dialog xbmcgui.DialogProgressBG() object to show progress
+ locks = [downloadLock, processLock] Locks() to the other threads
+ total: Total number of items to get
+ viewName: Name of library we're getting
+ """
+ def __init__(self, dialog, locks, total, viewName):
+ self.locks = locks
+ self.total = total
+ self.viewName = viewName
+ self.addonName = clientinfo.ClientInfo().getAddonName()
+ self._shouldstop = threading.Event()
+ self.dialog = dialog
+ threading.Thread.__init__(self)
+
+ def run(self):
+ total = self.total
+ downloadLock = self.locks[0]
+ processLock = self.locks[1]
+ self.dialog.create(
+ self.addonName + ": Sync " + self.viewName,
+ "Starting"
+ )
+ global getMetadataCount
+ global processMetadataCount
+ total = 2 * total
+ totalProgress = 0
+ while self.stopped() is not True:
+ with downloadLock:
+ getMetadataProgress = getMetadataCount
+ with processLock:
+ processMetadataProgress = processMetadataCount
+ totalProgress = getMetadataProgress + processMetadataProgress
+ percentage = int(float(totalProgress) / float(total)*100.0)
+ self.dialog.update(
+ percentage,
+ message="Downloaded: %s, Processed: %s" %
+ (getMetadataProgress, processMetadataProgress)
+ )
+ time.sleep(0.5)
+
+ def stopThread(self):
+ self._shouldstop.set()
+
+ def stopped(self):
+ return self._shouldstop.isSet()
+
+
class LibrarySync(threading.Thread):
_shared_state = {}
@@ -54,6 +214,7 @@ class LibrarySync(threading.Thread):
self.emby = embyserver.Read_EmbyServer()
self.vnodes = videonodes.VideoNodes()
self.plx = PlexAPI.PlexAPI()
+ self.syncThreadNumber = int(utils.settings('syncThreadNumber'))
threading.Thread.__init__(self)
@@ -84,14 +245,8 @@ class LibrarySync(threading.Thread):
# Verify if server plugin is installed.
if utils.settings('serverSync') == "true":
# Try to use fast start up
- url = "{server}/emby/Plugins?format=json"
- result = self.doUtils.downloadUrl(url)
+ completed = self.fastSync()
- for plugin in result:
- if plugin['Name'] == "Emby.Kodi Sync Queue":
- self.logMsg("Found server plugin.", 2)
- completed = self.fastSync()
-
if not completed:
# Fast sync failed or server plugin is not found
completed = self.fullSync(manualrun=True)
@@ -186,15 +341,7 @@ class LibrarySync(threading.Thread):
connection.commit()
self.logMsg("Commit successful.", 1)
- def fullSync(self, manualrun=False, repair=False):
- # Only run once when first setting up. Can be run manually.
- emby = self.emby
- music_enabled = utils.settings('enableMusic') == "true"
-
- utils.window('emby_dbScan', value="true")
- # Add sources
- utils.sourcesXML()
-
+ def initializeDBs(self):
embyconn = utils.kodiSQL('emby')
embycursor = embyconn.cursor()
# Create the tables for the emby database
@@ -210,8 +357,17 @@ class LibrarySync(threading.Thread):
embyconn.commit()
# content sync: movies, tvshows, musicvideos, music
- kodiconn = utils.kodiSQL('video')
- kodicursor = kodiconn.cursor()
+ embyconn.close()
+ return
+
+ def fullSync(self, manualrun=False, repair=False):
+ # Only run once when first setting up. Can be run manually.
+ self.compare = manualrun
+ music_enabled = utils.settings('enableMusic') == "true"
+
+ utils.window('emby_dbScan', value="true")
+ # Add sources
+ utils.sourcesXML()
if manualrun:
message = "Manual sync"
@@ -220,14 +376,13 @@ class LibrarySync(threading.Thread):
else:
message = "Initial sync"
utils.window('emby_initialScan', value="true")
-
- pDialog = self.progressDialog("%s" % message, forced=True)
+
starttotal = datetime.now()
# Set views
# self.maintainViews(embycursor, kodicursor)
# embyconn.commit()
-
+ self.initializeDBs()
# Sync video library
process = {
@@ -238,60 +393,48 @@ class LibrarySync(threading.Thread):
}
process = {
- 'movies': self.PlexMovies,
+ 'movies': self.PlexMovies
+ # 'tvshows': self.PlexTVShows
}
+
for itemtype in process:
startTime = datetime.now()
- completed = process[itemtype](embycursor, kodicursor, pDialog, compare=manualrun)
+ completed = process[itemtype]()
if not completed:
utils.window('emby_dbScan', clear=True)
- if pDialog:
- pDialog.close()
- embycursor.close()
- kodicursor.close()
return False
else:
- self.dbCommit(kodiconn)
- embyconn.commit()
elapsedTime = datetime.now() - startTime
self.logMsg(
"SyncDatabase (finished %s in: %s)"
- % (itemtype, str(elapsedTime).split('.')[0]), 1)
+ % (itemtype, str(elapsedTime).split('.')[0]), 0)
- # sync music
- if music_enabled:
+ # # sync music
+ # if music_enabled:
- musicconn = utils.kodiSQL('music')
- musiccursor = musicconn.cursor()
+ # musicconn = utils.kodiSQL('music')
+ # musiccursor = musicconn.cursor()
- startTime = datetime.now()
- completed = self.music(embycursor, musiccursor, pDialog, compare=manualrun)
- if not completed:
+ # startTime = datetime.now()
+ # completed = self.music(embycursor, musiccursor, pDialog, compare=manualrun)
+ # if not completed:
- utils.window('emby_dbScan', clear=True)
- if pDialog:
- pDialog.close()
+ # utils.window('emby_dbScan', clear=True)
- embycursor.close()
- musiccursor.close()
- return False
- else:
- musicconn.commit()
- embyconn.commit()
- elapsedTime = datetime.now() - startTime
- self.logMsg(
- "SyncDatabase (finished music in: %s)"
- % (str(elapsedTime).split('.')[0]), 1)
- musiccursor.close()
+ # embycursor.close()
+ # musiccursor.close()
+ # return False
+ # else:
+ # musicconn.commit()
+ # embyconn.commit()
+ # elapsedTime = datetime.now() - startTime
+ # self.logMsg(
+ # "SyncDatabase (finished music in: %s)"
+ # % (str(elapsedTime).split('.')[0]), 1)
+ # musiccursor.close()
- if pDialog:
- pDialog.close()
-
- embycursor.close()
- kodicursor.close()
-
utils.settings('SyncInstallRunDone', value="true")
utils.settings("dbCreatedWithVersion", self.clientInfo.getVersion())
self.saveLastSync()
@@ -465,100 +608,176 @@ class LibrarySync(threading.Thread):
# Save total
utils.window('Emby.nodes.total', str(totalnodes))
+ def GetUpdatelist(self, elementList):
+ """
+ Adds items to self.updatelist as well as self.allPlexElementsId dict
+ Input:
+ elementList: List of elements, e.g. a list of '_children'
+ movie elements as received via JSON from PMS
- def PlexMovies(self, embycursor, kodicursor, pdialog, compare=False):
+ Output: self.updatelist, self.allPlexElementsId
+ self.updatelist APPENDED(!!) list itemids (Plex Keys as
+ as received from API.getKey())
+ self.allPlexElementsId APPENDED(!!) dic
+ = {itemid: checksum}
+ """
+ if self.compare:
+ # Manual sync
+ for plexmovie in elementList:
+ if self.shouldStop():
+ return False
+ API = PlexAPI.API(plexmovie)
+ plex_checksum = API.getChecksum()
+ itemid = API.getKey()
+ self.allPlexElementsId[itemid] = plex_checksum
+ kodi_checksum = self.allKodiElementsId.get(itemid)
+ if kodi_checksum != plex_checksum:
+ # Only update if movie is not in Kodi or checksum is
+ # different
+ self.updatelist.append(itemid)
+ else:
+ # Initial or repair sync: get all Plex movies
+ for plexmovie in elementList:
+ API = PlexAPI.API(plexmovie)
+ itemid = API.getKey()
+ plex_checksum = API.getChecksum()
+ self.allPlexElementsId[itemid] = plex_checksum
+ self.updatelist.append(itemid)
+ # Update the Kodi popup info
+ return self.updatelist, self.allPlexElementsId
+
+ def PlexMovies(self):
+ # Initialize
plx = PlexAPI.PlexAPI()
+ compare = self.compare
+ self.updatelist = []
+ self.allPlexElementsId = {}
+ # Initialze DBs
+ embyconn = utils.kodiSQL('emby')
+ embycursor = embyconn.cursor()
+
# Get movies from Plex server
emby_db = embydb.Embydb_Functions(embycursor)
- movies = itemtypes.Movies(embycursor, kodicursor)
views = plx.GetPlexCollections('movie')
+ self.logMsg("Media folders: %s" % views, 1)
if compare:
# Pull the list of movies and boxsets in Kodi
try:
- all_kodimoviesId = dict(emby_db.getChecksum('Movie'))
+ self.allKodiElementsId = dict(emby_db.getChecksum('Movie'))
except ValueError:
- all_kodimoviesId = {}
- all_plexmoviesIds = {}
+ self.allKodiElementsId = {}
+ else:
+ # Getting all metadata, hence set Kodi elements to {}
+ self.allKodiElementsId = {}
+ embyconn.close()
##### PROCESS MOVIES #####
for view in views:
- updatelist = []
+ self.updatelist = []
if self.shouldStop():
return False
# Get items per view
viewId = view['id']
viewName = view['name']
- if pdialog:
- pdialog.update(
- heading=self.addonName,
- message="Gathering movies from view: %s..." % viewName
- )
all_plexmovies = plx.GetPlexSectionResults(viewId)
+ # Populate self.updatelist and self.allPlexElementsId
+ self.GetUpdatelist(all_plexmovies)
+ self.logMsg("Processed view %s with ID %s" % (viewName, viewId), 1)
- if compare:
- # Manual sync
- if pdialog:
- pdialog.update(
- heading=self.addonName,
- message="Comparing movies from view: %s..." % viewName
- )
- for plexmovie in all_plexmovies:
- if self.shouldStop():
- return False
- API = PlexAPI.API(plexmovie)
- plex_checksum = API.getChecksum()
- itemid = API.getKey()
- kodi_checksum = all_kodimoviesId.get(itemid)
- all_plexmoviesIds[itemid] = plex_checksum
- if kodi_checksum != plex_checksum:
- # Only update if movie is not in Kodi or checksum is different
- updatelist.append(itemid)
- else:
- # Initial or repair sync: get all Plex movies
- for plexmovie in all_plexmovies:
- API = PlexAPI.API(plexmovie)
- itemid = API.getKey()
- plex_checksum = API.getChecksum()
- all_plexmoviesIds[itemid] = plex_checksum
- updatelist.append(itemid)
+ self.logMsg("self.updatelist: %s" % self.updatelist, 2)
+ self.logMsg("self.allPlexElementsId: %s" % self.allPlexElementsId, 2)
+ self.logMsg("self.allKodiElementsId: %s" % self.allKodiElementsId, 2)
- total = len(updatelist)
- if pdialog:
- pdialog.update(heading="Processing %s / %s items" % (viewName, total))
+ # Run through self.updatelist, get XML metadata per item
+ # Initiate threads
+ self.logMsg("=====================", 1)
+ self.logMsg("Starting sync threads", 1)
+ self.logMsg("=====================", 1)
+ getMetadataQueue = Queue.Queue()
+ processMetadataQueue = Queue.Queue()
+ getMetadataLock = threading.Lock()
+ processMetadataLock = threading.Lock()
+ # To keep track
+ global getMetadataCount
+ getMetadataCount = 0
+ global processMetadataCount
+ processMetadataCount = 0
+ # Spawn GetMetadata threads
+ threads = []
+ for i in range(self.syncThreadNumber):
+ t = ThreadedGetMetadata(
+ getMetadataQueue,
+ processMetadataQueue,
+ getMetadataLock,
+ self.shouldStop
+ )
+ t.setDaemon(True)
+ t.start()
+ threads.append(t)
+ self.logMsg("%s download threads spawned" % self.syncThreadNumber, 1)
+ # Populate queue: GetMetadata
+ for itemId in self.updatelist:
+ getMetadataQueue.put(itemId)
+ self.logMsg("Queue populated", 1)
+ # Spawn one more thread to process Metadata, once downloaded
+ data = {
+ 'itemType': 'Movies',
+ 'viewName': viewName,
+ 'viewId': viewId
+ }
+ thread = ThreadedProcessMetadata(
+ processMetadataQueue,
+ data,
+ processMetadataLock,
+ self.shouldStop
+ )
+ thread.setDaemon(True)
+ thread.start()
+ threads.append(thread)
+ self.logMsg("Processing thread spawned", 1)
- count = 0
- for itemid in updatelist:
- # Process individual movies
- if self.shouldStop():
- return False
- # Download Metadata
- plexmovie = plx.GetPlexMetadata(itemid)
- # Check whether metadata is valid
- title = plexmovie[0].attrib['title']
- if pdialog:
- percentage = int((float(count) / float(total))*100)
- pdialog.update(percentage, message=title)
- count += 1
- # Download individual metadata
- self.logMsg("Start parsing metadata for movie: %s" % title, 0)
- movies.add_update(plexmovie, viewName, viewId)
-
- else:
- self.logMsg("Movies finished.", 2)
+ # Start one thread to show sync progress
+ dialog = xbmcgui.DialogProgressBG()
+ total = len(self.updatelist)
+ thread = ThreadedShowSyncInfo(
+ dialog,
+ [getMetadataLock, processMetadataLock],
+ total,
+ viewName
+ )
+ thread.setDaemon(True)
+ thread.start()
+ threads.append(thread)
+ self.logMsg("Kodi Infobox thread spawned", 1)
+ # Wait until finished
+ getMetadataQueue.join()
+ processMetadataQueue.join()
+ # Kill threads
+ self.logMsg("Waiting to kill threads", 1)
+ for thread in threads:
+ thread.stopThread()
+ self.logMsg("Stop sent to all threads", 1)
+ # Wait till threads are indeed dead
+ for thread in threads:
+ thread.join()
+ dialog.close()
+ self.logMsg("=====================", 1)
+ self.logMsg("Sync threads finished", 1)
+ self.logMsg("=====================", 1)
##### PROCESS DELETES #####
- self.logMsg("all_plexmoviesIds: %s" % all_plexmoviesIds, 0)
- self.logMsg("all_kodimoviesId: %s" % all_kodimoviesId, 0)
if compare:
# Manual sync, process deletes
- for kodimovie in all_kodimoviesId:
- if kodimovie not in all_plexmoviesIds:
- movies.remove(kodimovie)
- else:
- self.logMsg("Movies compare finished.", 1)
+ itemFkt = getattr(itemtypes, 'Movies')
+ with itemFkt() as item:
+ for kodimovie in self.allKodiElementsId:
+ if kodimovie not in self.allPlexElementsId:
+ item.remove(kodimovie)
+ else:
+ self.logMsg("Movies compare finished.", 1)
return True
def movies(self, embycursor, kodicursor, pdialog, compare=False):
@@ -915,6 +1134,176 @@ class LibrarySync(threading.Thread):
return True
+ def PlexTVShows(self, embycursor, kodicursor):
+ # Initialize
+ plx = PlexAPI.PlexAPI()
+ compare = self.compare
+ pdialog = self.pDialog
+ self.updatelist = []
+ self.allPlexElementsId = {}
+ # Get shows from emby
+ emby_db = embydb.Embydb_Functions(embycursor)
+ tvshows = itemtypes.TVShows(embycursor, kodicursor)
+
+ views = plx.GetPlexCollections('show')
+ self.logMsg("Media folders: %s" % views, 1)
+
+ self.allKodiElementsId = {}
+ if compare:
+ # Pull the list of TV shows already in Kodi
+ try:
+ all_koditvshows = dict(emby_db.getChecksum('Series'))
+ self.allKodiElementsId.update(all_koditvshows)
+ except ValueError:
+ pass
+ # Same for the episodes (sub-element of shows/series)
+ try:
+ all_kodiepisodes = dict(emby_db.getChecksum('Episode'))
+ self.allKodiElementsId.update(all_kodiepisodes)
+ except ValueError:
+ pass
+
+ for view in views:
+ self.updatelist = []
+ if self.shouldStop():
+ return False
+ # Get items per view
+ viewId = view['id']
+ viewName = view['name']
+ if pdialog:
+ pdialog.update(
+ heading=self.addonName,
+ message="Gathering TV Shows from view: %s..." % viewName)
+ all_plexTvShows = plx.GetPlexSectionResults(viewId)
+
+ # Populate self.updatelist with TV shows and self.allPlexElementsId
+ self.GetUpdatelist(all_plexTvShows, viewName)
+
+ # Run through self.updatelist, get XML metadata per item and safe
+ # to Kodi
+ self.ProcessUpdateList(tvshows, view)
+
+
+
+ if compare:
+ # Manual sync
+ for plexTvShow in all_plexTvShows:
+ if self.shouldStop():
+ return False
+ API = plx(plexTvShow)
+ plex_checksum = API.getChecksum()
+ itemid = API.getKey()
+ kodi_checksum = all_kodimoviesId.get(itemid)
+ all_plextvshowsIds[itemid] = itemid
+ kodi_checksum = all_koditvshows.get(itemid)
+ #if kodi_checksum != plex_checksum:
+
+
+ if all_koditvshows.get(itemid) != API.getChecksum():
+ # Only update if movie is not in Kodi or checksum is different
+ updatelist.append(itemid)
+
+ self.logMsg("TVShows to update for %s: %s" % (viewName, updatelist), 1)
+ embytvshows = emby.getFullItems(updatelist)
+ total = len(updatelist)
+ del updatelist[:]
+ else:
+ all_embytvshows = emby.getShows(viewId)
+ total = all_embytvshows['TotalRecordCount']
+ embytvshows = all_embytvshows['Items']
+
+
+ if pdialog:
+ pdialog.update(heading="Processing %s / %s items" % (viewName, total))
+
+ count = 0
+ for embytvshow in embytvshows:
+ # Process individual show
+ if self.shouldStop():
+ return False
+
+ itemid = embytvshow['Id']
+ title = embytvshow['Name']
+ if pdialog:
+ percentage = int((float(count) / float(total))*100)
+ pdialog.update(percentage, message=title)
+ count += 1
+ tvshows.add_update(embytvshow, viewName, viewId)
+
+ if not compare:
+ # Process episodes
+ all_episodes = emby.getEpisodesbyShow(itemid)
+ for episode in all_episodes['Items']:
+
+ # Process individual show
+ if self.shouldStop():
+ return False
+
+ episodetitle = episode['Name']
+ if pdialog:
+ pdialog.update(percentage, message="%s - %s" % (title, episodetitle))
+ tvshows.add_updateEpisode(episode)
+ else:
+ if compare:
+ # Get all episodes in view
+ if pdialog:
+ pdialog.update(
+ heading="Emby for Kodi",
+ message="Comparing episodes from view: %s..." % viewName)
+
+ all_embyepisodes = emby.getEpisodes(viewId, basic=True)
+ for embyepisode in all_embyepisodes['Items']:
+
+ if self.shouldStop():
+ return False
+
+ API = api.API(embyepisode)
+ itemid = embyepisode['Id']
+ all_embyepisodesIds.add(itemid)
+
+ if all_kodiepisodes.get(itemid) != API.getChecksum():
+ # Only update if movie is not in Kodi or checksum is different
+ updatelist.append(itemid)
+
+ self.logMsg("Episodes to update for %s: %s" % (viewName, updatelist), 1)
+ embyepisodes = emby.getFullItems(updatelist)
+ total = len(updatelist)
+ del updatelist[:]
+
+ count = 0
+ for episode in embyepisodes:
+
+ # Process individual episode
+ if self.shouldStop():
+ return False
+
+ title = episode['SeriesName']
+ episodetitle = episode['Name']
+ if pdialog:
+ percentage = int((float(count) / float(total))*100)
+ pdialog.update(percentage, message="%s - %s" % (title, episodetitle))
+ count += 1
+ tvshows.add_updateEpisode(episode)
+ else:
+ self.logMsg("TVShows finished.", 2)
+
+ ##### PROCESS DELETES #####
+ if compare:
+ # Manual sync, process deletes
+ for koditvshow in all_koditvshows:
+ if koditvshow not in all_embytvshowsIds:
+ tvshows.remove(koditvshow)
+ else:
+ self.logMsg("TVShows compare finished.", 1)
+
+ for kodiepisode in all_kodiepisodes:
+ if kodiepisode not in all_embyepisodesIds:
+ tvshows.remove(kodiepisode)
+ else:
+ self.logMsg("Episodes compare finished.", 1)
+
+ return True
+
def tvshows(self, embycursor, kodicursor, pdialog, compare=False):
# Get shows from emby
emby = self.emby
@@ -1117,16 +1506,11 @@ class LibrarySync(threading.Thread):
for type in types:
if pdialog:
- pdialog.update(
- heading="Emby for Kodi",
- message="Gathering %s..." % type)
-
+ pass
if compare:
# Manual Sync
if pdialog:
- pdialog.update(
- heading="Emby for Kodi",
- message="Comparing %s..." % type)
+ pass
if type != "artists":
all_embyitems = process[type][0](basic=True)
@@ -1165,7 +1549,7 @@ class LibrarySync(threading.Thread):
embyitems = all_embyitems['Items']
if pdialog:
- pdialog.update(heading="Processing %s / %s items" % (type, total))
+ pass
count = 0
for embyitem in embyitems:
diff --git a/resources/settings.xml b/resources/settings.xml
index 0ca045cb..ee1d9e78 100644
--- a/resources/settings.xml
+++ b/resources/settings.xml
@@ -68,5 +68,6 @@
+