+ {directionChangeable && (
+
toggleDirection(itemKey)}
>
- {item.direction === 'asc' ? 'โ Ascending โ' : 'โ Descending โ'}
+ {item.direction === 'asc'
+ ? 'โ Ascending โ'
+ : 'โ Descending โ'}
)}
diff --git a/packages/parser/src/regex.ts b/packages/parser/src/regex.ts
index d327bdcc..a6e80d3b 100644
--- a/packages/parser/src/regex.ts
+++ b/packages/parser/src/regex.ts
@@ -24,11 +24,13 @@ export const PARSE_REGEX = {
SCR: /(? {
const padding = blockSize - (data.length % blockSize);
@@ -40,7 +40,9 @@ export const decryptAndDecompress = (
): string => {
const secretKey = Settings.SECRET_KEY;
if (!secretKey) {
- console.error('|ERR| crypto > decryptAndDecompress > No secret key provided');
+ console.error(
+ '|ERR| crypto > decryptAndDecompress > No secret key provided'
+ );
throw new Error('No secret key provided');
}
const decipher = createDecipheriv('aes-256-cbc', secretKey, iv);
@@ -60,8 +62,6 @@ export const decryptAndDecompress = (
return decompressedData.toString('utf-8');
};
-
-
export function parseAndDecryptString(data: string): string | null {
try {
if (data.startsWith('E-')) {
@@ -72,7 +72,9 @@ export function parseAndDecryptString(data: string): string | null {
}
return data;
} catch (error: any) {
- console.error(`|ERR| crypto > parseAndDecryptString > Failed to decrypt data: ${error.message}`);
+ console.error(
+ `|ERR| crypto > parseAndDecryptString > Failed to decrypt data: ${error.message}`
+ );
return null;
}
-}
\ No newline at end of file
+}
diff --git a/packages/utils/src/details.ts b/packages/utils/src/details.ts
index 817e056b..3b438937 100644
--- a/packages/utils/src/details.ts
+++ b/packages/utils/src/details.ts
@@ -1,6 +1,5 @@
import { AddonDetail } from '@aiostreams/types';
-import {Settings} from './settings';
-
+import { Settings } from './settings';
export const addonDetails: AddonDetail[] = [
{
@@ -38,9 +37,9 @@ export const addonDetails: AddonDetail[] = [
required: false,
label: 'Use Multiple Instances',
description:
- 'Torrentio supports multiple services. By default, AIOStreams will pass all services to Torrentio. However, Torrentio has its\
- own service priority system which can\'t be overriden. If you want to use a custom priority system for your services, you can enable this option.\
- to create a separate request for each service.',
+ "Torrentio supports multiple services. By default, AIOStreams will pass all services to Torrentio. However, Torrentio has its\
+ own service priority system which can't be overriden. If you want to use a custom priority system for your services, you can enable this option.\
+ to create a separate request for each service.",
type: 'checkbox',
},
{
@@ -238,8 +237,8 @@ export const addonDetails: AddonDetail[] = [
min: Settings.MIN_TIMEOUT,
max: Settings.MAX_TIMEOUT,
},
- }
- ]
+ },
+ ],
},
{
name: 'Easynews+',
@@ -274,8 +273,8 @@ export const addonDetails: AddonDetail[] = [
min: Settings.MIN_TIMEOUT,
max: Settings.MAX_TIMEOUT,
},
- }
- ]
+ },
+ ],
},
{
name: 'Stremio GDrive',
@@ -502,7 +501,8 @@ export const serviceDetails = [
knownNames: ['SR', 'Seedr', 'SDR'],
credentials: [
{
- label: 'Encoded Token. Please authorise at MediaFusion and copy the token into here.',
+ label:
+ 'Encoded Token. Please authorise at MediaFusion and copy the token into here.',
id: 'apiKey',
},
],
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index a96c7869..58bfa1a3 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -1,4 +1,4 @@
export * from './crypto';
export * from './details';
export * from './settings';
-export * from './mediaflow';
\ No newline at end of file
+export * from './mediaflow';
diff --git a/packages/utils/src/mediaflow.ts b/packages/utils/src/mediaflow.ts
index a11ac6d8..dd9db0af 100644
--- a/packages/utils/src/mediaflow.ts
+++ b/packages/utils/src/mediaflow.ts
@@ -1,64 +1,81 @@
-import { Config } from "@aiostreams/types";
-import path from "path";
+import { Config } from '@aiostreams/types';
+import path from 'path';
const PRIVATE_CIDR = /^(10\.|127\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)/;
-export function createProxiedMediaFlowUrl(url: string, mediaFlowConfig: Config["mediaFlowConfig"], headers?:
- { request?: Record
, response?: Record }) {
- const streamUrl = url;
- const mediaFlowUrl = mediaFlowConfig?.proxyUrl?.replace(/\/$/, '');
- const mediaFlowApiPassword = mediaFlowConfig?.apiPassword;
- if (!streamUrl) {
- console.error('|ERR| mediaflow > createProxiedMediaFlowUrl > streamUrl is missing, could not create proxied URL');
- throw new Error('Stream URL is missing');
- }
- if (!mediaFlowConfig) {
- console.error('|ERR| mediaflow > createProxiedMediaFlowUrl > mediaFlowConfig is missing');
- throw new Error('MediaFlow configuration is missing');
- }
- if (!mediaFlowUrl || !mediaFlowApiPassword) {
- console.error('|ERR| mediaflow > createProxiedMediaFlowUrl > mediaFlowUrl or API password is missing');
- throw new Error('MediaFlow URL or API password is missing');
- }
+export function createProxiedMediaFlowUrl(
+ url: string,
+ mediaFlowConfig: Config['mediaFlowConfig'],
+ headers?: {
+ request?: Record;
+ response?: Record;
+ }
+) {
+ const streamUrl = url;
+ const mediaFlowUrl = mediaFlowConfig?.proxyUrl?.replace(/\/$/, '');
+ const mediaFlowApiPassword = mediaFlowConfig?.apiPassword;
+ if (!streamUrl) {
+ console.error(
+ '|ERR| mediaflow > createProxiedMediaFlowUrl > streamUrl is missing, could not create proxied URL'
+ );
+ throw new Error('Stream URL is missing');
+ }
+ if (!mediaFlowConfig) {
+ console.error(
+ '|ERR| mediaflow > createProxiedMediaFlowUrl > mediaFlowConfig is missing'
+ );
+ throw new Error('MediaFlow configuration is missing');
+ }
+ if (!mediaFlowUrl || !mediaFlowApiPassword) {
+ console.error(
+ '|ERR| mediaflow > createProxiedMediaFlowUrl > mediaFlowUrl or API password is missing'
+ );
+ throw new Error('MediaFlow URL or API password is missing');
+ }
- const queryParams: Record = {
- api_password: mediaFlowApiPassword,
- }
- queryParams.d = streamUrl;
+ const queryParams: Record = {
+ api_password: mediaFlowApiPassword,
+ };
+ queryParams.d = streamUrl;
- const responseHeaders = headers?.response || {
- "Content-Disposition": `attachment; filename=${path.basename(streamUrl)}`
- };
- const requestHeaders = headers?.request || {};
+ const responseHeaders = headers?.response || {
+ 'Content-Disposition': `attachment; filename=${path.basename(streamUrl)}`,
+ };
+ const requestHeaders = headers?.request || {};
- if (requestHeaders) {
- Object.entries(requestHeaders).forEach(([key, value]) => {
- queryParams[`h_${key}`] = value;
- });
- }
+ if (requestHeaders) {
+ Object.entries(requestHeaders).forEach(([key, value]) => {
+ queryParams[`h_${key}`] = value;
+ });
+ }
- if (responseHeaders) {
- Object.entries(responseHeaders).forEach(([key, value]) => {
- queryParams[`r_${key}`] = value;
- });
- }
-
- const encodedParams = new URLSearchParams(queryParams).toString();
- const baseUrl = new URL('/proxy/stream', mediaFlowUrl).toString();
- const proxiedUrl = `${baseUrl}?${encodedParams}`;
- //console.debug(`|DBG| mediaflow > createProxiedMediaFlowUrl > Proxied URL: ${proxiedUrl.replace(mediaFlowApiPassword, '***').replace(streamUrl, '***')}`);
- return proxiedUrl;
+ if (responseHeaders) {
+ Object.entries(responseHeaders).forEach(([key, value]) => {
+ queryParams[`r_${key}`] = value;
+ });
+ }
+
+ const encodedParams = new URLSearchParams(queryParams).toString();
+ const baseUrl = new URL('/proxy/stream', mediaFlowUrl).toString();
+ const proxiedUrl = `${baseUrl}?${encodedParams}`;
+ //console.debug(`|DBG| mediaflow > createProxiedMediaFlowUrl > Proxied URL: ${proxiedUrl.replace(mediaFlowApiPassword, '***').replace(streamUrl, '***')}`);
+ return proxiedUrl;
}
-
-export async function getMediaFlowPublicIp(mediaFlowConfig: Config["mediaFlowConfig"]) {
+export async function getMediaFlowPublicIp(
+ mediaFlowConfig: Config['mediaFlowConfig']
+) {
if (!mediaFlowConfig) {
- console.error('|ERR| mediaflow > getMediaFlowPublicIp > mediaFlowConfig is missing');
+ console.error(
+ '|ERR| mediaflow > getMediaFlowPublicIp > mediaFlowConfig is missing'
+ );
throw new Error('MediaFlow configuration is missing');
}
const mediaFlowUrl = mediaFlowConfig?.proxyUrl?.replace(/\/$/, '');
if (!mediaFlowUrl) {
- console.error('|ERR| mediaflow > getMediaFlowPublicIp > mediaFlowUrl is missing');
+ console.error(
+ '|ERR| mediaflow > getMediaFlowPublicIp > mediaFlowUrl is missing'
+ );
throw new Error('MediaFlow URL is missing');
}
if (mediaFlowConfig.publicIp) {
@@ -68,20 +85,29 @@ export async function getMediaFlowPublicIp(mediaFlowConfig: Config["mediaFlowCon
const parsedUrl = new URL(mediaFlowUrl);
if (PRIVATE_CIDR.test(parsedUrl.hostname)) {
// MediaFlow proxy URL is a private IP address
- console.debug('|DBG| mediaflow > getMediaFlowPublicIp > MediaFlow proxy URL is a private IP address so returning null');
+ console.debug(
+ '|DBG| mediaflow > getMediaFlowPublicIp > MediaFlow proxy URL is a private IP address so returning null'
+ );
return null;
}
try {
- console.debug('|DBG| mediaflow > getMediaFlowPublicIp > GET /proxy/ip?api_password=***');
- const response = await fetch(new URL(`/proxy/ip?api_password=${encodeURIComponent(mediaFlowConfig.apiPassword)}`, mediaFlowUrl).toString(), {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
- signal: AbortSignal.timeout(5000),
-
- });
+ console.debug(
+ '|DBG| mediaflow > getMediaFlowPublicIp > GET /proxy/ip?api_password=***'
+ );
+ const response = await fetch(
+ new URL(
+ `/proxy/ip?api_password=${encodeURIComponent(mediaFlowConfig.apiPassword)}`,
+ mediaFlowUrl
+ ).toString(),
+ {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ signal: AbortSignal.timeout(5000),
+ }
+ );
if (!response.ok) {
throw new Error(`${response.status}: ${response.statusText}`);
@@ -90,14 +116,10 @@ export async function getMediaFlowPublicIp(mediaFlowConfig: Config["mediaFlowCon
const data = await response.json();
const publicIp = data.ip;
return publicIp;
-
} catch (error: any) {
- console.error(`|ERR| mediaflow > getMediaFlowPublicIp > Failed to get public IP from MediaFlow - ${error.message}`);
+ console.error(
+ `|ERR| mediaflow > getMediaFlowPublicIp > Failed to get public IP from MediaFlow - ${error.message}`
+ );
return null;
}
-
-
-
-
-
-}
\ No newline at end of file
+}
diff --git a/packages/utils/src/settings.ts b/packages/utils/src/settings.ts
index cbf2955c..e08a688d 100644
--- a/packages/utils/src/settings.ts
+++ b/packages/utils/src/settings.ts
@@ -7,32 +7,71 @@ try {
console.error('Error loading .env file:', error);
}
-
export class Settings {
public static readonly ADDON_NAME = process.env.ADDON_NAME ?? 'AIOStreams';
- public static readonly ADDON_ID = process.env.ADDON_ID ?? 'aiostreams.viren070.com';
+ public static readonly ADDON_ID =
+ process.env.ADDON_ID ?? 'aiostreams.viren070.com';
public static readonly PORT = process.env.PORT ?? 3000;
- public static readonly BRANDING = process.env.BRANDING ?? process.env.NEXT_PUBLIC_ELFHOSTED_BRANDING
+ public static readonly BRANDING =
+ process.env.BRANDING ?? process.env.NEXT_PUBLIC_ELFHOSTED_BRANDING;
public static readonly SECRET_KEY = process.env.SECRET_KEY ?? '';
- public static readonly COMET_URL = process.env.COMET_URL ?? 'https://comet.elfhosted.com/';
- public static readonly MEDIAFUSION_URL = process.env.MEDIAFUSION_URL ?? 'https://mediafusion.elfhosted.com/';
- public static readonly TORRENTIO_URL = process.env.TORRENTIO_URL ?? 'https://torrentio.strem.fun/';
- public static readonly TORBOX_STREMIO_URL = process.env.TORBOX_STREMIO_URL ?? 'https://stremio.torbox.app/';
- public static readonly EASYNEWS_URL = process.env.EASYNEWS_URL ?? 'https://ea627ddf0ee7-easynews.baby-beamup.club/';
- public static readonly EASYNEWS_PLUS_URL = process.env.EASYNEWS_PLUS_URL ?? 'https://b89262c192b0-stremio-easynews-addon.baby-beamup.club/';
- public static readonly MAX_ADDONS = process.env.MAX_ADDONS ? parseInt(process.env.MAX_ADDONS) : 15;
- public static readonly MAX_MOVIE_SIZE = process.env.MAX_MOVIE_SIZE ? parseInt(process.env.MAX_MOVIE_SIZE) : 150000000000; // 150GB
- public static readonly MAX_EPISODE_SIZE = process.env.MAX_EPISODE_SIZE ? parseInt(process.env.MAX_EPISODE_SIZE) : 15000000000; // 15GB
- public static readonly MAX_TIMEOUT = process.env.MAX_TIMEOUT ? parseInt(process.env.MAX_TIMEOUT) : 50000;
- public static readonly MIN_TIMEOUT = process.env.MIN_TIMEOUT ? parseInt(process.env.MIN_TIMEOUT) : 1000;
- public static readonly DEFAULT_TIMEOUT = process.env.DEFAULT_TIMEOUT ? parseInt(process.env.DEFAULT_TIMEOUT) : 15000;
- public static readonly DEFAULT_TORRENTIO_TIMEOUT = process.env.DEFAULT_TORRENTIO_TIMEOUT ? parseInt(process.env.DEFAULT_TORRENTIO_TIMEOUT) : 5000;
- public static readonly DEFAULT_TORBOX_TIMEOUT = process.env.DEFAULT_TORBOX_TIMEOUT ? parseInt(process.env.DEFAULT_TORBOX_TIMEOUT) : 15000;
- public static readonly DEFAULT_COMET_TIMEOUT = process.env.DEFAULT_COMET_TIMEOUT ? parseInt(process.env.DEFAULT_COMET_TIMEOUT) : 15000;
- public static readonly DEFAULT_MEDIAFUSION_TIMEOUT = process.env.DEFAULT_MEDIAFUSION_TIMEOUT ? parseInt(process.env.DEFAULT_MEDIAFUSION_TIMEOUT) : 15000;
- public static readonly DEFAULT_EASYNEWS_TIMEMOUT = process.env.DEFAULT_EASYNEWS_TIMEMOUT ? parseInt(process.env.DEFAULT_EASYNEWS_TIMEMOUT) : 15000;
- public static readonly DEFAULT_EASYNEWS_PLUS_TIMEMOUT = process.env.DEFAULT_EASYNEWS_PLUS_TIMEMOUT ? parseInt(process.env.DEFAULT_EASYNEWS_PLUS_TIMEMOUT) : 15000;
- public static readonly SHOW_DIE = process.env.SHOW_DIE ? process.env.SHOW_DIE === 'true' : true;
+ public static readonly COMET_URL =
+ process.env.COMET_URL ?? 'https://comet.elfhosted.com/';
+ public static readonly MEDIAFUSION_URL =
+ process.env.MEDIAFUSION_URL ?? 'https://mediafusion.elfhosted.com/';
+ public static readonly TORRENTIO_URL =
+ process.env.TORRENTIO_URL ?? 'https://torrentio.strem.fun/';
+ public static readonly TORBOX_STREMIO_URL =
+ process.env.TORBOX_STREMIO_URL ?? 'https://stremio.torbox.app/';
+ public static readonly EASYNEWS_URL =
+ process.env.EASYNEWS_URL ??
+ 'https://ea627ddf0ee7-easynews.baby-beamup.club/';
+ public static readonly EASYNEWS_PLUS_URL =
+ process.env.EASYNEWS_PLUS_URL ??
+ 'https://b89262c192b0-stremio-easynews-addon.baby-beamup.club/';
+ public static readonly MAX_ADDONS = process.env.MAX_ADDONS
+ ? parseInt(process.env.MAX_ADDONS)
+ : 15;
+ public static readonly MAX_MOVIE_SIZE = process.env.MAX_MOVIE_SIZE
+ ? parseInt(process.env.MAX_MOVIE_SIZE)
+ : 150000000000; // 150GB
+ public static readonly MAX_EPISODE_SIZE = process.env.MAX_EPISODE_SIZE
+ ? parseInt(process.env.MAX_EPISODE_SIZE)
+ : 15000000000; // 15GB
+ public static readonly MAX_TIMEOUT = process.env.MAX_TIMEOUT
+ ? parseInt(process.env.MAX_TIMEOUT)
+ : 50000;
+ public static readonly MIN_TIMEOUT = process.env.MIN_TIMEOUT
+ ? parseInt(process.env.MIN_TIMEOUT)
+ : 1000;
+ public static readonly DEFAULT_TIMEOUT = process.env.DEFAULT_TIMEOUT
+ ? parseInt(process.env.DEFAULT_TIMEOUT)
+ : 15000;
+ public static readonly DEFAULT_TORRENTIO_TIMEOUT = process.env
+ .DEFAULT_TORRENTIO_TIMEOUT
+ ? parseInt(process.env.DEFAULT_TORRENTIO_TIMEOUT)
+ : 5000;
+ public static readonly DEFAULT_TORBOX_TIMEOUT = process.env
+ .DEFAULT_TORBOX_TIMEOUT
+ ? parseInt(process.env.DEFAULT_TORBOX_TIMEOUT)
+ : 15000;
+ public static readonly DEFAULT_COMET_TIMEOUT = process.env
+ .DEFAULT_COMET_TIMEOUT
+ ? parseInt(process.env.DEFAULT_COMET_TIMEOUT)
+ : 15000;
+ public static readonly DEFAULT_MEDIAFUSION_TIMEOUT = process.env
+ .DEFAULT_MEDIAFUSION_TIMEOUT
+ ? parseInt(process.env.DEFAULT_MEDIAFUSION_TIMEOUT)
+ : 15000;
+ public static readonly DEFAULT_EASYNEWS_TIMEMOUT = process.env
+ .DEFAULT_EASYNEWS_TIMEMOUT
+ ? parseInt(process.env.DEFAULT_EASYNEWS_TIMEMOUT)
+ : 15000;
+ public static readonly DEFAULT_EASYNEWS_PLUS_TIMEMOUT = process.env
+ .DEFAULT_EASYNEWS_PLUS_TIMEMOUT
+ ? parseInt(process.env.DEFAULT_EASYNEWS_PLUS_TIMEMOUT)
+ : 15000;
+ public static readonly SHOW_DIE = process.env.SHOW_DIE
+ ? process.env.SHOW_DIE === 'true'
+ : true;
}
-
-
diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json
index 511d8bf0..15094e48 100644
--- a/packages/utils/tsconfig.json
+++ b/packages/utils/tsconfig.json
@@ -1,8 +1,7 @@
{
- "extends": "../../tsconfig.base.json",
- "compilerOptions": {
- "outDir": "dist",
- "rootDir": "src"
- }
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "rootDir": "src"
}
-
\ No newline at end of file
+}
diff --git a/packages/wrappers/src/base.ts b/packages/wrappers/src/base.ts
index 5f1e44a4..8e31599d 100644
--- a/packages/wrappers/src/base.ts
+++ b/packages/wrappers/src/base.ts
@@ -6,7 +6,11 @@ import {
Config,
} from '@aiostreams/types';
import { extractSizeInBytes, parseFilename } from '@aiostreams/parser';
-import { getMediaFlowPublicIp, serviceDetails, Settings } from '@aiostreams/utils';
+import {
+ getMediaFlowPublicIp,
+ serviceDetails,
+ Settings,
+} from '@aiostreams/utils';
export class BaseWrapper {
private readonly streamPath: string = 'stream/{type}/{id}.json';
@@ -69,20 +73,28 @@ export class BaseWrapper {
if (this.userConfig.requestingIp) {
headers.set('X-Forwarded-For', this.userConfig.requestingIp);
headers.set('X-Real-IP', this.userConfig.requestingIp);
- }
+ }
if (this.userConfig.mediaFlowConfig?.mediaFlowEnabled) {
- const mediaFlowIp = await getMediaFlowPublicIp(this.userConfig.mediaFlowConfig);
+ const mediaFlowIp = await getMediaFlowPublicIp(
+ this.userConfig.mediaFlowConfig
+ );
if (mediaFlowIp) {
- console.log(`|DBG| wrappers > base > Forwarding IP from MediaFlow to ${this.addonName}`);
+ console.log(
+ `|DBG| wrappers > base > Forwarding IP from MediaFlow to ${this.addonName}`
+ );
headers.set('X-Forwarded-For', mediaFlowIp);
headers.set('X-Real-IP', mediaFlowIp);
}
} else {
- console.log(`|DBG| wrappers > base > Forwarding IP from request to ${this.addonName}`);
+ console.log(
+ `|DBG| wrappers > base > Forwarding IP from request to ${this.addonName}`
+ );
}
const urlParts = url.split('/');
const sanitisedUrl = `${urlParts[0]}//${urlParts[2]}/*************/${urlParts.slice(-3).join('/')}`;
- console.log(`|INF| wrappers > base > ${this.addonName}: GET ${sanitisedUrl}`);
+ console.log(
+ `|INF| wrappers > base > ${this.addonName}: GET ${sanitisedUrl}`
+ );
const response = await fetch(url, {
headers: headers,
signal: controller.signal,
@@ -127,7 +139,9 @@ export class BaseWrapper {
size: size,
url: stream.url,
externalUrl: stream.externalUrl,
- _infoHash: stream.infoHash || (stream.url ? (stream.url.match(/[a-fA-F0-9]{40}/)?.[0]) : undefined),
+ _infoHash:
+ stream.infoHash ||
+ (stream.url ? stream.url.match(/[a-fA-F0-9]{40}/)?.[0] : undefined),
torrent: {
infoHash: stream.infoHash,
fileIdx: stream.fileIdx,
@@ -145,12 +159,14 @@ export class BaseWrapper {
behaviorHints: {
countryWhitelist: stream.behaviorHints?.countryWhitelist,
notWebReady: stream.behaviorHints?.notWebReady,
- proxyHeaders: stream.behaviorHints?.proxyHeaders?.request || stream.behaviorHints?.proxyHeaders?.response
- ? {
- request: stream.behaviorHints?.proxyHeaders?.request,
- response: stream.behaviorHints?.proxyHeaders?.response,
- }
- : undefined,
+ proxyHeaders:
+ stream.behaviorHints?.proxyHeaders?.request ||
+ stream.behaviorHints?.proxyHeaders?.response
+ ? {
+ request: stream.behaviorHints?.proxyHeaders?.request,
+ response: stream.behaviorHints?.proxyHeaders?.response,
+ }
+ : undefined,
videoHash: stream.behaviorHints?.videoHash,
},
},
@@ -165,7 +181,9 @@ export class BaseWrapper {
let description = stream.description || stream.title;
if (!filename && description) {
- console.log(`|DBG| wrappers > base > parseStream: No filename found in behaviorHints, attempting to parse from description`);
+ console.log(
+ `|DBG| wrappers > base > parseStream: No filename found in behaviorHints, attempting to parse from description`
+ );
const lines = description.split('\n');
filename =
lines.find(
@@ -174,9 +192,13 @@ export class BaseWrapper {
/(? base > parseStream: With description: ${description}, found filename: ${filename}`);
+ console.log(
+ `|DBG| wrappers > base > parseStream: With description: ${description}, found filename: ${filename}`
+ );
} else if (!description) {
- console.log(`|WRN| wrappers > base > parseStream: No description found, filename could not be determined`);
+ console.log(
+ `|WRN| wrappers > base > parseStream: No description found, filename could not be determined`
+ );
}
let parsedInfo: ParsedNameData = parseFilename(filename || '');
@@ -187,11 +209,9 @@ export class BaseWrapper {
stream.behaviorHints?.videoSize ||
stream.size ||
stream.sizebytes ||
- description && extractSizeInBytes(description, 1024) ||
- stream.name && extractSizeInBytes(stream.name, 1024) ||
+ (description && extractSizeInBytes(description, 1024)) ||
+ (stream.name && extractSizeInBytes(stream.name, 1024)) ||
undefined;
-
-
// look for seeders
let seeders: string | undefined;
@@ -202,10 +222,10 @@ export class BaseWrapper {
// look for indexer
let indexer: string | undefined;
if (description) {
- const indexerMatch = RegExp(/[๐โ๏ธ๐] ([^\s\p{Emoji_Presentation}]+(?:\s[^\s\p{Emoji_Presentation}]+)*)/u).exec(
- description || ''
- );
- indexer = indexerMatch ? indexerMatch[1] : undefined
+ const indexerMatch = RegExp(
+ /[๐โ๏ธ๐] ([^\s\p{Emoji_Presentation}]+(?:\s[^\s\p{Emoji_Presentation}]+)*)/u
+ ).exec(description || '');
+ indexer = indexerMatch ? indexerMatch[1] : undefined;
}
// look for providers
diff --git a/packages/wrappers/src/comet.ts b/packages/wrappers/src/comet.ts
index 884c6ae3..a44e79f3 100644
--- a/packages/wrappers/src/comet.ts
+++ b/packages/wrappers/src/comet.ts
@@ -21,8 +21,7 @@ export class Comet extends BaseWrapper {
) {
let url = overrideUrl
? overrideUrl
- : Settings.COMET_URL +
- (configString ? configString + '/' : '');
+ : Settings.COMET_URL + (configString ? configString + '/' : '');
super(addonName, url, indexerTimeout, addonId, userConfig);
}
@@ -45,7 +44,10 @@ export class Comet extends BaseWrapper {
const debridMatch = RegExp(/^\[([a-zA-Z]{2})(\โก)\]/).exec(stream.name!);
const debrid = debridMatch
? {
- id: serviceDetails.find((service) => service.knownNames.includes(debridMatch[1]))?.id || debridMatch[1],
+ id:
+ serviceDetails.find((service) =>
+ service.knownNames.includes(debridMatch[1])
+ )?.id || debridMatch[1],
cached: debridMatch[2] === 'โก',
}
: undefined;
@@ -96,7 +98,7 @@ export async function getCometStreams(
overrideName?: string;
},
streamRequest: StreamRequest,
- addonId: string,
+ addonId: string
): Promise {
const supportedServices: string[] =
addonDetails.find((addon: AddonDetail) => addon.id === 'comet')
@@ -114,15 +116,14 @@ export async function getCometStreams(
indexerTimeout,
cometOptions.overrideName,
addonId,
- config,
+ config
);
return comet.getParsedStreams(streamRequest);
}
// find all usable and enabled services
const usableServices = config.services.filter(
- (service) =>
- supportedServices.includes(service.id) && service.enabled
+ (service) => supportedServices.includes(service.id) && service.enabled
);
// if no usable services found, throw an error
diff --git a/packages/wrappers/src/easynews.ts b/packages/wrappers/src/easynews.ts
index ba741b77..3d7e76e2 100644
--- a/packages/wrappers/src/easynews.ts
+++ b/packages/wrappers/src/easynews.ts
@@ -1,11 +1,14 @@
import { AddonDetail, ParsedNameData, StreamRequest } from '@aiostreams/types';
-import { parseFilename, extractSizeInBytes, extractDurationInMs } from '@aiostreams/parser';
+import {
+ parseFilename,
+ extractSizeInBytes,
+ extractDurationInMs,
+} from '@aiostreams/parser';
import { ParsedStream, Stream, Config } from '@aiostreams/types';
import { BaseWrapper } from './base';
import { addonDetails, serviceDetails } from '@aiostreams/utils';
import { Settings } from '@aiostreams/utils';
-
export class Easynews extends BaseWrapper {
constructor(
configString: string | null,
@@ -17,26 +20,26 @@ export class Easynews extends BaseWrapper {
) {
let url = overrideUrl
? overrideUrl
- : Settings.EASYNEWS_URL +
- (configString ? configString + '/' : '');
+ : Settings.EASYNEWS_URL + (configString ? configString + '/' : '');
super(addonName, url, indexerTimeout, addonId, userConfig);
}
protected parseStream(stream: Stream): ParsedStream {
- const [filename, sizeString, durationString] = stream.description?.split('\n') || [];
+ const [filename, sizeString, durationString] =
+ stream.description?.split('\n') || [];
const parsedFilename: ParsedNameData = parseFilename(
filename || stream.description || ''
);
const sizeInBytes = stream.description
- ? extractSizeInBytes(sizeString, 1024)
- : undefined;
+ ? extractSizeInBytes(sizeString, 1024)
+ : undefined;
const provider = {
- id: 'easynews',
- cached: true,
- }
+ id: 'easynews',
+ cached: true,
+ };
const durationInMs = extractDurationInMs(durationString || '');
@@ -56,7 +59,7 @@ export class Easynews extends BaseWrapper {
}
const getEasynewsConfigString = (username: string, password: string) => {
- return `%7B%22username%22%3A%22${username}%22%2C%22password%22%3A%22${password}%22%7D`
+ return `%7B%22username%22%3A%22${username}%22%2C%22password%22%3A%22${password}%22%7D`;
};
export async function getEasynewsStreams(
@@ -67,29 +70,37 @@ export async function getEasynewsStreams(
indexerTimeout?: string;
},
streamRequest: StreamRequest,
- addonId: string,
+ addonId: string
): Promise {
-
// look for the 'easynews' id in the services array and destructure the username and password
// if we cant find it, throw an error
- const easynewsService = serviceDetails.find((service) => service.id === 'easynews');
+ const easynewsService = serviceDetails.find(
+ (service) => service.id === 'easynews'
+ );
if (!easynewsService) {
throw new Error('Easynews service not found');
}
-
+
// check for the presence of the username and password in teh easynewsService.credentials object
// if not found, throw an error
- const credentails = config.services.find((service) => service.id === 'easynews')?.credentials;
+ const credentails = config.services.find(
+ (service) => service.id === 'easynews'
+ )?.credentials;
if (!credentails || !credentails.username || !credentails.password) {
throw new Error('Easynews credentials not found');
}
- const easynewsConfigString = getEasynewsConfigString(credentails.username, credentails.password);
+ const easynewsConfigString = getEasynewsConfigString(
+ credentails.username,
+ credentails.password
+ );
const easynews = new Easynews(
easynewsConfigString,
easynewsOptions.overrideUrl ?? null,
- easynewsOptions.indexerTimeout ? parseInt(easynewsOptions.indexerTimeout) : undefined,
+ easynewsOptions.indexerTimeout
+ ? parseInt(easynewsOptions.indexerTimeout)
+ : undefined,
easynewsOptions.overrideName,
addonId,
config
diff --git a/packages/wrappers/src/easynewsPlus.ts b/packages/wrappers/src/easynewsPlus.ts
index 7b60e49a..0d5a6064 100644
--- a/packages/wrappers/src/easynewsPlus.ts
+++ b/packages/wrappers/src/easynewsPlus.ts
@@ -1,11 +1,14 @@
import { AddonDetail, ParsedNameData, StreamRequest } from '@aiostreams/types';
-import { parseFilename, extractSizeInBytes, extractDurationInMs } from '@aiostreams/parser';
+import {
+ parseFilename,
+ extractSizeInBytes,
+ extractDurationInMs,
+} from '@aiostreams/parser';
import { ParsedStream, Stream, Config } from '@aiostreams/types';
import { BaseWrapper } from './base';
import { addonDetails, serviceDetails } from '@aiostreams/utils';
import { Settings } from '@aiostreams/utils';
-
export class EasynewsPlus extends BaseWrapper {
constructor(
configString: string | null,
@@ -17,28 +20,28 @@ export class EasynewsPlus extends BaseWrapper {
) {
let url = overrideUrl
? overrideUrl
- : Settings.EASYNEWS_PLUS_URL +
- (configString ? configString + '/' : '');
+ : Settings.EASYNEWS_PLUS_URL + (configString ? configString + '/' : '');
super(addonName, url, indexerTimeout, addonId, userConfig);
}
protected parseStream(stream: Stream): ParsedStream {
- const [filename, durationString, sizeString] = stream.description?.split('\n') || [];
+ const [filename, durationString, sizeString] =
+ stream.description?.split('\n') || [];
const parsedFilename: ParsedNameData = parseFilename(
filename || stream.description || ''
);
- const sizeInBytes = stream.behaviorHints?.videoSize
- ? stream.behaviorHints.videoSize
- : sizeString
+ const sizeInBytes = stream.behaviorHints?.videoSize
+ ? stream.behaviorHints.videoSize
+ : sizeString
? extractSizeInBytes(sizeString, 1024)
: undefined;
const provider = {
- id: 'easynews',
- cached: true,
- }
+ id: 'easynews',
+ cached: true,
+ };
const durationInMs = extractDurationInMs(durationString || '');
@@ -58,7 +61,7 @@ export class EasynewsPlus extends BaseWrapper {
}
const getEasynewsPlusConfigString = (username: string, password: string) => {
- return `%7B%22username%22%3A%22${username}%22%2C%22password%22%3A%22${password}%22%2C%22sort1%22%3A%22Size%22%2C%22sort1Direction%22%3A%22Descending%22%2C%22sort2%22%3A%22Relevance%22%2C%22sort2Direction%22%3A%22Descending%22%2C%22sort3%22%3A%22Date%20%26%20Time%22%2C%22sort3Direction%22%3A%22Descending%22%7D`
+ return `%7B%22username%22%3A%22${username}%22%2C%22password%22%3A%22${password}%22%2C%22sort1%22%3A%22Size%22%2C%22sort1Direction%22%3A%22Descending%22%2C%22sort2%22%3A%22Relevance%22%2C%22sort2Direction%22%3A%22Descending%22%2C%22sort3%22%3A%22Date%20%26%20Time%22%2C%22sort3Direction%22%3A%22Descending%22%7D`;
};
export async function getEasynewsPlusStreams(
@@ -69,29 +72,37 @@ export async function getEasynewsPlusStreams(
indexerTimeout?: string;
},
streamRequest: StreamRequest,
- addonId: string,
+ addonId: string
): Promise {
-
// look for the 'easynews' id in the services array and destructure the username and password
// if we cant find it, throw an error
- const easynewsService = serviceDetails.find((service) => service.id === 'easynews');
+ const easynewsService = serviceDetails.find(
+ (service) => service.id === 'easynews'
+ );
if (!easynewsService) {
throw new Error('Easynews service not found');
}
-
+
// check for the presence of the username and password in teh easynewsService.credentials object
// if not found, throw an error
- const credentails = config.services.find((service) => service.id === 'easynews')?.credentials;
+ const credentails = config.services.find(
+ (service) => service.id === 'easynews'
+ )?.credentials;
if (!credentails || !credentails.username || !credentails.password) {
throw new Error('Easynews credentials not found');
}
- const easynewsPlusConfigString = getEasynewsPlusConfigString(credentails.username, credentails.password);
+ const easynewsPlusConfigString = getEasynewsPlusConfigString(
+ credentails.username,
+ credentails.password
+ );
const easynews = new EasynewsPlus(
easynewsPlusConfigString,
easynewsPlusOptions.overrideUrl ?? null,
- easynewsPlusOptions.indexerTimeout ? parseInt(easynewsPlusOptions.indexerTimeout) : undefined,
+ easynewsPlusOptions.indexerTimeout
+ ? parseInt(easynewsPlusOptions.indexerTimeout)
+ : undefined,
easynewsPlusOptions.overrideName,
addonId,
config
diff --git a/packages/wrappers/src/index.ts b/packages/wrappers/src/index.ts
index 04d44aa6..ffb1e29e 100644
--- a/packages/wrappers/src/index.ts
+++ b/packages/wrappers/src/index.ts
@@ -4,4 +4,4 @@ export * from './torrentio';
export * from './comet';
export * from './mediafusion';
export * from './easynews';
-export * from './easynewsPlus';
\ No newline at end of file
+export * from './easynewsPlus';
diff --git a/packages/wrappers/src/mediafusion.ts b/packages/wrappers/src/mediafusion.ts
index 65faa429..35f55471 100644
--- a/packages/wrappers/src/mediafusion.ts
+++ b/packages/wrappers/src/mediafusion.ts
@@ -16,8 +16,7 @@ export class MediaFusion extends BaseWrapper {
) {
let url = overrideUrl
? overrideUrl
- : Settings.MEDIAFUSION_URL +
- (configString ? configString + '/' : '');
+ : Settings.MEDIAFUSION_URL + (configString ? configString + '/' : '');
super(addonName, url, indexerTimeout, addonId, userConfig);
}
@@ -27,7 +26,11 @@ export class MediaFusion extends BaseWrapper {
stream.behaviorHints?.filename?.trim() ||
stream.description?.split('\n')[0].replace('๐ ', '');
- if (filename && stream.description && filename.includes('Content Warning')) {
+ if (
+ filename &&
+ stream.description &&
+ filename.includes('Content Warning')
+ ) {
filename = stream.description.split('\n').join(' ');
}
@@ -55,9 +58,9 @@ export class MediaFusion extends BaseWrapper {
}
: undefined;
- const indexerMatch = RegExp(/๐ ([^\s\p{Emoji_Presentation}]+(?:\s[^\s\p{Emoji_Presentation}]+)*)/u).exec(
- stream.description || ''
- );
+ const indexerMatch = RegExp(
+ /๐ ([^\s\p{Emoji_Presentation}]+(?:\s[^\s\p{Emoji_Presentation}]+)*)/u
+ ).exec(stream.description || '');
const indexer = indexerMatch ? indexerMatch[1] : undefined;
const seedersMatch = RegExp(/๐ค (\d+)/).exec(stream.description || '');
@@ -65,12 +68,14 @@ export class MediaFusion extends BaseWrapper {
stream.description?.split('\n').forEach((line) => {
if (line.startsWith('๐')) {
- // the line contains the languages separated by ' + '.
+ // the line contains the languages separated by ' + '.
// the languages can either be flag emojis or the language name.
const normaliseLanguage = (lang: string) => {
// convert emojis to language names, and uppercase the first letter of each word
- return (emojiToLanguage(lang) || lang).replace(/\b\w/g, (char) => char.toUpperCase());
- }
+ return (emojiToLanguage(lang) || lang).replace(/\b\w/g, (char) =>
+ char.toUpperCase()
+ );
+ };
const languages = line.replace('๐ ', '').split(' + ');
languages.forEach((lang) => {
const normalisedLanguage = normaliseLanguage(lang);
@@ -104,7 +109,7 @@ export async function getMediafusionStreams(
overrideName?: string;
},
streamRequest: StreamRequest,
- addonId: string,
+ addonId: string
): Promise {
const supportedServices: string[] =
addonDetails.find((addon: AddonDetail) => addon.id === 'mediafusion')
@@ -129,15 +134,12 @@ export async function getMediafusionStreams(
// find all usable and enabled services
const usableServices = config.services.filter(
- (service) =>
- supportedServices.includes(service.id) && service.enabled
+ (service) => supportedServices.includes(service.id) && service.enabled
);
// if no usable services found, use mediafusion without debrid
if (usableServices.length < 1) {
- const configString = await getConfigString(
- getMediaFusionConfig()
- );
+ const configString = await getConfigString(getMediaFusionConfig());
const mediafusion = new MediaFusion(
configString,
null,
@@ -179,9 +181,7 @@ export async function getMediafusionStreams(
debridService.id,
debridService.credentials
);
- const encryptedStr = await getConfigString(
- mediafusionConfig
- );
+ const encryptedStr = await getConfigString(mediafusionConfig);
const mediafusion = new MediaFusion(
encryptedStr,
null,
@@ -204,9 +204,7 @@ export async function getMediafusionStreams(
service.id,
service.credentials
);
- const encryptedStr = await getConfigString(
- mediafusionConfig
- );
+ const encryptedStr = await getConfigString(mediafusionConfig);
const mediafusion = new MediaFusion(
encryptedStr,
null,
@@ -224,11 +222,14 @@ export async function getMediafusionStreams(
return parsedStreams;
}
-const getMediaFusionConfig = (service?: string, credentials: { [key: string]: string } = {}): any => {
+const getMediaFusionConfig = (
+ service?: string,
+ credentials: { [key: string]: string } = {}
+): any => {
return {
streaming_provider: service
? {
- token: !["pikpak"].includes(service) ? credentials.apiKey : undefined,
+ token: !['pikpak'].includes(service) ? credentials.apiKey : undefined,
email: credentials.email,
password: credentials.password,
service: service,
@@ -313,9 +314,7 @@ const getMediaFusionConfig = (service?: string, credentials: { [key: string]: st
};
};
-async function getConfigString(
- data: any
-): Promise {
+async function getConfigString(data: any): Promise {
const encryptUrl = `${Settings.MEDIAFUSION_URL}encrypt-user-data`;
const response = await fetch(encryptUrl, {
method: 'POST',
diff --git a/packages/wrappers/src/torbox.ts b/packages/wrappers/src/torbox.ts
index c0896553..25d824cf 100644
--- a/packages/wrappers/src/torbox.ts
+++ b/packages/wrappers/src/torbox.ts
@@ -46,26 +46,28 @@ export class Torbox extends BaseWrapper {
protected parseStream(stream: TorboxStream): ParsedStream | undefined {
let type = stream.type;
- const [dQuality, dFilename, dSize, dLanguage, dAgeOrSeeders] = stream.description
- .split('\n')
- .map((field: string) => {
+ const [dQuality, dFilename, dSize, dLanguage, dAgeOrSeeders] =
+ stream.description.split('\n').map((field: string) => {
if (field.startsWith('Type')) {
// the last line can either contain only the type or the type and the seeders/age
// we will always return the age or seeders and assign the type to the variable declared outside the map
const parts = field.split('|');
- type = ['torrent', 'usenet', 'web'].includes(type || '') ? type : parts[0].split(':')[1].trim().toLowerCase();
+ type = ['torrent', 'usenet', 'web'].includes(type || '')
+ ? type
+ : parts[0].split(':')[1].trim().toLowerCase();
if (parts.length > 1) {
return parts[1].split(':')[1].trim();
- }
+ }
// since the last line only contains the type, we will return undefined
return undefined;
-
}
const [_, value] = field.split(':');
return value.trim();
});
- const filename = stream.behaviorHints?.filename || dFilename
- const parsedFilename: ParsedNameData = parseFilename(filename || stream.description);
+ const filename = stream.behaviorHints?.filename || dFilename;
+ const parsedFilename: ParsedNameData = parseFilename(
+ filename || stream.description
+ );
/* If the quality from Torbox is not one of the qualities in the Config, they get filtered out
So, for now, we will not update the quality from Torbox
@@ -74,31 +76,47 @@ export class Torbox extends BaseWrapper {
parsedFilename.quality = quality;
}
*/
-
+
const language = stream.language || dLanguage;
const normaliseLanguage = (lang: string) => {
if (lang.toLowerCase() === 'multi audio') {
- return 'Multi';
+ return 'Multi';
}
- return lang.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ');
+ return lang
+ .split(' ')
+ .map(
+ (word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
+ )
+ .join(' ');
};
if (language) {
const normalisedLanguage = normaliseLanguage(language);
- if (normalisedLanguage !== 'Unknown' && !parsedFilename.languages.includes(normalisedLanguage)) {
+ if (
+ normalisedLanguage !== 'Unknown' &&
+ !parsedFilename.languages.includes(normalisedLanguage)
+ ) {
parsedFilename.languages.push(normalisedLanguage);
}
}
// usenet results provide size as a string, we need to convert it to a number
- const validateBehaviorHintSize = (size: string | number | undefined) => typeof size === 'string' ? parseInt(size) : size;
- const sizeInBytes = stream.size || validateBehaviorHintSize(stream.behaviorHints?.videoSize) || (dSize ? extractSizeInBytes(dSize, 1000) : undefined)
-
+ const validateBehaviorHintSize = (size: string | number | undefined) =>
+ typeof size === 'string' ? parseInt(size) : size;
+ const sizeInBytes =
+ stream.size ||
+ validateBehaviorHintSize(stream.behaviorHints?.videoSize) ||
+ (dSize ? extractSizeInBytes(dSize, 1000) : undefined);
+
const provider = {
id: 'torbox',
cached: stream.is_cached,
};
- const seeders = type === 'torrent' ? (stream.seeders || (dAgeOrSeeders ? parseInt(dAgeOrSeeders) : undefined)) : undefined;
+ const seeders =
+ type === 'torrent'
+ ? stream.seeders ||
+ (dAgeOrSeeders ? parseInt(dAgeOrSeeders) : undefined)
+ : undefined;
const age = type === 'usenet' ? dAgeOrSeeders || undefined : undefined;
const parsedStream: ParsedStream = this.createParsedResult(
diff --git a/packages/wrappers/src/torrentio.ts b/packages/wrappers/src/torrentio.ts
index eeda35ac..b3a82191 100644
--- a/packages/wrappers/src/torrentio.ts
+++ b/packages/wrappers/src/torrentio.ts
@@ -2,7 +2,7 @@ import { AddonDetail, ParsedNameData, StreamRequest } from '@aiostreams/types';
import { parseFilename, extractSizeInBytes } from '@aiostreams/parser';
import { ParsedStream, Stream, Config } from '@aiostreams/types';
import { BaseWrapper } from './base';
-import { addonDetails, serviceDetails } from '@aiostreams/utils'
+import { addonDetails, serviceDetails } from '@aiostreams/utils';
import { Settings } from '@aiostreams/utils';
import { emojiToLanguage } from '@aiostreams/formatters';
@@ -17,17 +17,16 @@ export class Torrentio extends BaseWrapper {
) {
let url = overrideUrl
? overrideUrl
- : Settings.TORRENTIO_URL +
- (configString ? configString + '/' : '');
+ : Settings.TORRENTIO_URL + (configString ? configString + '/' : '');
super(addonName, url, indexerTimeout, addonId, userConfig);
}
protected parseStream(stream: Stream): ParsedStream {
- const filename = stream.title
- ? stream.title.split('\n')[0]
+ const filename = stream.title
+ ? stream.title.split('\n')[0]
: stream.behaviorHints?.filename?.trim();
-
+
const parsedFilename: ParsedNameData = parseFilename(filename || '');
const sizeInBytes = stream.title
? extractSizeInBytes(stream.title, 1024)
@@ -37,22 +36,34 @@ export class Torrentio extends BaseWrapper {
);
const debrid = debridMatch
? {
- id: serviceDetails.find((service) => service.knownNames.includes(debridMatch[1]))?.id || debridMatch[1],
+ id:
+ serviceDetails.find((service) =>
+ service.knownNames.includes(debridMatch[1])
+ )?.id || debridMatch[1],
cached: debridMatch[2] === '+',
}
: undefined;
const seedersMatch = RegExp(/๐ค (\d+)/).exec(stream.title!);
const seeders = seedersMatch ? parseInt(seedersMatch[1]) : undefined;
- const indexerMatch = RegExp(/โ๏ธ (.+)/).exec(stream.title?.split('\n')[1] || '');
+ const indexerMatch = RegExp(/โ๏ธ (.+)/).exec(
+ stream.title?.split('\n')[1] || ''
+ );
const indexer = indexerMatch ? indexerMatch[1] : undefined;
const lastLine = stream.title?.split('\n').pop();
- if (lastLine && !(lastLine.includes('๐ค') && lastLine.includes('๐พ') && lastLine.includes('โ๏ธ'))) {
- // this line contains languages separated by ' / '.
+ if (
+ lastLine &&
+ !(
+ lastLine.includes('๐ค') &&
+ lastLine.includes('๐พ') &&
+ lastLine.includes('โ๏ธ')
+ )
+ ) {
+ // this line contains languages separated by ' / '.
const languages = lastLine.split(' / ');
// 'Multi Audio' can be converted to 'Multi'
- // other ones are flag emojis and need to be converted to languages.
+ // other ones are flag emojis and need to be converted to languages.
languages.forEach((language, index) => {
let convertedLanguage = language.trim();
if (convertedLanguage === 'Multi Audio') {
@@ -60,7 +71,9 @@ export class Torrentio extends BaseWrapper {
} else {
convertedLanguage = emojiToLanguage(language) || language;
// uppercase the first letter of each word
- convertedLanguage = convertedLanguage.replace(/\b\w/g, (char) => char.toUpperCase());
+ convertedLanguage = convertedLanguage.replace(/\b\w/g, (char) =>
+ char.toUpperCase()
+ );
}
if (!parsedFilename.languages.includes(convertedLanguage)) {
parsedFilename.languages.push(convertedLanguage);
@@ -115,8 +128,8 @@ export async function getTorrentioStreams(
}
// find all usable services
- const usableServices = config.services.filter((service) =>
- supportedServices.includes(service.id) && service.enabled
+ const usableServices = config.services.filter(
+ (service) => supportedServices.includes(service.id) && service.enabled
);
// if no usable services found, use torrentio without any configuration