diff --git a/src/error/index.ts b/src/error/index.ts index 7eb30ce..31f374d 100644 --- a/src/error/index.ts +++ b/src/error/index.ts @@ -1,3 +1,12 @@ +import winston from 'winston'; +import { BlockedReason, Context } from '../types'; +import { BlockedError } from './BlockedError'; +import { HttpError } from './HttpError'; +import { QueueIsFullError } from './QueueIsFullError'; +import { TimeoutError } from './TimeoutError'; +import { TooManyRequestsError } from './TooManyRequestsError'; +import { TooManyTimeoutsError } from './TooManyTimeoutsError'; + export * from './BlockedError'; export * from './HttpError'; export * from './NotFoundError'; @@ -5,3 +14,58 @@ export * from './QueueIsFullError'; export * from './TimeoutError'; export * from './TooManyRequestsError'; export * from './TooManyTimeoutsError'; + +export const logErrorAndReturnNiceString = (ctx: Context, logger: winston.Logger, source: string, error: unknown): string => { + if (error instanceof BlockedError) { + if (error.reason === BlockedReason.cloudflare_challenge) { + logger.warn(`${source}: Request was blocked via Cloudflare challenge.`, ctx); + } else if (error.reason === BlockedReason.cloudflare_censor) { + logger.warn(`${source}: Request was censored by Cloudflare.`, ctx); + } else if (error.reason === BlockedReason.media_flow_proxy_auth) { + return '⚠️ MediaFlow Proxy authentication failed. Please set the correct password.'; + } else { + logger.warn(`${source}: Request was blocked, headers: ${JSON.stringify(error.headers)}.`, ctx); + } + + return `⚠️ Request was blocked. Reason: ${error.reason}`; + } + + if (error instanceof TooManyRequestsError) { + logger.warn(`${source}: Rate limited for ${error.retryAfter} seconds.`, ctx); + + return '🚦 Request was rate-limited. Please try again later or consider self-hosting.'; + } + + if (error instanceof TooManyTimeoutsError) { + logger.warn(`${source}: Too many timeouts.`, ctx); + + return '🚦 Too many recent timeouts. Please try again later.'; + } + + if (error instanceof TimeoutError) { + logger.warn(`${source}: Request timed out.`, ctx); + + return '🐢 Request timed out.'; + } + + if (error instanceof QueueIsFullError) { + logger.warn(`${source}: Request queue is full.`, ctx); + + return '⏳ Request queue is full. Please try again later or consider self-hosting.'; + } + + if (error instanceof HttpError) { + logger.error(`${source}: HTTP status ${error.status} (${error.statusText}), headers: ${JSON.stringify(error.headers)}, stack: ${error.stack}.`, ctx); + + if (error.status >= 500) { + return `❌ Remote server has issues. We can't fix this, please try later again.`; + } + + return `❌ Request failed with status ${error.status} (${error.statusText}). Request-id: ${ctx.id}.`; + } + + const cause = (error as Error & { cause?: unknown }).cause; + logger.error(`${source} error: ${error}, cause: ${cause}, stack: ${(error as Error).stack}`, ctx); + + return `❌ Request failed. Request-id: ${ctx.id}.`; +}; diff --git a/src/utils/StreamResolver.ts b/src/utils/StreamResolver.ts index fcdb6a8..e97bf59 100644 --- a/src/utils/StreamResolver.ts +++ b/src/utils/StreamResolver.ts @@ -1,18 +1,10 @@ import bytes from 'bytes'; import { ContentType, Stream } from 'stremio-addon-sdk'; import winston from 'winston'; -import { - BlockedError, - HttpError, - NotFoundError, - QueueIsFullError, - TimeoutError, - TooManyRequestsError, - TooManyTimeoutsError, -} from '../error'; +import { logErrorAndReturnNiceString, NotFoundError } from '../error'; import { ExtractorRegistry } from '../extractor'; import { Source } from '../source'; -import { BlockedReason, Context, Format, UrlResult } from '../types'; +import { Context, Format, UrlResult } from '../types'; import { showExternalUrls } from './config'; import { envGetAppName } from './env'; import { Id } from './id'; @@ -72,7 +64,7 @@ export class StreamResolver { streams.push({ name: envGetAppName(), - title: [`🔗 ${handler.label}`, this.logErrorAndReturnNiceString(ctx, handler.id, error)].join('\n'), + title: [`🔗 ${handler.label}`, logErrorAndReturnNiceString(ctx, this.logger, handler.id, error)].join('\n'), externalUrl: ctx.hostUrl.href, }); } @@ -171,61 +163,6 @@ export class StreamResolver { return name; }; - private logErrorAndReturnNiceString(ctx: Context, source: string, error: unknown): string { - if (error instanceof BlockedError) { - if (error.reason === BlockedReason.cloudflare_challenge) { - this.logger.warn(`${source}: Request was blocked via Cloudflare challenge.`, ctx); - } else if (error.reason === BlockedReason.cloudflare_censor) { - this.logger.warn(`${source}: Request was censored by Cloudflare.`, ctx); - } else if (error.reason === BlockedReason.media_flow_proxy_auth) { - return '⚠️ MediaFlow Proxy authentication failed. Please set the correct password.'; - } else { - this.logger.warn(`${source}: Request was blocked, headers: ${JSON.stringify(error.headers)}.`, ctx); - } - - return `⚠️ Request was blocked. Reason: ${error.reason}`; - } - - if (error instanceof TooManyRequestsError) { - this.logger.warn(`${source}: Rate limited for ${error.retryAfter} seconds.`, ctx); - - return '🚦 Request was rate-limited. Please try again later or consider self-hosting.'; - } - - if (error instanceof TooManyTimeoutsError) { - this.logger.warn(`${source}: Too many timeouts.`, ctx); - - return '🚦 Too many recent timeouts. Please try again later.'; - } - - if (error instanceof TimeoutError) { - this.logger.warn(`${source}: Request timed out.`, ctx); - - return '🐢 Request timed out.'; - } - - if (error instanceof QueueIsFullError) { - this.logger.warn(`${source}: Request queue is full.`, ctx); - - return '⏳ Request queue is full. Please try again later or consider self-hosting.'; - } - - if (error instanceof HttpError) { - this.logger.error(`${source}: HTTP status ${error.status} (${error.statusText}), headers: ${JSON.stringify(error.headers)}, stack: ${error.stack}.`, ctx); - - if (error.status >= 500) { - return `❌ Remote server has issues. We can't fix this, please try later again.`; - } - - return `❌ Request failed with status ${error.status} (${error.statusText}). Request-id: ${ctx.id}.`; - } - - const cause = (error as Error & { cause?: unknown }).cause; - this.logger.error(`${source} error: ${error}, cause: ${cause}, stack: ${(error as Error).stack}`, ctx); - - return `❌ Request failed. Request-id: ${ctx.id}.`; - }; - private buildTitle(ctx: Context, urlResult: UrlResult): string { const titleLines = []; @@ -241,7 +178,7 @@ export class StreamResolver { titleLines.push(titleDetailsLine.join(' ')); if (urlResult.error) { - titleLines.push(this.logErrorAndReturnNiceString(ctx, urlResult.sourceId, urlResult.error)); + titleLines.push(logErrorAndReturnNiceString(ctx, this.logger, urlResult.sourceId, urlResult.error)); } return titleLines.join('\n');