Merge branch 'beta-version'
This commit is contained in:
commit
321930b2f0
8 changed files with 104 additions and 53 deletions
|
@ -1,5 +1,5 @@
|
||||||
[![stable version](https://img.shields.io/badge/stable_version-2.1.3-blue.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/stable/repository.plexkodiconnect/repository.plexkodiconnect-1.0.2.zip)
|
[![stable version](https://img.shields.io/badge/stable_version-2.1.3-blue.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/stable/repository.plexkodiconnect/repository.plexkodiconnect-1.0.2.zip)
|
||||||
[![beta version](https://img.shields.io/badge/beta_version-2.2.9-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip)
|
[![beta version](https://img.shields.io/badge/beta_version-2.2.10-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip)
|
||||||
|
|
||||||
[![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/Installation)
|
[![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/Installation)
|
||||||
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)
|
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)
|
||||||
|
|
11
addon.xml
11
addon.xml
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.2.9" provider-name="croneter">
|
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.2.10" provider-name="croneter">
|
||||||
<requires>
|
<requires>
|
||||||
<import addon="xbmc.python" version="2.1.0"/>
|
<import addon="xbmc.python" version="2.1.0"/>
|
||||||
<import addon="script.module.requests" version="2.9.1" />
|
<import addon="script.module.requests" version="2.9.1" />
|
||||||
|
@ -73,7 +73,14 @@
|
||||||
<summary lang="uk_UA">Нативна інтеграція Plex в Kodi</summary>
|
<summary lang="uk_UA">Нативна інтеграція Plex в Kodi</summary>
|
||||||
<description lang="uk_UA">Підключає Kodi до серверу Plex. Цей плагін передбачає, що ви керуєте всіма своїми відео за допомогою Plex (і ніяк не Kodi). Ви можете втратити дані, які вже зберігаються у відео та музичних БД Kodi (оскільки цей плагін безпосередньо їх змінює). Використовуйте на свій страх і ризик!</description>
|
<description lang="uk_UA">Підключає Kodi до серверу Plex. Цей плагін передбачає, що ви керуєте всіма своїми відео за допомогою Plex (і ніяк не Kodi). Ви можете втратити дані, які вже зберігаються у відео та музичних БД Kodi (оскільки цей плагін безпосередньо їх змінює). Використовуйте на свій страх і ризик!</description>
|
||||||
<disclaimer lang="uk_UA">Використовуйте на свій ризик</disclaimer>
|
<disclaimer lang="uk_UA">Використовуйте на свій ризик</disclaimer>
|
||||||
<news>version 2.2.9 (beta only):
|
<news>version 2.2.10 (beta only):
|
||||||
|
- Fix playlists getting recreated and deleted in an endless loop
|
||||||
|
- Add some safety nets for playlist sync
|
||||||
|
- Fix FutureWarning
|
||||||
|
- Fix playlist sync settings not disappearing
|
||||||
|
- Optimize code
|
||||||
|
|
||||||
|
version 2.2.9 (beta only):
|
||||||
- Hopefully fix Kodi and Plex playlists getting out of sync
|
- Hopefully fix Kodi and Plex playlists getting out of sync
|
||||||
- Fix and optimize startup of playlist sync
|
- Fix and optimize startup of playlist sync
|
||||||
- Hide certain playlist settings under certain conditions
|
- Hide certain playlist settings under certain conditions
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
version 2.2.10 (beta only):
|
||||||
|
- Fix playlists getting recreated and deleted in an endless loop
|
||||||
|
- Add some safety nets for playlist sync
|
||||||
|
- Fix FutureWarning
|
||||||
|
- Fix playlist sync settings not disappearing
|
||||||
|
- Optimize code
|
||||||
|
|
||||||
version 2.2.9 (beta only):
|
version 2.2.9 (beta only):
|
||||||
- Hopefully fix Kodi and Plex playlists getting out of sync
|
- Hopefully fix Kodi and Plex playlists getting out of sync
|
||||||
- Fix and optimize startup of playlist sync
|
- Fix and optimize startup of playlist sync
|
||||||
|
|
|
@ -1189,8 +1189,7 @@ class LibrarySync(Thread):
|
||||||
if typus == 'playlist':
|
if typus == 'playlist':
|
||||||
if not state.SYNC_PLAYLISTS:
|
if not state.SYNC_PLAYLISTS:
|
||||||
continue
|
continue
|
||||||
playlists.process_websocket(plex_id=str(item['itemID']),
|
playlists.process_websocket(plex_id=unicode(item['itemID']),
|
||||||
updated_at=str(item['updatedAt']),
|
|
||||||
status=status)
|
status=status)
|
||||||
elif status == 9:
|
elif status == 9:
|
||||||
# Immediately and always process deletions (as the PMS will
|
# Immediately and always process deletions (as the PMS will
|
||||||
|
|
|
@ -736,6 +736,18 @@ def get_all_playlists():
|
||||||
return xml
|
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):
|
def get_PMS_playlist(playlist, playlist_id=None):
|
||||||
"""
|
"""
|
||||||
Fetches the PMS playlist/playqueue as an XML. Pass in playlist_id if we
|
Fetches the PMS playlist/playqueue as an XML. Pass in playlist_id if we
|
||||||
|
|
|
@ -20,7 +20,7 @@ from . import state
|
||||||
LOG = getLogger('PLEX.playlists')
|
LOG = getLogger('PLEX.playlists')
|
||||||
|
|
||||||
# Safety margin for playlist filesystem operations
|
# Safety margin for playlist filesystem operations
|
||||||
FILESYSTEM_TIMEOUT = 3
|
FILESYSTEM_TIMEOUT = 1
|
||||||
# These filesystem events are considered similar
|
# These filesystem events are considered similar
|
||||||
SIMILAR_EVENTS = (events.EVENT_TYPE_CREATED, events.EVENT_TYPE_MODIFIED)
|
SIMILAR_EVENTS = (events.EVENT_TYPE_CREATED, events.EVENT_TYPE_MODIFIED)
|
||||||
|
|
||||||
|
@ -78,10 +78,10 @@ def delete_plex_playlist(playlist):
|
||||||
update_plex_table(playlist, delete=True)
|
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
|
Creates a new Kodi playlist file. Will also add (or modify an existing)
|
||||||
playlist table entry.
|
Plex playlist table entry.
|
||||||
Assumes that the Plex playlist is indeed new. A NEW Kodi playlist will be
|
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
|
created in any case (not replaced). Thus make sure that the "same" playlist
|
||||||
is deleted from both disk and the Plex database.
|
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
|
Be aware that user settings will be checked whether this Plex playlist
|
||||||
should actually indeed be synced
|
should actually indeed be synced
|
||||||
"""
|
"""
|
||||||
xml = PL.get_PMS_playlist(PL.Playlist_Object(), playlist_id=plex_id)
|
xml_metadata = PL.get_pms_playlist_metadata(plex_id)
|
||||||
if xml is None:
|
if xml_metadata is None:
|
||||||
LOG.error('Could not get Plex playlist %s', plex_id)
|
LOG.error('Could not get Plex playlist metadata %s', plex_id)
|
||||||
raise PL.PlaylistError('Could not get Plex playlist %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:
|
if state.SYNC_SPECIFIC_PLEX_PLAYLISTS:
|
||||||
prefix = utils.settings('syncSpecificPlexPlaylistsPrefix').lower()
|
prefix = utils.settings('syncSpecificPlexPlaylistsPrefix').lower()
|
||||||
if api.title() and not api.title().lower().startswith(prefix):
|
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
|
return
|
||||||
playlist = PL.Playlist_Object()
|
playlist = PL.Playlist_Object()
|
||||||
playlist.id = api.plex_id()
|
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:
|
if not state.ENABLE_MUSIC and playlist.type == v.KODI_PLAYLIST_TYPE_AUDIO:
|
||||||
return
|
return
|
||||||
playlist.plex_name = api.title()
|
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)
|
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)
|
name = utils.valid_filename(playlist.plex_name)
|
||||||
path = path_ops.path.join(v.PLAYLIST_PATH, playlist.type, '%s.m3u' % 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):
|
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))
|
occurance))
|
||||||
LOG.debug('Kodi playlist path: %s', path)
|
LOG.debug('Kodi playlist path: %s', path)
|
||||||
playlist.kodi_path = path
|
playlist.kodi_path = path
|
||||||
# Derive filename close to Plex playlist name
|
xml_playlist = PL.get_PMS_playlist(playlist, playlist_id=plex_id)
|
||||||
_write_playlist_to_file(playlist, xml)
|
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)
|
playlist.kodi_hash = utils.generate_file_md5(path)
|
||||||
update_plex_table(playlist)
|
update_plex_table(playlist)
|
||||||
LOG.debug('Created Kodi playlist based on Plex playlist: %s', playlist)
|
LOG.debug('Created Kodi playlist based on Plex playlist: %s', playlist)
|
||||||
|
@ -303,10 +307,11 @@ def _kodi_playlist_identical(xml_element):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def process_websocket(plex_id, updated_at, status):
|
def process_websocket(plex_id, status):
|
||||||
"""
|
"""
|
||||||
Hit by librarysync to process websocket messages concerning playlists
|
Hit by librarysync to process websocket messages concerning playlists
|
||||||
"""
|
"""
|
||||||
|
|
||||||
create = False
|
create = False
|
||||||
with state.LOCK_PLAYLISTS:
|
with state.LOCK_PLAYLISTS:
|
||||||
playlist = playlist_object_from_db(plex_id=plex_id)
|
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:
|
if playlist and status == 9:
|
||||||
LOG.debug('Plex deletion of playlist detected: %s', playlist)
|
LOG.debug('Plex deletion of playlist detected: %s', playlist)
|
||||||
delete_kodi_playlist(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:
|
elif playlist:
|
||||||
LOG.debug('Change of Plex playlist detected: %s', playlist)
|
xml = PL.get_pms_playlist_metadata(plex_id)
|
||||||
delete_kodi_playlist(playlist)
|
if xml is None:
|
||||||
create = True
|
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:
|
elif not playlist and not status == 9:
|
||||||
LOG.debug('Creation of new Plex playlist detected: %s',
|
LOG.debug('Creation of new Plex playlist detected: %s',
|
||||||
plex_id)
|
plex_id)
|
||||||
create = True
|
create = True
|
||||||
# To the actual work
|
# To the actual work
|
||||||
if create:
|
if create:
|
||||||
create_kodi_playlist(plex_id=plex_id, updated_at=updated_at)
|
create_kodi_playlist(plex_id)
|
||||||
except PL.PlaylistError:
|
except PL.PlaylistError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -367,7 +379,7 @@ def _full_sync():
|
||||||
if not playlist:
|
if not playlist:
|
||||||
LOG.debug('New Plex playlist %s discovered: %s',
|
LOG.debug('New Plex playlist %s discovered: %s',
|
||||||
api.plex_id(), api.title())
|
api.plex_id(), api.title())
|
||||||
create_kodi_playlist(api.plex_id(), api.updated_at())
|
create_kodi_playlist(api.plex_id())
|
||||||
continue
|
continue
|
||||||
elif playlist.plex_updatedat != api.updated_at():
|
elif playlist.plex_updatedat != api.updated_at():
|
||||||
LOG.debug('Detected changed Plex playlist %s: %s',
|
LOG.debug('Detected changed Plex playlist %s: %s',
|
||||||
|
@ -376,7 +388,7 @@ def _full_sync():
|
||||||
delete_kodi_playlist(playlist)
|
delete_kodi_playlist(playlist)
|
||||||
else:
|
else:
|
||||||
update_plex_table(playlist, delete=True)
|
update_plex_table(playlist, delete=True)
|
||||||
create_kodi_playlist(api.plex_id(), api.updated_at())
|
create_kodi_playlist(api.plex_id())
|
||||||
except PL.PlaylistError:
|
except PL.PlaylistError:
|
||||||
LOG.info('Skipping playlist %s: %s', api.plex_id(), api.title())
|
LOG.info('Skipping playlist %s: %s', api.plex_id(), api.title())
|
||||||
try:
|
try:
|
||||||
|
@ -481,9 +493,6 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
|
||||||
if not state.SYNC_PLAYLISTS:
|
if not state.SYNC_PLAYLISTS:
|
||||||
# Sync is deactivated
|
# Sync is deactivated
|
||||||
return
|
return
|
||||||
if event.is_directory:
|
|
||||||
# todo: take care of folder renames
|
|
||||||
return
|
|
||||||
try:
|
try:
|
||||||
_, extension = event.src_path.rsplit('.', 1)
|
_, extension = event.src_path.rsplit('.', 1)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -505,16 +514,20 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
|
||||||
events.EVENT_TYPE_CREATED: self.on_created,
|
events.EVENT_TYPE_CREATED: self.on_created,
|
||||||
events.EVENT_TYPE_DELETED: self.on_deleted,
|
events.EVENT_TYPE_DELETED: self.on_deleted,
|
||||||
}
|
}
|
||||||
event_type = event.event_type
|
|
||||||
with state.LOCK_PLAYLISTS:
|
with state.LOCK_PLAYLISTS:
|
||||||
_method_map[event_type](event)
|
_method_map[event.event_type](event)
|
||||||
|
|
||||||
def on_created(self, event):
|
def on_created(self, event):
|
||||||
LOG.debug('on_created: %s', event.src_path)
|
LOG.debug('on_created: %s', event.src_path)
|
||||||
old_playlist = playlist_object_from_db(path=event.src_path)
|
old_playlist = playlist_object_from_db(path=event.src_path)
|
||||||
if old_playlist:
|
if (old_playlist and old_playlist.kodi_hash ==
|
||||||
|
utils.generate_file_md5(event.src_path)):
|
||||||
LOG.debug('Playlist already in DB - skipping')
|
LOG.debug('Playlist already in DB - skipping')
|
||||||
return
|
return
|
||||||
|
elif old_playlist:
|
||||||
|
LOG.debug('Playlist already in DB but it has been changed')
|
||||||
|
self.on_modified(event)
|
||||||
|
return
|
||||||
playlist = PL.Playlist_Object()
|
playlist = PL.Playlist_Object()
|
||||||
playlist.kodi_path = event.src_path
|
playlist.kodi_path = event.src_path
|
||||||
playlist.kodi_hash = utils.generate_file_md5(event.src_path)
|
playlist.kodi_hash = utils.generate_file_md5(event.src_path)
|
||||||
|
@ -523,20 +536,13 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
|
||||||
except PL.PlaylistError:
|
except PL.PlaylistError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_deleted(self, event):
|
|
||||||
LOG.debug('on_deleted: %s', event.src_path)
|
|
||||||
playlist = playlist_object_from_db(path=event.src_path)
|
|
||||||
if not playlist:
|
|
||||||
LOG.error('Playlist not found in DB for path %s', event.src_path)
|
|
||||||
else:
|
|
||||||
delete_plex_playlist(playlist)
|
|
||||||
|
|
||||||
def on_modified(self, event):
|
def on_modified(self, event):
|
||||||
LOG.debug('on_modified: %s', event.src_path)
|
LOG.debug('on_modified: %s', event.src_path)
|
||||||
old_playlist = playlist_object_from_db(path=event.src_path)
|
old_playlist = playlist_object_from_db(path=event.src_path)
|
||||||
new_playlist = PL.Playlist_Object()
|
new_playlist = PL.Playlist_Object()
|
||||||
if old_playlist:
|
if old_playlist:
|
||||||
# Retain the name! Might've vom from Plex
|
# Retain the name! Might've come from Plex
|
||||||
|
# (rename should fire on_moved)
|
||||||
new_playlist.plex_name = old_playlist.plex_name
|
new_playlist.plex_name = old_playlist.plex_name
|
||||||
new_playlist.kodi_path = event.src_path
|
new_playlist.kodi_path = event.src_path
|
||||||
new_playlist.kodi_hash = utils.generate_file_md5(event.src_path)
|
new_playlist.kodi_hash = utils.generate_file_md5(event.src_path)
|
||||||
|
@ -570,19 +576,40 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
|
||||||
except PL.PlaylistError:
|
except PL.PlaylistError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def on_deleted(self, event):
|
||||||
|
LOG.debug('on_deleted: %s', event.src_path)
|
||||||
|
playlist = playlist_object_from_db(path=event.src_path)
|
||||||
|
if not playlist:
|
||||||
|
LOG.error('Playlist not found in DB for path %s', event.src_path)
|
||||||
|
else:
|
||||||
|
delete_plex_playlist(playlist)
|
||||||
|
|
||||||
|
|
||||||
|
class PlaylistQueue(OrderedSetQueue):
|
||||||
|
"""
|
||||||
|
OrderedSetQueue that drops all directory events immediately
|
||||||
|
"""
|
||||||
|
def _put(self, item):
|
||||||
|
if item[0].is_directory:
|
||||||
|
self.unfinished_tasks -= 1
|
||||||
|
else:
|
||||||
|
# Can't use super as OrderedSetQueue is old style class
|
||||||
|
OrderedSetQueue._put(self, item)
|
||||||
|
|
||||||
|
|
||||||
class PlaylistObserver(Observer):
|
class PlaylistObserver(Observer):
|
||||||
"""
|
"""
|
||||||
PKC implementation, overriding the dispatcher. PKC will wait for the
|
PKC implementation, overriding the dispatcher. PKC will wait for the
|
||||||
duration timeout (in seconds) before dispatching. A new event will reset
|
duration timeout (in seconds) AFTER receiving a filesystem event. A new
|
||||||
the timer.
|
("non-similar") event will reset the timer.
|
||||||
Creating and modifying will be regarded as equal.
|
Creating and modifying will be regarded as equal.
|
||||||
"""
|
"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(PlaylistObserver, self).__init__(*args, **kwargs)
|
super(PlaylistObserver, self).__init__(*args, **kwargs)
|
||||||
# Drop the same events that get into the queue even if there are other
|
# Drop the same events that get into the queue even if there are other
|
||||||
# events in between these similar events
|
# events in between these similar events. Ignore directory events
|
||||||
self._event_queue = OrderedSetQueue()
|
# completely
|
||||||
|
self._event_queue = PlaylistQueue()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _pkc_similar_events(event1, event2):
|
def _pkc_similar_events(event1, event2):
|
||||||
|
@ -591,7 +618,7 @@ class PlaylistObserver(Observer):
|
||||||
elif (event1.src_path == event2.src_path and
|
elif (event1.src_path == event2.src_path and
|
||||||
event1.event_type in SIMILAR_EVENTS and
|
event1.event_type in SIMILAR_EVENTS and
|
||||||
event2.event_type in SIMILAR_EVENTS):
|
event2.event_type in SIMILAR_EVENTS):
|
||||||
# Ignore a consecutive firing of created and modified events
|
# Set created and modified events to equal
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -616,14 +643,13 @@ class PlaylistObserver(Observer):
|
||||||
if self._pkc_similar_events(new_event, event):
|
if self._pkc_similar_events(new_event, event):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
# At least on Windows, a dir modified event will be
|
|
||||||
# triggered once the writing process is done. Fine though
|
|
||||||
yield event, watch
|
yield event, watch
|
||||||
event, watch = new_event, new_watch
|
event, watch = new_event, new_watch
|
||||||
yield event, watch
|
yield event, watch
|
||||||
|
|
||||||
def dispatch_events(self, event_queue, timeout):
|
def dispatch_events(self, event_queue, timeout):
|
||||||
for event, watch in self._dispatch_iterator(event_queue, timeout):
|
for event, watch in self._dispatch_iterator(event_queue, timeout):
|
||||||
|
# This is copy-paste of original code
|
||||||
with self._lock:
|
with self._lock:
|
||||||
# To allow unschedule/stop and safe removal of event handlers
|
# To allow unschedule/stop and safe removal of event handlers
|
||||||
# within event handlers itself, check if the handler is still
|
# within event handlers itself, check if the handler is still
|
||||||
|
|
|
@ -1218,7 +1218,7 @@ class API(object):
|
||||||
Pass in the collection id of e.g. the movie's metadata
|
Pass in the collection id of e.g. the movie's metadata
|
||||||
"""
|
"""
|
||||||
xml = PF.collections(self.library_section_id())
|
xml = PF.collections(self.library_section_id())
|
||||||
if not xml:
|
if xml is None:
|
||||||
return []
|
return []
|
||||||
return [(i.get('index'), i.get('ratingKey')) for i in xml]
|
return [(i.get('index'), i.get('ratingKey')) for i in xml]
|
||||||
|
|
||||||
|
|
|
@ -66,9 +66,9 @@
|
||||||
<setting type="sep" />
|
<setting type="sep" />
|
||||||
<setting id="enablePlaylistSync" type="bool" label="30020" default="true" visible="true"/><!-- Sync Plex playlists -->
|
<setting id="enablePlaylistSync" type="bool" label="30020" default="true" visible="true"/><!-- Sync Plex playlists -->
|
||||||
<setting id="syncSpecificKodiPlaylists" type="bool" label="30023" default="false" visible="eq(-1,true)" /><!-- Only sync specific Kodi playlists to Plex -->
|
<setting id="syncSpecificKodiPlaylists" type="bool" label="30023" default="false" visible="eq(-1,true)" /><!-- Only sync specific Kodi playlists to Plex -->
|
||||||
<setting id="syncSpecificKodiPlaylistsPrefix" type="text" label="30027" default="sync_" visible="eq(-1,true)"/><!-- Prefix in Kodi playlist name to trigger sync -->
|
<setting id="syncSpecificKodiPlaylistsPrefix" type="text" label="30027" default="sync_" visible="eq(-1,true) + eq(-2,true)"/><!-- Prefix in Kodi playlist name to trigger sync -->
|
||||||
<setting id="syncSpecificPlexPlaylists" type="bool" label="30021" default="false" visible="eq(-3,true)"/><!-- Only sync specific Plex playlists to Kodi -->
|
<setting id="syncSpecificPlexPlaylists" type="bool" label="30021" default="false" visible="eq(-3,true)"/><!-- Only sync specific Plex playlists to Kodi -->
|
||||||
<setting id="syncSpecificPlexPlaylistsPrefix" type="text" label="30026" default="sync_" visible="eq(-1,true)" /><!-- Prefix in Plex playlist name to trigger sync -->
|
<setting id="syncSpecificPlexPlaylistsPrefix" type="text" label="30026" default="sync_" visible="eq(-1,true) + eq(-4,true)" /><!-- Prefix in Plex playlist name to trigger sync -->
|
||||||
<setting type="sep" />
|
<setting type="sep" />
|
||||||
<setting type="lsep" label="39052" /><!-- Background Sync -->
|
<setting type="lsep" label="39052" /><!-- Background Sync -->
|
||||||
<setting id="enableBackgroundSync" type="bool" label="39026" default="true" visible="true"/>
|
<setting id="enableBackgroundSync" type="bool" label="39026" default="true" visible="true"/>
|
||||||
|
|
Loading…
Reference in a new issue