This commit is contained in:
Marcel van der Veldt 2015-08-06 13:01:49 +02:00
commit 3b9d1ac02f
6 changed files with 155 additions and 156 deletions

View file

@ -21,8 +21,7 @@ class DownloadUtils():
clientInfo = ClientInformation() clientInfo = ClientInformation()
addonName = clientInfo.getAddonName() addonName = clientInfo.getAddonName()
addonId = clientInfo.getAddonId() addon = xbmcaddon.Addon()
addon = xbmcaddon.Addon(id=addonId)
WINDOW = xbmcgui.Window(10000) WINDOW = xbmcgui.Window(10000)
# Requests session # Requests session
@ -79,6 +78,7 @@ class DownloadUtils():
"GoHome,PageUp,NextLetter,GoToSearch," "GoHome,PageUp,NextLetter,GoToSearch,"
"GoToSettings,PageDown,PreviousLetter,TakeScreenshot," "GoToSettings,PageDown,PreviousLetter,TakeScreenshot,"
"VolumeUp,VolumeDown,ToggleMute,SendString,DisplayMessage," "VolumeUp,VolumeDown,ToggleMute,SendString,DisplayMessage,"
"SetAudioStreamIndex,SetSubtitleStreamIndex,"
"Mute,Unmute,SetVolume," "Mute,Unmute,SetVolume,"
"Play,Playstate,PlayNext" "Play,Playstate,PlayNext"
@ -183,7 +183,6 @@ class DownloadUtils():
# Replace for the real values and append api_key # Replace for the real values and append api_key
url = url.replace("{server}", self.server, 1) url = url.replace("{server}", self.server, 1)
url = url.replace("{UserId}", self.userId, 1) url = url.replace("{UserId}", self.userId, 1)
#url = "%s&api_key=%s" % (url, self.token)
self.logMsg("URL: %s" % url, 2) self.logMsg("URL: %s" % url, 2)
# Prepare request # Prepare request
@ -293,7 +292,7 @@ class DownloadUtils():
if r.headers['X-Application-Error-Code'] == "ParentalControl": if r.headers['X-Application-Error-Code'] == "ParentalControl":
# Parental control - access restricted # Parental control - access restricted
WINDOW.setProperty("Server_status", "restricted") WINDOW.setProperty("Server_status", "restricted")
xbmcgui.Dialog().notification("Emby server", "Access restricted.", xbmcgui.NOTIFICATION_ERROR, time=5000) xbmcgui.Dialog().notification("Emby server", "Access restricted.", xbmcgui.NOTIFICATION_ERROR, icon="special://home/addons/plugin.video.emby/icon.png", time=5000)
return False return False
if (status == "401") or (status == "Auth"): if (status == "401") or (status == "Auth"):
@ -303,7 +302,7 @@ class DownloadUtils():
# Tell UserClient token has been revoked. # Tell UserClient token has been revoked.
WINDOW.setProperty("Server_status", "401") WINDOW.setProperty("Server_status", "401")
self.logMsg("HTTP Error: %s" % e, 0) self.logMsg("HTTP Error: %s" % e, 0)
xbmcgui.Dialog().notification("Error connecting", "Unauthorized.", xbmcgui.NOTIFICATION_ERROR) xbmcgui.Dialog().notification("Error connecting", "Unauthorized.", xbmcgui.NOTIFICATION_ERROR, icon="special://home/addons/plugin.video.emby/icon.png")
return 401 return 401
elif (r.status_code == 301) or (r.status_code == 302): elif (r.status_code == 301) or (r.status_code == 302):

View file

