2015-03-14 08:24:59 +11:00
#################################################################################################
# utils class
#################################################################################################
import xbmc
import xbmcgui
import xbmcaddon
from ClientInformation import ClientInformation
2015-05-07 16:11:20 +10:00
import Utils as utils
2015-03-14 08:24:59 +11:00
import os
###########################################################################
2015-05-07 16:11:20 +10:00
2015-03-14 08:24:59 +11:00
class PlayUtils ( ) :
2015-05-07 16:11:20 +10:00
_shared_state = { }
clientInfo = ClientInformation ( )
addonName = clientInfo . getAddonName ( )
addonId = clientInfo . getAddonId ( )
addon = xbmcaddon . Addon ( id = addonId )
def __init__ ( self ) :
self . __dict__ = self . _shared_state
def logMsg ( self , msg , lvl = 1 ) :
className = self . __class__ . __name__
utils . logMsg ( " %s %s " % ( self . addonName , className ) , str ( msg ) , int ( lvl ) )
2015-03-14 08:24:59 +11:00
def getPlayUrl ( self , server , id , result ) :
2015-04-14 04:56:36 +10:00
2015-05-07 16:11:20 +10:00
addon = self . addon
WINDOW = xbmcgui . Window ( 10000 )
username = WINDOW . getProperty ( ' currUser ' )
server = WINDOW . getProperty ( ' server %s ' % username )
if self . isDirectPlay ( result ) :
try :
# Try direct play
playurl = self . directPlay ( result )
if not playurl :
# Let user know that direct play failed
2015-05-14 16:05:52 +10:00
resp = xbmcgui . Dialog ( ) . select ( ' Warning: Unable to direct play. ' , [ ' Play from HTTP ' , ' Play from HTTP and remember next time. ' ] )
if resp > - 1 :
# Play from HTTP
2015-05-07 16:11:20 +10:00
playurl = self . directStream ( result , server , id )
2015-05-14 16:05:52 +10:00
if resp == 1 :
# Remember next time
addon . setSetting ( ' playFromStream ' , " true " )
2015-05-07 16:11:20 +10:00
if not playurl :
# Try transcoding
playurl = self . transcoding ( result , server , id )
WINDOW . setProperty ( " transcoding %s " % id , " true " )
self . logMsg ( " File is transcoding. " , 1 )
2015-05-08 10:24:32 +10:00
WINDOW . setProperty ( " %s playmethod " % playurl , " Transcode " )
2015-05-07 16:11:20 +10:00
else :
self . logMsg ( " File is direct streaming. " , 1 )
2015-05-08 10:24:32 +10:00
WINDOW . setProperty ( " %s playmethod " % playurl , " DirectStream " )
2015-05-07 16:11:20 +10:00
else :
# User decided not to proceed.
self . logMsg ( " Unable to direct play. Verify the following path is accessible by the device: %s . You might also need to add SMB credentials in the addon settings. " % result [ u ' MediaSources ' ] [ 0 ] [ u ' Path ' ] )
return False
else :
self . logMsg ( " File is direct playing. " , 1 )
2015-05-10 22:39:16 +10:00
WINDOW . setProperty ( " %s playmethod " % playurl . encode ( ' utf-8 ' ) , " DirectPlay " )
2015-05-07 16:11:20 +10:00
except :
return False
elif self . isDirectStream ( result ) :
try :
# Try direct stream
playurl = self . directStream ( result , server , id )
if not playurl :
# Try transcoding
playurl = self . transcoding ( result , server , id )
WINDOW . setProperty ( " transcoding %s " % id , " true " )
self . logMsg ( " File is transcoding. " , 1 )
2015-05-08 10:24:32 +10:00
WINDOW . setProperty ( " %s playmethod " % playurl , " Transcode " )
2015-05-07 16:11:20 +10:00
else :
self . logMsg ( " File is direct streaming. " , 1 )
2015-05-08 10:24:32 +10:00
WINDOW . setProperty ( " %s playmethod " % playurl , " DirectStream " )
2015-05-07 16:11:20 +10:00
except :
return False
elif self . isTranscoding ( result ) :
try :
# Try transcoding
playurl = self . transcoding ( result , server , id )
WINDOW . setProperty ( " transcoding %s " % id , " true " )
self . logMsg ( " File is transcoding. " , 1 )
2015-05-08 10:24:32 +10:00
WINDOW . setProperty ( " %s playmethod " % playurl , " Transcode " )
2015-05-07 16:11:20 +10:00
except :
return False
2015-05-10 22:39:16 +10:00
return playurl . encode ( ' utf-8 ' )
2015-05-07 16:11:20 +10:00
def isDirectPlay ( self , result ) :
# Requirements for Direct play:
# FileSystem, Accessible path
2015-05-08 10:24:32 +10:00
self . addon = xbmcaddon . Addon ( id = self . addonId )
2015-03-14 08:24:59 +11:00
2015-05-08 10:24:32 +10:00
playhttp = self . addon . getSetting ( ' playFromStream ' )
2015-05-07 16:11:20 +10:00
# User forcing to play via HTTP instead of SMB
if playhttp == " true " :
return False
canDirectPlay = result [ u ' MediaSources ' ] [ 0 ] [ u ' SupportsDirectPlay ' ]
# Make sure it's supported by server
if not canDirectPlay :
return False
location = result [ u ' LocationType ' ]
# File needs to be "FileSystem"
if u ' FileSystem ' in location :
# Verify if path is accessible
if self . fileExists ( result ) :
return True
2015-05-08 10:38:27 +10:00
else :
return False
2015-05-07 16:11:20 +10:00
def directPlay ( self , result ) :
2015-05-07 16:50:34 +10:00
addon = self . addon
2015-05-07 16:11:20 +10:00
try :
# Item can be played directly
playurl = result [ u ' MediaSources ' ] [ 0 ] [ u ' Path ' ]
2015-05-10 22:39:16 +10:00
2015-05-07 16:11:20 +10:00
if u ' VideoType ' in result :
# Specific format modification
if u ' Dvd ' in result [ u ' VideoType ' ] :
playurl = " %s /VIDEO_TS/VIDEO_TS.IFO " % playurl
elif u ' BluRay ' in result [ u ' VideoType ' ] :
playurl = " %s /BDMV/index.bdmv " % playurl
# Network - SMB protocol
if " \\ \\ " in playurl :
smbuser = addon . getSetting ( ' smbusername ' )
smbpass = addon . getSetting ( ' smbpassword ' )
# Network share
if smbuser :
playurl = playurl . replace ( " \\ \\ " , " smb:// %s : %s @ " % ( smbuser , smbpass ) )
else :
playurl = playurl . replace ( " \\ \\ " , " smb:// " )
playurl = playurl . replace ( " \\ " , " / " )
if " apple.com " in playurl :
USER_AGENT = ' QuickTime/7.7.4 '
playurl + = " ?|User-Agent= %s " % USER_AGENT
2015-05-10 22:39:16 +10:00
2015-05-07 16:11:20 +10:00
return playurl
except :
self . logMsg ( " Direct play failed. Trying Direct stream. " , 1 )
return False
def isDirectStream ( self , result ) :
# Requirements for Direct stream:
# FileSystem or Remote, BitRate, supported encoding
canDirectStream = result [ u ' MediaSources ' ] [ 0 ] [ u ' SupportsDirectStream ' ]
# Make sure it's supported by server
if not canDirectStream :
return False
location = result [ u ' LocationType ' ]
# File can be FileSystem or Remote, not Virtual
if u ' Virtual ' in location :
return False
# Verify BitRate
if not self . isNetworkQualitySufficient ( result ) :
return False
return True
def directStream ( self , result , server , id ) :
2015-03-14 08:24:59 +11:00
2015-05-07 16:11:20 +10:00
try :
# Play with Direct Stream
playurl = " %s /mediabrowser/Videos/ %s /stream?static=true " % ( server , id )
mediaSources = result [ u ' MediaSources ' ]
if mediaSources [ 0 ] . get ( ' DefaultAudioStreamIndex ' ) != None :
playurl = " %s &AudioStreamIndex= %s " % ( playurl , mediaSources [ 0 ] . get ( ' DefaultAudioStreamIndex ' ) )
if mediaSources [ 0 ] . get ( ' DefaultSubtitleStreamIndex ' ) != None :
playurl = " %s &SubtitleStreamIndex= %s " % ( playurl , mediaSources [ 0 ] . get ( ' DefaultSubtitleStreamIndex ' ) )
self . logMsg ( " Playurl: %s " % playurl )
return playurl
except :
self . logMsg ( " Direct stream failed. Trying transcoding. " , 1 )
return False
def isTranscoding ( self , result ) :
# Last resort, no requirements
# BitRate
canTranscode = result [ u ' MediaSources ' ] [ 0 ] [ u ' SupportsTranscoding ' ]
# Make sure it's supported by server
if not canTranscode :
return False
location = result [ u ' LocationType ' ]
# File can be FileSystem or Remote, not Virtual
if u ' Virtual ' in location :
return False
return True
def transcoding ( self , result , server , id ) :
try :
# Play transcoding
deviceId = self . clientInfo . getMachineId ( )
2015-04-14 04:56:36 +10:00
playurl = " %s /mediabrowser/Videos/ %s /master.m3u8?mediaSourceId= %s " % ( server , id , id )
2015-05-07 16:11:20 +10:00
playurl = " %s &VideoCodec=h264&AudioCodec=aac,ac3&deviceId= %s &VideoBitrate= %s " % ( playurl , deviceId , self . getVideoBitRate ( ) * 1000 )
mediaSources = result [ u ' MediaSources ' ]
if mediaSources [ 0 ] . get ( ' DefaultAudioStreamIndex ' ) != None :
playurl = " %s &AudioStreamIndex= %s " % ( playurl , mediaSources [ 0 ] [ u ' DefaultAudioStreamIndex ' ] )
if mediaSources [ 0 ] . get ( ' DefaultSubtitleStreamIndex ' ) != None :
playurl = " %s &SubtitleStreamIndex= %s " % ( playurl , mediaSources [ 0 ] [ u ' DefaultSubtitleStreamIndex ' ] )
2015-04-12 21:19:42 +10:00
2015-05-07 16:11:20 +10:00
self . logMsg ( " Playurl: %s " % playurl )
return playurl
except :
self . logMsg ( " Transcoding failed. " )
return False
''' forceTranscodingCodecs = self.addon.getSetting( ' forceTranscodingCodecs ' )
2015-04-12 21:19:42 +10:00
# check if we should force encoding due to the forceTranscodingCodecs setting
if forceTranscodingCodecs :
forceTranscodingCodecsSet = frozenset ( forceTranscodingCodecs . lower ( ) . split ( ' , ' ) )
codecs = frozenset ( [ mediaStream . get ( ' Codec ' , None ) for mediaStream in result . get ( ' MediaStreams ' , [ ] ) ] )
commonCodecs = forceTranscodingCodecsSet & codecs
#xbmc.log("emby isDirectPlay MediaStreams codecs: %s forceTranscodingCodecs: %s, common: %s" % (codecs, forceTranscodingCodecsSet, commonCodecs))
if commonCodecs :
2015-05-07 16:11:20 +10:00
return False '''
2015-03-14 08:24:59 +11:00
# Works out if the network quality can play directly or if transcoding is needed
def isNetworkQualitySufficient ( self , result ) :
2015-05-07 16:11:20 +10:00
2015-03-14 08:24:59 +11:00
settingsVideoBitRate = self . getVideoBitRate ( )
2015-05-07 16:11:20 +10:00
settingsVideoBitRate = settingsVideoBitRate * 1000
try :
mediaSources = result [ u ' MediaSources ' ]
sourceBitRate = int ( mediaSources [ 0 ] [ u ' Bitrate ' ] )
if settingsVideoBitRate > sourceBitRate :
return True
else :
return False
except :
return True
2015-03-14 08:24:59 +11:00
def getVideoBitRate ( self ) :
2015-05-07 16:11:20 +10:00
# get the addon video quality
videoQuality = self . addon . getSetting ( ' videoBitRate ' )
2015-03-14 08:24:59 +11:00
if ( videoQuality == " 0 " ) :
2015-05-07 16:11:20 +10:00
return 664
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 1 " ) :
2015-05-07 16:11:20 +10:00
return 996
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 2 " ) :
2015-05-07 16:11:20 +10:00
return 1320
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 3 " ) :
2015-05-07 16:11:20 +10:00
return 2000
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 4 " ) :
2015-05-07 16:11:20 +10:00
return 3200
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 5 " ) :
2015-05-07 16:11:20 +10:00
return 4700
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 6 " ) :
2015-05-07 16:11:20 +10:00
return 6200
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 7 " ) :
2015-05-07 16:11:20 +10:00
return 7700
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 8 " ) :
2015-05-07 16:11:20 +10:00
return 9200
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 9 " ) :
2015-05-07 16:11:20 +10:00
return 10700
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 10 " ) :
2015-05-07 16:11:20 +10:00
return 12200
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 11 " ) :
2015-05-07 16:11:20 +10:00
return 13700
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 12 " ) :
2015-05-07 16:11:20 +10:00
return 15200
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 13 " ) :
2015-05-07 16:11:20 +10:00
return 16700
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 14 " ) :
2015-05-07 16:11:20 +10:00
return 18200
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 15 " ) :
2015-05-07 16:11:20 +10:00
return 20000
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 16 " ) :
2015-05-07 16:11:20 +10:00
return 40000
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 17 " ) :
2015-05-07 16:11:20 +10:00
return 100000
2015-03-14 08:24:59 +11:00
elif ( videoQuality == " 18 " ) :
2015-05-07 16:11:20 +10:00
return 1000000
2015-03-14 14:09:36 +11:00
else :
2015-05-07 16:11:20 +10:00
return 2147483 # max bit rate supported by server (max signed 32bit integer)
2015-03-14 14:09:36 +11:00
2015-03-14 08:24:59 +11:00
def fileExists ( self , result ) :
2015-05-07 16:11:20 +10:00
if u ' Path ' not in result :
# File has no path in server
2015-05-05 12:53:21 +10:00
return False
2015-05-07 16:11:20 +10:00
path = result [ u ' Path ' ]
# Verify the device has access to the direct path
2015-05-17 11:21:49 +10:00
if os . path . exists ( unicode ( path ) ) == True :
# Local or Network path
self . logMsg ( " Path exists. " , 2 )
2015-03-14 08:24:59 +11:00
return True
2015-05-08 07:33:50 +10:00
elif " : \\ " not in path :
# Give benefit of the doubt for nfs protocol
# Does not behave with os.path.exists
2015-05-17 11:21:49 +10:00
self . logMsg ( " Can ' t verify path. Still try direct play. " , 2 )
2015-05-08 07:33:50 +10:00
return True
2015-03-14 08:24:59 +11:00
else :
2015-05-17 11:21:49 +10:00
self . logMsg ( " Path is detected as a Url. Try direct streaming. " , 2 )
2015-05-07 16:11:20 +10:00
return False