Merge custom plexapi 3.6.0-tautulli

This commit is contained in:
JonnyWong16 2020-08-03 10:24:15 -07:00
parent 056d0d81ac
commit c324cf69ed
No known key found for this signature in database
GPG key ID: B1F1F9807184697A
6 changed files with 175 additions and 14 deletions

View file

@ -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)

View file

@ -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):

View file

@ -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'))

View file

@ -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')

View file

@ -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 = {}

View file

@ -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)