feat: create utils package and other changes

This commit is contained in:
Viren070
2025-01-04 12:53:48 +00:00
parent 376d4bd4fc
commit fc8a12e792
25 changed files with 452 additions and 96 deletions
+290 -1
View File
@@ -48,6 +48,10 @@
"resolved": "packages/types",
"link": true
},
"node_modules/@aiostreams/utils": {
"resolved": "packages/utils",
"link": true
},
"node_modules/@aiostreams/wrappers": {
"resolved": "packages/wrappers",
"link": true
@@ -2676,6 +2680,12 @@
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
"license": "ISC"
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -2873,6 +2883,57 @@
"node": ">= 16"
}
},
"node_modules/cheerio": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz",
"integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==",
"license": "MIT",
"dependencies": {
"cheerio-select": "^2.1.0",
"dom-serializer": "^2.0.0",
"domhandler": "^5.0.3",
"domutils": "^3.1.0",
"encoding-sniffer": "^0.2.0",
"htmlparser2": "^9.1.0",
"parse5": "^7.1.2",
"parse5-htmlparser2-tree-adapter": "^7.0.0",
"parse5-parser-stream": "^7.1.2",
"undici": "^6.19.5",
"whatwg-mimetype": "^4.0.0"
},
"engines": {
"node": ">=18.17"
},
"funding": {
"url": "https://github.com/cheeriojs/cheerio?sponsor=1"
}
},
"node_modules/cheerio-select": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
"integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
"license": "BSD-2-Clause",
"dependencies": {
"boolbase": "^1.0.0",
"css-select": "^5.1.0",
"css-what": "^6.1.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/cheerio/node_modules/undici": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.0.tgz",
"integrity": "sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==",
"license": "MIT",
"engines": {
"node": ">=18.17"
}
},
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
@@ -3058,6 +3119,34 @@
"dev": true,
"license": "MIT"
},
"node_modules/css-select": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
"license": "BSD-2-Clause",
"dependencies": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
"domhandler": "^5.0.2",
"domutils": "^3.0.1",
"nth-check": "^2.0.1"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/css-what": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">= 6"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -3264,6 +3353,61 @@
"node": ">=0.10.0"
}
},
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "BSD-2-Clause"
},
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/domutils": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.1.tgz",
"integrity": "sha512-xWXmuRnN9OMP6ptPd2+H0cCbcYBULa5YDTbMm/2lvkWvNA3O4wcW+GvzooqBuNM8yy6pl3VIAeJTUUWUbfI5Fw==",
"license": "BSD-2-Clause",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
@@ -3312,6 +3456,31 @@
"node": ">= 0.8"
}
},
"node_modules/encoding-sniffer": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz",
"integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==",
"license": "MIT",
"dependencies": {
"iconv-lite": "^0.6.3",
"whatwg-encoding": "^3.1.1"
},
"funding": {
"url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
}
},
"node_modules/encoding-sniffer/node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/enhanced-resolve": {
"version": "5.18.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz",
@@ -3326,6 +3495,18 @@
"node": ">=10.13.0"
}
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/es-abstract": {
"version": "1.23.7",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.7.tgz",
@@ -4598,6 +4779,25 @@
"node": ">= 0.4"
}
},
"node_modules/htmlparser2": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
"integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==",
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.1.0",
"entities": "^4.5.0"
}
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -5653,6 +5853,18 @@
"node": ">= 10"
}
},
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"license": "BSD-2-Clause",
"dependencies": {
"boolbase": "^1.0.0"
},
"funding": {
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -5866,6 +6078,43 @@
"node": ">=6"
}
},
"node_modules/parse5": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz",
"integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==",
"license": "MIT",
"dependencies": {
"entities": "^4.5.0"
},
"funding": {
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
"node_modules/parse5-htmlparser2-tree-adapter": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
"integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
"license": "MIT",
"dependencies": {
"domhandler": "^5.0.3",
"parse5": "^7.0.0"
},
"funding": {
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
"node_modules/parse5-parser-stream": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
"integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
"license": "MIT",
"dependencies": {
"parse5": "^7.0.0"
},
"funding": {
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -8015,6 +8264,39 @@
}
}
},
"node_modules/whatwg-encoding": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
"license": "MIT",
"dependencies": {
"iconv-lite": "0.6.3"
},
"engines": {
"node": ">=18"
}
},
"node_modules/whatwg-encoding/node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/whatwg-mimetype": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
"integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -8707,7 +8989,9 @@
"dependencies": {
"@aiostreams/formatters": "^1.0.0",
"@aiostreams/types": "^1.0.0",
"@aiostreams/utils": "^1.0.0",
"@aiostreams/wrappers": "^1.0.0",
"cheerio": "^1.0.0",
"dotenv": "^16.4.7",
"express": "^4.21.2"
},
@@ -8785,12 +9069,17 @@
"name": "@aiostreams/types",
"version": "1.5.4"
},
"packages/utils": {
"name": "@aiostreams/utils",
"version": "1.5.4"
},
"packages/wrappers": {
"name": "@aiostreams/wrappers",
"version": "1.5.4",
"devDependencies": {
"@aiostreams/parser": "^1.0.0",
"@aiostreams/types": "^1.0.0"
"@aiostreams/types": "^1.0.0",
"@aiostreams/utils": "^1.0.0"
}
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
"scripts": {
"test": "npm run test --workspaces",
"format": "prettier --write .",
"build": "npm -w packages/types run build && npm -w packages/parser run build && npm -w packages/wrappers run build && npm -w packages/formatters run build && npm -w packages/addon run build && npm -w packages/frontend run build",
"build": "npm -w packages/types run build && npm -w packages/utils run build && npm -w packages/parser run build && npm -w packages/wrappers run build && npm -w packages/formatters run build && npm -w packages/addon run build && npm -w packages/frontend run build",
"build:watch": "tsc --build --watch",
"start:addon": "npm -w packages/addon start",
"start:addon:dev": "npm -w packages/addon run start:dev",
+2
View File
@@ -14,7 +14,9 @@
"dependencies": {
"@aiostreams/formatters": "^1.0.0",
"@aiostreams/types": "^1.0.0",
"@aiostreams/utils": "^1.0.0",
"@aiostreams/wrappers": "^1.0.0",
"cheerio": "^1.0.0",
"dotenv": "^16.4.7",
"express": "^4.21.2"
},
+2 -4
View File
@@ -17,7 +17,7 @@ import {
torrentioFormat,
torboxFormat,
} from '@aiostreams/formatters';
import Settings from './settings';
import { Settings } from '@aiostreams/utils';
export class AIOStreams {
private config: Config;
@@ -197,7 +197,7 @@ export class AIOStreams {
externalUrl: parsedStream.externalUrl,
infoHash: parsedStream.torrent?.infoHash,
fileIdx: parsedStream.torrent?.fileIdx,
name: "🎲 " + name,
name: Settings.SHOW_DIE ? `🎲 ${name}` : name,
description: description,
subtitles: parsedStream.stream?.subtitles,
sources: parsedStream.torrent?.sources,
@@ -384,7 +384,6 @@ export class AIOStreams {
addon.options,
streamRequest,
addonId,
Settings.COMET_URL
);
}
case 'mediafusion': {
@@ -393,7 +392,6 @@ export class AIOStreams {
addon.options,
streamRequest,
addonId,
Settings.MEDIAFUSION_URL
);
}
case 'gdrive': {
+3 -7
View File
@@ -1,12 +1,8 @@
import { AddonDetail, Config } from '@aiostreams/types';
import { addonDetails, serviceDetails } from '@aiostreams/wrappers';
import { addonDetails, serviceDetails, Settings } from '@aiostreams/utils';
export const allowedFormatters = ['gdrive', 'torrentio', 'torbox'];
export const MAX_ADDONS = 15;
export const MAX_MOVIE_SIZE = 150000000000; // 150GB
export const MAX_EPISODE_SIZE = 15000000000; // 15GB
export const allowedLanguages = [
'English',
'Japanese',
@@ -249,11 +245,11 @@ export function validateConfig(config: Config): {
);
}
if (config.addons.length > MAX_ADDONS) {
if (config.addons.length > Settings.MAX_ADDONS) {
return createResponse(
false,
'tooManyAddons',
`You can only select a maximum of ${MAX_ADDONS} addons`
`You can only select a maximum of ${Settings.MAX_ADDONS} addons`
);
}
-1
View File
@@ -2,4 +2,3 @@ export * from './addon';
export * from './config';
export * from './manifest';
export * from './responses';
export * from './crypto';
+47 -8
View File
@@ -1,15 +1,34 @@
import express, { Request, Response } from 'express';
import path from 'path';
import fs from 'fs';
import {load} from 'cheerio';
import { AIOStreams } from './addon';
import { Config, StreamRequest } from '@aiostreams/types';
import { validateConfig } from './config';
import { getManifest } from './manifest';
import { invalidConfig, missingConfig } from './responses';
import { compressAndEncrypt, decryptAndDecompress } from './crypto';
import Settings from './settings';
import {Settings, compressAndEncrypt, decryptAndDecompress} from '@aiostreams/utils';
const app = express();
console.log('PORT:', Settings.PORT);
console.log('SECRET_KEY:', Settings.SECRET_KEY ? 'Set' : 'Not Set');
console.log('COMET_URL:', Settings.COMET_URL);
console.log('MEDIAFUSION_URL:', Settings.MEDIAFUSION_URL);
console.log('MAX_ADDONS:', Settings.MAX_ADDONS);
console.log('MAX_MOVIE_SIZE:', Settings.MAX_MOVIE_SIZE);
console.log('MAX_EPISODE_SIZE:', Settings.MAX_EPISODE_SIZE);
console.log('MAX_TIMEOUT:', Settings.MAX_TIMEOUT);
console.log('MIN_TIMEOUT:', Settings.MIN_TIMEOUT);
console.log('SHOW_DIE:', Settings.SHOW_DIE);
console.log('BRANDING:', Settings.BRANDING ? 'Set' : 'Not Set');
if (!Settings.SECRET_KEY) {
console.warn('You have not set a SECRET_KEY, you will not be able to use encrypted configs');
}
const rootUrl = (req: Request) =>
`${req.protocol}://${req.hostname}${req.hostname === 'localhost' ? `:${Settings.PORT}` : ''}`;
@@ -25,18 +44,39 @@ app.use((req, res, next) => {
next();
});
app.use(express.static(path.join(__dirname, '../../frontend/out')));
//app.use(express.static(path.join(__dirname, '../../frontend/out')));
app.get(['/_next/*', '/assets/*'], (req, res) => {
res.sendFile(path.join(__dirname, '../../frontend/out', req.path));
});
app.get('/', (req, res) => {
res.redirect('/configure');
});
const sendModifiedHtml = (res: Response, filePath: string) => {
fs.readFile(filePath, 'utf8', (err, html) => {
if (err) {
console.error('Failed to read HTML file', err);
res.status(500).send('Internal Server Error');
return;
}
const $ = load(html);
if (Settings.BRANDING) {
$('[id*="BrandingDiv"]').html(Settings.BRANDING);
}
res.send($.html());
});
};
app.get('/configure', (req, res) => {
res.sendFile(path.join(__dirname, '../../frontend/out/configure.html'));
const filePath = path.join(__dirname, '../../frontend/out/configure.html');
sendModifiedHtml(res, filePath);
});
app.get('/:config/configure', (req, res) => {
// if the config starts with E- , decrypt it and redirect to base64 encoded config
const config = req.params.config;
if (config.startsWith("E-")) {
const encryptedConfig = config.replace('E-', '');
@@ -44,7 +84,6 @@ app.get('/:config/configure', (req, res) => {
const iv = Buffer.from(ivHex, 'hex');
const encrypted = Buffer.from(encryptedHex, 'hex');
const decryptedData = decryptAndDecompress(encrypted, iv);
// edit out any API keys from the decrypted data
const configJson = JSON.parse(decryptedData);
if (configJson.services) {
configJson.services.forEach((service: any) => {
@@ -57,10 +96,10 @@ app.get('/:config/configure', (req, res) => {
res.redirect(`/${base64Config}/configure`);
return;
}
res.sendFile(path.join(__dirname, '../../frontend/out/configure.html'));
const filePath = path.join(__dirname, '../../frontend/out/configure.html');
sendModifiedHtml(res, filePath);
});
app.get('/manifest.json', (req, res) => {
res.status(200).json(getManifest(false));
});
-19
View File
@@ -1,19 +0,0 @@
import dotenv from 'dotenv';
import path from 'path';
try {
dotenv.config({ path: path.resolve(__dirname, '../../../.env') });
} catch (error) {
console.error('Error loading .env file');
}
class Settings {
public static readonly PORT = process.env.PORT || 3000;
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/';
}
export default Settings;
+3
View File
@@ -14,6 +14,9 @@
},
{
"path": "../types"
},
{
"path": "../utils"
}
]
}
+21 -13
View File
@@ -22,10 +22,8 @@ import {
allowedFormatters,
allowedLanguages,
validateConfig,
MAX_EPISODE_SIZE,
MAX_MOVIE_SIZE,
} from '@aiostreams/config';
import { addonDetails, serviceDetails } from '@aiostreams/wrappers';
import { addonDetails, serviceDetails, Settings } from '@aiostreams/utils';
import Slider from '@/components/Slider';
@@ -154,6 +152,7 @@ export default function Configure() {
const [minEpisodeSize, setMinEpisodeSize] = useState<number | null>(null);
const [disableButtons, setDisableButtons] = useState<boolean>(false);
const [branding, setBranding] = useState<string | null>(null);
const getChoosableAddons = () => {
// only if torbox service is enabled we can use torbox addon
@@ -471,6 +470,12 @@ export default function Configure() {
}
const path = window.location.pathname;
const brandingDiv = document.getElementById('BrandingDiv');
console.log('BrandingDiv', brandingDiv);
console.log('BrandingDiv innerHTML', brandingDiv?.innerHTML);
if (brandingDiv) {
setBranding(brandingDiv.innerHTML);
}
try {
const configMatch = path.match(/\/([^/]+)\/configure/);
@@ -495,10 +500,13 @@ export default function Configure() {
style={{ alignSelf: 'center', justifyContent: 'center' }}
/>
<h1 style={{ textAlign: 'center' }}>AIOStreams v{version}</h1>
{process.env.NEXT_PUBLIC_ELFHOSTED_BRANDING && (
<div className={styles.branding} dangerouslySetInnerHTML={{ __html: process.env.NEXT_PUBLIC_ELFHOSTED_BRANDING }}>
</div>
)}
{process.env.NEXT_PUBLIC_ELFHOSTED_BRANDING && (
<div className={styles.branding} id="BrandingDiv" suppressHydrationWarning dangerouslySetInnerHTML={{ __html: process.env.NEXT_PUBLIC_ELFHOSTED_BRANDING }} />
)}
<div className={styles.branding} id="BrandingDiv" suppressHydrationWarning dangerouslySetInnerHTML={{ __html: branding || '' }} />
<p style={{ textAlign: 'center', padding: '15px' }}>
AIOStreams, the all-in-one streaming addon for Stremio. Combine your
streams from all your addons into one and filter them by resolution,
@@ -632,7 +640,7 @@ export default function Configure() {
</div>
<div className={styles.slidersContainer}>
<Slider
maxValue={MAX_MOVIE_SIZE}
maxValue={Settings.MAX_MOVIE_SIZE}
value={minMovieSize || 0}
setValue={setMinMovieSize}
defaultValue="min"
@@ -642,8 +650,8 @@ export default function Configure() {
Minimum movie size: {formatSize(minMovieSize || 0)}
</div>
<Slider
maxValue={MAX_MOVIE_SIZE}
value={maxMovieSize === null ? MAX_MOVIE_SIZE : maxMovieSize}
maxValue={Settings.MAX_MOVIE_SIZE}
value={maxMovieSize === null ? Settings.MAX_MOVIE_SIZE : maxMovieSize}
setValue={setMaxMovieSize}
defaultValue="max"
id="maxMovieSizeSlider"
@@ -653,7 +661,7 @@ export default function Configure() {
{maxMovieSize === null ? 'Unlimited' : formatSize(maxMovieSize)}
</div>
<Slider
maxValue={MAX_EPISODE_SIZE}
maxValue={Settings.MAX_EPISODE_SIZE}
value={minEpisodeSize || 0}
setValue={setMinEpisodeSize}
defaultValue="min"
@@ -663,9 +671,9 @@ export default function Configure() {
Minimum episode size: {formatSize(minEpisodeSize || 0)}
</div>
<Slider
maxValue={MAX_EPISODE_SIZE}
maxValue={Settings.MAX_EPISODE_SIZE}
value={
maxEpisodeSize === null ? MAX_EPISODE_SIZE : maxEpisodeSize
maxEpisodeSize === null ? Settings.MAX_EPISODE_SIZE : maxEpisodeSize
}
setValue={setMaxEpisodeSize}
defaultValue="max"
+3
View File
@@ -34,6 +34,9 @@
},
{
"path": "../wrappers"
},
{
"path": "../utils"
}
],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+11
View File
@@ -0,0 +1,11 @@
{
"name": "@aiostreams/utils",
"version": "1.5.4",
"main": "./dist/index.js",
"scripts": {
"test": "vitest run --passWithNoTests",
"build": "tsc"
},
"description": "Library to parse a torrent filename "
}
@@ -1,6 +1,6 @@
import { randomBytes, createCipheriv, createDecipheriv } from 'crypto';
import { deflateSync, inflateSync } from 'zlib';
import Settings from './settings';
import {Settings} from './settings';
const pad = (data: Buffer, blockSize: number): Buffer => {
const padding = blockSize - (data.length % blockSize);
@@ -1,7 +1,6 @@
import { AddonDetail } from '@aiostreams/types';
import {Settings} from './settings';
const MAX_TIMEOUT = 40000;
const MIN_TIMEOUT = 1000;
export const addonDetails: AddonDetail[] = [
{
@@ -50,8 +49,8 @@ export const addonDetails: AddonDetail[] = [
'The timeout for fetching streams from the Torrentio addon. This is the time in milliseconds that the addon will wait for a response before timing out. Leave it empty to use the recommended timeout.',
type: 'number',
constraints: {
min: MIN_TIMEOUT,
max: MAX_TIMEOUT,
min: Settings.MIN_TIMEOUT,
max: Settings.MAX_TIMEOUT,
},
},
],
@@ -107,8 +106,8 @@ export const addonDetails: AddonDetail[] = [
'The timeout for fetching streams from the Comet addon. This is the time in milliseconds that the addon will wait for a response before timing out. Leave it empty to use the recommended timeout.',
type: 'number',
constraints: {
min: MIN_TIMEOUT,
max: MAX_TIMEOUT,
min: Settings.MIN_TIMEOUT,
max: Settings.MAX_TIMEOUT,
},
},
],
@@ -168,8 +167,8 @@ export const addonDetails: AddonDetail[] = [
'The timeout for fetching streams from the Media Fusion addon. This is the time in milliseconds that the addon will wait for a response before timing out. Leave it empty to use the recommended timeout.',
type: 'number',
constraints: {
min: MIN_TIMEOUT,
max: MAX_TIMEOUT,
min: Settings.MIN_TIMEOUT,
max: Settings.MAX_TIMEOUT,
},
},
],
@@ -188,8 +187,8 @@ export const addonDetails: AddonDetail[] = [
'The timeout for fetching streams from the Torbox addon. This is the time in milliseconds that the addon will wait for a response from Torbox before timing out. Leave it empty to use the recommended timeout.',
type: 'number',
constraints: {
min: MIN_TIMEOUT,
max: MAX_TIMEOUT,
min: Settings.MIN_TIMEOUT,
max: Settings.MAX_TIMEOUT,
},
},
{
@@ -232,8 +231,8 @@ export const addonDetails: AddonDetail[] = [
'The timeout for fetching streams from the Google Drive addon in milliseconds. This is the time in milliseconds that the addon will wait for a response from your Cloudflare Worker before timing out. Leave it empty to use the recommended timeout.',
type: 'number',
constraints: {
min: MIN_TIMEOUT,
max: MAX_TIMEOUT,
min: Settings.MIN_TIMEOUT,
max: Settings.MAX_TIMEOUT,
},
},
],
@@ -268,8 +267,8 @@ export const addonDetails: AddonDetail[] = [
'The timeout for fetching streams from the custom addon in milliseconds',
type: 'number',
constraints: {
min: MIN_TIMEOUT,
max: MAX_TIMEOUT,
min: Settings.MIN_TIMEOUT,
max: Settings.MAX_TIMEOUT,
},
},
],
+3
View File
@@ -0,0 +1,3 @@
export * from './crypto';
export * from './details';
export * from './settings';
+25
View File
@@ -0,0 +1,25 @@
import dotenv from 'dotenv';
import path from 'path';
try {
dotenv.config({ path: path.resolve(__dirname, '../../../.env') });
} catch (error) {
console.error('Error loading .env file:', error);
}
export class Settings {
public static readonly PORT = process.env.PORT ? process.env.PORT : 3000;
public static readonly 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 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) : 40000;
public static readonly MIN_TIMEOUT = process.env.MIN_TIMEOUT ? parseInt(process.env.MIN_TIMEOUT) : 1000;
public static readonly SHOW_DIE = process.env.SHOW_DIE ? process.env.SHOW_DIE === 'true' : true;
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
}
}
+2 -1
View File
@@ -9,6 +9,7 @@
"description": "Library with wrappers for different addons",
"devDependencies": {
"@aiostreams/parser": "^1.0.0",
"@aiostreams/types": "^1.0.0"
"@aiostreams/types": "^1.0.0",
"@aiostreams/utils": "^1.0.0"
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ import {
ParsedNameData,
} from '@aiostreams/types';
import { extractSizeInBytes, parseFilename } from '@aiostreams/parser';
import { serviceDetails } from './details';
import { serviceDetails } from '@aiostreams/utils';
export class BaseWrapper {
private readonly streamPath: string = 'stream/{type}/{id}.json';
+5 -9
View File
@@ -2,7 +2,8 @@ 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 } from './details';
import { addonDetails } from '@aiostreams/utils';
import { Settings } from '@aiostreams/utils';
interface CometStream extends Stream {
torrentTitle?: string;
@@ -16,11 +17,10 @@ export class Comet extends BaseWrapper {
indexerTimeout: number = 10000,
addonName: string = 'Comet',
addonId: string,
cometUrl: string
) {
let url = overrideUrl
? overrideUrl
: cometUrl +
: Settings.COMET_URL +
(configString ? configString + '/' : '');
super(addonName, url, indexerTimeout, addonId);
@@ -96,7 +96,6 @@ export async function getCometStreams(
},
streamRequest: StreamRequest,
addonId: string,
cometUrl: string
): Promise<ParsedStream[]> {
const supportedServices: string[] =
addonDetails.find((addon: AddonDetail) => addon.id === 'comet')
@@ -114,7 +113,6 @@ export async function getCometStreams(
indexerTimeout,
cometOptions.overrideName,
addonId,
cometUrl
);
return comet.getParsedStreams(streamRequest);
}
@@ -166,8 +164,7 @@ export async function getCometStreams(
null,
indexerTimeout,
cometOptions.overrideName,
addonId,
cometUrl
addonId
);
return comet.getParsedStreams(streamRequest);
@@ -188,8 +185,7 @@ export async function getCometStreams(
null,
indexerTimeout,
cometOptions.overrideName,
addonId,
cometUrl
addonId
);
const streams = await comet.getParsedStreams(streamRequest);
parsedStreams.push(...streams);
-1
View File
@@ -1,4 +1,3 @@
export * from './details';
export * from './base';
export * from './torbox';
export * from './torrentio';
+4 -14
View File
@@ -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 './details';
import { addonDetails, serviceDetails, Settings } from '@aiostreams/utils';
export class MediaFusion extends BaseWrapper {
constructor(
@@ -11,11 +11,10 @@ export class MediaFusion extends BaseWrapper {
indexerTimeout: number = 10000,
addonName: string = 'MediaFusion',
addonId: string,
mediafusionUrl: string,
) {
let url = overrideUrl
? overrideUrl
: mediafusionUrl +
: Settings.MEDIAFUSION_URL +
(configString ? configString + '/' : '');
super(addonName, url, indexerTimeout, addonId);
@@ -82,7 +81,6 @@ export async function getMediafusionStreams(
},
streamRequest: StreamRequest,
addonId: string,
mediafusionUrl: string,
): Promise<ParsedStream[]> {
const supportedServices: string[] =
addonDetails.find((addon: AddonDetail) => addon.id === 'mediafusion')
@@ -100,7 +98,6 @@ export async function getMediafusionStreams(
indexerTimeout,
mediafusionOptions.overrideName,
addonId,
mediafusionUrl
);
return mediafusion.getParsedStreams(streamRequest);
}
@@ -111,9 +108,8 @@ export async function getMediafusionStreams(
);
// if no usable services found, use mediafusion without debrid
if (usableServices.length < 0) {
if (config.services.length < 0) {
const configString = await getConfigString(
'https://mediafusion.elfhosted.com/',
getMediaFusionConfig()
);
const mediafusion = new MediaFusion(
@@ -122,7 +118,6 @@ export async function getMediafusionStreams(
indexerTimeout,
mediafusionOptions.overrideName,
addonId,
mediafusionUrl
);
return mediafusion.getParsedStreams(streamRequest);
}
@@ -158,7 +153,6 @@ export async function getMediafusionStreams(
debridService.credentials.apiKey
);
const encryptedStr = await getConfigString(
'https://mediafusion.elfhosted.com/',
mediafusionConfig
);
const mediafusion = new MediaFusion(
@@ -167,7 +161,6 @@ export async function getMediafusionStreams(
indexerTimeout,
mediafusionOptions.overrideName,
addonId,
mediafusionUrl
);
return mediafusion.getParsedStreams(streamRequest);
@@ -184,7 +177,6 @@ export async function getMediafusionStreams(
service.credentials.apiKey
);
const encryptedStr = await getConfigString(
mediafusionUrl,
mediafusionConfig
);
const mediafusion = new MediaFusion(
@@ -193,7 +185,6 @@ export async function getMediafusionStreams(
indexerTimeout,
mediafusionOptions.overrideName,
addonId,
mediafusionUrl
);
const streams = await mediafusion.getParsedStreams(streamRequest);
parsedStreams.push(...streams);
@@ -290,10 +281,9 @@ const getMediaFusionConfig = (service?: string, token?: string) => {
};
async function getConfigString(
baseUrl: string = 'https://mediafusion.elfhosted.com/',
data: any
): Promise<string> {
const encryptUrl = `${baseUrl}encrypt-user-data`;
const encryptUrl = `${Settings.MEDIAFUSION_URL}encrypt-user-data`;
const response = await fetch(encryptUrl, {
method: 'POST',
+1 -1
View File
@@ -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 } from './details';
import { addonDetails } from '@aiostreams/utils';
export class Torrentio extends BaseWrapper {
constructor(
+3
View File
@@ -12,6 +12,9 @@
},
{
"path": "../types"
},
{
"path": "../utils"
}
]
}
+3
View File
@@ -18,6 +18,9 @@
},
{
"path": "./packages/frontend"
},
{
"path": "./packages/utils"
}
]
}