Movies now direct playing. Trailers playing but always transcoding
This commit is contained in:
parent
93ad4ae0cb
commit
cef41188e0
3 changed files with 200 additions and 144 deletions
|
@ -619,6 +619,8 @@ class PlexAPI():
|
||||||
'X-Plex-Version': self.plexversion,
|
'X-Plex-Version': self.plexversion,
|
||||||
'X-Plex-Client-Identifier': self.clientId,
|
'X-Plex-Client-Identifier': self.clientId,
|
||||||
'machineIdentifier': self.machineIdentifier,
|
'machineIdentifier': self.machineIdentifier,
|
||||||
|
'Connection': 'keep-alive',
|
||||||
|
'X-Plex-Provides': 'player',
|
||||||
'Accept': 'application/xml'
|
'Accept': 'application/xml'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1781,16 +1783,73 @@ class API():
|
||||||
|
|
||||||
def getBitrate(self):
|
def getBitrate(self):
|
||||||
"""
|
"""
|
||||||
Returns the bitrate as an int or None
|
Returns the bitrate as an int. The Part bitrate is returned; if not
|
||||||
|
available in the Plex XML, the Media bitrate is returned
|
||||||
"""
|
"""
|
||||||
item = self.item
|
item = self.item
|
||||||
try:
|
try:
|
||||||
|
bitrate = item[self.child][0][self.part].attrib['bitrate']
|
||||||
|
except KeyError:
|
||||||
bitrate = item[self.child][0].attrib['bitrate']
|
bitrate = item[self.child][0].attrib['bitrate']
|
||||||
bitrate = int(bitrate)
|
bitrate = int(bitrate)
|
||||||
except KeyError:
|
|
||||||
bitrate = None
|
|
||||||
return bitrate
|
return bitrate
|
||||||
|
|
||||||
|
def getDataFromPartOrMedia(self, key):
|
||||||
|
"""
|
||||||
|
Retrieves XML data 'key' first from the active part. If unsuccessful,
|
||||||
|
tries to retrieve the data from the Media response part.
|
||||||
|
|
||||||
|
If all fails, None is returned.
|
||||||
|
"""
|
||||||
|
media = self.item[self.child][0].attrib
|
||||||
|
part = self.item[self.child][0][self.part].attrib
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
value = part[key]
|
||||||
|
except KeyError:
|
||||||
|
value = media[key]
|
||||||
|
except KeyError:
|
||||||
|
value = None
|
||||||
|
return value
|
||||||
|
|
||||||
|
def getVideoCodec(self):
|
||||||
|
"""
|
||||||
|
Returns the video codec and resolution for the child and part selected.
|
||||||
|
If any data is not found on a part-level, the Media-level data is
|
||||||
|
returned.
|
||||||
|
If that also fails (e.g. for old trailers, None is returned)
|
||||||
|
|
||||||
|
Output:
|
||||||
|
{
|
||||||
|
'videocodec': xxx, e.g. 'h264'
|
||||||
|
'resolution': xxx, e.g. '720' or '1080'
|
||||||
|
'height': xxx, e.g. '816'
|
||||||
|
'width': xxx, e.g. '1920'
|
||||||
|
'aspectratio': xxx, e.g. '1.78'
|
||||||
|
'bitrate': xxx, e.g. 10642 (an int!)
|
||||||
|
'container': xxx e.g. 'mkv'
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
videocodec = self.getDataFromPartOrMedia('videoCodec')
|
||||||
|
resolution = self.getDataFromPartOrMedia('videoResolution')
|
||||||
|
height = self.getDataFromPartOrMedia('height')
|
||||||
|
width = self.getDataFromPartOrMedia('width')
|
||||||
|
aspectratio = self.getDataFromPartOrMedia('aspectratio')
|
||||||
|
bitrate = self.getDataFromPartOrMedia('bitrate')
|
||||||
|
container = self.getDataFromPartOrMedia('container')
|
||||||
|
|
||||||
|
videoCodec = {
|
||||||
|
'videocodec': videocodec,
|
||||||
|
'resolution': resolution,
|
||||||
|
'height': height,
|
||||||
|
'width': width,
|
||||||
|
'aspectratio': aspectratio,
|
||||||
|
'bitrate': bitrate,
|
||||||
|
'container': container
|
||||||
|
}
|
||||||
|
return videoCodec
|
||||||
|
|
||||||
def getMediaStreams(self):
|
def getMediaStreams(self):
|
||||||
"""
|
"""
|
||||||
Returns the media streams
|
Returns the media streams
|
||||||
|
@ -1798,7 +1857,7 @@ class API():
|
||||||
Output: each track contains a dictionaries
|
Output: each track contains a dictionaries
|
||||||
{
|
{
|
||||||
'video': videotrack-list, 'videocodec', 'height', 'width',
|
'video': videotrack-list, 'videocodec', 'height', 'width',
|
||||||
'aspectratio', video3DFormat'
|
'aspectratio', 'video3DFormat'
|
||||||
'audio': audiotrack-list, 'audiocodec', 'channels',
|
'audio': audiotrack-list, 'audiocodec', 'channels',
|
||||||
'audiolanguage'
|
'audiolanguage'
|
||||||
'subtitle': list of subtitle languages (or "Unknown")
|
'subtitle': list of subtitle languages (or "Unknown")
|
||||||
|
@ -1980,43 +2039,32 @@ class API():
|
||||||
allartworks['Primary'] = artwork
|
allartworks['Primary'] = artwork
|
||||||
return allartworks
|
return allartworks
|
||||||
|
|
||||||
def getTranscodeVideoPath(self, action, quality={}, subtitle={}, audioboost=None, partIndex=None, options={}):
|
def getTranscodeVideoPath(self, action, quality={}, subtitle={}, audioboost=None, options={}):
|
||||||
"""
|
"""
|
||||||
Transcode Video support; returns the URL to get a media started
|
Transcode Video support; returns the URL to get a media started
|
||||||
|
|
||||||
Input:
|
Input:
|
||||||
action 'Transcode' OR any other string
|
action 'DirectPlay', 'DirectStream' or 'Transcode'
|
||||||
|
|
||||||
quality: {
|
quality: {
|
||||||
'videoResolution': 'resolution',
|
'videoResolution': 'resolution',
|
||||||
'videoQuality': 'quality',
|
'videoQuality': 'quality',
|
||||||
'maxVideoBitrate': 'bitrate'
|
'maxVideoBitrate': 'bitrate'
|
||||||
}
|
}
|
||||||
|
(one or several of these options)
|
||||||
subtitle {'selected', 'dontBurnIn', 'size'}
|
subtitle {'selected', 'dontBurnIn', 'size'}
|
||||||
audioboost e.g. 100
|
audioboost e.g. 100
|
||||||
partIndex Index number of media part, starting with 0
|
|
||||||
options dict() of PlexConnect-options as received from aTV
|
options dict() of PlexConnect-options as received from aTV
|
||||||
Output:
|
Output:
|
||||||
final path to pull in PMS transcoder
|
final URL to pull in PMS transcoder
|
||||||
|
|
||||||
TODO: mediaIndex
|
TODO: mediaIndex
|
||||||
"""
|
"""
|
||||||
# path to item
|
# Set Client capabilities
|
||||||
transcodePath = self.server + \
|
clientArgs = {
|
||||||
'/video/:/transcode/universal/start.m3u8?'
|
'X-Plex-Client-Capabilities':
|
||||||
|
"protocols=shoutcast,"
|
||||||
ID = self.getKey()
|
"http-live-streaming,"
|
||||||
if partIndex is not None:
|
|
||||||
path = self.server + '/library/metadata/' + ID
|
|
||||||
else:
|
|
||||||
path = self.item[self.child][0][self.part].attrib['key']
|
|
||||||
args = {
|
|
||||||
'session': self.clientId,
|
|
||||||
'protocol': 'hls', # also seen: 'dash'
|
|
||||||
'fastSeek': '1',
|
|
||||||
'path': path,
|
|
||||||
'mediaIndex': 0, # Probably refering to XML reply sheme
|
|
||||||
'X-Plex-Client-Capabilities': "protocols=http-live-streaming,"
|
|
||||||
"http-streaming-video,"
|
"http-streaming-video,"
|
||||||
"http-streaming-video-720p,"
|
"http-streaming-video-720p,"
|
||||||
"http-streaming-video-1080p,"
|
"http-streaming-video-1080p,"
|
||||||
|
@ -2025,50 +2073,108 @@ class API():
|
||||||
"http-mp4-video-720p,"
|
"http-mp4-video-720p,"
|
||||||
"http-mp4-video-1080p;"
|
"http-mp4-video-1080p;"
|
||||||
"videoDecoders="
|
"videoDecoders="
|
||||||
"h264{profile:high&resolution:1080&level:51};"
|
"h264{profile:high&resolution:1080&level:51},"
|
||||||
|
"h265{profile:high&resolution:1080&level:51},"
|
||||||
|
"mpeg1video,"
|
||||||
|
"mpeg2video,"
|
||||||
|
"mpeg4,"
|
||||||
|
"msmpeg4,"
|
||||||
|
"mjpeg,"
|
||||||
|
"wmv2,"
|
||||||
|
"wmv3,"
|
||||||
|
"vc1,"
|
||||||
|
"cinepak,"
|
||||||
|
"h263;"
|
||||||
"audioDecoders="
|
"audioDecoders="
|
||||||
"mp3,"
|
"mp3,"
|
||||||
"aac{bitrate:160000},"
|
"aac,"
|
||||||
"ac3{channels:6},"
|
"ac3{bitrate:800000&channels:8},"
|
||||||
"dts{channels:6}"
|
"dts{bitrate:800000&channels:8},"
|
||||||
# 'offset': 0 # Resume point
|
"truehd,"
|
||||||
# 'directPlay': 0 # 1 if Kodi can also handle the container
|
"eac3,"
|
||||||
|
"dca,"
|
||||||
|
"mp2,"
|
||||||
|
"pcm,"
|
||||||
|
"wmapro,"
|
||||||
|
"wmav2,"
|
||||||
|
"wmavoice,"
|
||||||
|
"wmalossless;"
|
||||||
|
}
|
||||||
|
xargs = PlexAPI().getXArgsDeviceInfo(options=options)
|
||||||
|
# For Direct Playing
|
||||||
|
if action == "DirectPlay":
|
||||||
|
path = self.item[self.child][0][self.part].attrib['key']
|
||||||
|
transcodePath = self.server + path
|
||||||
|
# Be sure to have exactly ONE '?' in the path (might already have
|
||||||
|
# been returned, e.g. trailers!)
|
||||||
|
if '?' not in path:
|
||||||
|
transcodePath = transcodePath + '?'
|
||||||
|
url = transcodePath + \
|
||||||
|
urlencode(clientArgs) + '&' + \
|
||||||
|
urlencode(xargs)
|
||||||
|
return url
|
||||||
|
|
||||||
|
# For Direct Streaming or Transcoding
|
||||||
|
transcodePath = self.server + \
|
||||||
|
'/video/:/transcode/universal/start.m3u8?'
|
||||||
|
partCount = 0
|
||||||
|
for parts in self.item[self.child][0]:
|
||||||
|
partCount = partCount + 1
|
||||||
|
# Movie consists of several parts; grap one part
|
||||||
|
if partCount > 1:
|
||||||
|
path = self.item[self.child][0][self.part].attrib['key']
|
||||||
|
# Movie consists of only one part
|
||||||
|
else:
|
||||||
|
path = self.item[self.child].attrib['key']
|
||||||
|
args = {
|
||||||
|
'path': path,
|
||||||
|
'mediaIndex': 0, # Probably refering to XML reply sheme
|
||||||
|
'partIndex': self.part,
|
||||||
|
'protocol': 'hls', # seen in the wild: 'dash', 'http', 'hls'
|
||||||
|
'offset': 0, # Resume point
|
||||||
|
'fastSeek': 1
|
||||||
}
|
}
|
||||||
# All the settings
|
# All the settings
|
||||||
if partIndex is not None:
|
|
||||||
args['partIndex'] = partIndex
|
|
||||||
if subtitle:
|
if subtitle:
|
||||||
args_update = {
|
argsUpdate = {
|
||||||
'subtitles': 'burn',
|
'subtitles': 'burn',
|
||||||
'subtitleSize': subtitle['size'], # E.g. 100
|
'subtitleSize': subtitle['size'], # E.g. 100
|
||||||
'skipSubtitles': subtitle['dontBurnIn'] # '1': shut off PMS
|
'skipSubtitles': subtitle['dontBurnIn'] # '1': shut off PMS
|
||||||
}
|
}
|
||||||
args.update(args_update)
|
|
||||||
self.logMsg(
|
self.logMsg(
|
||||||
"Subtitle: selected %s, dontBurnIn %s, size %s"
|
"Subtitle: selected %s, dontBurnIn %s, size %s"
|
||||||
% (subtitle['selected'], subtitle['dontBurnIn'],
|
% (subtitle['selected'], subtitle['dontBurnIn'],
|
||||||
subtitle['size']),
|
subtitle['size']),
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
|
args.update(argsUpdate)
|
||||||
if audioboost:
|
if audioboost:
|
||||||
args_update = {
|
argsUpdate = {
|
||||||
'audioBoost': audioboost
|
'audioBoost': audioboost
|
||||||
}
|
}
|
||||||
args.update(args_update)
|
|
||||||
self.logMsg("audioboost: %s" % audioboost, 1)
|
self.logMsg("audioboost: %s" % audioboost, 1)
|
||||||
if action == 'Transcode':
|
args.update(argsUpdate)
|
||||||
# Possible Plex settings:
|
|
||||||
# 'videoResolution': vRes,
|
|
||||||
# 'maxVideoBitrate': mVB,
|
|
||||||
# : vQ
|
|
||||||
self.logMsg("Setting transcode quality to: %s" % quality, 1)
|
|
||||||
args['directStream'] = '0'
|
|
||||||
args.update(quality)
|
|
||||||
else:
|
|
||||||
args['directStream'] = '1'
|
|
||||||
|
|
||||||
xargs = PlexAPI().getXArgsDeviceInfo(options=options)
|
if action == "DirectStream":
|
||||||
return transcodePath + urlencode(args) + '&' + urlencode(xargs)
|
argsUpdate = {
|
||||||
|
'directPlay': '0',
|
||||||
|
'directStream': '1',
|
||||||
|
}
|
||||||
|
args.update(argsUpdate)
|
||||||
|
elif action == 'Transcode':
|
||||||
|
argsUpdate = {
|
||||||
|
'directPlay': '0',
|
||||||
|
'directStream': '0'
|
||||||
|
}
|
||||||
|
self.logMsg("Setting transcode quality to: %s" % quality, 1)
|
||||||
|
args.update(quality)
|
||||||
|
args.update(argsUpdate)
|
||||||
|
|
||||||
|
url = transcodePath + \
|
||||||
|
urlencode(clientArgs) + '&' + \
|
||||||
|
urlencode(xargs) + '&' + \
|
||||||
|
urlencode(args)
|
||||||
|
return url
|
||||||
|
|
||||||
def adjustResume(self, resume_seconds):
|
def adjustResume(self, resume_seconds):
|
||||||
resume = 0
|
resume = 0
|
||||||
|
|
|
@ -80,6 +80,7 @@ class PlaybackUtils():
|
||||||
|
|
||||||
propertiesPlayback = utils.window('emby_playbackProps', windowid=10101) == "true"
|
propertiesPlayback = utils.window('emby_playbackProps', windowid=10101) == "true"
|
||||||
introsPlaylist = False
|
introsPlaylist = False
|
||||||
|
partsPlaylist = False
|
||||||
dummyPlaylist = False
|
dummyPlaylist = False
|
||||||
|
|
||||||
self.logMsg("Playlist start position: %s" % startPos, 1)
|
self.logMsg("Playlist start position: %s" % startPos, 1)
|
||||||
|
@ -117,7 +118,7 @@ class PlaybackUtils():
|
||||||
if playListSize > 1:
|
if playListSize > 1:
|
||||||
getTrailers = True
|
getTrailers = True
|
||||||
if utils.settings('askCinema') == "true":
|
if utils.settings('askCinema') == "true":
|
||||||
resp = xbmcgui.Dialog().yesno("Emby Cinema Mode", "Play trailers?")
|
resp = xbmcgui.Dialog().yesno(self.addonName, "Play trailers?")
|
||||||
if not resp:
|
if not resp:
|
||||||
# User selected to not play trailers
|
# User selected to not play trailers
|
||||||
getTrailers = False
|
getTrailers = False
|
||||||
|
@ -158,6 +159,7 @@ class PlaybackUtils():
|
||||||
partcount = len(parts)
|
partcount = len(parts)
|
||||||
if partcount > 1:
|
if partcount > 1:
|
||||||
# Only add to the playlist after intros have played
|
# Only add to the playlist after intros have played
|
||||||
|
partsPlaylist = True
|
||||||
i = 0
|
i = 0
|
||||||
for part in parts:
|
for part in parts:
|
||||||
API.setPartNumber(i)
|
API.setPartNumber(i)
|
||||||
|
@ -176,6 +178,7 @@ class PlaybackUtils():
|
||||||
self.pl.verifyPlaylist()
|
self.pl.verifyPlaylist()
|
||||||
currentPosition += 1
|
currentPosition += 1
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
API.setPartNumber(0)
|
||||||
|
|
||||||
if dummyPlaylist:
|
if dummyPlaylist:
|
||||||
# Added a dummy file to the playlist,
|
# Added a dummy file to the playlist,
|
||||||
|
@ -201,14 +204,15 @@ class PlaybackUtils():
|
||||||
self.setProperties(playurl, listitem)
|
self.setProperties(playurl, listitem)
|
||||||
|
|
||||||
############### PLAYBACK ################
|
############### PLAYBACK ################
|
||||||
|
customPlaylist = utils.window('emby_customPlaylist', windowid=10101)
|
||||||
if homeScreen and seektime:
|
if homeScreen and seektime:
|
||||||
self.logMsg("Play as a widget item.", 1)
|
self.logMsg("Play as a widget item.", 1)
|
||||||
self.setListItem(listitem)
|
self.setListItem(listitem)
|
||||||
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
|
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
|
||||||
|
|
||||||
elif ((introsPlaylist and utils.window('emby_customPlaylist', windowid=10101) == "true") or
|
elif ((introsPlaylist and customPlaylist == "true") or
|
||||||
(homeScreen and not sizePlaylist)):
|
(homeScreen and not sizePlaylist) or
|
||||||
|
(partsPlaylist and customPlaylist == "true")):
|
||||||
# Playlist was created just now, play it.
|
# Playlist was created just now, play it.
|
||||||
self.logMsg("Play playlist.", 1)
|
self.logMsg("Play playlist.", 1)
|
||||||
xbmc.Player().play(playlist, startpos=startPos)
|
xbmc.Player().play(playlist, startpos=startPos)
|
||||||
|
|
|
@ -38,7 +38,6 @@ class PlayUtils():
|
||||||
|
|
||||||
def getPlayUrl(self, child=0, partIndex=None):
|
def getPlayUrl(self, child=0, partIndex=None):
|
||||||
|
|
||||||
item = self.item
|
|
||||||
# NO, I am not very fond of this construct!
|
# NO, I am not very fond of this construct!
|
||||||
self.API.setChildNumber(child)
|
self.API.setChildNumber(child)
|
||||||
if partIndex is not None:
|
if partIndex is not None:
|
||||||
|
@ -51,34 +50,27 @@ class PlayUtils():
|
||||||
# playurl = self.httpPlay()
|
# playurl = self.httpPlay()
|
||||||
# utils.window('emby_%s.playmethod' % playurl, value="DirectStream")
|
# utils.window('emby_%s.playmethod' % playurl, value="DirectStream")
|
||||||
|
|
||||||
# elif self.isDirectPlay():
|
if self.isDirectPlay():
|
||||||
|
self.logMsg("File is direct playing.", 1)
|
||||||
# self.logMsg("File is direct playing.", 1)
|
playurl = self.API.getTranscodeVideoPath('DirectPlay')
|
||||||
# playurl = self.directPlay()
|
playurl = playurl.encode('utf-8')
|
||||||
# playurl = playurl.encode('utf-8')
|
# Set playmethod property
|
||||||
# # Set playmethod property
|
utils.window('emby_%s.playmethod' % playurl, value="DirectPlay")
|
||||||
# utils.window('emby_%s.playmethod' % playurl, value="DirectPlay")
|
|
||||||
|
|
||||||
if self.isDirectStream():
|
|
||||||
|
|
||||||
|
elif self.isDirectStream():
|
||||||
self.logMsg("File is direct streaming.", 1)
|
self.logMsg("File is direct streaming.", 1)
|
||||||
playurl = self.API.getTranscodeVideoPath(
|
playurl = self.API.getTranscodeVideoPath('DirectStream')
|
||||||
'direct',
|
|
||||||
partIndex=partIndex
|
|
||||||
)
|
|
||||||
# Set playmethod property
|
# Set playmethod property
|
||||||
utils.window('emby_%s.playmethod' % playurl, value="DirectStream")
|
utils.window('emby_%s.playmethod' % playurl, value="DirectStream")
|
||||||
|
|
||||||
elif self.isTranscoding():
|
elif self.isTranscoding():
|
||||||
|
|
||||||
self.logMsg("File is transcoding.", 1)
|
self.logMsg("File is transcoding.", 1)
|
||||||
quality = {
|
quality = {
|
||||||
'bitrate': self.getBitrate()
|
'maxVideoBitrate': self.getBitrate()
|
||||||
}
|
}
|
||||||
playurl = self.API.getTranscodeVideoPath(
|
playurl = self.API.getTranscodeVideoPath(
|
||||||
'Transcode',
|
'Transcode',
|
||||||
quality=quality,
|
quality=quality
|
||||||
partIndex=partIndex
|
|
||||||
)
|
)
|
||||||
# Set playmethod property
|
# Set playmethod property
|
||||||
utils.window('emby_%s.playmethod' % playurl, value="Transcode")
|
utils.window('emby_%s.playmethod' % playurl, value="Transcode")
|
||||||
|
@ -102,55 +94,17 @@ class PlayUtils():
|
||||||
|
|
||||||
def isDirectPlay(self):
|
def isDirectPlay(self):
|
||||||
|
|
||||||
item = self.item
|
|
||||||
|
|
||||||
# Requirement: Filesystem, Accessible path
|
# Requirement: Filesystem, Accessible path
|
||||||
if utils.settings('playFromStream') == "true":
|
if utils.settings('playFromStream') == "true":
|
||||||
# User forcing to play via HTTP
|
# User forcing to play via HTTP
|
||||||
self.logMsg("Can't direct play, play from HTTP enabled.", 1)
|
self.logMsg("Can't direct play, user enabled play from HTTP.", 1)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if (utils.settings('transcodeH265') == "true" and
|
if not self.h265enabled():
|
||||||
item['MediaSources'][0]['Name'].startswith("1080P/H265")):
|
|
||||||
# Avoid H265 1080p
|
|
||||||
self.logMsg("Option to transcode 1080P/H265 enabled.", 1)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
canDirectPlay = item['MediaSources'][0]['SupportsDirectPlay']
|
# Found with e.g. trailers
|
||||||
# Make sure direct play is supported by the server
|
if self.API.getDataFromPartOrMedia('optimizedForStreaming') == '1':
|
||||||
if not canDirectPlay:
|
|
||||||
self.logMsg("Can't direct play, server doesn't allow/support it.", 1)
|
|
||||||
return False
|
|
||||||
|
|
||||||
location = item['LocationType']
|
|
||||||
if location == "FileSystem":
|
|
||||||
# Verify the path
|
|
||||||
if not self.fileExists():
|
|
||||||
self.logMsg("Unable to direct play.")
|
|
||||||
try:
|
|
||||||
count = int(utils.settings('failCount'))
|
|
||||||
except ValueError:
|
|
||||||
count = 0
|
|
||||||
self.logMsg("Direct play failed: %s times." % count, 1)
|
|
||||||
|
|
||||||
if count < 2:
|
|
||||||
# Let the user know that direct play failed
|
|
||||||
utils.settings('failCount', value=str(count+1))
|
|
||||||
xbmcgui.Dialog().notification(
|
|
||||||
heading="Emby server",
|
|
||||||
message="Unable to direct play.",
|
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
|
||||||
sound=False)
|
|
||||||
elif utils.settings('playFromStream') != "true":
|
|
||||||
# Permanently set direct stream as true
|
|
||||||
utils.settings('playFromStream', value="true")
|
|
||||||
utils.settings('failCount', value="0")
|
|
||||||
xbmcgui.Dialog().notification(
|
|
||||||
heading="Emby server",
|
|
||||||
message=("Direct play failed 3 times. Enabled play "
|
|
||||||
"from HTTP in the add-on settings."),
|
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
|
||||||
sound=False)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -164,15 +118,6 @@ class PlayUtils():
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
playurl = item['Path']
|
playurl = item['Path']
|
||||||
|
|
||||||
if item.get('VideoType'):
|
|
||||||
# Specific format modification
|
|
||||||
type = item['VideoType']
|
|
||||||
|
|
||||||
if type == "Dvd":
|
|
||||||
playurl = "%s/VIDEO_TS/VIDEO_TS.IFO" % playurl
|
|
||||||
elif type == "Bluray":
|
|
||||||
playurl = "%s/BDMV/index.bdmv" % playurl
|
|
||||||
|
|
||||||
# Assign network protocol
|
# Assign network protocol
|
||||||
if playurl.startswith('\\\\'):
|
if playurl.startswith('\\\\'):
|
||||||
playurl = playurl.replace("\\\\", "smb://")
|
playurl = playurl.replace("\\\\", "smb://")
|
||||||
|
@ -206,15 +151,21 @@ class PlayUtils():
|
||||||
self.logMsg("Failed to find file.")
|
self.logMsg("Failed to find file.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def isDirectStream(self):
|
def h265enabled(self):
|
||||||
|
videoCodec = self.API.getVideoCodec()
|
||||||
item = self.item
|
codec = videoCodec['videocodec']
|
||||||
|
resolution = videoCodec['resolution']
|
||||||
if (utils.settings('transcodeH265') == "true" and
|
if ((utils.settings('transcodeH265') == "true") and
|
||||||
item[0][0].attrib('videoCodec').startswith("h265") and
|
("h265" in codec) and
|
||||||
item[0][0].attrib('videoResolution').startswith("1080")):
|
(resolution == "1080")):
|
||||||
# Avoid H265 1080p
|
# Avoid H265 1080p
|
||||||
self.logMsg("Option to transcode 1080P/H265 enabled.", 1)
|
self.logMsg("Option to transcode 1080P/H265 enabled.", 0)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def isDirectStream(self):
|
||||||
|
if not self.h265enabled():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Requirement: BitRate, supported encoding
|
# Requirement: BitRate, supported encoding
|
||||||
|
@ -229,7 +180,6 @@ class PlayUtils():
|
||||||
if not self.isNetworkSufficient():
|
if not self.isNetworkSufficient():
|
||||||
self.logMsg("The network speed is insufficient to direct stream file.", 1)
|
self.logMsg("The network speed is insufficient to direct stream file.", 1)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def directStream(self):
|
def directStream(self):
|
||||||
|
@ -256,11 +206,7 @@ class PlayUtils():
|
||||||
settings = self.getBitrate()
|
settings = self.getBitrate()
|
||||||
|
|
||||||
sourceBitrate = self.API.getBitrate()
|
sourceBitrate = self.API.getBitrate()
|
||||||
if not sourceBitrate:
|
self.logMsg("The add-on settings bitrate is: %s, the video bitrate required is: %s" % (settings, sourceBitrate), 1)
|
||||||
self.logMsg("Bitrate value is missing.", 0)
|
|
||||||
return True
|
|
||||||
self.logMsg("The add-on settings bitrate is: %s, the video bitrate required is: %s"
|
|
||||||
% (settings, sourceBitrate), 1)
|
|
||||||
if settings < sourceBitrate:
|
if settings < sourceBitrate:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
Loading…
Reference in a new issue