webstreamr-github/src/extractor/HubCloud.ts

83 lines
2.6 KiB
TypeScript

import bytes from 'bytes';
import * as cheerio from 'cheerio';
import { Context, Format, Meta, UrlResult } from '../types';
import { Extractor } from './Extractor';
export class HubCloud extends Extractor {
public readonly id = 'hubcloud';
public readonly label = 'HubCloud';
public override readonly ttl: number = 259200000; // 3d
public supports(_ctx: Context, url: URL): boolean {
return null !== url.host.match(/hubcloud/);
}
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
const headers = { Referer: meta.referer ?? url.href };
const redirectHtml = await this.fetcher.text(ctx, url, { headers });
const redirectUrlMatch = redirectHtml.match(/var url ?= ?'(.*?)'/) as string[];
const linksHtml = await this.fetcher.text(ctx, new URL(redirectUrlMatch[1] as string), { headers: { Referer: url.href } });
const $ = cheerio.load(linksHtml);
const urlResults = [
...$('a')
.filter((_i, el) => {
const text = $(el).text();
return text.includes('FSL') || text.includes('Download File');
})
.map((_i, el) => {
const url = new URL($(el).attr('href') as string);
return {
url,
format: Format.unknown,
label: `${this.label} (FSL)`,
sourceId: `${this.id}_fsl`,
ttl: this.ttl,
meta: {
...meta,
bytes: bytes.parse($('#size').text()) as number,
title: $('title').text().trim(),
},
};
}).toArray(),
...$('a')
.filter((_i, el) => $(el).text().includes('PixelServer'))
.map((_i, el) => {
const url = new URL(($(el).attr('href') as string).replace('/u/', '/api/file/'));
return {
url,
format: Format.unknown,
label: `${this.label} (PixelServer)`,
sourceId: `${this.id}_pixelserver`,
ttl: this.ttl,
meta: {
...meta,
bytes: bytes.parse($('#size').text()) as number,
title: $('title').text().trim(),
},
};
}).toArray(),
];
return this.asyncFilter(urlResults, async ({ url }) => {
try {
await this.fetcher.head(ctx, url);
} catch {
return false;
}
return true;
});
};
private async asyncFilter<T>(array: T[], asyncCallback: (item: T) => Promise<boolean>): Promise<T[]> {
const results = await Promise.all(array.map(asyncCallback));
return array.filter((_, index) => results[index]);
}
}