Merge pull request #1054 from croneter/fix-album

Fix Recently Added Albums sort order (you will have to reset the Kodi database manually)
This commit is contained in:
croneter 2019-11-14 17:19:37 +01:00 committed by GitHub
commit ffeb79e4b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 89 additions and 15 deletions

View file

@ -140,6 +140,67 @@ class KillableThread(threading.Thread):
return self._suspended return self._suspended
class OrderedQueue(Queue.PriorityQueue, object):
"""
Queue that enforces an order on the items it returns. An item you push
onto the queue must be a tuple
(index, item)
where index=-1 is the item that will be returned first. The Queue will block
until index=-1, 0, 1, 2, 3, ... is then made available
"""
def __init__(self, maxsize=0):
super(OrderedQueue, self).__init__(maxsize)
self.smallest = -1
self.not_next_item = threading.Condition(self.mutex)
def _put(self, item, heappush=heapq.heappush):
heappush(self.queue, item)
if item[0] == self.smallest:
self.not_next_item.notify()
def get(self, block=True, timeout=None):
"""Remove and return an item from the queue.
If optional args 'block' is true and 'timeout' is None (the default),
block if necessary until an item is available. If 'timeout' is
a non-negative number, it blocks at most 'timeout' seconds and raises
the Empty exception if no item was available within that time.
Otherwise ('block' is false), return an item if one is immediately
available, else raise the Empty exception ('timeout' is ignored
in that case).
"""
self.not_empty.acquire()
try:
if not block:
if not self._qsize() or self.queue[0][0] != self.smallest:
raise Queue.Empty
elif timeout is None:
while not self._qsize():
self.not_empty.wait()
while self.queue[0][0] != self.smallest:
self.not_next_item.wait()
elif timeout < 0:
raise ValueError("'timeout' must be a non-negative number")
else:
endtime = Queue._time() + timeout
while not self._qsize():
remaining = endtime - Queue._time()
if remaining <= 0.0:
raise Queue.Empty
self.not_empty.wait(remaining)
while self.queue[0][0] != self.smallest:
remaining = endtime - Queue._time()
if remaining <= 0.0:
raise Queue.Empty
self.not_next_item.wait(remaining)
item = self._get()
self.smallest += 1
self.not_full.notify()
return item
finally:
self.not_empty.release()
class Tasks(list): class Tasks(list):
def add(self, task): def add(self, task):
for t in self: for t in self:

View file

