TV shows sync v0.1

This commit is contained in:
tomkat83 2016-01-09 16:14:02 +01:00
parent b3f588fd71
commit 5da6b4153e
3 changed files with 271 additions and 466 deletions

View file

@ -1232,16 +1232,46 @@ class PlexAPI():
try: try:
result = jsondata['_children'] result = jsondata['_children']
except KeyError: except KeyError:
self.logMsg("Error retrieving all items for Plex section %s" % viewId, 1) self.logMsg("Error retrieving all items for Plex section %s" % viewId, -1)
pass pass
return result return result
def GetPlexSubitems(self, key): def GetAllPlexLeaves(self, key):
""" """
Returns a list (raw JSON API dump) of all Plex subitems for the 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) (e.g. /library/metadata/194853/allLeaves pointing to all episodes
""" of a TV show)
Input:
key Key to a Plex item, e.g. 12345
"""
result = []
url = "{server}/library/metadata/%s/allLeaves" % key
jsondata = self.doUtils.downloadUrl(url)
try:
result = jsondata['_children']
except KeyError:
self.logMsg("Error retrieving all children for Plex item %s" % key, -1)
pass
return result
def GetAllPlexChildren(self, key):
"""
Returns a list (raw JSON API dump) of all Plex children for the key.
(e.g. /library/metadata/194853/children pointing to a season)
Input:
key Key to a Plex item, e.g. 12345
"""
result = []
url = "{server}/library/metadata/%s/children" % key
jsondata = self.doUtils.downloadUrl(url)
try:
result = jsondata['_children']
except KeyError:
self.logMsg("Error retrieving all children for Plex item %s" % key, -1)
pass
return result
def GetPlexMetadata(self, key): def GetPlexMetadata(self, key):
""" """
@ -1270,7 +1300,7 @@ class PlexAPI():
headerOptions = {'Accept': 'application/xml'} headerOptions = {'Accept': 'application/xml'}
xml = self.doUtils.downloadUrl(url, headerOptions=headerOptions) xml = self.doUtils.downloadUrl(url, headerOptions=headerOptions)
if not xml: if not xml:
self.logMsg("Error retrieving metadata for %s" % url, 1) self.logMsg("Error retrieving metadata for %s" % url, -1)
return xml return xml
@ -1388,17 +1418,23 @@ class API():
Returns the Plex unique movie id as a str, not int Returns the Plex unique movie id as a str, not int
""" """
item = self.item item = self.item
key_regex = re.compile(r'/(\d+)$')
# XML # XML
try: try:
item = item[self.child].attrib item = item[self.child].attrib
# JSON # JSON
except KeyError: except KeyError:
pass pass
key = item['key'] key = item['ratingKey']
key = key_regex.findall(key)[0]
return str(key) return str(key)
def getIndex(self):
"""
Returns the 'index' of an PMS XML reply. Depicts e.g. season number.
"""
item = self.item[self.child].attrib
index = item['index']
return str(index)
def getDateCreated(self): def getDateCreated(self):
""" """
Returns the date when this library item was created Returns the date when this library item was created
@ -1550,33 +1586,19 @@ class API():
genre.append(child.attrib['tag']) genre.append(child.attrib['tag'])
return genre return genre
def getProvider(self, providername): def getProvider(self, providername=None):
""" """
providername: imdb, tvdb, musicBrainzArtist, musicBrainzAlbum, providername: depricated
musicBrainzTrackId
Return IMDB: "tt1234567". Returns None if not found Return IMDB, e.g. "imdb://tt0903624?lang=en". Returns None if not found
""" """
item = self.item item = self.item
item = item[self.child].attrib item = item[self.child].attrib
imdb_regex = re.compile(r'''( regex = re.compile(r'''com.plexapp.agents.(.+)$''')
imdb:// # imdb tag, which will be followed be tt1234567
(tt\d{7}) # actual IMDB ID, e.g. tt1234567 provider = regex.findall(item['guid'])
\?? # zero or one ?
(.*) # rest, e.g. language setting
)''', re.VERBOSE)
try: try:
if "Imdb" in providername: provider = provider[0]
provider = imdb_regex.findall(item['guid'])
provider = provider[0][1]
elif "tvdb" in providername:
provider = item['ProviderIds']['Tvdb']
elif "musicBrainzArtist" in providername:
provider = item['ProviderIds']['MusicBrainzArtist']
elif "musicBrainzAlbum" in providername:
provider = item['ProviderIds']['MusicBrainzAlbum']
elif "musicBrainzTrackId" in providername:
provider = item['ProviderIds']['MusicBrainzTrackId']
except: except:
provider = None provider = None
return provider return provider
@ -1752,6 +1774,25 @@ class API():
string = " / ".join(listobject) string = " / ".join(listobject)
return string return string
def getEpisodeDetails(self):
"""
Call on a single episode.
Output: for the corresponding the TV show and season:
[
TV show key, Plex: 'grandparentRatingKey'
TV show title, Plex: 'grandparentTitle'
TV show season, Plex: 'parentIndex'
Episode number, Plex: 'index'
]
"""
item = self.item[self.child].attrib
key = item['grandparentRatingKey']
title = item['grandparentTitle']
season = item['parentIndex']
episode = item['index']
return key, title, season, episode
def getFilePath(self): def getFilePath(self):
""" """
returns the path to the Plex object, e.g. "/library/metadata/221803" returns the path to the Plex object, e.g. "/library/metadata/221803"

View file

@ -1173,12 +1173,8 @@ class MusicVideos(Items):
self.logMsg("Deleted musicvideo %s from kodi database" % itemid, 1) self.logMsg("Deleted musicvideo %s from kodi database" % itemid, 1)
class TVShows(Items): class TVShows(Items):
def __init__(self, embycursor, kodicursor):
Items.__init__(self, embycursor, kodicursor)
def added(self, items, pdialog): def added(self, items, pdialog):
total = len(items) total = len(items)
@ -1233,15 +1229,18 @@ class TVShows(Items):
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
API = api.API(item) API = PlexAPI.API(item)
if utils.settings('syncEmptyShows') == "false" and not item['RecursiveItemCount']: # if utils.settings('syncEmptyShows') == "false" and not item['RecursiveItemCount']:
self.logMsg("Skipping empty show: %s" % item['Name'], 1) # self.logMsg("Skipping empty show: %s" % item['Name'], 1)
return # return
# If the item already exist in the local Kodi DB we'll perform a full item update # If the item already exist in the local Kodi DB we'll perform a full item update
# If the item doesn't exist, we'll add it to the database # If the item doesn't exist, we'll add it to the database
update_item = True update_item = True
itemid = item['Id'] itemid = API.getKey()
if not itemid:
self.logMsg("Cannot parse XML data for TV show", -1)
return
emby_dbitem = emby_db.getItem_byId(itemid) emby_dbitem = emby_db.getItem_byId(itemid)
try: try:
showid = emby_dbitem[0] showid = emby_dbitem[0]
@ -1252,31 +1251,28 @@ class TVShows(Items):
update_item = False update_item = False
self.logMsg("showid: %s not found." % itemid, 2) self.logMsg("showid: %s not found." % itemid, 2)
if viewtag is None or viewid is None: # if viewtag is None or viewid is None:
# Get view tag from emby # # Get view tag from emby
viewtag, viewid, mediatype = emby.getView_embyId(itemid) # viewtag, viewid, mediatype = emby.getView_embyId(itemid)
self.logMsg("View tag found: %s" % viewtag, 2) # self.logMsg("View tag found: %s" % viewtag, 2)
# fileId information # fileId information
checksum = API.getChecksum() checksum = API.getChecksum()
dateadded = API.getDateCreated()
userdata = API.getUserData()
playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate']
# item details # item details
genres = item['Genres'] genres = API.getGenres()
title = item['Name'] title, sorttitle = API.getTitle()
plot = API.getOverview() plot = API.getPlot()
rating = item.get('CommunityRating') rating = API.getAudienceRating()
premieredate = API.getPremiereDate() premieredate = API.getPremiereDate()
tvdb = API.getProvider('Tvdb') tvdb = API.getProvider('Tvdb')
sorttitle = item['SortName']
mpaa = API.getMpaa() mpaa = API.getMpaa()
genre = " / ".join(genres) genre = API.joinList(genres)
studios = API.getStudios() studios = API.getStudios()
studio = " / ".join(studios) try:
studio = studios[0]
except IndexError:
studio = None
##### GET THE FILE AND PATH ##### ##### GET THE FILE AND PATH #####
playurl = API.getFilePath() playurl = API.getFilePath()
@ -1380,76 +1376,78 @@ class TVShows(Items):
kodicursor.execute(query, (path, None, None, 1, pathid)) kodicursor.execute(query, (path, None, None, 1, pathid))
# Process cast # Process cast
people = artwork.getPeopleArtwork(item['People']) people = API.getPeopleList()
kodi_db.addPeople(showid, people, "tvshow") kodi_db.addPeople(showid, people, "tvshow")
# Process genres # Process genres
kodi_db.addGenres(showid, genres, "tvshow") kodi_db.addGenres(showid, genres, "tvshow")
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), showid, "tvshow", kodicursor) allartworks = API.getAllArtwork()
artwork.addArtwork(allartworks, showid, "tvshow", kodicursor)
# Process studios # Process studios
kodi_db.addStudios(showid, studios, "tvshow") kodi_db.addStudios(showid, studios, "tvshow")
# Process tags: view, emby tags # Process tags: view, emby tags
tags = [viewtag] # tags = [viewtag]
tags.extend(item['Tags']) # tags.extend(item['Tags'])
if userdata['Favorite']: # if userdata['Favorite']:
tags.append("Favorite tvshows") # tags.append("Favorite tvshows")
kodi_db.addTags(showid, tags, "tvshow") # kodi_db.addTags(showid, tags, "tvshow")
# Process seasons # Process seasons
all_seasons = emby.getSeasons(itemid)
for season in all_seasons['Items']: def refreshSeasonEntry(self, item, showid):
self.add_updateSeason(season, showid=showid) API = PlexAPI.API(item)
else: kodicursor = self.kodicursor
kodi_db = self.kodi_db
# Finally, refresh the all season entry # Finally, refresh the all season entry
seasonid = kodi_db.addSeason(showid, -1) seasonid = kodi_db.addSeason(showid, -1)
# Process artwork # Process artwork for season
artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor) allartworks = API.getAllArtwork()
artwork.addArtwork(allartworks, seasonid, "season", kodicursor)
def add_updateSeason(self, item, showid=None):
def add_updateSeason(self, item, viewid=None, viewtag=None):
self.logMsg("add_updateSeason called with", 1)
self.logMsg("item: %s" % item, 1)
self.logMsg("viewid: %s" % viewid, 1)
self.logMsg("viewName: %s" % viewtag, 1)
showid = viewid
itemid = viewid
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
API = PlexAPI.API(item)
self.logMsg("add_updateSeason initialization done", 1)
if item['LocationType'] == "Virtual": seasonnum = API.getIndex()
self.logMsg("Skipping virtual season.") self.logMsg("seasonnum: %s" % seasonnum, 1)
return
seasonnum = item.get('IndexNumber', 1)
itemid = item['Id']
if showid is None:
try:
seriesId = item['SeriesId']
showid = emby_db.getItem_byId(seriesId)[0]
except KeyError:
return
except TypeError:
# Show is missing, update show instead.
show = self.emby.getItem(seriesId)
self.add_update(show)
return
seasonid = kodi_db.addSeason(showid, seasonnum) seasonid = kodi_db.addSeason(showid, seasonnum)
self.logMsg("seasonid: %s" % seasonid, 1)
# Create the reference in emby table # Create the reference in emby table
emby_db.addReference(itemid, seasonid, "Season", "season", parentid=showid) emby_db.addReference(itemid, seasonid, "Season", "season", parentid=showid)
self.logMsg("Added db reference", 1)
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor) allartworks = API.getAllArtwork()
self.logMsg("Gotten allartworks: %s" % allartworks, 1)
artwork.addArtwork(allartworks, seasonid, "season", kodicursor)
self.logMsg("Added Artwork reference", 1)
def add_updateEpisode(self, item): def add_updateEpisode(self, item, viewtag=None, viewid=None):
"""
viewtag and viewid are irrelevant!
"""
# Process single episode # Process single episode
kodiversion = self.kodiversion kodiversion = self.kodiversion
kodicursor = self.kodicursor kodicursor = self.kodicursor
emby_db = self.emby_db emby_db = self.emby_db
kodi_db = self.kodi_db kodi_db = self.kodi_db
artwork = self.artwork artwork = self.artwork
API = api.API(item) API = PlexAPI.API(item)
# If the item already exist in the local Kodi DB we'll perform a full item update # If the item already exist in the local Kodi DB we'll perform a full item update
# If the item doesn't exist, we'll add it to the database # If the item doesn't exist, we'll add it to the database
update_item = True update_item = True
itemid = item['Id'] itemid = API.getKey()
self.logMsg("itemid: %s" % itemid, 2)
emby_dbitem = emby_db.getItem_byId(itemid) emby_dbitem = emby_db.getItem_byId(itemid)
try: try:
episodeid = emby_dbitem[0] episodeid = emby_dbitem[0]
@ -1472,20 +1470,19 @@ class TVShows(Items):
dateplayed = userdata['LastPlayedDate'] dateplayed = userdata['LastPlayedDate']
# item details # item details
people = API.getPeople() director, writer, cast, producer = API.getPeople()
writer = " / ".join(people['Writer']) director = API.joinList(director)
director = " / ".join(people['Director']) writer = API.joinList(writer)
title = item['Name'] cast = API.joinList(cast)
plot = API.getOverview() producer = API.joinList(producer)
rating = item.get('CommunityRating') title, sorttitle = API.getTitle()
plot = API.getPlot()
rating = API.getAudienceRating()
runtime = API.getRuntime() runtime = API.getRuntime()
premieredate = API.getPremiereDate() premieredate = API.getPremiereDate()
# episode details # episode details
seriesId = item['SeriesId'] seriesId, seriesName, season, episode = API.getEpisodeDetails()
seriesName = item['SeriesName']
season = item.get('ParentIndexNumber')
episode = item.get('IndexNumber', -1)
if season is None: if season is None:
if item.get('AbsoluteEpisodeNumber'): if item.get('AbsoluteEpisodeNumber'):
@ -1496,16 +1493,18 @@ class TVShows(Items):
season = -1 season = -1
# Specials ordering within season # Specials ordering within season
if item.get('AirsAfterSeasonNumber'): # if item.get('AirsAfterSeasonNumber'):
airsBeforeSeason = item['AirsAfterSeasonNumber'] # airsBeforeSeason = item['AirsAfterSeasonNumber']
airsBeforeEpisode = 4096 # Kodi default number for afterseason ordering # airsBeforeEpisode = 4096 # Kodi default number for afterseason ordering
else: # else:
airsBeforeSeason = item.get('AirsBeforeSeasonNumber', "-1") # airsBeforeSeason = item.get('AirsBeforeSeasonNumber', "-1")
airsBeforeEpisode = item.get('AirsBeforeEpisodeNumber', "-1") # airsBeforeEpisode = item.get('AirsBeforeEpisodeNumber', "-1")
airsBeforeSeason = "-1"
airsBeforeEpisode = "-1"
# Append multi episodes to title # Append multi episodes to title
if item.get('IndexNumberEnd'): # if item.get('IndexNumberEnd'):
title = "| %02d | %s" % (item['IndexNumberEnd'], title) # title = "| %02d | %s" % (item['IndexNumberEnd'], title)
# Get season id # Get season id
show = emby_db.getItem_byId(seriesId) show = emby_db.getItem_byId(seriesId)
@ -1519,7 +1518,7 @@ class TVShows(Items):
try: try:
showid = show[0] showid = show[0]
except TypeError: except TypeError:
self.logMsg("Skipping: %s. Unable to add series: %s." % (itemid, seriesId)) self.logMsg("Skipping: %s. Unable to add series: %s." % (itemid, seriesId), -1)
return False return False
seasonid = kodi_db.addSeason(showid, season) seasonid = kodi_db.addSeason(showid, season)
@ -1659,11 +1658,12 @@ class TVShows(Items):
)) ))
kodicursor.execute(query, (pathid, filename, dateadded, fileid)) kodicursor.execute(query, (pathid, filename, dateadded, fileid))
self.logMsg("Start processing getPeopleList", 1)
# Process cast # Process cast
people = artwork.getPeopleArtwork(item['People']) people = API.getPeopleList()
kodi_db.addPeople(episodeid, people, "episode") kodi_db.addPeople(episodeid, people, "episode")
# Process artwork # Process artwork
artworks = artwork.getAllArtwork(item) artworks = API.getAllArtwork()
artwork.addOrUpdateArt(artworks['Primary'], episodeid, "episode", "thumb", kodicursor) artwork.addOrUpdateArt(artworks['Primary'], episodeid, "episode", "thumb", kodicursor)
# Process stream details # Process stream details
streams = API.getMediaStreams() streams = API.getMediaStreams()

