mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-08 06:00:51 -07:00
Merge custom plexapi 3.6.0-tautulli
This commit is contained in:
parent
056d0d81ac
commit
c324cf69ed
6 changed files with 175 additions and 14 deletions
|
@ -36,6 +36,8 @@ class Audio(PlexPartialObject):
|
||||||
self.key = data.attrib.get('key')
|
self.key = data.attrib.get('key')
|
||||||
self.lastViewedAt = utils.toDatetime(data.attrib.get('lastViewedAt'))
|
self.lastViewedAt = utils.toDatetime(data.attrib.get('lastViewedAt'))
|
||||||
self.librarySectionID = data.attrib.get('librarySectionID')
|
self.librarySectionID = data.attrib.get('librarySectionID')
|
||||||
|
self.librarySectionKey = data.attrib.get('librarySectionKey')
|
||||||
|
self.librarySectionTitle = data.attrib.get('librarySectionTitle')
|
||||||
self.ratingKey = utils.cast(int, data.attrib.get('ratingKey'))
|
self.ratingKey = utils.cast(int, data.attrib.get('ratingKey'))
|
||||||
self.summary = data.attrib.get('summary')
|
self.summary = data.attrib.get('summary')
|
||||||
self.thumb = data.attrib.get('thumb')
|
self.thumb = data.attrib.get('thumb')
|
||||||
|
@ -120,17 +122,26 @@ class Artist(Audio):
|
||||||
TAG = 'Directory'
|
TAG = 'Directory'
|
||||||
TYPE = 'artist'
|
TYPE = 'artist'
|
||||||
|
|
||||||
|
_include = ('?checkFiles=1&includeExtras=1&includeRelated=1'
|
||||||
|
'&includeOnDeck=1&includeChapters=1&includePopularLeaves=1'
|
||||||
|
'&includeMarkers=1&includeConcerts=1&includePreferences=1'
|
||||||
|
'&indcludeBandwidths=1&includeLoudnessRamps=1')
|
||||||
|
|
||||||
def _loadData(self, data):
|
def _loadData(self, data):
|
||||||
""" Load attribute values from Plex XML response. """
|
""" Load attribute values from Plex XML response. """
|
||||||
Audio._loadData(self, data)
|
Audio._loadData(self, data)
|
||||||
|
self._details_key = self.key + self._include
|
||||||
self.art = data.attrib.get('art')
|
self.art = data.attrib.get('art')
|
||||||
self.guid = data.attrib.get('guid')
|
self.guid = data.attrib.get('guid')
|
||||||
self.key = self.key.replace('/children', '') # FIX_BUG_50
|
self.key = self.key.replace('/children', '') # FIX_BUG_50
|
||||||
self.locations = self.listAttrs(data, 'path', etag='Location')
|
self.locations = self.listAttrs(data, 'path', etag='Location')
|
||||||
self.countries = self.findItems(data, media.Country)
|
self.countries = self.findItems(data, media.Country)
|
||||||
|
self.fields = self.findItems(data, media.Field)
|
||||||
self.genres = self.findItems(data, media.Genre)
|
self.genres = self.findItems(data, media.Genre)
|
||||||
self.similar = self.findItems(data, media.Similar)
|
self.similar = self.findItems(data, media.Similar)
|
||||||
self.collections = self.findItems(data, media.Collection)
|
self.collections = self.findItems(data, media.Collection)
|
||||||
|
self.moods = self.findItems(data, media.Mood)
|
||||||
|
self.styles = self.findItems(data, media.Style)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for album in self.albums():
|
for album in self.albums():
|
||||||
|
@ -217,17 +228,26 @@ class Album(Audio):
|
||||||
""" Load attribute values from Plex XML response. """
|
""" Load attribute values from Plex XML response. """
|
||||||
Audio._loadData(self, data)
|
Audio._loadData(self, data)
|
||||||
self.art = data.attrib.get('art')
|
self.art = data.attrib.get('art')
|
||||||
|
self.guid = data.attrib.get('guid')
|
||||||
|
self.leafCount = utils.cast(int, data.attrib.get('leafCount'))
|
||||||
|
self.loudnessAnalysisVersion = utils.cast(int, data.attrib.get('loudnessAnalysisVersion'))
|
||||||
self.key = self.key.replace('/children', '') # fixes bug #50
|
self.key = self.key.replace('/children', '') # fixes bug #50
|
||||||
self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt'), '%Y-%m-%d')
|
self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt'), '%Y-%m-%d')
|
||||||
|
self.parentGuid = data.attrib.get('parentGuid')
|
||||||
self.parentKey = data.attrib.get('parentKey')
|
self.parentKey = data.attrib.get('parentKey')
|
||||||
self.parentRatingKey = data.attrib.get('parentRatingKey')
|
self.parentRatingKey = data.attrib.get('parentRatingKey')
|
||||||
self.parentThumb = data.attrib.get('parentThumb')
|
self.parentThumb = data.attrib.get('parentThumb')
|
||||||
self.parentTitle = data.attrib.get('parentTitle')
|
self.parentTitle = data.attrib.get('parentTitle')
|
||||||
|
self.rating = utils.cast(float, data.attrib.get('rating'))
|
||||||
self.studio = data.attrib.get('studio')
|
self.studio = data.attrib.get('studio')
|
||||||
|
self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount'))
|
||||||
self.year = utils.cast(int, data.attrib.get('year'))
|
self.year = utils.cast(int, data.attrib.get('year'))
|
||||||
self.genres = self.findItems(data, media.Genre)
|
|
||||||
self.collections = self.findItems(data, media.Collection)
|
self.collections = self.findItems(data, media.Collection)
|
||||||
|
self.fields = self.findItems(data, media.Field)
|
||||||
|
self.genres = self.findItems(data, media.Genre)
|
||||||
self.labels = self.findItems(data, media.Label)
|
self.labels = self.findItems(data, media.Label)
|
||||||
|
self.moods = self.findItems(data, media.Mood)
|
||||||
|
self.styles = self.findItems(data, media.Style)
|
||||||
|
|
||||||
def track(self, title):
|
def track(self, title):
|
||||||
""" Returns the :class:`~plexapi.audio.Track` that matches the specified title.
|
""" Returns the :class:`~plexapi.audio.Track` that matches the specified title.
|
||||||
|
@ -312,20 +332,28 @@ class Track(Audio, Playable):
|
||||||
TAG = 'Track'
|
TAG = 'Track'
|
||||||
TYPE = 'track'
|
TYPE = 'track'
|
||||||
|
|
||||||
|
_include = ('?checkFiles=1&includeExtras=1&includeRelated=1'
|
||||||
|
'&includeOnDeck=1&includeChapters=1&includePopularLeaves=1'
|
||||||
|
'&includeMarkers=1&includeConcerts=1&includePreferences=1'
|
||||||
|
'&indcludeBandwidths=1&includeLoudnessRamps=1')
|
||||||
|
|
||||||
def _loadData(self, data):
|
def _loadData(self, data):
|
||||||
""" Load attribute values from Plex XML response. """
|
""" Load attribute values from Plex XML response. """
|
||||||
Audio._loadData(self, data)
|
Audio._loadData(self, data)
|
||||||
Playable._loadData(self, data)
|
Playable._loadData(self, data)
|
||||||
|
self._details_key = self.key + self._include
|
||||||
self.art = data.attrib.get('art')
|
self.art = data.attrib.get('art')
|
||||||
self.chapterSource = data.attrib.get('chapterSource')
|
self.chapterSource = data.attrib.get('chapterSource')
|
||||||
self.duration = utils.cast(int, data.attrib.get('duration'))
|
self.duration = utils.cast(int, data.attrib.get('duration'))
|
||||||
self.grandparentArt = data.attrib.get('grandparentArt')
|
self.grandparentArt = data.attrib.get('grandparentArt')
|
||||||
|
self.grandparentGuid = data.attrib.get('grandparentGuid')
|
||||||
self.grandparentKey = data.attrib.get('grandparentKey')
|
self.grandparentKey = data.attrib.get('grandparentKey')
|
||||||
self.grandparentRatingKey = data.attrib.get('grandparentRatingKey')
|
self.grandparentRatingKey = data.attrib.get('grandparentRatingKey')
|
||||||
self.grandparentThumb = data.attrib.get('grandparentThumb')
|
self.grandparentThumb = data.attrib.get('grandparentThumb')
|
||||||
self.grandparentTitle = data.attrib.get('grandparentTitle')
|
self.grandparentTitle = data.attrib.get('grandparentTitle')
|
||||||
self.guid = data.attrib.get('guid')
|
self.guid = data.attrib.get('guid')
|
||||||
self.originalTitle = data.attrib.get('originalTitle')
|
self.originalTitle = data.attrib.get('originalTitle')
|
||||||
|
self.parentGuid = data.attrib.get('parentGuid')
|
||||||
self.parentIndex = data.attrib.get('parentIndex')
|
self.parentIndex = data.attrib.get('parentIndex')
|
||||||
self.parentKey = data.attrib.get('parentKey')
|
self.parentKey = data.attrib.get('parentKey')
|
||||||
self.parentRatingKey = data.attrib.get('parentRatingKey')
|
self.parentRatingKey = data.attrib.get('parentRatingKey')
|
||||||
|
@ -351,6 +379,13 @@ class Track(Audio, Playable):
|
||||||
""" Return this track's :class:`~plexapi.audio.Artist`. """
|
""" Return this track's :class:`~plexapi.audio.Artist`. """
|
||||||
return self.fetchItem(self.grandparentKey)
|
return self.fetchItem(self.grandparentKey)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def locations(self):
|
||||||
|
""" This does not exist in plex xml response but is added to have a common
|
||||||
|
interface to get the location of the Artist
|
||||||
|
"""
|
||||||
|
return [part.file for part in self.iterParts() if part]
|
||||||
|
|
||||||
def _defaultSyncTitle(self):
|
def _defaultSyncTitle(self):
|
||||||
""" Returns str, default title for a new syncItem. """
|
""" Returns str, default title for a new syncItem. """
|
||||||
return '%s - %s - %s' % (self.grandparentTitle, self.parentTitle, self.title)
|
return '%s - %s - %s' % (self.grandparentTitle, self.parentTitle, self.title)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from plexapi import X_PLEX_CONTAINER_SIZE, log, utils
|
from plexapi import X_PLEX_CONTAINER_SIZE, log, utils, media
|
||||||
from plexapi.base import PlexObject
|
from plexapi.base import PlexObject
|
||||||
from plexapi.compat import quote, quote_plus, unquote, urlencode
|
from plexapi.compat import quote, quote_plus, unquote, urlencode
|
||||||
from plexapi.exceptions import BadRequest, NotFound
|
from plexapi.exceptions import BadRequest, NotFound
|
||||||
|
@ -1092,9 +1092,15 @@ class Collections(PlexObject):
|
||||||
def _loadData(self, data):
|
def _loadData(self, data):
|
||||||
self.ratingKey = utils.cast(int, data.attrib.get('ratingKey'))
|
self.ratingKey = utils.cast(int, data.attrib.get('ratingKey'))
|
||||||
self._details_key = "/library/metadata/%s%s" % (self.ratingKey, self._include)
|
self._details_key = "/library/metadata/%s%s" % (self.ratingKey, self._include)
|
||||||
|
self.contentRating = data.attrib.get('contentRating')
|
||||||
|
self.guid = data.attrib.get('guid')
|
||||||
self.key = data.attrib.get('key')
|
self.key = data.attrib.get('key')
|
||||||
|
self.librarySectionID = data.attrib.get('librarySectionID')
|
||||||
|
self.librarySectionKey = data.attrib.get('librarySectionKey')
|
||||||
|
self.librarySectionTitle = data.attrib.get('librarySectionTitle')
|
||||||
self.type = data.attrib.get('type')
|
self.type = data.attrib.get('type')
|
||||||
self.title = data.attrib.get('title')
|
self.title = data.attrib.get('title')
|
||||||
|
self.titleSort = data.attrib.get('titleSort')
|
||||||
self.subtype = data.attrib.get('subtype')
|
self.subtype = data.attrib.get('subtype')
|
||||||
self.summary = data.attrib.get('summary')
|
self.summary = data.attrib.get('summary')
|
||||||
self.index = utils.cast(int, data.attrib.get('index'))
|
self.index = utils.cast(int, data.attrib.get('index'))
|
||||||
|
@ -1106,6 +1112,7 @@ class Collections(PlexObject):
|
||||||
self.maxYear = utils.cast(int, data.attrib.get('maxYear'))
|
self.maxYear = utils.cast(int, data.attrib.get('maxYear'))
|
||||||
self.collectionMode = data.attrib.get('collectionMode')
|
self.collectionMode = data.attrib.get('collectionMode')
|
||||||
self.collectionSort = data.attrib.get('collectionSort')
|
self.collectionSort = data.attrib.get('collectionSort')
|
||||||
|
self.fields = self.findItems(data, media.Field)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def children(self):
|
def children(self):
|
||||||
|
|
|
@ -5,7 +5,7 @@ import xml
|
||||||
from plexapi import compat, log, settings, utils
|
from plexapi import compat, log, settings, utils
|
||||||
from plexapi.base import PlexObject
|
from plexapi.base import PlexObject
|
||||||
from plexapi.exceptions import BadRequest
|
from plexapi.exceptions import BadRequest
|
||||||
from plexapi.utils import cast
|
from plexapi.utils import cast, SEARCHTYPES
|
||||||
|
|
||||||
|
|
||||||
@utils.registerPlexObject
|
@utils.registerPlexObject
|
||||||
|
@ -45,6 +45,7 @@ class Media(PlexObject):
|
||||||
self.aspectRatio = cast(float, data.attrib.get('aspectRatio'))
|
self.aspectRatio = cast(float, data.attrib.get('aspectRatio'))
|
||||||
self.audioChannels = cast(int, data.attrib.get('audioChannels'))
|
self.audioChannels = cast(int, data.attrib.get('audioChannels'))
|
||||||
self.audioCodec = data.attrib.get('audioCodec')
|
self.audioCodec = data.attrib.get('audioCodec')
|
||||||
|
self.audioProfile = data.attrib.get('videoProfile')
|
||||||
self.bitrate = cast(int, data.attrib.get('bitrate'))
|
self.bitrate = cast(int, data.attrib.get('bitrate'))
|
||||||
self.container = data.attrib.get('container')
|
self.container = data.attrib.get('container')
|
||||||
self.duration = cast(int, data.attrib.get('duration'))
|
self.duration = cast(int, data.attrib.get('duration'))
|
||||||
|
@ -60,6 +61,16 @@ class Media(PlexObject):
|
||||||
self.videoResolution = data.attrib.get('videoResolution')
|
self.videoResolution = data.attrib.get('videoResolution')
|
||||||
self.width = cast(int, data.attrib.get('width'))
|
self.width = cast(int, data.attrib.get('width'))
|
||||||
self.parts = self.findItems(data, MediaPart)
|
self.parts = self.findItems(data, MediaPart)
|
||||||
|
self.proxyType = cast(int, data.attrib.get('proxyType'))
|
||||||
|
self.optimizedVersion = self.proxyType == SEARCHTYPES['optimizedVersion']
|
||||||
|
|
||||||
|
# For Photo only
|
||||||
|
self.aperture = data.attrib.get('aperture')
|
||||||
|
self.exposure = data.attrib.get('exposure')
|
||||||
|
self.iso = cast(int, data.attrib.get('iso'))
|
||||||
|
self.lens = data.attrib.get('lens')
|
||||||
|
self.make = data.attrib.get('make')
|
||||||
|
self.model = data.attrib.get('model')
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
part = self._initpath + '/media/%s' % self.id
|
part = self._initpath + '/media/%s' % self.id
|
||||||
|
@ -96,15 +107,20 @@ class MediaPart(PlexObject):
|
||||||
def _loadData(self, data):
|
def _loadData(self, data):
|
||||||
""" Load attribute values from Plex XML response. """
|
""" Load attribute values from Plex XML response. """
|
||||||
self._data = data
|
self._data = data
|
||||||
|
self.audioProfile = data.attrib.get('audioProfile')
|
||||||
self.container = data.attrib.get('container')
|
self.container = data.attrib.get('container')
|
||||||
|
self.deepAnalysisVersion = cast(int, data.attrib.get('deepAnalysisVersion'))
|
||||||
self.duration = cast(int, data.attrib.get('duration'))
|
self.duration = cast(int, data.attrib.get('duration'))
|
||||||
self.file = data.attrib.get('file')
|
self.file = data.attrib.get('file')
|
||||||
|
self.has64bitOffsets = cast(bool, data.attrib.get('has64bitOffsets'))
|
||||||
|
self.hasThumbnail = cast(bool, data.attrib.get('hasThumbnail'))
|
||||||
self.id = cast(int, data.attrib.get('id'))
|
self.id = cast(int, data.attrib.get('id'))
|
||||||
self.indexes = data.attrib.get('indexes')
|
self.indexes = data.attrib.get('indexes')
|
||||||
self.key = data.attrib.get('key')
|
self.key = data.attrib.get('key')
|
||||||
self.size = cast(int, data.attrib.get('size'))
|
self.size = cast(int, data.attrib.get('size'))
|
||||||
self.decision = data.attrib.get('decision')
|
self.decision = data.attrib.get('decision')
|
||||||
self.optimizedForStreaming = cast(bool, data.attrib.get('optimizedForStreaming'))
|
self.optimizedForStreaming = cast(bool, data.attrib.get('optimizedForStreaming'))
|
||||||
|
self.requiredBandwidths = data.attrib.get('requiredBandwidths')
|
||||||
self.syncItemId = cast(int, data.attrib.get('syncItemId'))
|
self.syncItemId = cast(int, data.attrib.get('syncItemId'))
|
||||||
self.syncState = data.attrib.get('syncState')
|
self.syncState = data.attrib.get('syncState')
|
||||||
self.videoProfile = data.attrib.get('videoProfile')
|
self.videoProfile = data.attrib.get('videoProfile')
|
||||||
|
@ -112,10 +128,13 @@ class MediaPart(PlexObject):
|
||||||
self.exists = cast(bool, data.attrib.get('exists'))
|
self.exists = cast(bool, data.attrib.get('exists'))
|
||||||
self.accessible = cast(bool, data.attrib.get('accessible'))
|
self.accessible = cast(bool, data.attrib.get('accessible'))
|
||||||
|
|
||||||
|
# For Photo only
|
||||||
|
self.orientation = cast(int, data.attrib.get('orientation'))
|
||||||
|
|
||||||
def _buildStreams(self, data):
|
def _buildStreams(self, data):
|
||||||
streams = []
|
streams = []
|
||||||
for elem in data:
|
for elem in data:
|
||||||
for cls in (VideoStream, AudioStream, SubtitleStream):
|
for cls in (VideoStream, AudioStream, SubtitleStream, LyricStream):
|
||||||
if elem.attrib.get('streamType') == str(cls.STREAMTYPE):
|
if elem.attrib.get('streamType') == str(cls.STREAMTYPE):
|
||||||
streams.append(cls(self._server, elem, self._initpath))
|
streams.append(cls(self._server, elem, self._initpath))
|
||||||
return streams
|
return streams
|
||||||
|
@ -132,6 +151,10 @@ class MediaPart(PlexObject):
|
||||||
""" Returns a list of :class:`~plexapi.media.SubtitleStream` objects in this MediaPart. """
|
""" Returns a list of :class:`~plexapi.media.SubtitleStream` objects in this MediaPart. """
|
||||||
return [stream for stream in self.streams if stream.streamType == SubtitleStream.STREAMTYPE]
|
return [stream for stream in self.streams if stream.streamType == SubtitleStream.STREAMTYPE]
|
||||||
|
|
||||||
|
def lyricStreams(self):
|
||||||
|
""" Returns a list of :class:`~plexapi.media.LyricStream` objects in this MediaPart. """
|
||||||
|
return [stream for stream in self.streams if stream.streamType == LyricStream.STREAMTYPE]
|
||||||
|
|
||||||
def setDefaultAudioStream(self, stream):
|
def setDefaultAudioStream(self, stream):
|
||||||
""" Set the default :class:`~plexapi.media.AudioStream` for this MediaPart.
|
""" Set the default :class:`~plexapi.media.AudioStream` for this MediaPart.
|
||||||
|
|
||||||
|
@ -177,7 +200,8 @@ class MediaPartStream(PlexObject):
|
||||||
languageCode (str): Ascii code for language (ex: eng, tha).
|
languageCode (str): Ascii code for language (ex: eng, tha).
|
||||||
selected (bool): True if this stream is selected.
|
selected (bool): True if this stream is selected.
|
||||||
streamType (int): Stream type (1=:class:`~plexapi.media.VideoStream`,
|
streamType (int): Stream type (1=:class:`~plexapi.media.VideoStream`,
|
||||||
2=:class:`~plexapi.media.AudioStream`, 3=:class:`~plexapi.media.SubtitleStream`).
|
2=:class:`~plexapi.media.AudioStream`, 3=:class:`~plexapi.media.SubtitleStream`,
|
||||||
|
4=:class:`~plexapi.media.LyricStream`).
|
||||||
type (int): Alias for streamType.
|
type (int): Alias for streamType.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -186,18 +210,22 @@ class MediaPartStream(PlexObject):
|
||||||
self._data = data
|
self._data = data
|
||||||
self.codec = data.attrib.get('codec')
|
self.codec = data.attrib.get('codec')
|
||||||
self.codecID = data.attrib.get('codecID')
|
self.codecID = data.attrib.get('codecID')
|
||||||
|
self.default = cast(bool, data.attrib.get('selected', '0'))
|
||||||
|
self.displayTitle = data.attrib.get('displayTitle')
|
||||||
|
self.extendedDisplayTitle = data.attrib.get('extendedDisplayTitle')
|
||||||
self.id = cast(int, data.attrib.get('id'))
|
self.id = cast(int, data.attrib.get('id'))
|
||||||
self.index = cast(int, data.attrib.get('index', '-1'))
|
self.index = cast(int, data.attrib.get('index', '-1'))
|
||||||
self.language = data.attrib.get('language')
|
self.language = data.attrib.get('language')
|
||||||
self.languageCode = data.attrib.get('languageCode')
|
self.languageCode = data.attrib.get('languageCode')
|
||||||
self.selected = cast(bool, data.attrib.get('selected', '0'))
|
self.selected = cast(bool, data.attrib.get('selected', '0'))
|
||||||
self.streamType = cast(int, data.attrib.get('streamType'))
|
self.streamType = cast(int, data.attrib.get('streamType'))
|
||||||
|
self.title = data.attrib.get('title')
|
||||||
self.type = cast(int, data.attrib.get('streamType'))
|
self.type = cast(int, data.attrib.get('streamType'))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse(server, data, initpath): # pragma: no cover seems to be dead code.
|
def parse(server, data, initpath): # pragma: no cover seems to be dead code.
|
||||||
""" Factory method returns a new MediaPartStream from xml data. """
|
""" Factory method returns a new MediaPartStream from xml data. """
|
||||||
STREAMCLS = {1: VideoStream, 2: AudioStream, 3: SubtitleStream}
|
STREAMCLS = {1: VideoStream, 2: AudioStream, 3: SubtitleStream, 4: LyricStream}
|
||||||
stype = cast(int, data.attrib.get('streamType'))
|
stype = cast(int, data.attrib.get('streamType'))
|
||||||
cls = STREAMCLS.get(stype, MediaPartStream)
|
cls = STREAMCLS.get(stype, MediaPartStream)
|
||||||
return cls(server, data, initpath)
|
return cls(server, data, initpath)
|
||||||
|
@ -236,18 +264,25 @@ class VideoStream(MediaPartStream):
|
||||||
self.bitDepth = cast(int, data.attrib.get('bitDepth'))
|
self.bitDepth = cast(int, data.attrib.get('bitDepth'))
|
||||||
self.bitrate = cast(int, data.attrib.get('bitrate'))
|
self.bitrate = cast(int, data.attrib.get('bitrate'))
|
||||||
self.cabac = cast(int, data.attrib.get('cabac'))
|
self.cabac = cast(int, data.attrib.get('cabac'))
|
||||||
|
self.chromaLocation = data.attrib.get('chromaLocation')
|
||||||
self.chromaSubsampling = data.attrib.get('chromaSubsampling')
|
self.chromaSubsampling = data.attrib.get('chromaSubsampling')
|
||||||
|
self.codedHeight = data.attrib.get('codedHeight')
|
||||||
|
self.codedWidth = data.attrib.get('codedWidth')
|
||||||
|
self.colorPrimaries = data.attrib.get('colorPrimaries')
|
||||||
|
self.colorRange = data.attrib.get('colorRange')
|
||||||
self.colorSpace = data.attrib.get('colorSpace')
|
self.colorSpace = data.attrib.get('colorSpace')
|
||||||
|
self.colorTrc = data.attrib.get('colorTrc')
|
||||||
self.duration = cast(int, data.attrib.get('duration'))
|
self.duration = cast(int, data.attrib.get('duration'))
|
||||||
self.frameRate = cast(float, data.attrib.get('frameRate'))
|
self.frameRate = cast(float, data.attrib.get('frameRate'))
|
||||||
self.frameRateMode = data.attrib.get('frameRateMode')
|
self.frameRateMode = data.attrib.get('frameRateMode')
|
||||||
self.hasScallingMatrix = cast(bool, data.attrib.get('hasScallingMatrix'))
|
self.hasScalingMatrix = cast(bool, data.attrib.get('hasScalingMatrix'))
|
||||||
self.height = cast(int, data.attrib.get('height'))
|
self.height = cast(int, data.attrib.get('height'))
|
||||||
self.level = cast(int, data.attrib.get('level'))
|
self.level = cast(int, data.attrib.get('level'))
|
||||||
self.profile = data.attrib.get('profile')
|
self.profile = data.attrib.get('profile')
|
||||||
self.refFrames = cast(int, data.attrib.get('refFrames'))
|
self.refFrames = cast(int, data.attrib.get('refFrames'))
|
||||||
|
self.requiredBandwidths = data.attrib.get('requiredBandwidths')
|
||||||
self.scanType = data.attrib.get('scanType')
|
self.scanType = data.attrib.get('scanType')
|
||||||
self.title = data.attrib.get('title')
|
self.streamIdentifier = cast(int, data.attrib.get('streamIdentifier'))
|
||||||
self.width = cast(int, data.attrib.get('width'))
|
self.width = cast(int, data.attrib.get('width'))
|
||||||
|
|
||||||
|
|
||||||
|
@ -281,8 +316,20 @@ class AudioStream(MediaPartStream):
|
||||||
self.channels = cast(int, data.attrib.get('channels'))
|
self.channels = cast(int, data.attrib.get('channels'))
|
||||||
self.dialogNorm = cast(int, data.attrib.get('dialogNorm'))
|
self.dialogNorm = cast(int, data.attrib.get('dialogNorm'))
|
||||||
self.duration = cast(int, data.attrib.get('duration'))
|
self.duration = cast(int, data.attrib.get('duration'))
|
||||||
|
self.profile = data.attrib.get('profile')
|
||||||
|
self.requiredBandwidths = data.attrib.get('requiredBandwidths')
|
||||||
self.samplingRate = cast(int, data.attrib.get('samplingRate'))
|
self.samplingRate = cast(int, data.attrib.get('samplingRate'))
|
||||||
self.title = data.attrib.get('title')
|
|
||||||
|
# For Track only
|
||||||
|
self.albumGain = cast(float, data.attrib.get('albumGain'))
|
||||||
|
self.albumPeak = cast(float, data.attrib.get('albumPeak'))
|
||||||
|
self.albumRange = cast(float, data.attrib.get('albumRange'))
|
||||||
|
self.endRamp = data.attrib.get('endRamp')
|
||||||
|
self.gain = cast(float, data.attrib.get('gain'))
|
||||||
|
self.loudness = cast(float, data.attrib.get('loudness'))
|
||||||
|
self.lra = cast(float, data.attrib.get('lra'))
|
||||||
|
self.peak = cast(float, data.attrib.get('peak'))
|
||||||
|
self.startRamp = data.attrib.get('startRamp')
|
||||||
|
|
||||||
|
|
||||||
@utils.registerPlexObject
|
@utils.registerPlexObject
|
||||||
|
@ -303,10 +350,35 @@ class SubtitleStream(MediaPartStream):
|
||||||
def _loadData(self, data):
|
def _loadData(self, data):
|
||||||
""" Load attribute values from Plex XML response. """
|
""" Load attribute values from Plex XML response. """
|
||||||
super(SubtitleStream, self)._loadData(data)
|
super(SubtitleStream, self)._loadData(data)
|
||||||
|
self.container = data.attrib.get('container')
|
||||||
self.forced = cast(bool, data.attrib.get('forced', '0'))
|
self.forced = cast(bool, data.attrib.get('forced', '0'))
|
||||||
self.format = data.attrib.get('format')
|
self.format = data.attrib.get('format')
|
||||||
self.key = data.attrib.get('key')
|
self.key = data.attrib.get('key')
|
||||||
self.title = data.attrib.get('title')
|
self.requiredBandwidths = data.attrib.get('requiredBandwidths')
|
||||||
|
|
||||||
|
|
||||||
|
@utils.registerPlexObject
|
||||||
|
class LyricStream(MediaPartStream):
|
||||||
|
""" Respresents a lyric stream within a :class:`~plexapi.media.MediaPart`.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
TAG (str): 'Stream'
|
||||||
|
STREAMTYPE (int): 4
|
||||||
|
format (str): Lyric format (ex: lrc).
|
||||||
|
key (str): Key of this subtitle stream (ex: /library/streams/212284).
|
||||||
|
title (str): Title of this lyric stream.
|
||||||
|
"""
|
||||||
|
TAG = 'Stream'
|
||||||
|
STREAMTYPE = 4
|
||||||
|
|
||||||
|
def _loadData(self, data):
|
||||||
|
""" Load attribute values from Plex XML response. """
|
||||||
|
super(LyricStream, self)._loadData(data)
|
||||||
|
self.format = data.attrib.get('format')
|
||||||
|
self.key = data.attrib.get('key')
|
||||||
|
self.minLines = cast(int, data.attrib.get('minLines'))
|
||||||
|
self.provider = data.attrib.get('provider')
|
||||||
|
self.timed = cast(bool, data.attrib.get('timed', '0'))
|
||||||
|
|
||||||
|
|
||||||
@utils.registerPlexObject
|
@utils.registerPlexObject
|
||||||
|
@ -601,6 +673,18 @@ class Mood(MediaTag):
|
||||||
FILTER = 'mood'
|
FILTER = 'mood'
|
||||||
|
|
||||||
|
|
||||||
|
@utils.registerPlexObject
|
||||||
|
class Style(MediaTag):
|
||||||
|
""" Represents a single Style media tag.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
TAG (str): 'Style'
|
||||||
|
FILTER (str): 'style'
|
||||||
|
"""
|
||||||
|
TAG = 'Style'
|
||||||
|
FILTER = 'style'
|
||||||
|
|
||||||
|
|
||||||
@utils.registerPlexObject
|
@utils.registerPlexObject
|
||||||
class Poster(PlexObject):
|
class Poster(PlexObject):
|
||||||
""" Represents a Poster.
|
""" Represents a Poster.
|
||||||
|
@ -689,6 +773,7 @@ class Chapter(PlexObject):
|
||||||
self.filter = data.attrib.get('filter') # I couldn't filter on it anyways
|
self.filter = data.attrib.get('filter') # I couldn't filter on it anyways
|
||||||
self.tag = data.attrib.get('tag')
|
self.tag = data.attrib.get('tag')
|
||||||
self.title = self.tag
|
self.title = self.tag
|
||||||
|
self.thumb = data.attrib.get('thumb')
|
||||||
self.index = cast(int, data.attrib.get('index'))
|
self.index = cast(int, data.attrib.get('index'))
|
||||||
self.start = cast(int, data.attrib.get('startTimeOffset'))
|
self.start = cast(int, data.attrib.get('startTimeOffset'))
|
||||||
self.end = cast(int, data.attrib.get('endTimeOffset'))
|
self.end = cast(int, data.attrib.get('endTimeOffset'))
|
||||||
|
|
|
@ -40,6 +40,8 @@ class Photoalbum(PlexPartialObject):
|
||||||
self.index = utils.cast(int, data.attrib.get('index'))
|
self.index = utils.cast(int, data.attrib.get('index'))
|
||||||
self.key = data.attrib.get('key')
|
self.key = data.attrib.get('key')
|
||||||
self.librarySectionID = data.attrib.get('librarySectionID')
|
self.librarySectionID = data.attrib.get('librarySectionID')
|
||||||
|
self.librarySectionKey = data.attrib.get('librarySectionKey')
|
||||||
|
self.librarySectionTitle = data.attrib.get('librarySectionTitle')
|
||||||
self.ratingKey = data.attrib.get('ratingKey')
|
self.ratingKey = data.attrib.get('ratingKey')
|
||||||
self.summary = data.attrib.get('summary')
|
self.summary = data.attrib.get('summary')
|
||||||
self.thumb = data.attrib.get('thumb')
|
self.thumb = data.attrib.get('thumb')
|
||||||
|
@ -99,16 +101,32 @@ class Photo(PlexPartialObject):
|
||||||
TYPE = 'photo'
|
TYPE = 'photo'
|
||||||
METADATA_TYPE = 'photo'
|
METADATA_TYPE = 'photo'
|
||||||
|
|
||||||
|
_include = ('?checkFiles=1&includeExtras=1&includeRelated=1'
|
||||||
|
'&includeOnDeck=1&includeChapters=1&includePopularLeaves=1'
|
||||||
|
'&includeMarkers=1&includeConcerts=1&includePreferences=1'
|
||||||
|
'&indcludeBandwidths=1&includeLoudnessRamps=1')
|
||||||
|
|
||||||
def _loadData(self, data):
|
def _loadData(self, data):
|
||||||
""" Load attribute values from Plex XML response. """
|
""" Load attribute values from Plex XML response. """
|
||||||
|
self.key = data.attrib.get('key')
|
||||||
|
self._details_key = self.key + self._include
|
||||||
self.listType = 'photo'
|
self.listType = 'photo'
|
||||||
self.addedAt = utils.toDatetime(data.attrib.get('addedAt'))
|
self.addedAt = utils.toDatetime(data.attrib.get('addedAt'))
|
||||||
|
self.createdAtAccuracy = data.attrib.get('createdAtAccuracy')
|
||||||
|
self.createdAtTZOffset = utils.cast(int, data.attrib.get('createdAtTZOffset'))
|
||||||
|
self.guid = data.attrib.get('guid')
|
||||||
self.index = utils.cast(int, data.attrib.get('index'))
|
self.index = utils.cast(int, data.attrib.get('index'))
|
||||||
self.key = data.attrib.get('key')
|
self.librarySectionID = data.attrib.get('librarySectionID')
|
||||||
|
self.librarySectionKey = data.attrib.get('librarySectionKey')
|
||||||
|
self.librarySectionTitle = data.attrib.get('librarySectionTitle')
|
||||||
self.originallyAvailableAt = utils.toDatetime(
|
self.originallyAvailableAt = utils.toDatetime(
|
||||||
data.attrib.get('originallyAvailableAt'), '%Y-%m-%d')
|
data.attrib.get('originallyAvailableAt'), '%Y-%m-%d')
|
||||||
|
self.parentGuid = data.attrib.get('parentGuid')
|
||||||
|
self.parentIndex = utils.cast(int, data.attrib.get('parentIndex'))
|
||||||
self.parentKey = data.attrib.get('parentKey')
|
self.parentKey = data.attrib.get('parentKey')
|
||||||
self.parentRatingKey = data.attrib.get('parentRatingKey')
|
self.parentRatingKey = data.attrib.get('parentRatingKey')
|
||||||
|
self.parentThumb = data.attrib.get('parentThumb')
|
||||||
|
self.parentTitle = data.attrib.get('parentTitle')
|
||||||
self.ratingKey = data.attrib.get('ratingKey')
|
self.ratingKey = data.attrib.get('ratingKey')
|
||||||
self.summary = data.attrib.get('summary')
|
self.summary = data.attrib.get('summary')
|
||||||
self.thumb = data.attrib.get('thumb')
|
self.thumb = data.attrib.get('thumb')
|
||||||
|
|
|
@ -23,7 +23,8 @@ log = logging.getLogger('plexapi')
|
||||||
# Library Types - Populated at runtime
|
# Library Types - Populated at runtime
|
||||||
SEARCHTYPES = {'movie': 1, 'show': 2, 'season': 3, 'episode': 4, 'trailer': 5, 'comic': 6, 'person': 7,
|
SEARCHTYPES = {'movie': 1, 'show': 2, 'season': 3, 'episode': 4, 'trailer': 5, 'comic': 6, 'person': 7,
|
||||||
'artist': 8, 'album': 9, 'track': 10, 'picture': 11, 'clip': 12, 'photo': 13, 'photoalbum': 14,
|
'artist': 8, 'album': 9, 'track': 10, 'picture': 11, 'clip': 12, 'photo': 13, 'photoalbum': 14,
|
||||||
'playlist': 15, 'playlistFolder': 16, 'collection': 18, 'userPlaylistItem': 1001}
|
'playlist': 15, 'playlistFolder': 16, 'collection': 18,
|
||||||
|
'optimizedVersion': 42, 'userPlaylistItem': 1001}
|
||||||
PLEXOBJECTS = {}
|
PLEXOBJECTS = {}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ class Video(PlexPartialObject):
|
||||||
self.key = data.attrib.get('key', '')
|
self.key = data.attrib.get('key', '')
|
||||||
self.lastViewedAt = utils.toDatetime(data.attrib.get('lastViewedAt'))
|
self.lastViewedAt = utils.toDatetime(data.attrib.get('lastViewedAt'))
|
||||||
self.librarySectionID = data.attrib.get('librarySectionID')
|
self.librarySectionID = data.attrib.get('librarySectionID')
|
||||||
|
self.librarySectionKey = data.attrib.get('librarySectionKey')
|
||||||
|
self.librarySectionTitle = data.attrib.get('librarySectionTitle')
|
||||||
self.ratingKey = utils.cast(int, data.attrib.get('ratingKey'))
|
self.ratingKey = utils.cast(int, data.attrib.get('ratingKey'))
|
||||||
self.summary = data.attrib.get('summary')
|
self.summary = data.attrib.get('summary')
|
||||||
self.thumb = data.attrib.get('thumb')
|
self.thumb = data.attrib.get('thumb')
|
||||||
|
@ -276,7 +278,8 @@ class Movie(Playable, Video):
|
||||||
METADATA_TYPE = 'movie'
|
METADATA_TYPE = 'movie'
|
||||||
_include = ('?checkFiles=1&includeExtras=1&includeRelated=1'
|
_include = ('?checkFiles=1&includeExtras=1&includeRelated=1'
|
||||||
'&includeOnDeck=1&includeChapters=1&includePopularLeaves=1'
|
'&includeOnDeck=1&includeChapters=1&includePopularLeaves=1'
|
||||||
'&includeConcerts=1&includePreferences=1')
|
'&includeConcerts=1&includePreferences=1'
|
||||||
|
'&indcludeBandwidths=1')
|
||||||
|
|
||||||
def _loadData(self, data):
|
def _loadData(self, data):
|
||||||
""" Load attribute values from Plex XML response. """
|
""" Load attribute values from Plex XML response. """
|
||||||
|
@ -415,6 +418,7 @@ class Show(Video):
|
||||||
self.theme = data.attrib.get('theme')
|
self.theme = data.attrib.get('theme')
|
||||||
self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount'))
|
self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount'))
|
||||||
self.year = utils.cast(int, data.attrib.get('year'))
|
self.year = utils.cast(int, data.attrib.get('year'))
|
||||||
|
self.fields = self.findItems(data, media.Field)
|
||||||
self.genres = self.findItems(data, media.Genre)
|
self.genres = self.findItems(data, media.Genre)
|
||||||
self.roles = self.findItems(data, media.Role)
|
self.roles = self.findItems(data, media.Role)
|
||||||
self.labels = self.findItems(data, media.Label)
|
self.labels = self.findItems(data, media.Label)
|
||||||
|
@ -527,12 +531,19 @@ class Season(Video):
|
||||||
Video._loadData(self, data)
|
Video._loadData(self, data)
|
||||||
# fix key if loaded from search
|
# fix key if loaded from search
|
||||||
self.key = self.key.replace('/children', '')
|
self.key = self.key.replace('/children', '')
|
||||||
|
self.art = data.attrib.get('art')
|
||||||
|
self.guid = data.attrib.get('guid')
|
||||||
self.leafCount = utils.cast(int, data.attrib.get('leafCount'))
|
self.leafCount = utils.cast(int, data.attrib.get('leafCount'))
|
||||||
self.index = utils.cast(int, data.attrib.get('index'))
|
self.index = utils.cast(int, data.attrib.get('index'))
|
||||||
|
self.parentGuid = data.attrib.get('parentGuid')
|
||||||
|
self.parentIndex = data.attrib.get('parentIndex')
|
||||||
self.parentKey = data.attrib.get('parentKey')
|
self.parentKey = data.attrib.get('parentKey')
|
||||||
self.parentRatingKey = utils.cast(int, data.attrib.get('parentRatingKey'))
|
self.parentRatingKey = utils.cast(int, data.attrib.get('parentRatingKey'))
|
||||||
|
self.parentTheme = data.attrib.get('parentTheme')
|
||||||
|
self.parentThumb = data.attrib.get('parentThumb')
|
||||||
self.parentTitle = data.attrib.get('parentTitle')
|
self.parentTitle = data.attrib.get('parentTitle')
|
||||||
self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount'))
|
self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount'))
|
||||||
|
self.fields = self.findItems(data, media.Field)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s>' % ':'.join([p for p in [
|
return '<%s>' % ':'.join([p for p in [
|
||||||
|
@ -644,7 +655,8 @@ class Episode(Playable, Video):
|
||||||
|
|
||||||
_include = ('?checkFiles=1&includeExtras=1&includeRelated=1'
|
_include = ('?checkFiles=1&includeExtras=1&includeRelated=1'
|
||||||
'&includeOnDeck=1&includeChapters=1&includePopularLeaves=1'
|
'&includeOnDeck=1&includeChapters=1&includePopularLeaves=1'
|
||||||
'&includeConcerts=1&includePreferences=1')
|
'&includeMarkers=1&includeConcerts=1&includePreferences=1'
|
||||||
|
'&indcludeBandwidths=1')
|
||||||
|
|
||||||
def _loadData(self, data):
|
def _loadData(self, data):
|
||||||
""" Load attribute values from Plex XML response. """
|
""" Load attribute values from Plex XML response. """
|
||||||
|
@ -657,6 +669,7 @@ class Episode(Playable, Video):
|
||||||
self.contentRating = data.attrib.get('contentRating')
|
self.contentRating = data.attrib.get('contentRating')
|
||||||
self.duration = utils.cast(int, data.attrib.get('duration'))
|
self.duration = utils.cast(int, data.attrib.get('duration'))
|
||||||
self.grandparentArt = data.attrib.get('grandparentArt')
|
self.grandparentArt = data.attrib.get('grandparentArt')
|
||||||
|
self.grandparentGuid = data.attrib.get('grandparentGuid')
|
||||||
self.grandparentKey = data.attrib.get('grandparentKey')
|
self.grandparentKey = data.attrib.get('grandparentKey')
|
||||||
self.grandparentRatingKey = utils.cast(int, data.attrib.get('grandparentRatingKey'))
|
self.grandparentRatingKey = utils.cast(int, data.attrib.get('grandparentRatingKey'))
|
||||||
self.grandparentTheme = data.attrib.get('grandparentTheme')
|
self.grandparentTheme = data.attrib.get('grandparentTheme')
|
||||||
|
@ -665,6 +678,7 @@ class Episode(Playable, Video):
|
||||||
self.guid = data.attrib.get('guid')
|
self.guid = data.attrib.get('guid')
|
||||||
self.index = utils.cast(int, data.attrib.get('index'))
|
self.index = utils.cast(int, data.attrib.get('index'))
|
||||||
self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt'), '%Y-%m-%d')
|
self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt'), '%Y-%m-%d')
|
||||||
|
self.parentGuid = data.attrib.get('parentGuid')
|
||||||
self.parentIndex = data.attrib.get('parentIndex')
|
self.parentIndex = data.attrib.get('parentIndex')
|
||||||
self.parentKey = data.attrib.get('parentKey')
|
self.parentKey = data.attrib.get('parentKey')
|
||||||
self.parentRatingKey = utils.cast(int, data.attrib.get('parentRatingKey'))
|
self.parentRatingKey = utils.cast(int, data.attrib.get('parentRatingKey'))
|
||||||
|
@ -675,6 +689,7 @@ class Episode(Playable, Video):
|
||||||
self.viewOffset = utils.cast(int, data.attrib.get('viewOffset', 0))
|
self.viewOffset = utils.cast(int, data.attrib.get('viewOffset', 0))
|
||||||
self.year = utils.cast(int, data.attrib.get('year'))
|
self.year = utils.cast(int, data.attrib.get('year'))
|
||||||
self.directors = self.findItems(data, media.Director)
|
self.directors = self.findItems(data, media.Director)
|
||||||
|
self.fields = self.findItems(data, media.Field)
|
||||||
self.media = self.findItems(data, media.Media)
|
self.media = self.findItems(data, media.Media)
|
||||||
self.writers = self.findItems(data, media.Writer)
|
self.writers = self.findItems(data, media.Writer)
|
||||||
self.labels = self.findItems(data, media.Label)
|
self.labels = self.findItems(data, media.Label)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue