Skip to content

Scripting Engine

jurialmunkey edited this page Feb 26, 2025 · 1 revision

Scripting Engine

Skin variables has a powerful skin scripting engine for chaining conditional commands together. Scripting engine files are stored in json format and run via RunScript

RunScript(script.skinvariables,run_executebuiltin=special://skin/shortcuts/builtins/commands.json,use_rules=True)

The above runs the command file shortcuts/builtins/commands.json
Any location and filename can be used.

The use_rules=True param must be specified to indicate that the script will be running commands from a file.

Basic Command File

Below is a basic example script e.g. our commands.json file

{
    "infolabels": {
        "fanart_path": "ListItem.Art(fanart)",
        "landscape_path": "ListItem.Art(landscape)"
    },
    "regex": {},
    "values": {},
    "sums": {},
    "decode": {},
    "encode": {},
    "escape": {},
    "capitalize": {},
    "lower": {},
    "upper": {},
    "operations": [],
    "actions": [
        "SetProperty(Fanart_Path,{fanart_path},Home)",
        "SetProperty(Landscape_Path,{landscape_path},Home)"
    ]
}

In effect this example is equivalent to:

SetProperty(Fanart_Path,$INFO[ListItem.Art(fanart)],Home)
SetProperty(Landscape_Path,$INFO[ListItem.Art(landscape)],Home)

NOTE: The lines with empty sections such as "regex" and "values" etc. are optional and can be removed if empty. They are displayed above to demonstrate possible options.

Infolabels

Retrieves $INFO[info] values and stores as a key
Any infolabel from https://kodi.wiki/view/InfoLabels can be used

"infolabels": {
    "key_01": "info_01",
    "key_02": "info_02"
}

Values

At times you may want some values to be conditional similar to a $VAR.

Conditional values are specified in the values section and have a list of rules to be met for the corresponding value to be stored into the key. The conditions are evaluated in order until a match is found (similar to how a $VAR might operate).tion)

Example:

{
    "infolabels": {
        "landscape_path": "ListItem.Art(landscape)",
        "fallback_path": "Skin.String(Landscape.FallBack)"
    },
    "values": {
        "image_path": [
            {
                "rules": ["{landscape_path}!="],
                "value": "{landscape_path}"
            },
            {
                "rules": ["{fallback_path}!="],
                "value": "{fallback_path}"
            },
            "special://skin/extras/backgrounds/default.jpg"
        ]
    },
    "actions": [
        "SetProperty(Landscape_Path,{image_path},Home)"
    ]
}

In effect this example is equivalent to:

<variable name="image_path">
    <value condition="!String.ISEmpty(ListItem.Art(landscape))">$INFO[ListItem.Art(landscape)]</value>
    <value condition="!String.ISEmpty(Skin.String(Landscape.FallBack))">$INFO[Skin.String(Landscape.FallBack)]</value>
    <value>special://skin/extras/backgrounds/default.jpg</value>
</variable>

SetProperty(Landscape_Path,$VAR[image_path],Home)

Rules Operators

Operator Description Example
== Equal ["{color}==blue"] "value in color equals blue"
!= Not Equal ["{color}!=blue"] "value in color does not equal blue"
<< Contains ["{color}<<blue"] "value in color contains blue" e.g. also matches if value is "deep blue" or "light blue" or "blue green" etc.
>> Contained ["{color}>>blue"] "value in color contained in blue" i.e. reverse of contains
!< Not Contains ["{color}!<blue"] "value in color does not contain blue" i.e. inverse of contains
!> Not Contained ["{color}!>blue"] "value in color is not contained in blue" i.e. inverse of contained

Empty values

Rules to compare against an empty value is as simple as leaving the other side of the operator blank
Example ["{color}=="] is "the value in color is empty"
Example ["{color}!="] is "the value in color is not empty"

Skin Boolean Conditions

Rules can also use skin engine booleans as conditions.
Any boolean from https://kodi.wiki/view/List_of_boolean_conditions can be used

Example: The value in color contains blue and the videoosd window is visible:

"rules": [
    "{color}<<blue",
    "Window.IsVisible(videoosd)"
]

AND operator

Rules can be chained together as a list of AND conditions where all conditions must be met.
AND conditions are a comma separated list of conditions.

Example: Match where value in color contains "blue" but not "deep" so matches "blue" or "light blue" or "blue green" but not "deep blue"

"rules": [
    "{color}<<blue",
    "{color}!<deep"
]

OR operator

Rules can also specify an OR condition with a double pipe || symbol
Example: Match where value in color contains either blue or green

["{color}<<blue||{color}<<green"]

AND plus OR operator

Example: Match where value in color contains "blue" or "green" but not "deep"

"rules": [
    "{color}<<blue||{color}<<green",
    "{color}!<deep"
]

Capitalize / Upper / Lower

Example: Modify the capitalization of the value stored in key and output to a different key

"capitalize": {"capitalized_key": "{key}"},
"upper": {"upper_key": "{key}"},
"lower": {"lower_key": "{key}"}

Regex

Use a regex condition to substitute a value using re.sub()

Example: Substitute all numbers found in key with an "X" and output back to key

"regex": {
    "key": {
         "regex": "[0-9]",
         "value": "X",
         "input": "{key}"
    }
}

Sums

Example: Sum a list of numbers together

"sums": {"total_value": ["{key_01}", "{key_02}", "{key_03}"]}

Decode / Encode

Apply URL decoding/encoding

Example:

"decode": {"decoded_key": "{key}"},
"encode": {"encoded_key": "{key}"}

Escape

Apply XML escaping e.g. convert & to &amp;

Example:

"escape": {"escaped_key": "{key}"}

Operations

By default the order of operations that occur before actions are:

  1. infolabels
  2. regex
  3. values
  4. sums
  5. decode
  6. encode
  7. escape
  8. lower
  9. upper

However, at times you may wish to specify a custom order for operations (e.g. to do regex after values etc.).

A custom list of operations can be specified with the operations list. The list of operations is conducted after all main operations complete but before actions.

Example:

"operations": [
    {"values": {VALUES_SECTION_GOES_HERE}},
    {"regex": {REGEX_SECTION_GOES_HERE}}
    [etc]
]

Passing external key values via RunScript

At times you may also wish to specify the value of a key at the moment of running the script itself. These key value pairs can be specified when running the script itself. Any key name can be used as long as it doesn't conflict with some other script command used by skin variables.

Example: Set key_01 to value_01 and key_02 to $INFO[System.Time]

RunScript(
script.skinvariables,
run_executebuiltin=special://skin/shortcuts/builtins/commands.json,
use_rules=True,
key_01=value_01,
key_02=$INFO[System.Time]
)

The above example is split onto separate lines for readability. Use as a single line command.

Conditional Actions

Actions can also be conditional, with multiple actions chained as values.

Example

"actions": [
    {
        "rules": ["!Container.IsUpdating"],
        "value": [
             "Notification(Container,Finished updating)", 
             "SetProperty(ContainerUpdating,False)"
        ]
    },
    {
        "rules": ["Container.IsUpdating"],
        "value": [
             "Notification(Container,Still updating)", 
             "SetProperty(ContainerUpdating,True)"
        ]
    },
]

Advanced Actions

Sleep

A sleep command can be used to wait between actions

Example:

"actions": [
    "Notification(SV,Sleep for 2.5 seconds)",
    "sleep=2.5",
    "Notification(SV,Wake Up)"
]

Route to skinvariables script

Occasionally you might want to reroute back to a skinvariables script. If you use the normal RunScript approach, the command will be triggered and then the next action will run immediately. However, it might be necessary to wait for the script to complete first. In that case use route=

Example:

"actions": [
    "route=run_executebuiltin=special://skin/shortcuts/builtins/other_commands.json&use_rules=True",
    "Notification(SV,Other Commands Completed)"
]

Variable Commands

More advanced actions that normally wouldn't be permitted by the skinning engine are also possible such as using a variable command from a key

Example: Use command stored in a window property:

"infolabels": {
    "string_command": "Window.Property(StringCommand)",
    "string_name": "Window.Property(StringName)",
    "string_value": "Window.Property(StringValue)"
}
"actions": [
    "{string_command}({string_name},{string_value})"
]

If we run SetProperty(StringCommand,Skin.SetString) before running the above then it will run as:

Skin.SetString($INFO[Window.Property(StringName)],$INFO[Window.Property(StringValue)])

If we run SetProperty(StringCommand,SetProperty) however, then the above will run as this instead:

SetProperty($INFO[Window.Property(StringName)],$INFO[Window.Property(StringValue)])