mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-05 20:51:15 -07:00
Bump plexapi from 4.15.15 to 4.15.16 (#2383)
* Bump plexapi from 4.15.15 to 4.15.16 Bumps [plexapi](https://github.com/pkkid/python-plexapi) from 4.15.15 to 4.15.16. - [Release notes](https://github.com/pkkid/python-plexapi/releases) - [Commits](https://github.com/pkkid/python-plexapi/compare/4.15.15...4.15.16) --- updated-dependencies: - dependency-name: plexapi dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Update plexapi==4.15.16 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci]
This commit is contained in:
parent
de697cb2ca
commit
cc1a325eac
13 changed files with 153 additions and 45 deletions
|
@ -193,6 +193,7 @@ class Artist(
|
|||
similar (List<:class:`~plexapi.media.Similar`>): List of similar objects.
|
||||
styles (List<:class:`~plexapi.media.Style`>): List of style objects.
|
||||
theme (str): URL to theme resource (/library/metadata/<ratingkey>/theme/<themeid>).
|
||||
ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
|
||||
"""
|
||||
TAG = 'Directory'
|
||||
TYPE = 'artist'
|
||||
|
@ -213,6 +214,7 @@ class Artist(
|
|||
self.similar = self.findItems(data, media.Similar)
|
||||
self.styles = self.findItems(data, media.Style)
|
||||
self.theme = data.attrib.get('theme')
|
||||
self.ultraBlurColors = self.findItem(data, media.UltraBlurColors)
|
||||
|
||||
def __iter__(self):
|
||||
for album in self.albums():
|
||||
|
@ -281,6 +283,21 @@ class Artist(
|
|||
filepaths += track.download(_savepath, keep_original_name, **kwargs)
|
||||
return filepaths
|
||||
|
||||
def popularTracks(self):
|
||||
""" Returns a list of :class:`~plexapi.audio.Track` popular tracks by the artist. """
|
||||
filters = {
|
||||
'album.subformat!': 'Compilation,Live',
|
||||
'artist.id': self.ratingKey,
|
||||
'group': 'title',
|
||||
'ratingCount>>': 0,
|
||||
}
|
||||
return self.section().search(
|
||||
libtype='track',
|
||||
filters=filters,
|
||||
sort='ratingCount:desc',
|
||||
limit=100
|
||||
)
|
||||
|
||||
def station(self):
|
||||
""" Returns a :class:`~plexapi.playlist.Playlist` artist radio station or `None`. """
|
||||
key = f'{self.key}?includeStations=1'
|
||||
|
@ -325,6 +342,7 @@ class Album(
|
|||
studio (str): Studio that released the album.
|
||||
styles (List<:class:`~plexapi.media.Style`>): List of style objects.
|
||||
subformats (List<:class:`~plexapi.media.Subformat`>): List of subformat objects.
|
||||
ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
|
||||
viewedLeafCount (int): Number of items marked as played in the album view.
|
||||
year (int): Year the album was released.
|
||||
"""
|
||||
|
@ -354,6 +372,7 @@ class Album(
|
|||
self.studio = data.attrib.get('studio')
|
||||
self.styles = self.findItems(data, media.Style)
|
||||
self.subformats = self.findItems(data, media.Subformat)
|
||||
self.ultraBlurColors = self.findItem(data, media.UltraBlurColors)
|
||||
self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount'))
|
||||
self.year = utils.cast(int, data.attrib.get('year'))
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ 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 urllib.parse import parse_qsl, urlencode, urlparse
|
||||
from xml.etree import ElementTree
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
|
@ -391,10 +391,9 @@ class PlexObject:
|
|||
|
||||
Parameters:
|
||||
key (string, optional): Override the key to reload.
|
||||
**kwargs (dict): A dictionary of XML include parameters to exclude or override.
|
||||
All parameters are included by default with the option to override each parameter
|
||||
or disable each parameter individually by setting it to False or 0.
|
||||
**kwargs (dict): A dictionary of XML include parameters to include/exclude or override.
|
||||
See :class:`~plexapi.base.PlexPartialObject` for all the available include parameters.
|
||||
Set parameter to True to include and False to exclude.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -402,20 +401,28 @@ class PlexObject:
|
|||
|
||||
from plexapi.server import PlexServer
|
||||
plex = PlexServer('http://localhost:32400', token='xxxxxxxxxxxxxxxxxxxx')
|
||||
movie = plex.library.section('Movies').get('Cars')
|
||||
|
||||
# Partial reload of the movie without the `checkFiles` parameter.
|
||||
# Excluding `checkFiles` will prevent the Plex server from reading the
|
||||
# file to check if the file still exists and is accessible.
|
||||
# The movie object will remain as a partial object.
|
||||
movie.reload(checkFiles=False)
|
||||
# Search results are partial objects.
|
||||
movie = plex.library.section('Movies').get('Cars')
|
||||
movie.isPartialObject() # Returns True
|
||||
|
||||
# Full reload of the movie with all include parameters.
|
||||
# Partial reload of the movie without a default include parameter.
|
||||
# The movie object will remain as a partial object.
|
||||
movie.reload(includeMarkers=False)
|
||||
movie.isPartialObject() # Returns True
|
||||
|
||||
# Full reload of the movie with all default include parameters.
|
||||
# The movie object will be a full object.
|
||||
movie.reload()
|
||||
movie.isFullObject() # Returns True
|
||||
|
||||
# Full reload of the movie with all default and extra include parameter.
|
||||
# Including `checkFiles` will tell the Plex server to check if the file
|
||||
# still exists and is accessible.
|
||||
# The movie object will be a full object.
|
||||
movie.reload(checkFiles=True)
|
||||
movie.isFullObject() # Returns True
|
||||
|
||||
"""
|
||||
return self._reload(key=key, **kwargs)
|
||||
|
||||
|
@ -505,25 +512,25 @@ class PlexPartialObject(PlexObject):
|
|||
automatically and update itself.
|
||||
"""
|
||||
_INCLUDES = {
|
||||
'checkFiles': 1,
|
||||
'includeAllConcerts': 1,
|
||||
'checkFiles': 0,
|
||||
'includeAllConcerts': 0,
|
||||
'includeBandwidths': 1,
|
||||
'includeChapters': 1,
|
||||
'includeChildren': 1,
|
||||
'includeConcerts': 1,
|
||||
'includeExternalMedia': 1,
|
||||
'includeExtras': 1,
|
||||
'includeChildren': 0,
|
||||
'includeConcerts': 0,
|
||||
'includeExternalMedia': 0,
|
||||
'includeExtras': 0,
|
||||
'includeFields': 'thumbBlurHash,artBlurHash',
|
||||
'includeGeolocation': 1,
|
||||
'includeLoudnessRamps': 1,
|
||||
'includeMarkers': 1,
|
||||
'includeOnDeck': 1,
|
||||
'includePopularLeaves': 1,
|
||||
'includePreferences': 1,
|
||||
'includeRelated': 1,
|
||||
'includeRelatedCount': 1,
|
||||
'includeReviews': 1,
|
||||
'includeStations': 1,
|
||||
'includeOnDeck': 0,
|
||||
'includePopularLeaves': 0,
|
||||
'includePreferences': 0,
|
||||
'includeRelated': 0,
|
||||
'includeRelatedCount': 0,
|
||||
'includeReviews': 0,
|
||||
'includeStations': 0,
|
||||
}
|
||||
_EXCLUDES = {
|
||||
'excludeElements': (
|
||||
|
@ -592,7 +599,11 @@ class PlexPartialObject(PlexObject):
|
|||
search result for a movie often only contain a portion of the attributes a full
|
||||
object (main url) for that movie would contain.
|
||||
"""
|
||||
return not self.key or (self._details_key or self.key) == self._initpath
|
||||
parsed_key = urlparse(self._details_key or self.key)
|
||||
parsed_initpath = urlparse(self._initpath)
|
||||
query_key = set(parse_qsl(parsed_key.query))
|
||||
query_init = set(parse_qsl(parsed_initpath.query))
|
||||
return not self.key or (parsed_key.path == parsed_initpath.path and query_key <= query_init)
|
||||
|
||||
def isPartialObject(self):
|
||||
""" Returns True if this is not a full object. """
|
||||
|
|
|
@ -197,7 +197,7 @@ class PlexClient(PlexObject):
|
|||
raise NotFound(message)
|
||||
else:
|
||||
raise BadRequest(message)
|
||||
data = response.text.encode('utf8')
|
||||
data = utils.cleanXMLString(response.text).encode('utf8')
|
||||
return ElementTree.fromstring(data) if data.strip() else None
|
||||
|
||||
def sendCommand(self, command, proxy=None, **params):
|
||||
|
|
|
@ -60,6 +60,7 @@ class Collection(
|
|||
title (str): Name of the collection.
|
||||
titleSort (str): Title to use when sorting (defaults to title).
|
||||
type (str): 'collection'
|
||||
ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
|
||||
updatedAt (datetime): Datetime the collection was updated.
|
||||
userRating (float): Rating of the collection (0.0 - 10.0) equaling (0 stars - 5 stars).
|
||||
"""
|
||||
|
@ -102,6 +103,7 @@ class Collection(
|
|||
self.title = data.attrib.get('title')
|
||||
self.titleSort = data.attrib.get('titleSort', self.title)
|
||||
self.type = data.attrib.get('type')
|
||||
self.ultraBlurColors = self.findItem(data, media.UltraBlurColors)
|
||||
self.updatedAt = utils.toDatetime(data.attrib.get('updatedAt'))
|
||||
self.userRating = utils.cast(float, data.attrib.get('userRating'))
|
||||
self._items = None # cache for self.items
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
# Library version
|
||||
MAJOR_VERSION = 4
|
||||
MINOR_VERSION = 15
|
||||
PATCH_VERSION = 15
|
||||
PATCH_VERSION = 16
|
||||
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__ = f"{__short_version__}.{PATCH_VERSION}"
|
||||
|
|
|
@ -2823,7 +2823,8 @@ class FilteringType(PlexObject):
|
|||
additionalFields.extend([
|
||||
('duration', 'integer', 'Duration'),
|
||||
('viewOffset', 'integer', 'View Offset'),
|
||||
('label', 'tag', 'Label')
|
||||
('label', 'tag', 'Label'),
|
||||
('ratingCount', 'integer', 'Rating Count'),
|
||||
])
|
||||
elif self.type == 'collection':
|
||||
additionalFields.extend([
|
||||
|
|
|
@ -106,12 +106,16 @@ class MediaPart(PlexObject):
|
|||
Attributes:
|
||||
TAG (str): 'Part'
|
||||
accessible (bool): True if the file is accessible.
|
||||
Requires reloading the media with ``checkFiles=True``.
|
||||
Refer to :func:`~plexapi.base.PlexObject.reload`.
|
||||
audioProfile (str): The audio profile of the file.
|
||||
container (str): The container type of the file (ex: avi).
|
||||
decision (str): Unknown.
|
||||
deepAnalysisVersion (int): The Plex deep analysis version for the file.
|
||||
duration (int): The duration of the file in milliseconds.
|
||||
exists (bool): True if the file exists.
|
||||
Requires reloading the media with ``checkFiles=True``.
|
||||
Refer to :func:`~plexapi.base.PlexObject.reload`.
|
||||
file (str): The path to this file on disk (ex: /media/Movies/Cars (2006)/Cars (2006).mkv)
|
||||
has64bitOffsets (bool): True if the file has 64 bit offsets.
|
||||
hasThumbnail (bool): True if the file (track) has an embedded thumbnail.
|
||||
|
@ -999,6 +1003,28 @@ class Review(PlexObject):
|
|||
self.text = data.attrib.get('text')
|
||||
|
||||
|
||||
@utils.registerPlexObject
|
||||
class UltraBlurColors(PlexObject):
|
||||
""" Represents a single UltraBlurColors media tag.
|
||||
|
||||
Attributes:
|
||||
TAG (str): 'UltraBlurColors'
|
||||
bottomLeft (str): The bottom left hex color.
|
||||
bottomRight (str): The bottom right hex color.
|
||||
topLeft (str): The top left hex color.
|
||||
topRight (str): The top right hex color.
|
||||
"""
|
||||
TAG = 'UltraBlurColors'
|
||||
|
||||
def _loadData(self, data):
|
||||
""" Load attribute values from Plex XML response. """
|
||||
self._data = data
|
||||
self.bottomLeft = data.attrib.get('bottomLeft')
|
||||
self.bottomRight = data.attrib.get('bottomRight')
|
||||
self.topLeft = data.attrib.get('topLeft')
|
||||
self.topRight = data.attrib.get('topRight')
|
||||
|
||||
|
||||
class BaseResource(PlexObject):
|
||||
""" Base class for all Art, Poster, and Theme objects.
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ class AdvancedSettingsMixin:
|
|||
|
||||
def preferences(self):
|
||||
""" Returns a list of :class:`~plexapi.settings.Preferences` objects. """
|
||||
data = self._server.query(self._details_key)
|
||||
return self.findItems(data, settings.Preferences, rtag='Preferences')
|
||||
key = f'{self.key}?includePreferences=1'
|
||||
return self.fetchItems(key, cls=settings.Preferences, rtag='Preferences')
|
||||
|
||||
def preference(self, pref):
|
||||
""" Returns a :class:`~plexapi.settings.Preferences` object for the specified pref.
|
||||
|
@ -240,8 +240,7 @@ class UnmatchMatchMixin:
|
|||
params['agent'] = utils.getAgentIdentifier(self.section(), agent)
|
||||
|
||||
key = key + '?' + urlencode(params)
|
||||
data = self._server.query(key, method=self._server._session.get)
|
||||
return self.findItems(data, initpath=key)
|
||||
return self.fetchItems(key, cls=media.SearchResult)
|
||||
|
||||
def fixMatch(self, searchResult=None, auto=False, agent=None):
|
||||
""" Use match result to update show metadata.
|
||||
|
@ -278,8 +277,8 @@ class ExtrasMixin:
|
|||
def extras(self):
|
||||
""" Returns a list of :class:`~plexapi.video.Extra` objects. """
|
||||
from plexapi.video import Extra
|
||||
data = self._server.query(self._details_key)
|
||||
return self.findItems(data, Extra, rtag='Extras')
|
||||
key = f'{self.key}/extras'
|
||||
return self.fetchItems(key, cls=Extra)
|
||||
|
||||
|
||||
class HubsMixin:
|
||||
|
@ -289,8 +288,7 @@ class HubsMixin:
|
|||
""" Returns a list of :class:`~plexapi.library.Hub` objects. """
|
||||
from plexapi.library import Hub
|
||||
key = f'{self.key}/related'
|
||||
data = self._server.query(key)
|
||||
return self.findItems(data, Hub)
|
||||
return self.fetchItems(key, cls=Hub)
|
||||
|
||||
|
||||
class PlayedUnplayedMixin:
|
||||
|
|
|
@ -250,7 +250,7 @@ class MyPlexAccount(PlexObject):
|
|||
return response.json()
|
||||
elif 'text/plain' in response.headers.get('Content-Type', ''):
|
||||
return response.text.strip()
|
||||
data = response.text.encode('utf8')
|
||||
data = utils.cleanXMLString(response.text).encode('utf8')
|
||||
return ElementTree.fromstring(data) if data.strip() else None
|
||||
|
||||
def ping(self):
|
||||
|
|
|
@ -768,7 +768,7 @@ class PlexServer(PlexObject):
|
|||
raise NotFound(message)
|
||||
else:
|
||||
raise BadRequest(message)
|
||||
data = response.text.encode('utf8')
|
||||
data = utils.cleanXMLString(response.text).encode('utf8')
|
||||
return ElementTree.fromstring(data) if data.strip() else None
|
||||
|
||||
def search(self, query, mediatype=None, limit=None, sectionId=None):
|
||||
|
|
|
@ -6,6 +6,7 @@ import logging
|
|||
import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
import time
|
||||
import unicodedata
|
||||
import warnings
|
||||
|
@ -673,3 +674,45 @@ def openOrRead(file):
|
|||
def sha1hash(guid):
|
||||
""" Return the SHA1 hash of a guid. """
|
||||
return sha1(guid.encode('utf-8')).hexdigest()
|
||||
|
||||
|
||||
# https://stackoverflow.com/a/64570125
|
||||
_illegal_XML_characters = [
|
||||
(0x00, 0x08),
|
||||
(0x0B, 0x0C),
|
||||
(0x0E, 0x1F),
|
||||
(0x7F, 0x84),
|
||||
(0x86, 0x9F),
|
||||
(0xFDD0, 0xFDDF),
|
||||
(0xFFFE, 0xFFFF),
|
||||
]
|
||||
if sys.maxunicode >= 0x10000: # not narrow build
|
||||
_illegal_XML_characters.extend(
|
||||
[
|
||||
(0x1FFFE, 0x1FFFF),
|
||||
(0x2FFFE, 0x2FFFF),
|
||||
(0x3FFFE, 0x3FFFF),
|
||||
(0x4FFFE, 0x4FFFF),
|
||||
(0x5FFFE, 0x5FFFF),
|
||||
(0x6FFFE, 0x6FFFF),
|
||||
(0x7FFFE, 0x7FFFF),
|
||||
(0x8FFFE, 0x8FFFF),
|
||||
(0x9FFFE, 0x9FFFF),
|
||||
(0xAFFFE, 0xAFFFF),
|
||||
(0xBFFFE, 0xBFFFF),
|
||||
(0xCFFFE, 0xCFFFF),
|
||||
(0xDFFFE, 0xDFFFF),
|
||||
(0xEFFFE, 0xEFFFF),
|
||||
(0xFFFFE, 0xFFFFF),
|
||||
(0x10FFFE, 0x10FFFF),
|
||||
]
|
||||
)
|
||||
_illegal_XML_ranges = [
|
||||
fr'{chr(low)}-{chr(high)}'
|
||||
for (low, high) in _illegal_XML_characters
|
||||
]
|
||||
_illegal_XML_re = re.compile(fr'[{"".join(_illegal_XML_ranges)}]')
|
||||
|
||||
|
||||
def cleanXMLString(s):
|
||||
return _illegal_XML_re.sub('', s)
|
||||
|
|
|
@ -375,6 +375,7 @@ class Movie(
|
|||
studio (str): Studio that created movie (Di Bonaventura Pictures; 21 Laps Entertainment).
|
||||
tagline (str): Movie tag line (Back 2 Work; Who says men can't change?).
|
||||
theme (str): URL to theme resource (/library/metadata/<ratingkey>/theme/<themeid>).
|
||||
ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
|
||||
useOriginalTitle (int): Setting that indicates if the original title is used for the movie
|
||||
(-1 = Library default, 0 = No, 1 = Yes).
|
||||
viewOffset (int): View offset in milliseconds.
|
||||
|
@ -420,6 +421,7 @@ class Movie(
|
|||
self.studio = data.attrib.get('studio')
|
||||
self.tagline = data.attrib.get('tagline')
|
||||
self.theme = data.attrib.get('theme')
|
||||
self.ultraBlurColors = self.findItem(data, media.UltraBlurColors)
|
||||
self.useOriginalTitle = utils.cast(int, data.attrib.get('useOriginalTitle', '-1'))
|
||||
self.viewOffset = utils.cast(int, data.attrib.get('viewOffset', 0))
|
||||
self.writers = self.findItems(data, media.Writer)
|
||||
|
@ -456,8 +458,8 @@ class Movie(
|
|||
|
||||
def reviews(self):
|
||||
""" Returns a list of :class:`~plexapi.media.Review` objects. """
|
||||
data = self._server.query(self._details_key)
|
||||
return self.findItems(data, media.Review, rtag='Video')
|
||||
key = f'{self.key}?includeReviews=1'
|
||||
return self.fetchItems(key, cls=media.Review, rtag='Video')
|
||||
|
||||
def editions(self):
|
||||
""" Returns a list of :class:`~plexapi.video.Movie` objects
|
||||
|
@ -543,6 +545,7 @@ class Show(
|
|||
(-1 = Account default, 0 = Manually selected, 1 = Shown with foreign audio, 2 = Always enabled).
|
||||
tagline (str): Show tag line.
|
||||
theme (str): URL to theme resource (/library/metadata/<ratingkey>/theme/<themeid>).
|
||||
ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
|
||||
useOriginalTitle (int): Setting that indicates if the original title is used for the show
|
||||
(-1 = Library default, 0 = No, 1 = Yes).
|
||||
viewedLeafCount (int): Number of items marked as played in the show view.
|
||||
|
@ -592,6 +595,7 @@ class Show(
|
|||
self.subtitleMode = utils.cast(int, data.attrib.get('subtitleMode', '-1'))
|
||||
self.tagline = data.attrib.get('tagline')
|
||||
self.theme = data.attrib.get('theme')
|
||||
self.ultraBlurColors = self.findItem(data, media.UltraBlurColors)
|
||||
self.useOriginalTitle = utils.cast(int, data.attrib.get('useOriginalTitle', '-1'))
|
||||
self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount'))
|
||||
self.year = utils.cast(int, data.attrib.get('year'))
|
||||
|
@ -614,8 +618,8 @@ class Show(
|
|||
""" Returns show's On Deck :class:`~plexapi.video.Video` object or `None`.
|
||||
If show is unwatched, return will likely be the first episode.
|
||||
"""
|
||||
data = self._server.query(self._details_key)
|
||||
return next(iter(self.findItems(data, rtag='OnDeck')), None)
|
||||
key = f'{self.key}?includeOnDeck=1'
|
||||
return next(iter(self.fetchItems(key, cls=Episode, rtag='OnDeck')), None)
|
||||
|
||||
def season(self, title=None, season=None):
|
||||
""" Returns the season with the specified title or number.
|
||||
|
@ -735,6 +739,7 @@ class Season(
|
|||
subtitleLanguage (str): Setting that indicates the preferred subtitle language.
|
||||
subtitleMode (int): Setting that indicates the auto-select subtitle mode.
|
||||
(-1 = Series default, 0 = Manually selected, 1 = Shown with foreign audio, 2 = Always enabled).
|
||||
ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
|
||||
viewedLeafCount (int): Number of items marked as played in the season view.
|
||||
year (int): Year the season was released.
|
||||
"""
|
||||
|
@ -766,6 +771,7 @@ class Season(
|
|||
self.ratings = self.findItems(data, media.Rating)
|
||||
self.subtitleLanguage = data.attrib.get('subtitleLanguage', '')
|
||||
self.subtitleMode = utils.cast(int, data.attrib.get('subtitleMode', '-1'))
|
||||
self.ultraBlurColors = self.findItem(data, media.UltraBlurColors)
|
||||
self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount'))
|
||||
self.year = utils.cast(int, data.attrib.get('year'))
|
||||
|
||||
|
@ -796,8 +802,8 @@ class Season(
|
|||
""" Returns season's On Deck :class:`~plexapi.video.Video` object or `None`.
|
||||
Will only return a match if the show's On Deck episode is in this season.
|
||||
"""
|
||||
data = self._server.query(self._details_key)
|
||||
return next(iter(self.findItems(data, rtag='OnDeck')), None)
|
||||
key = f'{self.key}?includeOnDeck=1'
|
||||
return next(iter(self.fetchItems(key, cls=Episode, rtag='OnDeck')), None)
|
||||
|
||||
def episode(self, title=None, episode=None):
|
||||
""" Returns the episode with the given title or number.
|
||||
|
@ -914,6 +920,7 @@ class Episode(
|
|||
skipParent (bool): True if the show's seasons are set to hidden.
|
||||
sourceURI (str): Remote server URI (server://<machineIdentifier>/com.plexapp.plugins.library)
|
||||
(remote playlist item only).
|
||||
ultraBlurColors (:class:`~plexapi.media.UltraBlurColors`): Ultra blur color object.
|
||||
viewOffset (int): View offset in milliseconds.
|
||||
writers (List<:class:`~plexapi.media.Writer`>): List of writers objects.
|
||||
year (int): Year the episode was released.
|
||||
|
@ -958,6 +965,7 @@ class Episode(
|
|||
self.roles = self.findItems(data, media.Role)
|
||||
self.skipParent = utils.cast(bool, data.attrib.get('skipParent', '0'))
|
||||
self.sourceURI = data.attrib.get('source') # remote playlist item
|
||||
self.ultraBlurColors = self.findItem(data, media.UltraBlurColors)
|
||||
self.viewOffset = utils.cast(int, data.attrib.get('viewOffset', 0))
|
||||
self.writers = self.findItems(data, media.Writer)
|
||||
self.year = utils.cast(int, data.attrib.get('year'))
|
||||
|
|
|
@ -26,7 +26,7 @@ musicbrainzngs==0.7.1
|
|||
packaging==24.1
|
||||
paho-mqtt==2.1.0
|
||||
platformdirs==4.2.2
|
||||
plexapi==4.15.15
|
||||
plexapi==4.15.16
|
||||
portend==3.2.0
|
||||
profilehooks==1.12.0
|
||||
PyJWT==2.9.0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue