From 5f342227129635cc10c4c79eaa20287e033963f2 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 2 Aug 2020 00:25:08 -0400 Subject: [PATCH 1/9] Optimize network calls for music syncing --- jellyfin_kodi/downloader.py | 49 ++++++++++++++---------- jellyfin_kodi/full_sync.py | 76 +++++++++++++++++++++++++------------ 2 files changed, 81 insertions(+), 44 deletions(-) diff --git a/jellyfin_kodi/downloader.py b/jellyfin_kodi/downloader.py index ba701231..762a4afe 100644 --- a/jellyfin_kodi/downloader.py +++ b/jellyfin_kodi/downloader.py @@ -189,31 +189,40 @@ def get_items(parent_id, item_type=None, basic=False, params=None): yield items -def get_artists(parent_id=None, basic=False, params=None, server_id=None): +def get_artists(parent_id=None): - query = { - 'url': "Artists", - 'params': { - 'UserId': "{UserId}", - 'ParentId': parent_id, - 'SortBy': "SortName", - 'SortOrder': "Ascending", - 'Fields': api.basic_info() if basic else api.music_info(), - 'CollapseBoxSetItems': False, - 'IsVirtualUnaired': False, - 'EnableTotalRecordCount': False, - 'LocationTypes': "FileSystem,Remote,Offline", - 'IsMissing': False, - 'Recursive': True - } + url = "Artists" + + params = { + 'UserId': "{UserId}", + 'ParentId': parent_id, + 'SortBy': "SortName", + 'SortOrder': "Ascending", + 'Fields': api.music_info(), + 'CollapseBoxSetItems': False, + 'IsVirtualUnaired': False, + 'EnableTotalRecordCount': False, + 'LocationTypes': "FileSystem,Remote,Offline", + 'IsMissing': False, + 'Recursive': True } - if params: - query['params'].update(params) + return _get(url, params) - for items in _get_items(query, server_id): - yield items +def get_library_items(library_id, item_type): + url = "Users/{UserId}/Items" + + params = { + 'ParentId': library_id, + 'IncludeItemTypes': item_type, + 'SortBy': "SortName", + 'SortOrder': "Ascending", + 'Fields': api.info(), + 'Recursive': True, + } + + return _get(url, params) def get_albums_by_artist(artist_id, basic=False): diff --git a/jellyfin_kodi/full_sync.py b/jellyfin_kodi/full_sync.py index 09ba5b73..eed0d5f6 100644 --- a/jellyfin_kodi/full_sync.py +++ b/jellyfin_kodi/full_sync.py @@ -407,36 +407,64 @@ class FullSync(object): with Database('jellyfin') as jellyfindb: obj = Music(self.server, jellyfindb, musicdb, self.direct_path) - for items in server.get_artists(library['Id'], False, self.sync['RestorePoint'].get('params')): + library_id = library['Id'] + artists_data = server.get_artists(library_id) + artists = artists_data['Items'] + num_artists = artists_data['TotalRecordCount'] + albums = server.get_library_items(library_id, 'MusicAlbum')['Items'] + songs = server.get_library_items(library_id, 'Audio')['Items'] - self.sync['RestorePoint'] = items['RestorePoint'] - start_index = items['RestorePoint']['params']['StartIndex'] + for index, artist in enumerate(artists): + artist_name = artist.get('Name') - for index, artist in enumerate(items['Items']): + percent = int((float(index) / float(num_artists)) * 100) + message = artist_name + dialog.update(percent, heading="%s: %s" % (translate('addon_name'), library['Name']), message=message) - percent = int((float(start_index + index) / float(items['TotalRecordCount'])) * 100) - message = artist['Name'] - dialog.update(percent, heading="%s: %s" % (translate('addon_name'), library['Name']), message=message) - obj.artist(artist, library=library) + obj.artist(artist, library=library) + artist_albums = [ album for album in albums if artist_name in album.get('Artists') ] + for album in artist_albums: + obj.album(album) + album_id = album.get('Id') + album_songs = [ song for song in songs if album_id == song.get('AlbumId') ] + for song in album_songs: + dialog.update(percent, + message="%s/%s/%s" % (message, album['Name'][:7], song['Name'][:7])) + obj.song(song) - for albums in server.get_albums_by_artist(artist['Id']): - for album in albums['Items']: - obj.album(album) - - for songs in server.get_items(album['Id'], "Audio"): - for song in songs['Items']: - - dialog.update(percent, - message="%s/%s/%s" % (message, album['Name'][:7], song['Name'][:7])) - obj.song(song) - - for songs in server.get_songs_by_artist(artist['Id']): - for song in songs['Items']: - - dialog.update(percent, message="%s/%s" % (message, song['Name'])) - obj.song(song) +# for items in server.get_artists(library['Id'], False, self.sync['RestorePoint'].get('params')): +# +# self.sync['RestorePoint'] = items['RestorePoint'] +# start_index = items['RestorePoint']['params']['StartIndex'] +# +# for index, artist in enumerate(items['Items']): +# +# percent = int((float(start_index + index) / float(items['TotalRecordCount'])) * 100) +# message = artist['Name'] +# dialog.update(percent, heading="%s: %s" % (translate('addon_name'), library['Name']), message=message) +# obj.artist(artist, library=library) +# +# import web_pdb; web_pdb.set_trace() +# for albums in server.get_albums_by_artist(artist['Id']): +# +# for album in albums['Items']: +# obj.album(album) +# +# for songs in server.get_items(album['Id'], "Audio"): +# for song in songs['Items']: +# +# dialog.update(percent, +# message="%s/%s/%s" % (message, album['Name'][:7], song['Name'][:7])) +# obj.song(song) +# +# for songs in server.get_songs_by_artist(artist['Id']): +# for song in songs['Items']: +# +# dialog.update(percent, message="%s/%s" % (message, song['Name'])) +# obj.song(song) +# if self.update_library: self.music_compare(library, obj, jellyfindb) From 2c55f7a27cc58863ae13a0dc93b0678dad7da996 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 2 Aug 2020 09:41:25 -0400 Subject: [PATCH 2/9] Remove library_check wrapper from songs --- jellyfin_kodi/objects/music.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/jellyfin_kodi/objects/music.py b/jellyfin_kodi/objects/music.py index b139c4d7..18a2466d 100644 --- a/jellyfin_kodi/objects/music.py +++ b/jellyfin_kodi/objects/music.py @@ -209,10 +209,9 @@ class Music(KodiDb): self.link(*values(temp_obj, QU.update_link_obj)) self.item_ids.append(temp_obj['Id']) - @stop - @jellyfin_item - @library_check - def song(self, item, e_item, library): + @stop() + @jellyfin_item() + def song(self, item, e_item): ''' Update object to kodi. ''' From 0ee5b616a57ba8676e74e35d04621304bcdd570b Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 2 Aug 2020 09:41:40 -0400 Subject: [PATCH 3/9] stupid getitems --- jellyfin_kodi/library.py | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/jellyfin_kodi/library.py b/jellyfin_kodi/library.py index 7a013abb..f777df4f 100644 --- a/jellyfin_kodi/library.py +++ b/jellyfin_kodi/library.py @@ -606,29 +606,29 @@ class UpdateWorker(threading.Thread): break default_args = (self.server, jellyfindb, kodidb, self.direct_path) - if item['Type'] == 'Movie': - obj = Movies(*default_args).movie - elif item['Type'] == 'BoxSet': - obj = Movies(*default_args).boxset - elif item['Type'] == 'Series': - obj = TVShows(*default_args).tvshow - elif item['Type'] == 'Season': - obj = TVShows(*default_args).season - elif item['Type'] == 'Episode': - obj = TVShows(*default_args).episode - elif item['Type'] == 'MusicVideo': - obj = MusicVideos(*default_args).musicvideo - elif item['Type'] == 'MusicAlbum': - obj = Music(*default_args).album - elif item['Type'] == 'MusicArtist': - obj = Music(*default_args).artist - elif item['Type'] == 'AlbumArtist': - obj = Music(*default_args).albumartist - elif item['Type'] == 'Audio': - obj = Music(*default_args).song - try: - if obj(item) and self.notify: + if item['Type'] == 'Movie': + obj = Movies(*default_args).movie(item) + elif item['Type'] == 'BoxSet': + obj = Movies(*default_args).boxset(item) + elif item['Type'] == 'Series': + obj = TVShows(*default_args).tvshow(item) + elif item['Type'] == 'Season': + obj = TVShows(*default_args).season(item) + elif item['Type'] == 'Episode': + obj = TVShows(*default_args).episode(item) + elif item['Type'] == 'MusicVideo': + obj = MusicVideos(*default_args).musicvideo(item) + elif item['Type'] == 'MusicAlbum': + obj = Music(*default_args).album(item) + elif item['Type'] == 'MusicArtist': + obj = Music(*default_args).artist(item) + elif item['Type'] == 'AlbumArtist': + obj = Music(*default_args).albumartist(item) + elif item['Type'] == 'Audio': + obj = Music(*default_args).song(item) + + if self.notify: self.notify_output.put((item['Type'], api.API(item).get_naming())) except LibraryException as error: if error.status == 'StopCalled': From eca9630918e9720f3074acb3cff01dec860729f5 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 2 Aug 2020 17:00:34 -0400 Subject: [PATCH 4/9] Remove library_check wrapper --- jellyfin_kodi/full_sync.py | 72 ++++++----------- jellyfin_kodi/helper/__init__.py | 1 - jellyfin_kodi/helper/utils.py | 16 ++++ jellyfin_kodi/helper/wrapper.py | 57 -------------- jellyfin_kodi/library.py | 111 ++++++++++++++------------- jellyfin_kodi/objects/movies.py | 12 +-- jellyfin_kodi/objects/music.py | 22 +++--- jellyfin_kodi/objects/musicvideos.py | 12 +-- jellyfin_kodi/objects/tvshows.py | 14 ++-- 9 files changed, 129 insertions(+), 188 deletions(-) diff --git a/jellyfin_kodi/full_sync.py b/jellyfin_kodi/full_sync.py index eed0d5f6..c86596a8 100644 --- a/jellyfin_kodi/full_sync.py +++ b/jellyfin_kodi/full_sync.py @@ -270,7 +270,7 @@ class FullSync(object): for items in server.get_items(library['Id'], "Movie", False, self.sync['RestorePoint'].get('params')): with self.video_database_locks() as (videodb, jellyfindb): - obj = Movies(self.server, jellyfindb, videodb, self.direct_path) + obj = Movies(self.server, jellyfindb, videodb, self.direct_path, library) self.sync['RestorePoint'] = items['RestorePoint'] start_index = items['RestorePoint']['params']['StartIndex'] @@ -280,11 +280,11 @@ class FullSync(object): dialog.update(int((float(start_index + index) / float(items['TotalRecordCount'])) * 100), heading="%s: %s" % (translate('addon_name'), library['Name']), message=movie['Name']) - obj.movie(movie, library=library) + obj.movie(movie) processed_ids.append(movie['Id']) with self.video_database_locks() as (videodb, jellyfindb): - obj = Movies(self.server, jellyfindb, videodb, self.direct_path) + obj = Movies(self.server, jellyfindb, videodb, self.direct_path, library) obj.item_ids = processed_ids if self.update_library: @@ -313,7 +313,7 @@ class FullSync(object): for items in server.get_items(library['Id'], "Series", False, self.sync['RestorePoint'].get('params')): with self.video_database_locks() as (videodb, jellyfindb): - obj = TVShows(self.server, jellyfindb, videodb, self.direct_path, True) + obj = TVShows(self.server, jellyfindb, videodb, self.direct_path, library, True) self.sync['RestorePoint'] = items['RestorePoint'] start_index = items['RestorePoint']['params']['StartIndex'] @@ -324,7 +324,7 @@ class FullSync(object): message = show['Name'] dialog.update(percent, heading="%s: %s" % (translate('addon_name'), library['Name']), message=message) - if obj.tvshow(show, library=library) is not False: + if obj.tvshow(show) is not False: for episodes in server.get_episode_by_show(show['Id']): for episode in episodes['Items']: @@ -334,7 +334,7 @@ class FullSync(object): processed_ids.append(show['Id']) with self.video_database_locks() as (videodb, jellyfindb): - obj = TVShows(self.server, jellyfindb, videodb, self.direct_path, True) + obj = TVShows(self.server, jellyfindb, videodb, self.direct_path, library, True) obj.item_ids = processed_ids if self.update_library: self.tvshows_compare(library, obj, jellyfindb) @@ -365,7 +365,7 @@ class FullSync(object): for items in server.get_items(library['Id'], "MusicVideo", False, self.sync['RestorePoint'].get('params')): with self.video_database_locks() as (videodb, jellyfindb): - obj = MusicVideos(self.server, jellyfindb, videodb, self.direct_path) + obj = MusicVideos(self.server, jellyfindb, videodb, self.direct_path, library) self.sync['RestorePoint'] = items['RestorePoint'] start_index = items['RestorePoint']['params']['StartIndex'] @@ -375,11 +375,11 @@ class FullSync(object): dialog.update(int((float(start_index + index) / float(items['TotalRecordCount'])) * 100), heading="%s: %s" % (translate('addon_name'), library['Name']), message=mvideo['Name']) - obj.musicvideo(mvideo, library=library) + obj.musicvideo(mvideo) processed_ids.append(mvideo['Id']) with self.video_database_locks() as (videodb, jellyfindb): - obj = MusicVideos(self.server, jellyfindb, videodb, self.direct_path) + obj = MusicVideos(self.server, jellyfindb, videodb, self.direct_path, library) obj.item_ids = processed_ids if self.update_library: self.musicvideos_compare(library, obj, jellyfindb) @@ -405,9 +405,11 @@ class FullSync(object): with self.library.music_database_lock: with Database('music') as musicdb: with Database('jellyfin') as jellyfindb: - obj = Music(self.server, jellyfindb, musicdb, self.direct_path) + obj = Music(self.server, jellyfindb, musicdb, self.direct_path, library) library_id = library['Id'] + + # Get all items in the library to process locally artists_data = server.get_artists(library_id) artists = artists_data['Items'] num_artists = artists_data['TotalRecordCount'] @@ -417,53 +419,27 @@ class FullSync(object): for index, artist in enumerate(artists): artist_name = artist.get('Name') + # Update percentage dialog percent = int((float(index) / float(num_artists)) * 100) message = artist_name dialog.update(percent, heading="%s: %s" % (translate('addon_name'), library['Name']), message=message) - obj.artist(artist, library=library) + # Add artist to database + obj.artist(artist) + + # Get all albums for each artist artist_albums = [ album for album in albums if artist_name in album.get('Artists') ] for album in artist_albums: + # Add album to database obj.album(album) album_id = album.get('Id') + # Get all songs in each album album_songs = [ song for song in songs if album_id == song.get('AlbumId') ] for song in album_songs: dialog.update(percent, message="%s/%s/%s" % (message, album['Name'][:7], song['Name'][:7])) + # Add song to database obj.song(song) - - - -# for items in server.get_artists(library['Id'], False, self.sync['RestorePoint'].get('params')): -# -# self.sync['RestorePoint'] = items['RestorePoint'] -# start_index = items['RestorePoint']['params']['StartIndex'] -# -# for index, artist in enumerate(items['Items']): -# -# percent = int((float(start_index + index) / float(items['TotalRecordCount'])) * 100) -# message = artist['Name'] -# dialog.update(percent, heading="%s: %s" % (translate('addon_name'), library['Name']), message=message) -# obj.artist(artist, library=library) -# -# import web_pdb; web_pdb.set_trace() -# for albums in server.get_albums_by_artist(artist['Id']): -# -# for album in albums['Items']: -# obj.album(album) -# -# for songs in server.get_items(album['Id'], "Audio"): -# for song in songs['Items']: -# -# dialog.update(percent, -# message="%s/%s/%s" % (message, album['Name'][:7], song['Name'][:7])) -# obj.song(song) -# -# for songs in server.get_songs_by_artist(artist['Id']): -# for song in songs['Items']: -# -# dialog.update(percent, message="%s/%s" % (message, song['Name'])) -# obj.song(song) # if self.update_library: self.music_compare(library, obj, jellyfindb) @@ -492,7 +468,7 @@ class FullSync(object): for items in server.get_items(library_id, "BoxSet", False, self.sync['RestorePoint'].get('params')): with self.video_database_locks() as (videodb, jellyfindb): - obj = Movies(self.server, jellyfindb, videodb, self.direct_path) + obj = Movies(self.server, jellyfindb, videodb, self.direct_path, library) self.sync['RestorePoint'] = items['RestorePoint'] start_index = items['RestorePoint']['params']['StartIndex'] @@ -509,7 +485,7 @@ class FullSync(object): ''' Delete all exisitng boxsets and re-add. ''' with self.video_database_locks() as (videodb, jellyfindb): - obj = Movies(self.server, jellyfindb, videodb, self.direct_path) + obj = Movies(self.server, jellyfindb, videodb, self.direct_path, library) obj.boxsets_reset() self.boxsets(None) @@ -542,7 +518,7 @@ class FullSync(object): movies = [x for x in items if x[1] == 'Movie'] tvshows = [x for x in items if x[1] == 'Series'] - obj = Movies(self.server, jellyfindb, kodidb, direct_path).remove + obj = Movies(self.server, jellyfindb, kodidb, direct_path, library).remove for item in movies: @@ -550,7 +526,7 @@ class FullSync(object): dialog.update(int((float(count) / float(len(items)) * 100)), heading="%s: %s" % (translate('addon_name'), library[0])) count += 1 - obj = TVShows(self.server, jellyfindb, kodidb, direct_path).remove + obj = TVShows(self.server, jellyfindb, kodidb, direct_path, library).remove for item in tvshows: diff --git a/jellyfin_kodi/helper/__init__.py b/jellyfin_kodi/helper/__init__.py index e4a65c98..4aa02574 100644 --- a/jellyfin_kodi/helper/__init__.py +++ b/jellyfin_kodi/helper/__init__.py @@ -27,4 +27,3 @@ from .utils import get_filesystem_encoding from .wrapper import progress from .wrapper import stop from .wrapper import jellyfin_item -from .wrapper import library_check diff --git a/jellyfin_kodi/helper/utils.py b/jellyfin_kodi/helper/utils.py index be8c3cd4..08364f8c 100644 --- a/jellyfin_kodi/helper/utils.py +++ b/jellyfin_kodi/helper/utils.py @@ -21,6 +21,7 @@ from kodi_six import xbmc, xbmcaddon, xbmcgui, xbmcvfs from . import LazyLogger from .translate import translate + ################################################################################################# LOG = LazyLogger(__name__) @@ -535,3 +536,18 @@ def get_filesystem_encoding(): enc = 'utf-8' return enc + + +def find_library(server, item): + from database import get_sync + + sync = get_sync() + + ancestors = server.jellyfin.get_ancestors(item['Id']) + for ancestor in ancestors: + if ancestor['Id'] in sync['Whitelist']: + LOG.info('Ancestor Found') + return ancestor + + LOG.error('No ancestor found, not syncing item with ID: {}'.format(item['Id'])) + return {} diff --git a/jellyfin_kodi/helper/wrapper.py b/jellyfin_kodi/helper/wrapper.py index de428163..9077a48c 100644 --- a/jellyfin_kodi/helper/wrapper.py +++ b/jellyfin_kodi/helper/wrapper.py @@ -77,60 +77,3 @@ def jellyfin_item(func): return func(self, item, e_item=e_item, *args, **kwargs) return wrapper - - -def library_check(func): - - ''' Wrapper to retrieve the library - ''' - def wrapper(self, item, *args, **kwargs): - - ''' TODO: Rethink this one... songs and albums cannot be found by library. expensive. - ''' - from database import get_sync - - if kwargs.get('library') is None: - sync = get_sync() - - if 'e_item' in kwargs: - try: - view_id = kwargs['e_item'][6] - view_name = self.jellyfin_db.get_view_name(view_id) - view = {'Name': view_name, 'Id': view_id} - except Exception: - view = None - - if view is None: - ancestors = self.server.jellyfin.get_ancestors(item['Id']) - - if not ancestors: - if item['Type'] == 'MusicArtist': - - try: - views = self.jellyfin_db.get_views_by_media('music')[0] - except Exception as error: - LOG.exception(error) - return - - view = {'Id': views[0], 'Name': views[1]} - else: # Grab the first music library - return - else: - for ancestor in ancestors: - if ancestor['Type'] == 'CollectionFolder': - - view = self.jellyfin_db.get_view_name(ancestor['Id']) - view = {'Id': None, 'Name': None} if view is None else {'Name': ancestor['Name'], 'Id': ancestor['Id']} - - break - - if view['Id'] not in [x.replace('Mixed:', "") for x in sync['Whitelist'] + sync['Libraries']]: - LOG.info("Library %s is not synced. Skip update.", view['Id']) - - return - - kwargs['library'] = view - - return func(self, item, *args, **kwargs) - - return wrapper diff --git a/jellyfin_kodi/library.py b/jellyfin_kodi/library.py index f777df4f..9a94361f 100644 --- a/jellyfin_kodi/library.py +++ b/jellyfin_kodi/library.py @@ -16,7 +16,7 @@ from full_sync import FullSync from views import Views from downloader import GetItemWorker from helper import translate, api, stop, settings, window, dialog, event -from helper.utils import split_list, set_screensaver, get_screensaver +from helper.utils import split_list, set_screensaver, get_screensaver, find_library from helper.exceptions import LibraryException from jellyfin import Jellyfin from helper import LazyLogger @@ -605,36 +605,39 @@ class UpdateWorker(threading.Thread): except Queue.Empty: break - default_args = (self.server, jellyfindb, kodidb, self.direct_path) - try: - if item['Type'] == 'Movie': - obj = Movies(*default_args).movie(item) - elif item['Type'] == 'BoxSet': - obj = Movies(*default_args).boxset(item) - elif item['Type'] == 'Series': - obj = TVShows(*default_args).tvshow(item) - elif item['Type'] == 'Season': - obj = TVShows(*default_args).season(item) - elif item['Type'] == 'Episode': - obj = TVShows(*default_args).episode(item) - elif item['Type'] == 'MusicVideo': - obj = MusicVideos(*default_args).musicvideo(item) - elif item['Type'] == 'MusicAlbum': - obj = Music(*default_args).album(item) - elif item['Type'] == 'MusicArtist': - obj = Music(*default_args).artist(item) - elif item['Type'] == 'AlbumArtist': - obj = Music(*default_args).albumartist(item) - elif item['Type'] == 'Audio': - obj = Music(*default_args).song(item) + # Verify that the updated item is in our local whitelist + library = find_library(self.server, item) + if library: + default_args = (self.server, jellyfindb, kodidb, self.direct_path, library) + try: + if item['Type'] == 'Movie': + obj = Movies(*default_args).movie(item) + elif item['Type'] == 'BoxSet': + obj = Movies(*default_args).boxset(item) + elif item['Type'] == 'Series': + obj = TVShows(*default_args).tvshow(item) + elif item['Type'] == 'Season': + obj = TVShows(*default_args).season(item) + elif item['Type'] == 'Episode': + obj = TVShows(*default_args).episode(item) + elif item['Type'] == 'MusicVideo': + obj = MusicVideos(*default_args).musicvideo(item) + elif item['Type'] == 'MusicAlbum': + obj = Music(*default_args).album(item) + elif item['Type'] == 'MusicArtist': + obj = Music(*default_args).artist(item) + elif item['Type'] == 'AlbumArtist': + obj = Music(*default_args).albumartist(item) + elif item['Type'] == 'Audio': + obj = Music(*default_args).song(item) - if self.notify: - self.notify_output.put((item['Type'], api.API(item).get_naming())) - except LibraryException as error: - if error.status == 'StopCalled': - break - except Exception as error: - LOG.exception(error) + if self.notify: + self.notify_output.put((item['Type'], api.API(item).get_naming())) + except LibraryException as error: + if error.status == 'StopCalled': + break + except Exception as error: + LOG.exception(error) self.queue.task_done() @@ -667,24 +670,28 @@ class UserDataWorker(threading.Thread): except Queue.Empty: break - try: - if item['Type'] == 'Movie': - Movies(self.args[0], jellyfindb, kodidb, self.args[1]).userdata(item) - elif item['Type'] in ['Series', 'Season', 'Episode']: - TVShows(self.args[0], jellyfindb, kodidb, self.args[1]).userdata(item) - elif item['Type'] == 'MusicAlbum': - Music(self.args[0], jellyfindb, kodidb, self.args[1]).album(item) - elif item['Type'] == 'MusicArtist': - Music(self.args[0], jellyfindb, kodidb, self.args[1]).artist(item) - elif item['Type'] == 'AlbumArtist': - Music(self.args[0], jellyfindb, kodidb, self.args[1]).albumartist(item) - elif item['Type'] == 'Audio': - Music(self.args[0], jellyfindb, kodidb, self.args[1]).song(item) - except LibraryException as error: - if error.status == 'StopCalled': - break - except Exception as error: - LOG.exception(error) + # Verify that the updated item is in our local whitelist + library = find_library(self.server, item) + if library: + default_args = (self.server, jellyfindb, kodidb, self.direct_path, library) + try: + if item['Type'] == 'Movie': + Movies(self.args[0], jellyfindb, kodidb, self.args[1]).userdata(item) + elif item['Type'] in ['Series', 'Season', 'Episode']: + TVShows(self.args[0], jellyfindb, kodidb, self.args[1]).userdata(item) + elif item['Type'] == 'MusicAlbum': + Music(self.args[0], jellyfindb, kodidb, self.args[1]).album(item) + elif item['Type'] == 'MusicArtist': + Music(self.args[0], jellyfindb, kodidb, self.args[1]).artist(item) + elif item['Type'] == 'AlbumArtist': + Music(self.args[0], jellyfindb, kodidb, self.args[1]).albumartist(item) + elif item['Type'] == 'Audio': + Music(self.args[0], jellyfindb, kodidb, self.args[1]).song(item) + except LibraryException as error: + if error.status == 'StopCalled': + break + except Exception as error: + LOG.exception(error) self.queue.task_done() @@ -765,13 +772,13 @@ class RemovedWorker(threading.Thread): break if item['Type'] == 'Movie': - obj = Movies(self.args[0], jellyfindb, kodidb, self.args[1]).remove + obj = Movies(self.args[0], jellyfindb, kodidb, self.args[1], library).remove elif item['Type'] in ['Series', 'Season', 'Episode']: - obj = TVShows(self.args[0], jellyfindb, kodidb, self.args[1]).remove + obj = TVShows(self.args[0], jellyfindb, kodidb, self.args[1], library).remove elif item['Type'] in ['MusicAlbum', 'MusicArtist', 'AlbumArtist', 'Audio']: - obj = Music(self.args[0], jellyfindb, kodidb, self.args[1]).remove + obj = Music(self.args[0], jellyfindb, kodidb, self.args[1], library).remove elif item['Type'] == 'MusicVideo': - obj = MusicVideos(self.args[0], jellyfindb, kodidb, self.args[1]).remove + obj = MusicVideos(self.args[0], jellyfindb, kodidb, self.args[1], library).remove try: obj(item['Id']) diff --git a/jellyfin_kodi/objects/movies.py b/jellyfin_kodi/objects/movies.py index a1867d28..d761fd66 100644 --- a/jellyfin_kodi/objects/movies.py +++ b/jellyfin_kodi/objects/movies.py @@ -8,7 +8,7 @@ from kodi_six.utils import py2_encode import downloader as server from database import jellyfin_db, queries as QUEM -from helper import api, stop, validate, validate_bluray_dir, validate_dvd_dir, jellyfin_item, library_check, values, Local +from helper import api, stop, validate, validate_bluray_dir, validate_dvd_dir, jellyfin_item, values, Local from helper import LazyLogger from helper.exceptions import PathValidationException @@ -24,7 +24,7 @@ LOG = LazyLogger(__name__) class Movies(KodiDb): - def __init__(self, server, jellyfindb, videodb, direct_path): + def __init__(self, server, jellyfindb, videodb, direct_path, library): self.server = server self.jellyfin = jellyfindb @@ -34,13 +34,13 @@ class Movies(KodiDb): self.jellyfin_db = jellyfin_db.JellyfinDatabase(jellyfindb.cursor) self.objects = Objects() self.item_ids = [] + self.library = library KodiDb.__init__(self, videodb.cursor) @stop @jellyfin_item - @library_check - def movie(self, item, e_item, library): + def movie(self, item, e_item): ''' If item does not exist, entry will be added. If item exists, entry will be updated. @@ -65,8 +65,8 @@ class Movies(KodiDb): LOG.info("MovieId %s missing from kodi. repairing the entry.", obj['MovieId']) obj['Path'] = API.get_file_path(obj['Path']) - obj['LibraryId'] = library['Id'] - obj['LibraryName'] = library['Name'] + obj['LibraryId'] = self.library['Id'] + obj['LibraryName'] = self.library['Name'] obj['Genres'] = obj['Genres'] or [] obj['Studios'] = [API.validate_studio(studio) for studio in (obj['Studios'] or [])] obj['People'] = obj['People'] or [] diff --git a/jellyfin_kodi/objects/music.py b/jellyfin_kodi/objects/music.py index 18a2466d..c0864595 100644 --- a/jellyfin_kodi/objects/music.py +++ b/jellyfin_kodi/objects/music.py @@ -6,7 +6,7 @@ from __future__ import division, absolute_import, print_function, unicode_litera import datetime from database import jellyfin_db, queries as QUEM -from helper import api, stop, validate, jellyfin_item, values, library_check, Local +from helper import api, stop, validate, jellyfin_item, values, Local from helper import LazyLogger from helper.exceptions import PathValidationException @@ -22,7 +22,7 @@ LOG = LazyLogger(__name__) class Music(KodiDb): - def __init__(self, server, jellyfindb, musicdb, direct_path): + def __init__(self, server, jellyfindb, musicdb, direct_path, library): self.server = server self.jellyfin = jellyfindb @@ -32,13 +32,13 @@ class Music(KodiDb): self.jellyfin_db = jellyfin_db.JellyfinDatabase(jellyfindb.cursor) self.objects = Objects() self.item_ids = [] + self.library = library KodiDb.__init__(self, musicdb.cursor) @stop @jellyfin_item - @library_check - def artist(self, item, e_item, library): + def artist(self, item, e_item): ''' If item does not exist, entry will be added. If item exists, entry will be updated. @@ -60,8 +60,8 @@ class Music(KodiDb): update = False LOG.info("ArtistId %s missing from kodi. repairing the entry.", obj['ArtistId']) - obj['LibraryId'] = library['Id'] - obj['LibraryName'] = library['Name'] + obj['LibraryId'] = self.library['Id'] + obj['LibraryName'] = self.library['Name'] obj['LastScraped'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') obj['ArtistType'] = "MusicArtist" obj['Genre'] = " / ".join(obj['Genres'] or []) @@ -199,7 +199,7 @@ class Music(KodiDb): except TypeError: try: - self.artist(self.server.jellyfin.get_item(temp_obj['Id']), library=None) + self.artist(self.server.jellyfin.get_item(temp_obj['Id'])) temp_obj['ArtistId'] = self.jellyfin_db.get_item_by_id(*values(temp_obj, QUEM.get_item_obj))[0] except Exception as error: LOG.exception(error) @@ -209,8 +209,8 @@ class Music(KodiDb): self.link(*values(temp_obj, QU.update_link_obj)) self.item_ids.append(temp_obj['Id']) - @stop() - @jellyfin_item() + @stop + @jellyfin_item def song(self, item, e_item): ''' Update object to kodi. @@ -353,7 +353,7 @@ class Music(KodiDb): except TypeError: try: - self.artist(self.server.jellyfin.get_item(temp_obj['Id']), library=None) + self.artist(self.server.jellyfin.get_item(temp_obj['Id'])) temp_obj['ArtistId'] = self.jellyfin_db.get_item_by_id(*values(temp_obj, QUEM.get_item_obj))[0] except Exception as error: LOG.exception(error) @@ -387,7 +387,7 @@ class Music(KodiDb): except TypeError: try: - self.artist(self.server.jellyfin.get_item(temp_obj['Id']), library=None) + self.artist(self.server.jellyfin.get_item(temp_obj['Id'])) temp_obj['ArtistId'] = self.jellyfin_db.get_item_by_id(*values(temp_obj, QUEM.get_item_obj))[0] except Exception as error: LOG.exception(error) diff --git a/jellyfin_kodi/objects/musicvideos.py b/jellyfin_kodi/objects/musicvideos.py index d5e1fddf..3c4b1679 100644 --- a/jellyfin_kodi/objects/musicvideos.py +++ b/jellyfin_kodi/objects/musicvideos.py @@ -10,7 +10,7 @@ from six.moves.urllib.parse import urlencode from kodi_six.utils import py2_encode from database import jellyfin_db, queries as QUEM -from helper import api, stop, validate, library_check, jellyfin_item, values, Local +from helper import api, stop, validate, jellyfin_item, values, Local from helper import LazyLogger from helper.exceptions import PathValidationException @@ -26,7 +26,7 @@ LOG = LazyLogger(__name__) class MusicVideos(KodiDb): - def __init__(self, server, jellyfindb, videodb, direct_path): + def __init__(self, server, jellyfindb, videodb, direct_path, library): self.server = server self.jellyfin = jellyfindb @@ -36,13 +36,13 @@ class MusicVideos(KodiDb): self.jellyfin_db = jellyfin_db.JellyfinDatabase(jellyfindb.cursor) self.objects = Objects() self.item_ids = [] + self.library = library KodiDb.__init__(self, videodb.cursor) @stop @jellyfin_item - @library_check - def musicvideo(self, item, e_item, library): + def musicvideo(self, item, e_item): ''' If item does not exist, entry will be added. If item exists, entry will be updated. @@ -70,8 +70,8 @@ class MusicVideos(KodiDb): LOG.info("MvideoId %s missing from kodi. repairing the entry.", obj['MvideoId']) obj['Path'] = API.get_file_path(obj['Path']) - obj['LibraryId'] = library['Id'] - obj['LibraryName'] = library['Name'] + obj['LibraryId'] = self.library['Id'] + obj['LibraryName'] = self.library['Name'] obj['Genres'] = obj['Genres'] or [] obj['ArtistItems'] = obj['ArtistItems'] or [] obj['Studios'] = [API.validate_studio(studio) for studio in (obj['Studios'] or [])] diff --git a/jellyfin_kodi/objects/tvshows.py b/jellyfin_kodi/objects/tvshows.py index 6247330c..124e95dc 100644 --- a/jellyfin_kodi/objects/tvshows.py +++ b/jellyfin_kodi/objects/tvshows.py @@ -11,7 +11,7 @@ from kodi_six.utils import py2_encode import downloader as server from database import jellyfin_db, queries as QUEM -from helper import api, stop, validate, jellyfin_item, library_check, values, Local +from helper import api, stop, validate, jellyfin_item, values, Local from helper import LazyLogger from helper.exceptions import PathValidationException @@ -27,7 +27,7 @@ LOG = LazyLogger(__name__) class TVShows(KodiDb): - def __init__(self, server, jellyfindb, videodb, direct_path, update_library=False): + def __init__(self, server, jellyfindb, videodb, direct_path, library, update_library=False): self.server = server self.jellyfin = jellyfindb @@ -38,13 +38,13 @@ class TVShows(KodiDb): self.jellyfin_db = jellyfin_db.JellyfinDatabase(jellyfindb.cursor) self.objects = Objects() self.item_ids = [] + self.library = library KodiDb.__init__(self, videodb.cursor) @stop @jellyfin_item - @library_check - def tvshow(self, item, e_item, library): + def tvshow(self, item, e_item): ''' If item does not exist, entry will be added. If item exists, entry will be updated. @@ -72,8 +72,8 @@ class TVShows(KodiDb): LOG.info("ShowId %s missing from kodi. repairing the entry.", obj['ShowId']) obj['Path'] = API.get_file_path(obj['Path']) - obj['LibraryId'] = library['Id'] - obj['LibraryName'] = library['Name'] + obj['LibraryId'] = self.library['Id'] + obj['LibraryName'] = self.library['Name'] obj['Genres'] = obj['Genres'] or [] obj['People'] = obj['People'] or [] obj['Mpaa'] = API.get_mpaa(obj['Mpaa']) @@ -411,7 +411,7 @@ class TVShows(KodiDb): if obj['ShowId'] is None: try: - self.tvshow(self.server.jellyfin.get_item(obj['SeriesId']), library=None) + self.tvshow(self.server.jellyfin.get_item(obj['SeriesId'])) obj['ShowId'] = self.jellyfin_db.get_item_by_id(*values(obj, QUEM.get_item_series_obj))[0] except (TypeError, KeyError) as error: LOG.error("Unable to add series %s", obj['SeriesId']) From 4178f0a36226a5d5cb01097ee811f2fe874dc412 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 2 Aug 2020 18:50:57 -0400 Subject: [PATCH 5/9] Fix boxset syncing --- jellyfin_kodi/full_sync.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/jellyfin_kodi/full_sync.py b/jellyfin_kodi/full_sync.py index c86596a8..09c6b9ac 100644 --- a/jellyfin_kodi/full_sync.py +++ b/jellyfin_kodi/full_sync.py @@ -214,10 +214,17 @@ class FullSync(object): try: if library_id.startswith('Boxsets:'): - if library_id.endswith('Refresh'): - self.refresh_boxsets() - else: - self.boxsets(library_id.split('Boxsets:')[1] if len(library_id) > len('Boxsets:') else None) + libraries = self.get_libraries(library_id.split('Boxsets:')[1] if len(library_id) > len('Boxsets:') else None) + for entry in libraries: + if entry[2] == 'boxsets': + boxset_library = {'Id': entry[0], 'Name': entry[1]} + break + + if boxset_library: + if library_id.endswith('Refresh'): + self.refresh_boxsets(boxset_library) + else: + self.boxsets(boxset_library) return @@ -461,11 +468,11 @@ class FullSync(object): obj.remove(x[0]) @progress(translate(33018)) - def boxsets(self, library_id=None, dialog=None): + def boxsets(self, library, dialog=None): ''' Process all boxsets. ''' - for items in server.get_items(library_id, "BoxSet", False, self.sync['RestorePoint'].get('params')): + for items in server.get_items(library['Id'], "BoxSet", False, self.sync['RestorePoint'].get('params')): with self.video_database_locks() as (videodb, jellyfindb): obj = Movies(self.server, jellyfindb, videodb, self.direct_path, library) @@ -480,7 +487,7 @@ class FullSync(object): message=boxset['Name']) obj.boxset(boxset) - def refresh_boxsets(self): + def refresh_boxsets(self, library): ''' Delete all exisitng boxsets and re-add. ''' From 7f012dc8b03e94683c7e9a82474b833c88a62baf Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 2 Aug 2020 19:12:15 -0400 Subject: [PATCH 6/9] Fix undefined variable in remove function --- jellyfin_kodi/library.py | 8 ++++---- jellyfin_kodi/objects/movies.py | 2 +- jellyfin_kodi/objects/music.py | 2 +- jellyfin_kodi/objects/musicvideos.py | 2 +- jellyfin_kodi/objects/tvshows.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/jellyfin_kodi/library.py b/jellyfin_kodi/library.py index 9a94361f..0af70723 100644 --- a/jellyfin_kodi/library.py +++ b/jellyfin_kodi/library.py @@ -772,13 +772,13 @@ class RemovedWorker(threading.Thread): break if item['Type'] == 'Movie': - obj = Movies(self.args[0], jellyfindb, kodidb, self.args[1], library).remove + obj = Movies(self.args[0], jellyfindb, kodidb, self.args[1]).remove elif item['Type'] in ['Series', 'Season', 'Episode']: - obj = TVShows(self.args[0], jellyfindb, kodidb, self.args[1], library).remove + obj = TVShows(self.args[0], jellyfindb, kodidb, self.args[1]).remove elif item['Type'] in ['MusicAlbum', 'MusicArtist', 'AlbumArtist', 'Audio']: - obj = Music(self.args[0], jellyfindb, kodidb, self.args[1], library).remove + obj = Music(self.args[0], jellyfindb, kodidb, self.args[1]).remove elif item['Type'] == 'MusicVideo': - obj = MusicVideos(self.args[0], jellyfindb, kodidb, self.args[1], library).remove + obj = MusicVideos(self.args[0], jellyfindb, kodidb, self.args[1]).remove try: obj(item['Id']) diff --git a/jellyfin_kodi/objects/movies.py b/jellyfin_kodi/objects/movies.py index d761fd66..6aa03081 100644 --- a/jellyfin_kodi/objects/movies.py +++ b/jellyfin_kodi/objects/movies.py @@ -24,7 +24,7 @@ LOG = LazyLogger(__name__) class Movies(KodiDb): - def __init__(self, server, jellyfindb, videodb, direct_path, library): + def __init__(self, server, jellyfindb, videodb, direct_path, library=None): self.server = server self.jellyfin = jellyfindb diff --git a/jellyfin_kodi/objects/music.py b/jellyfin_kodi/objects/music.py index c0864595..c0dec150 100644 --- a/jellyfin_kodi/objects/music.py +++ b/jellyfin_kodi/objects/music.py @@ -22,7 +22,7 @@ LOG = LazyLogger(__name__) class Music(KodiDb): - def __init__(self, server, jellyfindb, musicdb, direct_path, library): + def __init__(self, server, jellyfindb, musicdb, direct_path, library=None): self.server = server self.jellyfin = jellyfindb diff --git a/jellyfin_kodi/objects/musicvideos.py b/jellyfin_kodi/objects/musicvideos.py index 3c4b1679..a42d345e 100644 --- a/jellyfin_kodi/objects/musicvideos.py +++ b/jellyfin_kodi/objects/musicvideos.py @@ -26,7 +26,7 @@ LOG = LazyLogger(__name__) class MusicVideos(KodiDb): - def __init__(self, server, jellyfindb, videodb, direct_path, library): + def __init__(self, server, jellyfindb, videodb, direct_path, library=None): self.server = server self.jellyfin = jellyfindb diff --git a/jellyfin_kodi/objects/tvshows.py b/jellyfin_kodi/objects/tvshows.py index 124e95dc..de849045 100644 --- a/jellyfin_kodi/objects/tvshows.py +++ b/jellyfin_kodi/objects/tvshows.py @@ -27,7 +27,7 @@ LOG = LazyLogger(__name__) class TVShows(KodiDb): - def __init__(self, server, jellyfindb, videodb, direct_path, library, update_library=False): + def __init__(self, server, jellyfindb, videodb, direct_path, library=None, update_library=False): self.server = server self.jellyfin = jellyfindb From dc6c9e7dc2184bcdd4806c104ceefc2d41b35c92 Mon Sep 17 00:00:00 2001 From: Matt Date: Sun, 2 Aug 2020 19:15:59 -0400 Subject: [PATCH 7/9] Fix code smells for unused variables --- jellyfin_kodi/library.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/jellyfin_kodi/library.py b/jellyfin_kodi/library.py index 0af70723..a4c2550e 100644 --- a/jellyfin_kodi/library.py +++ b/jellyfin_kodi/library.py @@ -611,25 +611,25 @@ class UpdateWorker(threading.Thread): default_args = (self.server, jellyfindb, kodidb, self.direct_path, library) try: if item['Type'] == 'Movie': - obj = Movies(*default_args).movie(item) + Movies(*default_args).movie(item) elif item['Type'] == 'BoxSet': - obj = Movies(*default_args).boxset(item) + Movies(*default_args).boxset(item) elif item['Type'] == 'Series': - obj = TVShows(*default_args).tvshow(item) + TVShows(*default_args).tvshow(item) elif item['Type'] == 'Season': - obj = TVShows(*default_args).season(item) + TVShows(*default_args).season(item) elif item['Type'] == 'Episode': - obj = TVShows(*default_args).episode(item) + TVShows(*default_args).episode(item) elif item['Type'] == 'MusicVideo': - obj = MusicVideos(*default_args).musicvideo(item) + MusicVideos(*default_args).musicvideo(item) elif item['Type'] == 'MusicAlbum': - obj = Music(*default_args).album(item) + Music(*default_args).album(item) elif item['Type'] == 'MusicArtist': - obj = Music(*default_args).artist(item) + Music(*default_args).artist(item) elif item['Type'] == 'AlbumArtist': - obj = Music(*default_args).albumartist(item) + Music(*default_args).albumartist(item) elif item['Type'] == 'Audio': - obj = Music(*default_args).song(item) + Music(*default_args).song(item) if self.notify: self.notify_output.put((item['Type'], api.API(item).get_naming())) @@ -676,17 +676,17 @@ class UserDataWorker(threading.Thread): default_args = (self.server, jellyfindb, kodidb, self.direct_path, library) try: if item['Type'] == 'Movie': - Movies(self.args[0], jellyfindb, kodidb, self.args[1]).userdata(item) + Movies(*default_args).userdata(item) elif item['Type'] in ['Series', 'Season', 'Episode']: - TVShows(self.args[0], jellyfindb, kodidb, self.args[1]).userdata(item) + TVShows(*default_args).userdata(item) elif item['Type'] == 'MusicAlbum': - Music(self.args[0], jellyfindb, kodidb, self.args[1]).album(item) + Music(*default_args).album(item) elif item['Type'] == 'MusicArtist': - Music(self.args[0], jellyfindb, kodidb, self.args[1]).artist(item) + Music(*default_args).artist(item) elif item['Type'] == 'AlbumArtist': - Music(self.args[0], jellyfindb, kodidb, self.args[1]).albumartist(item) + Music(*default_args).albumartist(item) elif item['Type'] == 'Audio': - Music(self.args[0], jellyfindb, kodidb, self.args[1]).song(item) + Music(*default_args).song(item) except LibraryException as error: if error.status == 'StopCalled': break From ce21b375018fae80aa4d5a8ee8c34089b74942b8 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 3 Aug 2020 14:37:49 -0400 Subject: [PATCH 8/9] Remove unneeded message variable --- jellyfin_kodi/full_sync.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jellyfin_kodi/full_sync.py b/jellyfin_kodi/full_sync.py index 09c6b9ac..fe61044d 100644 --- a/jellyfin_kodi/full_sync.py +++ b/jellyfin_kodi/full_sync.py @@ -428,8 +428,7 @@ class FullSync(object): # Update percentage dialog percent = int((float(index) / float(num_artists)) * 100) - message = artist_name - dialog.update(percent, heading="%s: %s" % (translate('addon_name'), library['Name']), message=message) + dialog.update(percent, heading="%s: %s" % (translate('addon_name'), library['Name']), message=artist_name) # Add artist to database obj.artist(artist) @@ -444,7 +443,7 @@ class FullSync(object): album_songs = [ song for song in songs if album_id == song.get('AlbumId') ] for song in album_songs: dialog.update(percent, - message="%s/%s/%s" % (message, album['Name'][:7], song['Name'][:7])) + message="%s/%s/%s" % (artist_name, album['Name'][:7], song['Name'][:7])) # Add song to database obj.song(song) # From d10ca845f490d58e4c8c79e2da354e2cc6b67b3f Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 3 Aug 2020 15:07:26 -0400 Subject: [PATCH 9/9] empty default if there are no boxsets in the server --- jellyfin_kodi/full_sync.py | 1 + 1 file changed, 1 insertion(+) diff --git a/jellyfin_kodi/full_sync.py b/jellyfin_kodi/full_sync.py index fe61044d..cebbd565 100644 --- a/jellyfin_kodi/full_sync.py +++ b/jellyfin_kodi/full_sync.py @@ -213,6 +213,7 @@ class FullSync(object): } try: if library_id.startswith('Boxsets:'): + boxset_library = {} libraries = self.get_libraries(library_id.split('Boxsets:')[1] if len(library_id) > len('Boxsets:') else None) for entry in libraries: