354 lines
14 KiB
Python
354 lines
14 KiB
Python
# coding=utf-8
|
|
import os, sys
|
|
import xbmc, xbmcaddon, xbmcplugin, xbmcgui, xbmcvfs
|
|
import xml.etree.ElementTree as xmltree
|
|
import json
|
|
from traceback import print_exc
|
|
from urllib.parse import quote, unquote
|
|
|
|
from resources.lib.common import *
|
|
from resources.lib import pluginBrowser
|
|
|
|
class ViewAttribFunctions():
|
|
def __init__(self, ltype):
|
|
self.ltype = ltype
|
|
|
|
def _load_rules( self ):
|
|
if self.ltype.startswith('video'):
|
|
overridepath = os.path.join( DEFAULTPATH , "videorules.xml" )
|
|
else:
|
|
overridepath = os.path.join( DEFAULTPATH , "musicrules.xml" )
|
|
try:
|
|
tree = xmltree.parse( overridepath )
|
|
return tree
|
|
except:
|
|
return None
|
|
|
|
def translateContent( self, content ):
|
|
# Load the rules
|
|
tree = self._load_rules()
|
|
hasValue = True
|
|
elems = tree.getroot().find( "content" ).findall( "type" )
|
|
for elem in elems:
|
|
if elem.text == content:
|
|
return xbmc.getLocalizedString( int( elem.attrib.get( "label" ) ) )
|
|
return None
|
|
|
|
def editContent( self, actionPath, default ):
|
|
# Load all the rules
|
|
tree = self._load_rules().getroot()
|
|
elems = tree.find( "content" ).findall( "type" )
|
|
selectName = []
|
|
selectValue = []
|
|
# Find all the content types
|
|
for elem in elems:
|
|
selectName.append( xbmc.getLocalizedString( int( elem.attrib.get( "label" ) ) ) )
|
|
selectValue.append( elem.text )
|
|
# Let the user select a content type
|
|
selectedContent = xbmcgui.Dialog().select( LANGUAGE( 30309 ), selectName )
|
|
# If the user selected no operator...
|
|
if selectedContent == -1:
|
|
return
|
|
self.writeUpdatedRule( actionPath, "content", selectValue[ selectedContent ], addFilter = True )
|
|
|
|
def translateGroup( self, grouping ):
|
|
# Load the rules
|
|
tree = self._load_rules()
|
|
hasValue = True
|
|
elems = tree.getroot().find( "groupings" ).findall( "grouping" )
|
|
for elem in elems:
|
|
if elem.attrib.get( "name" ) == grouping:
|
|
return xbmc.getLocalizedString( int( elem.find( "label" ).text ) )
|
|
return None
|
|
|
|
def editGroup( self, actionPath, content, default ):
|
|
# Load all the rules
|
|
tree = self._load_rules().getroot()
|
|
elems = tree.find( "groupings" ).findall( "grouping" )
|
|
selectName = []
|
|
selectValue = []
|
|
# Find all the content types
|
|
for elem in elems:
|
|
checkContent = elem.find( content )
|
|
if checkContent is not None:
|
|
selectName.append( xbmc.getLocalizedString( int( elem.find( "label" ).text ) ) )
|
|
selectValue.append( elem.attrib.get( "name" ) )
|
|
# Let the user select a content type
|
|
selectedGrouping = xbmcgui.Dialog().select( LANGUAGE( 30310 ), selectName )
|
|
# If the user selected no operator...
|
|
if selectedGrouping == -1:
|
|
return
|
|
self.writeUpdatedRule( actionPath, "group", selectValue[ selectedGrouping ] )
|
|
|
|
def addLimit( self, actionPath ):
|
|
# Load all the rules
|
|
try:
|
|
tree = xmltree.parse( unquote(actionPath) )
|
|
root = tree.getroot()
|
|
# Add a new content tag
|
|
newContent = xmltree.SubElement( root, "limit" )
|
|
newContent.text = "25"
|
|
# Save the file
|
|
self.indent( root )
|
|
tree.write( unquote(actionPath), encoding="UTF-8" )
|
|
except:
|
|
print_exc()
|
|
|
|
def editLimit( self, actionPath, curValue ):
|
|
returnVal = xbmcgui.Dialog().input( LANGUAGE( 30311 ), curValue, type=xbmcgui.INPUT_NUMERIC )
|
|
if returnVal != "":
|
|
self.writeUpdatedRule( actionPath, "limit", returnVal )
|
|
|
|
def addPath( self, actionPath ):
|
|
# Load all the rules
|
|
tree = self._load_rules().getroot()
|
|
elems = tree.find( "paths" ).findall( "type" )
|
|
selectName = []
|
|
selectValue = []
|
|
# Find all the path types
|
|
for elem in elems:
|
|
selectName.append( xbmc.getLocalizedString( int( elem.attrib.get( "label" ) ) ) )
|
|
selectValue.append( elem.attrib.get( "name" ) )
|
|
# Find any sub-path types
|
|
for subElem in elem.findall( "type" ):
|
|
selectName.append( " - %s" %( xbmc.getLocalizedString( int( subElem.attrib.get( "label" ) ) ) ) )
|
|
selectValue.append( "%s/%s" %( elem.attrib.get( "name" ), subElem.attrib.get( "name" ) ) )
|
|
|
|
# Add option to select a plugin
|
|
selectName.append( LANGUAGE( 30514 ) )
|
|
selectValue.append( "::PLUGIN::" )
|
|
|
|
# Let the user select a path
|
|
selectedContent = xbmcgui.Dialog().select( LANGUAGE( 30309 ), selectName )
|
|
# If the user selected no operator...
|
|
if selectedContent == -1:
|
|
return
|
|
if selectValue[ selectedContent ] == "::PLUGIN::":
|
|
# The user has asked to browse for a plugin
|
|
path = pluginBrowser.getPluginPath(self.ltype)
|
|
if path is not None:
|
|
# User has selected a plugin
|
|
self.writeUpdatedPath( actionPath, (0, path), addFolder = True)
|
|
else:
|
|
# The user has chosen a specific path
|
|
self.writeUpdatedPath( actionPath, (0, selectValue[ selectedContent ] ), addFolder = True )
|
|
|
|
def editPath( self, actionPath, curValue ):
|
|
returnVal = xbmcgui.Dialog().input( LANGUAGE( 30312 ), curValue, type=xbmcgui.INPUT_ALPHANUM )
|
|
if returnVal != "":
|
|
self.writeUpdatedRule( actionPath, "path", returnVal )
|
|
|
|
def editIcon( self, actionPath, curValue ):
|
|
returnVal = xbmcgui.Dialog().input( LANGUAGE( 30313 ), curValue, type=xbmcgui.INPUT_ALPHANUM )
|
|
if returnVal != "":
|
|
self.writeUpdatedRule( actionPath, "icon", returnVal )
|
|
|
|
def browseIcon( self, actionPath ):
|
|
returnVal = xbmcgui.Dialog().browse( 2, LANGUAGE( 30313 ), "files", useThumbs = True )
|
|
if returnVal:
|
|
self.writeUpdatedRule( actionPath, "icon", returnVal )
|
|
|
|
def writeUpdatedRule( self, actionPath, attrib, value, addFilter = False ):
|
|
# This function writes an updated match, operator or value to a rule
|
|
try:
|
|
# Load the xml file
|
|
tree = xmltree.parse( actionPath )
|
|
root = tree.getroot()
|
|
# Add type="filter" if requested
|
|
if addFilter:
|
|
root.set( "type", "filter" )
|
|
# Find the attribute and update it
|
|
elem = root.find( attrib )
|
|
if elem is None:
|
|
# There's no existing attribute with this name, so create one
|
|
elem = xmltree.SubElement( root, attrib )
|
|
elem.text = value
|
|
# Save the file
|
|
self.indent( root )
|
|
tree.write( actionPath, encoding="UTF-8" )
|
|
except:
|
|
print_exc()
|
|
|
|
def writeUpdatedPath( self, actionPath, newComponent, addFolder = False ):
|
|
# This functions writes an updated path
|
|
try:
|
|
# Load the xml file
|
|
tree = xmltree.parse( unquote(actionPath) )
|
|
root = tree.getroot()
|
|
# Add type="folder" if requested
|
|
if addFolder:
|
|
root.set( "type", "folder" )
|
|
# Find the current path element
|
|
elem = root.find( "path" )
|
|
if elem is None:
|
|
# There's no existing path element, so create one
|
|
elem = xmltree.SubElement( root, "path" )
|
|
# Get the split version of the path
|
|
splitPath = self.splitPath( elem.text )
|
|
elem.text = ""
|
|
if len( splitPath ) == 0:
|
|
# If the splitPath is empty, add our new component straight away
|
|
elem.text = "%s/" %( newComponent[ 1 ] )
|
|
elif newComponent[ 0 ] == 0 and newComponent[ 1 ].startswith( "plugin://"):
|
|
# We've been passed a plugin, so only want to write that plugin
|
|
elem.text = newComponent[ 1 ]
|
|
else:
|
|
# Enumarate through everything in the existing path
|
|
for x, component in enumerate( splitPath ):
|
|
if x != newComponent[ 0 ]:
|
|
# Transfer this component to the new path
|
|
if x == 0:
|
|
elem.text = self.joinPath( component )
|
|
elif x == 1:
|
|
elem.text += "?%s=%s" %( component[ 0 ], quote(component[1]) )
|
|
else:
|
|
elem.text += "&%s=%s" %( component[ 0 ], quote(component[1]) )
|
|
else:
|
|
# Add our new component
|
|
if x == 0:
|
|
elem.text = "%s/" %( newComponent[ 1 ] )
|
|
elif x == 1:
|
|
elem.text += "?%s=%s" %( newComponent[ 1 ], quote(newComponent[2]) )
|
|
else:
|
|
elem.text += "&%s=%s" %( newComponent[ 1 ], quote(newComponent[2]) )
|
|
# Check that we added it
|
|
if x < newComponent[ 0 ]:
|
|
if newComponent[ 0 ] == 1:
|
|
elem.text += "?%s=%s" %( newComponent[ 1 ], quote(newComponent[2]) )
|
|
else:
|
|
elem.text += "&%s=%s" %( newComponent[ 1 ], quote(newComponent[2]) )
|
|
# Save the file
|
|
self.indent( root )
|
|
tree.write( unquote(actionPath), encoding="UTF-8" )
|
|
except:
|
|
print_exc()
|
|
|
|
def deletePathRule( self, actionPath, rule ):
|
|
# This function deletes a rule from a path component
|
|
result = xbmcgui.Dialog().yesno(ADDONNAME, LANGUAGE( 30407 ) )
|
|
if not result:
|
|
return
|
|
|
|
try:
|
|
# Load the xml file
|
|
tree = xmltree.parse( actionPath )
|
|
root = tree.getroot()
|
|
# Find the current path element
|
|
elem = root.find( "path" )
|
|
# Get the split version of the path
|
|
splitPath = self.splitPath( elem.text )
|
|
elem.text = ""
|
|
|
|
# Enumarate through everything in the existing path
|
|
addedQ = False
|
|
for x, component in enumerate( splitPath ):
|
|
if x != rule:
|
|
if x == 0:
|
|
elem.text = self.joinPath( component )
|
|
elif not addedQ:
|
|
elem.text += "?%s=%s" %( component[ 0 ], quote(component[1]) )
|
|
addedQ = True
|
|
else:
|
|
elem.text += "&%s=%s" %( component[ 0 ], quote(component[1]) )
|
|
# Save the file
|
|
self.indent( root )
|
|
tree.write( actionPath, encoding="UTF-8" )
|
|
except:
|
|
print_exc()
|
|
|
|
def splitPath( self, completePath ):
|
|
# This function returns an array of the different components of a path
|
|
# [library]://[primary path]/[secondary path]/?attribute1=value1&attribute2=value2...
|
|
# [( , )] [( , )] [( , )]...
|
|
splitPath = []
|
|
|
|
# If completePath is empty, return an empty list
|
|
if completePath is None:
|
|
return []
|
|
|
|
# If it's a plugin, then we don't want to split it as its unlikely the user will want to edit individual components
|
|
if completePath.startswith( "plugin://" ):
|
|
return [ ( completePath, None ) ]
|
|
|
|
# Split, get the library://primarypath/[secondarypath]
|
|
split = completePath.rsplit( "/", 1 )
|
|
if split[ 0 ].count( "/" ) == 3:
|
|
# There's a secondary path
|
|
paths = split[ 0 ].rsplit( "/", 1 )
|
|
splitPath.append( ( paths[0], paths[1] ) )
|
|
else:
|
|
splitPath.append( ( split[ 0 ], None ) )
|
|
|
|
|
|
# Now split the components
|
|
if len( split ) != 1 and split[ 1 ].startswith( "?" ):
|
|
for component in split[ 1 ][ 1: ].split( "&" ):
|
|
componentSplit = component.split( "=" )
|
|
splitPath.append( ( componentSplit[ 0 ], unquote( componentSplit[1]) ) )
|
|
|
|
return splitPath
|
|
|
|
def joinPath( self, components ):
|
|
# This function rejoins the library://path/subpath components of a path
|
|
returnPath = "%s/" %( components[ 0 ] )
|
|
if components[ 1 ] is not None:
|
|
returnPath += "%s/" %( components[ 1 ] )
|
|
return returnPath
|
|
|
|
|
|
def translatePath( self, path ):
|
|
# Load the rules
|
|
tree = self._load_rules()
|
|
subSearch = None
|
|
translated = [ path[ 0 ], path[ 1 ] ]
|
|
elems = tree.getroot().find( "paths" ).findall( "type" )
|
|
for elem in elems:
|
|
if elem.attrib.get( "name" ) == path[ 0 ]:
|
|
translated[ 0 ] = xbmc.getLocalizedString( int( elem.attrib.get( "label" ) ) )
|
|
subSearch = elem
|
|
break
|
|
|
|
if path[ 1 ] and subSearch is not None:
|
|
for elem in subSearch.findall( "type" ):
|
|
if elem.attrib.get( "name" ) == path[ 1 ]:
|
|
translated[ 1 ] = xbmc.getLocalizedString( int( elem.attrib.get( "label" ) ) )
|
|
break
|
|
|
|
returnString = translated[ 0 ]
|
|
if translated[ 1 ]:
|
|
returnString += " - %s" %( translated[ 1 ] )
|
|
|
|
return returnString
|
|
|
|
def translateMatch( self, value ):
|
|
if value == "any":
|
|
return xbmc.getLocalizedString(21426).capitalize()
|
|
else:
|
|
return xbmc.getLocalizedString(21425).capitalize()
|
|
|
|
def editMatch( self, actionPath ):
|
|
selectName = [ xbmc.getLocalizedString(21425).capitalize(), xbmc.getLocalizedString(21426).capitalize() ]
|
|
selectValue = [ "all", "any" ]
|
|
# Let the user select wether any or all rules need match
|
|
selectedMatch = xbmcgui.Dialog().select( LANGUAGE( 30310 ), selectName )
|
|
# If the user made no selection...
|
|
if selectedMatch == -1:
|
|
return
|
|
self.writeUpdatedRule( actionPath, "match", selectValue[ selectedMatch ] )
|
|
|
|
# in-place prettyprint formatter
|
|
def indent( self, elem, level=0 ):
|
|
i = "\n" + level*"\t"
|
|
if len(elem):
|
|
if not elem.text or not elem.text.strip():
|
|
elem.text = i + "\t"
|
|
if not elem.tail or not elem.tail.strip():
|
|
elem.tail = i
|
|
for elem in elem:
|
|
self.indent(elem, level+1)
|
|
if not elem.tail or not elem.tail.strip():
|
|
elem.tail = i
|
|
else:
|
|
if level and (not elem.tail or not elem.tail.strip()):
|
|
elem.tail = i
|