Merge pull request #258 from pkkid/chap

Chap
This commit is contained in:
Hellowlol 2018-04-03 01:53:54 +02:00 committed by GitHub
commit b401ef3cc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 12 deletions

View file

@ -43,6 +43,7 @@ class PlexObject(object):
self._server = server
self._data = data
self._initpath = initpath or self.key
self._details_key = ''
if data is not None:
self._loadData(data)
@ -182,7 +183,7 @@ class PlexObject(object):
def reload(self, key=None):
""" Reload the data for this object from self.key. """
key = key or self.key
key = key or self._details_key or self.key
if not key:
raise Unsupported('Cannot reload an object not built from a URL.')
self._initpath = key
@ -275,7 +276,7 @@ class PlexPartialObject(PlexObject):
if attr == 'key' or attr.startswith('_'): return value
if value not in (None, []): return value
if self.isFullObject(): return value
# Log warning that were reloading the object
# Log the reload.
clsname = self.__class__.__name__
title = self.__dict__.get('title', self.__dict__.get('name'))
objname = "%s '%s'" % (clsname, title) if title else clsname
@ -448,6 +449,14 @@ class Playable(object):
self.viewedAt = utils.toDatetime(data.attrib.get('viewedAt')) # history
self.playlistItemID = utils.cast(int, data.attrib.get('playlistItemID')) # playlist
def isFullObject(self):
""" Retruns True if this is already a full object. A full object means all attributes
were populated from the api path representing only this item. For example, the
search result for a movie often only contain a portion of the attributes a full
object (main url) for that movie contain.
"""
return self._details_key == self._initpath or not self.key
def getStreamURL(self, **params):
""" Returns a stream url that may be used by external applications such as VLC.

View file

@ -469,6 +469,26 @@ class Writer(MediaTag):
FILTER = 'writer'
@utils.registerPlexObject
class Chapter(PlexObject):
""" Represents a single Writer media tag.
Attributes:
TAG (str): 'Chapter'
"""
TAG = 'Chapter'
def _loadData(self, data):
self._data = data
self.id = cast(int, data.attrib.get('id', 0))
self.filter = data.attrib.get('filter') # I couldn't filter on it anyways
self.tag = data.attrib.get('tag')
self.title = self.tag
self.index = cast(int, data.attrib.get('index'))
self.start = cast(int, data.attrib.get('startTimeOffset'))
self.end = cast(int, data.attrib.get('endTimeOffset'))
@utils.registerPlexObject
class Field(PlexObject):
""" Represents a single Field.

View file

