This commit is contained in:
SpootDev 2016-03-31 12:41:06 -05:00
parent 753f267fde
commit 3c9c758bdd

View file

@ -1,458 +1,450 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################################# #################################################################################################
import xbmc import xbmc
import xbmcgui import xbmcgui
import xbmcvfs import xbmcvfs
import clientinfo import clientinfo
import utils import utils
################################################################################################# #################################################################################################
class PlayUtils(): class PlayUtils():
def __init__(self, item): def __init__(self, item):
self.item = item self.item = item
self.clientInfo = clientinfo.ClientInfo() self.clientInfo = clientinfo.ClientInfo()
self.addonName = self.clientInfo.getAddonName() self.addonName = self.clientInfo.getAddonName()
self.userid = utils.window('emby_currUser') self.userid = utils.window('emby_currUser')
self.server = utils.window('emby_server%s' % self.userid) self.server = utils.window('emby_server%s' % self.userid)
def logMsg(self, msg, lvl=1): def logMsg(self, msg, lvl=1):
self.className = self.__class__.__name__ self.className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl) utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
def getPlayUrl(self): def getPlayUrl(self):
log = self.logMsg window = utils.window
window = utils.window
item = self.item
item = self.item playurl = None
playurl = None
if (item.get('Type') in ("Recording", "TvChannel") and
if (item.get('Type') in ("Recording", "TvChannel") and item.get('MediaSources') and item['MediaSources'][0]['Protocol'] == "Http"):
item.get('MediaSources') and item['MediaSources'][0]['Protocol'] == "Http"): # Play LiveTV or recordings
# Play LiveTV or recordings self.logMsg("File protocol is http (livetv).", 1)
log("File protocol is http (livetv).", 1) playurl = "%s/emby/Videos/%s/live.m3u8?static=true" % (self.server, item['Id'])
playurl = "%s/emby/Videos/%s/live.m3u8?static=true" % (self.server, item['Id']) window('emby_%s.playmethod' % playurl, value="Transcode")
window('emby_%s.playmethod' % playurl, value="Transcode")
elif item.get('MediaSources') and item['MediaSources'][0]['Protocol'] == "Http":
elif item.get('MediaSources') and item['MediaSources'][0]['Protocol'] == "Http": # Only play as http, used for channels, or online hosting of content
# Only play as http, used for channels, or online hosting of content self.logMsg("File protocol is http.", 1)
log("File protocol is http.", 1) playurl = self.httpPlay()
playurl = self.httpPlay() window('emby_%s.playmethod' % playurl, value="DirectStream")
window('emby_%s.playmethod' % playurl, value="DirectStream")
elif self.isDirectPlay():
elif self.isDirectPlay():
self.logMsg("File is direct playing.", 1)
log("File is direct playing.", 1) playurl = self.directPlay()
playurl = self.directPlay() playurl = playurl.encode('utf-8')
playurl = playurl.encode('utf-8') # Set playmethod property
# Set playmethod property window('emby_%s.playmethod' % playurl, value="DirectPlay")
window('emby_%s.playmethod' % playurl, value="DirectPlay")
elif self.isDirectStream():
elif self.isDirectStream():
self.logMsg("File is direct streaming.", 1)
log("File is direct streaming.", 1) playurl = self.directStream()
playurl = self.directStream() # Set playmethod property
# Set playmethod property window('emby_%s.playmethod' % playurl, value="DirectStream")
window('emby_%s.playmethod' % playurl, value="DirectStream")
elif self.isTranscoding():
elif self.isTranscoding():
self.logMsg("File is transcoding.", 1)
log("File is transcoding.", 1) playurl = self.transcoding()
playurl = self.transcoding() # Set playmethod property
# Set playmethod property window('emby_%s.playmethod' % playurl, value="Transcode")
window('emby_%s.playmethod' % playurl, value="Transcode")
return playurl
return playurl
def httpPlay(self):
def httpPlay(self): # Audio, Video, Photo
# Audio, Video, Photo item = self.item
item = self.item server = self.server
server = self.server
itemid = item['Id']
itemid = item['Id'] mediatype = item['MediaType']
mediatype = item['MediaType']
if mediatype == "Audio":
if mediatype == "Audio": playurl = "%s/emby/Audio/%s/stream" % (server, itemid)
playurl = "%s/emby/Audio/%s/stream" % (server, itemid) else:
else: playurl = "%s/emby/Videos/%s/stream?static=true" % (server, itemid)
playurl = "%s/emby/Videos/%s/stream?static=true" % (server, itemid)
return playurl
return playurl
def isDirectPlay(self):
def isDirectPlay(self):
lang = utils.language
log = self.logMsg settings = utils.settings
lang = utils.language dialog = xbmcgui.Dialog()
settings = utils.settings
dialog = xbmcgui.Dialog() item = self.item
item = self.item # Requirement: Filesystem, Accessible path
if settings('playFromStream') == "true":
# Requirement: Filesystem, Accessible path # User forcing to play via HTTP
if settings('playFromStream') == "true": self.logMsg("Can't direct play, play from HTTP enabled.", 1)
# User forcing to play via HTTP return False
log("Can't direct play, play from HTTP enabled.", 1)
return False videotrack = item['MediaSources'][0]['Name']
transcodeH265 = settings('transcodeH265')
videotrack = item['MediaSources'][0]['Name']
transcodeH265 = settings('transcodeH265') if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack):
# Avoid H265/HEVC depending on the resolution
if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack): resolution = int(videotrack.split("P", 1)[0])
# Avoid H265/HEVC depending on the resolution res = {
resolution = int(videotrack.split("P", 1)[0])
res = { '1': 480,
'2': 720,
'1': 480, '3': 1080
'2': 720, }
'3': 1080 self.logMsg("Resolution is: %sP, transcode for resolution: %sP+"
} % (resolution, res[transcodeH265]), 1)
log("Resolution is: %sP, transcode for resolution: %sP+" if res[transcodeH265] <= resolution:
% (resolution, res[transcodeH265]), 1) return False
if res[transcodeH265] <= resolution:
return False canDirectPlay = item['MediaSources'][0]['SupportsDirectPlay']
# Make sure direct play is supported by the server
canDirectPlay = item['MediaSources'][0]['SupportsDirectPlay'] if not canDirectPlay:
# Make sure direct play is supported by the server self.logMsg("Can't direct play, server doesn't allow/support it.", 1)
if not canDirectPlay: return False
log("Can't direct play, server doesn't allow/support it.", 1)
return False location = item['LocationType']
if location == "FileSystem":
location = item['LocationType'] # Verify the path
if location == "FileSystem": if not self.fileExists():
# Verify the path self.logMsg("Unable to direct play.")
if not self.fileExists(): try:
log("Unable to direct play.") count = int(settings('failCount'))
try: except ValueError:
count = int(settings('failCount')) count = 0
except ValueError: self.logMsg("Direct play failed: %s times." % count, 1)
count = 0
log("Direct play failed: %s times." % count, 1) if count < 2:
# Let the user know that direct play failed
if count < 2: settings('failCount', value=str(count+1))
# Let the user know that direct play failed dialog.notification(
settings('failCount', value=str(count+1)) heading="Emby for Kodi",
dialog.notification( message=lang(33011),
heading="Emby for Kodi", icon="special://home/addons/plugin.video.emby/icon.png",
message=lang(33011), sound=False)
icon="special://home/addons/plugin.video.emby/icon.png", elif settings('playFromStream') != "true":
sound=False) # Permanently set direct stream as true
elif settings('playFromStream') != "true": settings('playFromStream', value="true")
# Permanently set direct stream as true settings('failCount', value="0")
settings('playFromStream', value="true") dialog.notification(
settings('failCount', value="0") heading="Emby for Kodi",
dialog.notification( message=lang(33012),
heading="Emby for Kodi", icon="special://home/addons/plugin.video.emby/icon.png",
message=lang(33012), sound=False)
icon="special://home/addons/plugin.video.emby/icon.png", return False
sound=False)
return False return True
return True def directPlay(self):
def directPlay(self): item = self.item
item = self.item try:
playurl = item['MediaSources'][0]['Path']
try: except (IndexError, KeyError):
playurl = item['MediaSources'][0]['Path'] playurl = item['Path']
except (IndexError, KeyError):
playurl = item['Path'] if item.get('VideoType'):
# Specific format modification
if item.get('VideoType'): type = item['VideoType']
# Specific format modification
type = item['VideoType'] if type == "Dvd":
playurl = "%s/VIDEO_TS/VIDEO_TS.IFO" % playurl
if type == "Dvd": elif type == "BluRay":
playurl = "%s/VIDEO_TS/VIDEO_TS.IFO" % playurl playurl = "%s/BDMV/index.bdmv" % playurl
elif type == "BluRay":
playurl = "%s/BDMV/index.bdmv" % playurl # Assign network protocol
if playurl.startswith('\\\\'):
# Assign network protocol playurl = playurl.replace("\\\\", "smb://")
if playurl.startswith('\\\\'): playurl = playurl.replace("\\", "/")
playurl = playurl.replace("\\\\", "smb://")
playurl = playurl.replace("\\", "/") if "apple.com" in playurl:
USER_AGENT = "QuickTime/7.7.4"
if "apple.com" in playurl: playurl += "?|User-Agent=%s" % USER_AGENT
USER_AGENT = "QuickTime/7.7.4"
playurl += "?|User-Agent=%s" % USER_AGENT return playurl
return playurl def fileExists(self):
def fileExists(self): if 'Path' not in self.item:
# File has no path defined in server
log = self.logMsg return False
if 'Path' not in self.item: # Convert path to direct play
# File has no path defined in server path = self.directPlay()
return False self.logMsg("Verifying path: %s" % path, 1)
# Convert path to direct play if xbmcvfs.exists(path):
path = self.directPlay() self.logMsg("Path exists.", 1)
log("Verifying path: %s" % path, 1) return True
if xbmcvfs.exists(path): elif ":" not in path:
log("Path exists.", 1) self.logMsg("Can't verify path, assumed linux. Still try to direct play.", 1)
return True return True
elif ":" not in path: else:
log("Can't verify path, assumed linux. Still try to direct play.", 1) self.logMsg("Failed to find file.", 1)
return True return False
else: def isDirectStream(self):
log("Failed to find file.", 1)
return False item = self.item
def isDirectStream(self): videotrack = item['MediaSources'][0]['Name']
transcodeH265 = utils.settings('transcodeH265')
log = self.logMsg
if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack):
item = self.item # Avoid H265/HEVC depending on the resolution
resolution = int(videotrack.split("P", 1)[0])
videotrack = item['MediaSources'][0]['Name'] res = {
transcodeH265 = utils.settings('transcodeH265')
'1': 480,
if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack): '2': 720,
# Avoid H265/HEVC depending on the resolution '3': 1080
resolution = int(videotrack.split("P", 1)[0]) }
res = { self.logMsg("Resolution is: %sP, transcode for resolution: %sP+"
% (resolution, res[transcodeH265]), 1)
'1': 480, if res[transcodeH265] <= resolution:
'2': 720, return False
'3': 1080
} # Requirement: BitRate, supported encoding
log("Resolution is: %sP, transcode for resolution: %sP+" canDirectStream = item['MediaSources'][0]['SupportsDirectStream']
% (resolution, res[transcodeH265]), 1) # Make sure the server supports it
if res[transcodeH265] <= resolution: if not canDirectStream:
return False return False
# Requirement: BitRate, supported encoding # Verify the bitrate
canDirectStream = item['MediaSources'][0]['SupportsDirectStream'] if not self.isNetworkSufficient():
# Make sure the server supports it self.logMsg("The network speed is insufficient to direct stream file.", 1)
if not canDirectStream: return False
return False
return True
# Verify the bitrate
if not self.isNetworkSufficient(): def directStream(self):
log("The network speed is insufficient to direct stream file.", 1)
return False item = self.item
server = self.server
return True
itemid = item['Id']
def directStream(self): itemtype = item['Type']
item = self.item if 'Path' in item and item['Path'].endswith('.strm'):
server = self.server # Allow strm loading when direct streaming
playurl = self.directPlay()
itemid = item['Id'] elif itemtype == "Audio":
itemtype = item['Type'] playurl = "%s/emby/Audio/%s/stream.mp3" % (server, itemid)
else:
if 'Path' in item and item['Path'].endswith('.strm'): playurl = "%s/emby/Videos/%s/stream?static=true" % (server, itemid)
# Allow strm loading when direct streaming
playurl = self.directPlay() return playurl
elif itemtype == "Audio":
playurl = "%s/emby/Audio/%s/stream.mp3" % (server, itemid) def isNetworkSufficient(self):
else:
playurl = "%s/emby/Videos/%s/stream?static=true" % (server, itemid)
settings = self.getBitrate()*1000
return playurl
try:
def isNetworkSufficient(self): sourceBitrate = int(self.item['MediaSources'][0]['Bitrate'])
except (KeyError, TypeError):
log = self.logMsg self.logMsg("Bitrate value is missing.", 1)
else:
settings = self.getBitrate()*1000 self.logMsg("The add-on settings bitrate is: %s, the video bitrate required is: %s"
% (settings, sourceBitrate), 1)
try: if settings < sourceBitrate:
sourceBitrate = int(self.item['MediaSources'][0]['Bitrate']) return False
except (KeyError, TypeError):
log("Bitrate value is missing.", 1) return True
else:
log("The add-on settings bitrate is: %s, the video bitrate required is: %s" def isTranscoding(self):
% (settings, sourceBitrate), 1)
if settings < sourceBitrate: item = self.item
return False
canTranscode = item['MediaSources'][0]['SupportsTranscoding']
return True # Make sure the server supports it
if not canTranscode:
def isTranscoding(self): return False
item = self.item return True
canTranscode = item['MediaSources'][0]['SupportsTranscoding'] def transcoding(self):
# Make sure the server supports it
if not canTranscode: item = self.item
return False
if 'Path' in item and item['Path'].endswith('.strm'):
return True # Allow strm loading when transcoding
playurl = self.directPlay()
def transcoding(self): else:
itemid = item['Id']
item = self.item deviceId = self.clientInfo.getDeviceId()
playurl = (
if 'Path' in item and item['Path'].endswith('.strm'): "%s/emby/Videos/%s/master.m3u8?MediaSourceId=%s"
# Allow strm loading when transcoding % (self.server, itemid, itemid)
playurl = self.directPlay() )
else: playurl = (
itemid = item['Id'] "%s&VideoCodec=h264&AudioCodec=ac3&MaxAudioChannels=6&deviceId=%s&VideoBitrate=%s"
deviceId = self.clientInfo.getDeviceId() % (playurl, deviceId, self.getBitrate()*1000))
playurl = (
"%s/emby/Videos/%s/master.m3u8?MediaSourceId=%s" return playurl
% (self.server, itemid, itemid)
) def getBitrate(self):
playurl = (
"%s&VideoCodec=h264&AudioCodec=ac3&MaxAudioChannels=6&deviceId=%s&VideoBitrate=%s" # get the addon video quality
% (playurl, deviceId, self.getBitrate()*1000)) videoQuality = utils.settings('videoBitrate')
bitrate = {
return playurl
'0': 664,
def getBitrate(self): '1': 996,
'2': 1320,
# get the addon video quality '3': 2000,
videoQuality = utils.settings('videoBitrate') '4': 3200,
bitrate = { '5': 4700,
'6': 6200,
'0': 664, '7': 7700,
'1': 996, '8': 9200,
'2': 1320, '9': 10700,
'3': 2000, '10': 12200,
'4': 3200, '11': 13700,
'5': 4700, '12': 15200,
'6': 6200, '13': 16700,
'7': 7700, '14': 18200,
'8': 9200, '15': 20000,
'9': 10700, '16': 40000,
'10': 12200, '17': 100000,
'11': 13700, '18': 1000000
'12': 15200, }
'13': 16700,
'14': 18200, # max bit rate supported by server (max signed 32bit integer)
'15': 20000, return bitrate.get(videoQuality, 2147483)
'16': 40000,
'17': 100000, def audioSubsPref(self, url, listitem):
'18': 1000000
} lang = utils.language
dialog = xbmcgui.Dialog()
# max bit rate supported by server (max signed 32bit integer) # For transcoding only
return bitrate.get(videoQuality, 2147483) # Present the list of audio to select from
audioStreamsList = {}
def audioSubsPref(self, url, listitem): audioStreams = []
audioStreamsChannelsList = {}
log = self.logMsg subtitleStreamsList = {}
lang = utils.language subtitleStreams = ['No subtitles']
dialog = xbmcgui.Dialog() downloadableStreams = []
# For transcoding only selectAudioIndex = ""
# Present the list of audio to select from selectSubsIndex = ""
audioStreamsList = {} playurlprefs = "%s" % url
audioStreams = []
audioStreamsChannelsList = {} item = self.item
subtitleStreamsList = {} try:
subtitleStreams = ['No subtitles'] mediasources = item['MediaSources'][0]
downloadableStreams = [] mediastreams = mediasources['MediaStreams']
selectAudioIndex = "" except (TypeError, KeyError, IndexError):
selectSubsIndex = "" return
playurlprefs = "%s" % url
for stream in mediastreams:
item = self.item # Since Emby returns all possible tracks together, have to sort them.
try: index = stream['Index']
mediasources = item['MediaSources'][0] type = stream['Type']
mediastreams = mediasources['MediaStreams']
except (TypeError, KeyError, IndexError): if 'Audio' in type:
return codec = stream['Codec']
channelLayout = stream.get('ChannelLayout', "")
for stream in mediastreams:
# Since Emby returns all possible tracks together, have to sort them. try:
index = stream['Index'] track = "%s - %s - %s %s" % (index, stream['Language'], codec, channelLayout)
type = stream['Type'] except:
track = "%s - %s %s" % (index, codec, channelLayout)
if 'Audio' in type:
codec = stream['Codec'] audioStreamsChannelsList[index] = stream['Channels']
channelLayout = stream.get('ChannelLayout', "") audioStreamsList[track] = index
audioStreams.append(track)
try:
track = "%s - %s - %s %s" % (index, stream['Language'], codec, channelLayout) elif 'Subtitle' in type:
except: try:
track = "%s - %s %s" % (index, codec, channelLayout) track = "%s - %s" % (index, stream['Language'])
except:
audioStreamsChannelsList[index] = stream['Channels'] track = "%s - %s" % (index, stream['Codec'])
audioStreamsList[track] = index
audioStreams.append(track) default = stream['IsDefault']
forced = stream['IsForced']
elif 'Subtitle' in type: downloadable = stream['IsTextSubtitleStream']
try:
track = "%s - %s" % (index, stream['Language']) if default:
except: track = "%s - Default" % track
track = "%s - %s" % (index, stream['Codec']) if forced:
track = "%s - Forced" % track
default = stream['IsDefault'] if downloadable:
forced = stream['IsForced'] downloadableStreams.append(index)
downloadable = stream['IsTextSubtitleStream']
subtitleStreamsList[track] = index
if default: subtitleStreams.append(track)
track = "%s - Default" % track
if forced:
track = "%s - Forced" % track if len(audioStreams) > 1:
if downloadable: resp = dialog.select(lang(33013), audioStreams)
downloadableStreams.append(index) if resp > -1:
# User selected audio
subtitleStreamsList[track] = index selected = audioStreams[resp]
subtitleStreams.append(track) selectAudioIndex = audioStreamsList[selected]
playurlprefs += "&AudioStreamIndex=%s" % selectAudioIndex
else: # User backed out of selection
if len(audioStreams) > 1: playurlprefs += "&AudioStreamIndex=%s" % mediasources['DefaultAudioStreamIndex']
resp = dialog.select(lang(33013), audioStreams) else: # There's only one audiotrack.
if resp > -1: selectAudioIndex = audioStreamsList[audioStreams[0]]
# User selected audio playurlprefs += "&AudioStreamIndex=%s" % selectAudioIndex
selected = audioStreams[resp]
selectAudioIndex = audioStreamsList[selected] if len(subtitleStreams) > 1:
playurlprefs += "&AudioStreamIndex=%s" % selectAudioIndex resp = dialog.select(lang(33014), subtitleStreams)
else: # User backed out of selection if resp == 0:
playurlprefs += "&AudioStreamIndex=%s" % mediasources['DefaultAudioStreamIndex'] # User selected no subtitles
else: # There's only one audiotrack. pass
selectAudioIndex = audioStreamsList[audioStreams[0]] elif resp > -1:
playurlprefs += "&AudioStreamIndex=%s" % selectAudioIndex # User selected subtitles
selected = subtitleStreams[resp]
if len(subtitleStreams) > 1: selectSubsIndex = subtitleStreamsList[selected]
resp = dialog.select(lang(33014), subtitleStreams)
if resp == 0: # Load subtitles in the listitem if downloadable
# User selected no subtitles if selectSubsIndex in downloadableStreams:
pass
elif resp > -1: itemid = item['Id']
# User selected subtitles url = [("%s/Videos/%s/%s/Subtitles/%s/Stream.srt"
selected = subtitleStreams[resp] % (self.server, itemid, itemid, selectSubsIndex))]
selectSubsIndex = subtitleStreamsList[selected] self.logMsg("Set up subtitles: %s %s" % (selectSubsIndex, url), 1)
listitem.setSubtitles(url)
# Load subtitles in the listitem if downloadable else:
if selectSubsIndex in downloadableStreams: # Burn subtitles
playurlprefs += "&SubtitleStreamIndex=%s" % selectSubsIndex
itemid = item['Id']
url = [("%s/Videos/%s/%s/Subtitles/%s/Stream.srt" else: # User backed out of selection
% (self.server, itemid, itemid, selectSubsIndex))] playurlprefs += "&SubtitleStreamIndex=%s" % mediasources.get('DefaultSubtitleStreamIndex', "")
log("Set up subtitles: %s %s" % (selectSubsIndex, url), 1)
listitem.setSubtitles(url) # Get number of channels for selected audio track
else: audioChannels = audioStreamsChannelsList.get(selectAudioIndex, 0)
# Burn subtitles if audioChannels > 2:
playurlprefs += "&SubtitleStreamIndex=%s" % selectSubsIndex playurlprefs += "&AudioBitrate=384000"
else:
else: # User backed out of selection playurlprefs += "&AudioBitrate=192000"
playurlprefs += "&SubtitleStreamIndex=%s" % mediasources.get('DefaultSubtitleStreamIndex', "")
# Get number of channels for selected audio track
audioChannels = audioStreamsChannelsList.get(selectAudioIndex, 0)
if audioChannels > 2:
playurlprefs += "&AudioBitrate=384000"
else:
playurlprefs += "&AudioBitrate=192000"
return playurlprefs return playurlprefs