2015-07-18 18:08:05 +10:00
# -*- coding: utf-8 -*-
2015-03-14 08:24:59 +11:00
#################################################################################################
# utils class
#################################################################################################
import xbmc
import xbmcgui
import xbmcaddon
2015-06-06 16:06:33 +10:00
import xbmcvfs
2015-03-14 08:24:59 +11:00
from ClientInformation import ClientInformation
2015-05-07 16:11:20 +10:00
import Utils as utils
2015-03-14 08:24:59 +11:00
###########################################################################
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 ( )
2015-07-23 18:18:17 +10:00
WINDOW = xbmcgui . Window ( 10000 )
2015-05-07 16:11:20 +10:00
def __init__ ( self ) :
self . __dict__ = self . _shared_state
def logMsg ( self , msg , lvl = 1 ) :
className = self . __class__ . __name__
2015-06-16 04:42:34 +10:00
utils . logMsg ( " %s %s " % ( self . addonName , className ) , msg , int ( lvl ) )
2015-05-07 16:11:20 +10:00
2015-03-14 08:24:59 +11:00
def getPlayUrl ( self , server , id , result ) :
2015-04-14 04:56:36 +10:00
2015-07-23 18:18:17 +10:00
WINDOW = self . WINDOW
2015-05-07 16:11:20 +10:00
username = WINDOW . getProperty ( ' currUser ' )
server = WINDOW . getProperty ( ' server %s ' % username )
2015-07-18 18:08:05 +10:00
if self . isDirectPlay ( result , True ) :
# Try direct play
playurl = self . directPlay ( result )
if playurl :
self . logMsg ( " File is direct playing. " , 1 )
WINDOW . setProperty ( " %s playmethod " % playurl . encode ( ' utf-8 ' ) , " DirectPlay " )
2015-05-07 16:11:20 +10:00
2015-07-23 17:30:04 +10:00
elif self . isDirectStream ( result ) :
2015-07-18 18:08:05 +10:00
# Try direct stream
playurl = self . directStream ( result , server , id )
if playurl :
self . logMsg ( " File is direct streaming. " , 1 )
WINDOW . setProperty ( " %s playmethod " % playurl , " DirectStream " )
2015-07-23 18:18:17 +10:00
elif self . isTranscoding ( result ) :
# Try transcoding
2015-07-18 18:08:05 +10:00
playurl = self . transcoding ( result , server , id )
if playurl :
2015-05-07 16:11:20 +10:00
self . logMsg ( " File is transcoding. " , 1 )
2015-05-08 10:24:32 +10:00
WINDOW . setProperty ( " %s playmethod " % playurl , " Transcode " )
2015-07-23 18:18:17 +10:00
else :
# Error
return False
2015-05-07 16:11:20 +10:00
2015-05-10 22:39:16 +10:00
return playurl . encode ( ' utf-8 ' )
2015-05-07 16:11:20 +10:00
2015-07-18 18:08:05 +10:00
def isDirectPlay ( self , result , dialog = False ) :
2015-05-07 16:11:20 +10:00
# Requirements for Direct play:
# FileSystem, Accessible path
2015-03-14 08:24:59 +11:00
2015-08-14 19:03:12 +10:00
playhttp = utils . settings ( ' playFromStream ' )
2015-05-07 16:11:20 +10:00
# User forcing to play via HTTP instead of SMB
if playhttp == " true " :
2015-06-03 07:26:23 +10:00
self . logMsg ( " Can ' t direct play: Play from HTTP is enabled. " , 1 )
2015-05-07 16:11:20 +10:00
return False
canDirectPlay = result [ u ' MediaSources ' ] [ 0 ] [ u ' SupportsDirectPlay ' ]
# Make sure it's supported by server
if not canDirectPlay :
2015-06-03 07:26:23 +10:00
self . logMsg ( " Can ' t direct play: Server does not allow or support it. " , 1 )
2015-05-07 16:11:20 +10:00
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 :
2015-07-23 18:18:17 +10:00
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 ' ] )
2015-07-18 18:08:05 +10:00
if dialog :
# Let user know that direct play failed
2015-07-23 18:18:17 +10:00
dialog = xbmcgui . Dialog ( )
resp = dialog . select ( ' Warning: Unable to direct play. ' , [ ' Play from HTTP ' , ' Play from HTTP and remember next time. ' ] )
2015-07-18 18:08:05 +10:00
if resp == 1 :
# Remember next time
2015-08-14 19:03:12 +10:00
utils . settings ( ' playFromStream ' , " true " )
2015-07-23 18:18:17 +10:00
elif resp < 0 :
2015-07-18 18:08:05 +10:00
# User decided not to proceed.
2015-07-23 18:18:17 +10:00
self . logMsg ( " User cancelled HTTP selection dialog. " , 1 )
self . WINDOW . setProperty ( " playurlFalse " , " true " )
2015-05-08 10:38:27 +10:00
return False
2015-05-07 16:11:20 +10:00
def directPlay ( self , result ) :
try :
2015-07-18 18:08:05 +10:00
try :
playurl = result [ u ' MediaSources ' ] [ 0 ] [ u ' Path ' ]
except :
playurl = result [ u ' Path ' ]
except :
self . logMsg ( " Direct play failed. Trying Direct stream. " , 1 )
return False
else :
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 :
2015-08-14 19:03:12 +10:00
smbuser = utils . settings ( ' smbusername ' )
smbpass = utils . settings ( ' smbpassword ' )
2015-05-07 16:11:20 +10:00
# 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 :
2015-07-18 18:08:05 +10:00
USER_AGENT = " QuickTime/7.7.4 "
2015-05-07 16:11:20 +10:00
playurl + = " ?|User-Agent= %s " % USER_AGENT
2015-05-10 22:39:16 +10:00
2015-05-07 16:11:20 +10:00
return playurl
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 :
2015-07-23 19:02:41 +10:00
self . logMsg ( " File location is virtual. Can ' t proceed. " , 1 )
2015-05-07 16:11:20 +10:00
return False
# Verify BitRate
if not self . isNetworkQualitySufficient ( result ) :
2015-07-23 19:02:41 +10:00
self . logMsg ( " The network speed is insufficient to playback the file. " , 1 )
2015-05-07 16:11:20 +10:00
return False
return True
2015-06-11 15:46:47 +10:00
2015-07-18 18:08:05 +10:00
def directStream ( self , result , server , id , type = " Video " ) :
2015-03-14 08:24:59 +11:00
2015-05-07 16:11:20 +10:00
try :
2015-07-18 18:08:05 +10:00
if " ThemeVideo " in type :
playurl = " %s /mediabrowser/Videos/ %s /stream?static=true " % ( server , id )
elif " Video " in type :
2015-06-11 15:46:47 +10:00
playurl = " %s /mediabrowser/Videos/ %s /stream?static=true " % ( server , id )
2015-07-18 18:08:05 +10:00
# Verify audio and subtitles
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 ' ) )
elif " Audio " in type :
2015-06-11 15:46:47 +10:00
playurl = " %s /mediabrowser/Audio/ %s /stream.mp3 " % ( server , id )
2015-07-18 18:08:05 +10:00
2015-05-07 16:11:20 +10:00
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 )
self . logMsg ( " Playurl: %s " % playurl )
2015-06-09 20:30:01 +10:00
2015-05-07 16:11:20 +10:00
return playurl
except :
self . logMsg ( " Transcoding failed. " )
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 ' ] )
2015-08-09 01:11:41 +10:00
except :
self . logMsg ( " Bitrate value is missing. " )
else :
2015-08-08 23:15:05 +10:00
self . logMsg ( " The video quality selected is: %s , the video bitrate required to direct stream is: %s . " % ( settingsVideoBitRate , sourceBitRate ) , 1 )
2015-08-09 01:11:41 +10:00
if settingsVideoBitRate < sourceBitRate :
2015-05-07 16:11:20 +10:00
return False
2015-08-09 01:11:41 +10:00
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
2015-08-14 19:03:12 +10:00
videoQuality = utils . settings ( ' videoBitRate ' )
2015-05-07 16:11:20 +10:00
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
2015-06-06 16:06:33 +10:00
# Convert Emby path to a path we can verify
path = self . directPlay ( result )
2015-06-09 20:30:01 +10:00
if not path :
return False
2015-05-17 20:52:21 +10:00
try :
2015-06-06 16:06:33 +10:00
pathexists = xbmcvfs . exists ( path )
except :
pathexists = False
2015-05-07 16:11:20 +10:00
# Verify the device has access to the direct path
2015-05-17 21:27:28 +10:00
if pathexists :
2015-05-17 11:21:49 +10:00
# Local or Network path
self . logMsg ( " Path exists. " , 2 )
2015-03-14 08:24:59 +11:00
return True
2015-07-25 21:57:39 +10:00
elif " : " not in path :
# Give benefit of the doubt for nfs.
self . logMsg ( " Can ' t verify path (assumed NFS). 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-06-06 16:06:33 +10:00
self . logMsg ( " Path is detected as follow: %s . Try direct streaming. " % path , 2 )
2015-08-06 18:09:45 +10:00
return False