mirror of
https://github.com/Viren070/AIOStreams.git
synced 2025-12-01 23:14:04 +01:00
feat(core/formatters): improve and refactor base formatter
- Strings can contain spaces in conditional checks (i.e. X in ~X can contain spaces) - (>=, >, <, <=)X conditionals can now be used with strings Co-authored-by: David Garcia <dgarcia3@atlassian.com>
This commit is contained in:
@@ -107,6 +107,151 @@ export interface ParseValue {
|
||||
};
|
||||
}
|
||||
|
||||
export const hardcodedParseValueKeysForRegexMatching: ParseValue = {
|
||||
stream: {
|
||||
filename: null,
|
||||
folderName: null,
|
||||
size: null,
|
||||
folderSize: null,
|
||||
library: null,
|
||||
quality: null,
|
||||
resolution: null,
|
||||
languages: null,
|
||||
uLanguages: null,
|
||||
languageEmojis: null,
|
||||
uLanguageEmojis: null,
|
||||
languageCodes: null,
|
||||
uLanguageCodes: null,
|
||||
smallLanguageCodes: null,
|
||||
uSmallLanguageCodes: null,
|
||||
wedontknowwhatakilometeris: null,
|
||||
uWedontknowwhatakilometeris: null,
|
||||
visualTags: null,
|
||||
audioTags: null,
|
||||
releaseGroup: null,
|
||||
regexMatched: null,
|
||||
encode: null,
|
||||
audioChannels: null,
|
||||
indexer: null,
|
||||
year: null,
|
||||
title: null,
|
||||
season: null,
|
||||
seasons: null,
|
||||
episode: null,
|
||||
seasonEpisode: null,
|
||||
seeders: null,
|
||||
age: null,
|
||||
duration: null,
|
||||
infoHash: null,
|
||||
type: null,
|
||||
message: null,
|
||||
proxied: null,
|
||||
},
|
||||
service: {
|
||||
id: null,
|
||||
shortName: null,
|
||||
name: null,
|
||||
cached: null,
|
||||
},
|
||||
addon: {
|
||||
name: "",
|
||||
presetId: "",
|
||||
manifestUrl: "",
|
||||
},
|
||||
config: {
|
||||
addonName: null,
|
||||
},
|
||||
debug: {
|
||||
json: null,
|
||||
jsonf: null,
|
||||
},
|
||||
}
|
||||
|
||||
export const stringModifiers = {
|
||||
'upper': (value: string) => value.toUpperCase(),
|
||||
'lower': (value: string) => value.toLowerCase(),
|
||||
'title': (value: string) => value
|
||||
.split(' ')
|
||||
.map((word) => word.toLowerCase())
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' '),
|
||||
'length': (value: string) => value.length.toString(),
|
||||
'reverse': (value: string) => value.split('').reverse().join(''),
|
||||
'base64': (value: string) => btoa(value),
|
||||
'string': (value: string) => value,
|
||||
}
|
||||
|
||||
const arrayModifierGetOrDefault = (value: string[], i: number) => value.length > 0 ? String(value[i]) : '';
|
||||
export const arrayModifiers = {
|
||||
'join': (value: string[]) => value.join(", "),
|
||||
'length': (value: string[]) => value.length.toString(),
|
||||
'first': (value: string[]) => arrayModifierGetOrDefault(value, 0),
|
||||
'last': (value: string[]) => arrayModifierGetOrDefault(value, value.length - 1),
|
||||
'random': (value: string[]) => arrayModifierGetOrDefault(value, Math.floor(Math.random() * value.length)),
|
||||
'sort': (value: string[]) => [...value].sort(),
|
||||
'reverse': (value: string[]) => [...value].reverse(),
|
||||
}
|
||||
|
||||
export const numberModifiers = {
|
||||
'comma': (value: number) => value.toLocaleString(),
|
||||
'hex': (value: number) => value.toString(16),
|
||||
'octal': (value: number) => value.toString(8),
|
||||
'binary': (value: number) => value.toString(2),
|
||||
'bytes': (value: number) => formatBytes(value, 1000),
|
||||
'bytes10': (value: number) => formatBytes(value, 1000),
|
||||
'bytes2': (value: number) => formatBytes(value, 1024),
|
||||
'string': (value: number) => value.toString(),
|
||||
'time': (value: number) => formatDuration(value),
|
||||
}
|
||||
|
||||
export const conditionalModifiers = {
|
||||
exact: {
|
||||
'istrue': (value: any) => value === true,
|
||||
'isfalse': (value: any) => value === false,
|
||||
'exists': (value: any) => {
|
||||
// Handle null, undefined, empty strings, empty arrays
|
||||
if (value === undefined || value === null) return false;
|
||||
if (typeof value === 'string') return (value.trim().length > 0 && value != 'null' && value != 'undefined');
|
||||
if (Array.isArray(value)) return value.length > 0;
|
||||
// For other types (numbers, booleans, objects), consider them as "existing"
|
||||
return true;
|
||||
},
|
||||
},
|
||||
|
||||
prefix: {
|
||||
'$': (value: any, check: any) => value.toLowerCase().startsWith(check.toLowerCase()),
|
||||
'^': (value: any, check: any) => value.toLowerCase().endsWith(check.toLowerCase()),
|
||||
'~': (value: any, check: any) => value.includes(check),
|
||||
'=': (value: any, check: any) => value == check,
|
||||
'>=': (value: any, check: any) => value >= check,
|
||||
'>': (value: any, check: any) => value > check,
|
||||
'<=': (value: any, check: any) => value <= check,
|
||||
'<': (value: any, check: any) => value < check,
|
||||
},
|
||||
}
|
||||
|
||||
const hardcodedModifiersForRegexMatching = {
|
||||
"join('.*?')": null,
|
||||
'join(".*?")': null,
|
||||
"$.*?": null,
|
||||
"^.*?": null,
|
||||
"~.*?": null,
|
||||
"=.*?": null,
|
||||
">=.*?": null,
|
||||
">.*?": null,
|
||||
"<=.*?": null,
|
||||
"<.*?": null,
|
||||
}
|
||||
|
||||
const modifiers = {
|
||||
...stringModifiers,
|
||||
...numberModifiers,
|
||||
...arrayModifiers,
|
||||
...conditionalModifiers.exact,
|
||||
...conditionalModifiers.prefix,
|
||||
...hardcodedModifiersForRegexMatching,
|
||||
}
|
||||
|
||||
export abstract class BaseFormatter {
|
||||
protected config: FormatterConfig;
|
||||
protected userData: UserData;
|
||||
@@ -257,6 +402,42 @@ export abstract class BaseFormatter {
|
||||
};
|
||||
}
|
||||
|
||||
protected buildRegexExpression(): RegExp {
|
||||
// Dynamically build the `variable` regex pattern from ParseValue keys
|
||||
// Futureproof: if we add new keys to ParseValue interface, we must add them here too
|
||||
const validVariables: (keyof ParseValue)[] = Object.keys(hardcodedParseValueKeysForRegexMatching) as (keyof ParseValue)[];
|
||||
// Get all valid properties (subkeys) from ParseValue structure
|
||||
const validProperties = validVariables.flatMap(sectionKey => {
|
||||
const section = hardcodedParseValueKeysForRegexMatching[sectionKey as keyof ParseValue];
|
||||
if (section && typeof section === 'object' && section !== null) {
|
||||
return Object.keys(section);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
const variable = `(?<variableName>${validVariables.join('|')})\\.(?<propertyName>${validProperties.join('|')})`;
|
||||
|
||||
// Dynamically build the `modifier` regex pattern from modifier keys
|
||||
// Sort by length (longest first) to ensure more specific patterns match before shorter ones
|
||||
const validModifiers = Object.keys(modifiers)
|
||||
.map(key => key.replace(/[\(\)\'\"\$\^\~\=\>\<]/g, '\\$&'))
|
||||
.sort((a, b) => b.length - a.length); // Sort by length, longest first
|
||||
|
||||
const modifier = `::(?<mod>${validModifiers.join('|')})`;
|
||||
|
||||
// Build the conditional check pattern separately
|
||||
// Use [^"]* to capture anything except quotes, making it non-greedy
|
||||
const checkTrue = `"(?<mod_check_true>[^"]*)"`;
|
||||
const checkFalse = `"(?<mod_check_false>[^"]*)"`;
|
||||
const checkTF = `\\[(?<mod_check>${checkTrue}\\|\\|${checkFalse})\\]`;
|
||||
|
||||
// TZ Locale pattern (e.g. 'UTC', 'GMT', 'EST', 'PST', 'en-US', 'en-GB', 'Europe/London', 'America/New_York')
|
||||
const modTZLocale = `::(?<mod_tzlocale>[A-Za-z]{2,3}(?:-[A-Z]{2})?|[A-Za-z]+?/[A-Za-z_]+?)`;
|
||||
|
||||
const regexPattern = `\\{${variable}(${modifier})?(${modTZLocale})?(${checkTF})?\\}`;
|
||||
|
||||
return new RegExp(regexPattern, 'gi')
|
||||
}
|
||||
|
||||
protected parseString(str: string, value: ParseValue): string | null {
|
||||
if (!str) return null;
|
||||
|
||||
@@ -264,20 +445,13 @@ export abstract class BaseFormatter {
|
||||
return value;
|
||||
};
|
||||
|
||||
const data = {
|
||||
stream: value.stream,
|
||||
service: value.service,
|
||||
addon: value.addon,
|
||||
config: value.config,
|
||||
};
|
||||
|
||||
value.debug = {
|
||||
json: JSON.stringify(data, replacer),
|
||||
jsonf: JSON.stringify(data, replacer, 2),
|
||||
json: JSON.stringify({ ...value, debug: undefined }, replacer),
|
||||
jsonf: JSON.stringify({ ...value, debug: undefined }, replacer, 2),
|
||||
};
|
||||
|
||||
const re =
|
||||
/\{(?<type>stream|service|addon|config|debug)\.(?<prop>\w+)(::(?<mod>(\w+(\([^)]*\))?|<|<=|=|>=|>|\^|\$|~|\/)+))?((::(?<mod_tzlocale>\S+?))|(?<mod_check>\[(?<mod_check_true>".*?")\|\|(?<mod_check_false>".*?")\]))?\}/gi;
|
||||
|
||||
const re = this.buildRegexExpression();
|
||||
let matches: RegExpExecArray | null;
|
||||
|
||||
while ((matches = re.exec(str))) {
|
||||
@@ -285,12 +459,12 @@ export abstract class BaseFormatter {
|
||||
|
||||
const index = matches.index as number;
|
||||
|
||||
const getV = value[matches.groups.type as keyof ParseValue];
|
||||
|
||||
if (!getV) {
|
||||
// Validate - variableName (exists in value)
|
||||
const variableDict = value[matches.groups.variableName as keyof ParseValue];
|
||||
if (!variableDict) {
|
||||
str = this.replaceCharsFromString(
|
||||
str,
|
||||
'{unknown_type}',
|
||||
'{unknown_variableName}',
|
||||
index,
|
||||
re.lastIndex
|
||||
);
|
||||
@@ -298,18 +472,12 @@ export abstract class BaseFormatter {
|
||||
continue;
|
||||
}
|
||||
|
||||
const v =
|
||||
getV[
|
||||
matches.groups.prop as
|
||||
| keyof ParseValue['stream']
|
||||
| keyof ParseValue['service']
|
||||
| keyof ParseValue['addon']
|
||||
];
|
||||
|
||||
if (v === undefined) {
|
||||
// Validate - property: variableDict[propertyName]
|
||||
const property = variableDict[matches.groups.propertyName as keyof typeof variableDict];
|
||||
if (property === undefined) {
|
||||
str = this.replaceCharsFromString(
|
||||
str,
|
||||
'{unknown_value}',
|
||||
'{unknown_propertyName}',
|
||||
index,
|
||||
re.lastIndex
|
||||
);
|
||||
@@ -317,15 +485,16 @@ export abstract class BaseFormatter {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate - Modifier(s)
|
||||
if (matches.groups.mod) {
|
||||
str = this.replaceCharsFromString(
|
||||
str,
|
||||
this.modifier(
|
||||
matches.groups.mod,
|
||||
v,
|
||||
matches.groups.mod_tzlocale ?? undefined,
|
||||
matches.groups.mod_check_true ?? undefined,
|
||||
matches.groups.mod_check_false ?? undefined,
|
||||
property as unknown,
|
||||
matches.groups.mod_tzlocale ?? "",
|
||||
matches.groups.mod_check_true ?? "",
|
||||
matches.groups.mod_check_false ?? "",
|
||||
value
|
||||
),
|
||||
index,
|
||||
@@ -335,7 +504,7 @@ export abstract class BaseFormatter {
|
||||
continue;
|
||||
}
|
||||
|
||||
str = this.replaceCharsFromString(str, v, index, re.lastIndex);
|
||||
str = this.replaceCharsFromString(str, property, index, re.lastIndex);
|
||||
re.lastIndex = index;
|
||||
}
|
||||
|
||||
@@ -357,310 +526,82 @@ export abstract class BaseFormatter {
|
||||
check_false?: string,
|
||||
_value?: ParseValue
|
||||
): string {
|
||||
const _mod = mod;
|
||||
mod = mod.toLowerCase();
|
||||
check_true = check_true?.slice(1, -1);
|
||||
check_false = check_false?.slice(1, -1);
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
// CONDITIONAL MODIFIERS
|
||||
const isExact = Object.keys(conditionalModifiers.exact).includes(mod);
|
||||
const isPrefix = Object.keys(conditionalModifiers.prefix).some(key => mod.startsWith(key));
|
||||
if (isExact || isPrefix) {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_conditional_modifier_check_true_or_false(${mod})}`;
|
||||
|
||||
// try to coerce true/false value from modifier
|
||||
let conditional: boolean | undefined;
|
||||
try {
|
||||
if (isExact) {
|
||||
const modAsKey = mod as keyof typeof conditionalModifiers.exact;
|
||||
conditional = conditionalModifiers.exact[modAsKey](value);
|
||||
}
|
||||
|
||||
// PREFIX
|
||||
else if (isPrefix) {
|
||||
for (let key of Object.keys(conditionalModifiers.prefix)) {
|
||||
if (mod.startsWith(key)) {
|
||||
var checkKey = mod.substring(key.length);
|
||||
if (typeof value !== 'string' || !value.includes(' ')) {
|
||||
checkKey = checkKey.replace(/ /g, '');
|
||||
}
|
||||
conditional = conditionalModifiers.prefix[key as keyof typeof conditionalModifiers.prefix](value, checkKey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
conditional = false;
|
||||
}
|
||||
|
||||
if (conditional === undefined) return `{unknown_conditional_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return conditional
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
return conditional ? check_true : check_false;
|
||||
}
|
||||
|
||||
// --- STRING MODIFIERS ---
|
||||
if (typeof value === 'string') {
|
||||
if (mod in stringModifiers) return stringModifiers[mod as keyof typeof stringModifiers](value);
|
||||
return `{unknown_str_modifier(${mod})}`;
|
||||
}
|
||||
|
||||
// --- ARRAY MODIFIERS ---
|
||||
else if (Array.isArray(value)) {
|
||||
if (mod in arrayModifiers) {
|
||||
const result = arrayModifiers[mod as keyof typeof arrayModifiers](value);
|
||||
if (typeof result === 'string') return result;
|
||||
return result.join(', ');
|
||||
}
|
||||
|
||||
// handle hardcoded modifiers here
|
||||
switch (true) {
|
||||
case mod === 'join':
|
||||
return value.join(', ');
|
||||
case mod.startsWith('join(') && mod.endsWith(')'): {
|
||||
// Extract the separator from join(separator)
|
||||
// e.g. join(' - ')
|
||||
const separator = mod
|
||||
.substring(5, mod.length - 1)
|
||||
.replace(/^['"]|['"]$/g, '');
|
||||
const separator = _mod
|
||||
.substring(6, _mod.length - 2)
|
||||
return value.join(separator);
|
||||
}
|
||||
case mod == 'length':
|
||||
return value.length.toString();
|
||||
case mod == 'first':
|
||||
return value.length > 0 ? String(value[0]) : '';
|
||||
case mod == 'last':
|
||||
return value.length > 0 ? String(value[value.length - 1]) : '';
|
||||
case mod == 'random':
|
||||
return value.length > 0
|
||||
? String(value[Math.floor(Math.random() * value.length)])
|
||||
: '';
|
||||
case mod == 'sort':
|
||||
return [...value].sort().join(', ');
|
||||
case mod == 'reverse':
|
||||
return [...value].reverse().join(', ');
|
||||
case mod.startsWith('~'): {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_array_modifier(${mod})}`;
|
||||
|
||||
const check = mod.replace('~', '').replace('_', ' ');
|
||||
|
||||
if (_value) {
|
||||
return value.some((item) => item.toLowerCase().includes(check))
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value.some((item) => item.toLowerCase().includes(check))
|
||||
? check_true
|
||||
: check_false;
|
||||
}
|
||||
case mod == 'exists': {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_array_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value.length > 0
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value.length > 0 ? check_true : check_false;
|
||||
}
|
||||
default:
|
||||
return `{unknown_array_modifier(${mod})}`;
|
||||
}
|
||||
} else if (typeof value === 'string') {
|
||||
switch (true) {
|
||||
case mod == 'upper':
|
||||
return value.toUpperCase();
|
||||
case mod == 'lower':
|
||||
return value.toLowerCase();
|
||||
case mod == 'title': {
|
||||
return value
|
||||
.split(' ')
|
||||
.map((word) => word.toLowerCase())
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ');
|
||||
}
|
||||
case mod == 'length':
|
||||
return value.length.toString();
|
||||
case mod == 'reverse':
|
||||
return value.split('').reverse().join('');
|
||||
case mod == 'base64':
|
||||
return btoa(value);
|
||||
case mod == 'string':
|
||||
return value;
|
||||
case mod == 'exists': {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_str_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value != 'null' && value
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value != 'null' && value ? check_true : check_false;
|
||||
}
|
||||
case mod.startsWith('='): {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_str_modifier(${mod})}`;
|
||||
|
||||
const check = mod.replace('=', '');
|
||||
|
||||
if (!check) return `{unknown_str_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value.toLowerCase() == check
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value.toLowerCase() == check ? check_true : check_false;
|
||||
}
|
||||
case mod.startsWith('$'): {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_str_modifier(${mod})}`;
|
||||
|
||||
const check = mod.replace('$', '');
|
||||
|
||||
if (!check) return `{unknown_str_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value.toLowerCase().startsWith(check)
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value.toLowerCase().startsWith(check)
|
||||
? check_true
|
||||
: check_false;
|
||||
}
|
||||
case mod.startsWith('^'): {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_str_modifier(${mod})}`;
|
||||
|
||||
const check = mod.replace('^', '');
|
||||
|
||||
if (!check) return `{unknown_str_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value.toLowerCase().endsWith(check)
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value.toLowerCase().endsWith(check) ? check_true : check_false;
|
||||
}
|
||||
case mod.startsWith('~'): {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_str_modifier(${mod})}`;
|
||||
|
||||
const check = mod.replace('~', '');
|
||||
|
||||
if (!check) return `{unknown_str_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value.toLowerCase().includes(check)
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value.toLowerCase().includes(check) ? check_true : check_false;
|
||||
}
|
||||
default:
|
||||
return `{unknown_str_modifier(${mod})}`;
|
||||
}
|
||||
} else if (typeof value === 'number') {
|
||||
switch (true) {
|
||||
case mod == 'comma':
|
||||
return value.toLocaleString();
|
||||
case mod == 'hex':
|
||||
return value.toString(16);
|
||||
case mod == 'octal':
|
||||
return value.toString(8);
|
||||
case mod == 'binary':
|
||||
return value.toString(2);
|
||||
case mod == 'bytes10' || mod == 'bytes':
|
||||
return formatBytes(value, 1000);
|
||||
case mod == 'bytes2':
|
||||
return formatBytes(value, 1024);
|
||||
case mod == 'string':
|
||||
return value.toString();
|
||||
case mod == 'time':
|
||||
return formatDuration(value);
|
||||
case mod.startsWith('>='): {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_int_modifier(${mod})}`;
|
||||
|
||||
const check = Number(mod.replace('>=', ''));
|
||||
|
||||
if (Number.isNaN(check)) return `{unknown_int_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value >= check
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value >= check ? check_true : check_false;
|
||||
}
|
||||
case mod.startsWith('>'): {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_int_modifier(${mod})}`;
|
||||
|
||||
const check = Number(mod.replace('>', ''));
|
||||
|
||||
if (Number.isNaN(check)) return `{unknown_int_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value > check
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value > check ? check_true : check_false;
|
||||
}
|
||||
case mod.startsWith('='): {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_int_modifier(${mod})}`;
|
||||
|
||||
const check = Number(mod.replace('=', ''));
|
||||
|
||||
if (Number.isNaN(check)) return `{unknown_int_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value == check
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value == check ? check_true : check_false;
|
||||
}
|
||||
case mod.startsWith('<='): {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_int_modifier(${mod})}`;
|
||||
|
||||
const check = Number(mod.replace('<=', ''));
|
||||
|
||||
if (Number.isNaN(check)) return `{unknown_int_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value <= check
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value <= check ? check_true : check_false;
|
||||
}
|
||||
case mod.startsWith('<'): {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_int_modifier(${mod})}`;
|
||||
|
||||
const check = Number(mod.replace('<', ''));
|
||||
|
||||
if (Number.isNaN(check)) return `{unknown_int_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value < check
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value < check ? check_true : check_false;
|
||||
}
|
||||
default:
|
||||
return `{unknown_int_modifier(${mod})}`;
|
||||
}
|
||||
} else if (typeof value === 'boolean') {
|
||||
switch (true) {
|
||||
case mod == 'istrue': {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_bool_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return value
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return value ? check_true : check_false;
|
||||
}
|
||||
case mod == 'isfalse': {
|
||||
if (typeof check_true !== 'string' || typeof check_false !== 'string')
|
||||
return `{unknown_bool_modifier(${mod})}`;
|
||||
|
||||
if (_value) {
|
||||
return !value
|
||||
? this.parseString(check_true, _value) || check_true
|
||||
: this.parseString(check_false, _value) || check_false;
|
||||
}
|
||||
|
||||
return !value ? check_true : check_false;
|
||||
}
|
||||
default:
|
||||
return `{unknown_bool_modifier(${mod})}`;
|
||||
}
|
||||
return `{unknown_array_modifier(${mod})}`;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof check_false == 'string' &&
|
||||
(['>', '>=', '=', '<=', '<', '~', '$', '^'].some((modif) =>
|
||||
mod.startsWith(modif)
|
||||
) ||
|
||||
['istrue', 'exists', 'isfalse'].includes(mod))
|
||||
) {
|
||||
if (_value) return this.parseString(check_false, _value) || check_false;
|
||||
return check_false;
|
||||
// --- NUMBER MODIFIERS ---
|
||||
else if (typeof value === 'number') {
|
||||
if (mod in numberModifiers) return numberModifiers[mod as keyof typeof numberModifiers](value);
|
||||
return `{unknown_int_modifier(${mod})}`;
|
||||
}
|
||||
|
||||
return `{unknown_modifier(${mod})}`;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UserData } from '../db';
|
||||
import { BaseFormatter, FormatterConfig } from './base';
|
||||
import { BaseFormatter } from './base';
|
||||
|
||||
export class TorrentioFormatter extends BaseFormatter {
|
||||
constructor(userData: UserData) {
|
||||
@@ -14,7 +14,7 @@ export class TorrentioFormatter extends BaseFormatter {
|
||||
{stream.folderName::exists["{stream.folderName}"||""]}
|
||||
{stream.filename::exists["{stream.filename}"||""]}
|
||||
{stream.size::>0["💾{stream.size::bytes2} "||""]}{stream.folderSize::>0["/ 💾{stream.folderSize::bytes2}"||""]}{stream.seeders::>=0["👤{stream.seeders} "||""]}{stream.age::exists["📅{stream.age} "||""]}{stream.indexer::exists["⚙️{stream.indexer}"||""]}
|
||||
{stream.languageEmojis::exists["{stream.languageEmojis::join( / ')}"||""]}
|
||||
{stream.languageEmojis::exists["{stream.languageEmojis::join(' / ')}"||""]}
|
||||
`,
|
||||
},
|
||||
userData
|
||||
@@ -95,4 +95,4 @@ export class MinimalisticGdriveFormatter extends BaseFormatter {
|
||||
userData
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user