@ -210,11 +210,6 @@ class PlayUtils():
deviceId = self.clientInfo.getMachineId() deviceId = self.clientInfo.getMachineId()
playurl = "%s/mediabrowser/Videos/%s/master.m3u8?mediaSourceId=%s" % (server, id, id) playurl = "%s/mediabrowser/Videos/%s/master.m3u8?mediaSourceId=%s" % (server, id, id)
playurl = "%s&VideoCodec=h264&AudioCodec=aac,ac3&deviceId=%s&VideoBitrate=%s" % (playurl, deviceId, self.getVideoBitRate()*1000) playurl = "%s&VideoCodec=h264&AudioCodec=aac,ac3&deviceId=%s&VideoBitrate=%s" % (playurl, deviceId, self.getVideoBitRate()*1000)
mediaSources = result[u'MediaSources']
prefs = self.audioSubsPref(mediaSources)
playurl = "%s%s" % (playurl, prefs)
self.logMsg("Playurl: %s" % playurl) self.logMsg("Playurl: %s" % playurl)
return playurl return playurl
@ -312,110 +307,4 @@ class PlayUtils():
return True return True
else: else:
self.logMsg("Path is detected as follow: %s. Try direct streaming." % path, 2) self.logMsg("Path is detected as follow: %s. Try direct streaming." % path, 2)
return False return False
def audioSubsPref(self, mediaSources):
addon = xbmcaddon.Addon()
defaultAudio = mediaSources[0][u'DefaultAudioStreamIndex']
playurlprefs = "&AudioStreamIndex=%s" % defaultAudio
codecs = [
# Possible codecs
u'und', u'ac3', u'dts', u'5.1', u'aac', u'mp3', u'dca'
]
try:
mediaStream = mediaSources[0].get('MediaStreams')
audiotracks = {}
substracks = {}
defaultSubs = None
for stream in mediaStream:
# Since Emby returns all possible tracks together, have to sort them.
if u'Audio' in stream[u'Type']:
if u'Language' in stream:
audiotracks[stream[u'Language']] = stream[u'Index']
else:
audiotracks[stream[u'Codec']] = stream[u'Index']
if u'Subtitle' in stream[u'Type']:
if u'Language' in stream:
substracks[stream[u'Language']] = stream[u'Index']
if stream[u'IsDefault'] == True:
defaultSubs = stream[u'Language']
else:
substracks[stream[u'Codec']] = stream[u'Index']
if stream[u'IsDefault']:
defaultSubs = stream[u'Codec']
self.logMsg("%s %s %s" % (defaultSubs, audiotracks, substracks), 1)
if len(audiotracks) == 1 and len(substracks) == 0:
# There's only one audio track and no subtitles
playurlprefs = "&AudioStreamIndex=%s" % defaultAudio
return playurlprefs
codec_intrack = False
for codec in codecs:
for track in audiotracks:
if codec in track:
codec_intrack = True
if self.audioPref in audiotracks:
self.logMsg("Door 1", 2)
# Audio pref is available
playurlprefs = "&AudioStreamIndex=%s" % audiotracks[self.audioPref]
if addon.getSetting('subsoverride') == "true":
# Subs are forced.
if self.subsPref in substracks:
self.logMsg("Door 1.1", 2)
playurlprefs = "%s&SubtitleStreamIndex=%s" % (playurlprefs, substracks[self.subsPref])
else:
# Use default subs
if defaultSubs != None:
self.logMsg("Door 1.2", 2)
playurlprefs = "%s&SubtitleStreamIndex=%s" % (playurlprefs, substracks[defaultSubs])
elif (len(audiotracks) == 1) and not codec_intrack:
self.logMsg("Door 2", 2)
# 1. There's one audio track.
# 2. The audio is defined as a language.
# 3. Audio pref is not available, guaranteed.
playurlprefs = "&AudioStreamIndex=%s" % defaultAudio
if self.subsPref in substracks:
self.logMsg("Door 2.1", 2)
# Subs pref is available.
playurlprefs = "%s&SubtitleStreamIndex=%s" % (playurlprefs, substracks[self.subsPref])
else:
# Use default subs
if defaultSubs != None:
self.logMsg("Door 2.2", 2)
playurlprefs = "%s&SubtitleStreamIndex=%s" % (playurlprefs, substracks[defaultSubs])
elif len(audiotracks) == 1 and codec_intrack:
self.logMsg("Door 3", 2)
# 1. There one audio track.
# 2. The audio is undefined or a codec.
# 3. Audio track is mislabeled.
playurlprefs = "&AudioStreamIndex=%s" % defaultAudio
if self.subsPref in substracks:
# If the subtitle is available, only display
# if the setting is enabled.
if addon.getSetting('subsoverride') == "true":
# Subs are forced.
self.logMsg("Door 3.1", 2)
playurlprefs = "%s&SubtitleStreamIndex=%s" % (playurlprefs, substracks[self.subsPref])
else:
# Use default subs
if defaultSubs != None:
self.logMsg("Door 3.2", 2)
playurlprefs = "%s&SubtitleStreamIndex=%s" % (playurlprefs, substracks[defaultSubs])
except: pass
return playurlprefs

View file

