mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-06 05:01:14 -07:00
Update plexapi==4.15.11
This commit is contained in:
parent
653a6d5c12
commit
85519b1b45
8 changed files with 173 additions and 16 deletions
|
@ -1,13 +1,21 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
from typing import TYPE_CHECKING, Generic, Iterable, List, Optional, TypeVar, Union
|
||||
import weakref
|
||||
from functools import cached_property
|
||||
from urllib.parse import urlencode
|
||||
from xml.etree import ElementTree
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
from plexapi import CONFIG, X_PLEX_CONTAINER_SIZE, log, utils
|
||||
from plexapi.exceptions import BadRequest, NotFound, UnknownType, Unsupported
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from plexapi.server import PlexServer
|
||||
|
||||
PlexObjectT = TypeVar("PlexObjectT", bound='PlexObject')
|
||||
MediaContainerT = TypeVar("MediaContainerT", bound="MediaContainer")
|
||||
|
||||
USER_DONT_RELOAD_FOR_KEYS = set()
|
||||
_DONT_RELOAD_FOR_KEYS = {'key'}
|
||||
OPERATORS = {
|
||||
|
@ -95,7 +103,7 @@ class PlexObject:
|
|||
ehash = f"{ehash}.session"
|
||||
elif initpath.startswith('/status/sessions/history'):
|
||||
ehash = f"{ehash}.history"
|
||||
ecls = utils.PLEXOBJECTS.get(ehash, utils.PLEXOBJECTS.get(elem.tag))
|
||||
ecls = utils.getPlexObject(ehash, default=elem.tag)
|
||||
# log.debug('Building %s as %s', elem.tag, ecls.__name__)
|
||||
if ecls is not None:
|
||||
return ecls(self._server, elem, initpath, parent=self)
|
||||
|
@ -116,14 +124,22 @@ class PlexObject:
|
|||
or disable each parameter individually by setting it to False or 0.
|
||||
"""
|
||||
details_key = self.key
|
||||
params = {}
|
||||
|
||||
if details_key and hasattr(self, '_INCLUDES'):
|
||||
includes = {}
|
||||
for k, v in self._INCLUDES.items():
|
||||
value = kwargs.get(k, v)
|
||||
value = kwargs.pop(k, v)
|
||||
if value not in [False, 0, '0']:
|
||||
includes[k] = 1 if value is True else value
|
||||
if includes:
|
||||
details_key += '?' + urlencode(sorted(includes.items()))
|
||||
params[k] = 1 if value is True else value
|
||||
|
||||
if details_key and hasattr(self, '_EXCLUDES'):
|
||||
for k, v in self._EXCLUDES.items():
|
||||
value = kwargs.pop(k, None)
|
||||
if value is not None:
|
||||
params[k] = 1 if value is True else value
|
||||
|
||||
if params:
|
||||
details_key += '?' + urlencode(sorted(params.items()))
|
||||
return details_key
|
||||
|
||||
def _isChildOf(self, **kwargs):
|
||||
|
@ -227,7 +243,7 @@ class PlexObject:
|
|||
|
||||
fetchItem(ekey, viewCount__gte=0)
|
||||
fetchItem(ekey, Media__container__in=["mp4", "mkv"])
|
||||
fetchItem(ekey, guid__regex=r"com\.plexapp\.agents\.(imdb|themoviedb)://|tt\d+")
|
||||
fetchItem(ekey, guid__regex=r"com\\.plexapp\\.agents\\.(imdb|themoviedb)://|tt\d+")
|
||||
fetchItem(ekey, guid__id__regex=r"(imdb|tmdb|tvdb)://")
|
||||
fetchItem(ekey, Media__Part__file__startswith="D:\\Movies")
|
||||
|
||||
|
@ -245,8 +261,7 @@ class PlexObject:
|
|||
if maxresults is not None:
|
||||
container_size = min(container_size, maxresults)
|
||||
|
||||
results = []
|
||||
subresults = []
|
||||
results = MediaContainer[cls](self._server, Element('MediaContainer'), initpath=ekey)
|
||||
headers = {}
|
||||
|
||||
while True:
|
||||
|
@ -324,7 +339,7 @@ class PlexObject:
|
|||
if rtag:
|
||||
data = next(utils.iterXMLBFS(data, rtag), [])
|
||||
# loop through all data elements to find matches
|
||||
items = []
|
||||
items = MediaContainer[cls](self._server, data, initpath=initpath) if data.tag == 'MediaContainer' else []
|
||||
for elem in data:
|
||||
if self._checkAttrs(elem, **kwargs):
|
||||
item = self._buildItemOrNone(elem, cls, initpath)
|
||||
|
@ -498,7 +513,14 @@ class PlexPartialObject(PlexObject):
|
|||
'includeRelated': 1,
|
||||
'includeRelatedCount': 1,
|
||||
'includeReviews': 1,
|
||||
'includeStations': 1
|
||||
'includeStations': 1,
|
||||
}
|
||||
_EXCLUDES = {
|
||||
'excludeElements': (
|
||||
'Media,Genre,Country,Guid,Rating,Collection,Director,Writer,Role,Producer,Similar,Style,Mood,Format'
|
||||
),
|
||||
'excludeFields': 'summary,tagline',
|
||||
'skipRefresh': 1,
|
||||
}
|
||||
|
||||
def __eq__(self, other):
|
||||
|
@ -996,7 +1018,11 @@ class PlexHistory(object):
|
|||
return self._server.query(self.historyKey, method=self._server._session.delete)
|
||||
|
||||
|
||||
class MediaContainer(PlexObject):
|
||||
class MediaContainer(
|
||||
Generic[PlexObjectT],
|
||||
List[PlexObjectT],
|
||||
PlexObject,
|
||||
):
|
||||
""" Represents a single MediaContainer.
|
||||
|
||||
Attributes:
|
||||
|
@ -1009,11 +1035,71 @@ class MediaContainer(PlexObject):
|
|||
librarySectionUUID (str): :class:`~plexapi.library.LibrarySection` UUID.
|
||||
mediaTagPrefix (str): "/system/bundle/media/flags/"
|
||||
mediaTagVersion (int): Unknown
|
||||
offset (int): The offset of current results.
|
||||
size (int): The number of items in the hub.
|
||||
totalSize (int): The total number of items for the query.
|
||||
|
||||
"""
|
||||
TAG = 'MediaContainer'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
server: "PlexServer",
|
||||
data: Element,
|
||||
*args: PlexObjectT,
|
||||
initpath: Optional[str] = None,
|
||||
parent: Optional[PlexObject] = None,
|
||||
) -> None:
|
||||
# super calls Generic.__init__ which calls list.__init__ eventually
|
||||
super().__init__(*args)
|
||||
PlexObject.__init__(self, server, data, initpath, parent)
|
||||
|
||||
def extend(
|
||||
self: MediaContainerT,
|
||||
__iterable: Union[Iterable[PlexObjectT], MediaContainerT],
|
||||
) -> None:
|
||||
curr_size = self.size if self.size is not None else len(self)
|
||||
super().extend(__iterable)
|
||||
# update size, totalSize, and offset
|
||||
if not isinstance(__iterable, MediaContainer):
|
||||
return
|
||||
|
||||
# prefer the totalSize of the new iterable even if it is smaller
|
||||
self.totalSize = (
|
||||
__iterable.totalSize
|
||||
if __iterable.totalSize is not None
|
||||
else self.totalSize
|
||||
) # ideally both should be equal
|
||||
|
||||
# the size of the new iterable is added to the current size
|
||||
self.size = curr_size + (
|
||||
__iterable.size if __iterable.size is not None else len(__iterable)
|
||||
)
|
||||
|
||||
# the offset is the minimum of the two, prefering older values
|
||||
if self.offset is not None and __iterable.offset is not None:
|
||||
self.offset = min(self.offset, __iterable.offset)
|
||||
else:
|
||||
self.offset = (
|
||||
self.offset if self.offset is not None else __iterable.offset
|
||||
)
|
||||
|
||||
# for all other attributes, overwrite with the new iterable's values if previously None
|
||||
for key in (
|
||||
"allowSync",
|
||||
"augmentationKey",
|
||||
"identifier",
|
||||
"librarySectionID",
|
||||
"librarySectionTitle",
|
||||
"librarySectionUUID",
|
||||
"mediaTagPrefix",
|
||||
"mediaTagVersion",
|
||||
):
|
||||
if (not hasattr(self, key)) or (getattr(self, key) is None):
|
||||
if not hasattr(__iterable, key):
|
||||
continue
|
||||
setattr(self, key, getattr(__iterable, key))
|
||||
|
||||
def _loadData(self, data):
|
||||
self._data = data
|
||||
self.allowSync = utils.cast(int, data.attrib.get('allowSync'))
|
||||
|
@ -1024,4 +1110,6 @@ class MediaContainer(PlexObject):
|
|||
self.librarySectionUUID = data.attrib.get('librarySectionUUID')
|
||||
self.mediaTagPrefix = data.attrib.get('mediaTagPrefix')
|
||||
self.mediaTagVersion = data.attrib.get('mediaTagVersion')
|
||||
self.offset = utils.cast(int, data.attrib.get("offset"))
|
||||
self.size = utils.cast(int, data.attrib.get('size'))
|
||||
self.totalSize = utils.cast(int, data.attrib.get("totalSize"))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue