2017-04-03 01:02:41 +10:00
|
|
|
# -*- coding: utf-8 -*-
|
2018-07-13 02:46:02 +10:00
|
|
|
from __future__ import absolute_import, division, unicode_literals
|
2017-04-03 01:02:41 +10:00
|
|
|
from logging import getLogger
|
2018-10-20 23:49:04 +11:00
|
|
|
import xbmcgui
|
2017-04-03 01:02:41 +10:00
|
|
|
|
2018-11-09 19:08:04 +11:00
|
|
|
from cProfile import Profile
|
|
|
|
from pstats import Stats
|
|
|
|
from StringIO import StringIO
|
|
|
|
|
2018-10-20 23:49:04 +11:00
|
|
|
from . import common
|
2018-11-10 01:05:17 +11:00
|
|
|
from .. import backgroundthread, utils, variables as v
|
2017-04-03 01:02:41 +10:00
|
|
|
|
2018-11-02 01:43:43 +11:00
|
|
|
LOG = getLogger('PLEX.sync.process_metadata')
|
2017-04-03 01:02:41 +10:00
|
|
|
|
|
|
|
|
2018-10-21 21:03:21 +11:00
|
|
|
class InitNewSection(object):
|
|
|
|
"""
|
|
|
|
Throw this into the queue used for ProcessMetadata to tell it which
|
|
|
|
Plex library section we're looking at
|
|
|
|
|
|
|
|
context: itemtypes.Movie, itemtypes.Episode, etc.
|
|
|
|
"""
|
|
|
|
def __init__(self, context, total_number_of_items, section_name,
|
2018-11-09 19:10:22 +11:00
|
|
|
section_id, plex_type):
|
2018-10-21 21:03:21 +11:00
|
|
|
self.context = context
|
|
|
|
self.total = total_number_of_items
|
|
|
|
self.name = section_name
|
|
|
|
self.id = section_id
|
2018-11-09 19:10:22 +11:00
|
|
|
self.plex_type = plex_type
|
2018-10-21 21:03:21 +11:00
|
|
|
|
|
|
|
|
2018-11-09 21:19:32 +11:00
|
|
|
class UpdateLastSync(object):
|
|
|
|
def __init__(self, plex_id):
|
|
|
|
self.plex_id = plex_id
|
|
|
|
|
|
|
|
|
2018-10-20 23:49:04 +11:00
|
|
|
class ProcessMetadata(backgroundthread.KillableThread, common.libsync_mixin):
|
2017-04-03 01:02:41 +10:00
|
|
|
"""
|
|
|
|
Not yet implemented for more than 1 thread - if ever. Only to be called by
|
|
|
|
ONE thread!
|
|
|
|
Processes the XML metadata in the queue
|
|
|
|
|
|
|
|
Input:
|
|
|
|
queue: Queue.Queue() object that you'll need to fill up with
|
|
|
|
the downloaded XML eTree objects
|
2018-04-18 04:18:25 +10:00
|
|
|
item_class: as used to call functions in itemtypes.py e.g. 'Movies' =>
|
2017-04-03 01:02:41 +10:00
|
|
|
itemtypes.Movies()
|
|
|
|
"""
|
2018-10-24 16:08:32 +11:00
|
|
|
def __init__(self, queue, last_sync, show_dialog):
|
2018-10-25 03:08:00 +11:00
|
|
|
self._canceled = False
|
2017-04-03 01:02:41 +10:00
|
|
|
self.queue = queue
|
2018-10-21 21:03:21 +11:00
|
|
|
self.last_sync = last_sync
|
2018-10-24 16:08:32 +11:00
|
|
|
self.show_dialog = show_dialog
|
2018-10-21 21:03:21 +11:00
|
|
|
self.total = 0
|
2018-11-09 19:05:14 +11:00
|
|
|
self.current = 1
|
2018-11-09 21:19:32 +11:00
|
|
|
self.processed = 0
|
|
|
|
self.title = ''
|
2018-10-21 21:03:21 +11:00
|
|
|
self.section_name = None
|
2018-10-24 16:08:32 +11:00
|
|
|
self.dialog = None
|
2018-10-20 23:49:04 +11:00
|
|
|
super(ProcessMetadata, self).__init__()
|
2017-04-03 01:02:41 +10:00
|
|
|
|
2018-11-04 03:18:25 +11:00
|
|
|
def update_progressbar(self):
|
2018-10-24 16:08:32 +11:00
|
|
|
if self.show_dialog:
|
|
|
|
try:
|
|
|
|
progress = int(float(self.current) / float(self.total) * 100.0)
|
|
|
|
except ZeroDivisionError:
|
|
|
|
progress = 0
|
|
|
|
self.dialog.update(progress,
|
2018-11-12 03:48:11 +11:00
|
|
|
'%s (%s)' % (self.section_name, self.section_type_text),
|
2018-11-13 02:37:56 +11:00
|
|
|
'%s/%s %s'
|
2018-11-09 19:05:14 +11:00
|
|
|
% (self.current, self.total, self.title))
|
2017-04-03 01:02:41 +10:00
|
|
|
|
|
|
|
def run(self):
|
2018-11-21 04:08:51 +11:00
|
|
|
"""
|
|
|
|
Do the work
|
|
|
|
"""
|
2018-04-18 04:18:25 +10:00
|
|
|
LOG.debug('Processing thread started')
|
2018-10-21 21:03:21 +11:00
|
|
|
try:
|
2018-11-21 04:08:51 +11:00
|
|
|
if self.show_dialog:
|
|
|
|
self.dialog = xbmcgui.DialogProgressBG()
|
|
|
|
self.dialog.create(utils.lang(39714))
|
|
|
|
# Init with the very first library section. This will block!
|
|
|
|
section = self.queue.get()
|
|
|
|
self.queue.task_done()
|
|
|
|
if section is None:
|
|
|
|
return
|
|
|
|
while not self.isCanceled():
|
|
|
|
if section is None:
|
|
|
|
break
|
|
|
|
LOG.debug('Start processing section %s (%ss)',
|
|
|
|
section.name, section.plex_type)
|
|
|
|
self.current = 1
|
|
|
|
self.processed = 0
|
|
|
|
self.total = section.total
|
|
|
|
self.section_name = section.name
|
|
|
|
self.section_type_text = utils.lang(
|
|
|
|
v.TRANSLATION_FROM_PLEXTYPE[section.plex_type])
|
|
|
|
profile = Profile()
|
|
|
|
profile.enable()
|
|
|
|
with section.context(self.last_sync) as context:
|
|
|
|
while not self.isCanceled():
|
|
|
|
# grabs item from queue. This will block!
|
|
|
|
item = self.queue.get()
|
|
|
|
if isinstance(item, InitNewSection) or item is None:
|
|
|
|
section = item
|
|
|
|
self.queue.task_done()
|
|
|
|
break
|
|
|
|
elif isinstance(item, UpdateLastSync):
|
|
|
|
context.plexdb.update_last_sync(item.plex_id,
|
|
|
|
section.plex_type,
|
|
|
|
self.last_sync)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
context.add_update(item['xml'][0],
|
|
|
|
section_name=section.name,
|
|
|
|
section_id=section.id,
|
|
|
|
children=item['children'])
|
|
|
|
except:
|
2018-11-21 04:28:34 +11:00
|
|
|
utils.ERROR(notify=True, cancel_sync=True)
|
2018-11-21 04:08:51 +11:00
|
|
|
self.title = item['xml'][0].get('title')
|
|
|
|
self.processed += 1
|
|
|
|
self.update_progressbar()
|
|
|
|
self.current += 1
|
|
|
|
if self.processed == 500:
|
|
|
|
self.processed = 0
|
|
|
|
context.commit()
|
|
|
|
self.queue.task_done()
|
|
|
|
profile.disable()
|
|
|
|
string_io = StringIO()
|
|
|
|
stats = Stats(profile, stream=string_io).sort_stats('cumulative')
|
|
|
|
stats.print_stats()
|
|
|
|
LOG.info('cProfile result: ')
|
|
|
|
LOG.info(string_io.getvalue())
|
2018-10-21 21:03:21 +11:00
|
|
|
finally:
|
2018-10-24 16:08:32 +11:00
|
|
|
if self.dialog:
|
|
|
|
self.dialog.close()
|
2018-11-09 18:56:57 +11:00
|
|
|
while not self.queue.empty():
|
|
|
|
# We need to empty the queue to let full_sync finish join()
|
|
|
|
self.queue.get()
|
|
|
|
self.queue.task_done()
|
2018-10-21 21:03:21 +11:00
|
|
|
LOG.debug('Processing thread terminated')
|