Spaces:
Build error
Build error
import { AddonDetail, ParseResult, StreamRequest } from '@aiostreams/types'; | |
import { ParsedStream, Stream, Config } from '@aiostreams/types'; | |
import { BaseWrapper } from './base'; | |
import { addonDetails, createLogger } from '@aiostreams/utils'; | |
import { Settings } from '@aiostreams/utils'; | |
const logger = createLogger('wrappers'); | |
export class Comet extends BaseWrapper { | |
constructor( | |
configString: string | null, | |
overrideUrl: string | null, | |
addonName: string = 'Comet', | |
addonId: string, | |
userConfig: Config, | |
indexerTimeout?: number | |
) { | |
let url = overrideUrl | |
? overrideUrl | |
: Settings.COMET_URL + (configString ? configString + '/' : ''); | |
super( | |
addonName, | |
url, | |
addonId, | |
userConfig, | |
indexerTimeout || Settings.DEFAULT_COMET_TIMEOUT, | |
Settings.DEFAULT_COMET_USER_AGENT | |
? { 'User-Agent': Settings.DEFAULT_COMET_USER_AGENT } | |
: undefined | |
); | |
} | |
protected parseStream(stream: Stream): ParseResult { | |
const parsedStream = super.parseStream(stream); | |
if (stream.url && parsedStream.type === 'stream') { | |
parsedStream.result.filename = stream.description?.split('\n')[0]; | |
if ( | |
Settings.FORCE_COMET_HOSTNAME !== undefined || | |
Settings.FORCE_COMET_PORT !== undefined || | |
Settings.FORCE_COMET_PROTOCOL !== undefined | |
) { | |
// modify the URL according to settings, needed when using a local URL for requests but a public stream URL is needed. | |
const url = new URL(stream.url); | |
if (Settings.FORCE_COMET_PROTOCOL !== undefined) { | |
url.protocol = Settings.FORCE_COMET_PROTOCOL; | |
} | |
if (Settings.FORCE_COMET_PORT !== undefined) { | |
url.port = Settings.FORCE_COMET_PORT.toString(); | |
} | |
if (Settings.FORCE_COMET_HOSTNAME !== undefined) { | |
url.hostname = Settings.FORCE_COMET_HOSTNAME; | |
} | |
parsedStream.result.url = url.toString(); | |
} | |
} | |
return parsedStream; | |
} | |
} | |
const getCometConfig = ( | |
debridService?: string, | |
credentials?: { [key: string]: string } | |
): string => | |
Buffer.from( | |
JSON.stringify({ | |
maxResultsPerResolution: 0, | |
maxSize: 0, | |
cachedOnly: false, | |
removeTrash: false, | |
resultFormat: ['all'], | |
debridService: debridService || 'torrent', | |
debridApiKey: debridService | |
? ['offcloud', 'pikpak'].includes(debridService) | |
? credentials?.email && credentials?.password | |
? `${credentials?.email}:${credentials?.password}` | |
: '' | |
: credentials?.apiKey || '' | |
: '', | |
debridStreamProxyPassword: '', | |
languages: { required: [], exclude: [], preferred: [] }, | |
resolutions: {}, | |
options: { remove_ranks_under: -10000000000 }, | |
}) | |
).toString('base64'); | |
export async function getCometStreams( | |
config: Config, | |
cometOptions: { | |
prioritiseDebrid?: string; | |
overrideUrl?: string; | |
indexerTimeout?: string; | |
overrideName?: string; | |
}, | |
streamRequest: StreamRequest, | |
addonId: string | |
): Promise<{ | |
addonStreams: ParsedStream[]; | |
addonErrors: string[]; | |
}> { | |
const supportedServices: string[] = | |
addonDetails.find((addon: AddonDetail) => addon.id === 'comet') | |
?.supportedServices || []; | |
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, | |
cometOptions.overrideName, | |
addonId, | |
config, | |
indexerTimeout | |
); | |
return await comet.getParsedStreams(streamRequest); | |
} | |
// find all usable and enabled services | |
const usableServices = config.services.filter( | |
(service) => supportedServices.includes(service.id) && service.enabled | |
); | |
// if no usable services found, use comet with default config | |
if (usableServices.length < 1) { | |
const comet = new Comet( | |
getCometConfig(), | |
null, | |
cometOptions.overrideName, | |
addonId, | |
config, | |
indexerTimeout | |
); | |
return await comet.getParsedStreams(streamRequest); | |
} | |
// 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) { | |
throw new Error( | |
'Debrid service API key not found for ' + cometOptions.prioritiseDebrid | |
); | |
} | |
const comet = new Comet( | |
getCometConfig(cometOptions.prioritiseDebrid, debridService.credentials), | |
null, | |
cometOptions.overrideName, | |
addonId, | |
config, | |
indexerTimeout | |
); | |
return await 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'); | |
} | |
const errorMessages: string[] = []; | |
const streamPromises = servicesToUse.map(async (service) => { | |
logger.info(`Getting Comet streams for ${service.id}`, { func: 'comet' }); | |
const comet = new Comet( | |
getCometConfig(service.id, service.credentials), | |
null, | |
cometOptions.overrideName, | |
addonId, | |
config, | |
indexerTimeout | |
); | |
return comet.getParsedStreams(streamRequest); | |
}); | |
const results = await Promise.allSettled(streamPromises); | |
results.forEach((result) => { | |
if (result.status === 'fulfilled') { | |
const streams = result.value; | |
parsedStreams.push(...streams.addonStreams); | |
errorMessages.push(...streams.addonErrors); | |
} else { | |
errorMessages.push(result.reason.message); | |
} | |
}); | |
return { addonStreams: parsedStreams, addonErrors: errorMessages }; | |
} | |