def _get_shortcuts( self, group, defaultGroup = None, isXML = False, profileDir = None, defaultsOnly = False ):
        # This will load the shortcut file
        # Additionally, if the override files haven't been loaded, we'll load them too
        log( "Loading shortcuts for group " + group )
                
        if profileDir is None:
            profileDir = xbmc.translatePath( "special://profile/" ).decode( "utf-8" )
        
        userShortcuts = os.path.join( profileDir, "addon_data", __addonid__, self.slugify( group ) + ".DATA.xml" )#.encode('utf-8')
        skinShortcuts = os.path.join( __skinpath__ , self.slugify( group ) + ".DATA.xml")#.encode('utf-8')
        defaultShortcuts = os.path.join( __defaultpath__ , self.slugify( group ) + ".DATA.xml" )#.encode('utf-8')
        if defaultGroup is not None:
            skinShortcuts = os.path.join( __skinpath__ , self.slugify( defaultGroup ) + ".DATA.xml")#.encode('utf-8')    
            defaultShortcuts = os.path.join( __defaultpath__ , self.slugify( defaultGroup ) + ".DATA.xml" )#.encode('utf-8')

        if defaultsOnly:
            paths = [skinShortcuts, defaultShortcuts ]
        else:
            paths = [userShortcuts, skinShortcuts, defaultShortcuts ]
        
        for path in paths:
            path = try_decode( path )
                
            tree = None
            if xbmcvfs.exists( path ):
                file = xbmcvfs.File( path ).read()
                self._save_hash( path, file )
                tree = xmltree.parse( path )
            
            if tree is not None:
                # If this is a user-selected list of shortcuts...
                if path == userShortcuts:
                    if group == "mainmenu":
                        self._get_skin_required( tree, group, profileDir )
                    # Process shortcuts, marked as user-selected                    
                    self._process_shortcuts( tree, group, profileDir, True )
                    
                else:
                    if group == "mainmenu":
                        self._get_skin_required( tree, group, profileDir )
                    self._process_shortcuts( tree, group, profileDir )
                                        
                log( " - Loaded file " + path ) 
                return tree
            else:
                self._save_hash( path, None )
                
        # No file loaded
        log( " - No shortcuts" )
        return xmltree.ElementTree( xmltree.Element( "shortcuts" ) )