@ -97,6 +97,13 @@ class PlaybackUtils():
xbmc.log("Failed to retrieve the playback path/url.") xbmc.log("Failed to retrieve the playback path/url.")
return return
if WINDOW.getProperty("%splaymethod" % playurl) == "Transcode":
playurlprefs = self.audioSubsPref(playurl, result.get("MediaSources"))
if playurlprefs:
playurl = playurlprefs
else: # User cancelled dialog
return
thumbPath = API().getArtwork(result, "Primary") thumbPath = API().getArtwork(result, "Primary")
#if the file is a virtual strm file, we need to override the path by reading it's contents #if the file is a virtual strm file, we need to override the path by reading it's contents
@ -146,22 +153,6 @@ class PlaybackUtils():
WINDOW.setProperty(playurl+"runtimeticks", str(result.get("RunTimeTicks"))) WINDOW.setProperty(playurl+"runtimeticks", str(result.get("RunTimeTicks")))
WINDOW.setProperty(playurl+"type", result.get("Type")) WINDOW.setProperty(playurl+"type", result.get("Type"))
WINDOW.setProperty(playurl+"item_id", id) WINDOW.setProperty(playurl+"item_id", id)
mediaSources = result.get("MediaSources")
if(mediaSources != None):
mediaStream = mediaSources[0].get('MediaStreams')
defaultsubs = ""
for stream in mediaStream:
if u'Subtitle' in stream[u'Type'] and stream[u'IsDefault']:
if u'Language' in stream:
defaultsubs = stream[u'Language']
else:
defaultsubs = stream[u'Codec']
WINDOW.setProperty("%ssubs" % playurl, defaultsubs.encode('utf-8'))
if mediaSources[0].get('DefaultAudioStreamIndex') != None:
WINDOW.setProperty(playurl+"AudioStreamIndex", str(mediaSources[0].get('DefaultAudioStreamIndex')))
if mediaSources[0].get('DefaultSubtitleStreamIndex') != None:
WINDOW.setProperty(playurl+"SubtitleStreamIndex", str(mediaSources[0].get('DefaultSubtitleStreamIndex')))
#launch the playback - only set the listitem props if we're not using the setresolvedurl approach #launch the playback - only set the listitem props if we're not using the setresolvedurl approach
if setup == "service": if setup == "service":
@ -174,6 +165,76 @@ class PlaybackUtils():
else: else:
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
def audioSubsPref(self, url, mediaSources):
WINDOW = xbmcgui.Window(10000)
# Present the list of audio to select from
audioStreamsList = {}
audioStreams = []
selectAudioIndex = ""
subtitleStreamsList = {}
subtitleStreams = ['No subtitles']
selectSubsIndex = ""
playurlprefs = "%s" % url
mediaStream = mediaSources[0].get('MediaStreams')
for stream in mediaStream:
index = stream['Index']
# Since Emby returns all possible tracks together, have to sort them.
if 'Audio' in stream['Type']:
try:
track = stream['Language']
audioStreamsList[track] = index
audioStreams.append(track)
except:
track = stream['Codec']
audioStreamsList[track] = index
audioStreams.append(track)
elif 'Subtitle' in stream['Type']:
try:
track = stream['Language']
subtitleStreamsList[track] = index
subtitleStreams.append(track)
except:
track = stream['Codec']
subtitleStreamsList[track] = index
subtitleStreams.append(track)
if len(audioStreams) > 1:
resp = xbmcgui.Dialog().select("Choose the audio stream", audioStreams)
if resp > -1:
# User selected audio
selected = audioStreams[resp]
selected_audioIndex = audioStreamsList[selected]
playurlprefs += "&AudioStreamIndex=%s" % selected_audioIndex
selectAudioIndex = str(selected_audioIndex)
else: return False
else: # There's only one audiotrack.
audioIndex = audioStreamsList[audioStreams[0]]
playurlprefs += "&AudioStreamIndex=%s" % audioIndex
selectAudioIndex = str(audioIndex)
if len(subtitleStreams) > 1:
resp = xbmcgui.Dialog().select("Choose the subtitle stream", subtitleStreams)
if resp == 0:
# User selected no subtitles
pass
elif resp > -1:
# User selected subtitles
selected = subtitleStreams[resp]
selected_subsIndex = subtitleStreamsList[selected]
playurlprefs += "&SubtitleStreamIndex=%s" % selected_subsIndex
selectSubsIndex = str(selected_subsIndex)
else: return False
# Reset the method with the new playurl
WINDOW.setProperty("%splaymethod" % playurlprefs, "Transcode")
WINDOW.setProperty("%sAudioStreamIndex" % playurlprefs, selectAudioIndex)
WINDOW.setProperty("%sSubtitleStreamIndex" % playurlprefs, selectSubsIndex)
return playurlprefs
def setArt(self, list,name,path): def setArt(self, list,name,path):
if name=='thumb' or name=='fanart_image' or name=='small_poster' or name=='tiny_poster' or name == "medium_landscape" or name=='medium_poster' or name=='small_fanartimage' or name=='medium_fanartimage' or name=='fanart_noindicators': if name=='thumb' or name=='fanart_image' or name=='small_poster' or name=='tiny_poster' or name == "medium_landscape" or name=='medium_poster' or name=='small_fanartimage' or name=='medium_fanartimage' or name=='fanart_noindicators':
list.setProperty(name, path) list.setProperty(name, path)

View file

@ -68,6 +68,8 @@ class Player( xbmc.Player ):
def stopAll(self): def stopAll(self):
WINDOW = xbmcgui.Window(10000)
if(len(self.played_information) == 0): if(len(self.played_information) == 0):
return return
@ -86,6 +88,7 @@ class Player( xbmc.Player ):
refresh_id = data.get("refresh_id") refresh_id = data.get("refresh_id")
currentFile = data.get("currentfile") currentFile = data.get("currentfile")
type = data.get("Type") type = data.get("Type")
playMethod = data.get('playmethod')
# Prevent websocket feedback # Prevent websocket feedback
self.WINDOW.setProperty("played_itemId", item_id) self.WINDOW.setProperty("played_itemId", item_id)
@ -116,12 +119,12 @@ class Player( xbmc.Player ):
listItem = [item_id] listItem = [item_id]
LibrarySync().removefromDB(listItem, True) LibrarySync().removefromDB(listItem, True)
# Stop transcoding # Stop transcoding
if self.WINDOW.getProperty("transcoding%s" % item_id) == "true": if playMethod == "Transcode":
deviceId = self.clientInfo.getMachineId() self.logMsg("Transcoding for %s terminated." % item_id)
url = "{server}/mediabrowser/Videos/ActiveEncodings?DeviceId=%s" % deviceId deviceId = self.clientInfo.getMachineId()
self.doUtils.downloadUrl(url, type="DELETE") url = "{server}/mediabrowser/Videos/ActiveEncodings?DeviceId=%s" % deviceId
self.WINDOW.clearProperty("transcoding%s" % item_id) self.doUtils.downloadUrl(url, type="DELETE")
self.played_information.clear() self.played_information.clear()
@ -190,11 +193,38 @@ class Player( xbmc.Player ):
if playTime: if playTime:
postdata['PositionTicks'] = int(playTime * 10000000) postdata['PositionTicks'] = int(playTime * 10000000)
if audioindex: if playMethod != "Transcode":
postdata['AudioStreamIndex'] = audioindex # Get current audio and subtitles track
track_query = '{"jsonrpc": "2.0", "method": "Player.GetProperties", "params": {"playerid":1,"properties": ["currentsubtitle","currentaudiostream","subtitleenabled"]} , "id": 1}'
result = xbmc.executeJSONRPC(track_query)
result = json.loads(result)
indexAudio = result['result']['currentaudiostream']['index']
indexSubs = result['result']['currentsubtitle']['index']
subsEnabled = result['result']['subtitleenabled']
if subtitleindex: # Convert back into an Emby index
postdata['SubtitleStreamIndex'] = subtitleindex audioTracks = len(xbmc.Player().getAvailableAudioStreams())
indexAudio = indexAudio + 1
if subsEnabled:
indexSubs = indexSubs + audioTracks + 1
else:
indexSubs = ""
if audioindex == indexAudio:
postdata['AudioStreamIndex'] = audioindex
else:
postdata['AudioStreamIndex'] = indexAudio
data['AudioStreamIndex'] = indexAudio
if subtitleindex == indexSubs:
postdata['SubtitleStreamIndex'] = subtitleindex
else:
postdata['SubtitleStreamIndex'] = indexSubs
data['SubtitleStreamIndex'] = indexSubs
else:
data['AudioStreamIndex'] = audioindex
data['SubtitleStreamIndex'] = subtitleindex
postdata = json.dumps(postdata) postdata = json.dumps(postdata)
self.logMsg("Report: %s" % postdata, 2) self.logMsg("Report: %s" % postdata, 2)
@ -227,7 +257,7 @@ class Player( xbmc.Player ):
def onPlayBackStarted( self ): def onPlayBackStarted( self ):
# Will be called when xbmc starts playing a file # Will be called when xbmc starts playing a file
WINDOW = self.WINDOW WINDOW = xbmcgui.Window(10000)
addon = self.addon addon = self.addon
xbmcplayer = self.xbmcplayer xbmcplayer = self.xbmcplayer
self.stopAll() self.stopAll()
@ -255,8 +285,6 @@ class Player( xbmc.Player ):
# only ever use the win props here, use the data map in all other places # only ever use the win props here, use the data map in all other places
runtime = WINDOW.getProperty(currentFile + "runtimeticks") runtime = WINDOW.getProperty(currentFile + "runtimeticks")
refresh_id = WINDOW.getProperty(currentFile + "refresh_id") refresh_id = WINDOW.getProperty(currentFile + "refresh_id")
audioindex = WINDOW.getProperty(currentFile + "AudioStreamIndex")
subtitleindex = WINDOW.getProperty(currentFile + "SubtitleStreamIndex")
playMethod = WINDOW.getProperty(currentFile + "playmethod") playMethod = WINDOW.getProperty(currentFile + "playmethod")
itemType = WINDOW.getProperty(currentFile + "type") itemType = WINDOW.getProperty(currentFile + "type")
@ -281,11 +309,27 @@ class Player( xbmc.Player ):
'IsMuted': muted 'IsMuted': muted
} }
if audioindex: # Get the current audio track and subtitles
if playMethod == "Transcode":
audioindex = WINDOW.getProperty(currentFile + "AudioStreamIndex")
subtitleindex = WINDOW.getProperty(currentFile + "SubtitleStreamIndex")
postdata['AudioStreamIndex'] = audioindex postdata['AudioStreamIndex'] = audioindex
if subtitleindex:
postdata['SubtitleStreamIndex'] = subtitleindex postdata['SubtitleStreamIndex'] = subtitleindex
else:
track_query = '{"jsonrpc": "2.0", "method": "Player.GetProperties", "params": {"playerid": 1,"properties": ["currentsubtitle","currentaudiostream","subtitleenabled"]} , "id": 1}'
result = xbmc.executeJSONRPC(track_query)
result = json.loads(result)
indexAudio = result['result']['currentaudiostream']['index']
indexSubs = result['result']['currentsubtitle']['index']
subsEnabled = result['result']['subtitleenabled']
postdata['AudioStreamIndex'] = indexAudio + 1
if subsEnabled:
audioTracks = len(xbmc.Player().getAvailableAudioStreams())
postdata['SubtitleStreamIndex'] = indexSubs + audioTracks + 1
else:
postdata['SubtitleStreamIndex'] = ""
# Post playback to server # Post playback to server
self.logMsg("Sending POST play started.", 1) self.logMsg("Sending POST play started.", 1)
@ -297,8 +341,8 @@ class Player( xbmc.Player ):
'item_id': item_id, 'item_id': item_id,
'refresh_id': refresh_id, 'refresh_id': refresh_id,
'currentfile': currentFile, 'currentfile': currentFile,
'AudioStreamIndex': audioindex, 'AudioStreamIndex': postdata['AudioStreamIndex'],
'SubtitleStreamIndex': subtitleindex, 'SubtitleStreamIndex': postdata['SubtitleStreamIndex'],
'playmethod': playMethod, 'playmethod': playMethod,
'Type': itemType, 'Type': itemType,
'currentPosition': int(seekTime) 'currentPosition': int(seekTime)
@ -349,4 +393,4 @@ class Player( xbmc.Player ):
def onPlayBackStopped( self ): def onPlayBackStopped( self ):
# Will be called when user stops xbmc playing a file # Will be called when user stops xbmc playing a file
self.logMsg("onPlayBackStopped", 0) self.logMsg("onPlayBackStopped", 0)
self.stopAll() self.stopAll()

View file

@ -96,7 +96,7 @@ class WebSocketThread(threading.Thread):
xbmc.executebuiltin("Dialog.Close(all,true)") xbmc.executebuiltin("Dialog.Close(all,true)")
xbmc.executebuiltin("XBMC.Notification(Playlist: Added %s items to Playlist,)" % len(itemIds)) xbmc.executebuiltin("XBMC.Notification(Playlist: Added %s items to Playlist,)" % len(itemIds))
PlaybackUtils().PLAYAllItems(itemIds, startPositionTicks) PlaybackUtils().PLAYAllItems(itemIds, startPositionTicks)
# Don't think this is being used.
elif "PlayNext" in playCommand: elif "PlayNext" in playCommand:
xbmc.executebuiltin("XBMC.Notification(Playlist: Added %s items to Playlist,)" % len(itemIds)) xbmc.executebuiltin("XBMC.Notification(Playlist: Added %s items to Playlist,)" % len(itemIds))
playlist = PlaybackUtils().AddToPlaylist(itemIds) playlist = PlaybackUtils().AddToPlaylist(itemIds)
@ -155,7 +155,7 @@ class WebSocketThread(threading.Thread):
command = data['Name'] command = data['Name']
arguments = data.get("Arguments") arguments = data.get("Arguments")
if command in ('Mute', 'Unmute', 'SetVolume'): if command in ('Mute', 'Unmute', 'SetVolume', 'SetSubtitleStreamIndex', 'SetAudioStreamIndex'):
# These commands need to be reported back # These commands need to be reported back
if command == "Mute": if command == "Mute":
xbmc.executebuiltin('Mute') xbmc.executebuiltin('Mute')
@ -164,6 +164,14 @@ class WebSocketThread(threading.Thread):
elif command == "SetVolume": elif command == "SetVolume":
volume = arguments['Volume'] volume = arguments['Volume']
xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume) xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume)
elif command == "SetSubtitleStreamIndex":
# Emby merges audio and subtitle index together
audioTracks = len(xbmc.Player().getAvailableAudioStreams())
index = int(arguments['Index']) - audioTracks
xbmc.Player().setSubtitleStream(index - 1)
elif command == "SetAudioStreamIndex":
index = int(arguments['Index'])
xbmc.Player().setAudioStream(index - 1)
# Report playback # Report playback
WINDOW.setProperty('commandUpdate', "true") WINDOW.setProperty('commandUpdate', "true")

