Create Playable object to put function specific to media that is playable like getStreamURL etc..

This commit is contained in:
Michael Shepanski 2016-04-03 23:55:29 -04:00
parent e81f2506e9
commit 50ac2f55e5
4 changed files with 63 additions and 79 deletions

View file

@ -3,10 +3,14 @@
PlexAPI Audio
"""
from plexapi import media, utils
from plexapi.utils import Playable, PlexPartialObject
NA = utils.NA
class Audio(utils.PlexPartialObject):
class Audio(PlexPartialObject):
def __init__(self, server, data, initpath):
super(Audio, self).__init__(data, initpath, server)
def _loadData(self, data):
self.addedAt = utils.toDatetime(data.attrib.get('addedAt', NA))
@ -22,6 +26,13 @@ class Audio(utils.PlexPartialObject):
self.type = data.attrib.get('type', NA)
self.updatedAt = utils.toDatetime(data.attrib.get('updatedAt', NA))
self.viewCount = utils.cast(int, data.attrib.get('viewCount', 0))
@property
def thumbUrl(self):
return self.server.url(self.thumb)
def refresh(self):
self.server.query('%s/refresh' % self.key, method=self.server.session.put)
@utils.register_libtype
@ -32,7 +43,7 @@ class Artist(Audio):
super(Artist, self)._loadData(data)
self.art = data.attrib.get('art', NA)
self.guid = data.attrib.get('guid', NA)
self.key = self.key.replace('/children', '') # plex bug? http://bit.ly/1Sc2J3V
self.key = self.key.replace('/children', '') # FIX_BUG_50
self.location = utils.findLocation(data)
if self.isFullObject():
self.countries = [media.Country(self.server, e) for e in data if e.tag == media.Country.TYPE]
@ -40,31 +51,23 @@ class Artist(Audio):
self.similar = [media.Similar(self.server, e) for e in data if e.tag == media.Similar.TYPE]
def albums(self):
path = '/library/metadata/%s/children' % self.ratingKey
path = '%s/children' % self.key
return utils.listItems(self.server, path, Album.TYPE)
def album(self, title):
path = '/library/metadata/%s/children' % self.ratingKey
path = '%s/children' % self.key
return utils.findItem(self.server, path, title)
def tracks(self, watched=None):
leavesKey = '/library/metadata/%s/allLeaves' % self.ratingKey
return utils.listItems(self.server, leavesKey, watched=watched)
path = '%s/allLeaves' % self.key
return utils.listItems(self.server, path, watched=watched)
def track(self, title):
path = '/library/metadata/%s/allLeaves' % self.ratingKey
path = '%s/allLeaves' % self.key
return utils.findItem(self.server, path, title)
def get(self, title):
return self.track(title)
def isFullObject(self):
# plex bug? http://bit.ly/1Sc2J3V
fixed_key = self.key.replace('/children', '')
return self.initpath == fixed_key
def refresh(self):
self.server.query('/library/metadata/%s/refresh' % self.ratingKey)
@utils.register_libtype
@ -74,7 +77,7 @@ class Album(Audio):
def _loadData(self, data):
super(Album, self)._loadData(data)
self.art = data.attrib.get('art', NA)
self.key = self.key.replace('/children', '') # plex bug? http://bit.ly/1Sc2J3V
self.key = self.key.replace('/children', '') # FIX_BUG_50
self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt', NA), '%Y-%m-%d')
self.parentKey = data.attrib.get('parentKey', NA)
self.parentRatingKey = data.attrib.get('parentRatingKey', NA)
@ -86,20 +89,15 @@ class Album(Audio):
self.genres = [media.Genre(self.server, e) for e in data if e.tag == media.Genre.TYPE]
def tracks(self, watched=None):
childrenKey = '/library/metadata/%s/children' % self.ratingKey
return utils.listItems(self.server, childrenKey, watched=watched)
path = '%s/children' % self.key
return utils.listItems(self.server, path, watched=watched)
def track(self, title):
path = '/library/metadata/%s/children' % self.ratingKey
path = '%s/children' % self.key
return utils.findItem(self.server, path, title)
def get(self, title):
return self.track(title)
def isFullObject(self):
# plex bug? http://bit.ly/1Sc2J3V
fixed_key = self.key.replace('/children', '')
return self.initpath == fixed_key
def artist(self):
return utils.listItems(self.server, self.parentKey)[0]
@ -112,7 +110,7 @@ class Album(Audio):
@utils.register_libtype
class Track(Audio):
class Track(Audio, Playable):
TYPE = 'track'
def _loadData(self, data):
@ -154,6 +152,3 @@ class Track(Audio):
def artist(self):
return utils.listItems(self.server, self.grandparentKey)[0]
def getStreamURL(self, **params):
return self._getStreamURL(**params)

View file

@ -4,20 +4,24 @@ PlexPlaylist
"""
from plexapi import utils
from plexapi.utils import cast, toDatetime
from plexapi.utils import PlexPartialObject
NA = utils.NA
@utils.register_libtype
class Playlist(utils.PlexPartialObject):
class Playlist(PlexPartialObject):
TYPE = 'playlist'
def __init__(self, server, data, initpath):
super(Playlist, self).__init__(data, initpath, server)
def _loadData(self, data):
self.addedAt = toDatetime(data.attrib.get('addedAt', NA))
self.composite = data.attrib.get('composite', NA) # url to thumbnail
self.duration = cast(int, data.attrib.get('duration', NA))
self.durationInSeconds = cast(int, data.attrib.get('durationInSeconds', NA))
self.guid = data.attrib.get('guid', NA)
self.key = data.attrib.get('key', NA).replace('/items', '') # plex bug? http://bit.ly/1Sc2J3V
self.key = data.attrib.get('key', NA).replace('/items', '') # FIX_BUG_50
self.leafCount = cast(int, data.attrib.get('leafCount', NA))
self.playlistType = data.attrib.get('playlistType', NA)
self.ratingKey = data.attrib.get('ratingKey', NA)
@ -30,8 +34,3 @@ class Playlist(utils.PlexPartialObject):
def items(self):
path = '%s/items' % self.key
return utils.listItems(self.server, path)
def isFullObject(self):
# plex bug? http://bit.ly/1Sc2J3V
fixed_key = self.key.replace('/items', '')
return self.initpath == fixed_key

