177 lines
5.7 KiB
Python
177 lines
5.7 KiB
Python
import plexobjects
|
|
import plexstream
|
|
import plexrequest
|
|
import util
|
|
|
|
|
|
class PlexPart(plexobjects.PlexObject):
|
|
def reload(self):
|
|
self.initpath = self.key
|
|
|
|
def __init__(self, data, initpath=None, server=None, media=None):
|
|
plexobjects.PlexObject.__init__(self, data, initpath, server)
|
|
self.container_ = self.container
|
|
self.container = media
|
|
self.streams = []
|
|
|
|
# If we weren't given any data, this is a synthetic part
|
|
if data is not None:
|
|
self.streams = [plexstream.PlexStream(e, initpath=self.initpath, server=self.server) for e in data if e.tag == 'Stream']
|
|
if self.indexes:
|
|
indexKeys = self.indexes('').split(",")
|
|
self.indexes = util.AttributeDict()
|
|
for indexKey in indexKeys:
|
|
self.indexes[indexKey] = True
|
|
|
|
def getAddress(self):
|
|
address = self.key
|
|
|
|
if address != "":
|
|
# TODO(schuyler): Do we need to add a token? Or will it be taken care of via header else:where?
|
|
address = self.container.getAbsolutePath(address)
|
|
|
|
return address
|
|
|
|
def isAccessible(self):
|
|
# If we haven't fetched accessibility info, assume it's accessible.
|
|
return self.accessible.asBool() if self.accessible else True
|
|
|
|
def isAvailable(self):
|
|
# If we haven't fetched availability info, assume it's available
|
|
return not self.exists or self.exists.asBool()
|
|
|
|
def getStreamsOfType(self, streamType):
|
|
streams = []
|
|
|
|
foundSelected = False
|
|
|
|
for stream in self.streams:
|
|
if stream.streamType.asInt() == streamType:
|
|
streams.append(stream)
|
|
|
|
if stream.isSelected():
|
|
foundSelected = True
|
|
|
|
# If this is subtitles, add the none option
|
|
if streamType == plexstream.PlexStream.TYPE_SUBTITLE:
|
|
none = plexstream.NoneStream()
|
|
streams.insert(0, none)
|
|
none.setSelected(not foundSelected)
|
|
|
|
return streams
|
|
|
|
# def getSelectedStreamStringOfType(self, streamType):
|
|
# default = None
|
|
# availableStreams = 0
|
|
# for stream in self.streams:
|
|
# if stream.streamType.asInt() == streamType:
|
|
# availableStreams = availableStreams + 1
|
|
# if stream.isSelected() or (default is None and streamType != stream.TYPE_SUBTITLE):
|
|
# default = stream
|
|
|
|
# if default is not None:
|
|
# availableStreams = availableStreams - 1
|
|
# title = default.getTitle()
|
|
# suffix = "More"
|
|
# else:
|
|
# title = "None"
|
|
# suffix = "Available"
|
|
|
|
# if availableStreams > 0 and streamType != stream.TYPE_VIDEO:
|
|
# # Indicate available streams to choose from, excluding video
|
|
# # streams until the server supports multiple videos streams.
|
|
|
|
# return u"{0} : {1} {2}".format(title, availableStreams, suffix)
|
|
# else:
|
|
# return title
|
|
|
|
def getSelectedStreamOfType(self, streamType):
|
|
# Video streams, in particular, may not be selected. Pretend like the
|
|
# first one was selected.
|
|
|
|
default = None
|
|
|
|
for stream in self.streams:
|
|
if stream.streamType.asInt() == streamType:
|
|
if stream.isSelected():
|
|
return stream
|
|
elif default is None and streamType != stream.TYPE_SUBTITLE:
|
|
default = stream
|
|
|
|
return default
|
|
|
|
def setSelectedStream(self, streamType, streamId, async):
|
|
if streamType == plexstream.PlexStream.TYPE_AUDIO:
|
|
typeString = "audio"
|
|
elif streamType == plexstream.PlexStream.TYPE_SUBTITLE:
|
|
typeString = "subtitle"
|
|
elif streamType == plexstream.PlexStream.TYPE_VIDEO:
|
|
typeString = "video"
|
|
else:
|
|
return None
|
|
|
|
path = "/library/parts/{0}?{1}StreamID={2}".format(self.id(''), typeString, streamId)
|
|
|
|
if self.getServer().supportsFeature("allPartsStreamSelection"):
|
|
path = path + "&allParts=1"
|
|
|
|
request = plexrequest.PlexRequest(self.getServer(), path, "PUT")
|
|
|
|
if async:
|
|
context = request.createRequestContext("ignored")
|
|
import plexapp
|
|
plexapp.APP.startRequest(request, context, "")
|
|
else:
|
|
request.postToStringWithTimeout()
|
|
|
|
matching = plexstream.NoneStream()
|
|
|
|
# Update any affected streams
|
|
for stream in self.streams:
|
|
if stream.streamType.asInt() == streamType:
|
|
if stream.id == streamId:
|
|
stream.setSelected(True)
|
|
matching = stream
|
|
elif stream.isSelected():
|
|
stream.setSelected(False)
|
|
|
|
return matching
|
|
|
|
def isIndexed(self):
|
|
return bool(self.indexes)
|
|
|
|
def getIndexUrl(self, indexKey):
|
|
path = self.getIndexPath(indexKey)
|
|
if path is not None:
|
|
return self.container.server.buildUrl(path + "?interval=10000", True)
|
|
else:
|
|
return None
|
|
|
|
def getIndexPath(self, indexKey, interval=None):
|
|
if self.indexes is not None and indexKey in self.indexes:
|
|
return "/library/parts/{0}/indexes/{1}".format(self.id, indexKey)
|
|
else:
|
|
return None
|
|
|
|
def hasStreams(self):
|
|
return bool(self.streams)
|
|
|
|
def __str__(self):
|
|
return "Part {0} {1}".format(self.id("NaN"), self.key)
|
|
|
|
def __eq__(self, other):
|
|
if other is None:
|
|
return False
|
|
|
|
if self.__class__ != other.__class__:
|
|
return False
|
|
|
|
return self.id == other.id
|
|
|
|
def __ne__(self, other):
|
|
return not self.__eq__(other)
|
|
|
|
def __repr__(self):
|
|
return self.__str__()
|
|
|
|
# TODO(schuyler): getStreams, getIndexThumbUrl
|