@ -102,14 +102,15 @@ class FullSync(common.fullsync_mixin):
self.threader.addTask(GetMetadataTask(self.queue, self.threader.addTask(GetMetadataTask(self.queue,
plex_id, plex_id,
self.plex_type, self.plex_type,
self.get_children)) self.get_children,
self.item_count))
self.item_count += 1 self.item_count += 1
def update_library(self): def update_library(self):
LOG.debug('Writing changes to Kodi library now') LOG.debug('Writing changes to Kodi library now')
i = 0 i = 0
if not self.section: if not self.section:
self.section = self.queue.get() _, self.section = self.queue.get()
self.queue.task_done() self.queue.task_done()
while not self.isCanceled() and self.item_count > 0: while not self.isCanceled() and self.item_count > 0:
section = self.section section = self.section
@ -125,7 +126,7 @@ class FullSync(common.fullsync_mixin):
with section.context(self.current_sync) as context: with section.context(self.current_sync) as context:
while not self.isCanceled() and self.item_count > 0: while not self.isCanceled() and self.item_count > 0:
try: try:
item = self.queue.get(block=False) _, item = self.queue.get(block=False)
except backgroundthread.Queue.Empty: except backgroundthread.Queue.Empty:
if self.threader.threader.working(): if self.threader.threader.working():
app.APP.monitor.waitForAbort(0.02) app.APP.monitor.waitForAbort(0.02)
@ -174,7 +175,7 @@ class FullSync(common.fullsync_mixin):
iterator.get('title1')), iterator.get('title1')),
section.section_id, section.section_id,
section.plex_type) section.plex_type)
self.queue.put(queue_info) self.queue.put((-1, queue_info))
last = True last = True
# To keep track of the item-number in order to kill while loops # To keep track of the item-number in order to kill while loops
self.item_count = 0 self.item_count = 0
@ -216,7 +217,7 @@ class FullSync(common.fullsync_mixin):
section.name, section.name,
section.section_id, section.section_id,
section.plex_type) section.plex_type)
self.queue.put(queue_info) self.queue.put((-1, queue_info))
self.total = iterator.total self.total = iterator.total
self.section_name = section.name self.section_name = section.name
self.section_type_text = utils.lang( self.section_type_text = utils.lang(
@ -268,6 +269,7 @@ class FullSync(common.fullsync_mixin):
element.section_type = element.plex_type element.section_type = element.plex_type
element.context = kind[2] element.context = kind[2]
element.get_children = kind[3] element.get_children = kind[3]
element.Queue = kind[4]
if self.repair or all_items: if self.repair or all_items:
updated_at = None updated_at = None
else: else:
@ -292,16 +294,22 @@ class FullSync(common.fullsync_mixin):
def full_library_sync(self): def full_library_sync(self):
""" """
""" """
# structure:
# (plex_type,
# section_type,
# context for itemtype,
# download children items, e.g. songs for a specific album?,
# Queue)
kinds = [ kinds = [
(v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_MOVIE, itemtypes.Movie, False), (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_MOVIE, itemtypes.Movie, False, Queue.Queue),
(v.PLEX_TYPE_SHOW, v.PLEX_TYPE_SHOW, itemtypes.Show, False), (v.PLEX_TYPE_SHOW, v.PLEX_TYPE_SHOW, itemtypes.Show, False, Queue.Queue),
(v.PLEX_TYPE_SEASON, v.PLEX_TYPE_SHOW, itemtypes.Season, False), (v.PLEX_TYPE_SEASON, v.PLEX_TYPE_SHOW, itemtypes.Season, False, Queue.Queue),
(v.PLEX_TYPE_EPISODE, v.PLEX_TYPE_SHOW, itemtypes.Episode, False) (v.PLEX_TYPE_EPISODE, v.PLEX_TYPE_SHOW, itemtypes.Episode, False, Queue.Queue)
] ]
if app.SYNC.enable_music: if app.SYNC.enable_music:
kinds.extend([ kinds.extend([
(v.PLEX_TYPE_ARTIST, v.PLEX_TYPE_ARTIST, itemtypes.Artist, False), (v.PLEX_TYPE_ARTIST, v.PLEX_TYPE_ARTIST, itemtypes.Artist, False, Queue.Queue),
(v.PLEX_TYPE_ALBUM, v.PLEX_TYPE_ARTIST, itemtypes.Album, True), (v.PLEX_TYPE_ALBUM, v.PLEX_TYPE_ARTIST, itemtypes.Album, True, backgroundthread.OrderedQueue),
]) ])
# ADD NEW ITEMS # ADD NEW ITEMS
# Already start setting up the iterators. We need to enforce # Already start setting up the iterators. We need to enforce
@ -323,6 +331,7 @@ class FullSync(common.fullsync_mixin):
self.section_type = section.section_type self.section_type = section.section_type
self.context = section.context self.context = section.context
self.get_children = section.get_children self.get_children = section.get_children
self.queue = section.Queue()
# Now do the heavy lifting # Now do the heavy lifting
if self.isCanceled() or not self.addupdate_section(section): if self.isCanceled() or not self.addupdate_section(section):
return False return False
@ -352,8 +361,11 @@ class FullSync(common.fullsync_mixin):
LOG.info('Start synching playstate and userdata for every item') LOG.info('Start synching playstate and userdata for every item')
# In order to not delete all your songs again # In order to not delete all your songs again
if app.SYNC.enable_music: if app.SYNC.enable_music:
# We don't need to enforce the album order now
kinds.pop(5)
kinds.extend([ kinds.extend([
(v.PLEX_TYPE_SONG, v.PLEX_TYPE_ARTIST, itemtypes.Song, True), (v.PLEX_TYPE_ALBUM, v.PLEX_TYPE_ARTIST, itemtypes.Album, True, Queue.Queue),
(v.PLEX_TYPE_SONG, v.PLEX_TYPE_ARTIST, itemtypes.Song, True, Queue.Queue),
]) ])
# Make sure we're not showing an item's title in the sync dialog # Make sure we're not showing an item's title in the sync dialog
self.title = '' self.title = ''
@ -429,7 +441,6 @@ class FullSync(common.fullsync_mixin):
return return
self.successful = True self.successful = True
try: try:
self.queue = backgroundthread.Queue.Queue()
if self.show_dialog: if self.show_dialog:
self.dialog = xbmcgui.DialogProgressBG() self.dialog = xbmcgui.DialogProgressBG()
self.dialog.create(utils.lang(39714)) self.dialog.create(utils.lang(39714))

View file

@ -36,11 +36,13 @@ class GetMetadataTask(common.fullsync_mixin, backgroundthread.Task):
queue Queue.Queue() object where this thread will store queue Queue.Queue() object where this thread will store
the downloaded metadata XMLs as etree objects the downloaded metadata XMLs as etree objects
""" """
def __init__(self, queue, plex_id, plex_type, get_children=False): def __init__(self, queue, plex_id, plex_type, get_children=False,
count=None):
self.queue = queue self.queue = queue
self.plex_id = plex_id self.plex_id = plex_id
self.plex_type = plex_type self.plex_type = plex_type
self.get_children = get_children self.get_children = get_children
self.count = count
super(GetMetadataTask, self).__init__() super(GetMetadataTask, self).__init__()
def _collections(self, item): def _collections(self, item):
@ -120,4 +122,4 @@ class GetMetadataTask(common.fullsync_mixin, backgroundthread.Task):
else: else:
item['children'] = children_xml item['children'] = children_xml
if not self.isCanceled(): if not self.isCanceled():
self.queue.put(item) self.queue.put((self.count, item))