View file

@ -38,8 +38,8 @@ NA = _NA()
# you request is None it will fetch the full object automatically and update itself.
class PlexPartialObject(object):
def __init__(self, server, data, initpath):
self.server = server # TODO: This should not be needed here..
def __init__(self, data, initpath, server=None):
self.server = server
self.initpath = initpath
self._loadData(data)
@ -62,13 +62,25 @@ class PlexPartialObject(object):
if value != NA:
super(PlexPartialObject, self).__setattr__(attr, value)
# TODO: This shouldn't be here, move downstream
@property
def thumbUrl(self):
return self.server.url(self.thumb)
# TODO: Move to Playable()
def _getStreamURL(self, **params):
def _loadData(self, data):
raise Exception('Abstract method not implemented.')
def isFullObject(self):
return self.initpath == self.key
def isPartialObject(self):
return not self.isFullObject()
def reload(self):
""" Reload the data for this object from PlexServer XML. """
data = self.server.query(self.key)
self.initpath = self.key
self._loadData(data[0])
class Playable(object):
def getStreamURL(self, **params):
if self.TYPE not in ('movie', 'episode', 'track'):
raise Unsupported('Fetching stream URL for %s is unsupported.' % self.TYPE)
mvb = params.get('maxVideoBitrate')
@ -86,36 +98,15 @@ class PlexPartialObject(object):
params = {k:v for k,v in params.items() if v is not None} # remove None values
streamtype = 'audio' if self.TYPE in ('track', 'album') else 'video'
return self.server.url('/%s/:/transcode/universal/start.m3u8?%s' % (streamtype, urlencode(params)))
def _loadData(self, data):
raise Exception('Abstract method not implemented.')
def isFullObject(self):
return self.initpath == self.key
def isPartialObject(self):
return not self.isFullObject()
# TODO: Move to Playable()
def iterParts(self):
for item in self.media:
for part in item.parts:
yield part
# TODO: Move to Playable()
def play(self, client):
client.playMedia(self)
# TODO: This shouldn't be here, move downstream
def refresh(self):
self.server.query('%s/refresh' % self.key, method=put)
def reload(self):
""" Reload the data for this object from PlexServer XML. """
data = self.server.query(self.key)
self.initpath = self.key
self._loadData(data[0])
def buildItem(server, elem, initpath, bytag=False):
libtype = elem.tag if bytag else elem.attrib.get('type')

View file

@ -3,12 +3,16 @@
PlexVideo
"""
from plexapi import media, utils
from plexapi.utils import Playable, PlexPartialObject
NA = utils.NA
class Video(utils.PlexPartialObject):
class Video(PlexPartialObject):
TYPE = None
def __init__(self, server, data, initpath):
super(Video, self).__init__(data, initpath, server)
def _loadData(self, data):
self.addedAt = utils.toDatetime(data.attrib.get('addedAt', NA))
self.key = data.attrib.get('key', NA)
@ -23,6 +27,10 @@ class Video(utils.PlexPartialObject):
self.updatedAt = utils.toDatetime(data.attrib.get('updatedAt', NA))
self.viewCount = utils.cast(int, data.attrib.get('viewCount', 0))
@property
def thumbUrl(self):
return self.server.url(self.thumb)
def analyze(self):
""" The primary purpose of media analysis is to gather information about that media
item. All of the media you add to a Library has properties that are useful to
@ -40,15 +48,12 @@ class Video(utils.PlexPartialObject):
self.server.query(path)
self.reload()
def play(self, client):
client.playMedia(self)
def refresh(self):
self.server.query('%s/refresh' % self.key, method=self.server.session.put)
@utils.register_libtype
class Movie(Video):
class Movie(Video, Playable):
TYPE = 'movie'
def _loadData(self, data):
@ -95,9 +100,6 @@ class Movie(Video):
@property
def isWatched(self):
return bool(self.viewCount > 0)
def getStreamURL(self, **params):
return self._getStreamURL(**params)
@utils.register_libtype
@ -198,7 +200,7 @@ class Season(Video):
@utils.register_libtype
class Episode(Video):
class Episode(Video, Playable):
TYPE = 'episode'
def _loadData(self, data):
@ -242,9 +244,6 @@ class Episode(Video):
@property
def thumbUrl(self):
return self.server.url(self.grandparentThumb)
def getStreamURL(self, **params):
return self._getStreamURL(videoResolution='800x600', **params)
def season(self):
return utils.listItems(self.server, self.parentKey)[0]