Example #2
0
    def buildElement( self, item, groupName, visibilityCondition, profileVisibility, submenuVisibility = None, itemid=-1, options=[] ):
        # This function will build an element for the passed Item in
        newelement = xmltree.Element( "item" )

        if itemid is not -1:
            newelement.set( "id", str( itemid ) )
            
        # Label and label2
        xmltree.SubElement( newelement, "label" ).text = DATA.local( item.find( "label" ).text )[1]
        xmltree.SubElement( newelement, "label2" ).text = DATA.local( item.find( "label2" ).text )[1]
            
        # Icon and thumb
        icon = item.find( "override-icon" )
        if icon is None:
            icon = item.find( "icon" )
        if icon is None:
            xmltree.SubElement( newelement, "icon" ).text = "DefaultShortcut.png"
        else:
            xmltree.SubElement( newelement, "icon" ).text = icon.text
        thumb = item.find( "thumb" )
        if thumb is not None:
            xmltree.SubElement( newelement, "thumb" ).text = item.find( "thumb" ).text
        
        # labelID and defaultID
        labelID = xmltree.SubElement( newelement, "property" )
        labelID.text = item.find( "labelID" ).text
        labelID.set( "name", "labelID" )
        defaultID = xmltree.SubElement( newelement, "property" )
        defaultID.text = item.find( "defaultID" ).text
        defaultID.set( "name", "defaultID" )
        
        # Additional properties
        properties = eval( item.find( "additional-properties" ).text )
        if len( properties ) != 0:
            repr( properties )
            for property in properties:
                if property[0] == "node.visible":
                    visibleProperty = xmltree.SubElement( newelement, "visible" )
                    visibleProperty.text = try_decode( property[1] )                    
                else:
                    additionalproperty = xmltree.SubElement( newelement, "property" )
                    additionalproperty.set( "name", property[0].decode( "utf-8" ) )
                    additionalproperty.text = DATA.local( property[1] )[1]
                        
                    # If this is a widget or background, set a skin setting to say it's enabled
                    if property[0] == "widget":
                        xbmc.executebuiltin( "Skin.SetBool(skinshortcuts-widget-" + property[1] + ")" )
                        # And if it's the main menu, list it
                        if groupName == "mainmenu":
                            xbmc.executebuiltin( "Skin.SetString(skinshortcuts-widget-" + str( self.widgetCount ) + "," + property[ 1 ] + ")" )
                            self.widgetCount += 1
                    elif property[0] == "background":
                        try:
                            xbmc.executebuiltin( "Skin.SetBool(skinshortcuts-background-" + property[1] + ")" )
                        except UnicodeEncodeError:							
                            xbmc.executebuiltin( "Skin.SetBool(skinshortcuts-background-" + property[1].encode('utf-8') + ")" )
                        
                    # If this is the main menu, and we're cloning widgets or backgrounds...
                    if groupName == "mainmenu":
                        if "clonewidgets" in options:
                            if property[0] == "widget" or property[0] == "widgetName" or property[0] == "widgetType" or property[0] == "widgetPlaylist":
                                self.MAINWIDGET[ property[0] ] = property[1]
                        if "clonebackgrounds" in options:
                            if property[0] == "background" or property[0] == "backgroundName" or property[0] == "backgroundPlaylist" or property[0] == "backgroundPlaylistName":
                                self.MAINBACKGROUND[ property[0] ] = property[1]

                    # For backwards compatibility, save widgetPlaylist as widgetPath too
                    if property[ 0 ] == "widgetPlaylist":
                        additionalproperty = xmltree.SubElement( newelement, "property" )
                        additionalproperty.set( "name", "widgetPath" )
                        try:
                            additionalproperty.text = DATA.local( property[1].decode( "utf-8" ) )[1]
                        except:
                            additionalproperty.text = DATA.local( property[1] )[1]
        
        # Primary visibility
        visibility = item.find( "visibility" )
        if visibility is not None:
            xmltree.SubElement( newelement, "visible" ).text = visibility.text
        
        #additional onclick (group overrides)
        onclicks = item.findall( "additional-action" )
        for onclick in onclicks:
            onclickelement = xmltree.SubElement( newelement, "onclick" )
            onclickelement.text = onclick.text
            if "condition" in onclick.attrib:
                onclickelement.set( "condition", onclick.attrib.get( "condition" ) )
        
        # Onclick
        onclicks = item.findall( "override-action" )
        if len( onclicks ) == 0:
            onclicks = item.findall( "action" )
            
        for onclick in onclicks:
            onclickelement = xmltree.SubElement( newelement, "onclick" )
            # PVR Action
            if onclick.text.startswith( "pvr-channel://" ):
                # PVR action
                onclickelement.text = "RunScript(script.skinshortcuts,type=launchpvr&channel=" + onclick.text.replace( "pvr-channel://", "" ) + ")"
            elif onclick.text.startswith( "ActivateWindow(" ) and xbmc.translatePath( "special://skin/" ) in onclick.text:
                # Skin-relative links
                try:
                    actionParts = onclick.text[15:-1].split( "," )
                    actionParts[1] = actionParts[1].replace( xbmc.translatePath( "special://skin/" ), "" )
                    path = actionParts[1].split( os.sep )
                    newAction = "special://skin"
                    for actionPart in actionParts[1].split( os.sep ):
                        if actionPart != "":
                            newAction = newAction + "/" + actionPart
                    if len( actionParts ) == 2:
                        onclickelement.text = "ActivateWindow(" + actionParts[0] + "," + newAction + ")"
                    else:
                        onclickelement.text = "ActivateWindow(" + actionParts[0] + "," + newAction + "," + actionParts[2] + ")"
                except:
                    pass
            else:
                onclickelement.text = onclick.text
                
            # Also add it as a path property
            if not self.propertyExists( "path", newelement ):
                # we only add the path property if there isn't already one in the list because it has to be unique in Kodi lists
                pathelement = xmltree.SubElement( newelement, "property" )
                pathelement.set( "name", "path" )
                pathelement.text = onclickelement.text
            
            # Get 'list' property (the action property of an ActivateWindow shortcut)
            if not self.propertyExists( "list", newelement ):
                # we only add the list property if there isn't already one in the list because it has to be unique in Kodi lists
                listElement = xmltree.SubElement( newelement, "property" )
                listElement.set( "name", "list" )
                listElement.text = DATA.getListProperty( onclickelement.text )
                
            if onclick.text == "ActivateWindow(Settings)":
                self.hasSettings = True
                
            if "condition" in onclick.attrib:
                onclickelement.set( "condition", onclick.attrib.get( "condition" ) )
                
            if len( self.checkForShortcuts ) != 0:
                # Check if we've been asked to watch for this shortcut
                newCheckForShortcuts = []
                for checkforShortcut in self.checkForShortcuts:
                    if onclick.text.lower() == checkforShortcut[ 0 ]:
                        # They match, change the value to True
                        newCheckForShortcuts.append( ( checkforShortcut[ 0 ], checkforShortcut[ 1 ], "True" ) )
                    else:
                        newCheckForShortcuts.append( checkforShortcut )
                self.checkForShortcuts = newCheckForShortcuts

        # Visibility
        if visibilityCondition is not None:
            visibilityElement = xmltree.SubElement( newelement, "visible" )
            if profileVisibility is not None:
                visibilityElement.text = profileVisibility + " + [" + visibilityCondition + "]"
            else:
                visibilityElement.text = visibilityCondition
            issubmenuElement = xmltree.SubElement( newelement, "property" )
            issubmenuElement.set( "name", "isSubmenu" )
            issubmenuElement.text = "True"
        elif profileVisibility is not None:
            visibilityElement = xmltree.SubElement( newelement, "visible" )
            visibilityElement.text = profileVisibility
                
        # Submenu visibility
        if submenuVisibility is not None:
            submenuVisibilityElement = xmltree.SubElement( newelement, "property" )
            submenuVisibilityElement.set( "name", "submenuVisibility" )
            if submenuVisibility.isdigit():
                submenuVisibilityElement.text = "$NUMBER[" + submenuVisibility + "]"
            else:
                submenuVisibilityElement.text = DATA.slugify( submenuVisibility )
                
        # Group name
        group = xmltree.SubElement( newelement, "property" )
        group.set( "name", "group" )
        group.text = try_decode( groupName )

        if groupName == "mainmenu":
            self.MAINWIDGET = {}
            self.MAINBACKGROUND = {}
        
        # If this isn't the main menu, and we're cloning widgets or backgrounds...
        if groupName != "mainmenu":
            if "clonewidgets" in options and len( self.MAINWIDGET ) is not 0:
                for key in self.MAINWIDGET:
                    additionalproperty = xmltree.SubElement( newelement, "property" )
                    additionalproperty.set( "name", key )
                    additionalproperty.text = try_decode( self.MAINWIDGET[ key ] )
            if "clonebackgrounds" in options and len( self.MAINBACKGROUND ) is not 0:
                for key in self.MAINBACKGROUND:
                    additionalproperty = xmltree.SubElement( newelement, "property" )
                    additionalproperty.set( "name", key )
                    additionalproperty.text = DATA.local( self.MAINBACKGROUND[ key ] )[1]

        propertyPatterns = self.getPropertyPatterns(labelID.text, groupName)
        if len(propertyPatterns) > 0:
            propertyReplacements = self.getPropertyReplacements(newelement)
            for propertyName in propertyPatterns:
                propertyPattern = propertyPatterns[propertyName][0]
                for original, replacement in propertyReplacements:
                    regexpPattern = re.compile(re.escape(original), re.IGNORECASE)
                    propertyPattern = regexpPattern.sub(replacement, propertyPattern)
    
                additionalproperty = xmltree.SubElement(newelement, "property")
                additionalproperty.set("name", propertyName.decode("utf-8"))
                additionalproperty.text = propertyPattern.decode("utf-8")
            
        return newelement
