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:
commit
ffeb79e4b5
3 changed files with 89 additions and 15 deletions
|
@ -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:
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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))
|
||||||
|
|
Loading…
Reference in a new issue