PlexKodiConnect/resources/lib/plexnet/plexmedia.py
2018-09-30 13:16:17 +02:00

159 lines
5.5 KiB
Python

import locks
import http
import plexobjects
import plexpart
import plexrequest
import util
class PlexMedia(plexobjects.PlexObject):
def __init__(self, data, initpath=None, server=None, container=None):
self._data = data.attrib
plexobjects.PlexObject.__init__(self, data, initpath, server)
self.container_ = self.get('container')
self.container = container
self.indirectHeaders = None
self.parts = []
# If we weren't given any data, this is a synthetic media
if data is not None:
self.parts = [plexpart.PlexPart(elem, initpath=self.initpath, server=self.server, media=self) for elem in data]
def get(self, key, default=None):
return self._data.get(key, default)
def hasStreams(self):
return len(self.parts) > 0 and self.parts[0].hasStreams()
def isIndirect(self):
return self.get('indirect') == '1'
def isAccessible(self):
for part in self.parts:
if not part.isAccessible():
return False
return True
def isAvailable(self):
for part in self.parts:
if not part.isAvailable():
return False
return True
def resolveIndirect(self):
if not self.isIndirect() or locks.LOCKS.isLocked("resolve_indirect"):
return self
part = self.parts[0]
if part is None:
util.DEBUG("Failed to resolve indirect media: missing valid part")
return None
postBody = None
postUrl = part.postURL
request = plexrequest.PlexRequest(self.getServer(), part.key, postUrl is not None and "POST" or "GET")
if postUrl is not None:
util.DEBUG("Fetching content for indirect media POST URL: {0}".format(postUrl))
# Force setting the certificate to handle following https redirects
postRequest = http.HttpRequest(postUrl, None, True)
postResponse = postRequest.getToStringWithTimeout(30)
if len(postResponse) > 0 and type(postRequest.event) == "roUrlEvent":
util.DEBUG("Retrieved data from postURL, posting to resolve container")
crlf = chr(13) + chr(10)
postBody = ""
for header in postRequest.event.getResponseHeadersArray():
for name in header:
postBody = postBody + name + ": " + header[name] + crlf
postBody = postBody + crlf + postResponse
else:
util.DEBUG("Failed to resolve indirect media postUrl")
self.Set("indirect", "-1")
return self
request.addParam("postURL", postUrl)
response = request.doRequestWithTimeout(30, postBody)
item = response.items[0]
if item is None or item.mediaItems[0] is None:
util.DEBUG("Failed to resolve indirect media: no media items")
self.indirect = -1
return self
media = item.mediaItems[0]
# Add indirect headers to the media item
media.indirectHeaders = util.AttributeDict()
for header in (item.container.httpHeaders or '').split("&"):
arr = header.split("=")
if len(arr) == 2:
media.indirectHeaders[arr[0]] = arr[1]
# Reset the fallback media id if applicable
if self.id.asInt() < 0:
media.id = self.id
return media.resolveIndirect()
def __str__(self):
extra = []
attrs = ("videoCodec", "audioCodec", "audioChannels", "protocol", "id")
if self.get('container'):
extra.append("container={0}".format(self.get('container')))
for astr in attrs:
if hasattr(self, astr):
attr = getattr(self, astr)
if attr and not attr.NA:
extra.append("{0}={1}".format(astr, attr))
return self.versionString(log_safe=True) + " " + ' '.join(extra)
def versionString(self, log_safe=False):
details = []
details.append(self.getVideoResolutionString())
if self.bitrate.asInt() > 0:
details.append(util.bitrateToString(self.bitrate.asInt() * 1000))
detailString = ', '.join(details)
return (log_safe and ' * ' or u" \u2022 ").join(filter(None, [self.title, detailString]))
def __eq__(self, other):
if not other:
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__()
def getVideoResolution(self):
if self.videoResolution:
standardDefinitionHeight = 480
if str(util.validInt(filter(unicode.isdigit, self.videoResolution))) != self.videoResolution:
return self.height.asInt() > standardDefinitionHeight and self.height.asInt() or standardDefinitionHeight
else:
return self.videoResolution.asInt(standardDefinitionHeight)
return self.height.asInt()
def getVideoResolutionString(self):
resNumber = util.validInt(filter(unicode.isdigit, self.videoResolution))
if resNumber > 0 and str(resNumber) == self.videoResolution:
return self.videoResolution + "p"
return self.videoResolution.upper()
def isSelected(self):
import plexapp
return self.selected.asBool() or self.id == plexapp.INTERFACE.getPreference("local_mediaId")
# TODO(schuyler): getParts