Skip to content

Commit f3ef67b

Browse files
committed
MediaContainer class is now a list
- can now support totalSize as returned from server
1 parent abcab4f commit f3ef67b

File tree

1 file changed

+61
-4
lines changed

1 file changed

+61
-4
lines changed

Diff for: plexapi/base.py

+61-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
# -*- coding: utf-8 -*-
22
import re
3+
from typing import TYPE_CHECKING, Generic, Iterable, List, Optional, Type, TypeVar, Union
34
import weakref
45
from functools import cached_property
56
from urllib.parse import urlencode
67
from xml.etree import ElementTree
8+
from xml.etree.ElementTree import Element
79

810
from plexapi import CONFIG, X_PLEX_CONTAINER_SIZE, log, utils
911
from plexapi.exceptions import BadRequest, NotFound, UnknownType, Unsupported
1012

13+
if TYPE_CHECKING:
14+
from plexapi.server import PlexServer
15+
16+
PlexObjectT = TypeVar("PlexObjectT", bound='PlexObject')
17+
MediaContainerT = TypeVar("MediaContainerT", bound="MediaContainer")
18+
1119
USER_DONT_RELOAD_FOR_KEYS = set()
1220
_DONT_RELOAD_FOR_KEYS = {'key'}
1321
OPERATORS = {
@@ -245,8 +253,7 @@ def fetchItems(self, ekey, cls=None, container_start=None, container_size=None,
245253
if maxresults is not None:
246254
container_size = min(container_size, maxresults)
247255

248-
results = []
249-
subresults = []
256+
results = MediaContainer[cls](self._server, Element('MediaContainer'), initpath=ekey)
250257
headers = {}
251258

252259
while True:
@@ -324,7 +331,7 @@ def findItems(self, data, cls=None, initpath=None, rtag=None, **kwargs):
324331
if rtag:
325332
data = next(utils.iterXMLBFS(data, rtag), [])
326333
# loop through all data elements to find matches
327-
items = []
334+
items = MediaContainer[cls](self._server, data, initpath=initpath) if data.tag == 'MediaContainer' else []
328335
for elem in data:
329336
if self._checkAttrs(elem, **kwargs):
330337
item = self._buildItemOrNone(elem, cls, initpath)
@@ -996,7 +1003,11 @@ def delete(self):
9961003
return self._server.query(self.historyKey, method=self._server._session.delete)
9971004

9981005

999-
class MediaContainer(PlexObject):
1006+
class MediaContainer(
1007+
Generic[PlexObjectT],
1008+
List[PlexObjectT],
1009+
PlexObject,
1010+
):
10001011
""" Represents a single MediaContainer.
10011012
10021013
Attributes:
@@ -1009,11 +1020,55 @@ class MediaContainer(PlexObject):
10091020
librarySectionUUID (str): :class:`~plexapi.library.LibrarySection` UUID.
10101021
mediaTagPrefix (str): "/system/bundle/media/flags/"
10111022
mediaTagVersion (int): Unknown
1023+
offset (int): The offset of current results.
10121024
size (int): The number of items in the hub.
1025+
totalSize (int): The total number of items for the query.
10131026
10141027
"""
10151028
TAG = 'MediaContainer'
10161029

1030+
def __init__(
1031+
self,
1032+
server: "PlexServer",
1033+
data: Element,
1034+
*args: PlexObjectT,
1035+
initpath: Optional[str] = None,
1036+
parent: Optional[PlexObject] = None,
1037+
) -> None:
1038+
# super calls Generic.__init__ which calls list.__init__ eventually
1039+
super().__init__(*args)
1040+
PlexObject.__init__(self, server, data, initpath, parent)
1041+
1042+
def extend(
1043+
self: MediaContainerT,
1044+
__iterable: Union[Iterable[PlexObjectT], MediaContainerT],
1045+
) -> None:
1046+
curr_size = self.size if self.size is not None else len(self)
1047+
super().extend(__iterable)
1048+
# update size, totalSize, and offset
1049+
if not isinstance(__iterable, MediaContainer):
1050+
return
1051+
1052+
# prefer the totalSize of the new iterable even if it is smaller
1053+
self.totalSize = (
1054+
__iterable.totalSize
1055+
if __iterable.totalSize is not None
1056+
else self.totalSize
1057+
) # ideally both should be equal
1058+
1059+
# the size of the new iterable is added to the current size
1060+
self.size = curr_size + (
1061+
__iterable.size if __iterable.size is not None else len(__iterable)
1062+
)
1063+
1064+
# the offset is the minimum of the two, prefering older values
1065+
if self.offset is not None and __iterable.offset is not None:
1066+
self.offset = min(self.offset, __iterable.offset)
1067+
else:
1068+
self.offset = (
1069+
self.offset if self.offset is not None else __iterable.offset
1070+
)
1071+
10171072
def _loadData(self, data):
10181073
self._data = data
10191074
self.allowSync = utils.cast(int, data.attrib.get('allowSync'))
@@ -1024,4 +1079,6 @@ def _loadData(self, data):
10241079
self.librarySectionUUID = data.attrib.get('librarySectionUUID')
10251080
self.mediaTagPrefix = data.attrib.get('mediaTagPrefix')
10261081
self.mediaTagVersion = data.attrib.get('mediaTagVersion')
1082+
self.offset = utils.cast(int, data.attrib.get("offset"))
10271083
self.size = utils.cast(int, data.attrib.get('size'))
1084+
self.totalSize = utils.cast(int, data.attrib.get("totalSize"))

0 commit comments

Comments
 (0)