From d44e782543bff2f53a99eaeebd99c6d7eeda0709 Mon Sep 17 00:00:00 2001 From: croneter Date: Sat, 7 Jul 2018 18:21:50 +0200 Subject: [PATCH] Fix playlists getting recreated and deleted in an endless loop --- resources/lib/librarysync.py | 3 +- resources/lib/playlist_func.py | 12 ++++++++ resources/lib/playlists.py | 54 +++++++++++++++++++++------------- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index 41fc10e0..64e44764 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -1189,8 +1189,7 @@ class LibrarySync(Thread): if typus == 'playlist': if not state.SYNC_PLAYLISTS: continue - playlists.process_websocket(plex_id=str(item['itemID']), - updated_at=str(item['updatedAt']), + playlists.process_websocket(plex_id=unicode(item['itemID']), status=status) elif status == 9: # Immediately and always process deletions (as the PMS will diff --git a/resources/lib/playlist_func.py b/resources/lib/playlist_func.py index c688f857..9bd668c0 100644 --- a/resources/lib/playlist_func.py +++ b/resources/lib/playlist_func.py @@ -736,6 +736,18 @@ def get_all_playlists(): return xml +def get_pms_playlist_metadata(plex_id): + """ + Returns an xml with the entire metadata like updatedAt. + """ + xml = DU().downloadUrl('{server}/playlists/%s' % plex_id) + try: + xml.attrib + except AttributeError: + xml = None + return xml + + def get_PMS_playlist(playlist, playlist_id=None): """ Fetches the PMS playlist/playqueue as an XML. Pass in playlist_id if we diff --git a/resources/lib/playlists.py b/resources/lib/playlists.py index dcf3e0a5..822bfbb6 100644 --- a/resources/lib/playlists.py +++ b/resources/lib/playlists.py @@ -78,10 +78,10 @@ def delete_plex_playlist(playlist): update_plex_table(playlist, delete=True) -def create_kodi_playlist(plex_id=None, updated_at=None): +def create_kodi_playlist(plex_id): """ - Creates a new Kodi playlist file. Will also add (or modify an existing) Plex - playlist table entry. + Creates a new Kodi playlist file. Will also add (or modify an existing) + Plex playlist table entry. Assumes that the Plex playlist is indeed new. A NEW Kodi playlist will be created in any case (not replaced). Thus make sure that the "same" playlist is deleted from both disk and the Plex database. @@ -90,15 +90,15 @@ def create_kodi_playlist(plex_id=None, updated_at=None): Be aware that user settings will be checked whether this Plex playlist should actually indeed be synced """ - xml = PL.get_PMS_playlist(PL.Playlist_Object(), playlist_id=plex_id) - if xml is None: - LOG.error('Could not get Plex playlist %s', plex_id) + xml_metadata = PL.get_pms_playlist_metadata(plex_id) + if xml_metadata is None: + LOG.error('Could not get Plex playlist metadata %s', plex_id) raise PL.PlaylistError('Could not get Plex playlist %s' % plex_id) - api = API(xml) + api = API(xml_metadata[0]) if state.SYNC_SPECIFIC_PLEX_PLAYLISTS: prefix = utils.settings('syncSpecificPlexPlaylistsPrefix').lower() if api.title() and not api.title().lower().startswith(prefix): - LOG.debug('User chose to not sync playlist %s', api.title()) + LOG.debug('User chose to not sync Plex playlist %s', api.title()) return playlist = PL.Playlist_Object() playlist.id = api.plex_id() @@ -106,8 +106,9 @@ def create_kodi_playlist(plex_id=None, updated_at=None): if not state.ENABLE_MUSIC and playlist.type == v.KODI_PLAYLIST_TYPE_AUDIO: return playlist.plex_name = api.title() - playlist.plex_updatedat = updated_at + playlist.plex_updatedat = api.updated_at() LOG.debug('Creating new Kodi playlist from Plex playlist: %s', playlist) + # Derive filename close to Plex playlist name name = utils.valid_filename(playlist.plex_name) path = path_ops.path.join(v.PLAYLIST_PATH, playlist.type, '%s.m3u' % name) while path_ops.exists(path) or playlist_object_from_db(path=path): @@ -126,8 +127,11 @@ def create_kodi_playlist(plex_id=None, updated_at=None): occurance)) LOG.debug('Kodi playlist path: %s', path) playlist.kodi_path = path - # Derive filename close to Plex playlist name - _write_playlist_to_file(playlist, xml) + xml_playlist = PL.get_PMS_playlist(playlist, playlist_id=plex_id) + if xml_playlist is None: + LOG.error('Could not get Plex playlist %s', plex_id) + raise PL.PlaylistError('Could not get Plex playlist %s' % plex_id) + _write_playlist_to_file(playlist, xml_playlist) playlist.kodi_hash = utils.generate_file_md5(path) update_plex_table(playlist) LOG.debug('Created Kodi playlist based on Plex playlist: %s', playlist) @@ -303,10 +307,11 @@ def _kodi_playlist_identical(xml_element): pass -def process_websocket(plex_id, updated_at, status): +def process_websocket(plex_id, status): """ Hit by librarysync to process websocket messages concerning playlists """ + create = False with state.LOCK_PLAYLISTS: playlist = playlist_object_from_db(plex_id=plex_id) @@ -314,20 +319,27 @@ def process_websocket(plex_id, updated_at, status): if playlist and status == 9: LOG.debug('Plex deletion of playlist detected: %s', playlist) delete_kodi_playlist(playlist) - elif playlist and playlist.plex_updatedat == updated_at: - LOG.debug('Playlist with id %s already synced: %s', - plex_id, playlist) elif playlist: - LOG.debug('Change of Plex playlist detected: %s', playlist) - delete_kodi_playlist(playlist) - create = True + xml = PL.get_pms_playlist_metadata(plex_id) + if not xml: + LOG.error('Could not download playlist %s', plex_id) + return + api = API(xml[0]) + if api.updated_at() == playlist.plex_updatedat: + LOG.debug('Playlist with id %s already synced: %s', + plex_id, playlist) + else: + LOG.debug('Change of Plex playlist detected: %s', + playlist) + delete_kodi_playlist(playlist) + create = True elif not playlist and not status == 9: LOG.debug('Creation of new Plex playlist detected: %s', plex_id) create = True # To the actual work if create: - create_kodi_playlist(plex_id=plex_id, updated_at=updated_at) + create_kodi_playlist(plex_id) except PL.PlaylistError: pass @@ -367,7 +379,7 @@ def _full_sync(): if not playlist: LOG.debug('New Plex playlist %s discovered: %s', api.plex_id(), api.title()) - create_kodi_playlist(api.plex_id(), api.updated_at()) + create_kodi_playlist(api.plex_id()) continue elif playlist.plex_updatedat != api.updated_at(): LOG.debug('Detected changed Plex playlist %s: %s', @@ -376,7 +388,7 @@ def _full_sync(): delete_kodi_playlist(playlist) else: update_plex_table(playlist, delete=True) - create_kodi_playlist(api.plex_id(), api.updated_at()) + create_kodi_playlist(api.plex_id()) except PL.PlaylistError: LOG.info('Skipping playlist %s: %s', api.plex_id(), api.title()) try: