Centralize Direct Play and Direct Paths

This commit is contained in:
tomkat83 2016-04-12 17:18:32 +02:00
parent e4aefaaa5e
commit 9d06225228
6 changed files with 180 additions and 147 deletions

View file

@ -2,7 +2,7 @@
<strings>
<!-- Add-on settings -->
<string id="30000">Server Address (IP)</string><!-- Verified -->
<string id="30002">Deactivate Direct Play and enforce Transcoding</string><!-- Verified -->
<string id="30002">Prefered playback method</string><!-- Verified -->
<string id="30004">Log level</string><!-- Verified -->
<string id="30005">Username: </string>
<string id="30006">Password: </string>
@ -130,7 +130,7 @@
<string id="30157">Enable Enhanced Images (eg CoverArt)</string><!-- Verified -->
<string id="30158">Metadata</string>
<string id="30159">Artwork</string>
<string id="30160">Video Quality</string><!-- Verified -->
<string id="30160">Video Quality for Transcoding</string><!-- Verified -->
<string id="30161">Enable Suggested Loader (Requires Restart)</string>
<string id="30162">Add Season Number</string>
@ -298,7 +298,7 @@
<string id="30533">Duration of the music library pop up (in seconds)</string>
<string id="30534">Server messages</string>
<string id="30535">[COLOR yellow]Generate a new unique device Id (e.g. when cloning Kodi)[/COLOR]</string>
<string id="30536">Users must log in every time when Kodi restarts</string>
<string id="30536">Users must log in every time Kodi restarts</string>
<string id="30537">RESTART KODI IF YOU MAKE ANY CHANGES</string>
<string id="30538">Complete Re-Sync necessary</string>
@ -384,7 +384,7 @@
<string id="39040">Replace Plex TV SHOWS with:</string>
<string id="39041">Original Plex MUSIC path to replace:</string>
<string id="39042">Replace Plex MUSIC with:</string>
<string id="39043">Go a step further and complete replace all original Plex library paths (/volume1/media) with custom SMB paths (smb://NAS/MyStuff)?</string>
<string id="39043">Go a step further and completely replace all original Plex library paths (/volume1/media) with custom SMB paths (smb://NAS/MyStuff)?</string>
<string id="39044">Please enter your custom smb paths in the settings under "Sync Options" and then restart Kodi</string>
<string id="39045">Appearance Tweaks</string>
@ -398,8 +398,8 @@
<string id="39053">Do a full library sync every x minutes</string>
<string id="39054">remote</string>
<string id="39055">Searching for Plex Server</string>
<string id="39056">Used by Sync and when attempting to Direct Play</string>
<string id="39057">Customize Paths</string>
<!-- Plex Entrypoint.py -->
<string id="39200">Log-out Plex Home User </string>

View file

@ -2,7 +2,7 @@
<strings>
<string id="30000">IP-Adresse des Servers</string>
<string id="30001">Automatisches Öffnen von Ordnern mit einem Eintrag</string>
<string id="30002">Direct Play deaktivieren and Transkodieren erzwingen</string>
<string id="30002">Gewünschte Wiedergabe-Methode</string>
<string id="30004">Log Level:</string>
<string id="30005">Benutzername: </string>
<string id="30006">Passwort: </string>
@ -163,7 +163,7 @@
<string id="30157">Deaktiviere erweiterte Bilder (z.B. CoverArt)</string>
<string id="30158">Metadaten</string>
<string id="30159">Grafiken</string>
<string id="30160">Videoqualität</string>
<string id="30160">Videoqualität für Transkodierung</string>
<string id="30161">'Empfohlen'-Loader aktivieren (Erfordert Neustart)</string>
<string id="30162">Staffelnummer hinzufügen</string>
@ -336,6 +336,9 @@
<string id="39053">Kompletten Scan aller Bibliotheken alle x Minuten durchführen</string>
<string id="39054">remote</string>
<string id="39055">Suche Plex Server</string>
<string id="39056">Verwendet für Synchronisierung sowie beim Versuch, Direct Play zu nutzen</string>
<string id="39057">Pfade ändern</string>
<!-- Plex Entrypoint.py -->

View file

@ -394,7 +394,7 @@ class PlexAPI():
name, scheme, ip, port, type, owned, token
"""
address = ip + ':' + port
baseURL = scheme+'://'+ip+':'+port
baseURL = scheme + '://' + ip + ':' + port
self.g_PMS[uuid] = {
'name': name,
'scheme': scheme,
@ -485,7 +485,8 @@ class PlexAPI():
elif "Resource-Identifier:" in each:
update['uuid'] = each.split(':')[1].strip()
elif "Name:" in each:
update['serverName'] = each.split(':')[1].strip().decode('utf-8', 'replace')
update['serverName'] = each.split(
':')[1].strip().decode('utf-8', 'replace')
elif "Port:" in each:
update['port'] = each.split(':')[1].strip()
elif "Updated-At:" in each:
@ -582,8 +583,8 @@ class PlexAPI():
PMS = {}
PMS['name'] = Dir.get('name')
infoAge = time.time() - int(Dir.get('lastSeenAt'))
oneDayInSec = 60*60*24
if infoAge > 2*oneDayInSec:
oneDayInSec = 60 * 60 * 24
if infoAge > 2 * oneDayInSec:
self.logMsg("Server %s not seen for 2 days - "
"skipping." % PMS['name'], 0)
continue
@ -628,22 +629,22 @@ class PlexAPI():
# declare new PMSs
while not queue.empty():
PMS = queue.get()
self.declarePMS(PMS['uuid'], PMS['name'],
PMS['protocol'], PMS['ip'], PMS['port'])
# dflt: token='', local, owned - updated later
self.updatePMSProperty(
PMS['uuid'], 'accesstoken', PMS['token'])
self.updatePMSProperty(
PMS['uuid'], 'owned', PMS['owned'])
self.updatePMSProperty(
PMS['uuid'], 'local', PMS['local'])
# set in declarePMS, overwrite for https encryption
self.updatePMSProperty(
PMS['uuid'], 'baseURL', PMS['baseURL'])
self.updatePMSProperty(
PMS['uuid'], 'ownername', PMS['ownername'])
queue.task_done()
PMS = queue.get()
self.declarePMS(PMS['uuid'], PMS['name'],
PMS['protocol'], PMS['ip'], PMS['port'])
# dflt: token='', local, owned - updated later
self.updatePMSProperty(
PMS['uuid'], 'accesstoken', PMS['token'])
self.updatePMSProperty(
PMS['uuid'], 'owned', PMS['owned'])
self.updatePMSProperty(
PMS['uuid'], 'local', PMS['local'])
# set in declarePMS, overwrite for https encryption
self.updatePMSProperty(
PMS['uuid'], 'baseURL', PMS['baseURL'])
self.updatePMSProperty(
PMS['uuid'], 'ownername', PMS['ownername'])
queue.task_done()
def pokePMS(self, PMS, queue):
# Ignore SSL certificates for now
@ -708,9 +709,10 @@ class PlexAPI():
"""
# provide credentials
### optional... when 'realm' is unknown
# optional... when 'realm' is unknown
##passmanager = urllib2.HTTPPasswordMgrWithDefaultRealm()
##passmanager.add_password(None, address, username, password) # None: default "realm"
# passmanager.add_password(None, address, username, password) # None:
# default "realm"
passmanager = urllib2.HTTPPasswordMgr()
passmanager.add_password(MyPlexHost, MyPlexURL, username, password)
authhandler = urllib2.HTTPBasicAuthHandler(passmanager)
@ -746,9 +748,11 @@ class PlexAPI():
MyPlexURL = 'http://' + MyPlexHost + MyPlexSignOutPath
# create POST request
xargs = { 'X-Plex-Token': authtoken }
xargs = {'X-Plex-Token': authtoken}
request = urllib2.Request(MyPlexURL, None, xargs)
request.get_method = lambda: 'POST' # turn into 'POST' - done automatically with data!=None. But we don't have data.
# turn into 'POST' - done automatically with data!=None. But we don't
# have data.
request.get_method = lambda: 'POST'
response = urllib2.urlopen(request).read()
@ -1005,12 +1009,12 @@ class PlexAPI():
if key.startswith('http://') or key.startswith('https://'): # external address - keep
path = key
else:
if AuthToken=='':
if AuthToken == '':
path = key
else:
xargs = dict()
xargs['X-Plex-Token'] = AuthToken
if key.find('?')==-1:
if key.find('?') == -1:
path = key + '?' + urlencode(xargs)
else:
path = key + '&' + urlencode(xargs)
@ -1040,14 +1044,15 @@ class PlexAPI():
# This is bogus (note the extra path component) but ATV is stupid when it comes to caching images, it doesn't use querystrings.
# Fortunately PMS is lenient...
transcodePath = '/photo/:/transcode/' +str(width)+'x'+str(height)+ '/' + quote_plus(path)
transcodePath = '/photo/:/transcode/' + \
str(width) + 'x' + str(height) + '/' + quote_plus(path)
args = dict()
args['width'] = width
args['height'] = height
args['url'] = path
if not AuthToken=='':
if not AuthToken == '':
args['X-Plex-Token'] = AuthToken
return transcodePath + '?' + urlencode(args)
@ -1062,10 +1067,10 @@ class PlexAPI():
result:
final path to image file
"""
if not AuthToken=='':
if not AuthToken == '':
xargs = dict()
xargs['X-Plex-Token'] = AuthToken
if path.find('?')==-1:
if path.find('?') == -1:
path = path + '?' + urlencode(xargs)
else:
path = path + '&' + urlencode(xargs)
@ -1095,7 +1100,7 @@ class PlexAPI():
args['maxAudioBitrate'] = maxAudioBitrate
xargs = clientinfo.ClientInfo().getXArgsDeviceInfo(options)
if not AuthToken=='':
if not AuthToken == '':
xargs['X-Plex-Token'] = AuthToken
return transcodePath + urlencode(args) + '&' + urlencode(xargs)
@ -1110,10 +1115,10 @@ class PlexAPI():
result:
final path to audio file
"""
if not AuthToken=='':
if not AuthToken == '':
xargs = dict()
xargs['X-Plex-Token'] = AuthToken
if path.find('?')==-1:
if path.find('?') == -1:
path = path + '?' + urlencode(xargs)
else:
path = path + '&' + urlencode(xargs)
@ -1229,7 +1234,7 @@ class API():
res = self.item[0][self.part].attrib.get('file')
except:
res = None
if res:
if res is not None:
res = unquote(res).decode('utf-8')
return res
@ -1946,7 +1951,8 @@ class API():
kodiindex = 0
for stream in mediastreams:
index = stream.attrib['id']
# Since Emby returns all possible tracks together, have to pull only external subtitles.
# Since Emby returns all possible tracks together, have to pull
# only external subtitles.
key = stream.attrib.get('key')
# IsTextSubtitleStream if true, is available to download from emby.
if stream.attrib.get('streamType') == "3" and key:
@ -2031,27 +2037,61 @@ class API():
listItem.addStreamInfo(
"video", {'duration': self.getRuntime()[1]})
def validatePlayurl(self, playurl, typus):
def validatePlayurl(self, path, typus, forceCheck=False):
"""
Returns a valid url for Kodi, e.g. with substituted path
Returns a valid path for Kodi, e.g. with '\' substituted to '\\' in
Unicode. Returns None if this is not possible
path : Unicode
typus : Plex type from PMS xml
forceCheck : Will always try to check validity of path
Will also skip confirmation dialog if path not found
"""
if path is None:
return None
types = {
'movie': 'movie',
'show': 'tv',
'season': 'tv',
'episode': 'tv',
'artist': 'music',
'album': 'music',
'song': 'music',
'track': 'music',
}
typus = types[typus]
if utils.window('remapSMB') == 'true':
playurl = playurl.replace(utils.window('remapSMB%sOrg' % typus),
utils.window('remapSMB%sNew' % typus))
path = path.replace(utils.window('remapSMB%sOrg' % typus),
utils.window('remapSMB%sNew' % typus))
# There might be backslashes left over:
playurl = playurl.replace('\\', '/')
path = path.replace('\\', '/')
elif utils.window('replaceSMB') == 'true':
if playurl.startswith('\\\\'):
playurl = 'smb:' + playurl.replace('\\', '/')
if (utils.window('emby_pathverified') != "true" and
not xbmcvfs.exists(playurl.encode('utf-8'))):
# Validate the path is correct with user intervention
if self.askToValidate(playurl):
utils.window('emby_shouldStop', value="true")
playurl = False
utils.window('emby_pathverified', value='true')
utils.settings('emby_pathverified', value='true')
return playurl
if path.startswith('\\\\'):
path = 'smb:' + path.replace('\\', '/')
if utils.window('emby_pathverified') == 'true' and forceCheck is False:
return path
check = xbmcvfs.exists(path.encode('utf-8'))
# exists() NEEDS either a '/' or '\\' at the end of a DIR name
if check is False:
check = xbmcvfs.exists((path + '/').encode('utf-8'))
if check is False:
check = xbmcvfs.exists((path + '\\').encode('utf-8'))
if check is False:
if forceCheck is False:
# Validate the path is correct with user intervention
if self.askToValidate(path):
utils.window('emby_shouldStop', value="true")
path = None
utils.window('emby_pathverified', value='true')
utils.settings('emby_pathverified', value='true')
else:
path = None
elif forceCheck is False:
if utils.window('emby_pathverified') != 'true':
utils.window('emby_pathverified', value='true')
utils.settings('emby_pathverified', value='true')
return path
def askToValidate(self, url):
"""

View file

@ -440,8 +440,8 @@ class Movies(Items):
# Something went wrong, trying to use non-direct paths
doIndirect = True
else:
playurl = API.validatePlayurl(playurl, 'movie')
if playurl is False:
playurl = API.validatePlayurl(playurl, API.getType())
if playurl is None:
return False
if "\\" in playurl:
# Local path
@ -450,7 +450,6 @@ class Movies(Items):
# Network share
filename = playurl.rsplit("/", 1)[1]
path = playurl.replace(filename, "")
utils.window('emby_pathverified', value="true")
if doIndirect:
# Set plugin path and media flags using real filename
path = "plugin://plugin.video.plexkodiconnect.movies/"
@ -1041,8 +1040,8 @@ class TVShows(Items):
# Something went wrong, trying to use non-direct paths
doIndirect = True
else:
playurl = API.validatePlayurl(playurl, 'tv')
if playurl is False:
playurl = API.validatePlayurl(playurl, API.getType())
if playurl is None:
return False
if "\\" in playurl:
# Local path
@ -1052,12 +1051,6 @@ class TVShows(Items):
# Network path
path = "%s/" % playurl
toplevelpath = "%s/" % dirname(dirname(path))
if (utils.window('emby_pathverified') != "true" and
not xbmcvfs.exists(path.encode('utf-8'))):
# Validate the path is correct with user intervention
if self.askToValidate(playurl):
return False
utils.window('emby_pathverified', value="true")
if doIndirect:
# Set plugin path
toplevelpath = "plugin://plugin.video.plexkodiconnect.tvshows/"
@ -1331,14 +1324,9 @@ class TVShows(Items):
# Something went wrong, trying to use non-direct paths
doIndirect = True
else:
playurl = API.validatePlayurl(playurl, 'tv')
if playurl is False:
playurl = API.validatePlayurl(playurl, API.getType())
if playurl is None:
return False
if (utils.window('emby_pathverified') != "true" and
not xbmcvfs.exists(playurl.encode('utf-8'))):
# Validate the path is correct with user intervention
if self.askToValidate(playurl):
return False
if "\\" in playurl:
# Local path
filename = playurl.rsplit("\\", 1)[1]
@ -1346,7 +1334,6 @@ class TVShows(Items):
# Network share
filename = playurl.rsplit("/", 1)[1]
path = playurl.replace(filename, "")
utils.window('emby_pathverified', value="true")
if doIndirect:
# Set plugin path and media flags using real filename
path = "plugin://plugin.video.plexkodiconnect.movies/"
@ -2085,14 +2072,9 @@ class Music(Items):
# Something went wrong, trying to use non-direct paths
doIndirect = True
else:
playurl = API.validatePlayurl(playurl, 'music')
if playurl is False:
playurl = API.validatePlayurl(playurl, API.getType())
if playurl is None:
return False
if (utils.window('emby_pathverified') != "true" and
not xbmcvfs.exists(playurl.encode('utf-8'))):
# Validate the path is correct with user intervention
if self.askToValidate(playurl):
return False
if "\\" in playurl:
# Local path
filename = playurl.rsplit("\\", 1)[1]
@ -2100,7 +2082,6 @@ class Music(Items):
# Network share
filename = playurl.rsplit("/", 1)[1]
path = playurl.replace(filename, "")
utils.window('emby_pathverified', value="true")
if doIndirect:
# Plex works a bit differently
path = "%s%s" % (self.server, item[0][0].attrib.get('key'))

View file

@ -91,34 +91,25 @@ class PlayUtils():
Returns the path/playurl if successful, False otherwise
"""
# Requirement: Filesystem, Accessible path
if utils.settings('playFromStream') == "true":
# set to either 'Direct Stream=1' or 'Transcode=2'
if utils.settings('playType') != "0":
# User forcing to play via HTTP
self.logMsg("Can't direct play, user enabled play from HTTP.", 1)
self.logMsg("User chose to not direct play", 1)
return False
if self.h265enabled():
return False
path = self.API.getFilePath()
path = self.API.validatePlayurl(self.API.getFilePath(),
self.API.getType(),
forceCheck=True)
if path is None:
self.logMsg('PMS item does not have a filepath', 2)
return False
# Assign network protocol
if path.startswith('\\\\'):
path = path.replace('\\\\', 'smb://')
path = path.replace('\\', '/')
# Plex returns Windows paths as e.g. 'c:\slfkjelf\slfje\file.mkv'
elif '\\' in path:
path = path.replace('\\', '\\\\')
if xbmcvfs.exists(path):
self.logMsg('Kodi can access file %s - direct playing' % path, 2)
return path
else:
self.logMsg('Kodi cannot access file %s - no direct play'
% path, 2)
% path, 1)
return False
else:
self.logMsg('Kodi can access file %s - direct playing' % path, 1)
return path
def directPlay(self):
@ -198,13 +189,17 @@ class PlayUtils():
return False
def isDirectStream(self):
if not self.h265enabled():
# set to 'Transcode=2'
if utils.settings('playType') == "2":
# User forcing to play via HTTP
self.logMsg("User chose to transcode", 1)
return False
if self.h265enabled():
return False
# Verify the bitrate
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. Transcoding", 1)
return False
return True
@ -228,11 +223,18 @@ class PlayUtils():
return playurl
def isNetworkSufficient(self):
"""
Returns True if the network is sufficient (set in file settings)
"""
try:
sourceBitrate = int(self.API.getDataFromPartOrMedia('bitrate'))
except:
self.logMsg('Could not detect source bitrate. It is assumed to be'
'sufficient', 1)
return True
settings = self.getBitrate()
sourceBitrate = int(self.API.getDataFromPartOrMedia('bitrate'))
self.logMsg("The add-on settings bitrate is: %s, the video bitrate required is: %s" % (settings, sourceBitrate), 1)
self.logMsg("The add-on settings bitrate is: %s, the video bitrate"
"required is: %s" % (settings, sourceBitrate), 1)
if settings < sourceBitrate:
return False
return True

View file

@ -37,13 +37,7 @@
<setting id="plexToken" label="plexToken" type="text" default="" visible="false" />
<setting id="plexHomeSize" type="number" default="1" visible="false" />
</category>
<category label="Plex Companion">
<setting type="lsep" label="39008" />
<setting id="plexCompanion" label="39004" type="bool" default="true" />
<setting id="deviceNameOpt" label="30504" type="bool" default="false" />
<setting id="deviceName" label="30016" type="text" visible="eq(-1,true)" default="Kodi" />
<setting id="companionPort" label="39005" type="number" default="3005" option="int" visible="eq(-3,true)"/>
</category>
<category label="30506"><!-- Sync Options -->
<setting type="lsep" label="30537" /><!-- Restart if you make changes -->
<setting id="syncEmptyShows" type="bool" label="30508" default="false" visible="false"/>
@ -63,14 +57,7 @@
<setting type="lsep" label="30538" /><!-- Complete Re-Sync necessary -->
<setting id="enableMusic" type="bool" label="30509" default="true" />
<setting id="useDirectPaths" type="enum" label="30511" values="Addon(Default)|Native(Direct paths)" default="0" visible="true"/> <!-- Playback mode -->
<setting id="replaceSMB" type="bool" label="39034" default="true" visible="eq(-1,1)"/> <!-- replace all Plex paths with SMB paths -->
<setting id="remapSMB" type="bool" label="39035" default="false" visible="eq(-2,1)"/> <!-- replace Plex paths /volume1/media or \\myserver\media with a custom SMB path smb://NAS/mystuff -->
<setting id="remapSMBmovieOrg" type="text" label="39037" default="" visible="eq(-1,true)"/> <!-- Original Plex MOVIE path to replace -->
<setting id="remapSMBmovieNew" type="text" label="39038" default="smb://" visible="eq(-2,true)"/> <!-- Replace Plex MOVIE with: -->
<setting id="remapSMBtvOrg" type="text" label="39039" default="" visible="eq(-3,true)"/> <!-- Original Plex TV SHOWS path to replace: -->
<setting id="remapSMBtvNew" type="text" label="39040" default="smb://" visible="eq(-4,true)"/> <!-- Replace Plex TV SHOWS with: -->
<setting id="remapSMBmusicOrg" type="text" label="39041" default="" visible="eq(-5,true)"/> <!-- Original Plex MUSIC path to replace: -->
<setting id="remapSMBmusicNew" type="text" label="39042" default="smb://" visible="eq(-6,true)"/> <!-- Replace Plex MUSIC with: -->
<setting id="streamMusic" type="bool" label="30510" default="false" visible="false" subsetting="true"/> <!-- Direct stream Music library -->
<setting type="lsep" label="30523" visible="false"/> <!-- Music metadata options -->
@ -81,6 +68,18 @@
<setting id="emby_pathverified" type="bool" default="false" visible="false" /> <!-- If 'false': one single warning message pops up if PKC cannot verify direct paths -->
</category>
<category label="39057"><!-- Customize Paths -->
<setting type="lsep" label="39056" /><!-- Used by Sync and to attempt to direct play -->
<setting id="replaceSMB" type="bool" label="39034" default="true" /> <!-- replace all Plex paths with SMB paths -->
<setting id="remapSMB" type="bool" label="39035" default="false" /> <!-- replace Plex paths /volume1/media or \\myserver\media with a custom SMB path smb://NAS/mystuff -->
<setting id="remapSMBmovieOrg" type="text" label="39037" default="" visible="eq(-1,true)"/> <!-- Original Plex MOVIE path to replace -->
<setting id="remapSMBmovieNew" type="text" label="39038" default="smb://" visible="eq(-2,true)"/> <!-- Replace Plex MOVIE with: -->
<setting id="remapSMBtvOrg" type="text" label="39039" default="" visible="eq(-3,true)"/> <!-- Original Plex TV SHOWS path to replace: -->
<setting id="remapSMBtvNew" type="text" label="39040" default="smb://" visible="eq(-4,true)"/> <!-- Replace Plex TV SHOWS with: -->
<setting id="remapSMBmusicOrg" type="text" label="39041" default="" visible="eq(-5,true)"/> <!-- Original Plex MUSIC path to replace: -->
<setting id="remapSMBmusicNew" type="text" label="39042" default="smb://" visible="eq(-6,true)"/> <!-- Replace Plex MUSIC with: -->
</category>
<category label="30516"><!-- Playback -->
<setting type="sep" />
<setting id="enableCinema" type="bool" label="30518" default="true" />
@ -92,15 +91,16 @@
<setting id="deleteMovies" type="bool" label="30116" visible="eq(-2,true)" default="false" subsetting="true" />
<setting id="resumeJumpBack" type="slider" label="30521" default="10" range="0,1,120" option="int" />
<setting type="sep" />
<setting id="playFromStream" type="bool" label="30002" default="false" />
<setting id="transcoderVideoQualities" type="enum" label="30160" values="420x420, 320Kbps|576x320, 720Kbps|720x480, 1.5Mbps|1024x768, 2Mbps|1280x720, 3Mbps|1280x720, 4Mbps|1920x1080, 8Mbps|1920x1080, 10Mbps|1920x1080, 12Mbps|1920x1080, 20Mbps|1920x1080, 40Mbps" visible="eq(-1,true)" default="11" />
<setting id="audioBoost" type="slider" label="39001" default="0" range="0,10,100" option="int"/>
<setting id="playType" type="enum" label="30002" values="Direct Play (default)|Direct Stream|Force Transcode" default="0" />
<setting id="transcoderVideoQualities" type="enum" label="30160" values="420x420, 320Kbps|576x320, 720Kbps|720x480, 1.5Mbps|1024x768, 2Mbps|1280x720, 3Mbps|1280x720, 4Mbps|1920x1080, 8Mbps|1920x1080, 10Mbps|1920x1080, 12Mbps|1920x1080, 20Mbps|1920x1080, 40Mbps" default="11" />
<setting id="transcodeH265" type="enum" label="30522" default="0" values="Disabled (default)|480p (and higher)|720p (and higher)|1080p" />
<setting id="audioBoost" type="slider" label="39001" default="0" range="0,10,100" option="int"/>
<setting id="subtitleSize" label="39002" type="slider" option="int" range="0,30,300" default="100" />
<setting id="markPlayed" type="number" visible="false" default="95" />
<setting id="failedCount" type="number" visible="false" default="0" />
<setting id="networkCreds" type="text" visible="false" default="" />
</category>
<!--
<category label="30235" visible="false">
<setting id="enableCoverArt" type="bool" label="30157" default="true" visible="false"/>
@ -113,8 +113,16 @@
<setting id="newmusictime" type="number" label="30533" visible="false" default="2" option="int" subsetting="true" />
</category>
-->
<category label="Plex Companion">
<setting type="lsep" label="39008" />
<setting id="plexCompanion" label="39004" type="bool" default="true" />
<setting id="deviceNameOpt" label="30504" type="bool" default="false" />
<setting id="deviceName" label="30016" type="text" visible="eq(-1,true)" default="Kodi" />
<setting id="companionPort" label="39005" type="number" default="3005" option="int" visible="eq(-3,true)"/>
</category>
<category label="39045"><!-- Appearance Tweaks -->
<setting id="connectMsg" type="bool" label="30249" default="true" />
<setting type="lsep" label="39046" />
<setting id="OnDeckTvAppendShow" type="bool" label="39047" default="false" /><!--On Deck view: Append show title to episode-->
<setting id="OnDeckTvAppendSeason" type="bool" label="39048" default="false" /><!--On Deck view: Append season number to episode-->
@ -123,7 +131,6 @@
<category label="30022"><!-- Advanced -->
<setting id="logLevel" type="enum" label="30004" values="Disabled|Info|Debug" default="1" />
<setting id="startupDelay" type="number" label="30529" default="0" option="int" />
<setting id="connectMsg" type="bool" label="30249" default="true" />
<setting label="39018" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect/?mode=repair)" option="close" /> <!-- Repair local database (force update all content) -->
<setting label="39020" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect/?mode=texturecache)" option="close" /> <!-- Cache all images to Kodi texture cache -->
<setting label="30535" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=deviceid)" /><!-- Reset device id uuid -->