Example #3
0
    def setProperties( self, properties, values, labelID, group, DATA ):
        # This function will take a list of properties and values and apply them to the
        # main menu item with the given labelID
        if not group:
            group = "mainmenu"

        # Decode values
        properties = try_decode( properties )
        values = try_decode( values )
        labelID = try_decode( labelID )
        group = try_decode( group )

        # Split up property names and values
        propertyNames = properties.split( "|" )
        propertyValues = values.replace( "::INFO::", "$INFO" ).split( "|" )
        labelIDValues = labelID.split( "|" )
        if len( labelIDValues ) == 0:
            # No labelID passed in, lets assume we were called in error
            return
        if len( propertyNames ) == 0:
            # No values passed in, lets assume we were called in error
            return

        # Get user confirmation that they want to make these changes
        message = "Set %s property to %s?" %( propertyNames[ 0 ], propertyValues[ 0 ] )
        if len( propertyNames ) == 2:
            message += "[CR](and 1 other property)"
        elif len( propertyNames ) > 2:
            message += "[CR](and %d other properties)" %( len( propertyNames ) -1 )
        shouldRun = xbmcgui.Dialog().yesno( __addon__.getAddonInfo( "name" ), message )
        if not shouldRun:
            return

        # Load the properties
        currentProperties, defaultProperties = DATA._get_additionalproperties( xbmc.translatePath( "special://profile/" ).decode( "utf-8" ) )
        otherProperties, requires, templateOnly = DATA._getPropertyRequires()

        # If there aren't any currentProperties, use the defaultProperties instead
        if currentProperties == [None]:
            currentProperties = defaultProperties

        # Pull out all properties into multi-dimensional dicts
        allProps = {}
        allProps[ group ] = {}
        for currentProperty in currentProperties:
            # If the group isn't in allProps, add it
            if currentProperty[ 0 ] not in allProps.keys():
                allProps[ currentProperty [ 0 ] ] = {}
            # If the labelID isn't in the allProps[ group ], add it
            if currentProperty[ 1 ] not in allProps[ currentProperty[ 0 ] ].keys():
                allProps[ currentProperty[ 0 ] ][ currentProperty[ 1 ] ] = {}
            # And add the property to allProps[ group ][ labelID ]
            if currentProperty[ 3 ] is not None:
                allProps[ currentProperty[ 0 ] ][ currentProperty [ 1 ] ][ currentProperty[ 2 ] ] = currentProperty[ 3 ]

        # Loop through the properties we've been asked to set
        for count, propertyName in enumerate(propertyNames):
            # Set the new value
            log( "Setting %s to %s" %( propertyName, propertyValues[ count ] ) )
            if len( labelIDValues ) != 1:
                labelID = labelIDValues[ count ]
            if labelID not in allProps[ group ].keys():
                allProps[ group ][ labelID ] = {}
            allProps[ group ][ labelID ][ propertyName ] = propertyValues[ count ]

            # Remove any properties whose requirements haven't been met
            for key in otherProperties:
                if key in allProps[ group ][ labelID ].keys() and key in requires.keys() and requires[ key ] not in allProps[ group ][ labelID ].keys():
                    # This properties requirements aren't met
                    log( "Removing value %s" %( key ) )
                    allProps[ group ][ labelID ].pop( key )

        # Build the list of all properties to save
        saveData = []
        for saveGroup in allProps:
            for saveLabelID in allProps[ saveGroup ]:
                for saveProperty in allProps[ saveGroup ][ saveLabelID ]:
                    saveData.append( [ saveGroup, saveLabelID, saveProperty, allProps[ saveGroup ][ saveLabelID ][ saveProperty ] ] )
        
        # Save the new properties
        try:
            f = xbmcvfs.File( os.path.join( __datapath__ , xbmc.getSkinDir().decode('utf-8') + ".properties" ), 'w' )
            f.write( repr( saveData ).replace( "],", "],\n" ) )
            f.close()
            log( "Properties file saved succesfully" )
        except:
            print_exc()
            log( "### ERROR could not save file %s" % __datapath__ )

        # The properties will only be used if the .DATA.xml file exists in the addon_data folder( otherwise
        # the script will use the default values), so we're going to open and write the 'group' that has been
        # passed to us
        menuitems = DATA._get_shortcuts( group, processShortcuts = False )
        DATA.indent( menuitems.getroot() )
        path = xbmc.translatePath( os.path.join( "special://profile", "addon_data", __addonid__, "%s.DATA.xml" %( DATA.slugify( group, True ) ) ).encode('utf-8') )
        menuitems.write( path, encoding="UTF-8" )

        log( "Properties updated" )

        # Mark that the menu needs to be rebuilt
        xbmcgui.Window( 10000 ).setProperty( "skinshortcuts-reloadmainmenu", "True" )
Example #4
0
    def addToMenu( self, path, label, icon, content, window, DATA ):
        log( repr( window ) )
        log( repr( label ) )
        log( repr( path ) )
        log( repr( content ) )
        # Show a waiting dialog
        dialog = xbmcgui.DialogProgress()
        dialog.create( path, __language__( 32063 ) )

        # Work out if it's a single item, or a node
        isNode = False
        json_query = xbmc.executeJSONRPC('{ "jsonrpc": "2.0", "id": 0, "method": "Files.GetDirectory", "params": { "properties": ["title", "file", "thumbnail"], "directory": "' + path + '", "media": "files" } }')
        json_query = unicode(json_query, 'utf-8', errors='ignore')
        json_response = simplejson.loads(json_query)

        labels = []
        paths = []
        nodePaths = []

        # Now we've retrieved the path, decode everything for writing
        path = try_decode( path )
        label = try_decode( label )
        icon = try_decode( icon )
        
        # Add all directories returned by the json query
        if json_response.has_key('result') and json_response['result'].has_key('files') and json_response['result']['files'] is not None:
            labels = [ __language__(32058) ]
            paths = [ "ActivateWindow(%s,%s,return)" %( window, path ) ]
            for item in json_response['result']['files']:
                if item[ "filetype" ] == "directory":
                    isNode = True
                    labels.append( item[ "label" ] )
                    nodePaths.append( "ActivateWindow(%s,%s,return)" %( window, item[ "file" ] ) )
        else:
            log( "Invalid JSON response returned" )

        # Add actions based on content
        if content == "albums":
            labels.append( "Play" )
            paths.append( "RunScript(script.skinshortcuts,type=launchalbum&album=%s)" %( self.extractID( path ) ) )
        if window == 10002:
            labels.append( "Slideshow" )
            paths.append( "SlideShow(%s,notrandom)" %( path ) )
            labels.append( "Slideshow (random)" )
            paths.append( "SlideShow(%s,random)" %( path ) )
            labels.append( "Slideshow (recursive)" )
            paths.append( "SlideShow(%s,recursive,notrandom)" %( path ) )
            labels.append( "Slideshow (recursive, random)" )
            paths.append( "SlideShow(%s,recursive,random)" %( path ) )
        if path.endswith( ".xsp" ):
            labels.append( "Play" )
            paths.append( "PlayMedia(%s)" %( path ) )

        allMenuItems = [ xbmcgui.ListItem(label=__language__( 32112 )) ] # Main menu
        allLabelIDs = [ "mainmenu" ]
        if isNode:
            allMenuItems.append( xbmcgui.ListItem(label=__language__( 32113 ) ) ) # Main menu + autofill submenu
            allLabelIDs.append( "mainmenu" )

        # Get main menu items
        menuitems = DATA._get_shortcuts( "mainmenu", processShortcuts = False )
        DATA._clear_labelID()
        for menuitem in menuitems.findall( "shortcut" ):
            # Get existing items labelID's
            allMenuItems.append( xbmcgui.ListItem(label=DATA.local( menuitem.find( "label" ).text )[2], iconImage=menuitem.find( "icon" ).text) )
            allLabelIDs.append( DATA._get_labelID( DATA.local( menuitem.find( "label" ).text )[3], menuitem.find( "action" ).text ) )

        # Close progress dialog
        dialog.close()

        # Show a select dialog so the user can pick where in the menu to add the item
        w = ShowDialog( "DialogSelect.xml", __cwd__, listing=allMenuItems, windowtitle=__language__( 32114 ) )
        w.doModal()
        selectedMenu = w.result
        del w
        
        if selectedMenu == -1 or selectedMenu is None:
            # User cancelled
            return

        action = paths[ 0 ]
        if isNode and selectedMenu == 1:
            # We're auto-filling submenu, so add all sub-nodes as possible default actions
            paths = paths + nodePaths

        if len( paths ) > 1:
            # There are multiple actions to choose from
            selectedAction = xbmcgui.Dialog().select( __language__( 32095 ), labels )
            
            if selectedAction == -1 or selectedAction is None:
                # User cancelled
                return True

            action = paths[ selectedAction ]

        # Add the shortcut to the menu the user has selected
        # Load existing main menu items
        menuitems = DATA._get_shortcuts( allLabelIDs[ selectedMenu ], processShortcuts = False )
        DATA._clear_labelID()
            
        # Generate a new labelID
        newLabelID = DATA._get_labelID( label, action )
        
        # Write the updated mainmenu.DATA.xml
        newelement = xmltree.SubElement( menuitems.getroot(), "shortcut" )
        xmltree.SubElement( newelement, "label" ).text = label
        xmltree.SubElement( newelement, "label2" ).text = "32024" # Custom shortcut
        xmltree.SubElement( newelement, "icon" ).text = icon
        xmltree.SubElement( newelement, "thumb" )
        xmltree.SubElement( newelement, "action" ).text = action
        
        DATA.indent( menuitems.getroot() )
        path = xbmc.translatePath( os.path.join( "special://profile", "addon_data", __addonid__, "%s.DATA.xml" %( DATA.slugify( allLabelIDs[ selectedMenu ], True ) ) ).encode('utf-8') )
        menuitems.write( path, encoding="UTF-8" )

        if isNode and selectedMenu == 1:
            # We're also going to write a submenu
            menuitems = xmltree.ElementTree( xmltree.Element( "shortcuts" ) )
            
            for item in json_response['result']['files']:
                if item[ "filetype" ] == "directory":
                    newelement = xmltree.SubElement( menuitems.getroot(), "shortcut" )
                    xmltree.SubElement( newelement, "label" ).text = item[ "label" ]
                    xmltree.SubElement( newelement, "label2" ).text = "32024" # Custom shortcut
                    xmltree.SubElement( newelement, "icon" ).text = item[ "thumbnail" ]
                    xmltree.SubElement( newelement, "thumb" )
                    xmltree.SubElement( newelement, "action" ).text = "ActivateWindow(%s,%s,return)" %( window, item[ "file" ] )
                
            DATA.indent( menuitems.getroot() )
            path = xbmc.translatePath( os.path.join( "special://profile", "addon_data", __addonid__, DATA.slugify( newLabelID, True ) + ".DATA.xml" ).encode('utf-8') )
            menuitems.write( path, encoding="UTF-8" )
        
        # Mark that the menu needs to be rebuilt
        xbmcgui.Window( 10000 ).setProperty( "skinshortcuts-reloadmainmenu", "True" )
        
        # And tell the user it all worked
        xbmcgui.Dialog().ok( __addon__.getAddonInfo( "name" ), __language__(32090) )
Example #5
0
    def setProperties(self, properties, values, labelID, group, DATA):
        # This function will take a list of properties and values and apply them to the
        # main menu item with the given labelID
        if not group:
            group = "mainmenu"

        # Decode values
        properties = try_decode(properties)
        values = try_decode(values)
        labelID = try_decode(labelID)
        group = try_decode(group)

        # Split up property names and values
        propertyNames = properties.split("|")
        propertyValues = values.replace("::INFO::", "$INFO").split("|")
        labelIDValues = labelID.split("|")
        if len(labelIDValues) == 0:
            # No labelID passed in, lets assume we were called in error
            return
        if len(propertyNames) == 0:
            # No values passed in, lets assume we were called in error
            return

        # Get user confirmation that they want to make these changes
        message = "Set %s property to %s?" % (propertyNames[0],
                                              propertyValues[0])
        if len(propertyNames) == 2:
            message += "[CR](and 1 other property)"
        elif len(propertyNames) > 2:
            message += "[CR](and %d other properties)" % (len(propertyNames) -
                                                          1)
        shouldRun = xbmcgui.Dialog().yesno(ADDON.getAddonInfo("name"), message)
        if not shouldRun:
            return

        # Load the properties
        currentProperties, defaultProperties = DATA._get_additionalproperties(
            xbmc.translatePath("special://profile/").decode("utf-8"))
        otherProperties, requires, templateOnly = DATA._getPropertyRequires()

        # If there aren't any currentProperties, use the defaultProperties instead
        if currentProperties == [None]:
            currentProperties = defaultProperties

        # Pull out all properties into multi-dimensional dicts
        allProps = {}
        allProps[group] = {}
        for currentProperty in currentProperties:
            # If the group isn't in allProps, add it
            if currentProperty[0] not in allProps.keys():
                allProps[currentProperty[0]] = {}
            # If the labelID isn't in the allProps[ group ], add it
            if currentProperty[1] not in allProps[currentProperty[0]].keys():
                allProps[currentProperty[0]][currentProperty[1]] = {}
            # And add the property to allProps[ group ][ labelID ]
            if currentProperty[3] is not None:
                allProps[currentProperty[0]][currentProperty[1]][
                    currentProperty[2]] = currentProperty[3]

        # Loop through the properties we've been asked to set
        for count, propertyName in enumerate(propertyNames):
            # Set the new value
            log("Setting %s to %s" % (propertyName, propertyValues[count]))
            if len(labelIDValues) != 1:
                labelID = labelIDValues[count]
            if labelID not in allProps[group].keys():
                allProps[group][labelID] = {}
            allProps[group][labelID][propertyName] = propertyValues[count]

            # Remove any properties whose requirements haven't been met
            for key in otherProperties:
                if key in allProps[group][labelID].keys(
                ) and key in requires.keys(
                ) and requires[key] not in allProps[group][labelID].keys():
                    # This properties requirements aren't met
                    log("Removing value %s" % (key))
                    allProps[group][labelID].pop(key)

        # Build the list of all properties to save
        saveData = []
        for saveGroup in allProps:
            for saveLabelID in allProps[saveGroup]:
                for saveProperty in allProps[saveGroup][saveLabelID]:
                    saveData.append([
                        saveGroup, saveLabelID, saveProperty,
                        allProps[saveGroup][saveLabelID][saveProperty]
                    ])

        # Save the new properties
        try:
            f = xbmcvfs.File(
                os.path.join(DATAPATH,
                             xbmc.getSkinDir().decode('utf-8') +
                             ".properties"), 'w')
            f.write(repr(saveData).replace("],", "],\n"))
            f.close()
            log("Properties file saved succesfully")
        except:
            print_exc()
            log("### ERROR could not save file %s" % DATAPATH)

        # The properties will only be used if the .DATA.xml file exists in the addon_data folder( otherwise
        # the script will use the default values), so we're going to open and write the 'group' that has been
        # passed to us
        menuitems = DATA._get_shortcuts(group, processShortcuts=False)
        DATA.indent(menuitems.getroot())
        path = xbmc.translatePath(
            os.path.join("special://profile", "addon_data", ADDONID,
                         "%s.DATA.xml" %
                         (DATA.slugify(group, True))).encode('utf-8'))
        menuitems.write(path, encoding="UTF-8")

        log("Properties updated")

        # Mark that the menu needs to be rebuilt
        xbmcgui.Window(10000).setProperty("skinshortcuts-reloadmainmenu",
                                          "True")
