Difference between revisions of "Expression Language"

From JRiverWiki
Jump to: navigation, search
(Added help links for using GV's.)
(Formatting Functions)
 
(206 intermediate revisions by 11 users not shown)
Line 1: Line 1:
==Using this page==
+
{{Tocright}}
The 'Contents' box above contains a list of available functions roughly grouped by usage scenario, and each function name gives a fair indication of what it might do. Each of the group headers contain some basic information pertinent to the functions inside the group. Click on a function or function group header in the Contents box to be taken directly to more information about it on the page. At the bottom right of each section there is a "Back to top" link which will take you back up to the Contents box allowing you to quickly get to where on the page you would like to go next.<br>Some of the function descriptions reference other functions to help illustrate their usage. Where this happens, a link to the referenced function is provided if needed. The browser's "Back" button will then return you to the previous place you were at on the page.<br>The page contains some references that link to external pages. Such links can be identified by the little square icon that follows them, [http://yabb.jriver.com/interact like this--->]. These links will not load in new tabs or windows, so, if you would like to keep this page open in your browser, right click on these links and choose to open them in a new tab or window.<br><div style="text-align:right;">([[#top|Back to top)]]</div>
+
Media Center provides a simple programming language that enhances and enriches its overall user interface and usability.
==Overview==
+
This language, commonly called the expression language, is simple to learn, simple to use, and can greatly enhance your experience using Media Center.
  
The J. River Media Core database engine supports Excel-style functions for use in view schemes, searches, displayed columns, and tag editing.
+
Expressions are ubiquitous throughout Media Center, used in areas such as:
 +
:* The categories in a view
 +
:* File list expression columns
 +
:* Theater View
 +
:* Customized view headers, grouping and sort criteria
 +
:* The library field manager (fields with data type Calculated data)
 +
:* File and folder location definitions
 +
:* Auto-import rules
 +
:* Custom DLNA titles
 +
:* The player's display
 +
:* Captions and thumbnail text
 +
:* The link manager (expressions help format link URLs)
 +
:* Rename, Move, & Copy tool
 +
:* Tag assignment
 +
:* Complex search queries
  
An expression is a mixture of text, fields, and functions. A function allows special operations to be performed. Functions are all listed with a name followed by an opening and closing parenthesis. When building expressions, the instructions you wish to pass to the function are placed inside these parenthesis, with multiple instructions separated by commas. When your expression is evaluated, any spaces entered after a comma are ignored. This allows you to compose complex expressions on multiple lines, making it easier to keep track of where you are in your expression. Occasionally, you will find that you want a space, or parenthesis character to be treated literally as part of your instructions, rather than expression syntax, and in these cases, the character is "escaped" by using a preceding forward slash. Examples using this escaping can be seen [[#Clean(...): Returns a cleaned up version of a filled in template|here]] and [[#Replace(...): Replace or remove strings from a value.|here]].
+
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.
As you progress with your expression building, you will begin nesting multiple functions into a single expression; always remember that a completed expression must contain a matching number of opening and closing parenthesis in order to work reliably.
 
  
The functions available to us range from highly functional, with a broad range of applicable uses, through specialised, limited use functions that only appeal to a select group of users, to seemingly redundant functions and obscure functions that Media Center uses internally. The functions below are listed with those with the broadest appeal at the top, and the more obscure at the bottom.
+
== The Anatomy of an Expression ==
  
<ins>'''Any given expression can only work on any given single file.  It is not possible to compare a field in one file with a field in another file.'''</ins><br>
+
As mentioned above, an expression is a mixture of text and function calls (and some reserved stuff described shortly).
Batch file operations are possible, and when used in a list, even a grouped list, an expression will be applied to each individual file in turn, not as a group.
+
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.
  
A slightly extended overview  is also available elsewhere in this wiki, titled [http://wiki.jriver.com/index.php/Database_Expressions Database Expressions], and another page attempts to demonstrate Media Center mimicking the [http://wiki.jriver.com/index.php/Database_Expressions_AND_OR_And_XOR "AND",&nbsp;"OR"&nbsp;and&nbsp;"XOR"] database searches.
+
But simple text only has so much utility.
 +
The ability to transform or generate content is much more interesting and useful.
 +
And this is when [[#Functions|functions]] are employed.
 +
Media Center [[#Function Index|provides many functions]], which when called, produce some output.
 +
Most functions require some form of input, called arguments, and most functions generate output.
 +
By supplying a function with various arguments, the function will return some output value which is just more text.
 +
And this output text can be the used by other functions, and so on.
 +
Each function has a unique name, and calling upon a function to do some work requires little more that using its name anywhere in the expression.
  
<div style="text-align:right;">([[#top|Back to top)]]</div>
+
A function call looks like this:
==Using expressions==
 
Expressions are ubiquitous in Media Center, and are useful in a variety of locations such as the following:
 
  
* Player Display (right-click the Player Display , choose "Customize")
+
:{{monospace|<i>functionname</i><b>(</b><i>argument 1</i>, <i>argument 2</i>, ...<b>)</b>}}
* Captions & Thumbnail text
 
* Panes (''aka Categories'')
 
* Expression columns (right-click a column header and choose "Add expression column")
 
* The library field manager (''Create expression-based library fields'')
 
* Theater View
 
* Link manager (''Use expressions to format link URLs'')
 
* Rename, Move, & Copy Files tool
 
  
The syntax of the expression language is generally consistent throughout Media Center. An expression is evaluated, [[#Formatting output|formatting output]] that is used in the context where the expression was evaluated. To perform [[#Tag assignment|Tag assignment]] or [[#Search rule filtering|Search rule filtering]], an expression is modified slightly to work in these contexts.
+
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.
<div style="text-align:right;">([[#top|Back to top)]]</div>
+
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 [[String_Manipulation_Functions#FixCase|FixCase()]] function to change its input to Title Case:
  
===Formatting output===
+
:{{monospace|fixcase(A good movie)}}
To give usage examples for all of these locations is beyond the scope of this page, so a few tips should suffice to get those interested up and running.
 
  
* Using expressions to produce custom Thumbnail text makes it possible to display only relevant or useful data.
+
The result is <span style="font-family: monospace,monospace; font-size:1em;">A Good Movie</span>.
* Expressions can be used to reduce link bar clutter by conditionally displaying links based on, for example, Media Type.
 
* File and directory paths may be based on expressions; this is especially useful in Options > File Locations, and in the "Rename, Move, & Copy Files" tool.
 
* User-specified library fields may be calculated, based on the output of expressions.
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
===Tag assignment===
+
A slightly more complex expression example consists of both text and a nested function call:
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 tag.  Without the prepended "=" character, the expression itself (and not its evaluated value) would be stored in the tag.
 
  
An assignment expression can be entered into the Tag Action Window, or by using inline editing in the file list or a pane entry.
+
:{{monospace|Wow! fixcase(replace(A good movie, good, great))}}
  
Note: Undo is supported, reverting each tag to its value prior to the assignment.  Redo is also supported, reapplying the most recent Undo.
+
Inner functions are called before outer functions, so the [[String_Manipulation_Functions#Replace|Replace()]] function is call first:
  
The following screenshots illustrates using an expression for tag assignment:<br>
+
:{{monospace|replace(A good movie, good, great)}}
{| align=center
 
|-
 
|
 
[[image:Inline1.png|frame|Pressing "Enter" copies the Date data into the caption field]]
 
|
 
[[image:Inline2.png|frame|Just like that!]]
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
===Search rule filtering===
+
and its output is then supplied as the input to the [[String_Manipulation_Functions#FixCase|FixCase()]] function.
Expressions can be used as search filters, and in order to do so, the expression must be entered into the search field using the following format:<br>
+
[[String_Manipulation_Functions#Replace|Replace()]] does its work substituting {{monospace|good}} with {{monospace|great}}, and returns {{monospace|A great movie}}.
'''[=EXPRESSION]=1''' or '''[=EXPRESSION]=0'''
+
This output is then supplied as the argument to [[String_Manipulation_Functions#FixCase|FixCase()]] which sees only the text {{monospace|A great movie}} (it knows nothing about how it was produced).  So the function call:
  
All files that match the expression will return "1" and all that don't match, return "0". Decide which is required and use "1" or "0" accordingly.
+
:{{monospace|fixcase(A great movie)}}
  
Remember that the search field appears in many places throughout Media Center, places that include:
+
in turn outputs {{monospace|A Great Movie}}.
* The search field itself (in the top right corner of the program)
+
Now that the functions have produced their output, the final output, including the literal {{monospace|Wow!}} leading text is
* A view scheme search list
 
* "Edit Files To Show" area of the Customize View dialogue
 
* Play Radio Files
 
* The last.fm submission filter
 
* The links manager
 
and this method of expression application can be used in all of them.
 
  
An example of an expression formatted for use in the search field would be:
+
:{{monospace|Wow! A Great Movie}}
'''<span style="color:blue">[=<ins>[[#IsEqual(...): Compares two values in one of nine specified modes|isequal]]</ins>(<ins>[[#FormatDate(...): Formats a date value in a specified manner|formatdate]]</ins>([date&nbsp;imported,0],MM//yyyy),formatdate(<ins>[[#Now(...): Retrieve and display the system date|now()]]</ins>,MM//yyyy),1)]=1</span>'''
 
Which will list all files that have been imported this month.
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
==Specify data types for expression based fields==
+
== Fields ==
It is often useful to force Media Center to operate on data of one type as if it were another type. This is useful for changing sort order, or handling list data as a simple string. For example, month names are sorted alphabetically by default, but by setting the data type, sorting can be chronological instead. Data types are forced by appending to an expression the string: '''&datatype=[<span style="color:blue">''DATA TYPE''</span>]''',  where <span style="color:blue">''DATA TYPE''</span> is one of the following values:
+
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 [[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:
  
* '''List''': ''A list of strings, separated by semicolons''
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">fixcase(field(album), 3)</span></div>
* '''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.)''
 
  
The following screen images show these data type instructions in action:
+
would produce <span style="font-family: monospace,monospace; font-size:1em;">AFTER HOURS</span>.
 +
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>.
 +
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.
  
{| align=center
+
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.
|-valign=top
+
Nonetheless, both forms are equivalent.
! colspan="2" style="background: #ecfeea; color: black; border: 1px solid black" | &DataType=[Month]
+
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:
! colspan="2" style="background: #ecfeea; color: black; border: 1px solid black" | &DataType=[List]
 
|-valign=top
 
|
 
[[image:Datatype1.png|left|frame|Used in a pane, '''formatdate([date,0],MMMM)''' returns the months as requested, but the alphabetic order is a little confusing.]]
 
|
 
[[image:Datatype2.png|right|frame|Adding the "month" data type, like so, '''formatdate([date,0],MMMM)&datatype=[month]''', takes care of the order.]]
 
|width=100|&nbsp;&nbsp;&nbsp;
 
|
 
[[image:Datatype3.png|left|frame|No data type has been specified, so the expression results are presented literally, as individual string values.]]
 
|
 
[[image:Datatype4.png|right|frame|Add the "list" data type to the expression and it is then formatted correctly in the pane. Here, the [[#ListBuild(...): Build a list from a series of values|ListBuild]] function has been used to create a nested browsing tree.]]
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
==Fields==
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">fixcase([album], 3)</span></div>
  
Any text between brackets [] will be replaced with the corresponding field from your library. 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, [My Fake Artist] will be treated literally, square brackets and all. After the field name, a comma can be placed followed by a 0 or 1 to indicate whether the field should be formatted.  So, [Duration] and [Duration, 1] will give "4:02" while [Duration, 0] will give "242". This is particularly important when working with the "Format" functions, where most times you will want the evaluator to work with the raw field contents rather than the formatted contents you see in the file list.
+
=== 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 [[Accessing_and_Storing_Functions#Field|Field()]] is the function used to return the value of a specified field.
 +
But [[Accessing_and_Storing_Functions#Field|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 [[Accessing_and_Storing_Functions#Field|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.
  
Function and field values in expressions are ''not'' case-sensitive.
+
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.
Available functions with descriptions and examples are listed below.
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
==Functions==
 
  
===Conditional Functions===
+
Not used earlier because it is optional, the second argument to the [[Accessing_and_Storing_Functions#Field|Field()]] function selects the mode of output:
The functions in this section evaluate one or more of their arguments to determine if their result is true or false, and execute specific actions depending upon that result.
+
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.
 +
Here are two examples using the date field, the first one outputs the date value in raw format, the second in the friendly format:
  
Although the expression language does not directly support AND, OR, and XOR, these can be easily emulated.  See: [[Database_Expressions_AND_OR_And_XOR]].
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">field(date, 0)</span></div>
 +
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">field(date, 1)</span></div>
  
Beginning with version 17.0.40, Media Center supports the NOT operator (a '''!''' character) in a conditional. This can be used to invert the sense of an '''If()''' statement for easier reading, or in an '''IfElse()''' to better support if-then-else chains.
+
==== Field Values: Override the expression, and [This] ====
 +
[[File:ExpressionOverride.png|right]]
 +
When creating (or editing) an expression based field, there is an option, shown in the image on the right, to "Allow custom data to override the expression".
 +
When enabled, it becomes possible to open the tag for editing either inline or in the tag window, just as you would any other regular tag, and replace the expression derived data with any other static data. Complex expression based fields can very easily slow view loading times to a crawl, and in many cases, this option can help speed things up again. Imagine an expression based field that manipulates another, otherwise static field, such the [Date] field. The returned expression values will never change, so why waste time evaluating the same results over and over, when you can simply replace them with static data and so forego any future expression processing?
  
====If(...): Conditional If/Then/Else evaluator.====
+
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".
  
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
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>''.
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" width=100 | If()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This will be the function you will likely use more than any other. It is typically used in conjunction with one or more other functions and allows you to give specific instructions depending upon whether the result is positive (1) or negative (0). The positive instruction is always given first.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''if(''expression to test'',instructions if positive,''instructions if negative'')'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''if(isequal([artist],bob dylan,1),Genius,Mediocre)'''<br>''Wherever this expression is applied, be it as an expression column or category, as part of a renaming rule, thumbnail text, if the artist tag is Bob Dylan, Media Center will produce Genius, and for all other artists, it will produce Mediocre.'' The "IsEqual()" function is described in the first table below.
 
<br>
 
'''if(isequal([artist],bob dylan,1),Genius,if(isequal([album],Joshua Tree,8),Great Album,Mediocre))'''
 
<br>''Here, we have two nested "If" functions. First we ask if the artist is Bob Dylan, if the result is positive, write "Genius". If the artist is not Dylan, we then ask if the album is "Joshua Tree", if yes, write "Great Album", and if no, write mediocre''
 
  
<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.
'''if(!isempty([comment]), Regex([comment], /#^(\S+\s+\S+\s+\S+)#/, 1), *No Comment)'''
 
<br />''Output's the first three words of the comment field; otherwise, outputs "*No Comment".  By inverting the sense of the conditional, the more interesting case is moved ahead of the more mundane case.
 
  
<br>Take care to provide all three arguments to the If() statement, and for nested statements, to ensure the proper number of closing parenthesis.  This can become less-than-obvious with nested sequences. The built-in expression editor can lessen the burden by allowing line breaks or whitespace after commas (argument separators).  For example, the previous example is easier to read and maintain as:
+
'''<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.
  
: if(!isempty([comment]),
+
'''<u>Note 2:</u>''' MC32 comes with the addition of the [[IsOverridden()|IsOverridden(...)]] function that now allows us to filter any given expression based field based on its override status.
:: Regex([comment], /#^(\S+\s+\S+\s+\S+)#/, 1),
 
:: *No Comment)'''
 
  
|}
+
==== Field Values: Empty, 0, and 1 ====
<div style="text-align:right;">([[#top|Back to top)]]</div>
+
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
 +
for numeric field types Integer and Decimal.
 +
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.
  
====IfElse(...): If/Then/Else sequence of conditional tests and actions.====
+
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>,
 +
but the display format (as in the file list) will be shown as empty.
 +
The empty display allows for less visual noise in the user interface, since a column full of <span style="font-family: monospace,monospace; font-size:1em;">0</span> values is not usually helpful.
 +
In fact, if you attempt to set a numeric field's value to <span style="font-family: monospace,monospace; font-size:1em;">0</span> in the file list, it will immediately be displayed as empty.
  
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
Generally this difference is unimportant, except when testing numeric values with [[Test_and_Comparison_Functions#IsEmpty|IsEmpty()]] or [[Test_and_Comparison_Functions#IsEqual|IsEqual()]].
|- valign="top"
+
It is easy to be fooled when testing such a value if the value shown in a file list is empty.
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" width=100 | IfElse()
+
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.
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | The IfElse() conditional (available since build 17.0.7) provides a convenient mechanism for shortening and more clearly expressing nested conditionals into an alternating sequence of tests and actions. For example, consider a nested sequence of If() tests such as If(test1, action1, If(test2, action2, If(test3, action3))), shown below in a sequence of if/then/else pseudo-code statements:
 
  
: if (test1)
+
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.
:: action1
+
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
: else if (test2)
+
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.
:: action2
 
: else if (test3)
 
:: action3
 
  
The IfElse() statement may be used to more cleanly express the flow of expression by removing the superfluous internal If() statements:
+
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 <span style="font-family: monospace,monospace; font-size:1em;">Unknown Disc #</span> (this ensures no blank values are generated as path components).
 +
To test such a field, always use and test against the raw format, and then expressions will be context agnostic.
  
'''IfElse(test1, action1, test2, action2, test3, action3)'''
+
===Field Assignment===
 +
<div>
 +
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
  
|- valign="top"
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">=removeleft([name], 4)</span></div>
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''ifelse(''test expression 1'',instructions 1,''test expression 2'',instructions 2, ...)'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''ifelse(isequal([media type], Audio), Le Tunes, isequal([media type], Video]), Flix)'''
 
  
''If media type is audio, outputs "Le Tunes", else if media type is video, outputs "Flix"''
+
entered into an edit cell for the  <span style="font-family: monospace,monospace; font-size:1em;">name</span> field would remove
<br>
+
four characters from the left of the <span style="font-family: monospace,monospace; font-size:1em;">name</span> 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.
'''ifelse(isequal([artist], Bob Dylan), Genius, isequal([album], Joshua Tree, 8), Great Album, 1, Mediocre)'''
 
 
 
''This example, implements the nested if statements from the If() section above, first testing if the artist is Bob Dylan, and if true, outputs "Genius", otherwise evaluates the second test to determine if the album is "Joshua Tree", and if true, outputs "Great Album", otherwise, performs a final test, in this case a degenerate test of 1 (and 1 is always true), thus outputting the value "Mediocre".''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
===Query, Test and Comparison Functions===
 
All of the functions in this section, when used on their own, will only ever return one of two values, 1 (true) or 0 (false). There is a "[[#FormatBoolean(...): Formats a boolean (true / false) value in a specified manner|FormatBoolean()]]" function that can be wrapped around these and allows us to specify the output for each case and is discussed in more depth in the Format section. The real power and versatility of these "Is" functions is released when they are wrapped inside the If() function discussed above.
 
 
 
====Compare(...): Compares two numbers====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Compare()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Compares two numbers, using the operators less than (<), greater than (>), or equal to (=).  Outputs 1 if the comparison is true, and 0 otherwise.  Available starting with MC17.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''compare(''1st number'', ''operator'', ''2nd number'')'''
 
 
 
''Available Operators:''
 
* =: ''numeric equivalence''
 
* <: ''numeric less than''
 
* <=: ''numeric less than or equal to''
 
* >: ''numeric greater than''
 
* >=: ''numeric greater than or equal to''
 
 
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''compare([bitrate], <, 320)'''<br>''If the 'bitrate' is less than 320 (Kbps), the output will be 1, otherwise, the output will be 0.''
 
 
 
<br>'''If(Compare(Math(Now() - [Date Modified, 0]), >, 21), Expired, FormatDate([Date Modified, 0], Elapsed))'''
 
 
 
''Shows the age of files under 21 days old, or shows 'Expired' for older files.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====IsEqual(...): Compares two values in one of nine specified modes====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | IsEqual()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Compares two values in one of nine specified modes ("exact match", "Is greater than" etc.) and outputs 1 for a positive match and 0 for a negative match. If no compare mode is specified, the compare will default to 0.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''isequal(''1st value to compare'',2nd value to compare'',compare mode)'''
 
 
 
''Available Compare Modes:''
 
* 0: ''case-sensitive string compare for equality''
 
* 1: ''case-insensitive string compare for equality''
 
* 2: ''numeric compare for equality''
 
* 3: ''numeric less than''
 
* 4: ''numeric less than or equal to''
 
* 5: ''numeric greater than''
 
* 6: ''numeric greater than or equal to''
 
* 7: ''substring search (case sensitive)''
 
* 8: ''substring search (case insensitive)''
 
 
 
'''In all cases, the first value is always compared with the second value, never the other way around'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''isequal([artist],[album],1)'''<br>''If the 'artist' and 'album' values are the same, the output will be 1, otherwise, the output will be 0.''
 
 
 
<br>'''if(isequal([artist],[album],1),Self Titled,[album])'''
 
<br>''Wrapped inside an 'If' function, if the 'artist' and 'album' values are the same, the output will be 'Self Titled', otherwise, the output will be the 'album' value.''
 
 
 
<br>'''if(isequal([artist],[album],1),Self Titled/,,[album]/))'''
 
<br>''This example demonstrates the character 'escaping' mentioned in the [[#Overview|overview]] earlier. Here, we want the output to be either "Self Titled," (note the inclusion of the comma) or the album value with a closing parenthesis. In order to achieve this, the comma, and the closing parenthesis, are escaped using a preceding forward-slash character. This informs the expression evaluator that these characters are not part of the expression syntax and are to be treated literally''
 
 
 
<br>'''if(isequal([filename (path)],Classical,8),Classical,Not Classical)'''
 
<br>''Here, compare mode number eight has been specified, so, if the letters classical appear anywhere in the file path for a given file, the expression will return "Classical" and if not, it will return "Not&nbsp;Classical".'' '''Note that when using compare modes seven and eight, the subject must be given first, and the term to compare for given second'''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====IsEmpty(...): Tests to see if a field is empty====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | IsEmpty()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Tests any given field for data. If the field is empty, the function returns 1, and if populated, the function returns 0. There are two different test modes available, a "string" test, and a "number" test. This is because as far as Media Center is concerned, fields designated as containing numerical values that are populated with the number zero, are empty. If no test mode is specified, the function will default to 0.
 
Pay particular attention to the third example offered below, as it covers a caveat that comes with this particular function.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''isempty([field to test],test mode)'''
 
''Available test modes:''
 
* 0: ''String test (field must be empty to get a positive result)''
 
* 1: ''Numerical test (field must be empty, or contain 0 to get a positive result)''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''isempty([comment],0)'''<br>''If the comment field is empty, this expression will return 1, but if the comment field contains data, the expression will return 0.''
 
 
 
<br>'''isempty([track #],1)'''
 
<br>''This expression will perform a numerical test for data in the [track #] field. If the field is empty, or contains 0, the expression will return a positive result, 1, otherwise, the result will be negative, 0.''
 
 
 
<br>'''if(isempty([disc #]),,[disc #])'''
 
<br>''Here, by not entering any instructions to carry out for a positive result, the expression will do just that, and output nothing, but if the [disc #] field does contain data, the expression will write that out. Upon first look, you would think that this could work really well in the "Rename, Move, & Copy Files" tool for only creating a \Disc #\ directory if needed. This will not work. When asking the rename tool to create directories from field data, it is smart enough to know that directories with no name are illegal in Windows, so when it encounters an empty field, it automatically converts it to "Unknown&nbsp;[Field&nbsp;Name]". It does this before the expression engine gets to see it, which means that the IsEmpty function will always return a negative result when used in the rename tool, even when the specified field is indeed empty. As we now know that empty fields are passed through the rename tool as "Unknown&nbsp;[field&nbsp;name]" we can use '''if([[#IsEqual(...): Compares two values in one of nine specified modes|isequal]]([disc&nbsp;#],unknown,8),,[disc&nbsp;#])''' to achieve the desired result. Note that this only applies when using the rename files tool.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====IsRange(...): Tests a value for inclusion within a given range====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | IsRange()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | IsRange allows us to test if any given field falls inside any given range of values. If the field falls inside the given range, the function returns 1, and if outside the given range, the function returns 0.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''IsRange([Field to Test],Specified-Range)'''
 
''The range to test for can be letters or numbers, separated by a hyphen, without spaces, lowest value first, highest second. Letters and numbers cannot be mixed, the range can only be one or the other''
 
* ''1-100''
 
* ''a-z''
 
* ''c-d''
 
* ''23-7542''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''isrange([artist],a-c)'''<br>''Abba or Blondie will return 1 (positive), and ZZ Top will return 0 (negative).''
 
 
 
<br>'''if(isrange([bitrate],96-191),Poor Quality,High Quality)'''
 
<br>''This expression will output "Poor Quality" for any file where the bitrate falls between 96 and 191, and "High Quality" for all others. Note that expressions are only as good as the instructions given, and that the above expression would label files with bitrates less than 96kbps as "High Quality". If this expression were used to add a category to a view, there would be two selectable choices in the category, Low Quality, and High Quality. Selecting either one would then filter the file list accordingly.''
 
 
 
<br>'''[http://yabb.jriver.com/interact/index.php?topic=38566.msg262229#msg262229 This post]''' ''on Interact shows the use of IsRange in a Search List. (right click the link, open in new tab to keep this page open). The expression format in that post shows how to form expressions for use in standard Media Center searches, something that was covered earlier'' [[#When, Where and How to use expressions|on this page.]]
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====IsMissing(...): Tests to see if a file exists on the system====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | IsMissing()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function tests the existence of a file in the file system. If the file is missing, the function returns 1 (positive), and if the file is found, the function returns 0 (negative). This function is useful for checking the integrity of your Media Center library as you can use it to produce a list of any files in your library that Media Center cannot find.  Beginning with version 17, IsMissing() treats special entries such as ripped Blu-ray or DVDs as single files, even though they physically exist in the file system as several files and directories.
 
 
 
'''Note''': IsMissing() works directly on the file system and will cause performance to suffer: the larger the library, the longer it will take to produce results.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''IsMissing(Full Path To File)'''
 
''Checks for existence of the file "Full Path To File", or the current file if unspecified.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''ismissing()'''<br>''Checks if the current file exists, and returns 1 (positive) if the file does not exist, and 0 (negative) if the file does exist.''
 
 
 
<br>'''ismissing(C:\Music\My Lost File.mp3)'''
 
<br>''Checks for "My Lost File.mp3" and returns 1 (positive) if the file does not exist, and 0 (negative) if the file does exist.''
 
 
 
<br>'''[=ismissing([filename])]=1'''
 
<br>''This example also demonstrates how to construct an expression for use as a Media Center search string. If you place this in the search field in the top right corner of the program while viewing all of your library, it will filter the list, leaving only the missing files on view. If your library is in good order, this list should be empty. You could also create a view scheme and use this string in the "Set rules for file display" search to give you a view that you can visit periodically to check that your library is intact
 
 
 
<br>'''if(ismissing(),File is missing,File exists)'''
 
<br>''Wrapped inside an "If()" function, the expression outputs "File is missing" or "File Exists" depending on the result returned by IsMissing()''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====IsRemovable(...): Tests to see if a file is stored on removable media====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | IsRemovable()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Checks to see if a file resides on removable media and if so, returns 1 (positive), and if not, returns 0 (negative). There is not a lot to say about this function, especially since Media Center comes equipped with a [Removable] field by default that is automatically populated with 1 for all files in the library that are on removable storage. The function works in exactly the same way as the IsMissing function described above, returning 1 (positive) if the file is on removable storage, and 0 (negative) if not.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''IsRemovable(Full Path To File)'''
 
 
 
''If no file path is specified, the function will default to checking the current file.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''isremovable()'''<br>''Checks if the current file is on removable storage, and if so, returns 1 (positive), if not, the function returns 0 (negative).''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====IsInPlayingNow & IsPlaying(...): Tests to see if a file is in the Playing Now playlist or currently being played====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | IsInPlayingNow()
 
| rowspan="2" style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | These two functions will be dealt with together as from their names, they are self-explanatory. One checks to see if a file has been added to the playing now list in any zone, and the other checks if a file in a list is currently playing or not, in any zone. With this in mind, their most practical use is as expression columns in a file list. To add an expression column to a list, right click on any existing column header and click on the "Add expression column" option.
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | IsPlaying()
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''IsInPlayingNow()'''<br>''Checks the current file, and if in the Playing Now list, returns 1 (positive), and if not, returns 0 (negative).
 
 
 
<br>'''IsPlaying()'''
 
<br>''Checks the current file, and if currently playing, returns 1 (positive), and if not, returns 0 (negative).
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''if(isinplayingnow(),Selected,Not Selected)'''<br>''As mentioned in the description, the ideal place for these functions is as 'expression columns'. If this example were used in an expression column, then files added to Playing Now will show as "Selected" and all other files would show as "Not Selected". If the idea here is to be able to quickly see which files have been added, this might look a bit 'busy' and defeat the purpose, to which end, it is perfectly acceptable to tell the expression that if a file is not in Playing Now, to output nothing, by simply not giving any instructions for the negative result, like so: '''if(isinplayingnow(),Selected,)'''. Now, this expression column will only show "Selected" against files that are in Playing Now, leaving all others empty, giving a much easier column to read.
 
 
 
<br>Use'' IsPlaying ''in exactly the same way as IsInPlayingNow()''
 
 
 
<br>''On the Interact support forum,'' '''[http://yabb.jriver.com/interact/index.php?topic=57461.0 mark_h describes how he puts these two functions to work for him]''', ''and rick.ca shows how he tweaked the idea when he answers the question:'' '''"[http://yabb.jriver.com/interact/index.php?topic=58137.msg393905#msg393905 is it possible to play an artist's full work when a genre is shuffling?]"'''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
<br><br>
 
 
 
===Formatting Functions===
 
All of these functions (with the exception of FormatBoolean) take raw data from the library and allow us to present that data in a way that we choose. What does "raw data" mean? Media Center stores duration information in seconds and converts that information into hours (if needed), minutes and seconds for display in the Duration column in a file list. Likewise, file size information is stored in bytes and is converted into Mb for display in the file list. So there you have it, raw data. The following section gives some idea of what is possible using the raw data and the Format functions. '''''To&nbsp;instruct the expression evaluator to use raw data, a zero is added to the library field, inside the square brackets, like so: [Date Imported,0]'''''
 
 
 
====Delimit(...): Outputs a value with head/tail strings when value is non-empty====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FormatNumber()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | '''Delimit()''' outputs a value if the value is non-empty, including head and/or tail strings.  Nothing is output when the value is empty.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Delimit(Value,Tail string,Head string)'''
 
 
 
* "Value" ''The value to be output if it is not empty.''
 
* "Tail string" ''Optional, defaults to space.  The string to append at the end of a non-empty Value.''
 
* "Head string" ''Optional, defaults to empty.  The string to append to the beginning of a non-empty Value.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''delimit([Track #], .)'''<br>
 
''Appends a period (.) after a track number if [Track #] is not empty, e.g.  "12.".''
 
 
 
<br />
 
'''delimit([Date (year)], {, })'''<br />
 
 
 
Outputs the year surrounded by curly braces, e.g. "{2012}".
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====FormatBoolean(...): Formats a boolean (true / false) value in a specified manner====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FormatBoolean()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function is wrapped around another function and will return specified strings for true and false values returned by that other function.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FormatBoolean(True/False Test,String to use if true,String to use if false)'''
 
* '''True/False Test''' ''Other functions perform their respective tests and return 1 to indicate a true result, and 0 to indicate a false result''
 
* '''String to use if true,String to use if false''' ''If these are not specified, the function will default to using "True" and "False"''
 
 
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''formatboolean(isempty([number plays]),Never Played,Has Been Played)'''<br>''On it's own, the function'' isempty([number plays]) ''will return either 1 or 0. When wrapped inside a'' formatboolean ''function as shown here, the output for a true result will be "Never Played", and for a false result, the output will be "Has Been Played".
 
 
 
<br>'''formatboolean(isempty([number plays]))'''<br>''Here, there are no strings specified for the true/false results, therefore the function will default to using "True" and "False"''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====FormatDuration(...): Presents a duration of seconds in a reader friendly format====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FormatDuration()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Media Center stores duration data in seconds, at up to sixteen decimal places. The value shown in the default "Duration" column in a file list is an internally formatted interpretation of this raw "Duration" data. As Media Center automatically applies this formatting for us, there is not a lot of call for this particular function.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FormatDuration(Value to format)'''
 
 
 
''"Value to format" can be either the raw duration data, or a given number of seconds''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''formatduration([duration,0])'''<br>''This expression will duplicate the contents of the default [duration] field as shown in a file list''
 
 
 
<br>'''formatduration(600)'''
 
<br>''This will output ten minutes in the format 10:00''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====FormatFileSize(...): Presents a number of bytes in a reader friendly format====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FormatFilesize()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Media Center stores file size data internally in bytes. This function will convert those byte values into reader-friendly values, 3.2 Kb or 10.4 Mb, for example. The function will also accept a byte value directly.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FormatFileSize(Value to format)'''
 
 
 
''"Value to format" can be either the raw [File Size] data or a given number of bytes.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''formatfilesize([file size,0])'''<br>''This expression will duplicate the contents of the default [file size] field as shown in a file list''
 
 
 
<br>'''formatfilesize(56123456)'''
 
<br>''This expression will convert 56,123,456 bytes and the output will be 53.5 MB''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====FormatNumber(...): Formats a number to a specified number of decimal places====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FormatNumber()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | '''FormatNumber()''' allows to format any given value to a set number of decimal places.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FormatNumber(Value to format,Number of decimal places,Output if value is zero,Label if value is greater than 1,Label if value equals 1)'''
 
 
 
* "Value to format" ''This could be a library field, such as [replay gain] or the result of a [[#Math(...): Evaluates a given mathematical formula|Math()]] expression. Any numerical value you encounter where you would like to limit the number of decimal places displayed can have this function applied.''
 
* "Number of decimal places" ''This is optional. If not specified, the function will default to zero decimal places. Use -1 to output as many decimal places as necessary.''
 
* "Output if value is zero" ''This is optional. If not specified, the function will return zero.''
 
* "Label if value is greater than 1" ''This is optional. If not specified, the function will not return anything, if specified, and the formatted number is greater than 1, the function will return with the number, plus this label.''
 
* "Label if value equals 1" ''This is optional, as detailed below..''
 
** If not specified, but a label for greater than 1 has been specified, then this "greater than 1" label will always be used.
 
** If neither are specified, the function will not return anything.
 
** If both are specified, and the formatted number equals 1, the function will return with the number, plus this label.''
 
 
 
''Note that even if you are only interested in applying a label for those results that equal 1, you must also indicate the preceding instructions, if only to instruct the evaluator to ignore them, as shown in the examples below.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''formatnumber([duration,0],2)'''<br>''This will return the duration of a track, in seconds, shown to two decimal places.''
 
 
 
<br>'''formatnumber([number plays,0],0,Not played this one yet,Plays,Play)'''
 
* "0" decimal places has been specified, therefore the result will be a whole number with no decimals shown.
 
* ''If [number plays] is zero, the result will be "Not played this one yet"''
 
* ''If [number plays] is greater than 1, lets say 6, the result will be "6 Plays"''
 
* ''If [number plays] is 1, the result will be "1 Play"''
 
 
 
<br>'''formatnumber([number plays,0],,,,Time)'''
 
''Here, the function will fall back to its defaults for everything except when the number equals one:''
 
* ''No decimal places have been specified, the result will default to a whole number with no decimals shown.''
 
* ''If [number plays] is zero, the result will be "0"''
 
* ''If [number plays] is greater than 1, lets say 6, the result will be "6"''
 
* ''If [number plays] is 1, the result will be "1 Time"''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====FormatRange(...): Formats a value as a range====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FormatRange()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function places any given value into its place in any given range.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FormatRange(Value to format,Range size,Mode)'''
 
'''Value to format:''' ''This could be a specific word or number, or any library field''
 
<br>'''Range Size:''' ''A numerical value dependent on how you wish to set up your range. If not specified, this will default to 1''
 
<br>'''Mode:''' ''There are three possible modes, detailed below. If not specified, this will default to zero.''
 
* '''0:''' ''Automatically choose between number / letter grouping''
 
* '''1:''' ''Specifies that letter grouping should be used''
 
* '''2:''' ''Specifies that number grouping should be used''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''formatrange([artist])'''<br>''This will return the first letter from the [artist] field. Note that as '''range size''' and '''mode''' values were not specified, the function defaulted to one and automatic respectively.''
 
 
 
<br>'''formatrange([artist],3,1)'''<br>''This will take the first letter from the artist field and place it in the appropriate letter range. In this case, a range size of three has been specified, therefore the output will be in the form of "a-c", "d-f", "g-i" etc. etc.''
 
 
 
<br>'''formatrange([bitrate],100,2)'''<br>''This will take the bitrate and place it in the appropriate number range. In this case a range of 100 has been specified, therefore the output will be in the form of "0-99", "100-199", "200-299" etc. etc.''
 
 
 
Note that this function always starts number ranges from zero, 0-9, 10-19, etc, etc.. If you really need a number grouping that starts from 1, 1-10, 11-20, 21-30,etc. etc., you can use expressions to create a pseudo range. Full details, with a helpful explanation, of "1 based grouping" can be found [[CD_Reference_Number|on this page]].
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====Orientation(...): Outputs the orientation of an image====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Orientation()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 |  Outputs a word indicating the orientation of an image file.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Orientation()'''
 
 
 
* '''Portrait''': ''Output when an image's height is greater than its width.''
 
* '''Landscape''': ''Output when an image's width is greater than its height.''
 
* '''Portrait''': ''Output when an image's height is equal to its width.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''if(isequal(orientation(), Square), Square, Rectangle)'''
 
Outputs "Square" for square images or "Rectangle" for portrait and landscape images.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====PadNumber(...): Adds leading zeros to any given number====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | PadNumber()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function is not a 'Format' function by name, but is by nature, hence its inclusion in this section. PadNumber is a nice, simple function that is used to add leading zeros to any given number value.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''PadNumber(Field to pad,Total number of digits required)'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''padnumber([track #],2)'''<br>''This will add a leading zero to all track numbers between one and nine.''
 
 
 
<br>'''padnumber([[#Counter(...): Counts upwards in specified increments|counter()]],4)'''
 
<br>''here, the output from the counter() function will be 'padded' to 4 characters: 0001, 0002, 0003, etc. etc.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====RatingStars(...): Outputs Rating as star characters====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | RatingStars()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function outputs the Rating field's value as the equivalent number of black star characters.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''RatingStars()'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''ratingstars()'''<br>''For a file that has a Rating of 4, outputs "★★★★".''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====Watched(...): Outputs a formatted bookmark position within a video====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Watched()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 |  Outputs a video's bookmark position in a human-readable format.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Watched()'''
 
 
 
* '''0''': ''Output a human-readable watched status.''
 
* '''1''': ''Output a numeric watched value, 0 if not watched, 1 if partially watched, 2 if entirely watched.''
 
* '''2''': ''Output a watched checkmark (√) if watched''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''Watched()'''
 
Outputs formatted watched status, such as, ''57% on Sep 25'', or ''Aug 21'', or nothing when the video has not been watched.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
<br><br>
 
 
 
===String Manipulation===
 
The primary use of the functions in this section is to manipulate the data associated with any given file or files. When used with direct editing in the file list, or in the action window, as decribed [[#When, Where and How to use expressions|here]], they offer extremely fast and efficient methods for batch editing the actual tag data associated with multiple files.<br>Note that when used indirectly, in expression based columns, categories or library fields, the referred fields are not altered in any way, the data is merely presented in the expression field formatted as requested.
 
====Clean(...): Returns a cleaned up version of a filled in template====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Clean()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | The Clean() function is used to generally strip empty bracketing, superfluous dash characters, leading or trailing articles, or replace filesystem-illegal characters.  It is typically employed to clean the joining of several fields, some of which may be empty, or to produce filesystem-safe filenames.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Clean(Value to clean, Mode)'''
 
 
 
''Value to clean'': a string that will be cleaned
 
 
 
''Mode'' (optional, defaults to 0):
 
* 0: default clean, removes empty () and [], superfluous dash (-) characters and sometimes comma (be careful)
 
* 1: removes the article 'the' from the beginning and ', the' from the end
 
* 2: removes any article (a, an, the, etc.) from the beginning and end
 
* 3: replaces each filesystem-illegal character --- '''\ / : * ? " < > |''' --- with an underscore (_)
 
 
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''Clean([Album] - [Date])'''
 
Consider the simple expression ''[Album] - [Date]''.  When the [Date] value is empty, the result will contain the undesirable dangling separator string " - " following the album name (e.g. "Greatest Hits - ").  Using Clean() in the default mode removes this dangling string, and in this example produces "Greatest Hits".
 
 
 
<br />'''Clean(The Beatles, 1)'''<br />
 
For sorting or grouping purposes, it is often desirable to remove the leading article "The" from a string.  Clean() in mode 1 provides a convenient solution, and in this example produces "Beatles".
 
 
 
<br />'''Clean(AC//DC: Back In Black, 3)<br />
 
When an expression is to be used to produce a filename, filesystem-illegal characters must be removed or converted to legal characters.  Clean() in mode 3 will convert such characters into safe underscores.  This example yields the filesystem-safe "AC_DC_ Back In Black".  Note: the double forward slash is required above to produce a single double forward slash, since forward slash is the Media Center expression language escape character.
 
 
 
<br />'''Clean(\//:*?"<>|, 3)'''<br />
 
This trivial example demonstrates how all filesystem-illegal characters are converted to underscores, producing the nine-character string consisting entirely of underscores "_________".
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====FixCase(...): Changes the case of a given string====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FixCase()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function will output any given text string in one of five specified case modes.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FixCase(String to modify,Case mode to apply)'''<br>''The ''"String to modify"'' can be plain text, a library field, or a combination of the two.''
 
 
 
The five modes available are:
 
* '''0:''' ''Title Case''
 
* '''1:''' ''All Words''
 
* '''2:''' ''First word''
 
* '''3:''' ''ALL UPPERCASE''
 
* '''4:''' ''all lowercase''
 
 
 
''If no case mode is specified, the function will default to using "Title Case". Title case will start each principal word with a capital. More detail regarding title case can be found [http://www.grammar-monster.com/lessons/capital_letters_title_case.htm here]''
 
 
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''fixcase([album])'''<br>This will take the contents of the [album] field and present it with the specified capitalisation. As there is no specified mode here, the function defaults to 0, so, if an album is entered in the library as "Time Out Of Mind", the function will return "Time Out of Mind" (note the lower case "of")
 
 
 
<br>'''fixcase(MY ALbUm IS cAlLeD [album],4)'''<br>This would return "my album is called time out of mind"
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====FixSpacing(...): Intelligently splits adjacent camel-cased words====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FixSpacing()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This FixSpacing() function inserts spaces between adjacent camel-cased words.  For example, ''OneWorld'' becomes ''One World''.  This function is useful for helping to clean and convert metadata that favors compactness over standard sentence structure.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FixSpacing(''String to convert'', ''Mode'')'''<br>''The "String to convert" is any string of text.''
 
 
 
The available modes are:
 
* '''0:''' ''Disables conversion''
 
* '''1:''' ''Enables camel-case conversion''
 
 
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''fixspacing([name], 1)'''<br>Takes the contents of the [name] field and expands any camel-case into standard sentence structure. E.g. MiracleOn34thStreet becomes Miracle On 34th Street.
 
 
 
<br>'''fixspacing(Another [name], 1)'''<br>Assuming the same [name] as above, this would return "Another Miracle On 34th Street".
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====Hexify(...): Hexifies a string to make it suitable for website usage====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Hexify()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | ''The only place this function is likely to be used is in the "Link Manager". Websites often don't like spaces in their addresses, and punctuation could confuse a site's search engine. Hexify attempts to take care of this by replacing spaces and punctuation with web friendly alternatives. For example, Bob Dylan would become Bob%20Dylan.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Hexify(Value to hexify)'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''hexify([artist] - [album])'''<br>Oasis - (What's The Story) Morning Glory? becomes: ''Oasis%20-%20%28What%27s%20The%20Story%29%20Morning%20Glory%3F''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====Left(...): Retrieves a specified number of characters from the left of a value====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Left()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function retrieves a specified number of characters from the left of any given value.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Left(Value to get characters from,Number of characters to get)'''<br>''"Value to get characters from" can be plain text, a library field, or combination of both. If more characters than exist are requested, all available characters are returned.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''left([filename],3)'''<br>''This will return the drive letter, colon and first back-slash from the filename. If asked to show more characters than actually exist, the expression will return the entire value, also, remember that spaces count as characters too.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====Length(...): Returns the number of characters in a string====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Length()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function returns the number of characters in any given string.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Length(String to count characters from)'''<br>''The ''"String to count characters from"'' can be plain text, a library field, or a combination of the two.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''length([filename])'''<br>''This will count the characters in the [filename] field and return the result. Spaces count as characters, so, C:\My File.mp3 would return 14.
 
 
 
<br>'''if(isequal(length([filename]),68,6),68 Characters or more,Less than 68 Characters)'''<br>''Here, Length() has been combined with another two functions, "If()" and "IsEqual()". The expression compares the length of the filename against the number 68. If there are 68 or more characters in the filename, the expression will return "68 Characters or more", otherwise, it will return "Less than 68 Characters". If you are working with a device with filename length limitations, these functions can be used to create extremely useful expressions that could help with your device management.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====Mid(...): Retrieves specified characters from a value.====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Mid()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Mid() retrieves a specified number of characters from a specified starting point in any given string.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Mid(Value to get characters from,Character to start at,Number of characters to get)'''
 
* '''Value to get characters from''': ''This can be a library field, plain text, or a combination of both.
 
* '''Character to start at''': ''This is a numerical pointer, and rather confusingly, the function treats the first character as zero and begins from there. If not specified, the function will default to zero.
 
* '''Number of characters to get''': ''If this value is not specified, the function will default to 1. -1 can be used to retrieve all available characters after the specified start point.
 
 
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''mid(12345)'''<br>''As values for "Character to start at" and "Number of characters to get" have not been specified, they default to 0 and 1 respectively and the function returns the first character in the string, 1.''
 
 
 
<br>'''mid(12345,1,2)'''<br>''The start point has been specified as the second character in, and 2 characters have been asked for, the result here will be 23.''
 
 
 
<br>An example of Mid() being used to re-order a date field was given in answer to the question "[http://yabb.jriver.com/interact/index.php?topic=52809.0 Can I include seconds in "import date"?]"
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
 
 
====Regex(...): Regular expression pattern matching and capture====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Regex()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function performs regular expression (RE) pattern matching on its input. It can be used in one of three different modes: a test mode to test for a match, a capture output mode to output the specified captured pattern, and a silent, capture-only mode.  All match captures are placed into special variables referenced as [R1], [R2], ... [R9], which can be used in subsequent expressions.  The contents of the captures [R1] ... [R9] are available until the entire expression completes, or Regex() is run again, whereby they are replaced.  The regular expression implementation used is the [http://msdn.microsoft.com/en-us/library/bb982727.aspx Microsoft 2010 TR1 engine]. (Available since build 16.0.155.)
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Regex(String to test, Regular expression, Mode, Case sensitivity)'''
 
 
 
* '''String to test''': ''One or more library fields, plain text, or a combination of both, which is used as the string evaluated for a match.''
 
* '''Regular expression''': ''This is the regular expression pattern used to perform matches and captures on the '''String to test'''.<br />The regular expression language assigns special meaning to many characters.  A few of these meta-characters, such as forward slash "/", comma "," and parenthesis "(" and ")", are also used by the Media Center expression language.  To force the Media Center expression engine to ignore the meta-characters in regular expressions, surround the entire regular expression with '''/#''' and '''#/'''.  This is Media Center's form of escapement, which tells the expression engine to ignore everything inside, so that the entire, uninterpreted regular expression can be provided to the Regex() regular expression evaluator.  Although '''/#''' and '''#/''' is not necessary when no conflicting characters are in use, and you may manually escape such characters with a forward slash "/", it is best practice to always encase a regular expression in '''/#''' and '''#/'''.''
 
* '''Mode''': ''Sets the mode in which Regex() will run.  Optional, defaults to 0.''
 
** '''0''': ''Runs in test mode, returning 1 or 0, indicating whether the string matched (1) or did not match (0) the pattern.  This mode is useful within an '''if()''' test, so that different true (1) or false (0) actions may be taken.  Output will be a 0 or 1. This mode is the default.''
 
** '''1''' to '''9''': ''Outputs the specified N<sup>th</sup> capture group's contents, where N ranges from 1 to 9.  Currently, only a single capture is output in this mode, but all captures are available in the [R1] ... [R9] capture variables.  This mode is used to easily output a single matching sub-string.''
 
** '''-1''': ''Runs in silent mode, with no output.  This mode is useful as a means to capture portions of the string, and later use those captures in subsequent portions of an expression.''
 
* '''Case sensitivity''': ''Toggles the case-sensitivity of regular expressions.  Optional, defaults to 0, ignoring case.  To use this option, a value or comma-placeholder must also be set for the'' '''Mode''' ''option.''<br />'''Note:''' Case insensitivity does not apply to characters inside a character class [ ]. Use both uppercase and lowercase characters when necessary to match either case (e.g. [aAbB] to match either uppercase or lowercase A or B).
 
** 0: ''Ignore case when matching (e.g. the letters '''E''' and '''e''' are identical).  This is the default.''
 
** 1: ''Consider case when matching (e.g. the letters '''E''' and '''e''' are considered different).''
 
 
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''Example: Modes 1 through 9'''
 
 
 
The examples in this section use one of the modes from 1 through 9, to output the specified capture.
 
 
 
'''<span style="font-family: Consolas, monospace;"><nowiki>
 
Regex([Name], /#(Big.*Man)#/, 1)
 
</nowiki></span>'''
 
 
 
''Matches track names that contain'' '''Big''' ''followed by'' '''Man''''', with anything (including nothing) in between, and outputs the matched tracks.''
 
Sample output:
 
:Big Butter and Egg Man
 
:Big Man
 
:Big Manager
 
:It's a Bigman Thing
 
 
 
&oline;&oline;&oline;&oline;
 
 
 
'''<span style="font-family: Consolas, monospace;"><nowiki>
 
Regex([Artist], /#([(].+)$#/, 1)
 
</nowiki></span>'''
 
 
 
''Matches against the Artist field and returns items that contain an opening (left) parenthesis followed by additional characters until the end of the artist string.  Only the sub-string from any opening parenthesis until the end of the string will be returned, since this is the only captured portion.''
 
 
 
Sample output:
 
:(Brian Eno/U2)
 
:(feat. DJ Cam)
 
:(Otis Day & The Knights)
 
:(w/Emmylou Harris)
 
 
 
&oline;&oline;&oline;&oline;
 
 
 
'''<span style="font-family: Consolas, monospace;"><nowiki>
 
Regex([Name], /#([(][^)]+)$#/, 1)
 
</nowiki></span>'''
 
 
 
''Similar to the previous example, but matches track names that contain a opening (left) parenthesis, but are missing the closing (right) parentheses through the end of the track name.  This might be useful to help detect tagging inconsistencies''
 
 
 
Sample output:
 
:(feat. David Bowie
 
 
 
----
 
'''Examples: Mode 0'''
 
 
 
The examples in this section use mode 0, to test if a string does or does not match the pattern.  The result of the test may be used to drive a conditional statement such as an if() statement.
 
 
 
'''<span style="font-family: Consolas, monospace;"><nowiki>
 
if(Regex([Artist],/#([[:punct:]])#/, 0),[R1] --> [Artist], No Punctuation)
 
</nowiki></span>'''
 
 
 
''Matches against the Artist field looking for any punctuation character.  The results of the Regex() expression will be a 0 (false) or 1 (true) since the mode is set to 0, The true side of the if() test is set to output the first (and only) capture, which is expressed as [R1], and is followed by the string " --> " and then the artist name.  In the false case, the string "No Punctuation" is output.''
 
 
 
Sample output:
 
: " &nbsp;--> Clarence "Frogman" Henry
 
: &      --> Al Cohn & Zoot Sims
 
: . &nbsp;--> Dr. John
 
: / &nbsp;--> Bootsy Collins/Fatboy Slim
 
 
 
&oline;&oline;&oline;&oline;
 
 
 
'''<div style="font-family: Consolas, monospace;"><nowiki>
 
if(Regex([Artist], /#([[:punct:]])#/, 0),
 
</nowiki><br />
 
: '''<nowiki>    Contains Punctuation\replace(replace([R1], ;,Semicolon), \, Backslash),
 
</nowiki><br />
 
: '''<nowiki>    No Punctuation)\replace(replace([Artist], ;, / and/ ), \, //)&DataType=[list]
 
</nowiki></div>'''
 
 
 
''A more complex example, similar to the previous one.  When used inside an expression column, builds an expandable tree with headings Contains Punctuation and No Punctuation that group artists based on whether or not their names contain any punctuation characters.  Because semicolon and backslash are list separator characters for the expression language, for the example expression to work properly, these must be replaced (otherwise the list will not build as desired).  In the list of punctuation, both backslash and semicolon characters have been replaced with their English equivalent words.  In artist names, a semicolon is often used as a separator between the main artist and featured artists, so the expression replaces semicolons within an artist name with the word "and".  Likewise, backslashes have been replaced with forward slashes.''
 
 
 
Sample output:
 
: &darr; Contains Punctuation
 
::  &darr;&nbsp;  $
 
::: &nbsp;Payola$
 
::  &darr;&nbsp;  *
 
::: &nbsp;D*Note
 
::  &rarr; +
 
::  &rarr; :
 
::  &rarr; Backslash
 
::  &darr;&nbsp; Semicolon
 
::: &nbsp;Lita Ford and Ozzy Osbourne
 
::: &nbsp;Seal and Jeff Beck
 
: &rarr; No Punctuation
 
 
 
&oline;&oline;&oline;&oline;
 
 
 
'''<span style="font-family: Consolas, monospace;"><nowiki>
 
if(Regex([Album], /#^([^-]+[^\s])- (.*)$#/, 0), [R1]: [R2], / No Change Necessary)
 
</nowiki></span>'''
 
 
 
''Some album names contain characters that are not legal in Windows, and after pulling properties from the file name, such characters will be translated into a dash "-" character (e.g. "Staring at the Sea: The Singles" becomes "Staring at the Sea- The Singles").  If you'd like to identify such possibly re-named album, an expression such the one above might help.  The expression matches characters from the beginning of the line that do not contain a dash, followed by a non-space character, followed by a dash, space and everything else.  Wrapped in an if() statement, these file names become apparent in an expression column.
 
 
 
----
 
'''Examples: Mode -1'''
 
 
 
The examples in this section use mode -1, which cause Regex() to suppress output.  This mode is only useful with captures, where the captures are utilized in subsequent portions of an expression.
 
 
 
The previous example (which helped to identify album titles that may have been changed after tags were updated from file properties) used mode 0 to guide an if() evaluation.  By using that expression column and selecting only the files whose album name should be changed, the identical Regex() statement can be used to easily fix the album property by changing the mode from 0 to -1:
 
 
 
'''<span style="font-family: Consolas, monospace;"><nowiki>
 
=Regex([Album], /#^([^-]+[^\s])- (.*)$#/, -1)[R1]: [R2]
 
</nowiki></span>'''
 
 
 
''Editing the Album tag and pasting the expression above into the edit field will set the munged album name to use a colon rather than dash.  Note: take care to select the correct files, and ensure the tags were changed as desired.  Use Undo if not.''
 
 
 
''A safety mechanism can be installed into the tag assignment.  By using the same Regex() statement from the last mode 0 example, and setting the false side of the if() statement to [Album], the expression would effectively only change those files whose album names matched the pattern.  Non-matched album names would be assigned to themselves, essentially acting as a no-op.  For completeness, that statement would be:''
 
 
 
'''<span style="font-family: Consolas, monospace;"><nowiki>
 
=if(Regex([Album], /#^([^-]+[^\s])- (.*)$#/, 0), [R1]: [R2], [Album])
 
</nowiki></span>'''
 
 
 
&oline;&oline;&oline;&oline;<br />
 
'''<span style="font-family: Consolas, monospace;"><nowiki>
 
Regex([Name], /#(\d{1,2})\.(\d{1,2}).(\d{4})#/, -1)[R3]//[R1]//[R2]
 
</nowiki></span>'''
 
 
 
''Matches and captures a date formatted as dd.mm.yyyy anywhere within a filename, and rearranges it in a standard format of yyyy/mm/dd.  Since '''Mode''' is set to -1, no output occurs. However, captured match segments are made available for subsequent use.  The three captures, [R1], [R2] and [R3] are arranged in the textual output such that the year, month and day ordering are as desired.
 
 
 
Sample output:
 
: 2011/08/19
 
: 2009/01/22
 
 
 
&oline;&oline;&oline;&oline;
 
 
 
'''<span style="font-family: Consolas, monospace;"><nowiki>
 
Regex([Name], /#^(.+?) \(([^(]+)\)$#/, -1)[R2]: [R1]
 
</nowiki></span>'''
 
 
 
''This example shows how rearranging segments of track titles can help call out naming inconsistencies.  The expression captures parenthetical information at the end of a track, and moves it to the beginning.  In an expression column, inconsistencies become clearer.''
 
 
 
Sample output:
 
: Ext. Version: Blinded by the Light
 
: Extended Version: Peter Gunn
 
: extended version: the saftey dance
 
: feat. Crystal Lake: You Might Need Somebody
 
: Feat. Billy Godfrey: Look Around
 
: feat Amel Larrieux: Gaze
 
 
 
&oline;&oline;&oline;&oline;
 
 
 
'''<span style="font-family: Consolas, monospace;"><nowiki>
 
listbuild(1, \, Regex([Name], /#^(.+?) \(([^(]+)\)$#/, -1)[R2],[R1])&datatype=[list]
 
</nowiki></span>'''
 
 
 
''Wrapping the previous expression in a listbuild() to create an expandable list provides quick grouping for even easier spotting of naming irregularities, especially when combined with Search to reduce the list size.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====RemoveCharacters(...): Removes specified characters from a given field or string====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | <small>RemoveCharacters()</small>
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function will remove specified characters from a given field or string using one of three specified modes. (Available in build 16.0.148 onwards.)
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''RemoveCharacters(String to test,CharactersToTestFor,Mode)'''
 
 
 
* '''String to test''': ''This can be plain text, a library field, or a combination of the two.''
 
* '''Characters to test for''': ''series of characters, or strings of characters, placed all together between two commas, that are to be removed'' (note that this function is <ins>case sensitive</ins>)
 
* '''Mode''': ''There are four available modes, each detailed below. Note that if no mode is specified, the function will default to using mode 0 (remove all instances)
 
''Available Modes:''
 
* 0: Remove all instances
 
* 1: Remove from the beginning only
 
* 2: Remove from the end only
 
* 3: Remove from each end
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''RemoveCharacters(Paper,Ppr,0)'''<br>This will result in "ae" as P, p and r are removed.
 
 
 
'''RemoveCharacters(Paper,Ppr,1)'''<br>This will result in "aper" as "mode 1" has been specified, and the capital P is removed from the start.
 
 
 
'''RemoveCharacters(Paper,Ppr,2)'''<br>This will result in "Pape" as "mode 2" has been specified, and the lower case r is removed from the end.
 
 
 
'''RemoveCharacters(Paper,Ppr,3)'''<br>This will result in "ape" as "mode 3" has been specified, the capital P is removed from the start, and the lower case r is removed from the end.
 
 
 
'''RemoveCharacters([artist],/(/),)'''<br>This will remove any opening or closing brackets from anywhere within the [artist] field. Note how the brackets are 'escaped' as discussed in the [[#Overview|'Overview']] section earlier.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====RemoveLeft(...): Trims characters from the start of a value====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | RemoveLeft()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | The output from this function will remove a specified number of characters from the start of any given value.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''RemoveLeft(Value to remove characters from,Number of characters to remove)'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''removeleft([name],5)'''<br>''This would show the name field, with the first five characters removed. If asked to remove more characters than actually exist, the output will be blank, also, remember that spaces count as characters too.''.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====RemoveRight(...): Trims characters from the end of a value====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | RemoveRight()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | The output from this function will remove a specified number of characters from the end of any given value.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''RemoveRight(Value to remove characters from,Number of characters to remove)'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''removeright([name],5)'''<br>''This would show the name field, with the last five characters removed. If asked to remove more characters than actually exist, the output will be blank, also, remember that spaces count as characters too.''.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====Replace(...): Replace or remove strings from a value.====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Replace()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Quite simply, this function allows to search for a specified string in a specified value, and if found, remove the specified string, or replace it with another.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Replace(Value to check,String to check for,String to replace with)'''
 
* '''Value to check''': ''This can be plain text, a library field, or combination of both.''
 
* '''String to check for''': ''Note that this check is <ins>case-sensitive</ins>''
 
* '''String to replace with''': ''Any instance of the "String to check for" will be replaced by this string. If not specified, any instance of the "String to check for" will be removed.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''replace(My Sample String,S,Replaced )'''<br>''All instances of upper-case "S" will be replaced by the text "Replaced ", (note the trailing space), resulting in'' "My Replaced ample Replaced tring"
 
 
 
<br>'''replace(My Sample String,s,Replaced )'''<br>''The "Value to check" does not contain any lower-case "s", resulting in unchanged output'' "My Sample String"
 
 
 
<br>'''replace(My Sample String,/ Sample,stic)'''<br>''In this example, the space preceding the word Sample is to be included in the "String to check for". Remembering that, as discussed in the [[#Overview|Overview]], spaces that follow a comma are ignored unless escaped, an escaping forward slash is used to force the inclusion of the space in the check. The result here will be'' "Mystic String".
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====Right(...): Retrieves a specified number of characters from the right of a value====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Right()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function retrieves a specified number of characters from the right of any given value.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Right(Value to get characters from,Number of characters to get)'''<br>''"Value to get characters from" can be plain text, a library field, or combination of both. If more characters than exist are requested, all available characters are returned.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''right([filename],3)'''<br>''This will return the last three characters from the filename. If asked to show more characters than actually exist, the expression will return the entire value, also, remember that spaces count as characters too.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
<br><br>
 
 
 
===List Manipulation===
 
The default Media Center library contains many fields that are referred to as "list type" fields. Users are also able to add their own "list type" fields to their libraries. A list type field contains one or more text items seperated by semi-colons. The semi-colons are referred to as the 'delimiter' and when displayed in a view category, text items seperated by semi-colons are displayed in a list of seprately selectable items. The "Keywords" field is a classic example of a list type field, which demonstrates how list type fields allow a single file to be tagged with many different keywords, as opposed to a 'standard' field, such as 'Genre', where a single file can only be tagged with a single genre.  The following functions provide the ability to combine or build custom list type fields using the default semi-colon delimiter, or a specified delimiter, count the number of items contained in a given list, or extract a numbered entry from within a list. Two of the functions listed in this section are used to create "list type" data from two or more existing sources and could reasonably be considered to be functions more suited to those who are very familiar with Media Center and how it gets its job done. If these functions are used to create a new 'calculated data' library field, they will not function as 'list type' fields unless the field is first created as a "User Data" field, with "List Type" specified. After creating the field in this way, it is possible to go back and edit the field, changing it to "calculated data" and entering an expression to be used. The [http://yabb.jriver.com/interact/index.php?topic=54226.msg374211#msg374211 "Eureka moment"] occurred in November 2009.
 
====ListBuild(...): Build a list from a series of values====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | ListBuild()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function provides the ability to create a single list from many different sources and allows a list delimiter to be specified. It has two modes that can be applied and are detailed below. Of these two modes, mode "0" (Combine all values) should be avoided. It has been included for 'function completeness' only, and when used, can produce some very strange results that do not filter as expected. In order for the data generated by this function to be treated as list data, the [[#Specify data types for expression based fields|'datatype']] must be specified as [list].
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''ListBuild(Mode,Delimiter,Items,To,Include)'''<br>
 
'''Mode:''' ''There are two different modes available:
 
* '''0''': ''combine all values. NOTE: <ins>This mode should be avoided as there is no recorded practical use for it, and it's behaviour can be unpredictable.</ins>''
 
* '''1''': ''combine non-empty values''
 
 
 
'''Delimiter''': ''The character used here will be used as a delimiter between each of the specified list items. To be clear, the keywords field uses a semi-colon delimiter by default; if a list is built using keywords and genre, and the specified delimiter is a back slash, it will be used between the keywords and genre fields when joining them, the semi-colons in the keywords field would not be altered. For example, if [keywords] contained "these;are;keywords" and [genre] contained "Rock", and these two were joined using ListBuild with a "\" specified as the delimiter, the resulting data would be "These;are;keywords\Rock". The real beauty and power of this function can be released when expressions are nested into the ListBuild instructions. For example, "listbuild(1,\,replace([keywords],;,\),[genre]" would return the data "These\are\keywords\Rock"''
 
<br>'''Items To Include''': ''This can be any number of specified text entries, expressions, or library fields, seperated by commas''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''listbuild(1,;,[keywords],[genre])&datatype=[list]'''<br>''This will return a semi-colon delimited list containing all keywords and genres. If either keyords or genre is empty, they will be ignored, so, the data returned for a file with no keywords, and a genre of "Rock" would be simply "Rock".''
 
 
 
<br>'''listbuild(1,\,[genre],[album artist (auto)],[album])&datatype=[list]'''<br>''When Media Center encounters a back slash character in a list type field, it 'nests' the data in the list. Think of this in exactly the same way as Windows reads file paths, each back slash is another folder along the file path, and in a Media Center list type view category, each back slash creates a virtual folder, and each semi-colon starts a new list entry, which means that effective browsing trees can be created using this knowledge. In the example shown here, a list of genres would be created, and each genre is able to be expanded to reveal a list of artists, which in turn can be expanded to reveal albums by that particular artist in that genre. So, now that this is getting interesting, there's an issue with this example. If a file has no specified [genre], the value is ignored, and the [album artist (auto)] value is placed on the root of the virtual tree, which means that the completely collapsed list contains a mixture of [genre] and [album artist (auto)]. The next example demonstrates how to clean that up.''
 
 
 
<br>'''listbuild(1,\,if([[#IsEmpty(...): Tests to see if a field is empty|isempty]]([genre]),!No Genre Applied,[genre]),[album artist (auto)],[album])&datatype=[list]'''<br>''Here, the previous example has been improved by nesting an [[#IsEmpty(...): Tests to see if a field is empty|IsEmpty()]] function into the listbuild function. The result is that all files without a specified genre are placed in a group at the top of the virtual tree called "!No Genre Applied", and the rest of the root consists of existing genre values, which is much tidier.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====ListCombine(...): Combines two delimited lists into a single delimited list====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | ListCombine()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Unlike the [[#ListBuild(...): Build a list from a series of values|ListBuild]] function above, which can be used to create a list from any number of varying sources, ListCombine() is used to merge two specified lists into one. In order for the data generated by this function to be treated as list data, the [[#Specify data types for expression based fields|'datatype']] must be specified as [list].
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''ListCombine(First list,Second list,Input Delimiter,Output Delimiter)'''<br>
 
'''First List''' ''and'' '''Second List''' are specified library fields.
 
 
 
'''Input Delimiter''': ''This is the value that will be used to join the two specified lists. The value is optional, and if not specified, the function will default to using a semi-colon.''
 
 
 
'''Output Delimiter''': ''This value is also optional. If specified, the function parses the output list (the result of the two lists, joined by the input delimiter) and replaces each occurrence of the input delimiter with the specified output delimiter.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''listcombine([people],[places])&datatype=[list]'''<br>''The result here would be a single, semi-colon delimited list containing all the values from the [people] and [places] fields.''
 
 
 
* [people] contains ''Family\Mum;Family\Dad;Family\Gran''
 
* [places] contains ''United Kingdom\Scotland\Edinburgh;United Kingdom\Scotland\Edinburgh\Edinburgh Castle''
 
* The output list from the above expression would be: ''Family\Mum;Family\Dad;Family\Gran'''<ins>;</ins>'''United Kingdom\Scotland\Edinburgh;United Kingdom\Scotland\Edinburgh\Edinburgh Castle'' (the specified "listcombine delimiter" shown in bold and underlined)
 
 
 
<br>'''listcombine([people],[places],\)&datatype=[list]'''<br>''Here, the resulting list will be the [people] and [places] lists joined using a back slash. Remember that Media Center interprets back slashes as a folder hierarchy when displaying list type fields in a view category pane.''
 
 
 
* [people] contains ''Family\Mum;Family\Dad;Family\Gran''
 
* [places] contains ''United Kingdom\Scotland\Edinburgh;United Kingdom\Scotland\Edinburgh\Edinburgh Castle''
 
* The output list from the above expression would be: ''Family\Mum;Family\Dad;Family\Gran'''<ins>\</ins>'''United Kingdom\Scotland\Edinburgh;United Kingdom\Scotland\Edinburgh\Edinburgh Castle'' (the specified "listcombine delimiter" shown in bold and underlined)
 
 
 
<br>'''listcombine([people],[places],\,;)&datatype=[list]'''<br>''Finally, a semi-colon output delimiter has been specified, therefore, all back slashes will be replaced by semi-colons, and the resulting list will be a single, flat list containing all the text entries from each field:''
 
 
 
* [people] contains ''Family\Mum;Family\Dad;Family\Gran''
 
* [places] contains ''United Kingdom\Scotland\Edinburgh;United Kingdom\Scotland\Edinburgh\Edinburgh Castle''
 
* The output list from the above expression would be: ''Family;Mum;Family;Dad;Family;Gran'''<ins>;</ins>'''United Kingdom;Scotland;Edinburgh;United Kingdom;Scotland;Edinburgh;Edinburgh Castle'' (the specified "listcombine delimiter" shown in bold and underlined)
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====ListCount(...): Returns the number of items in a delimited list====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | ListCount()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | ListCount is used to return the number of items that exist in any given field, using any given delimiter.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''ListCount([Field to count],Delimiter to use)'''<br>
 
'''Field to count''': ''Typically, this will be a list type field, but this is not compulsory. The data in any field can be parsed using any chosen delimiter''
 
 
 
'''Delimiter to use''': ''This is optional. If not specified, the function will default to using a semi-colon delimiter. Anything can be specified as a delimiter, from a single character to a whole word or words.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''listcount([People])'''<br>
 
''No delimiter has been specified here, therefore the function will default to using a semi-colon. The result here will match the number of people shown in a properly tagged photo. Note that the function is smart, so, if a file has no [People] tag, the function will return zero (0), and if it has [People] data, but no semi-colon, the function will return one (1).''
 
 
 
<br>'''listcount([filename (path)],\)'''<br>
 
''This function can be used to count the directories in a filepath by specifying a back slash as the delimiter.''
 
 
 
<br>'''listcount([keywords],!People)'''<br>
 
''This basic expression can be used as a building block to create a more complex expression to count the number of people tagged in a photo. the full expression can be seen [http://yabb.jriver.com/interact/index.php?topic=43975.msg301390#msg301390 here]. That thread is actually the release thread for the 'new' nesting feature, introduced in 2007, and although 2 pages long, is worth a read as it contains some quite useful information.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====ListItem(...): Returns a specified value from a delimited list====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | ListItem()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function numbers list items starting from zero and returns the value of a specifically numbered item.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''ListItem([Field],Number of item to retrieve,Field delimiter to use)'''
 
  
* '''Field''': ''The function will accept any given field, though is more typically used with list type fields.''
+
Note: Undo is supported, reverting each tag to its value prior to the assignment.
* '''Number of item to retrieve''': ''The number of the item in the list to retrieve. The list items are numbered starting from zero.''
+
Redo is also supported, reapplying the most recent Undo.
* '''Field delimiter to use''': ''This is optional. If not specified, the function will default to using a semi-colon delimiter. Anything can be specified as a delimiter, from a single character to a whole word or words.''
+
</div>
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''listitem([filename],0,\)'''<br>''This function will return a file's drive letter plus colon. Note that the same result could be achieved by using '''[[#Left(...): Retrieves a specified number of characters from the left of a value|left]]([filename],2)''', there is no 'right' or 'wrong' with these things, just personal preference, or 'what works for you'. A good rule of thumb is to use the simplest possible way to get to your goal, as less typing is better, and the more simple the expression, the easier it is to follow.''
 
  
<br>'''listitem([filename],2,\)'''<br>''Here, the result will be the name of the second directory along a file's folder path from the drive root. C:\Folder1\Folder2\ are itemised as 0\1\2\, so rather confusingly, the second directory is actually the third item in the back slash delimited path.''
+
== Expression Language Syntax ==
 +
Now that the basics have been covered, the more rigorous rules of the expression language syntax can be described.
  
<br>'''listitem([filename (path)],math(listcount([filename (path)],\)-1),\)'''<br>''This expression uses the [[#Math(...): Evaluates a given mathematical formula|math()]] and [[#ListCount(...): Returns the number of items in a delimited list|listcount()]] functions to find the "Number of item to retrieve" value. listcount() returns the total number of directories in the path, and the math function subtracts one from this number (because listcount() starts counting at one, but listitem starts counting from zero), this number is then used by the listitem function. The result will be the name of the parent folder of each file. Setting the expression up in this way means that the result will always be reliable regardless of the number of folders in the filepath as the expression will work all of this out for itself.''
+
:* 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.
<div style="text-align:right;">([[#top|Back to top)]]</div>
+
:* Fields designated using [[square bracket notation]] are expanded into the equivalent [[Accessing_and_Storing_Functions#Field|Field()]] function call.
<br><br>
+
:* Nested function calls are evaluated from the innermost function to outermost function, and again, left to right when one function follows another.
===Date & Time Functions===
+
:* A function is evaluated and its returned value contextually replaces the function call in the expression
Media Center provides several functions for date and time conversion, formatting and generationInternally, date and time for date fields is stored as a floating point number, where the integer portion represents the number of days since the Epoch, and the decimal portion represents the fraction of a day.
+
:* 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 <span style="font-family: monospace,monospace; font-size:1em;">/</span> disables the special meaning of the character that follows it.
 +
:* 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.
 +
:* To use a literal parenthesis, comma, or whitespace inside of function argument lists, escape themWhitespace 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.
  
The Windows locale setting will affect the interpretation and formatting of date and time information.
+
=== How Expressions Are Evaluated ===
====ConvertDate(...): Converts a human-readable date to the internal format required for use in date fields====
+
Expressions are evaluated in the context where they are used.
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
For example, an expression column in a file list is evaluated relative to those files in the file list.
|- valign="top"
+
And the general flow is that for each file in the list, the expression is evaluated and produces output.
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | ConvertDate()
+
The expression only has access to the fields available for the file currently being evaluated.
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 |
+
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.
  
Converts human-readable date / time strings into the floating point representation used internally by Media Center to represent date and time.
+
=== Expressions and Locales ===
 +
Media Center will respect the Windows locale setting for output values produced by certain functions,
 +
and within the values of certain fields.
 +
This is important to consider when writing expressions that consume such values.
 +
Under most circumstances, such values cause no harm.
 +
However special care must be taken with functions that require the use of period as the decimal point.
 +
One such function is [[Miscellaneous_Functions#Math|Math()]], which always uses period as the decimal point.
 +
If your locale uses some other character such as comma, these characters will have to be converted into periods before the
 +
critical function is called.
 +
Handling this problem is not difficult. Before passing to [[Miscellaneous_Functions#Math|Math()]] any floating point number,
 +
use [[String_Manipulation_Functions#Replace|Replace()]] first when necessary to convert the locale's decimal character into a period.
 +
Fields that cause problems are any fields that produce floating-point values,
 +
such as any Date type field in raw format (e.g. <span style="font-family: monospace,monospace; font-size:1em;">[date,0]</span>, <span style="font-family: monospace,monospace; font-size:1em;">[last played,0]</span>, <span style="font-family: monospace,monospace; font-size:1em;">[date modified,0]</span>, and <span style="font-family: monospace,monospace; font-size:1em;">[date imported,0]</span>),
 +
or any textual field that contains floating-point values that will be used for various calculations
 +
(e.g. any of the Dynamic Range variants).
 +
Certain functions such as [[Date_and_Time_Functions#Now|Now()]] and [[Date_and_Time_Functions#ConvertTime|ConvertTime()]] also return localized floating-point values.
 +
Consider also that the expression parser uses comma as the argument separator.
 +
Any literal numeric values specified as a function argument must have any embedded commas escaped.
  
|- valign="top"
+
=== A Complex Expression Example ===
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
+
[[File:Expression_Editor.png|right]]
| style="background: #ecfeea; color: black; border: 1px solid black" | '''convertdate(Date string)'''
+
Here is a more complex expression example that illustrates the various rules discussed above regarding expressions:
  
*'''Date string''' ''A human-readable date string to be converted.''
+
<span style="font-family: monospace,monospace; font-size:1em;">
|- valign="top"
+
<div style="margin-left: 20pt">if(  IsEmpty(  [Disc #]  ),</div>
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
+
<div style="margin-left: 40pt">Disc number is empty,</div>
|style="background: #ecfeea; color: black; border: 1px solid black" | '''convertdate(3/6/2012)'''<br>''Converts the date March 6th, 2012 into a floating point number that can be assigned to a date field.''
+
<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>
  
<br>'''formatdate(convertdate(12/2/1985), decade))'''
+
The expression demonstrates that
<br>''Converts the date string December 2nd, 1985 into internal date/time form, and then formats the result as a decades grouping of "1980's".  This might be used for grouping tracks by decades.
+
:* 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
<div style="text-align:right;">([[#top|Back to top)]]</div>
+
:* 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()]]
  
====FormatDate(...): Formats a date value in a specified manner====
+
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>,
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
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>.
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FormatDate()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | FormatDate provides custom formatting of date / time fields through the use of special format specifiers.  Select from the available format specifiers, and arrange them to produce the desired date and time components.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''formatdate(Date value, Format string, Output if date is empty)'''
 
  
*'''Date value''' ''The date to be formatted, in Media Center internal format (i.e. a floating point value).  This field is optional, and will default to [Date,0].  To use any date field, use the raw (unformatted) field specification (e.g. [Date Imported,0]).''
+
== Functions ==
  
*'''Format string''' ''The format specifier string to format the date or time components. Media Center supports Windows style, strftime() style, and Media Center-specific specifiers.  Select from any of the format specifiers in the following table. See also: '''[http://yabb.jriver.com/interact/index.php?topic=71000.msg479314#msg479314]''
+
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.
  
*'''Output if date is empty''' ''If the provided date is empty, anything placed here will be output instead. This could be plain text, such as "No Date", or a library field. This value is optional, and if not given, the expression will default to return nothing if the date is empty.''
+
This section describes all the various functions provided by Media Center's Expression Language.
  
<blockquote>
+
=== Function Arguments ===
{| style="background: #ecfeea;" border="1" cellpadding="1" cellspacing="0"
 
| || colspan="3" align="center" | '''Specifier''' || '''Description'''
 
|-
 
| rowspan="7" width="100" | '''Day'''
 
| align="center" width="65" | d || || Day || Day of the month as digits without leading zeros for single-digit days.
 
|-
 
| align="center" | dd  || %d ||        || Day of the month as digits with leading zeros for single-digit days.
 
|-
 
| align="center" | ddd  || %a ||        || Day of the week, abbreviated to three letters.
 
|-
 
| align="center" | dddd || %A || Dayname || Day of the week.
 
|-
 
| align="center" |      || %w ||        || Day of the week as a decimal number, Sunday as 0 (0-6).
 
|-
 
| align="center" |      || %j ||        || Day of the year (001-366)
 
|-
 
| align="center" |      || %j ||Dayordinal|| Ordinal day of the month (e.g. 1st, 2nd, etc.).
 
|-
 
| rowspan="4" | '''Month'''
 
| align="center" | M    ||    ||        || Month as digits without leading zeros for single-digit months.
 
|-
 
| align="center" | MM  || %m ||        || Month as digits with leading zeros for single-digit months.
 
|-
 
| align="center" | MMM  || %b ||        || Abbreviated month name, three letters (e.g. Apr, Nov).
 
|-
 
| align="center" | MMMM || %B || Month  || Full Month name (e.g. April, November).
 
|-
 
| rowspan="4" | '''Year'''
 
| align="center" | y    ||    ||        || Year represented only by the last digit.
 
|-
 
| align="center" | yy  || %y ||        || Year represented only by the last two digits. A leading zero is added for single-digit years.
 
|-
 
| align="center" | yyyy || %Y || Year    || Year represented by a full four or five digits.
 
|-
 
| align="center" |      ||    || Decade  || Year expressed as a decade (e.g. 1970's, 2010's)
 
|-
 
| rowspan="4" | '''Hour'''
 
| align="center" | h    ||    || Hour    || Hours with no leading zero for single-digit hours; 12-hour clock.
 
|-
 
| align="center" | hh  || %I ||        || Hours with leading zero for single-digit hours; 12-hour clock.
 
|-
 
| align="center" | H    ||    ||        || Hours with no leading zero for single-digit hours; 24-hour clock.
 
|-
 
| align="center" | HH  || %H ||        || Hours with leading zero for single-digit hours; 24-hour clock.
 
|-
 
| rowspan="2" | '''Minute'''
 
| align="center" | m    ||    || Minute  || Minutes with no leading zero for single-digit minutes.
 
|-
 
| align="center" | mm  || %M ||        || Minutes with leading zero for single-digit minutes.
 
|-
 
| rowspan="2" | '''Second'''
 
| align="center" | s    ||    || Second  || Seconds with no leading zero for single-digit seconds.
 
|-
 
| align="center" | ss  || %S ||        || Seconds with leading zero for single-digit seconds.
 
|-
 
| rowspan="2" | '''AM/PM'''
 
| align="center" | t    ||    ||        || One character time marker string, such as A or P.
 
|-
 
| align="center" | tt  || %p ||        || Multi-character time marker string, such as AM or PM.
 
|-
 
| rowspan="5" | '''Combined'''
 
| align="center" |      || %x || Date    || Date expressed in the system's format.
 
|-
 
| align="center" |      || %X || Time    || Time expressed in the system's format.
 
|-
 
| align="center" |      || %c || DateTime|| Date and time expressed in the system's format.
 
|-
 
| align="center" |      ||    || ShortDate|| Age-conditional date formatted as one of "Year", "MMM d", or "MMM d Year".
 
|-
 
| align="center" |      ||    || ShortDateTime || Date in ShortDate format plus Time.
 
|-
 
| rowspan="2" | '''Week Number'''
 
| align="center" |      || %U ||        || Week number with the first Sunday as the first day of week one (00-53).
 
|-
 
| align="center" |      || %W ||        || Week number with the first Monday as the first day of week one (00-53).
 
|-
 
| rowspan="4" | '''Miscellaneous'''
 
| align="center" |      ||    || Elapsed || Time expressed as elapsed time (e.g. 2.5 hours).
 
|-
 
| align="center" |      ||    ||ElapsedAgo|| Time expressed as elapsed time ago (e.g. 2.5 hours ago).
 
|-
 
| align="center" |      ||    || Filename|| Date and time expressed in filename-friendly format, includes seconds to avoid filename collisions (e.g. 20040521-032221).
 
|-
 
| align="center" |      || %% ||        || A percent (%) character.
 
|-
 
|}
 
</blockquote>
 
  
|- valign="top"
+
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:
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''formatdate(year-month)'''<br />''Returns the file's date formatted as Year-Month.  This uses the default [Date,0] field.  Example: 2012-April.''
 
  
<br>'''formatdate([last played,0],yyyy//MM//dd,Not Yet)'''<br>''This will return the last played date as year/month/day without the time, and regardless of the system locale setting. If a file has no last played info, the expression will output "Not&nbsp;Yet" instead.''
+
<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>
  
<br>'''formatdate([date modified,0], month %Y)'''
+
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:
<br>''This will return the month and 4-digit year a file was modified. Example: December 2010.''
+
:<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>
  
<br>'''formatdate([date imported,0],month)&datatype=[month]'''
+
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.
<br>''If you were to use the previous expression to create a view category that contained the months your files were imported, it would list the months alphabetically, with April first and September last. Thankfully, we can specify "data types" for expressions which further fine tune how Media Center displays the results. In this case, a data type of month has been specified, therefore Media Center will list the months in the correct chronological order. Data types were discussed [[#Specify data types for expression based fields|earlier on this page]].
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
====Now(...): Retrieve and display the system date====
+
The arguments themselves are also just expressions, and you can nest multiple functions to achieve complex logic:
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
:<span style="font-family: monospace,monospace; font-size:1em;">if(isequal([artist], [album], 1), Eponymous, [album])</span>
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Now()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Now() will return the raw system date. "raw" data is discussed in the [[#Field|Field]] description, and also in the introduction to the [[#Formatting Functions|"Format"]] functions. As Media Center's raw date data is illegible, this function needs to be used with the "[[#FormatDate(...): Formats a date value in a specified manner|FormatDate()]]" function, which allows the current date, and time, if desired, to be presented in many different styles.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Now()'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''formatdate(now(),date)'''<br>''Returns the current date, without the time, formatted according to the system settings on which the function is running.''
 
  
<br>'''formatdate(now(),dddd dd MMMM yyyy) [[#PadNumber(...): Adds leading zeros to any given number|padnumber]](formatdate(now(),hour),2):[[#PadNumber(...): Adds leading zeros to any given number|padnumber]](formatdate(now(),minute),2)'''<br>
+
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.
''Here, three seperate expressions have been strung together to return a fully formatted current date and time:'' '''''Sunday 26 September 2010 14:04'''''
 
  
<br>'''[=isequal(formatdate([date imported,0],MM//yyyy),formatdate(now(),MM//yyyy)]=1 ~sort=[Date Imported]-d'''<br>
+
:'''''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.
''Media Center comes with a stock smartlist titled "Imported This Month". On the face of it, this could be a handy list of files, but is actually rather misleading. Closer inspection of this stock smartlist reveals that it is not actually listing files "Imported This Month", but instead, listing those files that have been imported in the past 31 days by using the following rule: [Date&nbsp;Imported]=<31d&nbsp;~sort=[Date&nbsp;Imported]-d<br>
 
This would mean that if you were to view that list on the second of March, you could potentially be looking at a list of files imported during three different months. The example in bold above corrects this anomaly by comparing the month/year imported with the current month/year, and only lists the file if the two match.<br>
 
This is also an example of how to use an expression in a search rule, as detailed in "[[#When, Where and How to use expressions|When, Where and How to use expressions]]"
 
  
<br>''<ins>[http://yabb.jriver.com/interact/index.php?topic=56487.0 This topic]</ins> expands on the example above a little by showing how to construct rules that return files that have been played or imported today or yesterday.''
+
=== [[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>
===Other Functions===
+
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>
The functions in this group are varied, and do not readily fit into the other groups of functions.
+
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.
  
<div style="text-align:right;">([[#top|Back to top)]]</div>
+
==== [[Accessing and Storing Functions]] ====
 +
* '''[[Accessing_and_Storing_Functions#Field|Field(&hellip;)]]''': Returns a field's value.
 +
* '''[[Accessing_and_Storing_Functions#FieldQuery|FieldQuery(&hellip;)]]''': Return a list of matches based on a list of fields to search, from a selected scope of files.
 +
* '''[[Accessing_and_Storing_Functions#ItemCount|ItemCount(&hellip;)]]''': Counts the number of files that have the exact same value of the given expression as the file the expression runs in the context of.
 +
* '''[[Accessing_and_Storing_Functions#Load|Load(&hellip;)]]''': Outputs the value of a [[global variable]].
 +
* '''[[Accessing_and_Storing_Functions#Note|Note(&hellip;)]]''': Retrieve note fields.
 +
* '''[[Accessing_and_Storing_Functions#Save|Save(&hellip;)]]''': Saves a value to a [[global variable]].
 +
* '''[[Accessing_and_Storing_Functions#SaveAdd|SaveAdd(&hellip;)]]''': Adds to a [[global variable]].
 +
* '''[[Accessing_and_Storing_Functions#SetField|SetField(&hellip;)]]''': Sets a field's value.
 +
* '''[[Accessing_and_Storing_Functions#Tag|Tag(&hellip;)]]''': Returns a file's physical tag.
  
====Counter(...): Counts upwards in specified increments====
+
==== [[Conditional Functions]] ====
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
* '''[[Conditional Functions#And|And(&hellip;)]]''': Tests a set of values and returns 1 if all are true.
|- valign="top"
+
* '''[[Conditional Functions#FirstNotEmpty|FirstNotEmpty(&hellip;)]]''': Returns the first non-empty argument.
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Counter()
+
* '''[[Conditional Functions#If|If(&hellip;)]]''': Conditional ifelse evaluator.
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function can be used to number objects sequentially, from a specified starting point, in specified increments. The counter resets itself to zero after five seconds of inactivity.<br>Counter() can exhibit a touch of wierdness when used in certain situations, which will be covered in the examples, that demonstrate why this one is not really a 'fits all' function.
+
* '''[[Conditional Functions#IfCase|IfCase(&hellip;)]]''': Functions as a switch or select case statement.
|- valign="top"
+
* '''[[Conditional Functions#IfElse|IfElse(&hellip;)]]''': Conditional if-elseif evaluator.
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
+
* '''[[Conditional Functions#Not|Not(&hellip;)]]''': Negates the results of funtions.
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Counter(Number to start counting from,Increments to count up in)'''
+
* '''[[Conditional Functions#Or|Or(&hellip;)]]''': Tests a set of values and returns 1 if any are true.
  
* '''Number to start counting from''': ''This is optional. If not specified, the counter will start from one. If specified, the start value is inclusive, meaning that if a start value of five is specified, the first value the function returns will be five.''
+
==== [[Date and Time Functions]] ====
* '''Increments to count up in''': ''This optional. If not specified, the counter will count up in increments of 1''
+
* '''[[Date and Time Functions#CompareDates|CompareDates(&hellip;)]]''': Compares two dates, returning a formatted elapsed period between them
|- valign="top"
+
* '''[[Date and Time Functions#ConvertDate|ConvertDate(&hellip;)]]''': Converts a human-readable date to the internal format required for use in date fields
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
+
* '''[[Date and Time Functions#DateInRange|DateInRange(&hellip;)]]''': Compares a date with a range of dates
|style="background: #ecfeea; color: black; border: 1px solid black" | '''counter()'''<br>This shows the function in its simplest form. The counter will start at one and count upwards in increments of 1.
+
* '''[[Date and Time Functions#FormatDate|FormatDate(&hellip;)]]''': Formats a date value in a specified manner
 +
* '''[[Date and Time Functions#Now|Now(&hellip;)]]''': Retrieve and display the system date
 +
* '''[[Date and Time Functions#PlaylistTime|PlaylistTime(&hellip;)]]''': Returns the time of a track in the current playlist (a sum of all previous durations)
  
<br>'''[[#PadNumber(...): Adds leading zeros to any given number|padnumber]](counter(370,2),4)'''<br>This expression shows a combined use of functions. Counter() will count up, in two's, starting from 370, and the padnumber function will pad the results to four figures, giving output values of 0370, 0372, 0374, etc. etc..
+
==== [[File Path and Identifier Functions]] ====
 +
* '''[[File Path and Identifier Functions#DBLocation|DBLocation(&hellip;)]]''': Identifies a file's databases
 +
* '''[[File Path and Identifier Functions#Enviro|Enviro(&hellip;)]]''': Returns the full path to a host system variable
 +
* '''[[File Path and Identifier Functions#FileDBLocation|FileDBLocation(&hellip;)]]''': Identifies a file's databases
 +
* '''[[File Path and Identifier Functions#FileFolder|FileFolder(&hellip;)]]''': Returns the name of a file's parent
 +
* '''[[File Path and Identifier Functions#FileKey|FileKey(&hellip;)]]''': Returns a file's unique internal identifier
 +
* '''[[Miscellaneous Functions#FileLookup()|FileLookup()]]''': Looks up a file based on its filename
 +
* '''[[File Path and Identifier Functions#FileName|FileName(&hellip;)]]''': Returns a file's name component
 +
* '''[[File Path and Identifier Functions#FilePath|FilePath(&hellip;)]]''': Returns a file's path component
 +
* '''[[File Path and Identifier Functions#FileVolume|FileVolume(&hellip;)]]''': Returns a file's volume name component
  
<br>'''Weirdness'''<br>Counter() works really really well, and really really efficiently when used to sequentially number static data fields. It is not designed to be used in a dynamically changing expression column in a file list. To demonstrate this, right click on a list column header and choose the option to "Add expression column". Use the first, simple expression above, and press OK. The column is presented and all the items in the list are now numbered in this column, but, see what happens when you run the cursor up and down the list? The counter function just keeps on going and going. Right click on the expression column header, and it will appear at the top of the selectable columns list with a tick beside it, click on it to remove the column. This same anomally appears when counter() is used in the "Rename, Move, & Copy Files" tool. There may be a possible solution to this effect as seen in the renaming tool by using the CustomData(#) function, but only if the count is to start from 1.<br>Some interesting reading regarding the use of Counter() can be found in answer to "[http://yabb.jriver.com/interact/index.php?topic=48659.0 how to fill the NAME field with incrementing numbers?]" and "[http://yabb.jriver.com/interact/index.php?topic=50622.0 Prepending a consecutive number to titles as I copy them from MC13 to mp3 player]".
+
==== [[Formatting Functions]] ====
|}
+
* '''[[Formatting Functions#Decimal|Decimal(&hellip;)]]''': Standardises the decimal point to be a dot rather than a comma
<div style="text-align:right;">([[#top|Back to top)]]</div>
+
* '''[[Formatting Functions#Delimit|Delimit(&hellip;)]]''': Outputs a value with head/tail strings when value is non-empty
 +
* '''[[Formatting Functions#FormatBoolean|FormatBoolean(&hellip;)]]''': Formats a boolean (true / false) value in a specified manner
 +
* '''[[Formatting Functions#FormatDuration|FormatDuration(&hellip;)]]''': Presents a duration of seconds in a reader friendly format
 +
* '''[[Formatting Functions#FormatFileSize|FormatFileSize(&hellip;)]]''': Presents a number of bytes in a reader friendly format
 +
* '''[[Formatting Functions#FormatNumber|FormatNumber(&hellip;)]]''': Formats and rounds a number to a specified number of decimal places
 +
* '''[[Formatting Functions#FormatRange|FormatRange(&hellip;)]]''': Formats a value as a range
 +
* '''[[Formatting Functions#Orientation|Orientation(&hellip;)]]''': Outputs the orientation of an image
 +
* '''[[Formatting Functions#PadNumber|PadNumber(&hellip;)]]''': Adds leading zeros to any given number
 +
* '''[[Formatting Functions#RatingStars|RatingStars(&hellip;)]]''': Outputs the value of Rating as a number of star characters
 +
* '''[[Formatting Functions#RatingStars10|RatingStars10(&hellip;)]]''': Outputs the value of a 10 star rating field as a number of star characters
 +
* '''[[Formatting Functions#Watched|Watched(&hellip;)]]''': Outputs a formatted video bookmark
  
====CustomData(...): Sequence numbering when renaming files====
+
==== [[Grouping Functions]] ====
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
* '''[[Grouping Functions#GroupCount|GroupCount(&hellip;)]]''': Counts the members of a specified group (in a category or field).
|- valign="top"
+
* '''[[Grouping Functions#GroupCountQuery|GroupCountQuery(&hellip;)]]''': Globally counts the number of items in a specified group.
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | CustomData()
+
* '''[[Grouping Functions#GroupSummary|GroupSummary(&hellip;)]]''': Smartly summarizes the members of a specified group (mode, mean, min, max, etc as is most logical for that grouping).
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | The official description for this function goes as follows: ''"Returns custom data stored in a file array (used primarily for internal uses)."'' There is no recorded practical use for this function, with the exception of using it with a hash symbol in the library tool called "Rename, Move, & Copy Files". When used in the directory or filename rules of this tool, this function will number the files in the list from first to last, starting at number one. As long as any desired numbering is to begin at one, this function is a reasonable alternative to combat the wierdness demonstrated by the [[#Counter(...): Counts upwards in specified increments|Counter()]] function, and could be particularly useful when renaming image files. If the numbering is required to start counting from anywhere other than one, then [[#Counter(...): Counts upwards in specified increments|Counter()]] will need to be used, taking the wierdness and its work arounds into account.
+
* '''[[Grouping Functions#GroupSummaryQuery|GroupSummaryQuery(&hellip;)]]''': Get a summary for the current group of files based on another matching field.
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''CustomData(#)'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''[[#PadNumber(...): Adds leading zeros to any given number|padnumber]](customdata(#),4)_Christmas Party 2007'''<br>''It's important to remember that this function will only work when used as part of the renaming rule for either filename or directory (or both) within the "Rename, Move, & Copy Files" tool. In this example, imagine 324 photos from the Christmas party of 2007 were selected for renaming, and this expression was entered into the filename field. The resulting filenames would be 0001_Christmas Party 2007.jpg through to 0324_Christmas Party 2007.jpg. Note how the "[[#PadNumber(...): Adds leading zeros to any given number|padnumber()]]" function has been used to add the leading zeros.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
====FileName(...): Returns the name from a specified file name====
+
==== [[List Manipulation Functions]] ====
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
* '''[[List Manipulation Functions#ListBuild|ListBuild(&hellip;)]]''': Constructs a list from a series of items
|- valign="top"
+
* '''[[List Manipulation Functions#ListClean|ListClean(&hellip;)]]''': Various list operations
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FileName()
+
* '''[[List Manipulation Functions#ListCombine|ListCombine(&hellip;)]]''': Combines two delimited lists into a single delimited list
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function returns the file name for the files in a list, or for the specified file. A second parameter set to 0 will cause the suffix to be suppressed from the file name.  The library field [Filename (Name)] already contains the value that would be returned by FileName(); it generally should be used rather than this function.
+
* '''[[List Manipulation Functions#ListContains|ListContains(&hellip;)]]''': Checks for a value being in a list
|- valign="top"
+
* '''[[List Manipulation Functions#ListCount|ListCount(&hellip;)]]''': Returns the number of items in a list
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
+
* '''[[List Manipulation Functions#ListEqual|ListEqual(&hellip;)]]''': Checks for equality between two lists
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FileName(Filename to check, Suppress suffix)'''
+
* '''[[List Manipulation Functions#ListFilter|ListFilter(&hellip;)]]''': Filter any list, returning only values within a given range
 +
* '''[[List Manipulation Functions#ListFind|ListFind(&hellip;)]]''': Search a list for a value and return that value, or its index # in the list
 +
* '''[[List Manipulation Functions#ListFormat|ListFormat(&hellip;)]]''': Outputs a given list in a reader friendly format.
 +
* '''[[List Manipulation Functions#ListGrep|ListGrep(&hellip;)]]''': Returns list items containing specified text
 +
* '''[[List Manipulation Functions#ListItem|ListItem(&hellip;)]]''': Returns an item from a location in a list
 +
* '''[[List Manipulation Functions#ListLimit|ListLimit(&hellip;)]]''': Limits the length of a list
 +
* '''[[List Manipulation Functions#ListMath|ListMath(&hellip;)]]''': Perform one of 4 specific math functions on a list containing numbers
 +
* '''[[List Manipulation Functions#ListMix|ListMix(&hellip;)]]''': Combine corresponding values from multiple lists into a new list, using a template to process each item
 +
* '''[[List Manipulation Functions#ListRemove|ListRemove(&hellip;)]]''': Removes a string from a list
 +
* '''[[List Manipulation Functions#ListShuffle|ListShuffle(&hellip;)]]''': Shuffles a list
 +
* '''[[List Manipulation Functions#ListSort|ListSort(&hellip;)]]''': Sort a list of values
  
* Filename to check ''This is optional. If not specified, the function defaults to the current file.''
+
==== [[Miscellaneous Functions]] ====
* Suppress suffix ''This is optional. If set to 0, the file name's suffix will be suppressed from output.''
+
* '''[[Miscellaneous Functions#AlbumArtist|AlbumArtist(&hellip;)]]''': Returns a file's calculated album artist
|- valign="top"
+
* '''[[Miscellaneous Functions#AlbumKey|AlbumKey(&hellip;)]]''': Returns a unique album key for a file
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
+
* '''[[Miscellaneous Functions#AlbumType|AlbumType(&hellip;)]]''': Returns the album type for a file
|style="background: #ecfeea; color: black; border: 1px solid black" | '''filename(C:\Music\File.mp3)'''<br>''The result here would be... "File.mp3"''
+
* '''[[Miscellaneous Functions#AudioAnalysisState|AudioAnalysisState(&hellip;)]]''': Returns the state of audio analysis for a file
 +
* '''[[Miscellaneous Functions#Char|Char(&hellip;)]]''': Returns a character from the numeric code of that character
 +
* '''[[Miscellaneous Functions#CustomData|CustomData(&hellip;)]]''': Returns internal data to the expression language
 +
* '''[[Miscellaneous Functions#FileExtension|FileExtension(&hellip;)]]''': Returns the extension of the referenced file
 +
* '''[[Miscellaneous Functions#FilePlaylists()|FilePlaylists(&hellip;)]]''': Returns a list of playlists a file belongs to (Can also be used to search)
 +
* '''[[Miscellaneous Functions#Literal()|Literal(&hellip;)]]''': Returns a string as given without any formatting or processing
 +
* '''[[Miscellaneous Functions#Repeat|Repeat(&hellip;)]]''': Returns any given string repeated the specified number of times
 +
* '''[[Miscellaneous Functions#Row|Row(&hellip;)]]''': Returns the row number of a list entry
 +
* '''[[Miscellaneous Functions#Size|Size(&hellip;)]]''': Returns a file's size in a format specific to the media type
 +
* '''[[Miscellaneous Functions#Translate|Translate(&hellip;)]]''': Converts an English string found in the program to the current language selected in the language menu
 +
* '''[[Miscellaneous Functions#TreeNode|TreeNode(&hellip;)]]''': Returns the selected tree path
 +
* '''[[Miscellaneous Functions#TVInfo|TVInfo(&hellip;)]]''': Miscellaneous television and other pre-formatted information
  
<br />'''filename(C:\Music\File 2.wav, 0)'''<br>''The result here would be... "File 2"''
+
==== [[Number Functions]] ====
 +
* '''[[Number Functions#Avg|Avg(&hellip;)]]''': Returns the average from a set of numbers
 +
* '''[[Number Functions#Counter|Counter(&hellip;)]]''': Counts upwards in specified increments
 +
* '''[[Number Functions#Math|Math(&hellip;)]]''': Evaluates a given mathematical formula
 +
* '''[[Number Functions#Max|Max(&hellip;)]]''': Returns the largest value from a set of numbers
 +
* '''[[Number Functions#Min|Min(&hellip;)]]''': Returns the smallest value from a set of numbers
 +
* '''[[Number Functions#Number|Number(&hellip;)]]''': Returns the first number , including decimals, from a given string
 +
* '''[[Number Functions#Rand|Rand(&hellip;)]]''': Returns a random number anywhere between two given numbers
 +
* '''[[Number Functions#Range|Range(&hellip;)]]''': Creates a semi-colon delimited list of numbers in a field
 +
* '''[[Number Functions#Roman|Roman(&hellip;)]]''': Converts any given number to, or from, roman numerals
 +
* '''[[Number Functions#StackCount|StackCount(&hellip;)]]''': Returns the number of files in a stack
 +
* '''[[Number Functions#Sum|Sum(&hellip;)]]''': Returns the sum of a set of numbers
 +
* '''[[Number Functions#TrackNumber|TrackNumber(&hellip;)]]''': Returns a file's track # value
  
<br>'''filename()'''<br>''Returns the file name for each file in the list. The [filename (Name)] field returns the same information.
+
==== [[String Manipulation Functions]] ====
|}
+
* '''[[String Manipulation Functions#Clean|Clean(&hellip;)]]''': Clean a string to be used for various operations
<div style="text-align:right;">([[#top|Back to top)]]</div>
+
* '''[[String Manipulation Functions#Extract|Extract(&hellip;)]]''': Returns a portion of a string bounded by another substring
 +
* '''[[String Manipulation Functions#Find|Find(&hellip;)]]''': Finds a string or character in another string, returning its zero-based position in that string
 +
* '''[[String Manipulation Functions#FixCase|FixCase(&hellip;)]]''': Changes the case of a given string
 +
* '''[[String Manipulation Functions#FixSpacing|FixSpacing(&hellip;)]]''': Intelligently splits adjacent camel-cased words
 +
* '''[[String Manipulation Functions#Hexify|Hexify(&hellip;)]]''': Hexifies a string to make it suitable for web usage
 +
* '''[[String Manipulation Functions#Left|Left(&hellip;)]]''': Retrieves a specified number of characters from the left of a string
 +
* '''[[String Manipulation Functions#Length|Length(&hellip;)]]''': Returns the number of characters in a string
 +
* '''[[String Manipulation Functions#Letter|Letter(&hellip;)]]''': Returns the starting letter or letters of a given string
 +
* '''[[String Manipulation Functions#Mid|Mid(&hellip;)]]''': Retrieves specified characters from a string
 +
* '''[[String Manipulation Functions#MoveArticles|MoveArticles(&hellip;)]]''': Takes "The Beatles" and reverses it to "Beatles, The"
 +
* '''[[String Manipulation Functions#NoArticles|NoArticles(&hellip;)]]''': Takes "The Beatles" and returns "Beatles"
 +
* '''[[String Manipulation Functions#PadLeft|PadLeft(&hellip;)]]''': Pad any string with any character, to the left
 +
* '''[[String Manipulation Functions#PadRight|PadRight(&hellip;)]]''': Pad any string with any character, to the right
 +
* '''[[String Manipulation Functions#Regex|Regex(&hellip;)]]''': Regular expression pattern matching and capture
 +
* '''[[String Manipulation Functions#RemoveCharacters|RemoveCharacters(&hellip;)]]''': Removes a list of characters from a string
 +
* '''[[String Manipulation Functions#RemoveLeft|RemoveLeft(&hellip;)]]''': Trims characters from the beginning of a string
 +
* '''[[String Manipulation Functions#RemoveRight|RemoveRight(&hellip;)]]''': Trims characters from the end of a string
 +
* '''[[String Manipulation Functions#Replace|Replace(&hellip;)]]''': Replace or remove a string segment
 +
* '''[[String Manipulation Functions#Right|Right(&hellip;)]]''': Retrieves a specified number of characters from the right of a string
 +
* '''[[String Manipulation Functions#Swap|Swap(&hellip;)]]''': Takes Firstname Lastname and swaps to Lastname, Firstname
 +
* '''[[String Manipulation Functions#Trim|Trim(&hellip;)]]''': Removes leading and trailing non-printable characters and new lines from a string
 +
* '''[[String Manipulation Functions#TrimLines|TrimLines(&hellip;)]]''': Removes leading and trailing non-printable characters and new lines from a string
 +
* '''[[String Manipulation Functions#UnMoveArticles|UnMoveArticles(&hellip;)]]''': Takes "Beatles, The" and reverses it to restore the normal word order, "The Beatles"
 +
* '''[[String Manipulation Functions#Unswap|Unswap(&hellip;)]]''': Takes Lastname, Firstname and reverses it to Firstname Lastname
 +
* '''[[String Manipulation Functions#Urlify|Urlify(&hellip;)]]''': Takes a string and applies html formatting for browser consumption
  
====FileFolder(...): Returns the name of a parent sub-folder from a specified file path ====
+
==== [[Test and Comparison Functions]] ====
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
* '''[[Test and Comparison Functions#Compare|Compare(&hellip;)]]''': Compares two numbers
|- valign="top"
+
* '''[[Test and Comparison Functions#IsDigit|IsDigit(&hellip;)]]''': Determines whether or not a given value is digits
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FileFolder()
+
* '''[[Test and Comparison Functions#IsDriveMissing|IsDriveMissing(&hellip;)]]''': Checks if a drive is missing
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function returns a parent sub-folder name from a file path.  A value of Unassigned will be returned when the specified level exceeds the root of the path.
+
* '''[[Test and Comparison Functions#IsEmpty|IsEmpty(&hellip;)]]''': Tests a value for emptiness
|- valign="top"
+
* '''[[Test and Comparison Functions#IsEqual|IsEqual(&hellip;)]]''': Compares two values in one of seventeen specified modes
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
+
* '''[[Test and Comparison Functions#IsInPlayingNow|IsInPlayingNow(&hellip;)]]''': Tests to see if a file is in the Playing Now playlist
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FileFolder(Filepath, Level)'''
+
* '''[[Test and Comparison Functions#IsLowerCase|IsLowerCase(&hellip;)]]''': Tests to see if a value is lower case
 +
* '''[[Test and Comparison Functions#IsMissing|IsMissing(&hellip;)]]''': Tests to see if a file exists on the system
 +
* '''[[Test and Comparison Functions#IsOverridden|IsOveridden(&hellip;)]]''': Tests if an expression is overridden by a value
 +
* '''[[Test and Comparison Functions#IsPlaying|IsPlaying(&hellip;)]]''': Tests to see if a file is in currently being played
 +
* '''[[Test and Comparison Functions#IsRange|IsRange(&hellip;)]]''': Tests a value for inclusion within a given range
 +
* '''[[Test and Comparison Functions#IsRemovable|IsRemovable(&hellip;)]]''': Tests to see if a file is stored on removable media
 +
* '''[[Test and Comparison Functions#IsUpperCase|IsUpperCase(&hellip;)]]''': Tests to see if a value is upper case
 +
* '''[[Test and Comparison Functions#SearchTags|SearchTags(&hellip;)]]''': Finds all fields that contain a value
  
* Filepath ''This is optional. If not specified, the function defaults to the path of the current file.  Otherwise, the specified path will be used.''
+
== Data Types ==
* Level ''This is optional.  Specifies the parent sub-folder name to return, working the path from right-to-left (i.e. bottom of the folder tree upwards to the top).  A value of 0 (the default) specifies a file's immediate parent, 1 its grandparent, etc., up to the root of the path.''
+
It was mentioned already that the Media Center expression language is primarily a textual language - it consumes and produces text.
|- valign="top"
+
Nonetheless, certain areas of Media Center are influenced by the type of data used or presented,
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
+
and sometimes it is useful or necessary to coerce expression output into one data type or another.
|style="background: #ecfeea; color: black; border: 1px solid black" | '''filefolder()<br>filefolder([Filename,0], 0)'''<br>''Returns the name of the file's parent folder.''
+
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.
  
<br />'''filefolder(c:\some\path\to\a\file.ape, 2)<br />filefolder(c:\some\path\to\a\, 2)'''<br />''Returns the great grandparent sub-folder name "path".''  Notice above that the file name is not required in the path.  FileFolder() works by looking from the end of the file path until it finds a backslash (\).
+
Data types are forced by appending to an expression the string:
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
====Load(...): Outputs the value of a global variable====
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[<i>type</i>]</span></div>
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Load()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Loads and outputs the value of the specified global variable that has been previously stored with the [[#Save(...): Saves a value to a global variable|Save()]] function.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Load(Variable)'''
 
  
* Variable ''The global variable to load and output.''
+
where <i><span style="font-family: monospace,monospace; font-size:1em;">type</span></i> is one of the following values:
  
|- valign="top"
+
<div style="margin-left: 20pt;"><table style="border-spacing:0px; border-collapse:collapse">
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
+
<tr><td style="text-align:left; padding-right:20pt"><b>list</b></td><td>A list of strings, separated by semicolons</td></tr>
|style="background: #ecfeea; color: black; border: 1px solid black" | '''load(var1)'''<br />
+
<tr><td style="text-align:left; padding-right:20pt"><b>string</b></td><td>Sorts as strings (with smart number handling)</td></tr>
''Loads and outputs the previous stored value of the global variable "var1". If "var1" has not been previously stored, the output will be empty.''
+
<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>
  
<br />'''save(math(1 + 2), sum)load(sum)'''
+
=== Calculated Fields and Search ===
<br />''Saves the output of the math() function into "sum", and then loads and outputs the value of "sum", which is 3.''
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
====Math(...): Evaluates a given mathematical formula====
+
Media Center's [[Search Language]] supports some simple numeric [[Search Language#Comparison_Operators|comparison operators]].
{| style="width: 100%; border: 1px solid black" align="top"  cellpadding="3"
+
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.
|- valign="top"
+
In order to use the numeric comparison operators, a calculated expression field can be cast into one of the numeric types.
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Math()
+
In your numeric calculated fields, to allow the use Search's numeric comparison operators, add either of the casts:
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | The Math() function provides the ability to perform mathematical calculations. In addition to the standard arithmetic operators, it also supports various numerical, trigonometric, and comparative functions.  Simple variables are supported, as are multiple statements.
 
  
<blockquote>
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[integer]</span></div>
{| style="background: #ecfeea;" border="1" cellpadding="1" cellspacing="0"
 
| rowspan="6" width="100" valign="top" | '''Arithmetic Operators'''
 
| align="center" width="65" | + || Addition
 
|-
 
| align="center" | - || Subtraction
 
|-
 
| align="center" | * || Multiplication
 
|-
 
| align="center" | / || Division
 
|-
 
| align="center" | ^ || Power
 
|-
 
| align="center" | % || Modulo
 
|-
 
| rowspan="3" | '''Boolean Operators'''
 
| align="center" | ! || NOT
 
|-
 
| align="center" | & || AND
 
|-
 
| align="center" | <nowiki>|</nowiki> || OR
 
|-
 
| rowspan="1" | '''Grouping Operators'''
 
| align="center" | ( ) || Precedence grouping
 
|-
 
| rowspan="4" | '''Comparison Operators'''
 
| align="center" | } || Absolute value maximum (i.e. x or y that is maximum distance from 0).
 
|-
 
| align="center" | { || Absolute value minimum (i.e. x or y that is minimum distance from 0).
 
|-
 
| align="center" |  > || Distance between x and y, positive when x greater than y, negative otherwise.
 
|-
 
| align="center" | < || Distance between x and y, positive when x less than y, negative otherwise.
 
|-
 
| rowspan="7" | '''Functions'''
 
| align="center" | abs(x) || Returns the absolute value of x.
 
|-
 
| align="center" | sign(x) || Returns the sign of x (1 when x >= 0, -1 when x < 0).
 
|-
 
| align="center" | log(x) || Returns the natural logarithm (base e) of x.
 
|-
 
| align="center" | log10(x) || Returns the common logarithm (base 10) of x.
 
|-
 
| align="center" | pow(x,y) || Returns x raised to the y-th power.
 
|-
 
| align="center" | rand(x) || Returns a random value ranging between 0 to x.
 
|-
 
| align="center" | randn(x) || Returns a random value ranging between -x and x.
 
|-
 
| rowspan="5" | '''Comparison Functions'''
 
| align="center" | min(x,y) || Returns the minimum value of x and y.
 
|-
 
| align="center" | max(x,y) || Returns the maximum value of x and y.
 
|-
 
| align="center" | equal(x,y) || Returns 1 when x = y, 0 otherwise.
 
|-
 
| align="center" | below(x,y) || Returns 1 when x < y, 0 otherwise.
 
|-
 
| align="center" | above(x,y) || Returns 1 when x > y, 0 otherwise.
 
|-
 
| rowspan="6" | '''Trigonometric Functions'''
 
| align="center" | atan(x) || Returns the arctangent of x.
 
|-
 
| align="center" | cos(x) || Returns the cosine of x.
 
|-
 
| align="center" | sin(x) || Returns the sine of x.
 
|-
 
| align="center" | tan(x) || Returns the tangent of x.
 
|-
 
| align="center" | abscos(x) || Returns the absolute value of cosine(x).
 
|-
 
| align="center" | abssin(x) || Returns the absolute value of sin(x).
 
|}
 
</blockquote>
 
  
<br />
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[number]</span></div>
The order or precedence of the operators is summarized as follows, from top to bottom:
 
{| style="background: #ecfeea; color: black; border: none" cellpadding="0" cellspacing="0"
 
| align="center" width="100" | <tt>(&nbsp;&nbsp;)</tt>
 
|-
 
| align="center" | <tt>!</tt>
 
|-
 
| align="center" | <tt>^</tt>
 
|-
 
| align="center" | <tt>*&nbsp;&nbsp;/</tt> || Left to right
 
|-
 
| align="center" | <tt>+&nbsp;&nbsp;-</tt> || Left to right
 
|-
 
| align="center" | <tt><nowiki>|</nowiki>&nbsp;&nbsp;&</tt> || Left to right
 
|}
 
  
Variables may be assigned and used by specifying a simple string of letters. Examples: <tt>math(val=2)</tt> or <tt>math(x=pow(2,3))</tt>
+
to the end of the field's calculated expression.
  
Multiple equations may be specified, each separated by a semicolon. Expressions are evaluated left to right.  The final value of the Math() function will be the result of the right-most equation.  Example: <tt>math(x=4; pow(2^x))</tt>
+
=== 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:
  
<br />
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[list]</span></div>
'''Note''': Fields used inside of Math() are expanded directly.  Those that have no value (eg. empty fields) may produce incomplete Math() statements.  For example, if the field [Number Plays] is empty, an expression such as <tt>math([Number Plays] + 2)</tt> would be seen by Math() as " + 2".  This incomplete expression would by an error.  See <ins>[http://yabb.jriver.com/interact/index.php?topic=58110.0 this topic]</ins> for additional explanations and workarounds.
 
  
<br />
+
to the end of an expression to force an expression's output to be considered as a List type.
'''Please also note''': The Math() function uses dot (.) as the decimal point, so Math(1,5+1,5) will not work but Math(1.5+1.5) will. If you run MC on a system that uses comma (,) as the decimal point, all date related fields - [Date,0], [Last Played,0], [Date Modified,0], [Date Imported,0] etc. - with time information will in their raw format use comma as the decimal point. This is also the case with the Now() function. In these cases you must replace the commas with dots for the Math() function to work, like this: Math(Replace(Now(),/,,.) - Replace([Last Played,0],/,,.)). The escape character / must be used to have the commas recognised as commas.
+
Conversely, a List type may be forced into a String type by adding the cast:
  
|- valign="top"
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[string]</span></div>
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Math(Expression to evaluate)'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''math(10 + 4)'''<br>''Returns 14.''
 
  
<br />'''math(10 + 2 * 25)'''<br />
+
to the end of an expression.
''Returns 60, demonstrating that multiplication has higher precedence than addition.''
+
</div>
  
<br />'''math((10 + 2) * 25)'''<br />
+
=== Sort Order ===
''Returns 300, demonstrating that parenthesis grouping has higher precedence than multiplication.''
+
<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.
  
<br>'''listitem([filename (path)], math(listcount([filename (path)], \) - 1), \)'''<br>''
+
==== Sorting by Month ====
Evaluates the [[#ListCount(...): Returns the number of items in a delimited list|ListCount()]] function to determine the number of path components in the field [filename (path)], and uses Math() to subtract one. The result is then used in the [[#ListItem(...): Returns a specified value from a delimited list|ListItem()]] function which yields the parent folder name of the specified file.''
+
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="text-align:right;">([[#top|Back to top)]]</div>
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[month]</span></div>
  
====Note(...): Retrieve information from a note====
+
to the end of an expression to force an expression's output to be sorted by numeric month values.
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Note()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 |  Since build 14.0.111, [http://yabb.jriver.com/interact/index.php?topic=54548.0 Media Center has shipped with a "Notes" feature.] One of the many uses available via notes is the ability to store contact information, and that information can be labelled. Labels are typical contact information labels such as "Home phone", "Work phone", "Email" etc. etc.. This function can retrieve and display the contents of specified labels from a note.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Note(Field Label,Field Type,Occurrance)'''
 
  
* '''Field Label''': ''There are too many labels to list here. To see the available labels, select some text in a note and right click that selected text, then hover the cursor over "Set Field" to see the list of available labels.''
+
==== Sorting by Path ====
* '''Field Type''': ''If the specified label was, for example, "Phone", then the "Type" could be "Home" or "Business" or any of the other available "Phone" types. This value is optional, and if not specified, the function will default to the first type encountered.''
 
* '''Occurrance''': ''If a note contained two home phone numbers, they would be "occurrance 0" and "occurrance 1". If "occurrance 1" was required, the function requires this to be specified. This value is optional, and if not specified, the function will default to using zero.''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''note(phone)'''<br>'''note(phone,home)'''<br>'''note(phone,home,1)'''<br>''Here are three sample notes expressions. In the image below, they have been used to create expression list columns, with each expression used shown in the column header. The note, with labels on show, is visible on the right hand end of the image. When comparing the note with the data returned by each expression, it should become apparent how each expression is working.''
 
[[image:Notes.png|thumb|left|500px|alt=note image|A note + expression columns (''click to enlarge)'']]
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
====Save(...): Saves a value to a global variable====
+
Path data types sort using smart filename comparisons.
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Save()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Saves a value into the specified global variable, and optionally outputs the value.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Save(Value,Variable,Output value)'''
 
  
* Value ''The value to store into the variable.''
+
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.
* Variable ''The global variable in which to save a value.''
 
* Output value ''Optional, outputs Value after the save.''
 
  
|- valign="top"
+
Add the cast:
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''save(Much Money, local_bank)'''<br />
 
''Saves the value "Much Money" into the global variable "local_bank".''
 
  
<br />'''save(More Money, My Bank, 1)'''
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">&datatype=[path]</span></div>
<br />''Saves "More Money" into "My Bank" and outputs "More Money".''
 
  
 +
to the end of an expression to force an expression's output to be smart-sorted by path components.
  
The following links demonstrate usage of global variables:
+
</div>
* [http://yabb.jriver.com/interact/index.php?topic=76581.msg518902#msg518902 Generating album track count]
 
* [http://yabb.jriver.com/interact/index.php?topic=72049.0 Generating album ratings]
 
* [http://yabb.jriver.com/interact/index.php?topic=74116.0 Highlighting playing album]
 
  
|}
+
== Expressions and Search ==
<div style="text-align:right;">([[#top|Back to top)]]</div>
+
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:
  
====Tag(...): Returns a physical file tag (rather than looking in the database)====
+
<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>
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Tag()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function originally came into being as a need arose for there to be a way to re-import the exif date information from image files without affecting any other tags. To that end, the function works well, but that's really where it's functionality ends. Success with any other fields has been extremely limited indeed. The main reason for this is because, when using this function to query specific tag data blocks in an image file, the fields referenced by the tag() function must be spelled ''exactly'' as they appear in the tag block within the file, and yes, they ''are'' case sensitive. It is also extremely important to know that when building a file list that contains a "Tag()" derived column, Media Center will be inordinately slower, <ins>1000's of times slower</ins>, in building that list than it would be without the "Tag()" column. This is because each and every file in the list must be queried individually for the contents of the specified tag. This particular function is best used using the "inline editing" method outlined in the "[[#When, Where and How to use expressions|When, Where and How to use expressions]]" section of this page, to pull the desired data into the main library database and then reference the information from the database.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Tag(Field to read from the file)'''<br>Specific tag data blocks from jpg files can also be referenced:<br>'''Tag(Tag Block To Query: Field to read from the tag block)'''
 
  
* Field to read from the file: Not case sensitive in all scenarios, but always case sensitive when targeting specific tag data blocks within jpg files.
+
where expression is any valid expression, and numval is the expected numeric output produced by the expression.
* Tag blocks that can be queried from within jpg files are:
+
The expression is evaluated against the current list of available files and the expression output numerically compared against numval.
** EXIF
+
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.
** XMP
 
** IPTC
 
** MJMD
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''tag(artist)'''<br>''This will return the artist information from a file if that file contains the artist tag''
 
  
<br>'''tag(Gapless Header)''' or '''tag(Gapless Footer)'''<br>''These two expressions allow gapless information to be queried from mp3 files.''
+
The following example illustrates an expression-based search query:
  
<br>'''tag(exif: Date)'''<br>''This will return the raw date data from the EXIF data saved inside a jpg file. If this expression is used to import the data into Media Center's default [Date] field, Media Center will format the info into legible date information automatically. If importing into a custom field, wrap the tag() function inside a [[#FormatDate(...): Formats a date value in a specified manner|FormatDate()]] function like so: '''formatdate(tag(exif: Date),datetime)'''.''<br>''Note that "tag(exif: date)" will not return any result as the tag to query value is case sensitive and must be entered as "Date"''
+
<div style="margin-left: 20pt"><span style="font-family: monospace,monospace; font-size:1em;">[=ismissing([filename (path)]\Folder.jpg)]=1</span></div>
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
====TVInfo(...): Returns television-specific information about a file====
+
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>,
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
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>.
|- valign="top"
+
All these files where there was a successful comparison are returned in the file list,
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | TVInfo()
+
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.
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Used to retieve and display specified televison information for a file.
+
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.
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''TVInfo(Information to retrieve)'''
 
'''Information to retrieve''': ''The options available for use here are:''
 
  
* '''IsProgram''': ''Tests whether the file is a program or not. (Returns 0 or 1)''
+
== HTML Font Properties ==
* '''IsGuideProgram''': ''Tests whether the file is a guide program or not. (Returns 0 or 1)''
+
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.
* '''IsRecordedProgram''': ''Tests whether the file is a recorded program or not. (Returns 0 or 1)''
+
HTML tags are used by surrounding the desired content with an opening and closing tag, in the form of:
* '''Channel''': ''Returns the channel name, given a channel number.''
 
* '''ChannelKeywords''': ''Returns channel keywords.''
 
* '''NameDisplay''': ''Returns the name.''
 
* '''NameDisplayWithDate''': ''Returns the name + date.''
 
* '''SeriesDisplay''': ''Returns the series name.''
 
* '''TimeDisplay''': ''Shows the start time of a program using the system time format, but uses "Showing" if the program is on now.''
 
* '''TimeDisplayNoOnNow''': ''Shows the start time of a program using the system time format, without special handling for programs on now''
 
* '''SizeDisplay''': ''Returns the duration, formatted nicely for a television program.''
 
* '''WatchedDisplay''': ''Watched information, like no, yes, 80%, etc.''
 
  
|- valign="top"
+
: <span style="font-family: monospace,monospace; font-size:1em;"><<i>tag</i>><i>desired content</i><//<i>tag</i>></span>
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''TVInfo(namedisplay)'''<br>Click on "<ins>T</ins>ools > Options > Theater View", then click on "Customize file info panel", then choose "Television Program" from the drop-list at the top. It is then possible to use this function to tailor the information displayed on screen in Theater view when looking at TV programs. Some of the default items already utilise this function offering real world, real time examples of their usage.
 
* TV programs use the field "Date Recorded" to store the program time.
 
* The "Date" field is the original air / production date.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
<br><br>
+
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>
  
===Redundant Functions?===
+
The <b>font</b> tag supports the following attributes:
Taken at face value, all of the functions in this section would appear to be a little on the redundant side, falling neatly into the "a long way for a shortcut" category. Media Center could possibly rely on these functions internally, exalting their status to "highly useful" or "essential" even, but as this page is designed for end users, not Media Center, end users will find these functions redundant, and they are included here in the name of completeness only.
+
<div style="margin-left: 20pt;"><table style="border-spacing:0px; border-collapse:collapse">
====Field(...): Returns the value of a library field====
+
<tr><td style="text-align:left; padding-right:20pt"><b>alpha</b></td><td>Sets alpha-blending percentage (0 - 100)</td></tr>
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
+
<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>
|- valign="top"
+
<tr><td style="text-align:left; padding-right:20pt"><b>bgcolor</b></td><td>Sets the background color (same values as color)</td></tr>
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Field()
+
<tr><td style="text-align:left; padding-right:20pt"><b>face</b></td><td>Sets the font face (a font name)</td></tr>
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Place the name of any library field inside this function, and it will return the contents of that library field for each file. Entering the field name inside square brackets as normal, without the function, returns the same data.
+
<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>
  
'''Note''': Beginning with version 17, Media Center no longer supports function expansion inside the Field() parameter list; only simple text strings are supported. This is a performance optimization.
+
Any combination of HTML tags and font attributes can be used.
|- valign="top"
+
An HTML tag must have an opening and closing tag.
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
+
Nesting is allowed, but be sure to properly balance like opening and closing tags.
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Field(Field name to retrieve)'''
+
Attribute values must be double quoted. The closing tag's forward slash requires escapement with an extra forward slash.
|- valign="top"
+
The following examples illustrate using HTML font properties:
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''field(duration)'''<br>''Returns the formatted duration value for each file. '''field(duration,0)''' would return the raw duration data. Simply entering [duration] or [duration,0] returns the same result.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====FilePath(...): Returns the path from a specified filename====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FilePath()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function will return the file path information from root to parent folder for all files in a list, or for any specified file. Media Center has a [Filename (Path)] library field by default, which is probably easier to use or reference than this function.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FilePath(Filename to check)'''
 
  
* Filename to check ''This is optional. If not specified, the function defaults to the current file.''
+
: <span style="font-family: monospace,monospace; font-size:1em;"><nowiki><i>This is in italics<//i></nowiki></span>
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''filepath(C:\Music\File.mp3)'''<br>''The result here would be... "C:\Music"''
 
  
<br>'''filepath()'''<br>''Returns the filepath for each file in the list. The [filename (path)] field returns the same information.
+
: <span style="font-family: monospace,monospace; font-size:1em;"><nowiki><i><b>And this is bold and italic<//b><//i></nowiki></span>
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
====FileVolume(...): Returns the volume name from a specified filename====
+
: <span style="font-family: monospace,monospace; font-size:1em;"><nowiki><b>The<font color=&quot;ff0000&quot; size=&quot;80&quot; alpha=&quot;50&quot;> Great <//font>Gatsby<//b></nowiki></span>
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | FileVolume()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function will return the volume name information for all files in a list, or for any specified file. Media Center has a [Volume Name] library field by default, which is probably easier to use or reference than this function.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''FileVolume(Filename to check)'''
 
  
* Filename to check ''This is optional. If not specified, the function defaults to the current file.''
+
== Expression Editors ==
|- valign="top"
+
There are a couple of variations of dialog or edit field used to enter expressions.
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
+
Some allow multi-line expressions, while others are single line, but can be expanded to multi-line editors.
|style="background: #ecfeea; color: black; border: 1px solid black" | '''filevolume(C:\Music\File.mp3)'''<br>''The result here would be... "C:"''
+
Unfortunately, some single-line editors flatten multi-line expressions into a single line, replacing the newlines with spaces.
  
<br>'''filevolume()'''<br>''Returns the file name for each file in the list. The [Volume Name] field returns the same information.
+
== 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.
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====AlbumKey(...): Returns a unique album key for a file====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | AlbumKey()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Testing reveals that this function simply returns an "'''[album artist (auto)] - [album]'''" string for each file. If two different albums happen to have the same [album&nbsp;artist&nbsp;(auto)] and [album] data, their respective AlbumKey() will not be unique.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''AlbumKey()'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''AlbumKey()'''<br>''Create a new expression column in a list using this function and the result will be a column populated with the [album artist (auto)] - [album] data for each file.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====AlbumArtist(...): Returns the calculated album artist for a file====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | AlbumArtist()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function simply returns the "'''[album artist (auto)]'''" data for each file.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''AlbumArtist()'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''AlbumArtist()'''<br>''Create a new expression column in a list using this function and the result will be a column populated with the [album artist (auto)] data for each file.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====AlbumType(...): Returns the album type for a file====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | AlbumType()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function simply returns the "'''[album type]'''" for each file. [album type] is a default Media Center library field that informs the user of an album's status in the library, such as "Single artist (complete)" or "Multiple artists (incomplete)"
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''AlbumType()'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''AlbumType()'''<br>''Create a new expression column in a list using this function and the result will be a column populated with the [album type] data for each file. The [album type] library field will work just as well, and return the same information.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====Size(...): Returns the size of a file in a media type independent manner====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | Size()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | Dependent on media type, this function returns the following information:
 
  
* Audio: ''Duration''
+
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.
* Video: ''Duration''
 
* Image: ''Dimensions''
 
* Data: ''No information returned.''
 
  
|- valign="top"
+
The current caretaker of this documentation is forever in their debts.
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''Size()'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''Size()'''<br>''Create a new expression column in a list using this function and the result will be a column populated with media type dependent data for each file as listed in the function description above.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
====TrackNumber(...): Returns the track # of a file====
 
{| style="width: 100%; border: 1px solid black" align="top" border="1" cellpadding="3"
 
|- valign="top"
 
! scope="row" style="white-space:nowrap; background: #A8E4A0; color: black; border: 1px solid black;" width=100 | TrackNumber()
 
| style="background: #ecfeea; color: black; border: 1px solid black" width=1200 | This function simply returns the track # of a file. If a file has no track # assigned, the function returns zero.<br>This function has no real use and is actually flagged as "For internal use only", so, not one for end users, and again, only included here for the sake of completeness.
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Construction
 
| style="background: #ecfeea; color: black; border: 1px solid black" | '''TrackNumber()'''
 
|- valign="top"
 
! scope="row" style="background: #A8E4A0; color: black; border: 1px solid black;" | Examples
 
|style="background: #ecfeea; color: black; border: 1px solid black" | '''TrackNumber()'''<br>''Create a new expression column in a list using this function and the result will be a column populated with the track # information for each file.
 
|}
 
<div style="text-align:right;">([[#top|Back to top)]]</div>
 
  
[[Category:Frequently_Asked_Questions]]
+
[[Category:Frequently Asked Questions]]
 +
[[Category:Developer]]
 +
[[Category:Expression Language]]

Latest revision as of 05:24, 23 March 2024

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

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

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

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

The Anatomy of an Expression

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

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

A function call looks like this:

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

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

fixcase(A good movie)

The result is A Good Movie.

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

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

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

replace(A good movie, good, great)

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

fixcase(A great movie)

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

Wow! A Great Movie

Fields

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

fixcase(field(album), 3)

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

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

fixcase([album], 3)

Field Values

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

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

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

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

Field Values: Override the expression, and [This]

ExpressionOverride.png

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

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

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

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

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

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

Field Values: Empty, 0, and 1

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

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

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

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

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

Field Assignment

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

Field Assignment with Expression.png

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

=removeleft([name], 4)

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

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

Expression Language Syntax

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

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

How Expressions Are Evaluated

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

Expressions and Locales

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

A Complex Expression Example

Expression Editor.png

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

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

The expression demonstrates that

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

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

Functions

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

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

Function Arguments

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

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

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

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

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

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

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

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

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

Function Index

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

Accessing and Storing Functions

Conditional Functions

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

Date and Time Functions

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

File Path and Identifier Functions

Formatting Functions

Grouping Functions

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

List Manipulation Functions

Miscellaneous Functions

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

Number Functions

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

String Manipulation Functions

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

Test and Comparison Functions

Data Types

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

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

&datatype=[type]

where type is one of the following values:

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

Calculated Fields and Search

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

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

to the end of the field's calculated expression.

Lists and Trees

Datatype List.png

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

&datatype=[list]

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

&datatype=[string]

to the end of an expression.

Sort Order

Datatype Month.png

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

Sorting by Month

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

&datatype=[month]

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

Sorting by Path

Path data types sort using smart filename comparisons.

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

Add the cast:

&datatype=[path]

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

Expressions and Search

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

[=expression]=numval

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

The following example illustrates an expression-based search query:

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

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

HTML Font Properties

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

<tag>desired content<//tag>

The supported HTML tags are:

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

The font tag supports the following attributes:

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

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

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

Expression Editors

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

Acknowledgements

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

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

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