mirror of
https://github.com/pkkid/python-plexapi
synced 2024-11-24 20:53:09 +00:00
Add Library timeline support (#573)
* Add Library timeline support * Retry intentional failure with different canary test * Temporarily disable activities tests * Set tests for normal runs * Add tests to validate library timeline attributes
This commit is contained in:
parent
8410d81520
commit
860ad7bc3e
3 changed files with 95 additions and 2 deletions
|
@ -466,6 +466,12 @@ class LibrarySection(PlexObject):
|
|||
data = self._server.query(key)
|
||||
return self.findItems(data, cls=Setting)
|
||||
|
||||
def timeline(self):
|
||||
""" Returns a timeline query for this library section. """
|
||||
key = '/library/sections/%s/timeline' % self.key
|
||||
data = self._server.query(key)
|
||||
return LibraryTimeline(self, data)
|
||||
|
||||
def onDeck(self):
|
||||
""" Returns a list of media items on deck from this library section. """
|
||||
key = '/library/sections/%s/onDeck' % self.key
|
||||
|
@ -1060,6 +1066,46 @@ class FilterChoice(PlexObject):
|
|||
self.type = data.attrib.get('type')
|
||||
|
||||
|
||||
@utils.registerPlexObject
|
||||
class LibraryTimeline(PlexObject):
|
||||
"""Represents a LibrarySection timeline.
|
||||
|
||||
Attributes:
|
||||
TAG (str): 'LibraryTimeline'
|
||||
size (int): Unknown
|
||||
allowSync (bool): Unknown
|
||||
art (str): Relative path to art image.
|
||||
content (str): "secondary"
|
||||
identifier (str): "com.plexapp.plugins.library"
|
||||
latestEntryTime (int): Epoch timestamp
|
||||
mediaTagPrefix (str): "/system/bundle/media/flags/"
|
||||
mediaTagVersion (int): Unknown
|
||||
thumb (str): Relative path to library thumb image.
|
||||
title1 (str): Name of library section.
|
||||
updateQueueSize (int): Number of items queued to update.
|
||||
viewGroup (str): "secondary"
|
||||
viewMode (int): Unknown
|
||||
"""
|
||||
TAG = 'LibraryTimeline'
|
||||
|
||||
def _loadData(self, data):
|
||||
""" Load attribute values from Plex XML response. """
|
||||
self._data = data
|
||||
self.size = utils.cast(int, data.attrib.get('size'))
|
||||
self.allowSync = utils.cast(bool, data.attrib.get('allowSync'))
|
||||
self.art = data.attrib.get('art')
|
||||
self.content = data.attrib.get('content')
|
||||
self.identifier = data.attrib.get('identifier')
|
||||
self.latestEntryTime = utils.cast(int, data.attrib.get('latestEntryTime'))
|
||||
self.mediaTagPrefix = data.attrib.get('mediaTagPrefix')
|
||||
self.mediaTagVersion = utils.cast(int, data.attrib.get('mediaTagVersion'))
|
||||
self.thumb = data.attrib.get('thumb')
|
||||
self.title1 = data.attrib.get('title1')
|
||||
self.updateQueueSize = utils.cast(int, data.attrib.get('updateQueueSize'))
|
||||
self.viewGroup = data.attrib.get('viewGroup')
|
||||
self.viewMode = utils.cast(int, data.attrib.get('viewMode'))
|
||||
|
||||
|
||||
@utils.registerPlexObject
|
||||
class Location(PlexObject):
|
||||
""" Represents a single library Location.
|
||||
|
|
|
@ -16,10 +16,37 @@ def wait_for_idle_server(server):
|
|||
assert attempts < MAX_ATTEMPTS, f"Server still busy after {MAX_ATTEMPTS}s"
|
||||
|
||||
|
||||
def test_ensure_metadata_scans_completed(plex):
|
||||
def wait_for_metadata_processing(server):
|
||||
"""Wait for async metadata processing to complete."""
|
||||
attempts = 0
|
||||
|
||||
while True:
|
||||
busy = False
|
||||
for section in server.library.sections():
|
||||
tl = section.timeline()
|
||||
if tl.updateQueueSize > 0:
|
||||
busy = True
|
||||
print(f"{section.title}: {tl.updateQueueSize} items left")
|
||||
if not busy or attempts > MAX_ATTEMPTS:
|
||||
break
|
||||
time.sleep(1)
|
||||
attempts += 1
|
||||
assert attempts < MAX_ATTEMPTS, f"Metadata still processing after {MAX_ATTEMPTS}s"
|
||||
|
||||
|
||||
def test_ensure_activities_completed(plex):
|
||||
wait_for_idle_server(plex)
|
||||
|
||||
|
||||
@pytest.mark.authenticated
|
||||
def test_ensure_metadata_scans_completed_authenticated(plex):
|
||||
def test_ensure_activities_completed_authenticated(plex):
|
||||
wait_for_idle_server(plex)
|
||||
|
||||
|
||||
def test_ensure_metadata_scans_completed(plex):
|
||||
wait_for_metadata_processing(plex)
|
||||
|
||||
|
||||
@pytest.mark.authenticated
|
||||
def test_ensure_metadata_scans_completed_authenticated(plex):
|
||||
wait_for_metadata_processing(plex)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from datetime import datetime
|
||||
import pytest
|
||||
from plexapi.exceptions import NotFound
|
||||
|
||||
|
@ -277,3 +278,22 @@ def test_crazy_search(plex, movie):
|
|||
assert len(movies.search(container_size=1)) == 4
|
||||
assert len(movies.search(container_start=9999, container_size=1)) == 0
|
||||
assert len(movies.search(container_start=2, container_size=1)) == 2
|
||||
|
||||
|
||||
def test_library_section_timeline(plex):
|
||||
movies = plex.library.section("Movies")
|
||||
tl = movies.timeline()
|
||||
assert tl.TAG == "LibraryTimeline"
|
||||
assert tl.size > 0
|
||||
assert tl.allowSync is False
|
||||
assert tl.art == "/:/resources/movie-fanart.jpg"
|
||||
assert tl.content == "secondary"
|
||||
assert tl.identifier == "com.plexapp.plugins.library"
|
||||
assert datetime.fromtimestamp(tl.latestEntryTime).date() == datetime.today().date()
|
||||
assert tl.mediaTagPrefix == "/system/bundle/media/flags/"
|
||||
assert tl.mediaTagVersion > 1
|
||||
assert tl.thumb == "/:/resources/movie.png"
|
||||
assert tl.title1 == "Movies"
|
||||
assert tl.updateQueueSize == 0
|
||||
assert tl.viewGroup == "secondary"
|
||||
assert tl.viewMode == 65592
|
||||
|
|
Loading…
Reference in a new issue