Expression Language: Difference between revisions
m (Reverted edits by BocroElorm (Talk); changed back to last version by Gateley) |
|||
(258 intermediate revisions by 13 users not shown) | |||
Line 1: | Line 1: | ||
{{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. |
|||
Expressions are ubiquitous throughout Media Center, used in areas such as: |
|||
The J. River Media Core database engine supports Excel-style functions for use in view schemes, searches, displayed columns, and tag editing. |
|||
:* 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. |
|||
An expression is a mixture of text, fields, and functions. |
|||
== The Anatomy of an Expression == |
|||
Examples: |
|||
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 |
|||
As mentioned above, an expression is a mixture of text and function calls (and some reserved stuff described shortly). |
|||
====Fields==== |
|||
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. |
|||
But simple text only has so much utility. |
|||
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". |
|||
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. |
|||
A function call looks like this: |
|||
==Functions== |
|||
:{{monospace|<i>functionname</i><b>(</b><i>argument 1</i>, <i>argument 2</i>, ...<b>)</b>}} |
|||
A function allows special operations to be performed. A list of functions follows: |
|||
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(...): Outputs the value for a given field.=== |
|||
Whitespace after the commas is optional, but helps readability and formatting. |
|||
'''Field name:''' the name of the field to evaluate (i.e. Artist, Album, Name, etc.)<br> |
|||
And each argument itself is also just an expression. And some arguments are optional. |
|||
'''Format for display:''' 0 to use raw data, 1 to use data formatted for display (optional: defaults to 1) |
|||
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: |
|||
:{{monospace|fixcase(A good movie)}} |
|||
Notes:<br> |
|||
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]. |
|||
The result is <span style="font-family: monospace,monospace; font-size:1em;">A Good Movie</span>. |
|||
Examples: |
|||
Field(Artist) |
|||
Field(Artist, 0) |
|||
A slightly more complex expression example consists of both text and a nested function call: |
|||
===If(...): Outputs different values depending on the value of the first parameter.=== |
|||
'''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]) |
|||
:{{monospace|Wow! fixcase(replace(A good movie, good, great))}} |
|||
===IsMissing(...): Checks to see if a file exists on the system.=== |
|||
'''Filename:''' the filename to check (optional: defaults to this file) |
|||
Examples: |
|||
IsMissing() |
|||
IsMissing([Filename]) |
|||
Inner functions are called before outer functions, so the [[String_Manipulation_Functions#Replace|Replace()]] function is call first: |
|||
===IsRemovable(...): Checks to see if a file resides on removable media.=== |
|||
'''Filename:''' the filename to check (optional: defaults to this file) |
|||
Examples: |
|||
IsRemovable() |
|||
IsRemovable([Filename]) |
|||
:{{monospace|replace(A good movie, good, great)}} |
|||
===IsEqual(...): Compares values and outputs a "1" if the values pass the test, and "0" if they don't pass the test.=== |
|||
'''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) |
|||
and its output is then supplied as the input to the [[String_Manipulation_Functions#FixCase|FixCase()]] function. |
|||
===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.=== |
|||
[[String_Manipulation_Functions#Replace|Replace()]] does its work substituting {{monospace|good}} with {{monospace|great}}, and returns {{monospace|A great movie}}. |
|||
'''Value:''' the value to test<br> |
|||
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: |
|||
'''Mode:''' the mode to test (optional: defaults to 0) |
|||
:'''0:''' string style, so "" is empty<br> |
|||
:'''1:''' number style, so "" or 0 is empty |
|||
Examples: |
|||
IsEmpty([Artist]) |
|||
IsEmpty([Duration], 1) |
|||
:{{monospace|fixcase(A great movie)}} |
|||
===IsRange(...): Compares a value against a range and outputs a "1" if the values is inside the range, and "0" if not.=== |
|||
'''Value:''' the value to test<br> |
|||
'''Range:''' the range of values (in the form: a-z or 1-100)<br> |
|||
in turn outputs {{monospace|A Great Movie}}. |
|||
Examples: |
|||
Now that the functions have produced their output, the final output, including the literal {{monospace|Wow!}} leading text is |
|||
IsRange([Artist], a-b) |
|||
IsRange([Bitrate], 128-192) |
|||
:{{monospace|Wow! A Great Movie}} |
|||
===FilePath(...): Returns the path from a filename.=== |
|||
'''Filename:''' the filename to check (optional: defaults to this file) |
|||
== Fields == |
|||
Examples: |
|||
The expression examples thus far have been limited to static literal text. |
|||
FilePath() |
|||
Expressions have much more utility when they use data from other sources, such as a file's metadata. |
|||
FilePath([Filename]) |
|||
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: |
|||
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">fixcase(field(album), 3)</span></div> |
|||
===FileName(...): Returns the name from a filename. === |
|||
'''Filename:''' the filename to check (optional: defaults to this file) |
|||
would produce <span style="font-family: monospace,monospace; font-size:1em;">AFTER HOURS</span>. |
|||
Examples: |
|||
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() |
|||
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. |
|||
FileName([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. |
|||
===FileVolume(...): Returns the volume name from a filename.=== |
|||
Nonetheless, both forms are equivalent. |
|||
'''Filename:''' the filename to check (optional: defaults to this file) |
|||
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: |
|||
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">fixcase([album], 3)</span></div> |
|||
Examples: |
|||
FileVolume() |
|||
FileVolume([Filename]) |
|||
=== Field Values === |
|||
===FormatNumber(...): Formats a number in a specified manner.=== |
|||
For the sake of simplicity and clarity, the section above glossed over an important detail regarding how |
|||
'''Value:''' the number to format<br> |
|||
Media Center outputs field values. |
|||
'''Number of decimal places:''' specifies how many decimals to use (-1 uses as many as necessary) (optional: defaults to 0) |
|||
Recall that [[Accessing_and_Storing_Functions#Field|Field()]] is the function used to return the value of a specified field. |
|||
Examples: |
|||
But [[Accessing_and_Storing_Functions#Field|Field()]] also has a second argument that indicates the format of the value that it returns. |
|||
FormatNumber(3.123224, 0) |
|||
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([Replay Gain, 0], 3) |
|||
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. |
|||
FormatNumber([Duration, 0]) |
|||
===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) |
|||
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. |
|||
===PadNumber(...): Use to add leading zeros to a number.=== |
|||
'''Field:''' the field to pad<br> |
|||
'''Value:''' the number of digits you require in the number. |
|||
Examples: |
|||
PadNumber([track #],3) |
|||
Not used earlier because it is optional, the second argument to the [[Accessing_and_Storing_Functions#Field|Field()]] function selects the mode of output: |
|||
===RemoveLeft(...) and RemoveRight(...): Use to trim characters from the start or end of a field=== |
|||
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. |
|||
'''Field:''' the field to trim.<br> |
|||
Here are two examples using the date field, the first one outputs the date value in raw format, the second in the friendly format: |
|||
'''Value:''' how many characters to trim. (spaces count as characters) |
|||
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)''' |
|||
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">field(date, 0)</span></div> |
|||
===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, 1)</span></div> |
|||
'''1st Value:''' Where to start counting from. (optional. starts at 1 if not specified)<br> |
|||
'''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. |
|||
==== Field Values: Override the expression, and [This] ==== |
|||
Notes: |
|||
[[File:ExpressionOverride.png|right]] |
|||
The counter function resets back to one after five seconds of inactivity. |
|||
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 [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". |
|||
===Now(...): Use to return the current date=== |
|||
Examples: |
|||
FormatDate(Now()) formats the current date according to the system setting |
|||
FormatDate(Now(), year) returns the current year |
|||
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>''. |
|||
===ListItem(...): Use to return a value from a delimited list=== |
|||
'''List:''' List<br> |
|||
'''Index:''' Index (starts at 0)<br> |
|||
'''Delimiter:''' Delimiter (optional -- defaults to semi-colon)<br> |
|||
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. |
|||
Examples: |
|||
ListItem([People], 1) |
|||
ListItem([Filename (path)], 2, \) |
|||
'''<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. |
|||
===ListCount(...): Use to return the number of items in a delimited list=== |
|||
'''List:''' List<br> |
|||
'''Delimiter:''' Delimiter (optional -- defaults to semi-colon)<br> |
|||
==== Field Values: Empty, 0, and 1 ==== |
|||
Examples: |
|||
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 |
|||
ListCount([People]) |
|||
for numeric field types Integer and Decimal. |
|||
ListCount([Filename (path)], \) |
|||
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. |
|||
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(...): Use to find string items and replace or remove them=== |
|||
but the display format (as in the file list) will be shown as empty. |
|||
'''Field:''' The field to search in |
|||
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. |
|||
'''String:''' What to find |
|||
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. |
|||
'''replace with:''' What to replace with (optional, defaults to empty) |
|||
Generally this difference is unimportant, except when testing numeric values with [[Test_and_Comparison_Functions#IsEmpty|IsEmpty()]] or [[Test_and_Comparison_Functions#IsEqual|IsEqual()]]. |
|||
Examples: |
|||
It is easy to be fooled when testing such a value if the value shown in a file list is empty. |
|||
replace([artist],featuring,ft.) changes "Mark Ronson feat. Amy Winehouse" to "Mark Ronson ft. Amy Winehouse" |
|||
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 <span style="font-family: monospace,monospace; font-size:1em;">1</span> value can sometimes sort indistinguishably from an empty value. |
|||
Notes: |
|||
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 |
|||
All occurrences of the search are replaced, and searches are case sensitive, so: |
|||
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. |
|||
replace([artist],a) changes "Abba" to "Abb" |
|||
replace([artist],A) changes "ABBA" to "BB" |
|||
The friendly output of a field can differ, depending on context. |
|||
===ListCombine(...): Use to merge one list type field into another=== |
|||
For example, in a file list, and empty field will be shown as blank, but in the Rename, Move & Copy tool, |
|||
''ListCombine(List1, List2, Delimiter (optional, defaults to semicolon))''<br> |
|||
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). |
|||
'''List1 and List2:''' the two list type fields to combine |
|||
To test such a field, always use and test against the raw format, and then expressions will be context agnostic. |
|||
===Field Assignment=== |
|||
Examples: |
|||
<div> |
|||
listcombine([keywords],[people]) |
|||
The output of an expression can be used to assign a value to a tag. |
|||
This is accomplished by preceding the expression with an <span style="font-family: monospace,monospace; font-size:1em;">=</span> character. |
|||
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 |
|||
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">=removeleft([name], 4)</span></div> |
|||
Notes: |
|||
If used in the keywords field, the people list will be added to the keywords field and vice-versa |
|||
If used in a new field, the two lists will be added to the new field. |
|||
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 |
|||
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 |
|||
entered into an edit cell for the <span style="font-family: monospace,monospace; font-size:1em;">name</span> field would remove |
|||
===Tag(...): Reads in the physical file tag rather than looking in the database=== |
|||
four characters from the left of the <span style="font-family: monospace,monospace; font-size:1em;">name</span> field's current value. |
|||
''Tag([field])''<br> |
|||
An assignment expression can be entered into the Tag Action Window, or by using inline editing in the file list or a pane entry. |
|||
'''[field]:''' The physical file tag to read into the database. |
|||
The image on the right shows in-place field assignment. |
|||
Note: Undo is supported, reverting each tag to its value prior to the assignment. |
|||
Notes: |
|||
Redo is also supported, reapplying the most recent Undo. |
|||
.jpg files can contain EXIF, XMP, IPTC and MJMD tag blocks. When parsing file tags, MC does so in this order: |
|||
</div> |
|||
IPTC |
|||
XMP |
|||
== Expression Language Syntax == |
|||
MJMD |
|||
Now that the basics have been covered, the more rigorous rules of the expression language syntax can be described. |
|||
EXIF |
|||
Except for dates, where the order becomes: |
|||
:* An expression is any sequence of literal text and any number of function calls. |
|||
IPTC |
|||
:* Expressions are read and evaluated left to right. Literal text is output unmodified, function calls are evaluated and their return values output. |
|||
XMP |
|||
:* Fields designated using [[square bracket notation]] are expanded into the equivalent [[Accessing_and_Storing_Functions#Field|Field()]] function call. |
|||
EXIF |
|||
:* Nested function calls are evaluated from the innermost function to outermost function, and again, left to right when one function follows another. |
|||
MJMD |
|||
:* A function is evaluated and its returned value contextually replaces the function call in the expression |
|||
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. |
|||
:* Within a function's argument list, whitespace is ignored before and after commas, after an opening parenthesis, and before a closing parenthesis. |
|||
When using this function, capitalisation is important when it comes to defining the file tag to read in... |
|||
:* 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. |
|||
tag(exif: date) will ''not'' work, tag(exif: Date) will. |
|||
:* 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. |
|||
:* The escape sequence <nowiki>/* followed by /*</nowiki> will escape everything inside returning it as given without formatting or processing. |
|||
==Notes== |
|||
:* 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. |
|||
*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]/)) |
|||
:* 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. |
|||
*Case (upper vs. lower) does not matter for function names, field names, and most parameters. |
|||
*Spaces are interpreted literally in all areas, except immediately after a comma in a function. |
|||
=== How Expressions Are Evaluated === |
|||
*To specify a data type (for sorting, etc.), add &DataType=[...] to the end of the expression where ... is one of these values: |
|||
Expressions are evaluated in the context where they are used. |
|||
::String: sorts as strings (with smart number handling) |
|||
For example, an expression column in a file list is evaluated relative to those files in the file list. |
|||
::List: a list of strings, separated by semicolons |
|||
And the general flow is that for each file in the list, the expression is evaluated and produces output. |
|||
::Number: sorts values as numbers (decimal or integer) |
|||
The expression only has access to the fields available for the file currently being evaluated. |
|||
::Path: sorts using a smart filename compare style |
|||
This is important to remember, so it bears repeating. |
|||
::Month: sorts string month names (i.e. January, February, etc.) |
|||
One file after another, an expression is evaluated against that single file, its output is produced and stored away for use later, |
|||
Examples: |
|||
and then the result of that evaluation is entirely forgotten before the next file is evaluated. |
|||
FormatDate([Date, 0], Month)&DataType=[Month] |
|||
This means, the expression evaluator cannot use the results from one file's evaluated expression with the results of another |
|||
*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: |
|||
file's evaluation. |
|||
::[=<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.)'' |
|||
Examples: |
|||
=== Expressions and Locales === |
|||
[=isequal([people],jane,1)]=1 |
|||
Media Center will respect the Windows locale setting for output values produced by certain functions, |
|||
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 within the values of certain fields. |
|||
*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 is important to consider when writing expressions that consume such values. |
|||
Examples: |
|||
Under most circumstances, such values cause no harm. |
|||
Select 10 files, and in Tag Action Window, edit 'Comment' to be "=[Name] by [Artist]" (Ctrl+Z to undo) |
|||
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(…)]]''': Returns a field's value. |
|||
* '''[[Accessing_and_Storing_Functions#FieldQuery|FieldQuery(…)]]''': 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(…)]]''': 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(…)]]''': Outputs the value of a [[global variable]]. |
|||
* '''[[Accessing_and_Storing_Functions#Note|Note(…)]]''': Retrieve note fields. |
|||
* '''[[Accessing_and_Storing_Functions#Save|Save(…)]]''': Saves a value to a [[global variable]]. |
|||
* '''[[Accessing_and_Storing_Functions#SaveAdd|SaveAdd(…)]]''': Adds to a [[global variable]]. |
|||
* '''[[Accessing_and_Storing_Functions#SetField|SetField(…)]]''': Sets a field's value. |
|||
* '''[[Accessing_and_Storing_Functions#Tag|Tag(…)]]''': Returns a file's physical tag. |
|||
==== [[Conditional Functions]] ==== |
|||
* '''[[Conditional Functions#And|And(…)]]''': Tests a set of values and returns 1 if all are true. |
|||
* '''[[Conditional Functions#FirstNotEmpty|FirstNotEmpty(…)]]''': Returns the first non-empty argument. |
|||
* '''[[Conditional Functions#If|If(…)]]''': Conditional ifelse evaluator. |
|||
* '''[[Conditional Functions#IfCase|IfCase(…)]]''': Functions as a switch or select case statement. |
|||
* '''[[Conditional Functions#IfElse|IfElse(…)]]''': Conditional if-elseif evaluator. |
|||
* '''[[Conditional Functions#Not|Not(…)]]''': Negates the results of funtions. |
|||
* '''[[Conditional Functions#Or|Or(…)]]''': Tests a set of values and returns 1 if any are true. |
|||
==== [[Date and Time Functions]] ==== |
|||
* '''[[Date and Time Functions#CompareDates|CompareDates(…)]]''': Compares two dates, returning a formatted elapsed period between them |
|||
* '''[[Date and Time Functions#ConvertDate|ConvertDate(…)]]''': Converts a human-readable date to the internal format required for use in date fields |
|||
* '''[[Date and Time Functions#DateInRange|DateInRange(…)]]''': Compares a date with a range of dates |
|||
* '''[[Date and Time Functions#FormatDate|FormatDate(…)]]''': Formats a date value in a specified manner |
|||
* '''[[Date and Time Functions#Now|Now(…)]]''': Retrieve and display the system date |
|||
* '''[[Date and Time Functions#PlaylistTime|PlaylistTime(…)]]''': 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(…)]]''': Identifies a file's databases |
|||
* '''[[File Path and Identifier Functions#Enviro|Enviro(…)]]''': Returns the full path to a host system variable |
|||
* '''[[File Path and Identifier Functions#FileDBLocation|FileDBLocation(…)]]''': Identifies a file's databases |
|||
* '''[[File Path and Identifier Functions#FileFolder|FileFolder(…)]]''': Returns the name of a file's parent |
|||
* '''[[File Path and Identifier Functions#FileKey|FileKey(…)]]''': 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(…)]]''': Returns a file's name component |
|||
* '''[[File Path and Identifier Functions#FilePath|FilePath(…)]]''': Returns a file's path component |
|||
* '''[[File Path and Identifier Functions#FileVolume|FileVolume(…)]]''': Returns a file's volume name component |
|||
==== [[Formatting Functions]] ==== |
|||
* '''[[Formatting Functions#Delimit|Delimit(…)]]''': Outputs a value with head/tail strings when value is non-empty |
|||
* '''[[Formatting Functions#FormatBoolean|FormatBoolean(…)]]''': Formats a boolean (true / false) value in a specified manner |
|||
* '''[[Formatting Functions#FormatDuration|FormatDuration(…)]]''': Presents a duration of seconds in a reader friendly format |
|||
* '''[[Formatting Functions#FormatFileSize|FormatFileSize(…)]]''': Presents a number of bytes in a reader friendly format |
|||
* '''[[Formatting Functions#FormatNumber|FormatNumber(…)]]''': Formats and rounds a number to a specified number of decimal places |
|||
* '''[[Formatting Functions#FormatRange|FormatRange(…)]]''': Formats a value as a range |
|||
* '''[[Formatting Functions#Orientation|Orientation(…)]]''': Outputs the orientation of an image |
|||
* '''[[Formatting Functions#PadNumber|PadNumber(…)]]''': Adds leading zeros to any given number |
|||
* '''[[Formatting Functions#RatingStars|RatingStars(…)]]''': Outputs the value of Rating as a number of star characters |
|||
* '''[[Formatting Functions#RatingStars10|RatingStars10(…)]]''': Outputs the value of a 10 star rating field as a number of star characters |
|||
* '''[[Formatting Functions#Watched|Watched(…)]]''': Outputs a formatted video bookmark |
|||
==== [[Grouping Functions]] ==== |
|||
* '''[[Grouping Functions#GroupCount|GroupCount(…)]]''': Counts the members of a specified group (in a category or field). |
|||
* '''[[Grouping Functions#GroupCountQuery|GroupCountQuery(…)]]''': Globally counts the number of items in a specified group. |
|||
* '''[[Grouping Functions#GroupSummary|GroupSummary(…)]]''': Smartly summarizes the members of a specified group (mode, mean, min, max, etc as is most logical for that grouping). |
|||
* '''[[Grouping Functions#GroupSummaryQuery|GroupSummaryQuery(…)]]''': Get a summary for the current group of files based on another matching field. |
|||
==== [[List Manipulation Functions]] ==== |
|||
* '''[[List Manipulation Functions#ListBuild|ListBuild(…)]]''': Constructs a list from a series of items |
|||
* '''[[List Manipulation Functions#ListClean|ListClean(…)]]''': Various list operations |
|||
* '''[[List Manipulation Functions#ListCombine|ListCombine(…)]]''': Combines two delimited lists into a single delimited list |
|||
* '''[[List Manipulation Functions#ListContains|ListContains(…)]]''': Checks for a value being in a list |
|||
* '''[[List Manipulation Functions#ListCount|ListCount(…)]]''': Returns the number of items in a list |
|||
* '''[[List Manipulation Functions#ListEqual|ListEqual(…)]]''': Checks for equality between two lists |
|||
* '''[[List Manipulation Functions#ListFilter|ListFilter(…)]]''': Filter any list, returning only values within a given range |
|||
* '''[[List Manipulation Functions#ListFind|ListFind(…)]]''': Search a list for a value and return that value, or its index # in the list |
|||
* '''[[List Manipulation Functions#ListFormat|ListFormat(…)]]''': Outputs a given list in a reader friendly format. |
|||
* '''[[List Manipulation Functions#ListGrep|ListGrep(…)]]''': Returns list items containing specified text |
|||
* '''[[List Manipulation Functions#ListItem|ListItem(…)]]''': Returns an item from a location in a list |
|||
* '''[[List Manipulation Functions#ListLimit|ListLimit(…)]]''': Limits the length of a list |
|||
* '''[[List Manipulation Functions#ListMath|ListMath(…)]]''': Perform one of 4 specific math functions on a list containing numbers |
|||
* '''[[List Manipulation Functions#ListMix|ListMix(…)]]''': Combine corresponding values from multiple lists into a new list, using a template to process each item |
|||
* '''[[List Manipulation Functions#ListRemove|ListRemove(…)]]''': Removes a string from a list |
|||
* '''[[List Manipulation Functions#ListShuffle|ListShuffle(…)]]''': Shuffles a list |
|||
* '''[[List Manipulation Functions#ListSort|ListSort(…)]]''': Sort a list of values |
|||
==== [[Miscellaneous Functions]] ==== |
|||
* '''[[Miscellaneous Functions#AlbumArtist|AlbumArtist(…)]]''': Returns a file's calculated album artist |
|||
* '''[[Miscellaneous Functions#AlbumKey|AlbumKey(…)]]''': Returns a unique album key for a file |
|||
* '''[[Miscellaneous Functions#AlbumType|AlbumType(…)]]''': Returns the album type for a file |
|||
* '''[[Miscellaneous Functions#AudioAnalysisState|AudioAnalysisState(…)]]''': Returns the state of audio analysis for a file |
|||
* '''[[Miscellaneous Functions#Char|Char(…)]]''': Returns a character from the numeric code of that character |
|||
* '''[[Miscellaneous Functions#CustomData|CustomData(…)]]''': Returns internal data to the expression language |
|||
* '''[[Miscellaneous Functions#FilePlaylists()|FilePlaylists(…)]]''': Returns a list of playlists a file belongs to (Can also be used to search) |
|||
* '''[[Miscellaneous Functions#Literal()|Literal(…)]]''': Returns a string as given without any formatting or processing |
|||
* '''[[Miscellaneous Functions#Repeat|Repeat(…)]]''': Returns any given string repeated the specified number of times |
|||
* '''[[Miscellaneous Functions#Row|Row(…)]]''': Returns the row number of a list entry |
|||
* '''[[Miscellaneous Functions#Size|Size(…)]]''': Returns a file's size in a format specific to the media type |
|||
* '''[[Miscellaneous Functions#Translate|Translate(…)]]''': Converts an English string found in the program to the current language selected in the language menu |
|||
* '''[[Miscellaneous Functions#TreeNode|TreeNode(…)]]''': Returns the selected tree path |
|||
* '''[[Miscellaneous Functions#TVInfo|TVInfo(…)]]''': Miscellaneous television and other pre-formatted information |
|||
==== [[Number Functions]] ==== |
|||
* '''[[Number Functions#Avg|Avg(…)]]''': Returns the average from a set of numbers |
|||
* '''[[Number Functions#Counter|Counter(…)]]''': Counts upwards in specified increments |
|||
* '''[[Number Functions#Math|Math(…)]]''': Evaluates a given mathematical formula |
|||
* '''[[Number Functions#Max|Max(…)]]''': Returns the largest value from a set of numbers |
|||
* '''[[Number Functions#Min|Min(…)]]''': Returns the smallest value from a set of numbers |
|||
* '''[[Number Functions#Number|Number(…)]]''': Returns the first number , including decimals, from a given string |
|||
* '''[[Number Functions#Rand|Rand(…)]]''': Returns a random number anywhere between two given numbers |
|||
* '''[[Number Functions#Range|Range(…)]]''': Creates a semi-colon delimited list of numbers in a field |
|||
* '''[[Number Functions#Roman|Roman(…)]]''': Converts any given number to, or from, roman numerals |
|||
* '''[[Number Functions#StackCount|StackCount(…)]]''': Returns the number of files in a stack |
|||
* '''[[Number Functions#Sum|Sum(…)]]''': Returns the sum of a set of numbers |
|||
* '''[[Number Functions#TrackNumber|TrackNumber(…)]]''': Returns a file's track # value |
|||
==== [[String Manipulation Functions]] ==== |
|||
* '''[[String Manipulation Functions#Clean|Clean(…)]]''': Clean a string to be used for various operations |
|||
* '''[[String Manipulation Functions#Extract|Extract(…)]]''': Returns a portion of a string bounded by another substring |
|||
* '''[[String Manipulation Functions#Find|Find(…)]]''': Finds a string or character in another string, returning its zero-based position in that string |
|||
* '''[[String Manipulation Functions#FixCase|FixCase(…)]]''': Changes the case of a given string |
|||
* '''[[String Manipulation Functions#FixSpacing|FixSpacing(…)]]''': Intelligently splits adjacent camel-cased words |
|||
* '''[[String Manipulation Functions#Hexify|Hexify(…)]]''': Hexifies a string to make it suitable for web usage |
|||
* '''[[String Manipulation Functions#Left|Left(…)]]''': Retrieves a specified number of characters from the left of a string |
|||
* '''[[String Manipulation Functions#Length|Length(…)]]''': Returns the number of characters in a string |
|||
* '''[[String Manipulation Functions#Letter|Letter(…)]]''': Returns the starting letter or letters of a given string |
|||
* '''[[String Manipulation Functions#Mid|Mid(…)]]''': Retrieves specified characters from a string |
|||
* '''[[String Manipulation Functions#MoveArticles|MoveArticles(…)]]''': Takes "The Beatles" and reverses it to "Beatles, The" |
|||
* '''[[String Manipulation Functions#NoArticles|NoArticles(…)]]''': Takes "The Beatles" and returns "Beatles" |
|||
* '''[[String Manipulation Functions#PadLeft|PadLeft(…)]]''': Pad any string with any character, to the left |
|||
* '''[[String Manipulation Functions#PadRight|PadRight(…)]]''': Pad any string with any character, to the right |
|||
* '''[[String Manipulation Functions#Regex|Regex(…)]]''': Regular expression pattern matching and capture |
|||
* '''[[String Manipulation Functions#RemoveCharacters|RemoveCharacters(…)]]''': Removes a list of characters from a string |
|||
* '''[[String Manipulation Functions#RemoveLeft|RemoveLeft(…)]]''': Trims characters from the beginning of a string |
|||
* '''[[String Manipulation Functions#RemoveRight|RemoveRight(…)]]''': Trims characters from the end of a string |
|||
* '''[[String Manipulation Functions#Replace|Replace(…)]]''': Replace or remove a string segment |
|||
* '''[[String Manipulation Functions#Right|Right(…)]]''': Retrieves a specified number of characters from the right of a string |
|||
* '''[[String Manipulation Functions#Swap|Swap(…)]]''': Takes Firstname Lastname and swaps to Lastname, Firstname |
|||
* '''[[String Manipulation Functions#Trim|Trim(…)]]''': Removes leading and trailing non-printable characters and new lines from a string |
|||
* '''[[String Manipulation Functions#TrimLines|TrimLines(…)]]''': Removes leading and trailing non-printable characters and new lines from a string |
|||
* '''[[String Manipulation Functions#UnMoveArticles|UnMoveArticles(…)]]''': Takes "Beatles, The" and reverses it to restore the normal word order, "The Beatles" |
|||
* '''[[String Manipulation Functions#Unswap|Unswap(…)]]''': Takes Lastname, Firstname and reverses it to Firstname Lastname |
|||
* '''[[String Manipulation Functions#Urlify|Urlify(…)]]''': Takes a string and applies html formatting for browser consumption |
|||
==== [[Test and Comparison Functions]] ==== |
|||
* '''[[Test and Comparison Functions#Compare|Compare(…)]]''': Compares two numbers |
|||
* '''[[Test and Comparison Functions#IsDigit|IsDigit(…)]]''': Determines whether or not a given value is digits |
|||
* '''[[Test and Comparison Functions#IsDriveMissing|IsDriveMissing(…)]]''': Checks if a drive is missing |
|||
* '''[[Test and Comparison Functions#IsEmpty|IsEmpty(…)]]''': Tests a value for emptiness |
|||
* '''[[Test and Comparison Functions#IsEqual|IsEqual(…)]]''': Compares two values in one of seventeen specified modes |
|||
* '''[[Test and Comparison Functions#IsInPlayingNow|IsInPlayingNow(…)]]''': Tests to see if a file is in the Playing Now playlist |
|||
* '''[[Test and Comparison Functions#IsLowerCase|IsLowerCase(…)]]''': Tests to see if a value is lower case |
|||
* '''[[Test and Comparison Functions#IsMissing|IsMissing(…)]]''': Tests to see if a file exists on the system |
|||
* '''[[Test and Comparison Functions#IsPlaying|IsPlaying(…)]]''': Tests to see if a file is in currently being played |
|||
* '''[[Test and Comparison Functions#IsRange|IsRange(…)]]''': Tests a value for inclusion within a given range |
|||
* '''[[Test and Comparison Functions#IsRemovable|IsRemovable(…)]]''': Tests to see if a file is stored on removable media |
|||
* '''[[Test and Comparison Functions#IsUpperCase|IsUpperCase(…)]]''': Tests to see if a value is upper case |
|||
* '''[[Test and Comparison Functions#SearchTags|SearchTags(…)]]''': 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="ff0000" size="80" alpha="50"> 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:21, 11 February 2023
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:
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:
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 Values: Override the expression, and [This]
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.
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.
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
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
Here is a more complex expression example that illustrates the various rules discussed above regarding expressions:
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:
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
- Field(…): Returns a field's value.
- FieldQuery(…): Return a list of matches based on a list of fields to search, from a selected scope of files.
- ItemCount(…): 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.
- Load(…): Outputs the value of a global variable.
- Note(…): Retrieve note fields.
- Save(…): Saves a value to a global variable.
- SaveAdd(…): Adds to a global variable.
- SetField(…): Sets a field's value.
- Tag(…): Returns a file's physical tag.
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
- DBLocation(…): Identifies a file's databases
- Enviro(…): Returns the full path to a host system variable
- FileDBLocation(…): Identifies a file's databases
- FileFolder(…): Returns the name of a file's parent
- FileKey(…): Returns a file's unique internal identifier
- FileLookup(): Looks up a file based on its filename
- FileName(…): Returns a file's name component
- FilePath(…): Returns a file's path component
- FileVolume(…): Returns a file's volume name component
Formatting Functions
- Delimit(…): Outputs a value with head/tail strings when value is non-empty
- FormatBoolean(…): Formats a boolean (true / false) value in a specified manner
- FormatDuration(…): Presents a duration of seconds in a reader friendly format
- FormatFileSize(…): Presents a number of bytes in a reader friendly format
- FormatNumber(…): Formats and rounds a number to a specified number of decimal places
- FormatRange(…): Formats a value as a range
- Orientation(…): Outputs the orientation of an image
- PadNumber(…): Adds leading zeros to any given number
- RatingStars(…): Outputs the value of Rating as a number of star characters
- RatingStars10(…): Outputs the value of a 10 star rating field as a number of star characters
- Watched(…): Outputs a formatted video bookmark
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
- ListBuild(…): Constructs a list from a series of items
- ListClean(…): Various list operations
- ListCombine(…): Combines two delimited lists into a single delimited list
- ListContains(…): Checks for a value being in a list
- ListCount(…): Returns the number of items in a list
- ListEqual(…): Checks for equality between two lists
- ListFilter(…): Filter any list, returning only values within a given range
- ListFind(…): Search a list for a value and return that value, or its index # in the list
- ListFormat(…): Outputs a given list in a reader friendly format.
- ListGrep(…): Returns list items containing specified text
- ListItem(…): Returns an item from a location in a list
- ListLimit(…): Limits the length of a list
- ListMath(…): Perform one of 4 specific math functions on a list containing numbers
- ListMix(…): Combine corresponding values from multiple lists into a new list, using a template to process each item
- ListRemove(…): Removes a string from a list
- ListShuffle(…): Shuffles a list
- ListSort(…): Sort a list of values
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
- 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
- Compare(…): Compares two numbers
- IsDigit(…): Determines whether or not a given value is digits
- IsDriveMissing(…): Checks if a drive is missing
- IsEmpty(…): Tests a value for emptiness
- IsEqual(…): Compares two values in one of seventeen specified modes
- IsInPlayingNow(…): Tests to see if a file is in the Playing Now playlist
- IsLowerCase(…): Tests to see if a value is lower case
- IsMissing(…): Tests to see if a file exists on the system
- IsPlaying(…): Tests to see if a file is in currently being played
- IsRange(…): Tests a value for inclusion within a given range
- IsRemovable(…): Tests to see if a file is stored on removable media
- IsUpperCase(…): Tests to see if a value is upper case
- SearchTags(…): 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 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:
where type is one of the following values:
list | A list of strings, separated by semicolons |
string | Sorts as strings (with smart number handling) |
number | Sorts values as numbers (decimal or integer) |
integer | Sorts values as integers |
path | Sorts using a smart filename compare style |
month | Sorts 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:
to the end of the field's calculated expression.
Lists and Trees
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:
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:
to the end of an expression.
Sort Order
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:
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:
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:
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:
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:
alpha | Sets alpha-blending percentage (0 - 100) |
color | Sets the foreground color (RGB hex values from 00 to ff in the form of rrggbb) |
bgcolor | Sets the background color (same values as color) |
face | Sets the font face (a font name) |
size | Sets 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.