-
-
Notifications
You must be signed in to change notification settings - Fork 694
Custom Formatter
Here is a complete reference to the custom formatter system
A custom format allows you to fully control the output of the streams. You can test your formats live at the configuration page using the Preview.
When writing your format, you have access to specific objects, known as variables, each with their own properties. The format to access a variable is as follows:
{variableName.propertyName}.
You may also apply specific "modifiers". The available modifiers depend on the type of properties. i.e. strings, numbers, lists, each have their own modifiers.
| Access | Type | Description |
|---|---|---|
{config.addonName} |
string |
The name of the AIOStreams instance (the value of the ADDON_NAME environment variable) |
| Access | Type | Description |
|---|---|---|
{stream.proxied} |
boolean |
Whether the stream is proxied using MediaFlow proxy |
{stream.type} |
string |
Type of the stream e.g. debrid, usenet, http, live, youtube, p2p
|
{stream.filename} |
string |
Filename of the stream or media file |
{stream.folderName} |
string |
The folder name of the stream, usually only available to specific addons. |
{stream.size} |
number |
Size of the stream/file in bytes |
{stream.bitrate} |
number |
Bitrate of the stream in bits per second |
{stream.folderSize} |
number |
Size of the folder/torrent in bytes |
{stream.library} |
boolean |
Whether the stream is considered to be a stream from a personal library (e.g. debrid account |
{stream.quality} |
string |
Quality indicator of the stream |
{stream.resolution} |
string |
Video resolution (e.g., "1080p", "4K") |
{stream.languages} |
string[] |
Available audio languages |
{stream.seeders} |
number |
Number of seeders (for torrents) |
{stream.private} |
boolean |
true if the torrent is from a private tracker. |
{stream.freelech} |
boolean |
true if the torrent is freeleech. |
{stream.age} |
string |
Age of the stream since release |
{stream.ageHours} |
number |
The age of the stream in hours. |
{stream.duration} |
number |
Duration of the media in seconds |
{stream.infoHash} |
string |
Info hash for torrent streams |
{stream.message} |
string |
Additional information or status message |
{stream.languageEmojis} |
string[] |
Available audio languages in emoji form |
{stream.languageCodes} |
string[] |
Available audio languages in ISO 639 |
{stream.smallLanguageCodes} |
string[] |
Available audio languages in small caps |
{stream.uLanguages} |
string[] |
Available audio languages (that are also defined in your language settings) |
{stream.uLanguageEmojis} |
string[] |
Available audio languages in emoji form (that are also defined in your language settings) |
{stream.uLanguageCodes} |
string[] |
Available audio languages in ISO 639 (that are also defined in your language settings) |
{stream.uSmallLanguageCodes} |
string[] |
Available audio languages in small caps (that are also defined in your language settings) |
{stream.visualTags} |
string[] |
Tags related to video characteristics |
{stream.audioTags} |
string[] |
Tags related to audio characteristics |
{stream.audioChannels} |
string[] |
List of detected audio channels |
{stream.releaseGroup} |
string |
Name of the group that released the content |
{stream.encode} |
string |
Encoding format (e.g., "x264", "HEVC") |
{stream.edition} |
string |
Special edition information (e.g., "Director's Cut", "Extended Edition", "Anniversary Edition") |
{stream.remastered} |
boolean |
Whether the content is remastered |
{stream.repack} |
boolean |
Whether the release is a repack |
{stream.uncensored} |
boolean |
Whether the content is uncensored |
{stream.unrated} |
boolean |
Whether the content is unrated |
{stream.upscaled} |
boolean |
Whether the content has been upscaled |
{stream.network} |
string |
Source network or streaming service (e.g., "Netflix", "Disney+") |
{stream.container} |
string |
File container format (e.g., "mkv", "mp4", "avi") |
{stream.extension} |
string |
File extension (e.g., "mkv", "mp4", "avi", ".iso", "m2ts") |
{stream.indexer} |
string |
Source indexer that provided the stream |
{stream.title} |
string |
The title of the movie or show, extracted from the filename |
{stream.year} |
string |
Any year contained in the filename |
{stream.seasonPack} |
boolean |
true if the stream is part of a season pack. |
{stream.seasonEpisode} |
string[] |
A list of pre-formatted season and episode strings, e.g. ['S01', 'E201'], use the join modifier on this. |
{stream.seasons} |
number[] |
A list of seasons detected |
{stream.formattedSeasons} |
string |
A formatted season string e.g. S01 or S01-05
|
{stream.folderSeasons} |
number[] |
A list of seasons detected from the folderName, if available and different from seasons. |
{stream.formattedFolderSeasons} |
string |
A formatted season string from the folderName e.g. S01 or S01-05. |
{stream.episodes} |
number[] |
A list of episode numbers detected |
{stream.formattedEpisodes} |
string |
A formatted episode string e.g. E01 or E01-05
|
{stream.folderEpisodes} |
number[] |
A list of episode numbers detected from the folderName, if available and different from episodes. |
{stream.formattedFolderEpisodes} |
string |
A formatted episode string from the folderName e.g. E01 or E01-05. |
{stream.seadex} |
boolean |
Whether the stream is one of the best/alternative releases on SeaDex for that anime. |
{stream.seadexBest} |
boolean |
Whether the stream is one of the best releases on SeaDex for that anime. |
{stream.regexMatched} |
string |
The name of the highest preferred regex that was matched |
{stream.rankedRegexMatched} |
string[] |
A sorted list of all Regex Filter names that were matched. |
{stream.regexScore} |
number |
The score from the matched Regex Filter. |
{stream.nRegexScore} |
number |
The regex score normalised to a 0-100 scale with 100 being relative to the highest Regex Score from all your results. |
{stream.seScore} |
number |
The score from the matched Stream Expression sort rule. |
{stream.nSeScore} |
number |
The Stream Expression score normalised to a 0-100 scale with 100 being relative to the highest Stream Expression Score from all your results. |
{stream.seMatched} |
string |
The name of the Preferred Stream Expression that matched this stream. Name is extracted from the first comment that appears in the expression. |
{stream.rseMatched} |
string[] |
A list of all names of the Ranked Stream Expressions that this stream matched. The names for each RSE is taken from the comments that appear in the expression. |
| Access | Type | Description |
|---|---|---|
{service.id} |
string |
Unique identifier of the service (e.g. realdebrid) |
{service.shortName} |
string |
Abbreviated name of the service (e.g. RD) |
{service.name} |
string |
Full name of the provider (e.g. Real-Debrid) |
{service.cached} |
boolean |
Whether the stream is cached |
| Access | Type | Description |
|---|---|---|
{addon.presetId} |
string |
The ID of the preset that the addon was generated from |
{addon.name} |
string |
Display name of the addon |
{addon.manifestUrl} |
string |
The manifest URL of the addon |
| Access | Type | Description |
|---|---|---|
{metadata.queryType} |
string |
The type of media being queried for (e.g. movie, series). |
{metadata.title} |
string |
The title of the media being queried for. |
{metadata.runtime} |
number |
The runtime of the movie in minutes. |
{metadata.episodeRuntime} |
number |
The runtime of the episode in minutes. |
{metadata.genres} |
string[] |
A list of genres for the media. |
{metadata.year} |
number |
The release year of the media. |
| Access | Type | Description |
|---|---|---|
{debug.json} |
string |
Raw JSON string representation of data |
{debug.jsonf} |
string |
Formatted JSON string representation of data |
To apply a modifier, use it on a variable like so:
{variableName.propertyName::modifier}
You can apply as many modifiers as you want to the same variable. They will be applied in order from left to right.
-
::upper- Convert string to uppercase. -
::lower- Convert string to lowercase. -
::smallcaps- Convert string to ꜱᴍᴀʟʟ ᴄᴀᴘꜱ. -
::title- Title case the string (capitalise the first letter of each word). -
::replace('find', 'replaceWith')- Replaces all occurrences offindwithreplaceWith. -
::truncate(N)- Truncate the string toNcharacters and append…. -
::length- Return the length of the string. -
::reverse- Reverses the string.
-
::bytes/::bytes10- Format number as bytes using base 10 (e.g., KB, MB, GB). -
::sbytes/::sbytes10- Format number as "smart" bytes using base 10 (e.g., KB, MB, GB), which is more concise. -
::bytes2- Format as number of bytes using base 2 (e.g., KiB, MiB, GiB). -
::sbytes2- Format number as "smart" bytes using base 2 (e.g., KiB, MiB, GiB). -
::rbytes/::rbytes10- Same asbytesbut rounds to the nearest integer. -
::rbytes2- Same asbytes2but rounds to the nearest integer. -
::bitrate- Format as bitrate using appropriate unit (e.g., Kbps, Mbps). -
::rbitrate- Same asbitratebut rounds to the nearest integer. -
::sbitrate- Format as "smart" bitrate, providing a more concise output (e.g., 5.2 Mbps). -
::time- Format number of seconds as human-readable time (e.g.,1h 30m). -
::star- Displays a star rating (out of 5) based on an expected input of a number between 0-100 (e.g., fromnSeScoreornRegexScore). -
::pstar- Same asstarbut pads with empty stars to always show 5 total stars (e.g., ★★★☆☆). -
::hex- Encode the number to hexadecimal. -
::octal- Encode the number to octal. -
::binary- Encode the number to binary. -
::string- Convert the number to a string
-
::join('separator')- Join array elements with the specified separator. -
::slice(start, end)- Returns a section of the array.endis optional. -
::length- Return the number of elements in the array. -
::first- Return the first element of the array. -
::last- Return the last element of the array. -
::random- Returns a single random element from the array. -
::sort- Sorts the array. For strings, it's alphabetical; for numbers, it's numerical. -
::rsort- Sorts the array in reverse order. -
::lsort- Sorts the array lexicographically (alphabetically, case-sensitive). -
::reverse- Reverses the order of elements in the array. -
::string- Convers the array to a string.
Conditional modifiers evaluate to true or false and are used to create dynamic text. The format is:
{variable::conditionalModifier["trueString"||"falseString"]}
For example, to show the number of seeders only if it's greater than 1, you would do:
{stream.seeders::>1["Seeders: {stream.seeders}"||""]}
| Modifier | Description | Applicable Types | Example Usage |
|---|---|---|---|
istrue |
Checks if a boolean value is true. |
boolean |
`{service.cached::istrue["Cached" |
isfalse |
Checks if a boolean value is false. |
boolean |
`{service.cached::isfalse["Not Cached" |
exists |
Checks if a value is not null, undefined, an empty string, or an empty array. |
string, array, any
|
`{stream.folderName::exists["Folder: {stream.folderName}" |
$X |
Checks if a string starts with X or if the first element of an array is X. |
string, string[]
|
{stream.filename::$ShowName[...]} |
^X |
Checks if a string ends with X or if the last element of an array is X. |
string, string[]
|
{stream.filename::^.mkv[...]} |
~X |
Checks if a string or an array of strings includes X. |
string, string[]
|
{stream.languages::~English[...]} |
=X |
Checks if a value is exactly equal to X. |
string, number
|
{stream.resolution::=1080p[...]} |
>=X |
Checks if a number is greater than or equal to X. |
number |
{stream.seeders::>=100[...]} |
>X |
Checks if a number is greater than X. |
number |
{stream.seeders::>50[...]} |
<=X |
Checks if a number is less than or equal to X. |
number |
{stream.size::<=5GB[...]} |
<X |
Checks if a number is less than X. |
number |
{stream.ageHours::<24[...]} |
Note
The istrue and isfalse modifiers both evaluate to false when the property is null or undefined. To handle this, you must use two conditional modifiers when wanting to show an output depending on whether a value is true or false but not null e.g. {service.cached::istrue["Cached"||""]}{service.cached::isfalse["Uncached"||""]}
You can also create conditional statements using one of and, or, and xor. Like so:
{variableName.propertyName::conditionalModifier::conditional::variableName.propertyName::conditionalModifier["trueString"||"falseString"]}
You can continue chaining together conditionals as many times as you want, they are applied left to right so the statement (x and y or z) is evaluated as ((x and y) or (z)) whereas if written like (y or z and x) is evaluated as ((y or z) and x).
-
and- both expressions must evaluate to true -
or- at least one of the expressions must evaluate to true -
xor- exactly one of the expressions must evaluate to true
For example:
{service.cached::isfalse::or::stream.type::=p2p::and::stream.seeders::>0["Seeders: {stream.seeders}"||""]}
Only show seeders when the stream is either uncached or P2P.
You also have a few formatting tools available through the following syntax:
{tools.toolName}
| Access | Description |
|---|---|
{tools.newLine} |
Will add a newline wherever placed. Use this when you want an empty line. |
{tools.removeLine} |
Will remove the entire line wherever found |
Note
While {tools.newLine} is provided to you here and it will correctly display in the formatter preview, how it displays in Stremio is not controlled by AIOStreams. It is known that new lines are not respected in the name field on many platforms and as such it is recommended that you do not build your name template relying on {tools.newLine}
For Chillio, it won't display your name / description fields exactly like Stremio. The ChillLink protocol supports a title field, this corresponds to the name template. The other means of displaying information is via the metadata field. Here, AIOStreams can offer a list of attributes. To form this list, AIOStreams splits the output produced by the description template by line; each line in the description template gets its own metadata string.
If you would like to see some examples of formatters, join the Discord Server to see all the formats that have been created by the community.
You may also see the definitions for the built-in formatters at https://github.com/Viren070/AIOStreams/blob/main/packages/core/src/formatters/predefined.ts