python-plexapi/plexapi/video.py

413 lines
15 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
2016-12-16 23:38:08 +00:00
from plexapi import media, utils
from plexapi.utils import Playable, PlexPartialObject
2017-01-02 21:06:40 +00:00
NA = utils.NA
2014-12-29 03:21:58 +00:00
class Video(PlexPartialObject):
2014-12-29 03:21:58 +00:00
TYPE = None
def __init__(self, server, data, initpath):
2017-01-02 21:06:40 +00:00
"""Default class for all video types.
2016-12-16 23:38:08 +00:00
Args:
server (Plexserver): The PMS server your connected to
data (Element): Element built from server.query
2017-01-02 21:06:40 +00:00
initpath (str): Relativ path fx /library/sections/1/all
2016-12-16 23:38:08 +00:00
"""
super(Video, self).__init__(data, initpath, server)
2014-12-29 03:21:58 +00:00
def _loadData(self, data):
2016-12-16 23:38:08 +00:00
"""Used to set the attributes
2017-01-02 21:06:40 +00:00
2016-12-16 23:38:08 +00:00
Args:
data (Element): Usually built from server.query
"""
self.listType = 'video'
self.addedAt = utils.toDatetime(data.attrib.get('addedAt', NA))
2014-12-29 03:21:58 +00:00
self.key = data.attrib.get('key', NA)
2016-12-16 23:38:08 +00:00
self.lastViewedAt = utils.toDatetime(
data.attrib.get('lastViewedAt', NA))
2015-02-17 20:35:17 +00:00
self.librarySectionID = data.attrib.get('librarySectionID', NA)
2016-12-16 23:38:08 +00:00
self.ratingKey = utils.cast(int, data.attrib.get('ratingKey', NA))
2014-12-29 03:21:58 +00:00
self.summary = data.attrib.get('summary', NA)
self.thumb = data.attrib.get('thumb', NA)
self.title = data.attrib.get('title', NA)
self.titleSort = data.attrib.get('titleSort', self.title)
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))
2014-12-29 03:21:58 +00:00
@property
def thumbUrl(self):
2017-01-02 21:06:40 +00:00
"""Return url to thumb image."""
2017-01-02 21:19:07 +00:00
if self.thumb:
return self.server.url(self.thumb)
2014-12-29 03:21:58 +00:00
def analyze(self):
2016-12-16 23:38:08 +00:00
"""The primary purpose of media analysis is to gather information about
that mediaitem. All of the media you add to a Library has properties
that are useful to knowwhether it's a video file,
a music track, or one of your photos.
"""
2014-12-29 03:21:58 +00:00
self.server.query('/%s/analyze' % self.key)
def markWatched(self):
2017-01-02 21:06:40 +00:00
"""Mark a items as watched."""
2014-12-29 03:21:58 +00:00
path = '/:/scrobble?key=%s&identifier=com.plexapp.plugins.library' % self.ratingKey
self.server.query(path)
self.reload()
def markUnwatched(self):
2017-01-02 21:06:40 +00:00
"""Mark a item as unwatched."""
2014-12-29 03:21:58 +00:00
path = '/:/unscrobble?key=%s&identifier=com.plexapp.plugins.library' % self.ratingKey
self.server.query(path)
self.reload()
def refresh(self):
2017-01-02 21:06:40 +00:00
"""Refresh a item."""
2016-12-16 23:38:08 +00:00
self.server.query('%s/refresh' %
self.key, method=self.server.session.put)
def section(self):
2017-01-02 21:06:40 +00:00
"""Library section."""
return self.server.library.sectionByID(self.librarySectionID)
2014-12-29 03:21:58 +00:00
@utils.register_libtype
class Movie(Video, Playable):
2014-12-29 03:21:58 +00:00
TYPE = 'movie'
def _loadData(self, data):
2016-12-16 23:38:08 +00:00
"""Used to set the attributes
2017-01-02 21:06:40 +00:00
2016-12-16 23:38:08 +00:00
Args:
2017-01-02 21:06:40 +00:00
data (Element): XML reponse from PMS as Element
normally built from server.query
2016-12-16 23:38:08 +00:00
"""
Video._loadData(self, data)
Playable._loadData(self, data)
self.art = data.attrib.get('art', NA)
2016-12-16 23:38:08 +00:00
self.audienceRating = utils.cast(
float, data.attrib.get('audienceRating', NA))
self.audienceRatingImage = data.attrib.get('audienceRatingImage', NA)
self.chapterSource = data.attrib.get('chapterSource', NA)
2014-12-29 03:21:58 +00:00
self.contentRating = data.attrib.get('contentRating', NA)
self.duration = utils.cast(int, data.attrib.get('duration', NA))
self.guid = data.attrib.get('guid', NA)
self.originalTitle = data.attrib.get('originalTitle', NA)
2016-12-16 23:38:08 +00:00
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.rating = data.attrib.get('rating', NA)
self.ratingImage = data.attrib.get('ratingImage', NA)
self.studio = data.attrib.get('studio', NA)
self.tagline = data.attrib.get('tagline', NA)
self.userRating = utils.cast(float, data.attrib.get('userRating', NA))
self.viewOffset = utils.cast(int, data.attrib.get('viewOffset', 0))
self.year = utils.cast(int, data.attrib.get('year', NA))
2016-12-16 23:38:08 +00:00
if self.isFullObject(): # check this
self.collections = [media.Collection(
self.server, e) for e in data if e.tag == media.Collection.TYPE]
self.countries = [media.Country(self.server, e)
for e in data if e.tag == media.Country.TYPE]
self.directors = [media.Director(
self.server, e) for e in data if e.tag == media.Director.TYPE]
self.genres = [media.Genre(self.server, e)
for e in data if e.tag == media.Genre.TYPE]
self.media = [media.Media(self.server, e, self.initpath, self)
for e in data if e.tag == media.Media.TYPE]
self.producers = [media.Producer(
self.server, e) for e in data if e.tag == media.Producer.TYPE]
self.roles = [media.Role(self.server, e)
for e in data if e.tag == media.Role.TYPE]
self.writers = [media.Writer(self.server, e)
for e in data if e.tag == media.Writer.TYPE]
self.fields = [media.Field(e)
for e in data if e.tag == media.Field.TYPE]
self.videoStreams = utils.findStreams(self.media, 'videostream')
self.audioStreams = utils.findStreams(self.media, 'audiostream')
2016-12-16 23:38:08 +00:00
self.subtitleStreams = utils.findStreams(
self.media, 'subtitlestream')
@property
def actors(self):
return self.roles
2016-12-16 23:38:08 +00:00
@property
def isWatched(self):
return bool(self.viewCount > 0)
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):
2016-12-16 23:38:08 +00:00
"""Used to set the attributes
2017-01-02 21:06:40 +00:00
2016-12-16 23:38:08 +00:00
Args:
data (Element): Usually built from server.query
"""
Video._loadData(self, data)
self.art = data.attrib.get('art', NA)
2014-12-29 03:21:58 +00:00
self.banner = data.attrib.get('banner', NA)
self.childCount = utils.cast(int, data.attrib.get('childCount', NA))
self.contentRating = data.attrib.get('contentRating', NA)
self.duration = utils.cast(int, data.attrib.get('duration', NA))
self.guid = data.attrib.get('guid', NA)
self.index = data.attrib.get('index', NA)
self.leafCount = utils.cast(int, data.attrib.get('leafCount', NA))
self.location = utils.findLocations(data, single=True)
2016-12-16 23:38:08 +00:00
self.originallyAvailableAt = utils.toDatetime(
data.attrib.get('originallyAvailableAt', NA), '%Y-%m-%d')
self.rating = utils.cast(float, data.attrib.get('rating', NA))
self.studio = data.attrib.get('studio', NA)
self.theme = data.attrib.get('theme', NA)
2016-12-16 23:38:08 +00:00
self.viewedLeafCount = utils.cast(
int, data.attrib.get('viewedLeafCount', NA))
self.year = utils.cast(int, data.attrib.get('year', NA))
2017-01-02 21:19:07 +00:00
#if self.isFullObject(): # will be fixed with docs.
self.genres = [media.Genre(self.server, e)
for e in data if e.tag == media.Genre.TYPE]
self.roles = [media.Role(self.server, e)
for e in data if e.tag == media.Role.TYPE]
@property
def actors(self):
return self.roles
2016-12-16 23:38:08 +00:00
@property
def isWatched(self):
return bool(self.viewedLeafCount == self.leafCount)
2014-12-29 03:21:58 +00:00
def seasons(self):
2017-01-02 21:06:40 +00:00
"""Returns a list of Season."""
2014-12-29 03:21:58 +00:00
path = '/library/metadata/%s/children' % self.ratingKey
return utils.listItems(self.server, path, Season.TYPE)
2014-12-29 03:21:58 +00:00
2017-01-04 20:38:04 +00:00
def season(self, title=None):
2017-01-02 21:06:40 +00:00
"""Returns a Season
Args:
2017-01-04 20:38:04 +00:00
title (str, int): fx Season 1
2017-01-02 21:06:40 +00:00
"""
2017-01-04 20:38:04 +00:00
title = str(title)
if title.isdigit():
title = 'season %s' % title
2014-12-29 03:21:58 +00:00
path = '/library/metadata/%s/children' % self.ratingKey
return utils.findItem(self.server, path, title)
2014-12-29 03:21:58 +00:00
def episodes(self, watched=None):
2017-01-02 21:06:40 +00:00
"""Returs a list of Episode
Args:
watched (bool): Defaults to None. Exclude watched episodes
"""
2014-12-29 03:21:58 +00:00
leavesKey = '/library/metadata/%s/allLeaves' % self.ratingKey
return utils.listItems(self.server, leavesKey, watched=watched)
2014-12-29 03:21:58 +00:00
2017-01-04 20:38:04 +00:00
def episode(self, title=None, season=None, episode=None):
if title:
path = '/library/metadata/%s/allLeaves' % self.ratingKey
return utils.findItem(self.server, path, title)
elif season and episode:
results = [i for i in self.episodes()
if i.seasonNumber == season and i.index == episode]
if results:
return results[0]
2014-12-29 03:21:58 +00:00
def watched(self):
2017-01-02 21:06:40 +00:00
"""Return a list of watched episodes"""
return self.episodes(watched=True)
def unwatched(self):
2017-01-02 21:06:40 +00:00
"""Return a list of unwatched episodes"""
return self.episodes(watched=False)
2014-12-29 03:21:58 +00:00
def get(self, title):
2017-01-02 21:06:40 +00:00
"""Get a Episode with a title.
Args:
title (str): fx Secret santa
"""
2014-12-29 03:21:58 +00:00
return self.episode(title)
def refresh(self):
2017-01-02 21:06:40 +00:00
"""Refresh the metadata."""
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):
2016-12-16 23:38:08 +00:00
"""Used to set the attributes
2017-01-02 21:06:40 +00:00
2016-12-16 23:38:08 +00:00
Args:
data (Element): Usually built from server.query
"""
Video._loadData(self, data)
self.leafCount = utils.cast(int, data.attrib.get('leafCount', NA))
2017-01-04 20:38:04 +00:00
self.index = utils.cast(int, data.attrib.get('index', NA))
self.parentKey = data.attrib.get('parentKey', NA)
2016-12-16 23:38:08 +00:00
self.parentRatingKey = utils.cast(int, data.attrib.get('parentRatingKey', NA))
self.viewedLeafCount = utils.cast(
int, data.attrib.get('viewedLeafCount', NA))
@property
def isWatched(self):
return bool(self.viewedLeafCount == self.leafCount)
2014-12-29 03:21:58 +00:00
@property
def seasonNumber(self):
2017-01-02 21:06:40 +00:00
"""Reurns season number."""
return self.index
def episodes(self, watched=None):
2017-01-02 21:06:40 +00:00
"""Returs a list of Episode
Args:
watched (bool): Defaults to None. Exclude watched episodes
2017-01-02 21:19:07 +00:00
Returns:
list: of Episode
2017-01-04 20:38:04 +00:00
2016-12-16 23:38:08 +00:00
"""
2014-12-29 03:21:58 +00:00
childrenKey = '/library/metadata/%s/children' % self.ratingKey
return utils.listItems(self.server, childrenKey, watched=watched)
2014-12-29 03:21:58 +00:00
2017-01-04 20:38:04 +00:00
def episode(self, title=None, season=None, episode=None):
"""Find a episode with a matching title or match
against season and episode.
2017-01-02 21:06:40 +00:00
2016-12-16 23:38:08 +00:00
Args:
2017-01-02 21:06:40 +00:00
title (sting): Fx
2017-01-04 20:38:04 +00:00
season (int, optional): Not needed, just kept for comp with Show.
episode (int, optional): Default None
2017-01-02 21:06:40 +00:00
Returns:
Episode
2016-12-16 23:38:08 +00:00
"""
2017-01-04 20:38:04 +00:00
if title:
path = '/library/metadata/%s/children' % self.ratingKey
return utils.findItem(self.server, path, title)
if episode:
if season is None:
season = self.index
results = [i for i in self.episodes()
if i.seasonNumber == season and i.index == episode]
if results:
return results[0]
2014-12-29 03:21:58 +00:00
def get(self, title):
2017-01-04 20:38:04 +00:00
"""Get a episode witha matching title.
2017-01-02 21:06:40 +00:00
Args:
title (str): fx Secret santa
Returns:
Episode
"""
2014-12-29 03:21:58 +00:00
return self.episode(title)
def show(self):
2017-01-02 21:06:40 +00:00
"""Return this seasons show."""
return utils.listItems(self.server, self.parentKey)[0]
2014-12-29 03:21:58 +00:00
def watched(self):
2017-01-02 21:06:40 +00:00
"""Returns a list of watched Episode"""
return self.episodes(watched=True)
def unwatched(self):
2017-01-02 21:06:40 +00:00
"""Returns a list of unwatched Episode"""
return self.episodes(watched=False)
2014-12-29 03:21:58 +00:00
@utils.register_libtype
class Episode(Video, Playable):
2014-12-29 03:21:58 +00:00
TYPE = 'episode'
def _loadData(self, data):
2017-01-02 21:06:40 +00:00
"""Used to set the attributes
Args:
data (Element): Usually built from server.query
"""
Video._loadData(self, data)
Playable._loadData(self, data)
self.art = data.attrib.get('art', NA)
self.chapterSource = data.attrib.get('chapterSource', NA)
self.contentRating = data.attrib.get('contentRating', NA)
self.duration = utils.cast(int, data.attrib.get('duration', NA))
self.grandparentArt = data.attrib.get('grandparentArt', NA)
2014-12-29 03:21:58 +00:00
self.grandparentKey = data.attrib.get('grandparentKey', NA)
2016-12-16 23:38:08 +00:00
self.grandparentRatingKey = utils.cast(int, data.attrib.get('grandparentRatingKey', NA))
self.grandparentTheme = data.attrib.get('grandparentTheme', NA)
2014-12-29 03:21:58 +00:00
self.grandparentThumb = data.attrib.get('grandparentThumb', NA)
self.grandparentTitle = data.attrib.get('grandparentTitle', NA)
self.guid = data.attrib.get('guid', NA)
2017-01-04 20:38:04 +00:00
self.index = utils.cast(int, data.attrib.get('index', NA))
2016-12-16 23:38:08 +00:00
self.originallyAvailableAt = utils.toDatetime(
data.attrib.get('originallyAvailableAt', NA), '%Y-%m-%d')
2014-12-29 03:21:58 +00:00
self.parentIndex = data.attrib.get('parentIndex', NA)
self.parentKey = data.attrib.get('parentKey', NA)
2016-12-16 23:38:08 +00:00
self.parentRatingKey = utils.cast(int, data.attrib.get('parentRatingKey', NA))
2014-12-29 03:21:58 +00:00
self.parentThumb = data.attrib.get('parentThumb', NA)
self.rating = utils.cast(float, data.attrib.get('rating', NA))
self.viewOffset = utils.cast(int, data.attrib.get('viewOffset', 0))
self.year = utils.cast(int, data.attrib.get('year', NA))
2016-12-16 23:38:08 +00:00
self.directors = [media.Director(self.server, e)
for e in data if e.tag == media.Director.TYPE]
self.media = [media.Media(self.server, e, self.initpath, self)
for e in data if e.tag == media.Media.TYPE]
self.writers = [media.Writer(self.server, e)
for e in data if e.tag == media.Writer.TYPE]
self.videoStreams = utils.findStreams(self.media, 'videostream')
self.audioStreams = utils.findStreams(self.media, 'audiostream')
self.subtitleStreams = utils.findStreams(self.media, 'subtitlestream')
# data for active sessions and history
self.sessionKey = utils.cast(int, data.attrib.get('sessionKey', NA))
self.username = utils.findUsername(data)
self.player = utils.findPlayer(self.server, data)
self.transcodeSession = utils.findTranscodeSession(self.server, data)
# Cached season number
self._seasonNumber = None
@property
def isWatched(self):
2017-01-02 21:06:40 +00:00
"""Returns True if watched, False if not."""
return bool(self.viewCount > 0)
2014-12-29 03:21:58 +00:00
@property
def seasonNumber(self):
2017-01-02 21:06:40 +00:00
"""Return this episode seasonnumber."""
if self._seasonNumber is None:
self._seasonNumber = self.parentIndex if self.parentIndex else self.season().seasonNumber
2017-01-04 20:38:04 +00:00
return utils.cast(int, self._seasonNumber)
2015-02-24 03:42:29 +00:00
@property
def thumbUrl(self):
2017-01-02 21:06:40 +00:00
"""Return url to thumb image."""
2017-01-02 21:19:07 +00:00
if self.grandparentThumb:
return self.server.url(self.grandparentThumb)
2015-02-24 03:42:29 +00:00
2014-12-29 03:21:58 +00:00
def season(self):
2017-01-02 21:06:40 +00:00
"""Return this episode Season"""
return utils.listItems(self.server, self.parentKey)[0]
2014-12-29 03:21:58 +00:00
def show(self):
2017-01-02 21:06:40 +00:00
"""Return this episodes Show"""
return utils.listItems(self.server, self.grandparentKey)[0]