refactor: define member accessiblity explicitly
This commit is contained in:
parent
b4b8581383
commit
bdae1ff346
32 changed files with 157 additions and 152 deletions
|
|
@ -13,4 +13,9 @@ export default tseslint.config(
|
|||
{
|
||||
ignores: ['./dist'],
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-member-accessibility': 'error',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export class ConfigureController {
|
|||
|
||||
private readonly sources: Source[];
|
||||
|
||||
constructor(sources: Source[]) {
|
||||
public constructor(sources: Source[]) {
|
||||
this.router = Router();
|
||||
|
||||
this.sources = sources;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export class ManifestController {
|
|||
|
||||
private readonly sources: Source[];
|
||||
|
||||
constructor(sources: Source[]) {
|
||||
public constructor(sources: Source[]) {
|
||||
this.router = Router();
|
||||
|
||||
this.sources = sources;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export class StreamController {
|
|||
private readonly sources: Source[];
|
||||
private readonly streamResolver: StreamResolver;
|
||||
|
||||
constructor(logger: winston.Logger, sources: Source[], streams: StreamResolver) {
|
||||
public constructor(logger: winston.Logger, sources: Source[], streams: StreamResolver) {
|
||||
this.router = Router();
|
||||
|
||||
this.logger = logger;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ export class BlockedError extends Error {
|
|||
public readonly reason: BlockedReason;
|
||||
public readonly headers: Record<string, string[] | string | undefined>;
|
||||
|
||||
constructor(reason: BlockedReason, headers: Record<string, string[] | string | undefined>) {
|
||||
public constructor(reason: BlockedReason, headers: Record<string, string[] | string | undefined>) {
|
||||
super();
|
||||
|
||||
this.reason = reason;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ export class HttpError extends Error {
|
|||
public readonly statusText: string;
|
||||
public readonly headers: Record<string, string[] | string | undefined>;
|
||||
|
||||
constructor(status: number, statusText: string, headers: Record<string, string[] | string | undefined>) {
|
||||
public constructor(status: number, statusText: string, headers: Record<string, string[] | string | undefined>) {
|
||||
super();
|
||||
|
||||
this.status = status;
|
||||
|
|
|
|||
|
|
@ -6,27 +6,27 @@ import { Context, CountryCode, UrlResult } from '../types';
|
|||
import { NotFoundError } from '../error';
|
||||
|
||||
export class DoodStream implements Extractor {
|
||||
readonly id = 'doodstream';
|
||||
public readonly id = 'doodstream';
|
||||
|
||||
readonly label = 'DoodStream';
|
||||
public readonly label = 'DoodStream';
|
||||
|
||||
readonly ttl = 900000; // 15m
|
||||
public readonly ttl = 900000; // 15m
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/dood|do[0-9]go|dooodster|dooood/);
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/dood|do[0-9]go|dooodster|dooood/);
|
||||
|
||||
readonly normalize = (url: URL): URL => {
|
||||
public readonly normalize = (url: URL): URL => {
|
||||
const videoId = url.pathname.split('/').slice(-1)[0] as string;
|
||||
|
||||
return new URL(`http://dood.to/e/${videoId}`);
|
||||
};
|
||||
|
||||
readonly extract = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
public readonly extract = async (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-]+)/);
|
||||
|
|
|
|||
|
|
@ -6,23 +6,23 @@ import { Context, CountryCode, UrlResult } from '../types';
|
|||
import { NotFoundError } from '../error';
|
||||
|
||||
export class Dropload implements Extractor {
|
||||
readonly id = 'dropload';
|
||||
public readonly id = 'dropload';
|
||||
|
||||
readonly label = 'Dropload';
|
||||
public readonly label = 'Dropload';
|
||||
|
||||
readonly ttl = 900000; // 15m
|
||||
public readonly ttl = 900000; // 15m
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/dropload/);
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/dropload/);
|
||||
|
||||
readonly normalize = (url: URL): URL => new URL(url.href.replace('/e/', '/').replace('/embed-', '/'));
|
||||
public readonly normalize = (url: URL): URL => new URL(url.href.replace('/e/', '/').replace('/embed-', '/'));
|
||||
|
||||
readonly extract = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
public readonly extract = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
const html = await this.fetcher.text(ctx, url);
|
||||
|
||||
if (html.includes('File Not Found')) {
|
||||
|
|
|
|||
|
|
@ -3,23 +3,23 @@ import { Fetcher } from '../utils';
|
|||
import { Context, CountryCode, UrlResult } from '../types';
|
||||
|
||||
export class ExternalUrl implements Extractor {
|
||||
readonly id = 'external';
|
||||
public readonly id = 'external';
|
||||
|
||||
readonly label = 'External';
|
||||
public readonly label = 'External';
|
||||
|
||||
readonly ttl = 3600000; // 1h
|
||||
public readonly ttl = 3600000; // 1h
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly supports = (ctx: Context, url: URL): boolean => !('excludeExternalUrls' in ctx.config) && null !== url.host.match(/.*/);
|
||||
public readonly supports = (ctx: Context, url: URL): boolean => !('excludeExternalUrls' in ctx.config) && null !== url.host.match(/.*/);
|
||||
|
||||
readonly normalize = (url: URL): URL => url;
|
||||
public readonly normalize = (url: URL): URL => url;
|
||||
|
||||
readonly extract = async (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[]> => {
|
||||
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 });
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ export class ExtractorRegistry {
|
|||
private readonly extractors: Extractor[];
|
||||
private readonly urlResultCache: TTLCache<string, UrlResult[]>;
|
||||
|
||||
constructor(logger: winston.Logger, extractors: Extractor[]) {
|
||||
public constructor(logger: winston.Logger, extractors: Extractor[]) {
|
||||
this.logger = logger;
|
||||
this.extractors = extractors;
|
||||
this.urlResultCache = new TTLCache({ max: 1024 });
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, url: URL, countryCode: CountryCode, title?: string | undefined): Promise<UrlResult[]> => {
|
||||
public readonly handle = async (ctx: Context, url: URL, countryCode: CountryCode, title?: string | undefined): Promise<UrlResult[]> => {
|
||||
const extractor = this.extractors.find(extractor => extractor.supports(ctx, url));
|
||||
if (!extractor) {
|
||||
return [];
|
||||
|
|
|
|||
|
|
@ -4,23 +4,23 @@ import { Fetcher } from '../utils';
|
|||
import { Context, CountryCode, UrlResult } from '../types';
|
||||
|
||||
export class Fsst implements Extractor {
|
||||
readonly id = 'fsst';
|
||||
public readonly id = 'fsst';
|
||||
|
||||
readonly label = 'Fsst';
|
||||
public readonly label = 'Fsst';
|
||||
|
||||
readonly ttl = 900000; // 15m
|
||||
public readonly ttl = 900000; // 15m
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/fsst/);
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/fsst/);
|
||||
|
||||
readonly normalize = (url: URL): URL => url;
|
||||
public readonly normalize = (url: URL): URL => url;
|
||||
|
||||
readonly extract = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
public readonly extract = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
const html = await this.fetcher.text(ctx, url);
|
||||
|
||||
const $ = cheerio.load(html);
|
||||
|
|
|
|||
|
|
@ -5,23 +5,23 @@ import { Context, CountryCode, UrlResult } from '../types';
|
|||
|
||||
/** @see https://github.com/Gujal00/ResolveURL/blob/master/script.module.resolveurl/lib/resolveurl/plugins/kinoger.py */
|
||||
export class KinoGer implements Extractor {
|
||||
readonly id = 'kinoger';
|
||||
public readonly id = 'kinoger';
|
||||
|
||||
readonly label = 'KinoGer';
|
||||
public readonly label = 'KinoGer';
|
||||
|
||||
readonly ttl = 900000; // 15m
|
||||
public readonly ttl = 900000; // 15m
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
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 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/);
|
||||
|
||||
readonly normalize = (url: URL): URL => new URL(`${url.origin}/api/v1/video?id=${url.hash.slice(1)}`);
|
||||
public readonly normalize = (url: URL): URL => new URL(`${url.origin}/api/v1/video?id=${url.hash.slice(1)}`);
|
||||
|
||||
readonly extract = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
public readonly extract = async (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');
|
||||
|
|
|
|||
|
|
@ -8,23 +8,23 @@ interface SoaperInfoResponsePartial {
|
|||
}
|
||||
|
||||
export class Soaper implements Extractor {
|
||||
readonly id = 'soaper';
|
||||
public readonly id = 'soaper';
|
||||
|
||||
readonly label = 'Soaper';
|
||||
public readonly label = 'Soaper';
|
||||
|
||||
readonly ttl = 900000; // 15m
|
||||
public readonly ttl = 900000; // 15m
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/soaper/) && null !== url.pathname.match(/^\/(episode|movie)_/);
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/soaper/) && null !== url.pathname.match(/^\/(episode|movie)_/);
|
||||
|
||||
readonly normalize = (url: URL): URL => url;
|
||||
public readonly normalize = (url: URL): URL => url;
|
||||
|
||||
readonly extract = async (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[]> => {
|
||||
const movieOrEpisodeId = (url.pathname.match(/\/\w+_(\w+)/) as string[])[1] as string;
|
||||
|
||||
const form = new URLSearchParams();
|
||||
|
|
|
|||
|
|
@ -6,23 +6,23 @@ import { Context, CountryCode, UrlResult } from '../types';
|
|||
import { NotFoundError } from '../error';
|
||||
|
||||
export class SuperVideo implements Extractor {
|
||||
readonly id = 'supervideo';
|
||||
public readonly id = 'supervideo';
|
||||
|
||||
readonly label = 'SuperVideo';
|
||||
public readonly label = 'SuperVideo';
|
||||
|
||||
readonly ttl = 900000; // 15m
|
||||
public readonly ttl = 900000; // 15m
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/supervideo/);
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/supervideo/);
|
||||
|
||||
readonly normalize = (url: URL): URL => new URL(url.href.replace('/e/', '/').replace('/embed-', '/'));
|
||||
public readonly normalize = (url: URL): URL => new URL(url.href.replace('/e/', '/').replace('/embed-', '/'));
|
||||
|
||||
readonly extract = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
public readonly extract = async (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')) {
|
||||
|
|
|
|||
|
|
@ -6,23 +6,23 @@ import { Context, CountryCode, UrlResult } from '../types';
|
|||
import { NotFoundError } from '../error';
|
||||
|
||||
export class VidSrc implements Extractor {
|
||||
readonly id = 'vidsrc';
|
||||
public readonly id = 'vidsrc';
|
||||
|
||||
readonly label = 'VidSrc';
|
||||
public readonly label = 'VidSrc';
|
||||
|
||||
readonly ttl = 900000; // 15m
|
||||
public readonly ttl = 900000; // 15m
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/vidsrc/);
|
||||
public readonly supports = (_ctx: Context, url: URL): boolean => null !== url.host.match(/vidsrc/);
|
||||
|
||||
readonly normalize = (url: URL): URL => url;
|
||||
public readonly normalize = (url: URL): URL => url;
|
||||
|
||||
readonly extract = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
public readonly extract = async (ctx: Context, url: URL, countryCode: CountryCode): Promise<UrlResult[]> => {
|
||||
const html = await this.fetcher.text(ctx, url);
|
||||
|
||||
const $ = cheerio.load(html);
|
||||
|
|
|
|||
|
|
@ -5,21 +5,21 @@ import { Fetcher, getImdbId, Id, ImdbId } from '../utils';
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class CineHDPlus implements Source {
|
||||
readonly id = 'cinehdplus';
|
||||
public readonly id = 'cinehdplus';
|
||||
|
||||
readonly label = 'CineHDPlus';
|
||||
public readonly label = 'CineHDPlus';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['series'];
|
||||
public readonly contentTypes: ContentType[] = ['series'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.es, CountryCode.mx];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.es, CountryCode.mx];
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const seriesPageUrl = await this.fetchSeriesPageUrl(ctx, imdbId);
|
||||
|
|
|
|||
|
|
@ -5,21 +5,21 @@ import { Fetcher, getImdbId, Id, ImdbId } from '../utils';
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class Eurostreaming implements Source {
|
||||
readonly id = 'eurostreaming';
|
||||
public readonly id = 'eurostreaming';
|
||||
|
||||
readonly label = 'Eurostreaming';
|
||||
public readonly label = 'Eurostreaming';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['series'];
|
||||
public readonly contentTypes: ContentType[] = ['series'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.it];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.it];
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const seriesPageUrl = await this.fetchSeriesPageUrl(ctx, imdbId);
|
||||
|
|
|
|||
|
|
@ -4,21 +4,21 @@ import { Fetcher, getTmdbId, Id } from '../utils';
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class Frembed implements Source {
|
||||
readonly id = 'frembed';
|
||||
public readonly id = 'frembed';
|
||||
|
||||
readonly label = 'Frembed';
|
||||
public readonly label = 'Frembed';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['series'];
|
||||
public readonly contentTypes: ContentType[] = ['series'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.fr];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.fr];
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (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`);
|
||||
|
|
|
|||
|
|
@ -5,21 +5,21 @@ import { Fetcher, getImdbId, Id } from '../utils';
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class FrenchCloud implements Source {
|
||||
readonly id = 'frenchcloud';
|
||||
public readonly id = 'frenchcloud';
|
||||
|
||||
readonly label = 'FrenchCloud';
|
||||
public readonly label = 'FrenchCloud';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['movie'];
|
||||
public readonly contentTypes: ContentType[] = ['movie'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.fr];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.fr];
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (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}`);
|
||||
|
|
|
|||
|
|
@ -5,23 +5,23 @@ import { Fetcher, getTmdbId, getTmdbMovieDetails, getTmdbTvDetails, Id, TmdbId }
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class KinoGer implements Source {
|
||||
readonly id = 'kinoger';
|
||||
public readonly id = 'kinoger';
|
||||
|
||||
readonly label = 'KinoGer';
|
||||
public readonly label = 'KinoGer';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['movie', 'series'];
|
||||
public readonly contentTypes: ContentType[] = ['movie', 'series'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.de];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.de];
|
||||
|
||||
private readonly baseUrl = 'https://kinoger.com';
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
const tmdbId = await getTmdbId(ctx, this.fetcher, id);
|
||||
|
||||
const [keyword, year] = await this.getKeywordAndYear(ctx, tmdbId);
|
||||
|
|
|
|||
|
|
@ -5,21 +5,21 @@ import { Fetcher, getImdbId, Id } from '../utils';
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class MeineCloud implements Source {
|
||||
readonly id = 'meinecloud';
|
||||
public readonly id = 'meinecloud';
|
||||
|
||||
readonly label = 'MeineCloud';
|
||||
public readonly label = 'MeineCloud';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['movie'];
|
||||
public readonly contentTypes: ContentType[] = ['movie'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.de];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.de];
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (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}`);
|
||||
|
|
|
|||
|
|
@ -5,21 +5,21 @@ import { Fetcher, getImdbId, Id } from '../utils';
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class MostraGuarda implements Source {
|
||||
readonly id = 'mostraguarda';
|
||||
public readonly id = 'mostraguarda';
|
||||
|
||||
readonly label = 'MostraGuarda';
|
||||
public readonly label = 'MostraGuarda';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['movie'];
|
||||
public readonly contentTypes: ContentType[] = ['movie'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.it];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.it];
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (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}`);
|
||||
|
|
|
|||
|
|
@ -5,23 +5,23 @@ import { Fetcher, getTmdbId, getTmdbMovieDetails, getTmdbTvDetails, Id, TmdbId }
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class Soaper implements Source {
|
||||
readonly id = 'soaper';
|
||||
public readonly id = 'soaper';
|
||||
|
||||
readonly label = 'Soaper';
|
||||
public readonly label = 'Soaper';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['movie', 'series'];
|
||||
public readonly contentTypes: ContentType[] = ['movie', 'series'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.en];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.en];
|
||||
|
||||
private readonly baseUrl = 'https://soaper.live';
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (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);
|
||||
|
|
|
|||
|
|
@ -5,21 +5,21 @@ import { ImdbId, Fetcher, getImdbId, Id } from '../utils';
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class StreamKiste implements Source {
|
||||
readonly id = 'streamkiste';
|
||||
public readonly id = 'streamkiste';
|
||||
|
||||
readonly label = 'StreamKiste';
|
||||
public readonly label = 'StreamKiste';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['series'];
|
||||
public readonly contentTypes: ContentType[] = ['series'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.de];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.de];
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const seriesPageUrl = await this.fetchSeriesPageUrl(ctx, imdbId);
|
||||
|
|
|
|||
|
|
@ -5,21 +5,21 @@ import { Fetcher, getImdbId, Id } from '../utils';
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class VerHdLink implements Source {
|
||||
readonly id = 'verhdlink';
|
||||
public readonly id = 'verhdlink';
|
||||
|
||||
readonly label = 'VerHdLink';
|
||||
public readonly label = 'VerHdLink';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['movie'];
|
||||
public readonly contentTypes: ContentType[] = ['movie'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.es, CountryCode.mx];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.es, CountryCode.mx];
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (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}`);
|
||||
|
|
|
|||
|
|
@ -4,23 +4,23 @@ import { Fetcher, getImdbId, Id } from '../utils';
|
|||
import { Context, CountryCode } from '../types';
|
||||
|
||||
export class VidSrc implements Source {
|
||||
readonly id = 'vidsrc';
|
||||
public readonly id = 'vidsrc';
|
||||
|
||||
readonly label = 'VidSrc';
|
||||
public readonly label = 'VidSrc';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['movie', 'series'];
|
||||
public readonly contentTypes: ContentType[] = ['movie', 'series'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.en];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.en];
|
||||
|
||||
private readonly baseUrl = 'https://vidsrc.xyz';
|
||||
|
||||
private readonly fetcher: Fetcher;
|
||||
|
||||
constructor(fetcher: Fetcher) {
|
||||
public constructor(fetcher: Fetcher) {
|
||||
this.fetcher = fetcher;
|
||||
}
|
||||
|
||||
readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (ctx: Context, _type: string, id: Id): Promise<SourceResult[]> => {
|
||||
const imdbId = await getImdbId(ctx, this.fetcher, id);
|
||||
|
||||
const url = imdbId.season
|
||||
|
|
|
|||
|
|
@ -58,21 +58,21 @@ export class Fetcher {
|
|||
private readonly hostQueueCount = new Map<string, number>();
|
||||
private readonly countMutex = new Mutex();
|
||||
|
||||
constructor(logger: winston.Logger) {
|
||||
public constructor(logger: winston.Logger) {
|
||||
this.logger = logger;
|
||||
|
||||
this.httpCache = new TTLCache();
|
||||
}
|
||||
|
||||
readonly text = async (ctx: Context, url: URL, init?: CustomRequestInit): Promise<string> => {
|
||||
public readonly text = async (ctx: Context, url: URL, init?: CustomRequestInit): Promise<string> => {
|
||||
return (await this.cachedFetch(ctx, url, init)).body;
|
||||
};
|
||||
|
||||
readonly textPost = async (ctx: Context, url: URL, body: string, init?: CustomRequestInit): Promise<string> => {
|
||||
public readonly textPost = async (ctx: Context, url: URL, body: string, init?: CustomRequestInit): Promise<string> => {
|
||||
return (await this.cachedFetch(ctx, url, { ...init, method: 'POST', body })).body;
|
||||
};
|
||||
|
||||
readonly head = async (ctx: Context, url: URL, init?: CustomRequestInit): Promise<CachePolicy.Headers> => {
|
||||
public readonly head = async (ctx: Context, url: URL, init?: CustomRequestInit): Promise<CachePolicy.Headers> => {
|
||||
return (await this.cachedFetch(ctx, url, { ...init, method: 'HEAD' })).policy.responseHeaders();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -64,31 +64,31 @@ describe('resolve', () => {
|
|||
|
||||
test('adds error info', async () => {
|
||||
class MockHandler implements Source {
|
||||
readonly id = 'mockhandler';
|
||||
public readonly id = 'mockhandler';
|
||||
|
||||
readonly label = 'MockHandler';
|
||||
public readonly label = 'MockHandler';
|
||||
|
||||
readonly contentTypes: ContentType[] = ['movie'];
|
||||
public readonly contentTypes: ContentType[] = ['movie'];
|
||||
|
||||
readonly countryCodes: CountryCode[] = [CountryCode.de];
|
||||
public readonly countryCodes: CountryCode[] = [CountryCode.de];
|
||||
|
||||
readonly handle = async (): Promise<SourceResult[]> => {
|
||||
public readonly handle = async (): Promise<SourceResult[]> => {
|
||||
return [{ countryCode: CountryCode.de, url: new URL('https://example.com') }];
|
||||
};
|
||||
}
|
||||
|
||||
class MockExtractor implements Extractor {
|
||||
readonly id = 'mockextractor';
|
||||
public readonly id = 'mockextractor';
|
||||
|
||||
readonly label = 'MockExtractor';
|
||||
public readonly label = 'MockExtractor';
|
||||
|
||||
readonly ttl = 1;
|
||||
public readonly ttl = 1;
|
||||
|
||||
readonly supports = (): boolean => true;
|
||||
public readonly supports = (): boolean => true;
|
||||
|
||||
readonly normalize = (url: URL): URL => url;
|
||||
public readonly normalize = (url: URL): URL => url;
|
||||
|
||||
readonly extract = async (): Promise<UrlResult[]> =>
|
||||
public readonly extract = async (): Promise<UrlResult[]> =>
|
||||
[
|
||||
{
|
||||
url: new URL('https://example.com'),
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ export class StreamResolver {
|
|||
private readonly logger: winston.Logger;
|
||||
private readonly extractorRegistry: ExtractorRegistry;
|
||||
|
||||
constructor(logger: winston.Logger, extractorRegistry: ExtractorRegistry) {
|
||||
public constructor(logger: winston.Logger, extractorRegistry: ExtractorRegistry) {
|
||||
this.logger = logger;
|
||||
this.extractorRegistry = extractorRegistry;
|
||||
}
|
||||
|
||||
readonly resolve = async (ctx: Context, sources: Source[], type: ContentType, id: Id): Promise<ResolveResponse> => {
|
||||
public readonly resolve = async (ctx: Context, sources: Source[], type: ContentType, id: Id): Promise<ResolveResponse> => {
|
||||
if (sources.length === 0) {
|
||||
return {
|
||||
streams: [
|
||||
|
|
|
|||
|
|
@ -9,23 +9,23 @@ const { Fetcher } = jest.requireActual('../Fetcher');
|
|||
class MockedFetcher {
|
||||
private readonly fetcher: typeof Fetcher;
|
||||
|
||||
constructor() {
|
||||
public constructor() {
|
||||
this.fetcher = new Fetcher(winston.createLogger({ transports: [new winston.transports.Console()] }));
|
||||
}
|
||||
|
||||
readonly text = async (ctx: Context, url: URL, init?: RequestInit): Promise<string> => {
|
||||
public readonly text = async (ctx: Context, url: URL, init?: RequestInit): Promise<string> => {
|
||||
const path = `${__dirname}/../__fixtures__/Fetcher/${this.slugifyUrl(url)}`;
|
||||
|
||||
return this.fetch(path, ctx, url, init);
|
||||
};
|
||||
|
||||
readonly textPost = async (ctx: Context, url: URL, body: string, init?: RequestInit): Promise<string> => {
|
||||
public readonly textPost = async (ctx: Context, url: URL, body: string, init?: RequestInit): Promise<string> => {
|
||||
const path = `${__dirname}/../__fixtures__/Fetcher/post-${this.slugifyUrl(url)}-${slugify(body)}`;
|
||||
|
||||
return this.fetch(path, ctx, url, { ...init, method: 'POST', body });
|
||||
};
|
||||
|
||||
readonly head = async (ctx: Context, url: URL, init?: RequestInit): Promise<unknown> => {
|
||||
public readonly head = async (ctx: Context, url: URL, init?: RequestInit): Promise<unknown> => {
|
||||
const path = `${__dirname}/../__fixtures__/Fetcher/head-${this.slugifyUrl(url)}`;
|
||||
|
||||
return JSON.parse(await this.fetch(path, ctx, url, { ...init, method: 'HEAD' }));
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ export class ImdbId {
|
|||
public readonly season: number | undefined;
|
||||
public readonly episode: number | undefined;
|
||||
|
||||
constructor(id: string, season: number | undefined, episode: number | undefined) {
|
||||
public constructor(id: string, season: number | undefined, episode: number | undefined) {
|
||||
this.id = id;
|
||||
this.season = season;
|
||||
this.episode = episode;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ export class TmdbId {
|
|||
public readonly season: number | undefined;
|
||||
public readonly episode: number | undefined;
|
||||
|
||||
constructor(id: number, season: number | undefined, episode: number | undefined) {
|
||||
public constructor(id: number, season: number | undefined, episode: number | undefined) {
|
||||
this.id = id;
|
||||
this.season = season;
|
||||
this.episode = episode;
|
||||
|
|
|
|||
Loading…
Reference in a new issue