Merge branch 'beta-version'

This commit is contained in:
Croneter 2018-07-06 09:04:36 +02:00
commit 5926168427
6 changed files with 102 additions and 15 deletions

View file

@ -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.8-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.9-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)

View file

@ -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.8" provider-name="croneter"> <addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="2.2.9" 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,13 @@
<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.8 (beta only): <news>version 2.2.9 (beta only):
- Hopefully fix Kodi and Plex playlists getting out of sync
- Fix and optimize startup of playlist sync
- Hide certain playlist settings under certain conditions
- Fix errors in Kodi log
version 2.2.8 (beta only):
- Support for Plex collection artwork (PKC settings toggle under Artwork) - Support for Plex collection artwork (PKC settings toggle under Artwork)
- Fix hard PKC reset not working (OSError: no such file) - Fix hard PKC reset not working (OSError: no such file)
- Deduplication - Deduplication

View file

@ -1,3 +1,9 @@
version 2.2.9 (beta only):
- Hopefully fix Kodi and Plex playlists getting out of sync
- Fix and optimize startup of playlist sync
- Hide certain playlist settings under certain conditions
- Fix errors in Kodi log
version 2.2.8 (beta only): version 2.2.8 (beta only):
- Support for Plex collection artwork (PKC settings toggle under Artwork) - Support for Plex collection artwork (PKC settings toggle under Artwork)
- Fix hard PKC reset not working (OSError: no such file) - Fix hard PKC reset not working (OSError: no such file)

View file

@ -262,9 +262,10 @@ class LibrarySync(Thread):
# This will NOT update playstates and userratings! # This will NOT update playstates and userratings!
LOG.info('Running fullsync for CHANGED PMS items with repair=%s', LOG.info('Running fullsync for CHANGED PMS items with repair=%s',
repair) repair)
if self._full_sync() is False: if not self._full_sync():
return False
if not playlists.full_sync():
return False return False
playlists.full_sync()
return True return True
def _full_sync(self): def _full_sync(self):
@ -1265,8 +1266,8 @@ class LibrarySync(Thread):
""" """
for item in data: for item in data:
status = item['state'] status = item['state']
if status == 'buffering': if status == 'buffering' or status == 'stopped':
# Drop buffering messages immediately # Drop buffering and stop messages immediately - no value
continue continue
plex_id = item['ratingKey'] plex_id = item['ratingKey']
skip = False skip = False
@ -1561,10 +1562,9 @@ class LibrarySync(Thread):
initial_sync_done = True initial_sync_done = True
kodi_db_version_checked = True kodi_db_version_checked = True
last_sync = utils.unix_timestamp() last_sync = utils.unix_timestamp()
playlist_monitor = playlists.kodi_playlist_monitor()
self.sync_fanart() self.sync_fanart()
self.fanartthread.start() self.fanartthread.start()
if state.SYNC_PLAYLISTS and playlists.full_sync():
playlist_monitor = playlists.kodi_playlist_monitor()
else: else:
LOG.error('Initial start-up full sync unsuccessful') LOG.error('Initial start-up full sync unsuccessful')
xbmc.executebuiltin('InhibitIdleShutdown(false)') xbmc.executebuiltin('InhibitIdleShutdown(false)')
@ -1614,11 +1614,10 @@ class LibrarySync(Thread):
initial_sync_done = True initial_sync_done = True
last_sync = utils.unix_timestamp() last_sync = utils.unix_timestamp()
LOG.info('Done initial sync on Kodi startup') LOG.info('Done initial sync on Kodi startup')
playlist_monitor = playlists.kodi_playlist_monitor()
artwork.Artwork().cache_major_artwork() artwork.Artwork().cache_major_artwork()
self.sync_fanart() self.sync_fanart()
self.fanartthread.start() self.fanartthread.start()
if state.SYNC_PLAYLISTS and playlists.full_sync():
playlist_monitor = playlists.kodi_playlist_monitor()
else: else:
LOG.info('Startup sync has not yet been successful') LOG.info('Startup sync has not yet been successful')
utils.window('plex_dbScan', clear=True) utils.window('plex_dbScan', clear=True)

View file

