diff --git a/.env.sample b/.env.sample index 37a73757..2f01384e 100644 --- a/.env.sample +++ b/.env.sample @@ -84,6 +84,11 @@ BUILTIN_GET_TORRENT_TIMEOUT=5000 # Higher values will increase search times but use more system resources. BUILTIN_GET_TORRENT_CONCURRENCY=100 + +# ---- Bitmagnet ---- +# Enter the URL of a bitmagnet instance to enable the Bitmagnet addon in the marketplace. +# BUILTIN_BITMAGNET_URL= + # ---- Prowlarr ------ # Optionally provide a default prowlarr URL and API Key here. Users cannot see the values set here. # BUILTIN_PROWLARR_URL= @@ -91,6 +96,7 @@ BUILTIN_GET_TORRENT_CONCURRENCY=100 # Optionally provide a comma separated list of indexers to limit the addon to use. If not provided, it uses all indexers. # You may also limit the indexers used by adding a tag with the name "aiostreams" to the indexers in Prowlarr. # BUILTIN_PROWLARR_INDEXERS= +# BUILTIN_DEFAULT_PROWLARR_TIMEOUT= # The timeout for search requests. BUILTIN_PROWLARR_SEARCH_TIMEOUT= # How long specific responses should be cached for. @@ -140,11 +146,11 @@ BUILTIN_NAB_CAPABILITIES_CACHE_TTL=1209600 # --- Zilean --- BUILTIN_ZILEAN_URL="https://zilean.elfhosted.com" -# BUILTIN_ZILEAN_TIMEOUT= +# BUILTIN_DEFAULT_ZILEAN_TIMEOUT= # --- AnimeTosho --- BUILTIN_ANIMETOSHO_URL="https://feed.animetosho.org" -# BUILTIN_ANIMETOSHO_TIMEOUT= +# BUILTIN_DEFAULT_ANIMETOSHO_TIMEOUT= # ============================================================================= diff --git a/packages/core/src/presets/animetosho.ts b/packages/core/src/presets/animetosho.ts index d7eb2166..3923efec 100644 --- a/packages/core/src/presets/animetosho.ts +++ b/packages/core/src/presets/animetosho.ts @@ -11,7 +11,7 @@ export class AnimeToshoPreset extends TorznabPreset { ...baseOptions( 'AnimeTosho', supportedResources, - Env.BUILTIN_ANIMETOSHO_TIMEOUT || Env.DEFAULT_TIMEOUT + Env.BUILTIN_DEFAULT_ANIMETOSHO_TIMEOUT || Env.DEFAULT_TIMEOUT ).filter((option) => option.id !== 'url' && option.id !== 'resources'), { id: 'services', @@ -35,7 +35,7 @@ export class AnimeToshoPreset extends TorznabPreset { NAME: 'AnimeTosho', LOGO: '/assets/animetosho_logo.png', URL: Env.BUILTIN_ANIMETOSHO_URL, - TIMEOUT: Env.BUILTIN_ANIMETOSHO_TIMEOUT || Env.DEFAULT_TIMEOUT, + TIMEOUT: Env.BUILTIN_DEFAULT_ANIMETOSHO_TIMEOUT || Env.DEFAULT_TIMEOUT, USER_AGENT: Env.DEFAULT_USER_AGENT, SUPPORTED_SERVICES: StremThruPreset.supportedServices, DESCRIPTION: 'Directly search AnimeTosho.', diff --git a/packages/core/src/presets/bitmagnet.ts b/packages/core/src/presets/bitmagnet.ts new file mode 100644 index 00000000..3543630a --- /dev/null +++ b/packages/core/src/presets/bitmagnet.ts @@ -0,0 +1,78 @@ +import { Option, UserData } from '../db/index.js'; +import { Env, constants } from '../utils/index.js'; +import { StremThruPreset } from './stremthru.js'; +import { TorznabPreset } from './torznab.js'; + +export class BitmagnetPreset extends TorznabPreset { + static override get METADATA() { + const supportedResources = [constants.STREAM_RESOURCE]; + const options: Option[] = [ + { + id: 'name', + name: 'Name', + description: 'What to call this addon', + type: 'string', + required: true, + default: 'Bitmagnet', + }, + { + id: 'timeout', + name: 'Timeout', + description: 'The timeout for this addon', + type: 'number', + required: true, + default: Env.BUILTIN_DEFAULT_BITMAGNET_TIMEOUT || Env.DEFAULT_TIMEOUT, + }, + { + id: 'services', + name: 'Services', + description: + 'Optionally override the services that are used. If not specified, then the services that are enabled and supported will be used.', + type: 'multi-select', + required: false, + showInNoobMode: false, + options: StremThruPreset.supportedServices.map((service) => ({ + value: service, + label: constants.SERVICE_DETAILS[service].name, + })), + default: undefined, + emptyIsUndefined: true, + }, + ]; + + return { + ID: 'bitmagnet', + NAME: 'Bitmagnet', + LOGO: 'https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/bitmagnet.png', + URL: `${Env.INTERNAL_URL}/builtins/torznab`, + TIMEOUT: Env.BUILTIN_DEFAULT_BITMAGNET_TIMEOUT || Env.DEFAULT_TIMEOUT, + USER_AGENT: Env.DEFAULT_USER_AGENT, + SUPPORTED_SERVICES: StremThruPreset.supportedServices, + DESCRIPTION: 'Directly search a Bitmagnet instance.', + OPTIONS: options, + SUPPORTED_STREAM_TYPES: [constants.DEBRID_STREAM_TYPE], + SUPPORTED_RESOURCES: supportedResources, + BUILTIN: true, + }; + } + + protected static override generateManifestUrl( + userData: UserData, + services: constants.ServiceId[], + options: Record + ): string { + if (!Env.BUILTIN_BITMAGNET_URL) { + throw new Error('The Bitmagnet URL is not set'); + } + + const config = { + ...this.getBaseConfig(userData, services), + url: `${Env.BUILTIN_BITMAGNET_URL.replace(/\/$/, '')}/torznab`, + apiPath: '/api', + forceQuerySearch: true, + }; + + const configString = this.base64EncodeJSON(config); + return `${Env.INTERNAL_URL}/builtins/torznab/${configString}/manifest.json`; + } +} diff --git a/packages/core/src/presets/jackett.ts b/packages/core/src/presets/jackett.ts index 58b0db82..a7e58ff5 100644 --- a/packages/core/src/presets/jackett.ts +++ b/packages/core/src/presets/jackett.ts @@ -21,7 +21,7 @@ export class JackettPreset extends TorznabPreset { description: 'The timeout for this addon', type: 'number', required: true, - default: Env.BUILTIN_JACKETT_TIMEOUT || Env.DEFAULT_TIMEOUT, + default: Env.BUILTIN_DEFAULT_JACKETT_TIMEOUT || Env.DEFAULT_TIMEOUT, }, { id: 'services', @@ -71,7 +71,7 @@ export class JackettPreset extends TorznabPreset { NAME: 'Jackett', LOGO: 'https://raw.githubusercontent.com/Jackett/Jackett/refs/heads/master/src/Jackett.Common/Content/jacket_medium.png', URL: `${Env.INTERNAL_URL}/builtins/torznab`, - TIMEOUT: Env.BUILTIN_JACKETT_TIMEOUT || Env.DEFAULT_TIMEOUT, + TIMEOUT: Env.BUILTIN_DEFAULT_JACKETT_TIMEOUT || Env.DEFAULT_TIMEOUT, USER_AGENT: Env.DEFAULT_USER_AGENT, SUPPORTED_SERVICES: StremThruPreset.supportedServices, DESCRIPTION: 'Directly search a Jackett instance.', diff --git a/packages/core/src/presets/knaben.ts b/packages/core/src/presets/knaben.ts index bbb7ef84..a71a7fa1 100644 --- a/packages/core/src/presets/knaben.ts +++ b/packages/core/src/presets/knaben.ts @@ -21,7 +21,7 @@ export class KnabenPreset extends TorznabPreset { description: 'The timeout for this addon', type: 'number', required: true, - default: Env.BUILTIN_KNABEN_TIMEOUT || Env.DEFAULT_TIMEOUT, + default: Env.BUILTIN_DEFAULT_KNABEN_TIMEOUT || Env.DEFAULT_TIMEOUT, }, { id: 'services', @@ -45,7 +45,7 @@ export class KnabenPreset extends TorznabPreset { NAME: 'Knaben', LOGO: '/assets/knaben_logo.png', URL: `${Env.INTERNAL_URL}/builtins/knaben`, - TIMEOUT: Env.BUILTIN_KNABEN_TIMEOUT || Env.DEFAULT_TIMEOUT, + TIMEOUT: Env.BUILTIN_DEFAULT_KNABEN_TIMEOUT || Env.DEFAULT_TIMEOUT, USER_AGENT: Env.DEFAULT_USER_AGENT, SUPPORTED_SERVICES: StremThruPreset.supportedServices, DESCRIPTION: 'Directly search Knaben for results with your services.', diff --git a/packages/core/src/presets/nzbhydra.ts b/packages/core/src/presets/nzbhydra.ts index 017c2332..39c50654 100644 --- a/packages/core/src/presets/nzbhydra.ts +++ b/packages/core/src/presets/nzbhydra.ts @@ -20,7 +20,7 @@ export class NZBHydraPreset extends NewznabPreset { name: 'Timeout', description: 'The timeout for this addon', type: 'number', - default: Env.BUILTIN_NZBHYDRA_TIMEOUT, + default: Env.BUILTIN_DEFAULT_NZBHYDRA_TIMEOUT, constraints: { min: Env.MIN_TIMEOUT, max: Env.MAX_TIMEOUT, @@ -61,7 +61,7 @@ export class NZBHydraPreset extends NewznabPreset { NAME: 'NZBHydra', LOGO: 'https://raw.githubusercontent.com/theotherp/nzbhydra2/refs/heads/master/core/ui-src/img/logo.png', URL: `${Env.INTERNAL_URL}/builtins/newznab`, - TIMEOUT: Env.BUILTIN_NZBHYDRA_TIMEOUT || Env.DEFAULT_TIMEOUT, + TIMEOUT: Env.BUILTIN_DEFAULT_NZBHYDRA_TIMEOUT || Env.DEFAULT_TIMEOUT, USER_AGENT: Env.DEFAULT_USER_AGENT, SUPPORTED_SERVICES: [constants.TORBOX_SERVICE], DESCRIPTION: diff --git a/packages/core/src/presets/presetManager.ts b/packages/core/src/presets/presetManager.ts index 348fe69c..ced88007 100644 --- a/packages/core/src/presets/presetManager.ts +++ b/packages/core/src/presets/presetManager.ts @@ -62,6 +62,7 @@ import { ProwlarrPreset } from './prowlarr.js'; import { JackettPreset } from './jackett.js'; import { NZBHydraPreset } from './nzbhydra.js'; import { KnabenPreset } from './knaben.js'; +import { BitmagnetPreset } from './bitmagnet.js'; let PRESET_LIST: string[] = [ 'custom', @@ -75,6 +76,7 @@ let PRESET_LIST: string[] = [ 'stremthruStore', 'zilean', 'knaben', + Env.BUILTIN_BITMAGNET_URL ? 'bitmagnet' : '', 'animetosho', 'prowlarr', 'jackett', @@ -268,6 +270,8 @@ export class PresetManager { return NZBHydraPreset; case 'knaben': return KnabenPreset; + case 'bitmagnet': + return BitmagnetPreset; default: throw new Error(`Preset ${id} not found`); } diff --git a/packages/core/src/presets/zilean.ts b/packages/core/src/presets/zilean.ts index 5c362427..4eecdead 100644 --- a/packages/core/src/presets/zilean.ts +++ b/packages/core/src/presets/zilean.ts @@ -11,7 +11,7 @@ export class ZileanPreset extends TorznabPreset { ...baseOptions( 'Zilean', supportedResources, - Env.BUILTIN_ZILEAN_TIMEOUT || Env.DEFAULT_TIMEOUT + Env.BUILTIN_DEFAULT_ZILEAN_TIMEOUT || Env.DEFAULT_TIMEOUT ).filter((option) => option.id !== 'url' && option.id !== 'resources'), { id: 'url', @@ -42,7 +42,7 @@ export class ZileanPreset extends TorznabPreset { NAME: 'Zilean', LOGO: '/assets/zilean_logo.jpg', URL: Env.BUILTIN_ZILEAN_URL, - TIMEOUT: Env.BUILTIN_ZILEAN_TIMEOUT || Env.DEFAULT_TIMEOUT, + TIMEOUT: Env.BUILTIN_DEFAULT_ZILEAN_TIMEOUT || Env.DEFAULT_TIMEOUT, USER_AGENT: Env.DEFAULT_USER_AGENT, SUPPORTED_SERVICES: StremThruPreset.supportedServices, DESCRIPTION: 'Directly search a Zilean instance.', diff --git a/packages/core/src/utils/env.ts b/packages/core/src/utils/env.ts index 8f24d598..12227308 100644 --- a/packages/core/src/utils/env.ts +++ b/packages/core/src/utils/env.ts @@ -1665,7 +1665,7 @@ export const Env = cleanEnv(process.env, { default: 'https://zilean.elfhosted.com', desc: 'Builtin Zilean URL', }), - BUILTIN_ZILEAN_TIMEOUT: num({ + BUILTIN_DEFAULT_ZILEAN_TIMEOUT: num({ default: undefined, desc: 'Builtin Zilean timeout', }), @@ -1674,11 +1674,20 @@ export const Env = cleanEnv(process.env, { default: 'https://feed.animetosho.org', desc: 'Builtin AnimeTosho URL', }), - BUILTIN_ANIMETOSHO_TIMEOUT: num({ + BUILTIN_DEFAULT_ANIMETOSHO_TIMEOUT: num({ default: undefined, desc: 'Builtin AnimeTosho timeout', }), + BUILTIN_BITMAGNET_URL: url({ + default: undefined, + desc: 'Builtin Bitmagnet URL', + }), + BUILTIN_DEFAULT_BITMAGNET_TIMEOUT: num({ + default: undefined, + desc: 'Builtin Bitmagnet timeout', + }), + BUILTIN_JACKETT_URL: url({ default: undefined, desc: 'Builtin Jackett URL', @@ -1687,7 +1696,7 @@ export const Env = cleanEnv(process.env, { default: undefined, desc: 'Builtin Jackett API Key', }), - BUILTIN_JACKETT_TIMEOUT: num({ + BUILTIN_DEFAULT_JACKETT_TIMEOUT: num({ default: undefined, desc: 'Builtin Jackett timeout', }), @@ -1700,7 +1709,7 @@ export const Env = cleanEnv(process.env, { default: undefined, desc: 'Builtin NZBHydra API Key', }), - BUILTIN_NZBHYDRA_TIMEOUT: num({ + BUILTIN_DEFAULT_NZBHYDRA_TIMEOUT: num({ default: undefined, desc: 'Builtin NZBHydra timeout', }), @@ -1717,6 +1726,10 @@ export const Env = cleanEnv(process.env, { default: undefined, desc: 'Comma separated list of prowlarr indexers to use.', }), + BUILTIN_DEFAULT_PROWLARR_TIMEOUT: num({ + default: undefined, + desc: 'Default timeout for the builtin Prowlarr addon.', + }), BUILTIN_PROWLARR_SEARCH_TIMEOUT: num({ default: 30000, // 30 seconds desc: 'Builtin Prowlarr Search timeout', @@ -1730,7 +1743,7 @@ export const Env = cleanEnv(process.env, { desc: 'Builtin Prowlarr Indexers cache TTL', }), - BUILTIN_KNABEN_TIMEOUT: num({ + BUILTIN_DEFAULT_KNABEN_TIMEOUT: num({ default: undefined, desc: 'Builtin Knaben timeout', }), diff --git a/packages/core/src/utils/startup.ts b/packages/core/src/utils/startup.ts index 1ea8199b..3900faff 100644 --- a/packages/core/src/utils/startup.ts +++ b/packages/core/src/utils/startup.ts @@ -518,6 +518,10 @@ const logStartupInfo = () => { 'TMDB API Key:', Env.TMDB_API_KEY ? '✅ Configured' : '❌ None' ); + logKeyValue( + 'TVDB API Key:', + Env.TVDB_API_KEY ? '✅ Configured' : '❌ None' + ); logKeyValue( 'Trakt Client ID:', Env.TRAKT_CLIENT_ID ? '✅ Configured' : '❌ None' @@ -543,6 +547,22 @@ const logStartupInfo = () => { ' ' ); + // Bitmagnet + logKeyValue( + 'Bitmagnet:', + Env.BUILTIN_BITMAGNET_URL ? '✅ Configured' : '❌ None' + ); + if (Env.BUILTIN_BITMAGNET_URL) { + logKeyValue(' URL:', Env.BUILTIN_BITMAGNET_URL, ' '); + } + if (Env.BUILTIN_DEFAULT_BITMAGNET_TIMEOUT) { + logKeyValue( + ' Default Timeout:', + formatMilliseconds(Env.BUILTIN_DEFAULT_BITMAGNET_TIMEOUT), + ' ' + ); + } + // Prowlarr const prowlarrSearchEnabled = Env.BUILTIN_PROWLARR_URL && Env.BUILTIN_PROWLARR_API_KEY; @@ -583,19 +603,19 @@ const logStartupInfo = () => { // animetosho logKeyValue('AnimeTosho:', Env.BUILTIN_ANIMETOSHO_URL); - if (Env.BUILTIN_ANIMETOSHO_TIMEOUT) { + if (Env.BUILTIN_DEFAULT_ANIMETOSHO_TIMEOUT) { logKeyValue( - ' Timeout:', - formatMilliseconds(Env.BUILTIN_ANIMETOSHO_TIMEOUT), + ' Default Timeout:', + formatMilliseconds(Env.BUILTIN_DEFAULT_ANIMETOSHO_TIMEOUT), ' ' ); } logKeyValue('Zilean', Env.BUILTIN_ZILEAN_URL); - if (Env.BUILTIN_ZILEAN_TIMEOUT) { + if (Env.BUILTIN_DEFAULT_ZILEAN_TIMEOUT) { logKeyValue( - ' Timeout:', - formatMilliseconds(Env.BUILTIN_ZILEAN_TIMEOUT), + ' Default Timeout:', + formatMilliseconds(Env.BUILTIN_DEFAULT_ZILEAN_TIMEOUT), ' ' ); }