refactor: use proper prototype class methods
This commit is contained in:
parent
0e6558e0b1
commit
4bc25692a8
27 changed files with 83 additions and 59 deletions
|
|
@ -18,7 +18,7 @@ export class ConfigureController {
|
|||
this.router.get('/:config/configure', this.getConfigure.bind(this));
|
||||
}
|
||||
|
||||
private readonly getConfigure = (req: Request, res: Response) => {
|
||||
private getConfigure(req: Request, res: Response) {
|
||||
const config: Config = JSON.parse(req.params['config'] || JSON.stringify(getDefaultConfig()));
|
||||
|
||||
const manifest = buildManifest(this.sources, config);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export class ManifestController {
|
|||
this.router.get('/:config/manifest.json', this.getManifest.bind(this));
|
||||
}
|
||||
|
||||
private readonly getManifest = (req: Request, res: Response) => {
|
||||
private getManifest(req: Request, res: Response) {
|
||||
const config: Config = JSON.parse(req.params['config'] || JSON.stringify(getDefaultConfig()));
|
||||
|
||||
const manifest = buildManifest(this.sources, config);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export class StreamController {
|
|||
this.router.get('/:config/stream/:type/:id.json', this.getStream.bind(this));
|
||||
}
|
||||
|
||||
private readonly getStream = async (req: Request, res: Response) => {
|
||||
private async getStream(req: Request, res: Response) {
|
||||
const config: Config = req.params['config'] ? JSON.parse(req.params['config']) : getDefaultConfig();
|
||||
const type: ContentType = (req.params['type'] || '') as ContentType;
|
||||
const id: string = req.params['id'] || '';
|
||||
|
|
|
|||
|
|
@ -18,15 +18,17 @@ export class DoodStream extends Extractor {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/dood|do[0-9]go|dooodster|dooood/);
|
||||
public supports(_ctx: Context, url: URL): boolean {
|
||||
return null !== url.host.match(/dood|do[0-9]go|dooodster|dooood/);
|
||||
};
|
||||
|
||||
public override readonly normalize = (url: URL): URL => {
|
||||
public override normalize(url: URL): URL {
|
||||
const videoId = url.pathname.split('/').slice(-1)[0] as string;
|
||||
|
||||
return new URL(`http://dood.to/e/${videoId}`);
|
||||
};
|
||||
|
||||
protected readonly extractInternal = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> {
|
||||
const html = await this.fetcher.text(ctx, new URL(url));
|
||||
|
||||
const passMd5Match = html.match(/\/pass_md5\/[\w-]+\/([\w-]+)/);
|
||||
|
|
|
|||
|
|
@ -18,11 +18,13 @@ export class Dropload extends Extractor {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/dropload/);
|
||||
public supports(_ctx: Context, url: URL): boolean {
|
||||
return null !== url.host.match(/dropload/);
|
||||
}
|
||||
|
||||
public override readonly normalize = (url: URL): URL => new URL(url.href.replace('/e/', '/').replace('/embed-', '/'));
|
||||
|
||||
protected readonly extractInternal = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> {
|
||||
const html = await this.fetcher.text(ctx, url);
|
||||
|
||||
if (html.includes('File Not Found')) {
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@ export class ExternalUrl extends Extractor {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly supports = (ctx: Context, url: URL): boolean => showExternalUrls(ctx.config) && null !== url.host.match(/.*/);
|
||||
public supports(ctx: Context, url: URL): boolean {
|
||||
return showExternalUrls(ctx.config) && null !== url.host.match(/.*/);
|
||||
}
|
||||
|
||||
protected readonly extractInternal = async (ctx: Context, url: URL, countryCode: CountryCode, title: string | undefined): Promise<UrlResult[]> => {
|
||||
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode, title: string | undefined): Promise<UrlResult[]> {
|
||||
try {
|
||||
// Make sure the URL is accessible, but avoid causing noise and delays doing this
|
||||
await this.fetcher.head(ctx, url, { noFlareSolverr: true, timeout: 1000 });
|
||||
|
|
|
|||
|
|
@ -8,13 +8,15 @@ export abstract class Extractor {
|
|||
|
||||
public readonly ttl: number = 900000; // 15m
|
||||
|
||||
public abstract readonly supports: (ctx: Context, url: URL) => boolean;
|
||||
public abstract supports(ctx: Context, url: URL): boolean;
|
||||
|
||||
public readonly normalize = (url: URL): URL => url;
|
||||
public normalize(url: URL): URL {
|
||||
return url;
|
||||
};
|
||||
|
||||
protected abstract readonly extractInternal: (ctx: Context, url: URL, countryCode: CountryCode, title?: string | undefined) => Promise<UrlResult[]>;
|
||||
protected abstract extractInternal(ctx: Context, url: URL, countryCode: CountryCode, title?: string | undefined): Promise<UrlResult[]>;
|
||||
|
||||
public readonly extract = async (ctx: Context, url: URL, countryCode: CountryCode, title?: string | undefined): Promise<UrlResult[]> => {
|
||||
public async extract(ctx: Context, url: URL, countryCode: CountryCode, title?: string | undefined): Promise<UrlResult[]> {
|
||||
try {
|
||||
return await this.extractInternal(ctx, url, countryCode, title);
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export class ExtractorRegistry {
|
|||
this.urlResultCache = new TTLCache({ max: 1024 });
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, url: URL, countryCode: CountryCode, title?: string | undefined): Promise<UrlResult[]> => {
|
||||
public async handle(ctx: Context, url: URL, countryCode: CountryCode, title?: string | undefined): Promise<UrlResult[]> {
|
||||
const extractor = this.extractors.find(extractor => extractor.supports(ctx, url));
|
||||
if (!extractor) {
|
||||
return [];
|
||||
|
|
|
|||
|
|
@ -16,9 +16,11 @@ export class Fsst extends Extractor {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/fsst/);
|
||||
public supports(_ctx: Context, url: URL): boolean {
|
||||
return null !== url.host.match(/fsst/);
|
||||
};
|
||||
|
||||
protected readonly extractInternal = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> {
|
||||
const html = await this.fetcher.text(ctx, url);
|
||||
|
||||
const $ = cheerio.load(html);
|
||||
|
|
|
|||
|
|
@ -17,11 +17,15 @@ export class KinoGer extends Extractor {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/kinoger\.re|shiid4u\.upn\.one|moflix\.upns\.xyz|player\.upn\.one|wasuytm\.store|ultrastream\.online/);
|
||||
public supports(_ctx: Context, url: URL): boolean {
|
||||
return null !== url.host.match(/kinoger\.re|shiid4u\.upn\.one|moflix\.upns\.xyz|player\.upn\.one|wasuytm\.store|ultrastream\.online/);
|
||||
}
|
||||
|
||||
public override readonly normalize = (url: URL): URL => new URL(`${url.origin}/api/v1/video?id=${url.hash.slice(1)}`);
|
||||
public override normalize(url: URL): URL {
|
||||
return new URL(`${url.origin}/api/v1/video?id=${url.hash.slice(1)}`);
|
||||
}
|
||||
|
||||
protected readonly extractInternal = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> {
|
||||
const hexData = await this.fetcher.text(ctx, url, { headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36' } });
|
||||
|
||||
const encrypted = Buffer.from(hexData, 'hex');
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@ export class Soaper extends Extractor {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/soaper/) && null !== url.pathname.match(/^\/(episode|movie)_/);
|
||||
public supports(_ctx: Context, url: URL): boolean {
|
||||
return null !== url.host.match(/soaper/) && null !== url.pathname.match(/^\/(episode|movie)_/);
|
||||
}
|
||||
|
||||
protected readonly extractInternal = async (ctx: Context, url: URL, countryCode: CountryCode, title: string | undefined): Promise<UrlResult[]> => {
|
||||
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode, title: string | undefined): Promise<UrlResult[]> {
|
||||
const movieOrEpisodeId = (url.pathname.match(/\/\w+_(\w+)/) as string[])[1] as string;
|
||||
|
||||
const form = new URLSearchParams();
|
||||
|
|
|
|||
|
|
@ -18,11 +18,15 @@ export class SuperVideo extends Extractor {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/supervideo/);
|
||||
public supports(_ctx: Context, url: URL): boolean {
|
||||
return null !== url.host.match(/supervideo/);
|
||||
}
|
||||
|
||||
public override readonly normalize = (url: URL): URL => new URL(url.href.replace('/e/', '/').replace('/embed-', '/'));
|
||||
public override normalize(url: URL): URL {
|
||||
return new URL(url.href.replace('/e/', '/').replace('/embed-', '/'));
|
||||
}
|
||||
|
||||
protected readonly extractInternal = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> {
|
||||
const html = await this.fetcher.text(ctx, url);
|
||||
|
||||
if (html.includes('This video can be watched as embed only')) {
|
||||
|
|
|
|||
|
|
@ -18,9 +18,11 @@ export class VidSrc extends Extractor {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/vidsrc/);
|
||||
public supports(_ctx: Context, url: URL): boolean {
|
||||
return null !== url.host.match(/vidsrc/);
|
||||
}
|
||||
|
||||
protected readonly extractInternal = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
protected async extractInternal(ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> {
|
||||
const html = await this.fetcher.text(ctx, url);
|
||||
|
||||
const $ = cheerio.load(html);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export class CineHDPlus implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const seriesPageUrl = await this.fetchSeriesPageUrl(ctx, imdbId);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export class Eurostreaming implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const seriesPageUrl = await this.fetchSeriesPageUrl(ctx, imdbId);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export class Frembed implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const tmdbId = await getTmdbId(ctx, this.fetcher, id);
|
||||
|
||||
const apiUrl = new URL(`https://frembed.space/api/series?id=${tmdbId.id}&sa=${tmdbId.season}&epi=${tmdbId.episode}&idType=tmdb`);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export class FrenchCloud implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const pageUrl = new URL(`https://frenchcloud.cam/movie/${imdbId.id}`);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export class KinoGer implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const tmdbId = await getTmdbId(ctx, this.fetcher, id);
|
||||
|
||||
const [keyword, year] = await this.getKeywordAndYear(ctx, tmdbId);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export class MeineCloud implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const pageUrl = new URL(`https://meinecloud.click/movie/${imdbId.id}`);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export class MostraGuarda implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const pageUrl = new URL(`https://mostraguarda.stream/movie/${imdbId.id}`);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export class Soaper implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const tmdbId = await getTmdbId(ctx, this.fetcher, id);
|
||||
|
||||
const [keyword, year, hrefPrefix] = await this.getKeywordYearAndHrefPrefix(ctx, tmdbId);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export class StreamKiste implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const seriesPageUrl = await this.fetchSeriesPageUrl(ctx, imdbId);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export class VerHdLink implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const pageUrl = new URL(`https://verhdlink.cam/movie/${imdbId.id}`);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export class VidSrc implements Source {
|
|||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const url = imdbId.season
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ export interface Source {
|
|||
|
||||
readonly countryCodes: CountryCode[];
|
||||
|
||||
readonly handle: (ctx: Context, type: ContentType, id: Id) => Promise<(SourceResult[])>;
|
||||
handle(ctx: Context, type: ContentType, id: Id): Promise<(SourceResult[])>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,19 +64,19 @@ export class Fetcher {
|
|||
this.httpCache = new TTLCache();
|
||||
}
|
||||
|
||||
public readonly text = async (ctx: Context, url: URL, init?: CustomRequestInit): Promise<string> => {
|
||||
public async text(ctx: Context, url: URL, init?: CustomRequestInit): Promise<string> {
|
||||
return (await this.cachedFetch(ctx, url, init)).body;
|
||||
};
|
||||
|
||||
public readonly textPost = async (ctx: Context, url: URL, body: string, init?: CustomRequestInit): Promise<string> => {
|
||||
public async textPost(ctx: Context, url: URL, body: string, init?: CustomRequestInit): Promise<string> {
|
||||
return (await this.cachedFetch(ctx, url, { ...init, method: 'POST', body })).body;
|
||||
};
|
||||
|
||||
public readonly head = async (ctx: Context, url: URL, init?: CustomRequestInit): Promise<CachePolicy.Headers> => {
|
||||
public async head(ctx: Context, url: URL, init?: CustomRequestInit): Promise<CachePolicy.Headers> {
|
||||
return (await this.cachedFetch(ctx, url, { ...init, method: 'HEAD' })).policy.responseHeaders();
|
||||
};
|
||||
|
||||
public readonly getInit = (ctx: Context, url: URL, init?: CustomRequestInit): CustomRequestInit => {
|
||||
public getInit(ctx: Context, url: URL, init?: CustomRequestInit): CustomRequestInit {
|
||||
const cookieString = this.cookieJar.getCookieStringSync(url.href);
|
||||
|
||||
const noReferer = init?.noReferer ?? false;
|
||||
|
|
@ -99,7 +99,7 @@ export class Fetcher {
|
|||
};
|
||||
};
|
||||
|
||||
private readonly handleHttpCacheItem = async (ctx: Context, httpCacheItem: HttpCacheItem, url: URL, init?: CustomRequestInit): Promise<HttpCacheItem> => {
|
||||
private async handleHttpCacheItem(ctx: Context, httpCacheItem: HttpCacheItem, url: URL, init?: CustomRequestInit): Promise<HttpCacheItem> {
|
||||
if (httpCacheItem.status && httpCacheItem.status >= 200 && httpCacheItem.status <= 299) {
|
||||
return httpCacheItem;
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ export class Fetcher {
|
|||
throw new HttpError(httpCacheItem.status, httpCacheItem.statusText, responseHeaders);
|
||||
};
|
||||
|
||||
private readonly determineTtl = (httpCacheItem: HttpCacheItem): number => {
|
||||
private determineTtl(httpCacheItem: HttpCacheItem): number {
|
||||
if (httpCacheItem.status === 200) {
|
||||
return Math.max(httpCacheItem.policy.timeToLive(), 900000); // 15m at least
|
||||
}
|
||||
|
|
@ -170,7 +170,7 @@ export class Fetcher {
|
|||
return httpCacheItem.policy.timeToLive();
|
||||
};
|
||||
|
||||
private readonly headersToObject = (headers: Headers): Record<string, string> => {
|
||||
private headersToObject(headers: Headers): Record<string, string> {
|
||||
const obj: Record<string, string> = {};
|
||||
|
||||
headers.forEach((value, name) => {
|
||||
|
|
@ -180,7 +180,7 @@ export class Fetcher {
|
|||
return obj;
|
||||
};
|
||||
|
||||
private readonly cachedFetch = async (ctx: Context, url: URL, init?: CustomRequestInit): Promise<HttpCacheItem> => {
|
||||
private async cachedFetch(ctx: Context, url: URL, init?: CustomRequestInit): Promise<HttpCacheItem> {
|
||||
const newInit = this.getInit(ctx, url, init);
|
||||
|
||||
const request: CachePolicy.Request = { url: url.href, method: newInit.method ?? 'GET', headers: {} };
|
||||
|
|
@ -206,7 +206,7 @@ export class Fetcher {
|
|||
return this.handleHttpCacheItem(ctx, httpCacheItem, url, init);
|
||||
};
|
||||
|
||||
private readonly fetchWithTimeout = async (ctx: Context, url: URL, init?: CustomRequestInit): Promise<Response> => {
|
||||
private async fetchWithTimeout(ctx: Context, url: URL, init?: CustomRequestInit): Promise<Response> {
|
||||
this.logger.info(`Fetch ${init?.method ?? 'GET'} ${url}`, ctx);
|
||||
|
||||
const controller = new AbortController();
|
||||
|
|
@ -222,9 +222,11 @@ export class Fetcher {
|
|||
return response;
|
||||
};
|
||||
|
||||
private readonly getHostQueueCount = (host: string): number => this.hostQueueCount.get(host) ?? 0;
|
||||
private getHostQueueCount(host: string): number {
|
||||
return this.hostQueueCount.get(host) ?? 0;
|
||||
}
|
||||
|
||||
private readonly lockFetchSlot = async (host: string, queueErrorLimit: number) => {
|
||||
private async lockFetchSlot(host: string, queueErrorLimit: number) {
|
||||
await this.countMutex.runExclusive(() => {
|
||||
if (this.getHostQueueCount(host) > queueErrorLimit) {
|
||||
throw new QueueIsFullError();
|
||||
|
|
@ -234,13 +236,13 @@ export class Fetcher {
|
|||
});
|
||||
};
|
||||
|
||||
private readonly unlockFetchSlot = async (host: string) => {
|
||||
private async unlockFetchSlot(host: string) {
|
||||
await this.countMutex.runExclusive(() => {
|
||||
this.hostQueueCount.set(host, Math.max(0, this.getHostQueueCount(host) - 1));
|
||||
});
|
||||
};
|
||||
|
||||
private readonly waitForHostQueueCount = async (host: string, queueLimit: number, queueErrorLimit: number): Promise<void> => {
|
||||
private async waitForHostQueueCount(host: string, queueLimit: number, queueErrorLimit: number): Promise<void> {
|
||||
while (this.getHostQueueCount(host) > queueLimit) {
|
||||
if (this.getHostQueueCount(host) > queueErrorLimit) {
|
||||
// Very unlikely to happen..
|
||||
|
|
@ -251,7 +253,7 @@ export class Fetcher {
|
|||
}
|
||||
};
|
||||
|
||||
private readonly queuedFetch = async (ctx: Context, url: URL, init?: CustomRequestInit): Promise<Response> => {
|
||||
private async queuedFetch(ctx: Context, url: URL, init?: CustomRequestInit): Promise<Response> {
|
||||
const queueLimit = init?.queueLimit ?? 5;
|
||||
const queueErrorLimit = init?.queueErrorLimit ?? 10;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export class StreamResolver {
|
|||
this.extractorRegistry = extractorRegistry;
|
||||
}
|
||||
|
||||
public readonly resolve = async (ctx: Context, sources: Source[], type: ContentType, id: Id): Promise<ResolveResponse> => {
|
||||
public async resolve(ctx: Context, sources: Source[], type: ContentType, id: Id): Promise<ResolveResponse> {
|
||||
if (sources.length === 0) {
|
||||
return {
|
||||
streams: [
|
||||
|
|
@ -120,7 +120,7 @@ export class StreamResolver {
|
|||
};
|
||||
};
|
||||
|
||||
private readonly determineTtl = (urlResults: UrlResult[]): number | undefined => {
|
||||
private determineTtl(urlResults: UrlResult[]): number | undefined {
|
||||
if (!urlResults.length) {
|
||||
return 900000; // 15m
|
||||
}
|
||||
|
|
@ -132,7 +132,7 @@ export class StreamResolver {
|
|||
return Math.min(...urlResults.map(urlResult => urlResult.ttl as number));
|
||||
};
|
||||
|
||||
private readonly buildUrl = (ctx: Context, urlResult: UrlResult): { externalUrl: string } | { url: string } | { ytId: string } => {
|
||||
private buildUrl(ctx: Context, urlResult: UrlResult): { externalUrl: string } | { url: string } | { ytId: string } {
|
||||
if (!urlResult.isExternal) {
|
||||
return { url: urlResult.url.href };
|
||||
}
|
||||
|
|
@ -144,7 +144,7 @@ export class StreamResolver {
|
|||
return { ytId: 'E4WlUXrJgy4' };
|
||||
};
|
||||
|
||||
private readonly buildName = (ctx: Context, urlResult: UrlResult): string => {
|
||||
private buildName(ctx: Context, urlResult: UrlResult): string {
|
||||
let name = envGetAppName();
|
||||
|
||||
name += urlResult.meta.height ? ` ${urlResult.meta.height}P` : ' N/A';
|
||||
|
|
@ -156,7 +156,7 @@ export class StreamResolver {
|
|||
return name;
|
||||
};
|
||||
|
||||
private readonly logErrorAndReturnNiceString = (ctx: Context, source: string, error: unknown): string => {
|
||||
private logErrorAndReturnNiceString(ctx: Context, source: string, error: unknown): string {
|
||||
if (error instanceof BlockedError) {
|
||||
if (error.reason === 'cloudflare_challenge') {
|
||||
this.logger.warn(`${source}: Request was blocked via Cloudflare challenge.`, ctx);
|
||||
|
|
@ -190,7 +190,7 @@ export class StreamResolver {
|
|||
return `❌ Request failed. Request-id: ${ctx.id}.`;
|
||||
};
|
||||
|
||||
private readonly buildTitle = (ctx: Context, urlResult: UrlResult): string => {
|
||||
private buildTitle(ctx: Context, urlResult: UrlResult): string {
|
||||
const titleLines = [];
|
||||
|
||||
if (urlResult.meta.title) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue