Difference between revisions of "Expression Language"

From JRiverWiki
Jump to: navigation, search
m (rorollibocc)
(Formatting Functions)
 
(265 intermediate revisions by 15 users not shown)
Line 1: Line 1:
noligetlidel
+
{{Tocright}}
==Overview==
+
Media Center provides a simple programming language that enhances and enriches its overall user interface and usability.
 +
This language, commonly called the expression language, is simple to learn, simple to use, and can greatly enhance your experience using Media Center.
  
The J. River Media Core database engine supports Excel-style functions for use in view schemes, searches, displayed columns, and tag editing.
+
Expressions are ubiquitous throughout Media Center, used in areas such as:
 +
:* The categories in a view
 +
:* File list expression columns
 +
:* Theater View
 +
:* Customized view headers, grouping and sort criteria
 +
:* The library field manager (fields with data type Calculated data)
 +
:* File and folder location definitions
 +
:* Auto-import rules
 +
:* Custom DLNA titles
 +
:* The player's display
 +
:* Captions and thumbnail text
 +
:* The link manager (expressions help format link URLs)
 +
:* Rename, Move, & Copy tool
 +
:* Tag assignment
 +
:* Complex search queries
  
An expression is a mixture of text, fields, and functions.
+
An expression is a mixture of ordinary text, pre-defined functions, and a few reserved characters and constructs that have special meaning. An expression is evaluated by Media Center's expression engine and textual output is produced. This output is then used by Media Center to customize the user interface and affect its method of operation.
  
    Examples:
+
== The Anatomy of an Expression ==
    This is simple text
 
    This is an artist: [Artist]
 
    The song [Name] is rated [Rating] stars
 
    The file is FormatBoolean(IsMissing(), missing from, on) your machine
 
  
====Fields====
+
As mentioned above, an expression is a mixture of text and function calls (and some reserved stuff described shortly).
 +
The simplest expression would be some basic, literal text, such as <span style="font-family: monospace,monospace; font-size:1em;">A good movie</span>.
 +
The expression engine evaluates this expression, finds nothing special, and then outputs the result: <span style="font-family: monospace,monospace; font-size:1em;">A good movie</span>.  Simple.
  
Any text between brackets [] will be replaced with the corresponding field. As an example, [Artist] would be replaced by Bob Dylan for any Bob Dylan tracks. If the text between brackets doesn't match any known fields, it will be left alone. After the field name, a comma can be placed followed by a 0 or 1 for whether the field should get formatted.  So, [Duration] and [Duration, 1] will give "4:02" while [Duration, 0] will give "242".
+
But simple text only has so much utility.
 +
The ability to transform or generate content is much more interesting and useful.
 +
