From 4e5714db4465aec50aef4afca7d18965032dc324 Mon Sep 17 00:00:00 2001 From: Viren070 Date: Mon, 30 Dec 2024 14:35:01 +0000 Subject: [PATCH] feat: add comet and improve method of getting choosable addons --- packages/addon/src/addon.ts | 4 + packages/addon/src/config.ts | 53 +++++- packages/frontend/src/app/configure/page.tsx | 15 +- .../src/components/AddonsList.module.css | 1 + .../frontend/src/components/AddonsList.tsx | 17 ++ packages/types/src/types.ts | 9 +- packages/wrappers/src/comet.ts | 175 ++++++++++++++++++ packages/wrappers/src/index.ts | 1 + 8 files changed, 268 insertions(+), 7 deletions(-) create mode 100644 packages/wrappers/src/comet.ts diff --git a/packages/addon/src/addon.ts b/packages/addon/src/addon.ts index 22169c85..82562cb8 100644 --- a/packages/addon/src/addon.ts +++ b/packages/addon/src/addon.ts @@ -1,5 +1,6 @@ import { BaseWrapper, + getCometStreams, getTorboxStreams, getTorrentioStreams, } from '@aiostreams/wrappers'; @@ -315,6 +316,9 @@ export class AIOStreams { streamRequest ); } + case 'comet': { + return await getCometStreams(this.config, addon.options, streamRequest); + } case 'gdrive': { if (!addon.options.addonUrl) { throw new Error('The addon URL was undefined for GDrive'); diff --git a/packages/addon/src/config.ts b/packages/addon/src/config.ts index 7f21fafd..465eac8c 100644 --- a/packages/addon/src/config.ts +++ b/packages/addon/src/config.ts @@ -2,7 +2,7 @@ import { Config } from '@aiostreams/types'; import { AddonDetail } from '@aiostreams/types'; export const allowedFormatters = ['gdrive', 'torrentio', 'torbox']; -export const allowedAddons = ['torrentio', 'torbox', 'gdrive', 'custom']; +export const allowedAddons = ['torrentio', 'comet', 'torbox', 'gdrive', 'custom']; export const MAX_ADDONS = 10; export const MAX_SIZE = 150000000000; // 1500GB @@ -11,6 +11,8 @@ export const addonDetails: AddonDetail[] = [ { name: 'Torrentio', id: 'torrentio', + requiresService: false, + supportedServices: ['realdebrid', 'alldebrid', 'premiumize', 'debridlink', 'torbox', 'offcloud', 'putio'], options: [ { id: 'overrideName', @@ -49,9 +51,54 @@ export const addonDetails: AddonDetail[] = [ ], }, + { + name: 'Comet', + id: 'comet', + requiresService: true, + supportedServices: ['realdebrid', 'alldebrid', 'premiumize', 'debridlink', 'torbox'], + options: [ + { + id: 'prioritiseDebrid', + required: false, + label: 'Prioritise Debrid Service', + description: + 'Prioritise a specific debrid service when fetching streams. This option is useful when you want to use a specific debrid service for fetching streams. By default, the addon will make a separate request for each debrid service. I highly recommend provding a value for this option as it will speed up the fetching process and remove redundant results.', + type: 'select', + options: [{ value: 'realdebrid', label: 'Real Debrid' }, { value: 'alldebrid', label: 'All Debrid' }, { value: 'premiumize', label: 'Premiumize' }, { value: 'debridlink', label: 'Debrid Link' }, { value: 'torbox', label: 'Torbox' }], + }, + { + id: 'overrideName', + required: false, + label: 'Override Addon Name', + description: 'Override the name of the Comet addon that shows up in the results', + type: 'text', + }, + { + id: 'overrideUrl', + required: false, + label: 'Override URL', + description: + 'Override the URL used to fetch streams from the Comet addon. This option is incompatible with the prioritiseDebrid option. By default, the URL is generated based on the selected services and their credentials. Use this option to override the URL with a custom URL.', + type: 'text', + }, + { + id: 'indexerTimeout', + required: false, + label: 'Override Indexer Timeout', + description: '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: 1000, + max: 20000 + } + } + ] + }, { name: 'Torbox', id: 'torbox', + requiresService: true, + supportedServices: ['torbox'], options: [ { id: 'indexerTimeout', @@ -76,6 +123,8 @@ export const addonDetails: AddonDetail[] = [ { name: 'Google Drive (Viren070)', id: 'gdrive', + requiresService: false, + supportedServices: [], options: [ { id: 'addonUrl', @@ -107,6 +156,8 @@ export const addonDetails: AddonDetail[] = [ { name: 'Custom', id: 'custom', + requiresService: false, + supportedServices: [], options: [ { id: 'name', diff --git a/packages/frontend/src/app/configure/page.tsx b/packages/frontend/src/app/configure/page.tsx index 47799324..f898f1c6 100644 --- a/packages/frontend/src/app/configure/page.tsx +++ b/packages/frontend/src/app/configure/page.tsx @@ -188,11 +188,16 @@ export default function Configure() { const getChoosableAddons = () => { // only if torbox service is enabled we can use torbox addon - const choosableAddons: string[] = ['torrentio', 'gdrive', 'custom']; - if ( - services.some((service) => service.enabled && service.id === 'torbox') - ) { - choosableAddons.push('torbox'); + const choosableAddons: string[] = []; + for (const addon of addonDetails) { + if (addon.requiresService) { + // look through services and see if the ID of any service is in addon.supportedServices + if (services.some((service) => addon.supportedServices.includes(service.id) && service.enabled && Object.keys(service.credentials).length > 0)) { + choosableAddons.push(addon.id); + } + } else { + choosableAddons.push(addon.id); + } } return choosableAddons; }; diff --git a/packages/frontend/src/components/AddonsList.module.css b/packages/frontend/src/components/AddonsList.module.css index a54de873..0b0d1b78 100644 --- a/packages/frontend/src/components/AddonsList.module.css +++ b/packages/frontend/src/components/AddonsList.module.css @@ -90,6 +90,7 @@ align-items: center; } +.option select, .option input[type='text'], .option input[type='number'] { diff --git a/packages/frontend/src/components/AddonsList.tsx b/packages/frontend/src/components/AddonsList.tsx index 81dbe29e..3695bc15 100644 --- a/packages/frontend/src/components/AddonsList.tsx +++ b/packages/frontend/src/components/AddonsList.tsx @@ -115,6 +115,23 @@ const AddonsList: React.FC = ({ className={styles.textInput} /> )} + {option.type === 'select' && ( + + ) + } {option.type === 'number' && ( { + return { + "indexers": [ + "bitsearch", + "eztv", + "thepiratebay", + "therarbg", + "yts" + ], + "maxResults": 0, + "maxResultsPerResolution": 0, + "maxSize": 0, + "reverseResultOrder": false, + "removeTrash": true, + "resultFormat": [ + "All" + ], + "resolutions": [ + "All" + ], + "languages": [ + "All" + ], + "debridService": debridService, + "debridApiKey": debridApiKey, + "stremthruUrl": "", + "debridStreamProxyPassword": "" + } +} + +export async function getCometStreams( + config: Config, + cometOptions: { + prioritiseDebrid?: string; + overrideUrl?: string; + indexerTimeout?: string; + overrideName?: string; + }, + streamRequest: StreamRequest +): Promise { + const supportedServices: string[] = [ + 'realdebrid', + 'alldebrid', + 'premiumize', + 'torbox', + 'debridlink', + ]; + const parsedStreams: ParsedStream[] = []; + const indexerTimeout = cometOptions.indexerTimeout ? parseInt(cometOptions.indexerTimeout) : undefined; + + // If overrideUrl is provided, use it to get streams and skip all other steps + if (cometOptions.overrideUrl) { + const comet = new Comet(null, cometOptions.overrideUrl as string, indexerTimeout, cometOptions.overrideName); + return comet.getParsedStreams(streamRequest); + } + + // find all usable services + const usableServices = config.services.filter((service) => + supportedServices.includes(service.id) + ); + + // if no usable services found, raise an error + if (usableServices.length < 0) { + throw new Error('No usable services found'); + } + + + // otherwise, depending on the configuration, create multiple instances of comet or use a single instance with the prioritised service + + if (cometOptions.prioritiseDebrid && !supportedServices.includes(cometOptions.prioritiseDebrid)) { + throw new Error('Invalid debrid service'); + } + + if (cometOptions.prioritiseDebrid) { + const debridService = usableServices.find( + (service) => service.id === cometOptions.prioritiseDebrid + ); + if (!debridService) { + throw new Error('Debrid service not found for ' + cometOptions.prioritiseDebrid); + } + if (!debridService.credentials.apiKey) { + throw new Error('Debrid service API key not found for ' + cometOptions.prioritiseDebrid); + } + + // get the comet config and b64 encode it + const cometConfig = getCometConfig(cometOptions.prioritiseDebrid, debridService.credentials.apiKey); + const configString = Buffer.from(JSON.stringify(cometConfig)).toString('base64'); + const comet = new Comet(configString, null, indexerTimeout, cometOptions.overrideName); + + return comet.getParsedStreams(streamRequest); + } + + // if no prioritised service is provided, create a comet instance for each service + const servicesToUse = usableServices.filter((service) => service.enabled); + if (servicesToUse.length < 1) { + throw new Error('No supported service(s) enabled'); + } + for (const service of servicesToUse) { + const cometConfig = getCometConfig(service.id, service.credentials.apiKey); + const configString = Buffer.from(JSON.stringify(cometConfig)).toString('base64'); + const comet = new Comet(configString, null, indexerTimeout, cometOptions.overrideName); + const streams = await comet.getParsedStreams(streamRequest); + parsedStreams.push(...streams); + } + + return parsedStreams; + +} diff --git a/packages/wrappers/src/index.ts b/packages/wrappers/src/index.ts index 48acd2d5..861d97ee 100644 --- a/packages/wrappers/src/index.ts +++ b/packages/wrappers/src/index.ts @@ -1,3 +1,4 @@ export * from './base'; export * from './torbox'; export * from './torrentio'; +export * from './comet'; \ No newline at end of file