@ -1,8 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from logging import getLogger from logging import getLogger
import Queue
import xbmc
from .watchdog import events from .watchdog import events
from .watchdog.observers import Observer from .watchdog.observers import Observer
from .watchdog.utils.bricks import OrderedSetQueue
from . import playlist_func as PL from . import playlist_func as PL
from .plex_api import API from .plex_api import API
from . import kodidb_functions as kodidb from . import kodidb_functions as kodidb
@ -16,6 +19,11 @@ from . import state
LOG = getLogger('PLEX.playlists') LOG = getLogger('PLEX.playlists')
# Safety margin for playlist filesystem operations
FILESYSTEM_TIMEOUT = 3
# These filesystem events are considered similar
SIMILAR_EVENTS = (events.EVENT_TYPE_CREATED, events.EVENT_TYPE_MODIFIED)
# Which playlist formates are supported by PKC? # Which playlist formates are supported by PKC?
SUPPORTED_FILETYPES = ( SUPPORTED_FILETYPES = (
'm3u', 'm3u',
@ -329,6 +337,9 @@ def full_sync():
Full sync of playlists between Kodi and Plex. Returns True is successful, Full sync of playlists between Kodi and Plex. Returns True is successful,
False otherwise False otherwise
""" """
if not state.SYNC_PLAYLISTS:
LOG.debug('Not syncing playlists')
return True
LOG.info('Starting playlist full sync') LOG.info('Starting playlist full sync')
with state.LOCK_PLAYLISTS: with state.LOCK_PLAYLISTS:
return _full_sync() return _full_sync()
@ -467,6 +478,9 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
:type event: :type event:
:class:`FileSystemEvent` :class:`FileSystemEvent`
""" """
if not state.SYNC_PLAYLISTS:
# Sync is deactivated
return
if event.is_directory: if event.is_directory:
# todo: take care of folder renames # todo: take care of folder renames
return return
@ -545,7 +559,7 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
LOG.debug('on_moved: %s to %s', event.src_path, event.dest_path) LOG.debug('on_moved: %s to %s', event.src_path, event.dest_path)
old_playlist = playlist_object_from_db(path=event.src_path) old_playlist = playlist_object_from_db(path=event.src_path)
if not old_playlist: if not old_playlist:
LOG.error('Did not have source path in the DB', event.src_path) LOG.error('Did not have source path in the DB %s', event.src_path)
else: else:
delete_plex_playlist(old_playlist) delete_plex_playlist(old_playlist)
new_playlist = PL.Playlist_Object() new_playlist = PL.Playlist_Object()
@ -557,6 +571,68 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
pass pass
class PlaylistObserver(Observer):
"""
PKC implementation, overriding the dispatcher. PKC will wait for the
duration timeout (in seconds) before dispatching. A new event will reset
the timer.
Creating and modifying will be regarded as equal.
"""
def __init__(self, *args, **kwargs):
super(PlaylistObserver, self).__init__(*args, **kwargs)
# Drop the same events that get into the queue even if there are other
# events in between these similar events
self._event_queue = OrderedSetQueue()
@staticmethod
def _pkc_similar_events(event1, event2):
if event1 == event2:
return True
elif (event1.src_path == event2.src_path and
event1.event_type in SIMILAR_EVENTS and
event2.event_type in SIMILAR_EVENTS):
# Ignore a consecutive firing of created and modified events
return True
return False
def _dispatch_iterator(self, event_queue, timeout):
"""
This iterator will block for timeout (seconds) until an event is
received or raise Queue.Empty.
"""
event, watch = event_queue.get(block=True, timeout=timeout)
event_queue.task_done()
start = utils.unix_timestamp()
while utils.unix_timestamp() - start < timeout:
if state.STOP_PKC:
raise Queue.Empty
try:
new_event, new_watch = event_queue.get(block=False)
except Queue.Empty:
xbmc.sleep(200)
else:
event_queue.task_done()
start = utils.unix_timestamp()
if self._pkc_similar_events(new_event, event):
continue
else:
# At least on Windows, a dir modified event will be
# triggered once the writing process is done. Fine though
yield event, watch
event, watch = new_event, new_watch
yield event, watch
def dispatch_events(self, event_queue, timeout):
for event, watch in self._dispatch_iterator(event_queue, timeout):
with self._lock:
# To allow unschedule/stop and safe removal of event handlers
# within event handlers itself, check if the handler is still
# registered after every dispatch.
for handler in list(self._handlers.get(watch, [])):
if handler in self._handlers.get(watch, []):
handler.dispatch(event)
def kodi_playlist_monitor(): def kodi_playlist_monitor():
""" """
Monitors the Kodi playlist folder special://profile/playlist for the user. Monitors the Kodi playlist folder special://profile/playlist for the user.
@ -566,7 +642,7 @@ def kodi_playlist_monitor():
observer.stop() (and maybe observer.join()) to shut down properly observer.stop() (and maybe observer.join()) to shut down properly
""" """
event_handler = PlaylistEventhandler() event_handler = PlaylistEventhandler()
observer = Observer() observer = PlaylistObserver(timeout=FILESYSTEM_TIMEOUT)
observer.schedule(event_handler, v.PLAYLIST_PATH, recursive=True) observer.schedule(event_handler, v.PLAYLIST_PATH, recursive=True)
observer.start() observer.start()
return observer return observer

View file

@ -65,9 +65,9 @@
<setting type="lsep" label="$LOCALIZE[136]" /><!-- Playlists --> <setting type="lsep" label="$LOCALIZE[136]" /><!-- Playlists -->
<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="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)"/><!-- Prefix in Kodi playlist name to trigger sync -->
<setting id="syncSpecificPlexPlaylists" type="bool" label="30021" default="false" visible="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)" /><!-- 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 -->