From 36ff245a8f8340ae2a18c6ce62a4d48c9e4ea06f Mon Sep 17 00:00:00 2001 From: Viren070 Date: Sun, 27 Apr 2025 15:01:59 +0100 Subject: [PATCH] feat: add easynews++ --- packages/addon/src/addon.ts | 9 +++ packages/utils/src/details.ts | 45 +++++++++++ packages/wrappers/src/easynewsPlusPlus.ts | 96 +++++++++++++++++++++++ packages/wrappers/src/index.ts | 1 + 4 files changed, 151 insertions(+) create mode 100644 packages/wrappers/src/easynewsPlusPlus.ts diff --git a/packages/addon/src/addon.ts b/packages/addon/src/addon.ts index d6b54edd..e13ebe2d 100644 --- a/packages/addon/src/addon.ts +++ b/packages/addon/src/addon.ts @@ -3,6 +3,7 @@ import { getCometStreams, getDebridioStreams, getDMMCastStreams, + getEasynewsPlusPlusStreams, getEasynewsPlusStreams, getEasynewsStreams, getJackettioStreams, @@ -1052,6 +1053,14 @@ export class AIOStreams { addonId ); } + case 'easynews-plus-plus': { + return await getEasynewsPlusStreams( + this.config, + addon.options, + streamRequest, + addonId + ); + } case 'debridio': { return await getDebridioStreams( this.config, diff --git a/packages/utils/src/details.ts b/packages/utils/src/details.ts index 0469c992..8a7dd185 100644 --- a/packages/utils/src/details.ts +++ b/packages/utils/src/details.ts @@ -462,6 +462,51 @@ export const addonDetails: AddonDetail[] = [ }, ], }, + { + name: 'Easynews++', + id: 'easynews-plus-plus', + requiresService: true, + supportedServices: ['easynews'], + options: [ + { + id: 'overrideName', + required: false, + label: 'Override Addon Name', + description: + "Override the name of the addon that shows up in the results. Leave it empty to use the default name of 'Easynews++'.", + type: 'text', + }, + { + id: 'overrideUrl', + secret: true, + required: false, + label: 'Override URL', + description: + 'Override the URL used to fetch streams from the Easynews++ addon. By default, the URL is generated based on the username and password provided for the Easynews service. 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 Easynews++ addon in milliseconds. This is the time in milliseconds that the addon will wait for a response from Easynews Plus before timing out. Leave it empty to use the recommended timeout.', + type: 'number', + constraints: { + min: Settings.MIN_TIMEOUT, + max: Settings.MAX_TIMEOUT, + }, + }, + { + id: 'strictTitleMatching', + required: false, + label: 'Strict Title Matching', + description: + 'Enable strict title matching for Easynews Next. This option will filter out results that do not match the title exactly.', + type: 'checkbox', + }, + ], + }, { name: 'Debridio', id: 'debridio', diff --git a/packages/wrappers/src/easynewsPlusPlus.ts b/packages/wrappers/src/easynewsPlusPlus.ts new file mode 100644 index 00000000..11a08552 --- /dev/null +++ b/packages/wrappers/src/easynewsPlusPlus.ts @@ -0,0 +1,96 @@ +import { ParseResult, StreamRequest } from '@aiostreams/types'; +import { ParsedStream, Stream, Config } from '@aiostreams/types'; +import { BaseWrapper } from './base'; +import { Settings } from '@aiostreams/utils'; + +export class EasynewsPlusPlus extends BaseWrapper { + constructor( + configString: string | null, + overrideUrl: string | null, + addonName: string = 'Easynews++', + addonId: string, + userConfig: Config, + indexerTimeout?: number + ) { + let url = overrideUrl + ? overrideUrl + : Settings.EASYNEWS_PLUS_URL + (configString ? configString + '/' : ''); + + super( + addonName, + url, + addonId, + userConfig, + indexerTimeout || Settings.DEFAULT_EASYNEWS_PLUS_TIMEMOUT + ); + } + + protected parseStream(stream: Stream): ParseResult { + const parseResult = super.parseStream(stream); + if (parseResult.type !== 'error') { + parseResult.result.type = 'usenet'; + } + return parseResult; + } +} + +const getEasynewsPlusPlusConfigString = ( + username: string, + password: string, + strictTitleMatching: boolean = false +) => { + const options = { + uiLanguage: 'eng', + username: username, + password: password, + strictTitleMatching: strictTitleMatching, + preferredLanguage: '', + sortingPreference: 'quality_first', + showQualities: '4k,1080p,720p,480p', + maxResultsPerQuality: '', + maxFileSize: '', + }; + return encodeURIComponent(JSON.stringify(options)); +}; + +export async function getEasynewsPlusPlusStreams( + config: Config, + easynewsPlusOptions: { + overrideName?: string; + overrideUrl?: string; + strictTitleMatching?: boolean; + indexerTimeout?: string; + }, + streamRequest: StreamRequest, + addonId: string +): Promise<{ + addonStreams: ParsedStream[]; + addonErrors: string[]; +}> { + // 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; + if (!credentails || !credentails.username || !credentails.password) { + throw new Error('Easynews credentials not found'); + } + + const easynewsPlusConfigString = getEasynewsPlusPlusConfigString( + credentails.username, + credentails.password + ); + + const easynews = new EasynewsPlusPlus( + easynewsPlusConfigString, + easynewsPlusOptions.overrideUrl ?? null, + easynewsPlusOptions.overrideName, + addonId, + config, + easynewsPlusOptions.indexerTimeout + ? parseInt(easynewsPlusOptions.indexerTimeout) + : undefined + ); + + return await easynews.getParsedStreams(streamRequest); +} diff --git a/packages/wrappers/src/index.ts b/packages/wrappers/src/index.ts index 5e1077cf..2317e369 100644 --- a/packages/wrappers/src/index.ts +++ b/packages/wrappers/src/index.ts @@ -5,6 +5,7 @@ export * from './comet'; export * from './mediafusion'; export * from './easynews'; export * from './easynewsPlus'; +export * from './easynewsPlusPlus'; export * from './debridio'; export * from './jackettio'; export * from './orion';