View file

@ -87,6 +87,8 @@ class ThreadedProcessMetadata(threading.Thread):
data = { data = {
'itemType': as used to call functions in itemtypes.py 'itemType': as used to call functions in itemtypes.py
e.g. 'Movies' => itemtypes.Movies() e.g. 'Movies' => itemtypes.Movies()
'method' Name of method in itemtypes.py
e.g. 'add_updateSeason'
'viewName' Plex str for library view (e.g. 'Movies') 'viewName' Plex str for library view (e.g. 'Movies')
'viewId' Plex Id to identifiy the library view 'viewId' Plex Id to identifiy the library view
} }
@ -108,6 +110,7 @@ class ThreadedProcessMetadata(threading.Thread):
viewId = self.data['viewId'] viewId = self.data['viewId']
global processMetadataCount global processMetadataCount
with itemFkt() as item: with itemFkt() as item:
itemSubFkt = getattr(item, self.data['method'])
while self.stopped() is False: while self.stopped() is False:
# grabs item from queue # grabs item from queue
try: try:
@ -117,7 +120,7 @@ class ThreadedProcessMetadata(threading.Thread):
continue continue
# Do the work; lock to be sure we've only got 1 Thread # Do the work; lock to be sure we've only got 1 Thread
with self.lock: with self.lock:
item.add_update( itemSubFkt(
plexitem, plexitem,
viewtag=viewName, viewtag=viewName,
viewid=viewId viewid=viewId
@ -159,18 +162,18 @@ class ThreadedShowSyncInfo(threading.Thread):
downloadLock = self.locks[0] downloadLock = self.locks[0]
processLock = self.locks[1] processLock = self.locks[1]
self.dialog.create( self.dialog.create(
self.addonName + ": Sync " + self.viewName + "%s: Sync %s: %s items" % (self.addonName,
': ' + str(total) + 'items', self.viewName,
"Starting" str(total)),
) "Starting")
global getMetadataCount global getMetadataCount
global processMetadataCount global processMetadataCount
total = 2 * total total = 2 * total
totalProgress = 0 totalProgress = 0
while self.stopped() is not True: while self.stopped() is False:
with downloadLock: with downloadLock:
getMetadataProgress = getMetadataCount getMetadataProgress = getMetadataCount
with processLock: #with processLock:
processMetadataProgress = processMetadataCount processMetadataProgress = processMetadataCount
totalProgress = getMetadataProgress + processMetadataProgress totalProgress = getMetadataProgress + processMetadataProgress
try: try:
@ -182,7 +185,7 @@ class ThreadedShowSyncInfo(threading.Thread):
message="Downloaded: %s, Processed: %s" % message="Downloaded: %s, Processed: %s" %
(getMetadataProgress, processMetadataProgress) (getMetadataProgress, processMetadataProgress)
) )
time.sleep(0.5) time.sleep(1)
def stopThread(self): def stopThread(self):
self._shouldstop.set() self._shouldstop.set()
@ -345,16 +348,17 @@ class LibrarySync(threading.Thread):
# embyconn.commit() # embyconn.commit()
self.initializeDBs() self.initializeDBs()
# Sync video library # Sync video library
process = { # process = {
'movies': self.movies, # 'movies': self.movies,
'musicvideos': self.musicvideos, # 'musicvideos': self.musicvideos,
'tvshows': self.tvshows, # 'tvshows': self.tvshows,
'homevideos': self.homevideos # 'homevideos': self.homevideos
} # }
process = { process = {
'movies': self.PlexMovies 'movies': self.PlexMovies,
'tvshows': self.PlexTVShows
# 'tvshows': self.PlexTVShows # 'tvshows': self.PlexTVShows
} }
@ -585,10 +589,12 @@ class LibrarySync(threading.Thread):
""" """
if self.compare: if self.compare:
# Manual sync # Manual sync
for plexmovie in elementList: for item in elementList:
# Only look at valid items = Plex library items
if item.get('ratingKey', False):
if self.shouldStop(): if self.shouldStop():
return False return False
API = PlexAPI.API(plexmovie) API = PlexAPI.API(item)
plex_checksum = API.getChecksum() plex_checksum = API.getChecksum()
itemid = API.getKey() itemid = API.getKey()
self.allPlexElementsId[itemid] = plex_checksum self.allPlexElementsId[itemid] = plex_checksum
@ -599,8 +605,10 @@ class LibrarySync(threading.Thread):
self.updatelist.append(itemid) self.updatelist.append(itemid)
else: else:
# Initial or repair sync: get all Plex movies # Initial or repair sync: get all Plex movies
for plexmovie in elementList: for item in elementList:
API = PlexAPI.API(plexmovie) # Only look at valid items = Plex library items
if item.get('ratingKey', False):
API = PlexAPI.API(item)
itemid = API.getKey() itemid = API.getKey()
plex_checksum = API.getChecksum() plex_checksum = API.getChecksum()
self.allPlexElementsId[itemid] = plex_checksum self.allPlexElementsId[itemid] = plex_checksum
@ -608,7 +616,7 @@ class LibrarySync(threading.Thread):
# Update the Kodi popup info # Update the Kodi popup info
return self.updatelist, self.allPlexElementsId return self.updatelist, self.allPlexElementsId
def GetAndProcessXMLs(self, itemType, viewName, viewId): def GetAndProcessXMLs(self, itemType, viewName, viewId, method):
""" """
Downloads all XMLs for itemType (e.g. Movies, TV-Shows). Processes them Downloads all XMLs for itemType (e.g. Movies, TV-Shows). Processes them
by then calling itemtypes.<itemType>() by then calling itemtypes.<itemType>()
@ -617,6 +625,8 @@ class LibrarySync(threading.Thread):
itemType: to construct itemtypes.py function name: 'Movies' itemType: to construct itemtypes.py function name: 'Movies'
viewName: Plex name of library, e.g. 'My Movies' viewName: Plex name of library, e.g. 'My Movies'
viewId: Plex Id for that library viewId: Plex Id for that library
method: name of itemtypes.py method,
e.g. 'add_updateSeason'
Returns True if/when done Returns True if/when done
""" """
@ -639,6 +649,9 @@ class LibrarySync(threading.Thread):
getMetadataCount = 0 getMetadataCount = 0
global processMetadataCount global processMetadataCount
processMetadataCount = 0 processMetadataCount = 0
# Populate queue: GetMetadata
for itemId in self.updatelist:
getMetadataQueue.put(itemId)
# Spawn GetMetadata threads # Spawn GetMetadata threads
threads = [] threads = []
for i in range(self.syncThreadNumber): for i in range(self.syncThreadNumber):
@ -652,13 +665,11 @@ class LibrarySync(threading.Thread):
t.start() t.start()
threads.append(t) threads.append(t)
self.logMsg("%s download threads spawned" % self.syncThreadNumber, 1) 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) self.logMsg("Queue populated", 1)
# Spawn one more thread to process Metadata, once downloaded # Spawn one more thread to process Metadata, once downloaded
data = { data = {
'itemType': itemType, 'itemType': itemType,
'method': method,
'viewName': viewName, 'viewName': viewName,
'viewId': viewId 'viewId': viewId
} }
@ -714,7 +725,6 @@ class LibrarySync(threading.Thread):
self.logMsg("%s compare finished." % itemType, 1) self.logMsg("%s compare finished." % itemType, 1)
return True return True
def PlexMovies(self): def PlexMovies(self):
# Initialize # Initialize
plx = PlexAPI.PlexAPI() plx = PlexAPI.PlexAPI()
@ -724,21 +734,20 @@ class LibrarySync(threading.Thread):
views = plx.GetPlexCollections('movie') views = plx.GetPlexCollections('movie')
self.logMsg("Media folders: %s" % views, 1) self.logMsg("Media folders: %s" % views, 1)
if self.compare:
# Get movies from Plex server # Get movies from Plex server
embyconn = utils.kodiSQL('emby') embyconn = utils.kodiSQL('emby')
embycursor = embyconn.cursor() embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor) emby_db = embydb.Embydb_Functions(embycursor)
if self.compare:
# Pull the list of movies and boxsets in Kodi # Pull the list of movies and boxsets in Kodi
try: try:
self.allKodiElementsId = dict(emby_db.getChecksum('Movie')) self.allKodiElementsId = dict(emby_db.getChecksum('Movie'))
except ValueError: except ValueError:
self.allKodiElementsId = {} self.allKodiElementsId = {}
embyconn.close()
else: else:
# Getting all metadata, hence set Kodi elements to {} # Getting all metadata, hence set Kodi elements to {}
self.allKodiElementsId = {} self.allKodiElementsId = {}
embyconn.close()
##### PROCESS MOVIES ##### ##### PROCESS MOVIES #####
for view in views: for view in views:
@ -752,177 +761,14 @@ class LibrarySync(threading.Thread):
# Populate self.updatelist and self.allPlexElementsId # Populate self.updatelist and self.allPlexElementsId
self.GetUpdatelist(all_plexmovies) self.GetUpdatelist(all_plexmovies)
self.logMsg("Processed view %s with ID %s" % (viewName, viewId), 1) self.logMsg("Processed view %s with ID %s" % (viewName, viewId), 1)
# Returns True if successful result = self.GetAndProcessXMLs(
result = self.GetAndProcessXMLs('Movies', viewName, viewId) 'Movies',
viewName,
viewId,
'add_update'
)
return result return result
def movies(self, embycursor, kodicursor, pdialog, compare=False):
# Get movies from emby
emby = self.emby
emby_db = embydb.Embydb_Functions(embycursor)
movies = itemtypes.Movies(embycursor, kodicursor)
views = emby_db.getView_byType('movies')
views += emby_db.getView_byType('mixed')
self.logMsg("Media folders: %s" % views, 1)
if compare:
# Pull the list of movies and boxsets in Kodi
try:
all_kodimovies = dict(emby_db.getChecksum('Movie'))
except ValueError:
all_kodimovies = {}
try:
all_kodisets = dict(emby_db.getChecksum('BoxSet'))
except ValueError:
all_kodisets = {}
all_embymoviesIds = set()
all_embyboxsetsIds = set()
updatelist = []
##### PROCESS MOVIES #####
for view in views:
if self.shouldStop():
return False
# Get items per view
viewId = view['id']
viewName = view['name']
if pdialog:
pdialog.update(
heading="Emby for Kodi",
message="Gathering movies from view: %s..." % viewName)
if compare:
# Manual sync
if pdialog:
pdialog.update(
heading="Emby for Kodi",
message="Comparing movies from view: %s..." % viewName)
all_embymovies = emby.getMovies(viewId, basic=True)
for embymovie in all_embymovies['Items']:
if self.shouldStop():
return False
API = api.API(embymovie)
itemid = embymovie['Id']
all_embymoviesIds.add(itemid)
if all_kodimovies.get(itemid) != API.getChecksum():
# Only update if movie is not in Kodi or checksum is different
updatelist.append(itemid)
self.logMsg("Movies to update for %s: %s" % (viewName, updatelist), 1)
embymovies = emby.getFullItems(updatelist)
total = len(updatelist)
del updatelist[:]
else:
# Initial or repair sync
all_embymovies = emby.getMovies(viewId)
total = all_embymovies['TotalRecordCount']
embymovies = all_embymovies['Items']
if pdialog:
pdialog.update(heading="Processing %s / %s items" % (viewName, total))
count = 0
for embymovie in embymovies:
# Process individual movies
if self.shouldStop():
return False
title = embymovie['Name']
if pdialog:
percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title)
count += 1
movies.add_update(embymovie, viewName, viewId)
else:
self.logMsg("Movies finished.", 2)
##### PROCESS BOXSETS #####
if pdialog:
pdialog.update(heading="Emby for Kodi", message="Gathering boxsets from server...")
boxsets = emby.getBoxset()
if compare:
# Manual sync
embyboxsets = []
if pdialog:
pdialog.update(
heading="Emby for Kodi",
message="Comparing boxsets...")
for boxset in boxsets['Items']:
if self.shouldStop():
return False
# Boxset has no real userdata, so using etag to compare
checksum = boxset['Etag']
itemid = boxset['Id']
all_embyboxsetsIds.add(itemid)
if all_kodisets.get(itemid) != checksum:
# Only update if boxset is not in Kodi or checksum is different
updatelist.append(itemid)
embyboxsets.append(boxset)
self.logMsg("Boxsets to update: %s" % updatelist, 1)
total = len(updatelist)
else:
total = boxsets['TotalRecordCount']
embyboxsets = boxsets['Items']
if pdialog:
pdialog.update(heading="Processing Boxsets / %s items" % total)
count = 0
for boxset in embyboxsets:
# Process individual boxset
if self.shouldStop():
return False
title = boxset['Name']
if pdialog:
percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title)
count += 1
movies.add_updateBoxset(boxset)
else:
self.logMsg("Boxsets finished.", 2)
##### PROCESS DELETES #####
if compare:
# Manual sync, process deletes
for kodimovie in all_kodimovies:
if kodimovie not in all_embymoviesIds:
movies.remove(kodimovie)
else:
self.logMsg("Movies compare finished.", 1)
for boxset in all_kodisets:
if boxset not in all_embyboxsetsIds:
movies.remove(boxset)
else:
self.logMsg("Boxsets compare finished.", 1)
return True
def musicvideos(self, embycursor, kodicursor, pdialog, compare=False): def musicvideos(self, embycursor, kodicursor, pdialog, compare=False):
# Get musicvideos from emby # Get musicvideos from emby
emby = self.emby emby = self.emby
@ -1111,22 +957,21 @@ class LibrarySync(threading.Thread):
return True return True
def PlexTVShows(self, embycursor, kodicursor): def PlexTVShows(self):
# Initialize # Initialize
plx = PlexAPI.PlexAPI() plx = PlexAPI.PlexAPI()
compare = self.compare
pdialog = self.pDialog
self.updatelist = [] self.updatelist = []
self.allPlexElementsId = {} self.allPlexElementsId = {}
# Get shows from emby
emby_db = embydb.Embydb_Functions(embycursor)
tvshows = itemtypes.TVShows(embycursor, kodicursor)
views = plx.GetPlexCollections('show') views = plx.GetPlexCollections('show')
self.logMsg("Media folders: %s" % views, 1) self.logMsg("Media folders: %s" % views, 1)
self.allKodiElementsId = {} self.allKodiElementsId = {}
if compare: if self.compare:
# Get movies from Plex server
embyconn = utils.kodiSQL('emby')
embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor)
# Pull the list of TV shows already in Kodi # Pull the list of TV shows already in Kodi
try: try:
all_koditvshows = dict(emby_db.getChecksum('Series')) all_koditvshows = dict(emby_db.getChecksum('Series'))
@ -1139,145 +984,64 @@ class LibrarySync(threading.Thread):
self.allKodiElementsId.update(all_kodiepisodes) self.allKodiElementsId.update(all_kodiepisodes)
except ValueError: except ValueError:
pass pass
embyconn.close()
##### PROCESS TV Shows #####
for view in views: for view in views:
self.updatelist = [] self.updatelist = []
self.allPlexElementsId = {}
if self.shouldStop(): if self.shouldStop():
return False return False
# Get items per view # Get items per view
viewId = view['id'] viewId = view['id']
viewName = view['name'] viewName = view['name']
if pdialog: allPlexTvShows = plx.GetPlexSectionResults(viewId)
pdialog.update( # Populate self.updatelist and self.allPlexElementsId
heading=self.addonName, self.GetUpdatelist(allPlexTvShows)
message="Gathering TV Shows from view: %s..." % viewName) # Process self.updatelist
all_plexTvShows = plx.GetPlexSectionResults(viewId) self.GetAndProcessXMLs('TVShows',
viewName,
viewId,
'add_update')
self.logMsg("Processed view %s with ID %s" % (viewName, viewId), 1)
# Populate self.updatelist with TV shows and self.allPlexElementsId # Save for later use
self.GetUpdatelist(all_plexTvShows, viewName) allPlexTvShowsId = self.allPlexElementsId
# Run through self.updatelist, get XML metadata per item and safe ##### PROCESS TV Seasons #####
# to Kodi # Cycle through tv shows
self.ProcessUpdateList(tvshows, view) for tvShowId in allPlexTvShowsId:
self.updatelist = []
self.allPlexElementsId = {}
# Grab all seasons to tvshow from PMS
seasons = plx.GetAllPlexChildren(tvShowId)
# Populate self.updatelist and self.allPlexElementsId
self.GetUpdatelist(seasons)
# Process self.updatelist
self.GetAndProcessXMLs('TVShows',
None,
tvShowId, # send showId instead of viewid
'add_updateSeason')
XMLtvshow = plx.GetPlexMetadata(tvShowId)
with itemtypes.TVShows() as TVshow:
TVshow.refreshSeasonEntry(XMLtvshow, tvShowId)
self.logMsg("Processed all seasons of TV show with Plex Id %s" % tvShowId, 1)
##### PROCESS TV Episodes #####
# Cycle through tv shows
if compare: for tvShowId in allPlexTvShowsId:
# Manual sync self.updatelist = []
for plexTvShow in all_plexTvShows: self.allPlexElementsId = {}
if self.shouldStop(): # Grab all episodes to tvshow from PMS
return False episodes = plx.GetAllPlexLeaves(tvShowId)
API = plx(plexTvShow) # Populate self.updatelist and self.allPlexElementsId
plex_checksum = API.getChecksum() self.GetUpdatelist(episodes)
itemid = API.getKey() # Process self.updatelist
kodi_checksum = all_kodimoviesId.get(itemid) self.GetAndProcessXMLs('TVShows',
all_plextvshowsIds[itemid] = itemid None,
kodi_checksum = all_koditvshows.get(itemid) None,
#if kodi_checksum != plex_checksum: 'add_updateEpisode')
self.logMsg("Processed all episodes of TV show with Plex Id %s" % tvShowId, 1)
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 return True