Learn how {expressions} work and useful Helper Functions

All about user-defined episode / movie / file name format expressions
Post Reply
User avatar
rednoah
The Source
Posts: 23529
Joined: 16 Nov 2011, 08:59
Location: Taipei
Contact:

Learn how {expressions} work and useful Helper Functions

Post by rednoah »

The Unwind-on-Undefined Behaviour

If you're using format expression like {director} or {vc} you may have noticed that if a variable is not defined, it will cause the entire {expression} to fail and unwind.

A common issue when writing expressions like this [{vc}, {ac}] is that it might evaluate to [, ] if the required bindings are undefined. A better way would be to write {"$vc, $ac"} (as String) or {[vc, ac]} (as List) in which case this single expression will only work if all required bindings are defined.

This expression will either evaluate successfully as a single unit, or fail as a single unit:

Format: Select all

{"A ${director} Movie"}
So if the binding is undefined, it would be evaluated like this and fail with an Exception:

Format: Select all

{"A ${throw new Exception()} Movie"}
Alternatively, if you access properties via the {self} binding you will not get this unwind-on-undefined behavior.

Format: Select all

{"A ${self.director} Movie"}
Which would evaluate like this if undefined:

Format: Select all

{"A ${null} Movie"} // A null Movie
This is useful if you want to check properties with an if-then-else statement:

Format: Select all

{"A ${self.director ?: 'No Name'} Movie"}


Helper Functions

FileBot adds a few simple functions that can make your code much more easy to read if you need to collect the values of multiple bindings/expressions that may or may not fail and unwind.

any(Closure...)
Find and return the value of the first expression that evaluates successfully without returning null or throwing an Exception. If none of the expressions evaluates successfully null will be returned.

e.g. Take collection, or if collection is undefined take the first genre, or if no genres are defined use a fixed String value:

Format: Select all

{ any{ collection }{ genre }{ 'No collection or Genre' } }
allOf(Closure...)
Find and return all values of all the expressions that evaluate successfully and ignore all expressions that fail or unwind.

e.g. Take the values of multiple bindings and simply ignore those that are undefined:

Format: Select all

{ allOf{ fn.match(/Extended.Edition/) }{ vc }{ ac }{ hdr }{ source }{ group }.join('.') }
none(Closure...)
Check if each expression yields a negative result of fails to yield a result altogether.

e.g. Return true if none of the given expressions yield a positive result:

Groovy: Select all

none{ ext =~ /jpg|png/ }{ fn.match(/sample|trailer/) }
@see ExpressionFormatFunctions



Real-World Examples

e.g. combine binding variable and separator literals into a single {expression} so that you get either all or nothing (e.g. ".10bit" or ".HDR" but never just ".") and don't end up with superfluous separator literals:

Format: Select all

{ ny.colon(' - ') }{ '-' + vf }{ '.' + bitdepth + ' bit' }{ '.' + hdr }{ '-' + group }
e.g. guess source tag based on video resolution if {vs} video source is undefined:

Format: Select all

{ any{ vs }{ width >= 1280 ? 'BluRay' : 'DVD' } }
e.g. use {certification} if defined, or yield NR otherwise:

Format: Select all

{ any{ certification }{ 'NR' } }
e.g. use {s} if defined, or yield Specials, since special episodes (e.g. S00E01) technically do not have a season number, i.e. {s} is not 0 but undefined in this case:

Format: Select all

{ any{ 'Season ' + s.pad(2) }{ 'Specials' } }
e.g. use the {plex} format with additional media info bindings (that may or may not be defined) enclosed in brackets:

Format: Select all

{ drive }/Media/{ plex.id % { allOf{ vf }{ hdr }.joining(' ', ' [', ']') } }


Reference Documentation

:idea: Please read the FAQ and How to Request Help.
Post Reply