@ -512,11 +512,12 @@ class MyPlexServerShare(PlexObject):
class MyPlexResource(PlexObject):
""" This object represents resources connected to your Plex server that can provide
content such as Plex Media Servers, iPhone or Android clients, etc. The raw xml
for the data presented here can be found at: https://plex.tv/api/resources?includeHttps=1
for the data presented here can be found at:
https://plex.tv/api/resources?includeHttps=1&includeRelay=1
Attributes:
TAG (str): 'Device'
key (str): 'https://plex.tv/api/resources?includeHttps=1'
key (str): 'https://plex.tv/api/resources?includeHttps=1&includeRelay=1'
accessToken (str): This resources accesstoken.
clientIdentifier (str): Unique ID for this resource.
connections (list): List of :class:`~myplex.ResourceConnection` objects
@ -537,7 +538,7 @@ class MyPlexResource(PlexObject):
synced (bool): Unknown (possibly True if the resource has synced content?)
"""
TAG = 'Device'
key = 'https://plex.tv/api/resources?includeHttps=1'
key = 'https://plex.tv/api/resources?includeHttps=1&includeRelay=1'
def _loadData(self, data):
self._data = data
@ -557,6 +558,11 @@ class MyPlexResource(PlexObject):
self.synced = utils.cast(bool, data.attrib.get('synced'))
self.presence = utils.cast(bool, data.attrib.get('presence'))
self.connections = self.findItems(data, ResourceConnection)
self.publicAddressMatches = utils.cast(bool, data.attrib.get('publicAddressMatches'))
# This seems to only be available if its not your device (say are shared server)
self.httpsRequired = utils.cast(bool, data.attrib.get('httpsRequired'))
self.ownerid = utils.cast(int, data.attrib.get('ownerId', 0))
self.sourceTitle = data.attrib.get('sourceTitle') # owners plex username.
def connect(self, ssl=None, timeout=None):
""" Returns a new :class:`~server.PlexServer` or :class:`~client.PlexClient` object.
@ -615,6 +621,7 @@ class ResourceConnection(PlexObject):
self.uri = data.attrib.get('uri')
self.local = utils.cast(bool, data.attrib.get('local'))
self.httpuri = 'http://%s:%s' % (self.address, self.port)
self.relay = utils.cast(bool, data.attrib.get('relay'))
class MyPlexDevice(PlexObject):

View file

@ -30,7 +30,7 @@ class Video(PlexPartialObject):
self._data = data
self.listType = 'video'
self.addedAt = utils.toDatetime(data.attrib.get('addedAt'))
self.key = data.attrib.get('key')
self.key = data.attrib.get('key', '')
self.lastViewedAt = utils.toDatetime(data.attrib.get('lastViewedAt'))
self.librarySectionID = data.attrib.get('librarySectionID')
self.ratingKey = utils.cast(int, data.attrib.get('ratingKey'))
@ -79,11 +79,11 @@ class Video(PlexPartialObject):
@utils.registerPlexObject
class Movie(Video, Playable):
class Movie(Playable, Video):
""" Represents a single Movie.
Attributes:
TAG (str): 'Diectory'
TAG (str): 'Video'
TYPE (str): 'movie'
art (str): Key to movie artwork (/library/metadata/<ratingkey>/art/<artid>)
audienceRating (float): Audience rating (usually from Rotten Tomatoes).
@ -111,14 +111,21 @@ class Movie(Video, Playable):
producers (List<:class:`~plexapi.media.Producer`>): List of producers objects.
roles (List<:class:`~plexapi.media.Role`>): List of role objects.
writers (List<:class:`~plexapi.media.Writer`>): List of writers objects.
chapters (List<:class:`~plexapi.media.Chapter`>): List of Chapter objects.
similar (List<:class:`~plexapi.media.Similar`>): List of Similar objects.
"""
TAG = 'Video'
TYPE = 'movie'
_include = ('?checkFiles=1&includeExtras=1&includeRelated=1'
'&includeOnDeck=1&includeChapters=1&includePopularLeaves=1'
'&includeConcerts=1&includePreferences=1')
def _loadData(self, data):
""" Load attribute values from Plex XML response. """
Video._loadData(self, data)
Playable._loadData(self, data)
self._details_key = self.key + self._include
self.art = data.attrib.get('art')
self.audienceRating = utils.cast(float, data.attrib.get('audienceRating'))
self.audienceRatingImage = data.attrib.get('audienceRatingImage')
@ -147,6 +154,8 @@ class Movie(Video, Playable):
self.roles = self.findItems(data, media.Role)
self.writers = self.findItems(data, media.Writer)
self.labels = self.findItems(data, media.Label)
self.chapters = self.findItems(data, media.Chapter)
self.similar = self.findItems(data, media.Similar)
@property
def actors(self):
@ -204,7 +213,7 @@ class Show(Video):
""" Represents a single Show (including all seasons and episodes).
Attributes:
TAG (str): 'Diectory'
TAG (str): 'Directory'
TYPE (str): 'show'
art (str): Key to show artwork (/library/metadata/<ratingkey>/art/<artid>)
banner (str): Key to banner artwork (/library/metadata/<ratingkey>/art/<artid>)
@ -223,6 +232,7 @@ class Show(Video):
year (int): Year the show was released.
genres (List<:class:`~plexapi.media.Genre`>): List of genre objects.
roles (List<:class:`~plexapi.media.Role`>): List of role objects.
similar (List<:class:`~plexapi.media.Similar`>): List of Similar objects.
"""
TAG = 'Directory'
TYPE = 'show'
@ -255,6 +265,7 @@ class Show(Video):
self.genres = self.findItems(data, media.Genre)
self.roles = self.findItems(data, media.Role)
self.labels = self.findItems(data, media.Label)
self.similar = self.findItems(data, media.Similar)
@property
def actors(self):
@ -341,7 +352,7 @@ class Season(Video):
""" Represents a single Show Season (including all episodes).
Attributes:
TAG (str): 'Diectory'
TAG (str): 'Directory'
TYPE (str): 'season'
leafCount (int): Number of episodes in season.
index (int): Season number.
@ -437,11 +448,11 @@ class Season(Video):
@utils.registerPlexObject
class Episode(Video, Playable):
class Episode(Playable, Video):
""" Represents a single Shows Episode.
Attributes:
TAG (str): 'Diectory'
TAG (str): 'Video'
TYPE (str): 'episode'
art (str): Key to episode artwork (/library/metadata/<ratingkey>/art/<artid>)
chapterSource (str): Unknown (media).
@ -471,11 +482,15 @@ class Episode(Video, Playable):
"""
TAG = 'Video'
TYPE = 'episode'
_include = ('?checkFiles=1&includeExtras=1&includeRelated=1'
'&includeOnDeck=1&includeChapters=1&includePopularLeaves=1'
'&includeConcerts=1&includePreferences=1')
def _loadData(self, data):
""" Load attribute values from Plex XML response. """
Video._loadData(self, data)
Playable._loadData(self, data)
self._details_key = self.key + self._include
self._seasonNumber = None # cached season number
self.art = data.attrib.get('art')
self.chapterSource = data.attrib.get('chapterSource')
@ -504,6 +519,7 @@ class Episode(Video, Playable):
self.writers = self.findItems(data, media.Writer)
self.labels = self.findItems(data, media.Label)
self.collections = self.findItems(data, media.Collection)
self.chapters = self.findItems(data, media.Chapter)
def __repr__(self):
return '<%s>' % ':'.join([p for p in [