Rewire library sync, suspend sync during playback

- Fixes #451
This commit is contained in:
croneter 2018-04-17 20:18:25 +02:00
parent 88ef5f9eda
commit 678544d236
7 changed files with 592 additions and 625 deletions

View file

@ -136,6 +136,7 @@ class KodiMonitor(xbmc.Monitor):
LOG.debug("Method: %s Data: %s", method, data)
if method == "Player.OnPlay":
state.SUSPEND_SYNC = True
self.PlayBackStart(data)
elif method == "Player.OnStop":
# Should refresh our video nodes, e.g. on deck
@ -149,6 +150,7 @@ class KodiMonitor(xbmc.Monitor):
_playback_cleanup(ended=True)
else:
_playback_cleanup()
state.SUSPEND_SYNC = False
elif method == 'Playlist.OnAdd':
self._playlist_onadd(data)
elif method == 'Playlist.OnRemove':

View file

@ -12,15 +12,16 @@ import variables as v
###############################################################################
log = getLogger("PLEX."+__name__)
LOG = getLogger("PLEX." + __name__)
###############################################################################
@thread_methods(add_suspends=['SUSPEND_LIBRARY_THREAD',
'DB_SCAN',
'STOP_SYNC'])
class Process_Fanart_Thread(Thread):
'STOP_SYNC',
'SUSPEND_SYNC'])
class ThreadedProcessFanart(Thread):
"""
Threaded download of additional fanart in the background
@ -39,21 +40,10 @@ class Process_Fanart_Thread(Thread):
Thread.__init__(self)
def run(self):
"""
Catch all exceptions and log them
"""
try:
self.__run()
except Exception as e:
log.error('Exception %s' % e)
import traceback
log.error("Traceback:\n%s" % traceback.format_exc())
def __run(self):
"""
Do the work
"""
log.debug("---===### Starting FanartSync ###===---")
LOG.debug("---===### Starting FanartSync ###===---")
stopped = self.stopped
suspended = self.suspended
queue = self.queue
@ -63,7 +53,7 @@ class Process_Fanart_Thread(Thread):
# Set in service.py
if stopped():
# Abort was requested while waiting. We should exit
log.info("---===### Stopped FanartSync ###===---")
LOG.info("---===### Stopped FanartSync ###===---")
return
sleep(1000)
# grabs Plex item from queue
@ -73,15 +63,14 @@ class Process_Fanart_Thread(Thread):
sleep(200)
continue
log.debug('Get additional fanart for Plex id %s' % item['plex_id'])
LOG.debug('Get additional fanart for Plex id %s', item['plex_id'])
with getattr(itemtypes,
v.ITEMTYPE_FROM_PLEXTYPE[item['plex_type']])() as cls:
result = cls.getfanart(item['plex_id'],
refresh=item['refresh'])
v.ITEMTYPE_FROM_PLEXTYPE[item['plex_type']])() as item_type:
result = item_type.getfanart(item['plex_id'],
refresh=item['refresh'])
if result is True:
log.debug('Done getting fanart for Plex id %s'
% item['plex_id'])
LOG.debug('Done getting fanart for Plex id %s', item['plex_id'])
with plexdb.Get_Plex_DB() as plex_db:
plex_db.set_fanart_synched(item['plex_id'])
queue.task_done()
log.debug("---===### Stopped FanartSync ###===---")
LOG.debug("---===### Stopped FanartSync ###===---")

View file

@ -11,20 +11,22 @@ import sync_info
###############################################################################
log = getLogger("PLEX."+__name__)
LOG = getLogger("PLEX." + __name__)
###############################################################################
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD', 'STOP_SYNC'])
class Threaded_Get_Metadata(Thread):
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD',
'STOP_SYNC',
'SUSPEND_SYNC'])
class ThreadedGetMetadata(Thread):
"""
Threaded download of Plex XML metadata for a certain library item.
Fills the out_queue with the downloaded etree XML objects
Input:
queue Queue.Queue() object that you'll need to fill up
with Plex itemIds
with plex_ids
out_queue Queue() object where this thread will store
the downloaded metadata XMLs as etree objects
"""
@ -60,21 +62,10 @@ class Threaded_Get_Metadata(Thread):
self.out_queue.task_done()
def run(self):
"""
Catch all exceptions and log them
"""
try:
self.__run()
except Exception as e:
log.error('Exception %s' % e)
import traceback
log.error("Traceback:\n%s" % traceback.format_exc())
def __run(self):
"""
Do the work
"""
log.debug('Starting get metadata thread')
LOG.debug('Starting get metadata thread')
# cache local variables because it's faster
queue = self.queue
out_queue = self.out_queue
@ -88,11 +79,11 @@ class Threaded_Get_Metadata(Thread):
sleep(20)
continue
# Download Metadata
xml = GetPlexMetadata(item['itemId'])
xml = GetPlexMetadata(item['plex_id'])
if xml is None:
# Did not receive a valid XML - skip that item for now
log.error("Could not get metadata for %s. Skipping that item "
"for now" % item['itemId'])
LOG.error("Could not get metadata for %s. Skipping that item "
"for now", item['plex_id'])
# Increase BOTH counters - since metadata won't be processed
with sync_info.LOCK:
sync_info.GET_METADATA_COUNT += 1
@ -100,21 +91,21 @@ class Threaded_Get_Metadata(Thread):
queue.task_done()
continue
elif xml == 401:
log.error('HTTP 401 returned by PMS. Too much strain? '
LOG.error('HTTP 401 returned by PMS. Too much strain? '
'Cancelling sync for now')
window('plex_scancrashed', value='401')
# Kill remaining items in queue (for main thread to cont.)
queue.task_done()
break
item['XML'] = xml
item['xml'] = xml
if item.get('get_children') is True:
children_xml = GetAllPlexChildren(item['itemId'])
children_xml = GetAllPlexChildren(item['plex_id'])
try:
children_xml[0].attrib
except (TypeError, IndexError, AttributeError):
log.error('Could not get children for Plex id %s'
% item['itemId'])
LOG.error('Could not get children for Plex id %s',
item['plex_id'])
item['children'] = []
else:
item['children'] = children_xml
@ -128,4 +119,4 @@ class Threaded_Get_Metadata(Thread):
queue.task_done()
# Empty queue in case PKC was shut down (main thread hangs otherwise)
self.terminate_now()
log.debug('Get metadata thread terminated')
LOG.debug('Get metadata thread terminated')

View file

@ -10,13 +10,15 @@ import itemtypes
import sync_info
###############################################################################
log = getLogger("PLEX."+__name__)
LOG = getLogger("PLEX." + __name__)
###############################################################################
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD', 'STOP_SYNC'])
class Threaded_Process_Metadata(Thread):
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD',
'STOP_SYNC',
'SUSPEND_SYNC'])
class ThreadedProcessMetadata(Thread):
"""
Not yet implemented for more than 1 thread - if ever. Only to be called by
ONE thread!
@ -25,12 +27,12 @@ class Threaded_Process_Metadata(Thread):
Input:
queue: Queue.Queue() object that you'll need to fill up with
the downloaded XML eTree objects
item_type: as used to call functions in itemtypes.py e.g. 'Movies' =>
item_class: as used to call functions in itemtypes.py e.g. 'Movies' =>
itemtypes.Movies()
"""
def __init__(self, queue, item_type):
def __init__(self, queue, item_class):
self.queue = queue
self.item_type = item_type
self.item_class = item_class
Thread.__init__(self)
def terminate_now(self):
@ -49,23 +51,12 @@ class Threaded_Process_Metadata(Thread):
self.queue.task_done()
def run(self):
"""
Catch all exceptions and log them
"""
try:
self.__run()
except Exception as e:
log.error('Exception %s' % e)
import traceback
log.error("Traceback:\n%s" % traceback.format_exc())
def __run(self):
"""
Do the work
"""
log.debug('Processing thread started')
LOG.debug('Processing thread started')
# Constructs the method name, e.g. itemtypes.Movies
item_fct = getattr(itemtypes, self.item_type)
item_fct = getattr(itemtypes, self.item_class)
# cache local variables because it's faster
queue = self.queue
stopped = self.stopped
@ -79,24 +70,19 @@ class Threaded_Process_Metadata(Thread):
continue
# Do the work
item_method = getattr(item_class, item['method'])
if item.get('children') is not None:
item_method(item['XML'][0],
viewtag=item['viewName'],
viewid=item['viewId'],
if item.get('children'):
item_method(item['xml'][0],
viewtag=item['view_name'],
viewid=item['view_id'],
children=item['children'])
else:
item_method(item['XML'][0],
viewtag=item['viewName'],
viewid=item['viewId'])
item_method(item['xml'][0],
viewtag=item['view_name'],
viewid=item['view_id'])
# Keep track of where we are at
try:
log.debug('found child: %s'
% item['children'].attrib)
except:
pass
with sync_info.LOCK:
sync_info.PROCESS_METADATA_COUNT += 1
sync_info.PROCESSING_VIEW_NAME = item['title']
queue.task_done()
self.terminate_now()
log.debug('Processing thread terminated')
LOG.debug('Processing thread terminated')

View file

@ -2,14 +2,14 @@
from logging import getLogger
from threading import Thread, Lock
from xbmc import sleep, Player
from xbmc import sleep
from xbmcgui import DialogProgressBG
from utils import thread_methods, language as lang
###############################################################################
log = getLogger("PLEX."+__name__)
LOG = getLogger("PLEX." + __name__)
GET_METADATA_COUNT = 0
PROCESS_METADATA_COUNT = 0
@ -19,8 +19,10 @@ LOCK = Lock()
###############################################################################
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD', 'STOP_SYNC'])
class Threaded_Show_Sync_Info(Thread):
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD',
'STOP_SYNC',
'SUSPEND_SYNC'])
class ThreadedShowSyncInfo(Thread):
"""
Threaded class to show the Kodi statusbar of the metadata download.
@ -34,38 +36,26 @@ class Threaded_Show_Sync_Info(Thread):
Thread.__init__(self)
def run(self):
"""
Catch all exceptions and log them
"""
try:
self.__run()
except Exception as e:
log.error('Exception %s' % e)
import traceback
log.error("Traceback:\n%s" % traceback.format_exc())
def __run(self):
"""
Do the work
"""
log.debug('Show sync info thread started')
LOG.debug('Show sync info thread started')
# cache local variables because it's faster
total = self.total
dialog = DialogProgressBG('dialoglogProgressBG')
dialog.create("%s %s: %s %s"
% (lang(39714), self.item_type, str(total), lang(39715)))
player = Player()
total = 2 * total
totalProgress = 0
while self.stopped() is False and not player.isPlaying():
total_progress = 0
while not self.stopped():
with LOCK:
get_progress = GET_METADATA_COUNT
process_progress = PROCESS_METADATA_COUNT
viewName = PROCESSING_VIEW_NAME
totalProgress = get_progress + process_progress
view_name = PROCESSING_VIEW_NAME
total_progress = get_progress + process_progress
try:
percentage = int(float(totalProgress) / float(total)*100.0)
percentage = int(float(total_progress) / float(total)*100.0)
except ZeroDivisionError:
percentage = 0
dialog.update(percentage,
@ -74,8 +64,8 @@ class Threaded_Show_Sync_Info(Thread):
lang(39712),
process_progress,
lang(39713),
viewName))
view_name))
# Sleep for x milliseconds
sleep(200)
dialog.close()
log.debug('Show sync info thread terminated')
LOG.debug('Show sync info thread terminated')

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,9 @@ STOP_PKC = False
SUSPEND_LIBRARY_THREAD = False
# Set if user decided to cancel sync
STOP_SYNC = False
# Set e.g. during media playback if PKC should not do any syncs. Will NOT
# suspend synching of playstate progress
SUSPEND_SYNC = False
# Could we access the paths?
PATH_VERIFIED = False
# Set if a Plex-Kodi DB sync is being done - along with
@ -36,8 +39,6 @@ FORCE_RELOAD_SKIN = True
# Stemming from the PKC settings.xml
# Shall we show Kodi dialogs when synching?
SYNC_DIALOG = True
# Have we already checked the Kodi DB on consistency?
KODI_DB_CHECKED = False
# Is synching of Plex music enabled?
ENABLE_MUSIC = True
# How often shall we sync?