Example #6
0
    def addToMenu(self, path, label, icon, content, window, DATA):
        log(repr(window))
        log(repr(label))
        log(repr(path))
        log(repr(content))
        # Show a waiting dialog
        dialog = xbmcgui.DialogProgress()
        dialog.create(path, LANGUAGE(32063))

        # Work out if it's a single item, or a node
        isNode = False
        jsonPath = path.replace("\\", "\\\\")

        json_query = xbmc.executeJSONRPC(
            '{ "jsonrpc": "2.0", "id": 0, "method": "Files.GetDirectory", "params": { "properties": ["title", "file", "thumbnail"], "directory": "'
            + jsonPath + '", "media": "files" } }')
        json_query = unicode(json_query, 'utf-8', errors='ignore')
        json_response = simplejson.loads(json_query)

        labels = []
        paths = []
        nodePaths = []

        # Now we've retrieved the path, decode everything for writing
        path = try_decode(path)
        label = try_decode(label)
        icon = try_decode(icon)

        # Add all directories returned by the json query
        if json_response.has_key('result') and json_response['result'].has_key(
                'files') and json_response['result']['files'] is not None:
            labels = [LANGUAGE(32058)]
            paths = ["ActivateWindow(%s,%s,return)" % (window, path)]
            for item in json_response['result']['files']:
                if item["filetype"] == "directory":
                    isNode = True
                    labels.append(item["label"])
                    nodePaths.append("ActivateWindow(%s,%s,return)" %
                                     (window, item["file"]))
        else:
            # Unable to add to get directory listings
            log("Invalid JSON response returned")
            log(repr(simplejson))
            # And tell the user it failed
            xbmcgui.Dialog().ok(ADDON.getAddonInfo("name"),
                                ADDON.getLocalizedString(32115))
            return

        # Add actions based on content
        if content == "albums":
            labels.append("Play")
            paths.append(
                "RunScript(script.skinshortcuts,type=launchalbum&album=%s)" %
                (self.extractID(path)))
        if window == 10002:
            labels.append("Slideshow")
            paths.append("SlideShow(%s,notrandom)" % (path))
            labels.append("Slideshow (random)")
            paths.append("SlideShow(%s,random)" % (path))
            labels.append("Slideshow (recursive)")
            paths.append("SlideShow(%s,recursive,notrandom)" % (path))
            labels.append("Slideshow (recursive, random)")
            paths.append("SlideShow(%s,recursive,random)" % (path))
        if path.endswith(".xsp"):
            labels.append("Play")
            paths.append("PlayMedia(%s)" % (path))

        allMenuItems = [xbmcgui.ListItem(label=LANGUAGE(32112))]  # Main menu
        allLabelIDs = ["mainmenu"]
        if isNode:
            allMenuItems.append(xbmcgui.ListItem(
                label=LANGUAGE(32113)))  # Main menu + autofill submenu
            allLabelIDs.append("mainmenu")

        # Get main menu items
        menuitems = DATA._get_shortcuts("mainmenu", processShortcuts=False)
        DATA._clear_labelID()
        for menuitem in menuitems.findall("shortcut"):
            # Get existing items labelID's
            allMenuItems.append(
                xbmcgui.ListItem(label=DATA.local(
                    menuitem.find("label").text)[2],
                                 iconImage=menuitem.find("icon").text))
            allLabelIDs.append(
                DATA._get_labelID(
                    DATA.local(menuitem.find("label").text)[3],
                    menuitem.find("action").text))

        # Close progress dialog
        dialog.close()

        # Show a select dialog so the user can pick where in the menu to add the item
        w = ShowDialog("DialogSelect.xml",
                       CWD,
                       listing=allMenuItems,
                       windowtitle=LANGUAGE(32114))
        w.doModal()
        selectedMenu = w.result
        del w

        if selectedMenu == -1 or selectedMenu is None:
            # User cancelled
            return

        action = paths[0]
        if isNode and selectedMenu == 1:
            # We're auto-filling submenu, so add all sub-nodes as possible default actions
            paths = paths + nodePaths

        if len(paths) > 1:
            # There are multiple actions to choose from
            selectedAction = xbmcgui.Dialog().select(LANGUAGE(32095), labels)

            if selectedAction == -1 or selectedAction is None:
                # User cancelled
                return True

            action = paths[selectedAction]

        # Add the shortcut to the menu the user has selected
        # Load existing main menu items
        menuitems = DATA._get_shortcuts(allLabelIDs[selectedMenu],
                                        processShortcuts=False)
        DATA._clear_labelID()

        # Generate a new labelID
        newLabelID = DATA._get_labelID(label, action)

        # Write the updated mainmenu.DATA.xml
        newelement = xmltree.SubElement(menuitems.getroot(), "shortcut")
        xmltree.SubElement(newelement, "label").text = label
        xmltree.SubElement(newelement,
                           "label2").text = "32024"  # Custom shortcut
        xmltree.SubElement(newelement, "icon").text = icon
        xmltree.SubElement(newelement, "thumb")
        xmltree.SubElement(newelement, "action").text = action

        DATA.indent(menuitems.getroot())
        path = xbmc.translatePath(
            os.path.join(
                "special://profile", "addon_data",
                ADDONID, "%s.DATA.xml" % (DATA.slugify(
                    allLabelIDs[selectedMenu], True))).encode('utf-8'))
        menuitems.write(path, encoding="UTF-8")

        if isNode and selectedMenu == 1:
            # We're also going to write a submenu
            menuitems = xmltree.ElementTree(xmltree.Element("shortcuts"))

            for item in json_response['result']['files']:
                if item["filetype"] == "directory":
                    newelement = xmltree.SubElement(menuitems.getroot(),
                                                    "shortcut")
                    xmltree.SubElement(newelement,
                                       "label").text = item["label"]
                    xmltree.SubElement(
                        newelement, "label2").text = "32024"  # Custom shortcut
                    xmltree.SubElement(newelement,
                                       "icon").text = item["thumbnail"]
                    xmltree.SubElement(newelement, "thumb")
                    xmltree.SubElement(
                        newelement,
                        "action").text = "ActivateWindow(%s,%s,return)" % (
                            window, item["file"])

            DATA.indent(menuitems.getroot())
            path = xbmc.translatePath(
                os.path.join("special://profile", "addon_data", ADDONID,
                             DATA.slugify(newLabelID, True) +
                             ".DATA.xml").encode('utf-8'))
            menuitems.write(path, encoding="UTF-8")

        # Mark that the menu needs to be rebuilt
        xbmcgui.Window(10000).setProperty("skinshortcuts-reloadmainmenu",
                                          "True")

        # And tell the user it all worked
        xbmcgui.Dialog().ok(ADDON.getAddonInfo("name"), LANGUAGE(32090))
    def local( self, data ):
        # This is our function to manage localisation
        # It accepts strings in one of the following formats:
        #   #####, ::LOCAL::#####, ::SCRIPT::#####
        #   $LOCALISE[#####], $SKIN[####|skin.id|last translation]
        #   $ADDON[script.skinshortcuts #####]
        # If returns a list containing:
        #   [Number/$SKIN, $LOCALIZE/$ADDON/Local string, Local string]
        #   [Used for saving, used for building xml, used for displaying in dialog]
        
        if data is None:
            return ["","","",""]
        
        data = try_decode( data )

        skinid = None
        lasttranslation = None
        
        # Get just the integer of the string, for the input forms where this is valid
        if not data.find( "::SCRIPT::" ) == -1:
            data = data[10:]
        elif not data.find( "::LOCAL::" ) == -1:            
            data = data[9:]
        elif not data.find( "$LOCALIZE[" ) == -1:
            data = data.replace( "$LOCALIZE[", "" ).replace( "]", "" ).replace( " ", "" )
        elif not data.find( "$ADDON[script.skinshortcuts" ) == -1:
            data = data.replace( "$ADDON[script.skinshortcuts", "" ).replace( "]", "" ).replace( " ", "" )
        
        # Get the integer and skin id, from $SKIN input forms
        elif not data.find( "$SKIN[" ) == -1:
            splitdata = data[6:-1].split( "|" )
            data = splitdata[0]
            skinid = splitdata[1]
            lasttranslation = splitdata[2]
            
        if data.isdigit():
            if int( data ) >= 31000 and int( data ) < 32000:
                # A number from a skin - we're going to return a $SKIN[#####|skin.id|last translation] unit
                if skinid is None:
                    # Set the skinid to the current skin id
                    skinid = xbmc.getSkinDir()
                    
                # If we're on the same skin as the skinid, get the latest translation
                if skinid == xbmc.getSkinDir():
                    lasttranslation = xbmc.getLocalizedString( int( data ) )
                    returnString = "$SKIN[" + data + "|" + skinid + "|" + lasttranslation + "]"
                    return [ returnString, "$LOCALIZE[" + data + "]", lasttranslation, data ]
                    
                returnString = "$SKIN[" + data + "|" + skinid + "|" + lasttranslation + "]"
                return [ returnString, lasttranslation, lasttranslation, data ]
                
            elif int( data ) >= 32000 and int( data ) < 33000:
                # A number from the script
                return [ data, "$ADDON[script.skinshortcuts " + data + "]", __language__( int( data ) ), data ]
                
            else:
                # A number from XBMC itself (probably)
                return [ data, "$LOCALIZE[" + data + "]", xbmc.getLocalizedString( int( data ) ), data ]
                
        # This isn't anything we can localize, just return it (in triplicate ;))
        return[ data, data, data, data ]
    def writexml( self, profilelist, mainmenuID, groups, numLevels, buildMode, progress, options, minitems ): 
        # Reset the hashlist, add the profile list and script version
        hashlist.list = []
        hashlist.list.append( ["::PROFILELIST::", profilelist] )
        hashlist.list.append( ["::SCRIPTVER::", __addonversion__] )
        hashlist.list.append( ["::XBMCVER::", __xbmcversion__] )
        if int( __xbmcversion__ ) <= 15:
            hashlist.list.append( ["::MUSICCONTENT::", xbmc.getCondVisibility( "Library.HasContent(Music)" ) ] )
        
        # Clear any skin settings for backgrounds and widgets
        DATA._reset_backgroundandwidgets()
        self.widgetCount = 1
        
        # Create a new tree and includes for the various groups
        tree = xmltree.ElementTree( xmltree.Element( "includes" ) )
        root = tree.getroot()
        
        # Create a Template object and pass it the root
        Template = template.Template()
        Template.includes = root
        
        # Get any shortcuts we're checking for
        self.checkForShortcuts = []
        overridestree = DATA._get_overrides_skin()
        checkForShorctcutsOverrides = overridestree.getroot().findall( "checkforshortcut" )
        for checkForShortcutOverride in checkForShorctcutsOverrides:
            if "property" in checkForShortcutOverride.attrib:
                # Add this to the list of shortcuts we'll check for
                self.checkForShortcuts.append( ( checkForShortcutOverride.text.lower(), checkForShortcutOverride.attrib.get( "property" ), "False" ) )
        
        mainmenuTree = xmltree.SubElement( root, "include" )
        mainmenuTree.set( "name", "skinshortcuts-mainmenu" )
        
        submenuTrees = []
        for level in range( 0,  int( numLevels) + 1 ):
            subelement = xmltree.SubElement(root, "include")
            subtree = xmltree.SubElement( root, "include" )
            if level == 0:
                subtree.set( "name", "skinshortcuts-submenu" )
            else:
                subtree.set( "name", "skinshortcuts-submenu-" + str( level ) )
            if not subtree in submenuTrees:
                submenuTrees.append( subtree )
        
        if buildMode == "single":
            allmenuTree = xmltree.SubElement( root, "include" )
            allmenuTree.set( "name", "skinshortcuts-allmenus" )
        
        profilePercent = 100 / len( profilelist )
        profileCount = -1
        
        submenuNodes = {}
        
        for profile in profilelist:
            log( "Building menu for profile %s" %( profile[ 2 ] ) )
            # Load profile details
            profileDir = profile[0]
            profileVis = profile[1]
            profileCount += 1
            
            # Reset whether we have settings
            self.hasSettings = False
            
            # Reset any checkForShortcuts to say we haven't found them
            newCheckForShortcuts = []
            for checkforShortcut in self.checkForShortcuts:
                newCheckForShortcuts.append( ( checkforShortcut[ 0 ], checkforShortcut[ 1 ], "False" ) )
            self.checkForShortcuts = newCheckForShortcuts

            # Clear any previous labelID's
            DATA._clear_labelID()

            # Clear any additional properties, which may be for a different profile
            DATA.currentProperties = None
            
            # Create objects to hold the items
            menuitems = []
            templateMainMenuItems = xmltree.Element( "includes" )
            
            # If building the main menu, split the mainmenu shortcut nodes into the menuitems list
            fullMenu = False
            if groups == "" or groups.split( "|" )[0] == "mainmenu":
                # Set a skinstring that marks that we're providing the whole menu
                xbmc.executebuiltin( "Skin.SetBool(SkinShortcuts-FullMenu)" )
                for node in DATA._get_shortcuts( "mainmenu", None, True, profile[0] ).findall( "shortcut" ):
                    menuitems.append( node )
                fullMenu = True
            else:
                # Clear any skinstring marking that we're providing the whole menu
                xbmc.executebuiltin( "Skin.Reset(SkinShortcuts-FullMenu)" )
                    
            # If building specific groups, split them into the menuitems list
            count = 0
            if groups != "":
                for group in groups.split( "|" ):
                    if count != 0 or group != "mainmenu":
                        menuitems.append( group )
                        
            if len( menuitems ) == 0:
                # No groups to build
                break
                
            itemidmainmenu = 0
            percent = profilePercent / len( menuitems )
            
            i = 0
            for item in menuitems:
                i += 1
                itemidmainmenu += 1
                progress.update( ( profilePercent * profileCount) + percent * i )
                submenuDefaultID = None

                if not isinstance( item, basestring ):
                    # This is a main menu item (we know this because it's an element, not a string)
                    submenu = item.find( "labelID" ).text

                    # Build the menu item
                    menuitem = self.buildElement( item, "mainmenu", None, profile[1], DATA.slugify( submenu, convertInteger=True ), itemid = itemidmainmenu, options = options )

                    # Add the menu item to the various includes, retaining a reference to them
                    mainmenuItemA = copy.deepcopy( menuitem )
                    mainmenuTree.append( mainmenuItemA )

                    if buildMode == "single":
                        mainmenuItemB = copy.deepcopy( menuitem )
                        allmenuTree.append( mainmenuItemB )

                    templateMainMenuItems.append( copy.deepcopy( menuitem ) )

                    # Get submenu defaultID
                    submenuDefaultID = item.find( "defaultID" ).text
                else:
                    # It's an additional menu, so get its labelID
                    submenu = DATA._get_labelID( item, None )
                    
                # Build the submenu
                count = 0 # Used to keep track of additional submenu
                for submenuTree in submenuTrees:
                    submenuVisibilityName = submenu
                    if count == 1:
                        submenu = submenu + "." + str( count )
                    elif count != 0:
                        submenu = submenu[:-1] + str( count )
                        submenuVisibilityName = submenu[:-2]
                        
                    # Get the tree's we're going to write the menu to
                    if submenu in submenuNodes:
                        justmenuTreeA = submenuNodes[ submenu ][ 0 ]
                        justmenuTreeB = submenuNodes[ submenu ][ 1 ]
                    else:
                        # Create these nodes
                        justmenuTreeA = xmltree.SubElement( root, "include" )
                        justmenuTreeB = xmltree.SubElement( root, "include" )
                        
                        justmenuTreeA.set( "name", "skinshortcuts-group-" + DATA.slugify( submenu ) )
                        justmenuTreeB.set( "name", "skinshortcuts-group-alt-" + DATA.slugify( submenu ) )
                        
                        submenuNodes[ submenu ] = [ justmenuTreeA, justmenuTreeB ]
                        
                    itemidsubmenu = 0
                    
                    # Get the shortcuts for the submenu
                    if count == 0:
                        submenudata = DATA._get_shortcuts( submenu, submenuDefaultID, True, profile[0] )
                    else:
                        submenudata = DATA._get_shortcuts( submenu, None, True, profile[0] )
                        
                    if type( submenudata ) == list:
                        submenuitems = submenudata
                    else:
                        submenuitems = submenudata.findall( "shortcut" )
                    
                    # Are there any submenu items for the main menu?
                    if count == 0:
                        if len( submenuitems ) != 0:
                            try:
                                hasSubMenu = xmltree.SubElement( mainmenuItemA, "property" )
                                hasSubMenu.set( "name", "hasSubmenu" )
                                hasSubMenu.text = "True"
                                if buildMode == "single":
                                    hasSubMenu = xmltree.SubElement( mainmenuItemB, "property" )
                                    hasSubMenu.set( "name", "hasSubmenu" )
                                    hasSubMenu.text = "True"
                            except:
                                # There probably isn't a main menu
                                pass
                        else:   
                            try:
                                hasSubMenu = xmltree.SubElement( mainmenuItemA, "property" )
                                hasSubMenu.set( "name", "hasSubmenu" )
                                hasSubMenu.text = "False"
                                if buildMode == "single":
                                    hasSubMenu = xmltree.SubElement( mainmenuItemB, "property" )
                                    hasSubMenu.set( "name", "hasSubmenu" )
                                    hasSubMenu.text = "False"
                            except:
                                # There probably isn't a main menu
                                pass
                
                    # If we're building a single menu, update the onclicks of the main menu
                    if buildMode == "single" and not len( submenuitems ) == 0:
                        for onclickelement in mainmenuItemB.findall( "onclick" ):
                            if "condition" in onclickelement.attrib:
                                onclickelement.set( "condition", "StringCompare(Window(10000).Property(submenuVisibility)," + DATA.slugify( submenuVisibilityName, convertInteger=True ) + ") + [" + onclickelement.attrib.get( "condition" ) + "]" )
                                newonclick = xmltree.SubElement( mainmenuItemB, "onclick" )
                                newonclick.text = "SetProperty(submenuVisibility," + DATA.slugify( submenuVisibilityName, convertInteger=True ) + ",10000)"
                                newonclick.set( "condition", onclickelement.attrib.get( "condition" ) )
                            else:
                                onclickelement.set( "condition", "StringCompare(Window(10000).Property(submenuVisibility)," + DATA.slugify( submenuVisibilityName, convertInteger=True ) + ")" )
                                newonclick = xmltree.SubElement( mainmenuItemB, "onclick" )
                                newonclick.text = "SetProperty(submenuVisibility," + DATA.slugify( submenuVisibilityName, convertInteger=True ) + ",10000)"
                    
                    # Build the submenu items
                    for submenuItem in submenuitems:
                        itemidsubmenu += 1
                        # Build the item without any visibility conditions
                        menuitem = self.buildElement( submenuItem, submenu, None, profile[1], itemid = itemidsubmenu, options = options )
                        isSubMenuElement = xmltree.SubElement( menuitem, "property" )
                        isSubMenuElement.set( "name", "isSubmenu" )
                        isSubMenuElement.text = "True"

                        # Add it, with appropriate visibility conditions, to the various submenu includes
                        justmenuTreeA.append( copy.deepcopy( menuitem ) )

                        menuitemCopy = copy.deepcopy( menuitem )
                        visibilityElement = menuitemCopy.find( "visible" )
                        visibilityElement.text = "[%s] + %s" %( visibilityElement.text, "StringCompare(Window(10000).Property(submenuVisibility)," + DATA.slugify( submenuVisibilityName, convertInteger=True ) + ")" )
                        justmenuTreeB.append( menuitemCopy )

                        if buildMode == "single":
                            # Add the property 'submenuVisibility'
                            allmenuTreeCopy = copy.deepcopy( menuitemCopy )
                            submenuVisibility = xmltree.SubElement( allmenuTreeCopy, "property" )
                            submenuVisibility.set( "name", "submenuVisibility" )
                            submenuVisibility.text = DATA.slugify( submenuVisibilityName, convertInteger=True )
                            allmenuTree.append( allmenuTreeCopy )

                        menuitemCopy = copy.deepcopy( menuitem )
                        visibilityElement = menuitemCopy.find( "visible" )
                        visibilityElement.text = "[%s] + %s" %( visibilityElement.text, "StringCompare(Container(" + mainmenuID + ").ListItem.Property(submenuVisibility)," + DATA.slugify( submenuVisibilityName, convertInteger=True ) + ")" )
                        submenuTree.append( menuitemCopy )
                            
                    # Build the template for the submenu
                    Template.parseItems( "submenu", count, justmenuTreeA, profile[ 2 ], profile[ 1 ], "StringCompare(Container(" + mainmenuID + ").ListItem.Property(submenuVisibility)," + DATA.slugify( submenuVisibilityName, convertInteger=True ) + ")", item )
                        
                    count += 1

            if self.hasSettings == False:
                # Check if the overrides asks for a forced settings...
                overridestree = DATA._get_overrides_skin()
                forceSettings = overridestree.getroot().find( "forcesettings" )
                if forceSettings is not None:
                    # We want a settings option to be added
                    newelement = xmltree.SubElement( mainmenuTree, "item" )
                    xmltree.SubElement( newelement, "label" ).text = "$LOCALIZE[10004]"
                    xmltree.SubElement( newelement, "icon" ).text = "DefaultShortcut.png"
                    xmltree.SubElement( newelement, "onclick" ).text = "ActivateWindow(settings)" 
                    xmltree.SubElement( newelement, "visible" ).text = profile[1]
                    
                    if buildMode == "single":
                        newelement = xmltree.SubElement( mainmenuTree, "item" )
                        xmltree.SubElement( newelement, "label" ).text = "$LOCALIZE[10004]"
                        xmltree.SubElement( newelement, "icon" ).text = "DefaultShortcut.png"
                        xmltree.SubElement( newelement, "onclick" ).text = "ActivateWindow(settings)" 
                        xmltree.SubElement( newelement, "visible" ).text = profile[1]
                            
            if len( self.checkForShortcuts ) != 0:
                # Add a value to the variable for all checkForShortcuts
                for checkForShortcut in self.checkForShortcuts:
                    if profile[ 1 ] is not None and xbmc.getCondVisibility( profile[ 1 ] ):
                        # Current profile - set the skin bool
                        if checkForShortcut[ 2 ] == "True":
                            xbmc.executebuiltin( "Skin.SetBool(%s)" %( checkForShortcut[ 1 ] ) )
                        else:
                            xbmc.executebuiltin( "Skin.Reset(%s)" %( checkForShortcut[ 1 ] ) )
                    # Save this to the hashes file, so we can set it on profile changes
                    hashlist.list.append( [ "::SKINBOOL::", [ profile[ 1 ], checkForShortcut[ 1 ], checkForShortcut[ 2 ] ] ] )

            # Build the template for the main menu
            Template.parseItems( "mainmenu", 0, templateMainMenuItems, profile[ 2 ], profile[ 1 ], "", "", mainmenuID )

            # If we haven't built enough main menu items, copy the ones we have
            while itemidmainmenu < minitems and fullMenu and len( mainmenuTree ) != 0:
                updatedMenuTree = copy.deepcopy( mainmenuTree )
                for item in updatedMenuTree:
                    itemidmainmenu += 1
                    # Update ID
                    item.set( "id", str( itemidmainmenu ) )
                    for idElement in item.findall( "property" ):
                        if idElement.attrib.get( "name" ) == "id":
                            idElement.text = "$NUM[%s]" %( str( itemidmainmenu ) )
                    mainmenuTree.append( item )
                
        # Build any 'Other' templates
        Template.writeOthers()
        
        progress.update( 100, message = __language__( 32098 ) )
                
        # Get the skins addon.xml file
        addonpath = xbmc.translatePath( os.path.join( "special://skin/", 'addon.xml').encode("utf-8") ).decode("utf-8")
        addon = xmltree.parse( addonpath )
        extensionpoints = addon.findall( "extension" )
        paths = []
        for extensionpoint in extensionpoints:
            if extensionpoint.attrib.get( "point" ) == "xbmc.gui.skin":
                resolutions = extensionpoint.findall( "res" )
                for resolution in resolutions:
                    path = xbmc.translatePath( os.path.join( try_decode( self.skinDir ) , try_decode( resolution.attrib.get( "folder" ) ), "script-skinshortcuts-includes.xml").encode("utf-8") ).decode('utf-8')
                    paths.append( path )
        skinVersion = addon.getroot().attrib.get( "version" )
        
        # Save the tree
        DATA.indent( tree.getroot() )
        for path in paths:
            tree.write( path, encoding="UTF-8" )
            
            # Save the hash of the file we've just written
            with open(path, "r+") as f:
                DATA._save_hash( path, f.read() )
                f.close()
            
        # Save the hashes
        # Append the skin version to the hashlist
        hashlist.list.append( ["::SKINVER::", skinVersion] )

        # Save the hashes
        file = xbmcvfs.File( os.path.join( __masterpath__ , xbmc.getSkinDir() + ".hash" ), "w" )
        file.write( repr( hashlist.list ) )
        file.close