python-plexapi/plexapi/video.py

258 lines
11 KiB
Python
Raw Normal View History

2014-12-29 03:21:58 +00:00
"""
PlexVideo
"""
import re
from requests import put
from plexapi import media, utils
2015-02-17 20:35:17 +00:00
from plexapi.client import Client
from plexapi.myplex import MyPlexUser
from plexapi.exceptions import Unsupported
try:
from urllib import urlencode # Python2
except ImportError:
from urllib.parse import urlencode # Python3
NA = utils.NA
2014-12-29 03:21:58 +00:00
class Video(utils.PlexPartialObject):
2014-12-29 03:21:58 +00:00
TYPE = None
def _loadData(self, data):
self.type = data.attrib.get('type', NA)
self.key = data.attrib.get('key', NA)
2015-02-17 20:35:17 +00:00
self.librarySectionID = data.attrib.get('librarySectionID', NA)
2014-12-29 03:21:58 +00:00
self.ratingKey = data.attrib.get('ratingKey', NA)
self.title = data.attrib.get('title', NA)
2016-01-19 20:38:08 +00:00
self.originalTitle = data.attrib.get('originalTitle', NA)
2014-12-29 03:21:58 +00:00
self.summary = data.attrib.get('summary', NA)
self.art = data.attrib.get('art', NA)
self.thumb = data.attrib.get('thumb', NA)
self.addedAt = utils.toDatetime(data.attrib.get('addedAt', NA))
self.updatedAt = utils.toDatetime(data.attrib.get('updatedAt', NA))
self.lastViewedAt = utils.toDatetime(data.attrib.get('lastViewedAt', NA))
self.sessionKey = utils.cast(int, data.attrib.get('sessionKey', NA))
2015-02-17 20:35:17 +00:00
self.user = self._find_user(data) # for active sessions
self.player = self._find_player(data) # for active sessions
self.transcodeSession = self._find_transcodeSession(data)
2014-12-29 03:21:58 +00:00
if self.isFullObject():
# These are auto-populated when requested
self.media = [media.Media(self.server, elem, self.initpath, self) for elem in data if elem.tag == media.Media.TYPE]
self.countries = [media.Country(self.server, elem) for elem in data if elem.tag == media.Country.TYPE]
self.directors = [media.Director(self.server, elem) for elem in data if elem.tag == media.Director.TYPE]
self.genres = [media.Genre(self.server, elem) for elem in data if elem.tag == media.Genre.TYPE]
self.producers = [media.Producer(self.server, elem) for elem in data if elem.tag == media.Producer.TYPE]
self.actors = [media.Actor(self.server, elem) for elem in data if elem.tag == media.Actor.TYPE]
self.writers = [media.Writer(self.server, elem) for elem in data if elem.tag == media.Writer.TYPE]
2014-12-29 03:21:58 +00:00
2015-02-24 03:42:29 +00:00
@property
def thumbUrl(self):
return self.server.url(self.thumb)
2015-02-17 20:35:17 +00:00
def _find_user(self, data):
elem = data.find('User')
if elem is not None:
return MyPlexUser(elem, self.initpath)
return None
def _find_player(self, data):
elem = data.find('Player')
if elem is not None:
return Client(self.server, elem)
return None
def _find_transcodeSession(self, data):
elem = data.find('TranscodeSession')
if elem is not None:
return media.TranscodeSession(self.server, elem)
return None
2014-12-29 03:21:58 +00:00
def iter_parts(self):
for item in self.media:
for part in item.parts:
2014-12-29 03:21:58 +00:00
yield part
def analyze(self):
self.server.query('/%s/analyze' % self.key)
2015-06-04 04:00:37 +00:00
def getStreamUrl(self, offset=0, maxVideoBitrate=None, videoResolution=None, **kwargs):
""" Fetch URL to stream video directly.
offset: Start time (in seconds) video will initiate from (ex: 300).
maxVideoBitrate: Max bitrate video and audio stream (ex: 64).
videoResolution: Max resolution of a video stream (ex: 1280x720).
params: Dict of additional parameters to include in URL.
"""
if self.TYPE not in [Movie.TYPE, Episode.TYPE]:
raise Unsupported('Cannot get stream URL for %s.' % self.TYPE)
2015-06-04 04:00:37 +00:00
params = {}
2015-06-08 16:41:47 +00:00
params['path'] = self.key
2015-06-04 04:00:37 +00:00
params['offset'] = offset
params['copyts'] = kwargs.get('copyts', 1)
params['mediaIndex'] = kwargs.get('mediaIndex', 0)
params['X-Plex-Platform'] = kwargs.get('platform', 'Chrome')
if 'protocol' in kwargs:
params['protocol'] = kwargs['protocol']
2015-06-04 04:00:37 +00:00
if maxVideoBitrate:
params['maxVideoBitrate'] = max(maxVideoBitrate, 64)
if videoResolution and re.match('^\d+x\d+$', videoResolution):
params['videoResolution'] = videoResolution
2015-10-02 13:18:44 +00:00
return self.server.url('/video/:/transcode/universal/start.m3u8?%s' % urlencode(params))
2015-06-04 04:00:37 +00:00
2014-12-29 03:21:58 +00:00
def markWatched(self):
path = '/:/scrobble?key=%s&identifier=com.plexapp.plugins.library' % self.ratingKey
self.server.query(path)
self.reload()
def markUnwatched(self):
path = '/:/unscrobble?key=%s&identifier=com.plexapp.plugins.library' % self.ratingKey
self.server.query(path)
self.reload()
def play(self, client):
client.playMedia(self)
def refresh(self):
self.server.query('%s/refresh' % self.key, method=put)
2014-12-29 03:21:58 +00:00
@utils.register_libtype
2014-12-29 03:21:58 +00:00
class Movie(Video):
TYPE = 'movie'
def _loadData(self, data):
super(Movie, self)._loadData(data)
self.studio = data.attrib.get('studio', NA)
self.contentRating = data.attrib.get('contentRating', NA)
self.rating = data.attrib.get('rating', NA)
self.viewCount = utils.cast(int, data.attrib.get('viewCount', 0))
self.viewOffset = utils.cast(int, data.attrib.get('viewOffset', 0))
self.year = utils.cast(int, data.attrib.get('year', NA))
2015-02-17 20:35:17 +00:00
self.summary = data.attrib.get('summary', NA)
2014-12-29 03:21:58 +00:00
self.tagline = data.attrib.get('tagline', NA)
self.duration = utils.cast(int, data.attrib.get('duration', NA))
self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt', NA), '%Y-%m-%d')
2014-12-29 03:21:58 +00:00
self.primaryExtraKey = data.attrib.get('primaryExtraKey', NA)
self.is_watched = bool(self.viewCount > 0) # custom attr
2014-12-29 03:21:58 +00:00
@utils.register_libtype
2014-12-29 03:21:58 +00:00
class Show(Video):
TYPE = 'show'
2015-02-24 03:42:29 +00:00
2014-12-29 03:21:58 +00:00
def _loadData(self, data):
super(Show, self)._loadData(data)
self.studio = data.attrib.get('studio', NA)
self.contentRating = data.attrib.get('contentRating', NA)
self.rating = data.attrib.get('rating', NA)
self.year = utils.cast(int, data.attrib.get('year', NA))
2014-12-29 03:21:58 +00:00
self.banner = data.attrib.get('banner', NA)
self.theme = data.attrib.get('theme', NA)
self.duration = utils.cast(int, data.attrib.get('duration', NA))
self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt', NA), '%Y-%m-%d')
self.leafCount = utils.cast(int, data.attrib.get('leafCount', NA))
self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount', NA))
self.childCount = utils.cast(int, data.attrib.get('childCount', NA))
2014-12-29 03:21:58 +00:00
def seasons(self):
path = '/library/metadata/%s/children' % self.ratingKey
return utils.list_items(self.server, path, Season.TYPE)
2014-12-29 03:21:58 +00:00
def season(self, title):
path = '/library/metadata/%s/children' % self.ratingKey
return utils.find_item(self.server, path, title)
2014-12-29 03:21:58 +00:00
def episodes(self, watched=None):
2014-12-29 03:21:58 +00:00
leavesKey = '/library/metadata/%s/allLeaves' % self.ratingKey
return utils.list_items(self.server, leavesKey, watched=watched)
2014-12-29 03:21:58 +00:00
def episode(self, title):
path = '/library/metadata/%s/allLeaves' % self.ratingKey
return utils.find_item(self.server, path, title)
2014-12-29 03:21:58 +00:00
def watched(self):
return self.episodes(watched=True)
def unwatched(self):
return self.episodes(watched=False)
2014-12-29 03:21:58 +00:00
def get(self, title):
return self.episode(title)
def refresh(self):
self.server.query('/library/metadata/%s/refresh' % self.ratingKey)
2014-12-29 03:21:58 +00:00
@utils.register_libtype
2014-12-29 03:21:58 +00:00
class Season(Video):
TYPE = 'season'
def _loadData(self, data):
super(Season, self)._loadData(data)
self.librarySectionID = data.attrib.get('librarySectionID', NA)
self.librarySectionTitle = data.attrib.get('librarySectionTitle', NA)
self.parentRatingKey = data.attrib.get('parentRatingKey', NA)
self.parentKey = data.attrib.get('parentKey', NA)
self.parentTitle = data.attrib.get('parentTitle', NA)
self.parentSummary = data.attrib.get('parentSummary', NA)
self.index = data.attrib.get('index', NA)
self.parentIndex = data.attrib.get('parentIndex', NA)
self.parentThumb = data.attrib.get('parentThumb', NA)
self.parentTheme = data.attrib.get('parentTheme', NA)
self.leafCount = utils.cast(int, data.attrib.get('leafCount', NA))
self.viewedLeafCount = utils.cast(int, data.attrib.get('viewedLeafCount', NA))
2014-12-29 03:21:58 +00:00
def episodes(self, watched=None):
2014-12-29 03:21:58 +00:00
childrenKey = '/library/metadata/%s/children' % self.ratingKey
return utils.list_items(self.server, childrenKey, watched=watched)
2014-12-29 03:21:58 +00:00
def episode(self, title):
path = '/library/metadata/%s/children' % self.ratingKey
return utils.find_item(self.server, path, title)
2014-12-29 03:21:58 +00:00
def get(self, title):
return self.episode(title)
def show(self):
return utils.list_items(self.server, self.parentKey)[0]
2014-12-29 03:21:58 +00:00
def watched(self):
return self.episodes(watched=True)
def unwatched(self):
return self.episodes(watched=False)
2014-12-29 03:21:58 +00:00
@utils.register_libtype
2014-12-29 03:21:58 +00:00
class Episode(Video):
TYPE = 'episode'
def _loadData(self, data):
super(Episode, self)._loadData(data)
self.librarySectionID = data.attrib.get('librarySectionID', NA)
self.librarySectionTitle = data.attrib.get('librarySectionTitle', NA)
self.grandparentKey = data.attrib.get('grandparentKey', NA)
self.grandparentTitle = data.attrib.get('grandparentTitle', NA)
self.grandparentThumb = data.attrib.get('grandparentThumb', NA)
self.parentKey = data.attrib.get('parentKey', NA)
self.parentIndex = data.attrib.get('parentIndex', NA)
self.parentThumb = data.attrib.get('parentThumb', NA)
self.contentRating = data.attrib.get('contentRating', NA)
self.index = data.attrib.get('index', NA)
self.rating = data.attrib.get('rating', NA)
self.viewCount = utils.cast(int, data.attrib.get('viewCount', 0))
self.viewOffset = utils.cast(int, data.attrib.get('viewOffset', 0))
self.year = utils.cast(int, data.attrib.get('year', NA))
self.duration = utils.cast(int, data.attrib.get('duration', NA))
self.originallyAvailableAt = utils.toDatetime(data.attrib.get('originallyAvailableAt', NA), '%Y-%m-%d')
self.is_watched = bool(self.viewCount > 0) # custom attr
2014-12-29 03:21:58 +00:00
2015-02-24 03:42:29 +00:00
@property
def thumbUrl(self):
return self.server.url(self.grandparentThumb)
2014-12-29 03:21:58 +00:00
def season(self):
return utils.list_items(self.server, self.parentKey)[0]
2014-12-29 03:21:58 +00:00
def show(self):
return utils.list_items(self.server, self.grandparentKey)[0]