And this is when [[#Functions|functions]] are employed.
 +
Media Center [[#Function Index|provides many functions]], which when called, produce some output.
 +
Most functions require some form of input, called arguments, and most functions generate output.
 +
By supplying a function with various arguments, the function will return some output value which is just more text.
 +
And this output text can be the used by other functions, and so on.
 +
Each function has a unique name, and calling upon a function to do some work requires little more that using its name anywhere in the expression.
  
==Functions==
+
A function call looks like this:
  
A function allows special operations to be performed. A list of functions follows:
+
:{{monospace|<i>functionname</i><b>(</b><i>argument 1</i>, <i>argument 2</i>, ...<b>)</b>}}
  
===Field(...): Outputs the value for a given field.===
+
The syntax of the function call is the function's case-insensitive name, immediately followed by an opening parenthesis character, one or more comma-separated arguments, and a closing parenthesis character.
'''Field name:''' the name of the field to evaluate (i.e. Artist, Album, Name, etc.)<br>
+
Whitespace after the commas is optional, but helps readability and formatting.
'''Format for display:''' 0 to use raw data, 1 to use data formatted for display (optional: defaults to 1)
+
And each argument itself is also just an expression. And some arguments are optional.
 +
If an argument is optional, it can be omitted and its default value will be used.
 +
If the argument is omitted, a comma-separator will still be required if additional arguments follow.
 +
The following example uses the [[String_Manipulation_Functions#FixCase|FixCase()]] function to change its input to Title Case:
  
Notes:<br>
+
:{{monospace|fixcase(A good movie)}}
You can use brackets around a field to accomplish the same thing.  For example, GetField(Artist) can be replaced by [Artist] and GetField(Artist, 0) can be replaced by [Artist, 0].
 
  
    Examples:
+
The result is <span style="font-family: monospace,monospace; font-size:1em;">A Good Movie</span>.
    Field(Artist)
 
    Field(Artist, 0)
 
  
===If(...): Outputs different values depending on the value of the first parameter.===
+
A slightly more complex expression example consists of both text and a nested function call:
'''Test Expression:''' the value that gets tested<br>
 
'''True:''' the value used if the test expression equals 1<br>
 
'''False:''' the value used if the test expression does not equal 1<br>
 
    Examples:
 
    If(1, 1, 0)
 
    If(IsMissing(), The file is missing., The file is here.)
 
    If(IsEqual([Artist], Abba, 1), Too embarrassing, [Artist])
 
  
===IsMissing(...): Checks to see if a file exists on the system.===
+
:{{monospace|Wow! fixcase(replace(A good movie, good, great))}}
'''Filename:''' the filename to check (optional: defaults to this file)
 
    Examples:
 
    IsMissing()
 
    IsMissing([Filename])
 
  
===IsRemovable(...): Checks to see if a file resides on removable media.===
+
Inner functions are called before outer functions, so the [[String_Manipulation_Functions#Replace|Replace()]] function is call first:
'''Filename:''' the filename to check (optional: defaults to this file)
 
    Examples:
 
    IsRemovable()
 
    IsRemovable([Filename])
 
  
===IsEqual(...): Compares values and outputs a "1" if the values pass the test, and "0" if they don't pass the test.===
+
:{{monospace|replace(A good movie, good, great)}}
'''Value 1:''' the first value<br>
 
'''Value 2:''' the second value<br>
 
'''Compare type:''' the mode to compare (optional: defaults to case-sensitive string compare)<br>
 
:'''0:''' case-sensitive string compare for equality<br>
 
:'''1:''' case-insensitive string compare for equality<br>
 
:'''2:''' numeric compare for equality<br>
 
:'''3:''' numeric less than<br>
 
:'''4:''' numeric less than or equal to<br>
 
:'''5:''' numeric greater than<br>
 
:'''6:''' numeric greater than or equal to<br>
 
:'''7:''' substring search (case sensitive)<br>
 
:'''8:''' substring search (case insensitive)<br>
 
    Examples:
 
    IsEqual([Artist], [Album], 1)
 
    IsEqual([Duration, 0], [Bitrate, 0], 2)
 
  
===IsEmpty(...): Tests to see if a value is empty and outputs a "1" if the value is empty, and "0" if it's not empty.===
+
and its output is then supplied as the input to the [[String_Manipulation_Functions#FixCase|FixCase()]] function.
'''Value:''' the value to test<br>
+
[[String_Manipulation_Functions#Replace|Replace()]] does its work substituting {{monospace|good}} with {{monospace|great}}, and returns {{monospace|A great movie}}.
'''Mode:''' the mode to test (optional: defaults to 0)
+
This output is then supplied as the argument to [[String_Manipulation_Functions#FixCase|FixCase()]] which sees only the text {{monospace|A great movie}} (it knows nothing about how it was produced).  So the function call:
:'''0:''' string style, so "" is empty<br>
 
:'''1:''' number style, so "" or 0 is empty
 
    Examples:
 
    IsEmpty([Artist])
 
    IsEmpty([Duration], 1)
 
  
===IsRange(...): Compares a value against a range and outputs a "1" if the values is inside the range, and "0" if not.===
+
:{{monospace|fixcase(A great movie)}}
'''Value:''' the value to test<br>
 
'''Range:''' the range of values (in the form: a-z or 1-100)<br>
 
  
    Examples:
+
in turn outputs {{monospace|A Great Movie}}.
    IsRange([Artist], a-b)
+
Now that the functions have produced their output, the final output, including the literal {{monospace|Wow!}} leading text is
    IsRange([Bitrate], 128-192)
 
  
===FilePath(...): Returns the path from a filename.===
+
:{{monospace|Wow! A Great Movie}}
'''Filename:''' the filename to check (optional: defaults to this file)
 
  
    Examples:
+
== Fields ==
    FilePath()
+
The expression examples thus far have been limited to static literal text.
    FilePath([Filename])
+
Expressions have much more utility when they use data from other sources, such as a file's metadata.
 +
Media Center maintains this metadata in its defined fields.
 +
This data is accessed using the [[Accessing_and_Storing_Functions#Field|Field()]] function, and its first argument is the case-insensitive name of the field to be accessed.
 +
For example, the function call <span style="font-family: monospace,monospace; font-size:1em;">field(album)</span> will return the current* file's value for the album field (* more will be said later about the current file).
 +
If the album field contained the value <span style="font-family: monospace,monospace; font-size:1em;">After Hours</span>, the expression:
  
===FileName(...): Returns the name from a filename. ===
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">fixcase(field(album), 3)</span></div>
'''Filename:''' the filename to check (optional: defaults to this file)
 
  
    Examples:
+
would produce <span style="font-family: monospace,monospace; font-size:1em;">AFTER HOURS</span>.
    FileName()
+
First <span style="font-family: monospace,monospace; font-size:1em;">field(album)</span> is evaluated, returning <span style="font-family: monospace,monospace; font-size:1em;">After Hours</span>.
    FileName([Filename])
+
The [[String_Manipulation_Functions#FixCase|FixCase()]] function is supplied with this output as its first argument, and its second argument is <span style="font-family: monospace,monospace; font-size:1em;">3</span>, which happens to specify that it should perform upper-casing.
  
===FileVolume(...): Returns the volume name from a filename.===
+
Because fields are so frequently used in expressions, an abbreviated form called [[square bracket notation]] exists for accessing their values. This makes it easier to both read and write expressions.
'''Filename:''' the filename to check (optional: defaults to this file)
+
Nonetheless, both forms are equivalent.
 +
The abbreviated form is simple: immediately surround the field's name with opening and closing square brackets, for example, <span style="font-family: monospace,monospace; font-size:1em;">[album]</span>.
 +
The previous example is now written more simply as:
  
    Examples:
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">fixcase([album], 3)</span></div>
    FileVolume()
 
    FileVolume([Filename])
 
  
===FormatNumber(...): Formats a number in a specified manner.===
+
=== Field Values ===
'''Value:''' the number to format<br> 
+
For the sake of simplicity and clarity, the section above glossed over an important detail regarding how
'''Number of decimal places:''' specifies how many decimals to use (-1 uses as many as necessary) (optional: defaults to 0)
+
Media Center outputs field values.
    Examples:                     
+
Recall that [[Accessing_and_Storing_Functions#Field|Field()]] is the function used to return the value of a specified field.
    FormatNumber(3.123224, 0)     
+
But [[Accessing_and_Storing_Functions#Field|Field()]] also has a second argument that indicates the format of the value that it returns.
    FormatNumber([Replay Gain, 0], 3)
+
Because field values are used in a variety of situations, the [[Accessing_and_Storing_Functions#Field|Field()]] function can produce output suitably formatted for the requirements.
    FormatNumber([Duration, 0])   
+
There are two forms of output: one is a nice, friendly human-readable format suitable for use in views or other display locations; the other is a raw format which returns the representation stored internally by Media Center which is useful when uninterpreted values are necessary.
                                 
 
===FormatDate(...): Formats a date value in a specified manner.===
 
'''Value:''' the date to format<br> 
 
'''Formatting:''' formatting style
 
:'''Year:''' 1997             
 
:'''Month:''' March           
 
:'''Day:''' 12                 
 
:'''Filename:''' 20040521-032221
 
:'''Elapsed:''' 3.2 days ago   
 
:'''Other:''' flexible formatting (i.e. yy-MMMM-dd)
 
No Date Output: the output when the date is empty (optional: defaults to nothing)
 
    Examples:                     
 
    FormatDate([Date Imported, 0], elapsed)
 
    FormatDate([Date, 0], MMMM: d, no date)
 
                                 
 
===FormatBoolean(...): Formats a boolean (true / false) value in a specified manner.===
 
'''Value:''' the boolean to format (optional: defaults to false)<br>
 
'''True display:''' string to display for true (optional: defaults to "True")<br>
 
'''False display:''' string to display for false (optional: defaults to "False")
 
    Examples:                     
 
    FormatBoolean(1)             
 
    FormatBoolean(IsMissing(), File missing, File exists)
 
                                 
 
===FormatDuration(...): Formats a duration in seconds to a readable string.===
 
'''Value:''' the value to format    
 
                                 
 
    Examples:                     
 
    FormatDuration(60)           
 
    FormatDuration([Duration, 0]) 
 
                                 
 
===FormatFileSize(...): Formats a number of bytes as a readable string.===
 
'''Value:''' the value to format   
 
                                 
 
    Examples:                     
 
    FormatFileSize(1024)         
 
    FormatFileSize([File Size, 0])
 
                                 
 
===FormatRange(...): Formats a value as a range.===
 
'''Value:''' the value to format<br>
 
'''Range size:''' the number of letters / numbers to put in a grouping (optional: defaults to 1)<br>
 
'''Mode:''' the mode to perform the grouping (optional: defaults to 0)
 
:0: automatically choose between number / letter grouping
 
:1: use letter grouping   
 
:2: use number grouping   
 
    Examples:                     
 
    FormatRange(Abba, 3)         
 
    FormatRange([Artist])         
 
    FormatRange([Bitrate, 0], 100, 2)
 
                                 
 
===AlbumArtist(...): Returns the calculated album artist for a file.===
 
No parameters                 
 
                                 
 
    Examples:                     
 
    AlbumArtist()                 
 
                                 
 
===AlbumType(...): Returns the album type for a file.===
 
No parameters                 
 
                                 
 
    Examples:                    
 
    AlbumType()                   
 
                                 
 
===Size(...): Returns the size of a file in a media-type independent manner.===
 
No parameters                 
 
                                 
 
    Examples:                     
 
    Size()                       
 
                                 
 
===CustomData(...): Returns custom data stored in a file array. (used primarily for internal uses)===
 
'''Field:''' a field name ("#" gets the array sequence number)
 
                                 
 
    Examples:                     
 
    CustomData(#)                 
 
    CustomData(My Special List Data Field)
 
                                 
 
===Clean(...): Returns a cleaned up version of a filled in template.===
 
'''Value:''' the value to clean     
 
                                 
 
    Examples:                     
 
    Clean(Size())                 
 
    Clean([Artist] - [Album] /([Genre]/))
 
                                 
 
===FixCase(...): Changes the case of a string.===
 
'''Value:''' the value to change<br>
 
'''Mode:''' case mode (optional: defaults to title case)
 
:0: title case             
 
:1: all words             
 
:2: first word             
 
:3: all uppercase         
 
:4: all lowercase         
 
                                 
 
    Examples:                     
 
    FixCase(MaKe ME PreTTy, 0)   
 
    FixCase([File Type], 3)       
 
                                 
 
===Mid(...): Retrieves specified characters from a value.===
 
'''Value:''' the value to get characters from<br>
 
'''Start:''' the character to start at (optional: defaults to 0)<br>
 
'''Characters:''' the number of characters to get (-1 returns all) (optional: defaults to 1)
 
                                 
 
    Examples:                     
 
    Mid(Abba)                     
 
    Mid(Abba, 0, 2)               
 
    Mid([Artist], 3, -1)         
 
  
===PadNumber(...): Use to add leading zeros to a number.===
+
By default, Media Center <i>always</i> outputs the friendly format, so expressions sometimes need to take this into account and chose the format accordingly.
'''Field:''' the field to pad<br>
 
'''Value:''' the number of digits you require in the number.
 
    Examples:
 
    PadNumber([track #],3)
 
  
===RemoveLeft(...) and RemoveRight(...): Use to trim characters from the start or end of a field===
+
Not used earlier because it is optional, the second argument to the [[Accessing_and_Storing_Functions#Field|Field()]] function selects the mode of output:
'''Field:''' the field to trim.<br>
+
the value <span style="font-family: monospace,monospace; font-size:1em;">0</span> selects the raw mode, and the default value of <span style="font-family: monospace,monospace; font-size:1em;">1</span> selects the friendly mode.
'''Value:''' how many characters to trim. (spaces count as characters)
+
Here are two examples using the date field, the first one outputs the date value in raw format, the second in the friendly format:
    Examples:
 
    RemoveRight(abba abc,4) returns abba
 
    RemoveRight([filename (name)],4) returns the file name without the extension. (picture.jpg becomes picture)
 
    RemoveLeft([name],3) returns '''Tangled Up In Blue''' from '''01 Tangled Up In Blue'''
 
    Note that you can select all desired files, then simply enter the expression into the [Name] field in the tag window as '''=removeleft([name],3)'''
 
  
===Counter(...): Use to return a value that starts at one and counts up with each use===
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">field(date, 0)</span></div>
'''1st Value:''' Where to start counting from. (optional. starts at 1 if not specified)<br>
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">field(date, 1)</span></div>
'''2nd Value:''' Incremental value. (optional. counts in increments of 1 if not specified)
 
    Examples:
 
    Counter() returns 0
 
    Select 10 files, pick 'Rename' from the right click menu on the Track # field and type '=Counter(1)' to number tracks sequentially
 
   
 
    Use with text:
 
    Select files, right click in the field to edit and choose rename. Type =TEXT-counter(150,2) and press enter to have the selected fields filled<br>   sequentially as TEXT-150, TEXT-152, TEXT-154 etc. etc.
 
  
    Notes:
+
==== Field Values: Override the expression, and [This] ====
    The counter function resets back to one after five seconds of inactivity.
+
[[File:ExpressionOverride.png|right]]
 +
When creating (or editing) an expression based field, there is an option, shown in the image on the right, to "Allow custom data to override the expression".
 +
When enabled, it becomes possible to open the tag for editing either inline or in the tag window, just as you would any other regular tag, and replace the expression derived data with any other static data. Complex expression based fields can very easily slow view loading times to a crawl, and in many cases, this option can help speed things up again. Imagine an expression based field that manipulates another, otherwise static field, such the [Date] field. The returned expression values will never change, so why waste time evaluating the same results over and over, when you can simply replace them with static data and so forego any future expression processing?
  
===Now(...): Use to return the current date===
+
Media Center 28 saw the introduction of a [https://yabb.jriver.com/interact/index.php/topic,124543.msg906895.html#msg906895 [This]] variable that can also be invoked, so, using the example, ''=removeleft([This], 4)'' would remove four characters from the left of "this field".
    Examples:
 
    FormatDate(Now()) formats the current date according to the system setting
 
    FormatDate(Now(), year) returns the current year
 
  
===ListItem(...): Use to return a value from a delimited list===
+
The new [This] variable can be used to override expression data. Select one, or 1000s of files, then edit, either inline or in the tag window, using the simple expression ''=[this]'' and apply to have MC replace the expression result with, the expression result, which from that point forwards, will be static data and the expression will no longer run ''<u>for those files</u>''.
'''List:''' List<br>
 
'''Index:''' Index (starts at 0)<br>
 
'''Delimiter:''' Delimiter (optional -- defaults to semi-colon)<br>
 
  
    Examples:
+
To remove the static data and return to expression evaluated data instead, simply edit again, deleting the static data, which when applied, will cause the expression evaluated result to return.
    ListItem([People], 1)
 
    ListItem([Filename (path)], 2, \)
 
  
===ListCount(...): Use to return the number of items in a delimited list===
+
'''<u>Note:</u>''' Use this "override" option with care. It requires least maintenance when used in situations where ''all'' expression values for all files for that field will be replaced with static data. Currently (October 2022) there is no way to differentiate between static data and expression derived data meaning the potential for things to get very confusing, very quickly, is very high indeed.
'''List:''' List<br>
 
'''Delimiter:''' Delimiter (optional -- defaults to semi-colon)<br>
 
  
    Examples:
+
'''<u>Note 2:</u>''' MC32 comes with the addition of the [[IsOverridden()|IsOverridden(...)]] function that now allows us to filter any given expression based field based on its override status.
    ListCount([People])
 
    ListCount([Filename (path)], \)
 
  
===Replace(...): Use to find string items and replace or remove them===
+
==== Field Values: Empty, 0, and 1 ====
'''Field:''' The field to search in
+
The Media Center expression language does not strongly differentiate between the numeric value zero <span style="font-family: monospace,monospace; font-size:1em;">0</span> and emptiness
'''String:''' What to find
+
for numeric field types Integer and Decimal.
'''replace with:''' What to replace with (optional, defaults to empty)
+
And in some cases, the numeric value of <span style="font-family: monospace,monospace; font-size:1em;">1</span> is treated similarly to the empty value.
  
    Examples:
+
When a value of 0 is entered as a numeric field's value, the raw value will be shown as <span style="font-family: monospace,monospace; font-size:1em;">0</span>,
    replace([artist],featuring,ft.) changes "Mark Ronson feat. Amy Winehouse" to "Mark Ronson ft. Amy Winehouse"
+
but the display format (as in the file list) will be shown as empty.
 +
The empty display allows for less visual noise in the user interface, since a column full of <span style="font-family: monospace,monospace; font-size:1em;">0</span> values is not usually helpful.
 +
In fact, if you attempt to set a numeric field's value to <span style="font-family: monospace,monospace; font-size:1em;">0</span> in the file list, it will immediately be displayed as empty.
  
    Notes:
+
Generally this difference is unimportant, except when testing numeric values with [[Test_and_Comparison_Functions#IsEmpty|IsEmpty()]] or [[Test_and_Comparison_Functions#IsEqual|IsEqual()]].
    All occurrences of the search are replaced, and searches are case sensitive, so:
+
It is easy to be fooled when testing such a value if the value shown in a file list is empty.
    replace([artist],a) changes "Abba" to "Abb"
+
The values shown in the Tag Action Window will reveal the actual raw value, as will an expression column using the field's raw format.
    replace([artist],A) changes "ABBA" to "BB"
 
  
===ListCombine(...): Use to merge one list type field into another===
+
Another consideration for integer fields is that when sorting, a <span style="font-family: monospace,monospace; font-size:1em;">1</span> value can sometimes sort indistinguishably from an empty value.
''ListCombine(List1, List2, Delimiter (optional, defaults to semicolon))''<br>
+
The Integer type <span style="font-family: monospace,monospace; font-size:1em;">disc #</span> field is typically empty when an album consists of only one disc, and as such, Media Center will sort
'''List1 and List2:''' the two list type fields to combine
+
the <span style="font-family: monospace,monospace; font-size:1em;">disc #</span> values of empty (<span style="font-family: monospace,monospace; font-size:1em;">0</span>) and <span style="font-family: monospace,monospace; font-size:1em;">1</span> identically.
  
    Examples:
+
The friendly output of a field can differ, depending on context.
    listcombine([keywords],[people])
+
For example, in a file list, and empty field will be shown as blank, but in the Rename, Move & Copy tool,
 +
it will be output as <span style="font-family: monospace,monospace; font-size:1em;">Unknown Disc #</span> (this ensures no blank values are generated as path components).
 +
To test such a field, always use and test against the raw format, and then expressions will be context agnostic.
  
    Notes:
+
===Field Assignment===
    If used in the keywords field, the people list will be added to the keywords field and vice-versa
+
<div>
    If used in a new field, the two lists will be added to the new field.
+
The output of an expression can be used to assign a value to a tag.
    If you specify a delimiter, the chosen delimiter is only used to seperate the two lists. So, if [keywords]=on drugs;hilarious;rainbow and [people]=rod;jane;freddy
+
This is accomplished by preceding the expression with an <span style="font-family: monospace,monospace; font-size:1em;">=</span> character.
    The given example will return on drugs;hilarious;rainbow;rod;jane;freddy and listcombine([keywords],[people],~) will return on drugs;hilarious;rainbow~rod;jane;freddy
+
The <span style="font-family: monospace,monospace; font-size:1em;">=</span> character causes the tagging engine to invoke the expression evaluator first,
 +
and then to use its output as the value to assign to the field.
 +
[[File:Field_Assignment_with_Expression.png|right]]
 +
Without the prepended <span style="font-family: monospace,monospace; font-size:1em;">=</span> character, the literal expression text itself and not its evaluated value would be stored in the tag.
 +
The expression can refer to the field's own value to modify itself, and this offers a convenient way to perform complex transformations on field values.
 +
For example, the assignment expression
  
===Tag(...): Reads in the physical file tag rather than looking in the database===
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">=removeleft([name], 4)</span></div>
''Tag([field])''<br>
 
'''[field]:''' The physical file tag to read into the database.
 
  
    Notes:
+
entered into an edit cell for the  <span style="font-family: monospace,monospace; font-size:1em;">name</span> field would remove
    .jpg files can contain EXIF, XMP, IPTC and MJMD tag blocks. When parsing file tags, MC does so in this order:
+
four characters from the left of the <span style="font-family: monospace,monospace; font-size:1em;">name</span> field's current value.
    IPTC
+
An assignment expression can be entered into the Tag Action Window, or by using inline editing in the file list or a pane entry.
    XMP
+
The image on the right shows in-place field assignment.
    MJMD
+
 
    EXIF
+
Note: Undo is supported, reverting each tag to its value prior to the assignment.
    Except for dates, where the order becomes:
+
Redo is also supported, reapplying the most recent Undo.
    IPTC
+
</div>
    XMP
+
 
    EXIF
+
== Expression Language Syntax ==
    MJMD
+
Now that the basics have been covered, the more rigorous rules of the expression language syntax can be described.
    You can force MC to read in a tag from a specific .jpg tag block by using the format: tag(EXIF: Date) to read the EXIF date, and so on.
+
 
    When using this function, capitalisation is important when it comes to defining the file tag to read in...
+
:* An expression is any sequence of literal text and any number of function calls.
    tag(exif: date) will ''not'' work, tag(exif: Date) will.
+
:* Expressions are read and evaluated left to right. Literal text is output unmodified, function calls are evaluated and their return values output.
+
:* Fields designated using [[square bracket notation]] are expanded into the equivalent [[Accessing_and_Storing_Functions#Field|Field()]] function call.
==Notes==                            
+
:* Nested function calls are evaluated from the innermost function to outermost function, and again, left to right when one function follows another.
*To use a special character (bracket, parenthesis) as regular text in a function, place a / before it. Change / to // to output an actual slash. Example: Clean([Artist] - [Album] /([Genre]/))
+
:* A function is evaluated and its returned value contextually replaces the function call in the expression
*Case (upper vs. lower) does not matter for function names, field names, and most parameters.
+
:* Within a function's argument list, whitespace is ignored before and after commas, after an opening parenthesis, and before a closing parenthesis.
*Spaces are interpreted literally in all areas, except immediately after a comma in a function.
+
:* The forward-slash escape character <span style="font-family: monospace,monospace; font-size:1em;">/</span> disables the special meaning of the character that follows it.
*To specify a data type (for sorting, etc.), add &DataType=[...] to the end of the expression where ... is one of these values:
+
:* The escape sequence <span style="font-family: monospace,monospace; font-size:1em;">/#</span> followed by <span style="font-family: monospace,monospace; font-size:1em;">#/</span> escapes everything inside.
::String: sorts as strings (with smart number handling)
+
:* The escape sequence <nowiki>/* followed by /*</nowiki> will escape everything inside returning it as given without formatting or processing.
::List: a list of strings, separated by semicolons
+
:* To use a literal parenthesis, comma, or whitespace inside of function argument lists, escape them. Whitespace within an argument's value is literal and does not need to be escaped when it is surrounded by other non-whitespace text.
::Number: sorts values as numbers (decimal or integer)
+
:* An expression may be split into multiple lines, but when it does not satisfy the conditions above regarding whitespace around function parenthesis and commas, use a forward-slash escape as the last character before the newline. Extraneous newlines in the expression editor will produce a trailing ellipsis (...) in the output.
::Path: sorts using a smart filename compare style
+
 
::Month: sorts string month names (i.e. January, February, etc.)
+
=== How Expressions Are Evaluated ===
    Examples:                
+
Expressions are evaluated in the context where they are used.
    FormatDate([Date, 0], Month)&DataType=[Month]
+
For example, an expression column in a file list is evaluated relative to those files in the file list.
*It is possible to use an expression in the search bar (or smartlist or step 4 of the View Scheme Editor). Use the following format:
+
And the general flow is that for each file in the list, the expression is evaluated and produces output.
::[=<type your expression here>]=1 ''(or 0. =1 will return all files for which the expression is true, and =0 will return all files for which it is false.)''
+
The expression only has access to the fields available for the file currently being evaluated.
    Examples:
+
This is important to remember, so it bears repeating.
    [=isequal([people],jane,1)]=1
+
One file after another, an expression is evaluated against that single file, its output is produced and stored away for use later,
An interesting point regarding expressions such as this in the search field, is that when using it to match list type fields such as people, the search is an 'exact match' type search, so the results from the above example would only contain pictures of jane on her own.
+
and then the result of that evaluation is entirely forgotten before the next file is evaluated.
*It is possible to use an expression when editing values in a file list or in the Tag Action Window.  This works like Excel formulas -- simply prepend an equal sign to the front of the edited text and it will be interpreted as an expression. (use '= to output an actual equal)
+
This means, the expression evaluator cannot use the results from one file's evaluated expression with the results of another
    Examples:
+
file's evaluation.
    Select 10 files, and in Tag Action Window, edit 'Comment' to be "=[Name] by [Artist]" (Ctrl+Z to undo)
+
 
 +
=== Expressions and Locales ===
 +
Media Center will respect the Windows locale setting for output values produced by certain functions,
 +
and within the values of certain fields.
 +
This is important to consider when writing expressions that consume such values.
 +
Under most circumstances, such values cause no harm.
 +
However special care must be taken with functions that require the use of period as the decimal point.
 +
One such function is [[Miscellaneous_Functions#Math|Math()]], which always uses period as the decimal point.
 +
If your locale uses some other character such as comma, these characters will have to be converted into periods before the
 +
critical function is called.
 +
Handling this problem is not difficult. Before passing to [[Miscellaneous_Functions#Math|Math()]] any floating point number,
 +
use [[String_Manipulation_Functions#Replace|Replace()]] first when necessary to convert the locale's decimal character into a period.
 +
Fields that cause problems are any fields that produce floating-point values,
 +
such as any Date type field in raw format (e.g. <span style="font-family: monospace,monospace; font-size:1em;">[date,0]</span>, <span style="font-family: monospace,monospace; font-size:1em;">[last played,0]</span>, <span style="font-family: monospace,monospace; font-size:1em;">[date modified,0]</span>, and <span style="font-family: monospace,monospace; font-size:1em;">[date imported,0]</span>),
 +
or any textual field that contains floating-point values that will be used for various calculations
 +
(e.g. any of the Dynamic Range variants).
 +
Certain functions such as [[Date_and_Time_Functions#Now|Now()]] and [[Date_and_Time_Functions#ConvertTime|ConvertTime()]] also return localized floating-point values.
 +
Consider also that the expression parser uses comma as the argument separator.
 +
Any literal numeric values specified as a function argument must have any embedded commas escaped.
 +
 
 +
=== A Complex Expression Example ===
 +
[[File:Expression_Editor.png|right]]
 +
Here is a more complex expression example that illustrates the various rules discussed above regarding expressions:
 +
 
 +
<span style="font-family: monospace,monospace; font-size:1em;">
 +
<div style="margin-left: 20pt">if(  IsEmpty(  [Disc #]  ),</div>
 +
<div style="margin-left: 40pt">Disc number is empty,</div>
 +
<div style="margin-left: 40pt">Delimit(</div>
 +
<div style="margin-left: 60pt">field(disc #) , </div>
 +
<div style="margin-left: 60pt">/)    ,</div>
 +
<div style="margin-left: 60pt">DISC /(</div>
 +
<div style="margin-left: 40pt">)</div>
 +
<div style="margin-left: 20pt">)</div>
 +
</span>
 +
 
 +
The expression demonstrates that
 +
:* whitespace before and after commas or opening and closing parenthesis is ignored
 +
:* expressions can be safely split into multiple lines using the whitespace rules just mentioned
 +
:* function and field names are case insensitive
 +
:* forward slash is used and required to escape parenthesis (see inside the [[Formatting_Functions#Delimit|Delimit()]] function)
 +
:* whitespace does not require escapement when surrounded by other characters (see after the <span style="font-family: monospace,monospace; font-size:1em;">C</span> in <span style="font-family: monospace,monospace; font-size:1em;">DISC</span>)
 +
:* literal text is output unmodified (<span style="font-family: monospace,monospace; font-size:1em;">Disc number is empty</span>)
 +
:* functions can be nested (Both [[Test_and_Comparison_Functions#IsEmpty|IsEmpty()]] and [[Formatting_Functions#Delimit|Delimit()]] are nested within the [[Conditional_Functions#If|If()]] function, and the [[Accessing_and_Storing_Functions#Field|Field()]] function is nested within [[Formatting_Functions#Delimit|Delimit()]]
 +
 
 +
When the expression is run, files that have no disc number will produce <span style="font-family: monospace,monospace; font-size:1em;">Disc number is empty</span>,
 +
and files that have, say, a disc number value of <span style="font-family: monospace,monospace; font-size:1em;">3</span> will produce <span style="font-family: monospace,monospace; font-size:1em;">DISC (3)</span>.
 +
 
 +
== Functions ==
 +
 
 +
Functions enable you to transform or generate content automatically. For background information on how functions are used in expressions, refer to [[#The Anatomy of an Expression|The Anatomy of an Expression]] section above.
 +
 
 +
This section describes all the various functions provided by Media Center's Expression Language.
 +
 
 +
=== Function Arguments ===
 +
 
 +
As discussed [[#The_Anatomy_of_an_Expression|above]], a function call consists of the function's case-insensitive name, immediately followed by an opening parenthesis character, one or more comma-separated arguments, and a closing parenthesis character:
 +
 
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;"><i>functionname</i><b>(</b><i>argument 1</i>, <i>argument 2</i>, ...<b>)</b></span></div>
 +
 
 +
Functions may have one or more arguments. In some cases, these arguments are optional, and will automatically use a default value if omitted. For example, these two expressions are equivalent because the mode argument for [[Test_and_Comparison_Functions#IsEmpty|IsEmpty()]] is optional and defaults to 0:
 +
:<span style="font-family: monospace,monospace; font-size:1em;">isempty([comment], 0)</span>
 +
:<span style="font-family: monospace,monospace; font-size:1em;">isempty([comment])</span>
 +
 
 +
In this case, a comma-separator will still be required if additional arguments follow the optional one. Whitespace after the commas is also optional, but helps readability and formatting. However, if any extra arguments are included in a function call which are not valid for that function, they are dropped and omitted from output. This is of particular importance when using string-manipulation functions on text. If the text you enter contains any commas, these must be escaped or the expression engine will consider text after the comma to be additional arguments.
 +
 
 +
The arguments themselves are also just expressions, and you can nest multiple functions to achieve complex logic:
 +
:<span style="font-family: monospace,monospace; font-size:1em;">if(isequal([artist], [album], 1), Eponymous, [album])</span>
 +
 
 +
Nested function calls are always treated as a ''single'' argument when used as the input to another function (so that commas in the output of one function do not need to be escaped to be used as input in another function). This includes fields, since they are expanded to the equivalent [[Accessing_and_Storing_Functions#Field|Field()]] function call.
 +
 
 +
:'''''Please Note:''''' In some cases below, such as with [[String_Manipulation_Functions#Unswap|Unswap()]], we have ignored this detail in order to simplify the examples. If you enter any text manually into a function, all commas ''must be'' escaped in order to achieve the correct result. This detail is unimportant in most real-world usages, however, because you will typically use either field values or the output of other functions as the arguments in your expressions. However, if you need to include commas in a string literal argument to a function, you need to escape every one, or block escape the entire argument.
 +
 
 +
=== [[Function Index]] ===
 +
Unfortunately, ''when'' these were actually introduced has ''not'' been tracked. The only way to be certain you have access to all of the functions below is to make sure you have the most current build of Media Center installed.<br>
 +
The available functions are grouped below based on the type of operation they might perform. If you prefer, a [[Complete Expression Language Alphabetical List|flat, alphabetically sorted function list is available here.]]<br>
 +
Over time, as Media Center evolves, expression functions are added or changed. Those changes are typically not reflected here immediately. In the list available [https://yabb.jriver.com/interact/index.php/topic,125477.msg868288.html#msg868288 here, on interact], any entries in red text are currently missing from these wiki pages.
 +
 
 +
==== [[Accessing and Storing Functions]] ====
 +
* '''[[Accessing_and_Storing_Functions#Field|Field(&hellip;)]]''': Returns a field's value.
 +
* '''[[Accessing_and_Storing_Functions#FieldQuery|FieldQuery(&hellip;)]]''': Return a list of matches based on a list of fields to search, from a selected scope of files.
 +
* '''[[Accessing_and_Storing_Functions#ItemCount|ItemCount(&hellip;)]]''': Counts the number of files that have the exact same value of the given expression as the file the expression runs in the context of.
 +
* '''[[Accessing_and_Storing_Functions#Load|Load(&hellip;)]]''': Outputs the value of a [[global variable]].
 +
* '''[[Accessing_and_Storing_Functions#Note|Note(&hellip;)]]''': Retrieve note fields.
 +
* '''[[Accessing_and_Storing_Functions#Save|Save(&hellip;)]]''': Saves a value to a [[global variable]].
 +
* '''[[Accessing_and_Storing_Functions#SaveAdd|SaveAdd(&hellip;)]]''': Adds to a [[global variable]].
 +
* '''[[Accessing_and_Storing_Functions#SetField|SetField(&hellip;)]]''': Sets a field's value.
 +
* '''[[Accessing_and_Storing_Functions#Tag|Tag(&hellip;)]]''': Returns a file's physical tag.
 +
 
 +
==== [[Conditional Functions]] ====
 +
* '''[[Conditional Functions#And|And(&hellip;)]]''': Tests a set of values and returns 1 if all are true.
 +
* '''[[Conditional Functions#FirstNotEmpty|FirstNotEmpty(&hellip;)]]''': Returns the first non-empty argument.
 +
* '''[[Conditional Functions#If|If(&hellip;)]]''': Conditional ifelse evaluator.
 +
* '''[[Conditional Functions#IfCase|IfCase(&hellip;)]]''': Functions as a switch or select case statement.
 +
* '''[[Conditional Functions#IfElse|IfElse(&hellip;)]]''': Conditional if-elseif evaluator.
 +
* '''[[Conditional Functions#Not|Not(&hellip;)]]''': Negates the results of funtions.
 +
* '''[[Conditional Functions#Or|Or(&hellip;)]]''': Tests a set of values and returns 1 if any are true.
 +
 
 +
==== [[Date and Time Functions]] ====
 +
* '''[[Date and Time Functions#CompareDates|CompareDates(&hellip;)]]''': Compares two dates, returning a formatted elapsed period between them
 +
* '''[[Date and Time Functions#ConvertDate|ConvertDate(&hellip;)]]''': Converts a human-readable date to the internal format required for use in date fields
 +
* '''[[Date and Time Functions#DateInRange|DateInRange(&hellip;)]]''': Compares a date with a range of dates
 +
* '''[[Date and Time Functions#FormatDate|FormatDate(&hellip;)]]''': Formats a date value in a specified manner
 +
* '''[[Date and Time Functions#Now|Now(&hellip;)]]''': Retrieve and display the system date
 +
* '''[[Date and Time Functions#PlaylistTime|PlaylistTime(&hellip;)]]''': Returns the time of a track in the current playlist (a sum of all previous durations)
 +
 
 +
==== [[File Path and Identifier Functions]] ====
 +
* '''[[File Path and Identifier Functions#DBLocation|DBLocation(&hellip;)]]''': Identifies a file's databases
 +
* '''[[File Path and Identifier Functions#Enviro|Enviro(&hellip;)]]''': Returns the full path to a host system variable
 +
* '''[[File Path and Identifier Functions#FileDBLocation|FileDBLocation(&hellip;)]]''': Identifies a file's databases
 +
* '''[[File Path and Identifier Functions#FileFolder|FileFolder(&hellip;)]]''': Returns the name of a file's parent
 +
* '''[[File Path and Identifier Functions#FileKey|FileKey(&hellip;)]]''': Returns a file's unique internal identifier
 +
* '''[[Miscellaneous Functions#FileLookup()|FileLookup()]]''': Looks up a file based on its filename
 +
* '''[[File Path and Identifier Functions#FileName|FileName(&hellip;)]]''': Returns a file's name component
 +
* '''[[File Path and Identifier Functions#FilePath|FilePath(&hellip;)]]''': Returns a file's path component
 +
* '''[[File Path and Identifier Functions#FileVolume|FileVolume(&hellip;)]]''': Returns a file's volume name component
 +
 
 +
==== [[Formatting Functions]] ====
 +
* '''[[Formatting Functions#Decimal|Decimal(&hellip;)]]''': Standardises the decimal point to be a dot rather than a comma
 +
* '''[[Formatting Functions#Delimit|Delimit(&hellip;)]]''': Outputs a value with head/tail strings when value is non-empty
 +
* '''[[Formatting Functions#FormatBoolean|FormatBoolean(&hellip;)]]''': Formats a boolean (true / false) value in a specified manner
 +
* '''[[Formatting Functions#FormatDuration|FormatDuration(&hellip;)]]''': Presents a duration of seconds in a reader friendly format
 +
* '''[[Formatting Functions#FormatFileSize|FormatFileSize(&hellip;)]]''': Presents a number of bytes in a reader friendly format
 +
* '''[[Formatting Functions#FormatNumber|FormatNumber(&hellip;)]]''': Formats and rounds a number to a specified number of decimal places
 +
* '''[[Formatting Functions#FormatRange|FormatRange(&hellip;)]]''': Formats a value as a range
 +
* '''[[Formatting Functions#Orientation|Orientation(&hellip;)]]''': Outputs the orientation of an image
 +
* '''[[Formatting Functions#PadNumber|PadNumber(&hellip;)]]''': Adds leading zeros to any given number
 +
* '''[[Formatting Functions#RatingStars|RatingStars(&hellip;)]]''': Outputs the value of Rating as a number of star characters
 +
* '''[[Formatting Functions#RatingStars10|RatingStars10(&hellip;)]]''': Outputs the value of a 10 star rating field as a number of star characters
 +
* '''[[Formatting Functions#Watched|Watched(&hellip;)]]''': Outputs a formatted video bookmark
 +
 
 +
==== [[Grouping Functions]] ====
 +
* '''[[Grouping Functions#GroupCount|GroupCount(&hellip;)]]''': Counts the members of a specified group (in a category or field).
 +
* '''[[Grouping Functions#GroupCountQuery|GroupCountQuery(&hellip;)]]''': Globally counts the number of items in a specified group.
 +
* '''[[Grouping Functions#GroupSummary|GroupSummary(&hellip;)]]''': Smartly summarizes the members of a specified group (mode, mean, min, max, etc as is most logical for that grouping).
 +
* '''[[Grouping Functions#GroupSummaryQuery|GroupSummaryQuery(&hellip;)]]''': Get a summary for the current group of files based on another matching field.
 +
 
 +
==== [[List Manipulation Functions]] ====
 +
* '''[[List Manipulation Functions#ListBuild|ListBuild(&hellip;)]]''': Constructs a list from a series of items
 +
* '''[[List Manipulation Functions#ListClean|ListClean(&hellip;)]]''': Various list operations
 +
* '''[[List Manipulation Functions#ListCombine|ListCombine(&hellip;)]]''': Combines two delimited lists into a single delimited list
 +
* '''[[List Manipulation Functions#ListContains|ListContains(&hellip;)]]''': Checks for a value being in a list
 +
* '''[[List Manipulation Functions#ListCount|ListCount(&hellip;)]]''': Returns the number of items in a list
 +
* '''[[List Manipulation Functions#ListEqual|ListEqual(&hellip;)]]''': Checks for equality between two lists
 +
* '''[[List Manipulation Functions#ListFilter|ListFilter(&hellip;)]]''': Filter any list, returning only values within a given range
 +
* '''[[List Manipulation Functions#ListFind|ListFind(&hellip;)]]''': Search a list for a value and return that value, or its index # in the list
 +
* '''[[List Manipulation Functions#ListFormat|ListFormat(&hellip;)]]''': Outputs a given list in a reader friendly format.
 +
* '''[[List Manipulation Functions#ListGrep|ListGrep(&hellip;)]]''': Returns list items containing specified text
 +
* '''[[List Manipulation Functions#ListItem|ListItem(&hellip;)]]''': Returns an item from a location in a list
 +
* '''[[List Manipulation Functions#ListLimit|ListLimit(&hellip;)]]''': Limits the length of a list
 +
* '''[[List Manipulation Functions#ListMath|ListMath(&hellip;)]]''': Perform one of 4 specific math functions on a list containing numbers
 +
* '''[[List Manipulation Functions#ListMix|ListMix(&hellip;)]]''': Combine corresponding values from multiple lists into a new list, using a template to process each item
 +
* '''[[List Manipulation Functions#ListRemove|ListRemove(&hellip;)]]''': Removes a string from a list
 +
* '''[[List Manipulation Functions#ListShuffle|ListShuffle(&hellip;)]]''': Shuffles a list
 +
* '''[[List Manipulation Functions#ListSort|ListSort(&hellip;)]]''': Sort a list of values
 +
 
 +
==== [[Miscellaneous Functions]] ====
 +
* '''[[Miscellaneous Functions#AlbumArtist|AlbumArtist(&hellip;)]]''': Returns a file's calculated album artist
 +
* '''[[Miscellaneous Functions#AlbumKey|AlbumKey(&hellip;)]]''': Returns a unique album key for a file
 +
* '''[[Miscellaneous Functions#AlbumType|AlbumType(&hellip;)]]''': Returns the album type for a file
 +
* '''[[Miscellaneous Functions#AudioAnalysisState|AudioAnalysisState(&hellip;)]]''': Returns the state of audio analysis for a file
 +
* '''[[Miscellaneous Functions#Char|Char(&hellip;)]]''': Returns a character from the numeric code of that character
 +
* '''[[Miscellaneous Functions#CustomData|CustomData(&hellip;)]]''': Returns internal data to the expression language
 +
* '''[[Miscellaneous Functions#FileExtension|FileExtension(&hellip;)]]''': Returns the extension of the referenced file
 +
* '''[[Miscellaneous Functions#FilePlaylists()|FilePlaylists(&hellip;)]]''': Returns a list of playlists a file belongs to (Can also be used to search)
 +
* '''[[Miscellaneous Functions#Literal()|Literal(&hellip;)]]''': Returns a string as given without any formatting or processing
 +
* '''[[Miscellaneous Functions#Repeat|Repeat(&hellip;)]]''': Returns any given string repeated the specified number of times
 +
* '''[[Miscellaneous Functions#Row|Row(&hellip;)]]''': Returns the row number of a list entry
 +
* '''[[Miscellaneous Functions#Size|Size(&hellip;)]]''': Returns a file's size in a format specific to the media type
 +
* '''[[Miscellaneous Functions#Translate|Translate(&hellip;)]]''': Converts an English string found in the program to the current language selected in the language menu
 +
* '''[[Miscellaneous Functions#TreeNode|TreeNode(&hellip;)]]''': Returns the selected tree path
 +
* '''[[Miscellaneous Functions#TVInfo|TVInfo(&hellip;)]]''': Miscellaneous television and other pre-formatted information
 +
 
 +
==== [[Number Functions]] ====
 +
* '''[[Number Functions#Avg|Avg(&hellip;)]]''': Returns the average from a set of numbers
 +
* '''[[Number Functions#Counter|Counter(&hellip;)]]''': Counts upwards in specified increments
 +
* '''[[Number Functions#Math|Math(&hellip;)]]''': Evaluates a given mathematical formula
 +
* '''[[Number Functions#Max|Max(&hellip;)]]''': Returns the largest value from a set of numbers
 +
* '''[[Number Functions#Min|Min(&hellip;)]]''': Returns the smallest value from a set of numbers
 +
* '''[[Number Functions#Number|Number(&hellip;)]]''': Returns the first number , including decimals, from a given string
 +
* '''[[Number Functions#Rand|Rand(&hellip;)]]''': Returns a random number anywhere between two given numbers
 +
* '''[[Number Functions#Range|Range(&hellip;)]]''': Creates a semi-colon delimited list of numbers in a field
 +
* '''[[Number Functions#Roman|Roman(&hellip;)]]''': Converts any given number to, or from, roman numerals
 +
* '''[[Number Functions#StackCount|StackCount(&hellip;)]]''': Returns the number of files in a stack
 +
* '''[[Number Functions#Sum|Sum(&hellip;)]]''': Returns the sum of a set of numbers
 +
* '''[[Number Functions#TrackNumber|TrackNumber(&hellip;)]]''': Returns a file's track # value
 +
 
 +
==== [[String Manipulation Functions]] ====
 +
* '''[[String Manipulation Functions#Clean|Clean(&hellip;)]]''': Clean a string to be used for various operations
 +
* '''[[String Manipulation Functions#Extract|Extract(&hellip;)]]''': Returns a portion of a string bounded by another substring
 +
* '''[[String Manipulation Functions#Find|Find(&hellip;)]]''': Finds a string or character in another string, returning its zero-based position in that string
 +
* '''[[String Manipulation Functions#FixCase|FixCase(&hellip;)]]''': Changes the case of a given string
 +
* '''[[String Manipulation Functions#FixSpacing|FixSpacing(&hellip;)]]''': Intelligently splits adjacent camel-cased words
 +
* '''[[String Manipulation Functions#Hexify|Hexify(&hellip;)]]''': Hexifies a string to make it suitable for web usage
 +
* '''[[String Manipulation Functions#Left|Left(&hellip;)]]''': Retrieves a specified number of characters from the left of a string
 +
* '''[[String Manipulation Functions#Length|Length(&hellip;)]]''': Returns the number of characters in a string
 +
* '''[[String Manipulation Functions#Letter|Letter(&hellip;)]]''': Returns the starting letter or letters of a given string
 +
* '''[[String Manipulation Functions#Mid|Mid(&hellip;)]]''': Retrieves specified characters from a string
 +
* '''[[String Manipulation Functions#MoveArticles|MoveArticles(&hellip;)]]''': Takes "The Beatles" and reverses it to "Beatles, The"
 +
* '''[[String Manipulation Functions#NoArticles|NoArticles(&hellip;)]]''': Takes "The Beatles" and returns "Beatles"
 +
* '''[[String Manipulation Functions#PadLeft|PadLeft(&hellip;)]]''': Pad any string with any character, to the left
 +
* '''[[String Manipulation Functions#PadRight|PadRight(&hellip;)]]''': Pad any string with any character, to the right
 +
* '''[[String Manipulation Functions#Regex|Regex(&hellip;)]]''': Regular expression pattern matching and capture
 +
* '''[[String Manipulation Functions#RemoveCharacters|RemoveCharacters(&hellip;)]]''': Removes a list of characters from a string
 +
* '''[[String Manipulation Functions#RemoveLeft|RemoveLeft(&hellip;)]]''': Trims characters from the beginning of a string
 +
* '''[[String Manipulation Functions#RemoveRight|RemoveRight(&hellip;)]]''': Trims characters from the end of a string
 +
* '''[[String Manipulation Functions#Replace|Replace(&hellip;)]]''': Replace or remove a string segment
 +
* '''[[String Manipulation Functions#Right|Right(&hellip;)]]''': Retrieves a specified number of characters from the right of a string
 +
* '''[[String Manipulation Functions#Swap|Swap(&hellip;)]]''': Takes Firstname Lastname and swaps to Lastname, Firstname
 +
* '''[[String Manipulation Functions#Trim|Trim(&hellip;)]]''': Removes leading and trailing non-printable characters and new lines from a string
 +
* '''[[String Manipulation Functions#TrimLines|TrimLines(&hellip;)]]''': Removes leading and trailing non-printable characters and new lines from a string
 +
* '''[[String Manipulation Functions#UnMoveArticles|UnMoveArticles(&hellip;)]]''': Takes "Beatles, The" and reverses it to restore the normal word order, "The Beatles"
 +
* '''[[String Manipulation Functions#Unswap|Unswap(&hellip;)]]''': Takes Lastname, Firstname and reverses it to Firstname Lastname
 +
* '''[[String Manipulation Functions#Urlify|Urlify(&hellip;)]]''': Takes a string and applies html formatting for browser consumption
 +
 
 +
==== [[Test and Comparison Functions]] ====
 +
* '''[[Test and Comparison Functions#Compare|Compare(&hellip;)]]''': Compares two numbers
 +
* '''[[Test and Comparison Functions#IsDigit|IsDigit(&hellip;)]]''': Determines whether or not a given value is digits
 +
* '''[[Test and Comparison Functions#IsDriveMissing|IsDriveMissing(&hellip;)]]''': Checks if a drive is missing
 +
* '''[[Test and Comparison Functions#IsEmpty|IsEmpty(&hellip;)]]''': Tests a value for emptiness
 +
* '''[[Test and Comparison Functions#IsEqual|IsEqual(&hellip;)]]''': Compares two values in one of seventeen specified modes
 +
* '''[[Test and Comparison Functions#IsInPlayingNow|IsInPlayingNow(&hellip;)]]''': Tests to see if a file is in the Playing Now playlist
 +
* '''[[Test and Comparison Functions#IsLowerCase|IsLowerCase(&hellip;)]]''': Tests to see if a value is lower case
 +
* '''[[Test and Comparison Functions#IsMissing|IsMissing(&hellip;)]]''': Tests to see if a file exists on the system
 +
* '''[[Test and Comparison Functions#IsOverridden|IsOveridden(&hellip;)]]''': Tests if an expression is overridden by a value
 +
* '''[[Test and Comparison Functions#IsPlaying|IsPlaying(&hellip;)]]''': Tests to see if a file is in currently being played
 +
* '''[[Test and Comparison Functions#IsRange|IsRange(&hellip;)]]''': Tests a value for inclusion within a given range
 +
* '''[[Test and Comparison Functions#IsRemovable|IsRemovable(&hellip;)]]''': Tests to see if a file is stored on removable media
 +
* '''[[Test and Comparison Functions#IsUpperCase|IsUpperCase(&hellip;)]]''': Tests to see if a value is upper case
 +
* '''[[Test and Comparison Functions#SearchTags|SearchTags(&hellip;)]]''': Finds all fields that contain a value
 +
 
 +
== Data Types ==
 +
It was mentioned already that the Media Center expression language is primarily a textual language - it consumes and produces text.
 +
Nonetheless, certain areas of Media Center are influenced by the type of data used or presented,
 +
and sometimes it is useful or necessary to coerce expression output into one data type or another.
 +
Each Media Center field is defined to be of a certain data type,
 +
listed in the [[File_Properties_%28tags%29#Field_Specifications|Field Data Types]] table.
 +
These types influence how values are output, sorted, and interpreted on input.
 +
And expressions always output data of type String.
 +
By coercing the data type of an expression, output formatting and sorting can be controlled in various ways.
 +
 
 +
Data types are forced by appending to an expression the string:
 +
 
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[<i>type</i>]</span></div>
 +
 
 +
where <i><span style="font-family: monospace,monospace; font-size:1em;">type</span></i> is one of the following values:
 +
 
 +
<div style="margin-left: 20pt;"><table style="border-spacing:0px; border-collapse:collapse">
 +
<tr><td style="text-align:left; padding-right:20pt"><b>list</b></td><td>A list of strings, separated by semicolons</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b>string</b></td><td>Sorts as strings (with smart number handling)</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b>number</b></td><td>Sorts values as numbers (decimal or integer)</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b>integer</b></td><td>Sorts values as integers</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b>path</b></td><td>Sorts using a smart filename compare style</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b>month</b></td><td>Sorts string month names (i.e. January, February, etc.)</td></tr>
 +
</table></div>
 +
 
 +
=== Calculated Fields and Search ===
 +
 
 +
Media Center's [[Search Language]] supports some simple numeric [[Search Language#Comparison_Operators|comparison operators]].
 +
Because expressions always evaluate as a String type, these operators would be unavailable for use in a search query to compare numeric values from a calculated expression field.
 +
In order to use the numeric comparison operators, a calculated expression field can be cast into one of the numeric types.
 +
In your numeric calculated fields, to allow the use Search's numeric comparison operators, add either of the casts:
 +
 
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[integer]</span></div>
 +
 
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[number]</span></div>
 +
 
 +
to the end of the field's calculated expression.
 +
 
 +
=== Lists and Trees ===
 +
<div>
 +
[[File:Datatype_List.png|right]]
 +
The list of output in view categories and pane columns can be modified by forcing the data type to a List type.
 +
Two things happen when the data type is List:
 +
The values within a List type are split into their individual (semicolon-separated) list items
 +
The backslash character takes on a special meaning and becomes another form of separator that creates tree-like hierarchies,
 +
collapsible in panes columns and creates drill-down categories in any category view type (Standard View > Categories, Theater View, DLNA, Gizmo/WebGizmo).
 +
Forcing an expression's type to <span style="font-family: monospace,monospace; font-size:1em;">list</span> causes this list item separation and hierarchy generation.
 +
Alternatively, forcing a List type to <span style="font-family: monospace,monospace; font-size:1em;">string</span> defeats this.
 +
Add the cast:
 +
 
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[list]</span></div>
 +
 
 +
to the end of an expression to force an expression's output to be considered as a List type.
 +
Conversely, a List type may be forced into a String type by adding the cast:
 +
 
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[string]</span></div>
 +
 
 +
to the end of an expression.
 +
</div>
 +
 
 +
=== Sort Order ===
 +
<div>
 +
[[File:Datatype_Month.png|right]]
 +
Normally strings are sorted ASCII-betically with some smart numeric sorting.
 +
But this form of sort may not always be desired.
 +
 
 +
==== Sorting by Month ====
 +
Generally it is more useful to see month names sorting such that January sorts before April, instead of alphabetically where April would sort before January.
 +
Forcing an expression's type to Month forces string month values to be treated instead as their equivalent numerical month numbers.
 +
For example, the first month January and the third month March sort before the fourth month April.
 +
Add the cast:
 +
 
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[month]</span></div>
 +
 
 +
to the end of an expression to force an expression's output to be sorted by numeric month values.
 +
 
 +
==== Sorting by Path ====
 +
 
 +
Path data types sort using smart filename comparisons.
 +
 
 +
XXX: Note: This section is incomplete.  I cannot distingish any difference between using a datatype of <span style="font-family: monospace,monospace; font-size:1em;">path</span> vs. <span style="font-family: monospace,monospace; font-size:1em;">string</span>.  It seems <span style="font-family: monospace,monospace; font-size:1em;">path</span> sort order is always engaged.
 +
 
 +
Add the cast:
 +
 
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[path]</span></div>
 +
 
 +
to the end of an expression to force an expression's output to be smart-sorted by path components.
 +
 
 +
</div>
 +
 
 +
== Expressions and Search ==
 +
The expression language is fully available to the search query engine (Search, Set rules for file display, etc.).
 +
This allows creation of more complex search queries than would otherwise be possible.
 +
An expression-based search query is any valid expression that produces a zero or non-zero numeric output.
 +
The syntax of the query is:
 +
 
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;"><b>[=</b><i>expression</i><b>]=</b><i>numval</i></span></div>
 +
 
 +
where expression is any valid expression, and numval is the expected numeric output produced by the expression.
 +
The expression is evaluated against the current list of available files and the expression output numerically compared against numval.
 +
All files for which the comparison is true are returned as part of the file list produced by the query and all files that fail the comparison are winnowed from the file list.
 +
 
 +
The following example illustrates an expression-based search query:
 +
 
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">[=ismissing([filename (path)]\Folder.jpg)]=1</span></div>
 +
 
 +
The [[Test_and_Comparison_Functions#IsMissing|IsMissing()]] function is run using the file name argument <span style="font-family: monospace,monospace; font-size:1em;">[filename (path)]</span> appended by <span style="font-family: monospace,monospace; font-size:1em;">\Folder.jpg</span>,
 +
and returns a Boolean value <span style="font-family: monospace,monospace; font-size:1em;">1</span> for files that are missing, and this <span style="font-family: monospace,monospace; font-size:1em;">1</span> is compared against the value <i>numval</i>.
 +
All these files where there was a successful comparison are returned in the file list,
 +
and all those for which the expression produced <span style="font-family: monospace,monospace; font-size:1em;">0</span> are filtered from the file list.
 +
By inverting the comparison and using a <span style="font-family: monospace,monospace; font-size:1em;">0</span> numval, the set of files remaining in the file list would be those that did not match.
 +
 
 +
== HTML Font Properties ==
 +
The expression language recognizes a limited set of HTML font properties and attributes. These can be used to set font styles in most text drawing areas, such as captions, thumbnail text and in the configuration of Theater View.
 +
HTML tags are used by surrounding the desired content with an opening and closing tag, in the form of:
 +
 
 +
: <span style="font-family: monospace,monospace; font-size:1em;"><<i>tag</i>><i>desired content</i><//<i>tag</i>></span>
 +
 
 +
The supported HTML tags are:
 +
<div style="margin-left: 20pt;"><table style="border-spacing:0px; border-collapse:collapse">
 +
<tr><td style="text-align:left; padding-right:20pt"><b><nowiki><b></nowiki></b></td><td>Bold</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b><nowiki><i></nowiki></b></td><td>Italics</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b><nowiki><u></nowiki></b></td><td>Underline</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b><nowiki><font></nowiki></b></td><td>Font properties (see attributes below)</td></tr>
 +
</table></div>
 +
 
 +
The <b>font</b> tag supports the following attributes:
 +
<div style="margin-left: 20pt;"><table style="border-spacing:0px; border-collapse:collapse">
 +
<tr><td style="text-align:left; padding-right:20pt"><b>alpha</b></td><td>Sets alpha-blending percentage (0 - 100)</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b>color</b></td><td>Sets the foreground color (RGB hex values from 00 to ff in the form of rrggbb)</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b>bgcolor</b></td><td>Sets the background color (same values as color)</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b>face</b></td><td>Sets the font face (a font name)</td></tr>
 +
<tr><td style="text-align:left; padding-right:20pt"><b>size</b></td><td>Sets the font size (a percentage scaling value)</td></tr>
 +
</table></div>
 +
 
 +
Any combination of HTML tags and font attributes can be used.
 +
An HTML tag must have an opening and closing tag.
 +
Nesting is allowed, but be sure to properly balance like opening and closing tags.
 +
Attribute values must be double quoted. The closing tag's forward slash requires escapement with an extra forward slash.
 +
The following examples illustrate using HTML font properties:
 +
 
 +
: <span style="font-family: monospace,monospace; font-size:1em;"><nowiki><i>This is in italics<//i></nowiki></span>
 +
 
 +
: <span style="font-family: monospace,monospace; font-size:1em;"><nowiki><i><b>And this is bold and italic<//b><//i></nowiki></span>
 +
 
 +
: <span style="font-family: monospace,monospace; font-size:1em;"><nowiki><b>The<font color=&quot;ff0000&quot; size=&quot;80&quot; alpha=&quot;50&quot;> Great <//font>Gatsby<//b></nowiki></span>
 +
 
 +
== Expression Editors ==
 +
There are a couple of variations of dialog or edit field used to enter expressions.
 +
Some allow multi-line expressions, while others are single line, but can be expanded to multi-line editors.
 +
Unfortunately, some single-line editors flatten multi-line expressions into a single line, replacing the newlines with spaces.
 +
 
 +
== Acknowledgements ==
 +
A big tip of hat to [[User:Marko|marko]] who tackled the enormous challenge of documenting the MC Expression Language in detail. His work was instrumental and through which has brought clarity and great assistance to Media Center users worldwide.
 +
 
 +
Also, a huge thanks to user [[User:MrC|MrC]] who built [[Expression_Language_Archive|the amazing and long-lived previous version of this page]], upon which this is still heavily based.
 +
 
 +
The current caretaker of this documentation is forever in their debts.
 +
 
 +
[[Category:Frequently Asked Questions]]
 +
[[Category:Developer]]
 +
[[Category:Expression Language]]

Latest revision as of 05:24, 23 March 2024

Media Center provides a simple programming language that enhances and enriches its overall user interface and usability. This language, commonly called the expression language, is simple to learn, simple to use, and can greatly enhance your experience using Media Center.

Expressions are ubiquitous throughout Media Center, used in areas such as:

  • The categories in a view
  • File list expression columns
  • Theater View
  • Customized view headers, grouping and sort criteria
  • The library field manager (fields with data type Calculated data)
  • File and folder location definitions
  • Auto-import rules
  • Custom DLNA titles
  • The player's display
  • Captions and thumbnail text
  • The link manager (expressions help format link URLs)
  • Rename, Move, & Copy tool
  • Tag assignment
  • Complex search queries

An expression is a mixture of ordinary text, pre-defined functions, and a few reserved characters and constructs that have special meaning. An expression is evaluated by Media Center's expression engine and textual output is produced. This output is then used by Media Center to customize the user interface and affect its method of operation.

The Anatomy of an Expression

As mentioned above, an expression is a mixture of text and function calls (and some reserved stuff described shortly). The simplest expression would be some basic, literal text, such as A good movie. The expression engine evaluates this expression, finds nothing special, and then outputs the result: A good movie. Simple.

But simple text only has so much utility. The ability to transform or generate content is much more interesting and useful. And this is when functions are employed. Media Center provides many functions, which when called, produce some output. Most functions require some form of input, called arguments, and most functions generate output. By supplying a function with various arguments, the function will return some output value which is just more text. And this output text can be the used by other functions, and so on. Each function has a unique name, and calling upon a function to do some work requires little more that using its name anywhere in the expression.

A function call looks like this:

functionname(argument 1, argument 2, ...)

The syntax of the function call is the function's case-insensitive name, immediately followed by an opening parenthesis character, one or more comma-separated arguments, and a closing parenthesis character. Whitespace after the commas is optional, but helps readability and formatting. And each argument itself is also just an expression. And some arguments are optional. If an argument is optional, it can be omitted and its default value will be used. If the argument is omitted, a comma-separator will still be required if additional arguments follow. The following example uses the FixCase() function to change its input to Title Case:

fixcase(A good movie)

The result is A Good Movie.

A slightly more complex expression example consists of both text and a nested function call:

Wow! fixcase(replace(A good movie, good, great))

Inner functions are called before outer functions, so the Replace() function is call first:

replace(A good movie, good, great)

and its output is then supplied as the input to the FixCase() function. Replace() does its work substituting good with great, and returns A great movie. This output is then supplied as the argument to FixCase() which sees only the text A great movie (it knows nothing about how it was produced). So the function call:

fixcase(A great movie)

in turn outputs A Great Movie. Now that the functions have produced their output, the final output, including the literal Wow! leading text is

Wow! A Great Movie

Fields

The expression examples thus far have been limited to static literal text. Expressions have much more utility when they use data from other sources, such as a file's metadata. Media Center maintains this metadata in its defined fields. This data is accessed using the Field() function, and its first argument is the case-insensitive name of the field to be accessed. For example, the function call field(album) will return the current* file's value for the album field (* more will be said later about the current file). If the album field contained the value After Hours, the expression:

fixcase(field(album), 3)

would produce AFTER HOURS. First field(album) is evaluated, returning After Hours. The FixCase() function is supplied with this output as its first argument, and its second argument is 3, which happens to specify that it should perform upper-casing.

Because fields are so frequently used in expressions, an abbreviated form called square bracket notation exists for accessing their values. This makes it easier to both read and write expressions. Nonetheless, both forms are equivalent. The abbreviated form is simple: immediately surround the field's name with opening and closing square brackets, for example, [album]. The previous example is now written more simply as:

fixcase([album], 3)

Field Values

For the sake of simplicity and clarity, the section above glossed over an important detail regarding how Media Center outputs field values. Recall that Field() is the function used to return the value of a specified field. But Field() also has a second argument that indicates the format of the value that it returns. Because field values are used in a variety of situations, the Field() function can produce output suitably formatted for the requirements. There are two forms of output: one is a nice, friendly human-readable format suitable for use in views or other display locations; the other is a raw format which returns the representation stored internally by Media Center which is useful when uninterpreted values are necessary.

By default, Media Center always outputs the friendly format, so expressions sometimes need to take this into account and chose the format accordingly.

Not used earlier because it is optional, the second argument to the Field() function selects the mode of output: the value 0 selects the raw mode, and the default value of 1 selects the friendly mode. Here are two examples using the date field, the first one outputs the date value in raw format, the second in the friendly format:

field(date, 0)
field(date, 1)

Field Values: Override the expression, and [This]

ExpressionOverride.png

When creating (or editing) an expression based field, there is an option, shown in the image on the right, to "Allow custom data to override the expression". When enabled, it becomes possible to open the tag for editing either inline or in the tag window, just as you would any other regular tag, and replace the expression derived data with any other static data. Complex expression based fields can very easily slow view loading times to a crawl, and in many cases, this option can help speed things up again. Imagine an expression based field that manipulates another, otherwise static field, such the [Date] field. The returned expression values will never change, so why waste time evaluating the same results over and over, when you can simply replace them with static data and so forego any future expression processing?

Media Center 28 saw the introduction of a [This] variable that can also be invoked, so, using the example, =removeleft([This], 4) would remove four characters from the left of "this field".

The new [This] variable can be used to override expression data. Select one, or 1000s of files, then edit, either inline or in the tag window, using the simple expression =[this] and apply to have MC replace the expression result with, the expression result, which from that point forwards, will be static data and the expression will no longer run for those files.

To remove the static data and return to expression evaluated data instead, simply edit again, deleting the static data, which when applied, will cause the expression evaluated result to return.

Note: Use this "override" option with care. It requires least maintenance when used in situations where all expression values for all files for that field will be replaced with static data. Currently (October 2022) there is no way to differentiate between static data and expression derived data meaning the potential for things to get very confusing, very quickly, is very high indeed.

Note 2: MC32 comes with the addition of the IsOverridden(...) function that now allows us to filter any given expression based field based on its override status.

Field Values: Empty, 0, and 1

The Media Center expression language does not strongly differentiate between the numeric value zero 0 and emptiness for numeric field types Integer and Decimal. And in some cases, the numeric value of 1 is treated similarly to the empty value.

When a value of 0 is entered as a numeric field's value, the raw value will be shown as 0, but the display format (as in the file list) will be shown as empty. The empty display allows for less visual noise in the user interface, since a column full of 0 values is not usually helpful. In fact, if you attempt to set a numeric field's value to 0 in the file list, it will immediately be displayed as empty.

Generally this difference is unimportant, except when testing numeric values with IsEmpty() or IsEqual(). It is easy to be fooled when testing such a value if the value shown in a file list is empty. The values shown in the Tag Action Window will reveal the actual raw value, as will an expression column using the field's raw format.

Another consideration for integer fields is that when sorting, a 1 value can sometimes sort indistinguishably from an empty value. The Integer type disc # field is typically empty when an album consists of only one disc, and as such, Media Center will sort the disc # values of empty (0) and 1 identically.

The friendly output of a field can differ, depending on context. For example, in a file list, and empty field will be shown as blank, but in the Rename, Move & Copy tool, it will be output as Unknown Disc # (this ensures no blank values are generated as path components). To test such a field, always use and test against the raw format, and then expressions will be context agnostic.

Field Assignment

The output of an expression can be used to assign a value to a tag. This is accomplished by preceding the expression with an = character. The = character causes the tagging engine to invoke the expression evaluator first, and then to use its output as the value to assign to the field.

Field Assignment with Expression.png

Without the prepended = character, the literal expression text itself and not its evaluated value would be stored in the tag. The expression can refer to the field's own value to modify itself, and this offers a convenient way to perform complex transformations on field values. For example, the assignment expression

=removeleft([name], 4)

entered into an edit cell for the name field would remove four characters from the left of the name field's current value. An assignment expression can be entered into the Tag Action Window, or by using inline editing in the file list or a pane entry. The image on the right shows in-place field assignment.

Note: Undo is supported, reverting each tag to its value prior to the assignment. Redo is also supported, reapplying the most recent Undo.

Expression Language Syntax

Now that the basics have been covered, the more rigorous rules of the expression language syntax can be described.

  • An expression is any sequence of literal text and any number of function calls.
  • Expressions are read and evaluated left to right. Literal text is output unmodified, function calls are evaluated and their return values output.
  • Fields designated using square bracket notation are expanded into the equivalent Field() function call.
  • Nested function calls are evaluated from the innermost function to outermost function, and again, left to right when one function follows another.
  • A function is evaluated and its returned value contextually replaces the function call in the expression
  • Within a function's argument list, whitespace is ignored before and after commas, after an opening parenthesis, and before a closing parenthesis.
  • The forward-slash escape character / disables the special meaning of the character that follows it.
  • The escape sequence /# followed by #/ escapes everything inside.
  • The escape sequence /* followed by /* will escape everything inside returning it as given without formatting or processing.
  • To use a literal parenthesis, comma, or whitespace inside of function argument lists, escape them. Whitespace within an argument's value is literal and does not need to be escaped when it is surrounded by other non-whitespace text.
  • An expression may be split into multiple lines, but when it does not satisfy the conditions above regarding whitespace around function parenthesis and commas, use a forward-slash escape as the last character before the newline. Extraneous newlines in the expression editor will produce a trailing ellipsis (...) in the output.

How Expressions Are Evaluated

Expressions are evaluated in the context where they are used. For example, an expression column in a file list is evaluated relative to those files in the file list. And the general flow is that for each file in the list, the expression is evaluated and produces output. The expression only has access to the fields available for the file currently being evaluated. This is important to remember, so it bears repeating. One file after another, an expression is evaluated against that single file, its output is produced and stored away for use later, and then the result of that evaluation is entirely forgotten before the next file is evaluated. This means, the expression evaluator cannot use the results from one file's evaluated expression with the results of another file's evaluation.

Expressions and Locales

Media Center will respect the Windows locale setting for output values produced by certain functions, and within the values of certain fields. This is important to consider when writing expressions that consume such values. Under most circumstances, such values cause no harm. However special care must be taken with functions that require the use of period as the decimal point. One such function is Math(), which always uses period as the decimal point. If your locale uses some other character such as comma, these characters will have to be converted into periods before the critical function is called. Handling this problem is not difficult. Before passing to Math() any floating point number, use Replace() first when necessary to convert the locale's decimal character into a period. Fields that cause problems are any fields that produce floating-point values, such as any Date type field in raw format (e.g. [date,0], [last played,0], [date modified,0], and [date imported,0]), or any textual field that contains floating-point values that will be used for various calculations (e.g. any of the Dynamic Range variants). Certain functions such as Now() and ConvertTime() also return localized floating-point values. Consider also that the expression parser uses comma as the argument separator. Any literal numeric values specified as a function argument must have any embedded commas escaped.

A Complex Expression Example

Expression Editor.png

Here is a more complex expression example that illustrates the various rules discussed above regarding expressions:

if( IsEmpty( [Disc #] ),
Disc number is empty,
Delimit(
field(disc #) ,
/) ,
DISC /(
)
)

The expression demonstrates that

  • whitespace before and after commas or opening and closing parenthesis is ignored
  • expressions can be safely split into multiple lines using the whitespace rules just mentioned
  • function and field names are case insensitive
  • forward slash is used and required to escape parenthesis (see inside the Delimit() function)
  • whitespace does not require escapement when surrounded by other characters (see after the C in DISC)
  • literal text is output unmodified (Disc number is empty)
  • functions can be nested (Both IsEmpty() and Delimit() are nested within the If() function, and the Field() function is nested within Delimit()

When the expression is run, files that have no disc number will produce Disc number is empty, and files that have, say, a disc number value of 3 will produce DISC (3).

Functions

Functions enable you to transform or generate content automatically. For background information on how functions are used in expressions, refer to The Anatomy of an Expression section above.

This section describes all the various functions provided by Media Center's Expression Language.

Function Arguments

As discussed above, a function call consists of the function's case-insensitive name, immediately followed by an opening parenthesis character, one or more comma-separated arguments, and a closing parenthesis character:

functionname(argument 1, argument 2, ...)

Functions may have one or more arguments. In some cases, these arguments are optional, and will automatically use a default value if omitted. For example, these two expressions are equivalent because the mode argument for IsEmpty() is optional and defaults to 0:

isempty([comment], 0)
isempty([comment])

In this case, a comma-separator will still be required if additional arguments follow the optional one. Whitespace after the commas is also optional, but helps readability and formatting. However, if any extra arguments are included in a function call which are not valid for that function, they are dropped and omitted from output. This is of particular importance when using string-manipulation functions on text. If the text you enter contains any commas, these must be escaped or the expression engine will consider text after the comma to be additional arguments.

The arguments themselves are also just expressions, and you can nest multiple functions to achieve complex logic:

if(isequal([artist], [album], 1), Eponymous, [album])

Nested function calls are always treated as a single argument when used as the input to another function (so that commas in the output of one function do not need to be escaped to be used as input in another function). This includes fields, since they are expanded to the equivalent Field() function call.

Please Note: In some cases below, such as with Unswap(), we have ignored this detail in order to simplify the examples. If you enter any text manually into a function, all commas must be escaped in order to achieve the correct result. This detail is unimportant in most real-world usages, however, because you will typically use either field values or the output of other functions as the arguments in your expressions. However, if you need to include commas in a string literal argument to a function, you need to escape every one, or block escape the entire argument.

Function Index

Unfortunately, when these were actually introduced has not been tracked. The only way to be certain you have access to all of the functions below is to make sure you have the most current build of Media Center installed.
The available functions are grouped below based on the type of operation they might perform. If you prefer, a flat, alphabetically sorted function list is available here.
Over time, as Media Center evolves, expression functions are added or changed. Those changes are typically not reflected here immediately. In the list available here, on interact, any entries in red text are currently missing from these wiki pages.

Accessing and Storing Functions

Conditional Functions

  • And(…): Tests a set of values and returns 1 if all are true.
  • FirstNotEmpty(…): Returns the first non-empty argument.
  • If(…): Conditional ifelse evaluator.
  • IfCase(…): Functions as a switch or select case statement.
  • IfElse(…): Conditional if-elseif evaluator.
  • Not(…): Negates the results of funtions.
  • Or(…): Tests a set of values and returns 1 if any are true.

Date and Time Functions

  • CompareDates(…): Compares two dates, returning a formatted elapsed period between them
  • ConvertDate(…): Converts a human-readable date to the internal format required for use in date fields
  • DateInRange(…): Compares a date with a range of dates
  • FormatDate(…): Formats a date value in a specified manner
  • Now(…): Retrieve and display the system date
  • PlaylistTime(…): Returns the time of a track in the current playlist (a sum of all previous durations)

File Path and Identifier Functions

Formatting Functions

Grouping Functions

  • GroupCount(…): Counts the members of a specified group (in a category or field).
  • GroupCountQuery(…): Globally counts the number of items in a specified group.
  • GroupSummary(…): Smartly summarizes the members of a specified group (mode, mean, min, max, etc as is most logical for that grouping).
  • GroupSummaryQuery(…): Get a summary for the current group of files based on another matching field.

List Manipulation Functions

Miscellaneous Functions

  • AlbumArtist(…): Returns a file's calculated album artist
  • AlbumKey(…): Returns a unique album key for a file
  • AlbumType(…): Returns the album type for a file
  • AudioAnalysisState(…): Returns the state of audio analysis for a file
  • Char(…): Returns a character from the numeric code of that character
  • CustomData(…): Returns internal data to the expression language
  • FileExtension(…): Returns the extension of the referenced file
  • FilePlaylists(…): Returns a list of playlists a file belongs to (Can also be used to search)
  • Literal(…): Returns a string as given without any formatting or processing
  • Repeat(…): Returns any given string repeated the specified number of times
  • Row(…): Returns the row number of a list entry
  • Size(…): Returns a file's size in a format specific to the media type
  • Translate(…): Converts an English string found in the program to the current language selected in the language menu
  • TreeNode(…): Returns the selected tree path
  • TVInfo(…): Miscellaneous television and other pre-formatted information

Number Functions

  • Avg(…): Returns the average from a set of numbers
  • Counter(…): Counts upwards in specified increments
  • Math(…): Evaluates a given mathematical formula
  • Max(…): Returns the largest value from a set of numbers
  • Min(…): Returns the smallest value from a set of numbers
  • Number(…): Returns the first number , including decimals, from a given string
  • Rand(…): Returns a random number anywhere between two given numbers
  • Range(…): Creates a semi-colon delimited list of numbers in a field
  • Roman(…): Converts any given number to, or from, roman numerals
  • StackCount(…): Returns the number of files in a stack
  • Sum(…): Returns the sum of a set of numbers
  • TrackNumber(…): Returns a file's track # value

String Manipulation Functions

  • Clean(…): Clean a string to be used for various operations
  • Extract(…): Returns a portion of a string bounded by another substring
  • Find(…): Finds a string or character in another string, returning its zero-based position in that string
  • FixCase(…): Changes the case of a given string
  • FixSpacing(…): Intelligently splits adjacent camel-cased words
  • Hexify(…): Hexifies a string to make it suitable for web usage
  • Left(…): Retrieves a specified number of characters from the left of a string
  • Length(…): Returns the number of characters in a string
  • Letter(…): Returns the starting letter or letters of a given string
  • Mid(…): Retrieves specified characters from a string
  • MoveArticles(…): Takes "The Beatles" and reverses it to "Beatles, The"
  • NoArticles(…): Takes "The Beatles" and returns "Beatles"
  • PadLeft(…): Pad any string with any character, to the left
  • PadRight(…): Pad any string with any character, to the right
  • Regex(…): Regular expression pattern matching and capture
  • RemoveCharacters(…): Removes a list of characters from a string
  • RemoveLeft(…): Trims characters from the beginning of a string
  • RemoveRight(…): Trims characters from the end of a string
  • Replace(…): Replace or remove a string segment
  • Right(…): Retrieves a specified number of characters from the right of a string
  • Swap(…): Takes Firstname Lastname and swaps to Lastname, Firstname
  • Trim(…): Removes leading and trailing non-printable characters and new lines from a string
  • TrimLines(…): Removes leading and trailing non-printable characters and new lines from a string
  • UnMoveArticles(…): Takes "Beatles, The" and reverses it to restore the normal word order, "The Beatles"
  • Unswap(…): Takes Lastname, Firstname and reverses it to Firstname Lastname
  • Urlify(…): Takes a string and applies html formatting for browser consumption

Test and Comparison Functions

Data Types

It was mentioned already that the Media Center expression language is primarily a textual language - it consumes and produces text. Nonetheless, certain areas of Media Center are influenced by the type of data used or presented, and sometimes it is useful or necessary to coerce expression output into one data type or another. Each Media Center field is defined to be of a certain data type, listed in the Field Data Types table. These types influence how values are output, sorted, and interpreted on input. And expressions always output data of type String. By coercing the data type of an expression, output formatting and sorting can be controlled in various ways.

Data types are forced by appending to an expression the string:

&datatype=[type]

where type is one of the following values:

listA list of strings, separated by semicolons
stringSorts as strings (with smart number handling)
numberSorts values as numbers (decimal or integer)
integerSorts values as integers
pathSorts using a smart filename compare style
monthSorts string month names (i.e. January, February, etc.)

Calculated Fields and Search

Media Center's Search Language supports some simple numeric comparison operators. Because expressions always evaluate as a String type, these operators would be unavailable for use in a search query to compare numeric values from a calculated expression field. In order to use the numeric comparison operators, a calculated expression field can be cast into one of the numeric types. In your numeric calculated fields, to allow the use Search's numeric comparison operators, add either of the casts:

&datatype=[integer]
&datatype=[number]

to the end of the field's calculated expression.

Lists and Trees

Datatype List.png

The list of output in view categories and pane columns can be modified by forcing the data type to a List type. Two things happen when the data type is List: The values within a List type are split into their individual (semicolon-separated) list items The backslash character takes on a special meaning and becomes another form of separator that creates tree-like hierarchies, collapsible in panes columns and creates drill-down categories in any category view type (Standard View > Categories, Theater View, DLNA, Gizmo/WebGizmo). Forcing an expression's type to list causes this list item separation and hierarchy generation. Alternatively, forcing a List type to string defeats this. Add the cast:

&datatype=[list]

to the end of an expression to force an expression's output to be considered as a List type. Conversely, a List type may be forced into a String type by adding the cast:

&datatype=[string]

to the end of an expression.

Sort Order

Datatype Month.png

Normally strings are sorted ASCII-betically with some smart numeric sorting. But this form of sort may not always be desired.

Sorting by Month

Generally it is more useful to see month names sorting such that January sorts before April, instead of alphabetically where April would sort before January. Forcing an expression's type to Month forces string month values to be treated instead as their equivalent numerical month numbers. For example, the first month January and the third month March sort before the fourth month April. Add the cast:

&datatype=[month]

to the end of an expression to force an expression's output to be sorted by numeric month values.

Sorting by Path

Path data types sort using smart filename comparisons.

XXX: Note: This section is incomplete. I cannot distingish any difference between using a datatype of path vs. string. It seems path sort order is always engaged.

Add the cast:

&datatype=[path]

to the end of an expression to force an expression's output to be smart-sorted by path components.

Expressions and Search

The expression language is fully available to the search query engine (Search, Set rules for file display, etc.). This allows creation of more complex search queries than would otherwise be possible. An expression-based search query is any valid expression that produces a zero or non-zero numeric output. The syntax of the query is:

[=expression]=numval

where expression is any valid expression, and numval is the expected numeric output produced by the expression. The expression is evaluated against the current list of available files and the expression output numerically compared against numval. All files for which the comparison is true are returned as part of the file list produced by the query and all files that fail the comparison are winnowed from the file list.

The following example illustrates an expression-based search query:

[=ismissing([filename (path)]\Folder.jpg)]=1

The IsMissing() function is run using the file name argument [filename (path)] appended by \Folder.jpg, and returns a Boolean value 1 for files that are missing, and this 1 is compared against the value numval. All these files where there was a successful comparison are returned in the file list, and all those for which the expression produced 0 are filtered from the file list. By inverting the comparison and using a 0 numval, the set of files remaining in the file list would be those that did not match.

HTML Font Properties

The expression language recognizes a limited set of HTML font properties and attributes. These can be used to set font styles in most text drawing areas, such as captions, thumbnail text and in the configuration of Theater View. HTML tags are used by surrounding the desired content with an opening and closing tag, in the form of:

<tag>desired content<//tag>

The supported HTML tags are:

<b>Bold
<i>Italics
<u>Underline
<font>Font properties (see attributes below)

The font tag supports the following attributes:

alphaSets alpha-blending percentage (0 - 100)
colorSets the foreground color (RGB hex values from 00 to ff in the form of rrggbb)
bgcolorSets the background color (same values as color)
faceSets the font face (a font name)
sizeSets the font size (a percentage scaling value)

Any combination of HTML tags and font attributes can be used. An HTML tag must have an opening and closing tag. Nesting is allowed, but be sure to properly balance like opening and closing tags. Attribute values must be double quoted. The closing tag's forward slash requires escapement with an extra forward slash. The following examples illustrate using HTML font properties:

<i>This is in italics<//i>
<i><b>And this is bold and italic<//b><//i>
<b>The<font color="ff0000" size="80" alpha="50"> Great <//font>Gatsby<//b>

Expression Editors

There are a couple of variations of dialog or edit field used to enter expressions. Some allow multi-line expressions, while others are single line, but can be expanded to multi-line editors. Unfortunately, some single-line editors flatten multi-line expressions into a single line, replacing the newlines with spaces.

Acknowledgements

A big tip of hat to marko who tackled the enormous challenge of documenting the MC Expression Language in detail. His work was instrumental and through which has brought clarity and great assistance to Media Center users worldwide.

Also, a huge thanks to user MrC who built the amazing and long-lived previous version of this page, upon which this is still heavily based.

The current caretaker of this documentation is forever in their debts.