View file

@ -33,8 +33,6 @@
<setting id="resumeJumpBack" type="slider" label="On Resume Jump Back Seconds" default="10" range="0,1,120" option="int" visible="true" enable="true" /> <setting id="resumeJumpBack" type="slider" label="On Resume Jump Back Seconds" default="10" range="0,1,120" option="int" visible="true" enable="true" />
<setting id="playFromStream" type="bool" label="30002" visible="true" enable="true" default="false" /> <setting id="playFromStream" type="bool" label="30002" visible="true" enable="true" default="false" />
<setting id="videoBitRate" type="enum" label="30160" values="664 Kbps SD|996 Kbps HD|1.3 Mbps HD|2.0 Mbps HD|3.2 Mbps HD|4.7 Mbps HD|6.2 Mbps HD|7.7 Mbps HD|9.2 Mbps HD|10.7 Mbps HD|12.2 Mbps HD|13.7 Mbps HD|15.2 Mbps HD|16.7 Mbps HD|18.2 Mbps HD|20.0 Mbps HD|40.0 Mbps HD|100.0 Mbps HD [default]|1000.0 Mbps HD" visible="eq(-1,true)" default="17" /> <setting id="videoBitRate" type="enum" label="30160" values="664 Kbps SD|996 Kbps HD|1.3 Mbps HD|2.0 Mbps HD|3.2 Mbps HD|4.7 Mbps HD|6.2 Mbps HD|7.7 Mbps HD|9.2 Mbps HD|10.7 Mbps HD|12.2 Mbps HD|13.7 Mbps HD|15.2 Mbps HD|16.7 Mbps HD|18.2 Mbps HD|20.0 Mbps HD|40.0 Mbps HD|100.0 Mbps HD [default]|1000.0 Mbps HD" visible="eq(-1,true)" default="17" />
<setting id="forceTranscodingCodecs" type="text" label="30245" visible="false" />
<setting id="subsoverride" type="bool" label="Always display subtitles" default="false" enable="true" visible="true" />
</category> </category>
<category label="Extras"> <category label="Extras">
<setting id="disableCoverArt" type="bool" label="30157" default="false" visible="true" enable="true" /> <setting id="disableCoverArt" type="bool" label="30157" default="false" visible="true" enable="true" />