refactor(extractor): introduce internal type to reduce common code
This commit is contained in:
parent
db860c25c6
commit
50a7e5559b
26 changed files with 68 additions and 100 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import bytes from 'bytes';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { buildMediaFlowProxyExtractorRedirectUrl, supportsMediaFlowProxy } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ export class DoodStream extends Extractor {
|
|||
return new URL(`http://dood.to/e/${videoId}`);
|
||||
};
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
@ -44,8 +44,6 @@ export class DoodStream extends Extractor {
|
|||
{
|
||||
url: buildMediaFlowProxyExtractorRedirectUrl(ctx, 'Doodstream', url, headers),
|
||||
format: Format.mp4,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import bytes from 'bytes';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { extractUrlFromPacked, guessHeightFromPlaylist } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ export class Dropload extends Extractor {
|
|||
|
||||
public override readonly normalize = (url: URL): URL => new URL(url.href.replace('/d/', '/').replace('/e/', '/').replace('/embed-', '/'));
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
@ -44,8 +44,6 @@ export class Dropload extends Extractor {
|
|||
{
|
||||
url: playlistUrl,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { showExternalUrls } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -13,14 +13,13 @@ export class ExternalUrl extends Extractor {
|
|||
return showExternalUrls(ctx.config) && null !== url.host.match(/.*/);
|
||||
}
|
||||
|
||||
protected async extractInternal(_ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(_ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
return [
|
||||
{
|
||||
url: url,
|
||||
format: Format.unknown,
|
||||
isExternal: true,
|
||||
label: `${url.host}`,
|
||||
ttl: this.ttl,
|
||||
meta,
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta, UrlResult } from '../types';
|
||||
import { Fetcher } from '../utils';
|
||||
|
||||
export abstract class Extractor {
|
||||
|
|
@ -23,12 +23,16 @@ export abstract class Extractor {
|
|||
return url;
|
||||
};
|
||||
|
||||
protected abstract extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]>;
|
||||
protected abstract extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]>;
|
||||
|
||||
public async extract(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
try {
|
||||
return (await this.extractInternal(ctx, url, meta)).map(
|
||||
urlResult => ({ ...urlResult, label: this.formatLabel(urlResult.label) }),
|
||||
urlResult => ({
|
||||
...urlResult,
|
||||
label: this.formatLabel(urlResult.label ?? this.label),
|
||||
ttl: this.ttl,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof NotFoundError) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import bytes from 'bytes';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { buildMediaFlowProxyExtractorStreamUrl, supportsMediaFlowProxy } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ export class Fastream extends Extractor {
|
|||
return new URL(url.href.replace('/e/', '/embed-').replace('/d/', '/embed-'));
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const downloadUrl = new URL(url.href.replace('/embed-', '/d/'));
|
||||
|
|
@ -38,8 +38,6 @@ export class Fastream extends Extractor {
|
|||
{
|
||||
url: playlistUrl,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
bytes: bytes.parse(heightAndSizeMatch[2] as string) as number,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import bytes from 'bytes';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { buildMediaFlowProxyExtractorStreamUrl, supportsMediaFlowProxy, unpackEval } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ export class FileLions extends Extractor {
|
|||
return new URL(url.href.replace('/v/', '/f/').replace('/download/', '/f/').replace('/file/', '/f/'));
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
@ -87,8 +87,6 @@ export class FileLions extends Extractor {
|
|||
{
|
||||
url: await buildMediaFlowProxyExtractorStreamUrl(ctx, this.fetcher, 'FileLions', url, headers),
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
height: parseInt(heightMatch[1] as string),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as cheerio from 'cheerio';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import {
|
||||
buildMediaFlowProxyExtractorStreamUrl,
|
||||
supportsMediaFlowProxy,
|
||||
|
|
@ -45,7 +45,7 @@ export class FileMoon extends Extractor {
|
|||
return new URL(url.href.replace('/e/', '/d/'));
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta, originalUrl?: URL): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta, originalUrl?: URL): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
@ -72,8 +72,6 @@ export class FileMoon extends Extractor {
|
|||
{
|
||||
url: playlistUrl,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
...(heightMatch && { height: parseInt(heightMatch[1] as string) }),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as cheerio from 'cheerio';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
export class Fsst extends Extractor {
|
||||
|
|
@ -11,7 +11,7 @@ export class Fsst extends Extractor {
|
|||
return null !== url.host.match(/fsst/);
|
||||
};
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers, noProxyHeaders: true });
|
||||
|
|
@ -29,8 +29,6 @@ export class Fsst extends Extractor {
|
|||
return [{
|
||||
url: await this.fetcher.getFinalRedirectUrl(ctx, new URL(fileHref), { headers, noProxyHeaders: true }, 1),
|
||||
format: Format.mp4,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
height: parseInt(heightAndUrlMatch[1] as string),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import bytes from 'bytes';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
export class HubCloud extends Extractor {
|
||||
|
|
@ -14,7 +14,7 @@ export class HubCloud extends Extractor {
|
|||
return null !== url.host.match(/hubcloud/);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const redirectHtml = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
@ -36,7 +36,6 @@ export class HubCloud extends Extractor {
|
|||
url,
|
||||
format: Format.unknown,
|
||||
label: `${this.label} (FSL)`,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
bytes: bytes.parse($('#size').text()) as number,
|
||||
|
|
@ -53,7 +52,6 @@ export class HubCloud extends Extractor {
|
|||
url,
|
||||
format: Format.unknown,
|
||||
label: `${this.label} (PixelServer)`,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
bytes: bytes.parse($('#size').text()) as number,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as cheerio from 'cheerio';
|
||||
import { Context, Meta, UrlResult } from '../types';
|
||||
import { Context, InternalUrlResult, Meta } from '../types';
|
||||
import { Fetcher } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
import { HubCloud } from './HubCloud';
|
||||
|
|
@ -23,7 +23,7 @@ export class HubDrive extends Extractor {
|
|||
return null !== url.host.match(/hubdrive/);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import crypto from 'crypto';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { guessHeightFromPlaylist } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ export class KinoGer extends Extractor {
|
|||
return new URL(`${url.origin}/api/v1/video?id=${url.hash.slice(1)}`);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = {
|
||||
'Origin': url.origin,
|
||||
'Referer': url.origin + '/',
|
||||
|
|
@ -66,8 +66,6 @@ export class KinoGer extends Extractor {
|
|||
{
|
||||
url: m3u8Url,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
height: meta.height ?? await guessHeightFromPlaylist(ctx, this.fetcher, m3u8Url, { headers }),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import bytes from 'bytes';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import {
|
||||
buildMediaFlowProxyExtractorStreamUrl,
|
||||
supportsMediaFlowProxy,
|
||||
|
|
@ -34,7 +34,7 @@ export class LuluStream extends Extractor {
|
|||
return new URL(`/e/${videoId}`, url);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const fileUrl = new URL(url.href.replace('/e/', '/d/'));
|
||||
|
|
@ -55,8 +55,6 @@ export class LuluStream extends Extractor {
|
|||
{
|
||||
url: playlistUrl,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import bytes from 'bytes';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { buildMediaFlowProxyExtractorRedirectUrl, supportsMediaFlowProxy } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ export class Mixdrop extends Extractor {
|
|||
|
||||
public override readonly normalize = (url: URL): URL => new URL(url.href.replace('/f/', '/e/'));
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const fileUrl = new URL(url.href.replace('/e/', '/f/'));
|
||||
const html = await this.fetcher.text(ctx, fileUrl);
|
||||
|
||||
|
|
@ -35,8 +35,6 @@ export class Mixdrop extends Extractor {
|
|||
{
|
||||
url: buildMediaFlowProxyExtractorRedirectUrl(ctx, 'Mixdrop', url),
|
||||
format: Format.mp4,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
bytes: bytes.parse((sizeMatch[1] as string).replace(',', '')) as number,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { BlockedError } from '../error';
|
||||
import { BlockedReason, Context, Format, Meta, UrlResult } from '../types';
|
||||
import { BlockedReason, Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { guessHeightFromPlaylist } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ export class RgShows extends Extractor {
|
|||
return null !== url.host.match(/rgshows/);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { 'Referer': 'https://www.rgshows.ru/', 'Origin': 'https://www.rgshows.ru', 'User-Agent': 'Mozilla' };
|
||||
|
||||
const data = await this.fetcher.json(ctx, url, { headers }) as RgShowsApiData;
|
||||
|
|
@ -38,8 +38,6 @@ export class RgShows extends Extractor {
|
|||
{
|
||||
url: streamUrl,
|
||||
format: isMp4 ? Format.mp4 : (isHls ? Format.hls : /* istanbul ignore next */ Format.unknown),
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
...(isHls && { height: meta.height ?? await guessHeightFromPlaylist(ctx, this.fetcher, streamUrl, { headers }) }),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as cheerio from 'cheerio';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
export class SaveFiles extends Extractor {
|
||||
|
|
@ -18,7 +18,7 @@ export class SaveFiles extends Extractor {
|
|||
return new URL(url.href.replace('/e/', '/').replace('/d/', '/'));
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
@ -37,8 +37,6 @@ export class SaveFiles extends Extractor {
|
|||
{
|
||||
url: new URL(fileMatch[1] as string),
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
export class StreamEmbed extends Extractor {
|
||||
|
|
@ -11,7 +11,7 @@ export class StreamEmbed extends Extractor {
|
|||
return null !== url.host.match(/bullstream|mp4player|watch\.gxplayer/);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
@ -26,8 +26,6 @@ export class StreamEmbed extends Extractor {
|
|||
{
|
||||
url: new URL(`/m3u8/${video.uid}/${video.md5}/master.txt?s=1&id=${video.id}&cache=${video.status}`, url.origin),
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
height: parseInt(JSON.parse(video.quality)[0]),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as cheerio from 'cheerio';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { guessHeightFromPlaylist } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ export class StreamUp extends Extractor {
|
|||
].includes(url.host);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: `${url.origin}/`, Origin: url.origin };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
@ -36,8 +36,6 @@ export class StreamUp extends Extractor {
|
|||
{
|
||||
url: playlistUrl,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
height: meta.height ?? await guessHeightFromPlaylist(ctx, this.fetcher, playlistUrl),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
import bytes from 'bytes';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import {
|
||||
buildMediaFlowProxyExtractorRedirectUrl,
|
||||
supportsMediaFlowProxy,
|
||||
} from '../utils';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { buildMediaFlowProxyExtractorRedirectUrl, supportsMediaFlowProxy } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
export class Streamtape extends Extractor {
|
||||
|
|
@ -45,7 +42,7 @@ export class Streamtape extends Extractor {
|
|||
return new URL(url.href.replace('/e/', '/v/'));
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
// Only needed to properly find non-existing files via 404 response
|
||||
|
|
@ -62,8 +59,6 @@ export class Streamtape extends Extractor {
|
|||
{
|
||||
url: buildMediaFlowProxyExtractorRedirectUrl(ctx, 'Streamtape', url, headers),
|
||||
format: Format.mp4,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import bytes from 'bytes';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { extractUrlFromPacked, guessHeightFromPlaylist } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ export class SuperVideo extends Extractor {
|
|||
return new URL(url.href.replace('/e/', '/').replace('/k/', '/').replace('/embed-', '/'));
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
@ -48,8 +48,6 @@ export class SuperVideo extends Extractor {
|
|||
{
|
||||
url: m3u8Url,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as cheerio from 'cheerio';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { buildMediaFlowProxyExtractorRedirectUrl, supportsMediaFlowProxy } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ export class Uqload extends Extractor {
|
|||
return new URL(url.href.replace('/embed-', '/'));
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const html = await this.fetcher.text(ctx, url);
|
||||
|
||||
if (/File Not Found/.test(html)) {
|
||||
|
|
@ -35,8 +35,6 @@ export class Uqload extends Extractor {
|
|||
{
|
||||
url: buildMediaFlowProxyExtractorRedirectUrl(ctx, 'Uqload', url),
|
||||
format: Format.mp4,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as cheerio from 'cheerio';
|
||||
import { BlockedError, TooManyRequestsError } from '../error';
|
||||
import { Context, Format, Meta, NonEmptyArray, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta, NonEmptyArray } from '../types';
|
||||
import { Fetcher, guessHeightFromPlaylist } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ export class VidSrc extends Extractor {
|
|||
return null !== url.host.match(/vidsrc|vsrc/);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
// While this is a crappy thing to do, they seem to be blocking overly strict IMO
|
||||
const randomIp = `${Math.floor(Math.random() * 223) + 1}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}`;
|
||||
const newCtx = { ...ctx, ip: randomIp };
|
||||
|
|
@ -31,7 +31,7 @@ export class VidSrc extends Extractor {
|
|||
return this.extractUsingRandomDomain(newCtx, url, meta, [...this.domains]);
|
||||
};
|
||||
|
||||
private async extractUsingRandomDomain(ctx: Context, url: URL, meta: Meta, domains: string[]): Promise<UrlResult[]> {
|
||||
private async extractUsingRandomDomain(ctx: Context, url: URL, meta: Meta, domains: string[]): Promise<InternalUrlResult[]> {
|
||||
const domainIndex = Math.floor(Math.random() * domains.length);
|
||||
const [domain] = domains.splice(domainIndex, 1) as [string];
|
||||
|
||||
|
|
@ -74,7 +74,6 @@ export class VidSrc extends Extractor {
|
|||
url: m3u8Url,
|
||||
format: Format.hls,
|
||||
label: serverName,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
height: await guessHeightFromPlaylist(ctx, this.fetcher, m3u8Url, { headers: { Referer: iframeUrl.href } }),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as cheerio from 'cheerio';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { extractUrlFromPacked, guessHeightFromPlaylist } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ export class Vidora extends Extractor {
|
|||
return new URL(url.href.replace('/embed/', '/'));
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const html = await this.fetcher.text(ctx, url);
|
||||
|
||||
const $ = cheerio.load(html);
|
||||
|
|
@ -31,8 +31,6 @@ export class Vidora extends Extractor {
|
|||
{
|
||||
url: m3u8Url,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
height: meta.height ?? await guessHeightFromPlaylist(ctx, this.fetcher, m3u8Url, { headers }),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Context, CountryCode, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, CountryCode, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { CustomRequestConfig, guessHeightFromPlaylist, hasMultiEnabled, iso639FromCountryCode } from '../utils';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ export class VixSrc extends Extractor {
|
|||
return null !== url.host.match(/vixsrc/);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url);
|
||||
|
|
@ -38,8 +38,6 @@ export class VixSrc extends Extractor {
|
|||
{
|
||||
url: playlistUrl,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
countryCodes,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import bytes from 'bytes';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { NotFoundError } from '../error';
|
||||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import {
|
||||
buildMediaFlowProxyExtractorStreamUrl, guessHeightFromPlaylist,
|
||||
supportsMediaFlowProxy,
|
||||
|
|
@ -125,7 +125,7 @@ export class Voe extends Extractor {
|
|||
return new URL(`/${url.pathname.replace(/\/+$/, '').split('/').at(-1)}`, url);
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
let html: string;
|
||||
|
|
@ -167,8 +167,6 @@ export class Voe extends Extractor {
|
|||
{
|
||||
url: playlistUrl,
|
||||
format: Format.hls,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
height,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Context, Format, Meta, UrlResult } from '../types';
|
||||
import { Context, Format, InternalUrlResult, Meta } from '../types';
|
||||
import { Extractor } from './Extractor';
|
||||
|
||||
export class YouTube extends Extractor {
|
||||
|
|
@ -12,7 +12,7 @@ export class YouTube extends Extractor {
|
|||
return null !== url.host.match(/youtube/) && url.searchParams.has('v');
|
||||
}
|
||||
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<UrlResult[]> {
|
||||
protected async extractInternal(ctx: Context, url: URL, meta: Meta): Promise<InternalUrlResult[]> {
|
||||
const headers = { Referer: meta.referer ?? url.href };
|
||||
|
||||
const html = await this.fetcher.text(ctx, url, { headers });
|
||||
|
|
@ -24,8 +24,6 @@ export class YouTube extends Extractor {
|
|||
url,
|
||||
format: Format.unknown,
|
||||
ytId: url.searchParams.get('v') as string,
|
||||
label: this.label,
|
||||
ttl: this.ttl,
|
||||
meta: {
|
||||
...meta,
|
||||
title: titleMatch[1] as string,
|
||||
|
|
|
|||
11
src/types.ts
11
src/types.ts
|
|
@ -93,6 +93,17 @@ export enum Format {
|
|||
unknown = 'unknown',
|
||||
}
|
||||
|
||||
export interface InternalUrlResult {
|
||||
url: URL;
|
||||
format: Format;
|
||||
isExternal?: boolean;
|
||||
ytId?: string;
|
||||
error?: unknown;
|
||||
label?: string;
|
||||
meta?: Meta;
|
||||
requestHeaders?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface UrlResult {
|
||||
url: URL;
|
||||
format: Format;
|
||||
|
|
|
|||
Loading…
Reference in a new issue