mirror of
https://github.com/movie-web/providers.git
synced 2025-09-13 16:43:25 +00:00
Rename flags + rename targets + add disallowed section to feature mapping
This commit is contained in:
@@ -15,40 +15,52 @@ export function makeProviderMocks() {
|
||||
|
||||
const sourceA = {
|
||||
id: 'a',
|
||||
name: 'A',
|
||||
rank: 1,
|
||||
disabled: false,
|
||||
flags: [],
|
||||
} as Sourcerer;
|
||||
const sourceB = {
|
||||
id: 'b',
|
||||
name: 'B',
|
||||
rank: 2,
|
||||
disabled: false,
|
||||
flags: [],
|
||||
} as Sourcerer;
|
||||
const sourceCDisabled = {
|
||||
id: 'c',
|
||||
name: 'C',
|
||||
rank: 3,
|
||||
disabled: true,
|
||||
flags: [],
|
||||
} as Sourcerer;
|
||||
const sourceAHigherRank = {
|
||||
id: 'a',
|
||||
name: 'A',
|
||||
rank: 100,
|
||||
disabled: false,
|
||||
flags: [],
|
||||
} as Sourcerer;
|
||||
const sourceGSameRankAsA = {
|
||||
id: 'g',
|
||||
name: 'G',
|
||||
rank: 1,
|
||||
disabled: false,
|
||||
flags: [],
|
||||
} as Sourcerer;
|
||||
const fullSourceYMovie = {
|
||||
id: 'y',
|
||||
name: 'Y',
|
||||
rank: 105,
|
||||
scrapeMovie: vi.fn(),
|
||||
flags: [],
|
||||
} as Sourcerer;
|
||||
const fullSourceYShow = {
|
||||
id: 'y',
|
||||
name: 'Y',
|
||||
rank: 105,
|
||||
scrapeShow: vi.fn(),
|
||||
flags: [],
|
||||
} as Sourcerer;
|
||||
const fullSourceZBoth = {
|
||||
id: 'z',
|
||||
@@ -56,6 +68,7 @@ const fullSourceZBoth = {
|
||||
rank: 106,
|
||||
scrapeMovie: vi.fn(),
|
||||
scrapeShow: vi.fn(),
|
||||
flags: [],
|
||||
} as Sourcerer;
|
||||
|
||||
const embedD = {
|
||||
|
@@ -1,12 +1,14 @@
|
||||
import { mockEmbeds, mockSources } from '@/__test__/providerTests';
|
||||
import { FeatureMap } from '@/main/targets.ts';
|
||||
import { getProviders } from '@/providers/get';
|
||||
import { vi, describe, it, expect, afterEach } from 'vitest';
|
||||
|
||||
const mocks = await vi.hoisted(async () => (await import('../providerTests.ts')).makeProviderMocks());
|
||||
vi.mock('@/providers/all', () => mocks);
|
||||
|
||||
const features = {
|
||||
const features: FeatureMap = {
|
||||
requires: [],
|
||||
disallowed: []
|
||||
}
|
||||
|
||||
describe('getProviders()', () => {
|
||||
|
77
src/__test__/utils/features.test.ts
Normal file
77
src/__test__/utils/features.test.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { FeatureMap, Flags, flags, flagsAllowedInFeatures } from "@/main/targets";
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
describe('flagsAllowedInFeatures()', () => {
|
||||
function checkFeatures(featureMap: FeatureMap, flags: Flags[], output: boolean) {
|
||||
expect(flagsAllowedInFeatures(featureMap, flags)).toEqual(output);
|
||||
}
|
||||
|
||||
it('should check required correctly', () => {
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: []
|
||||
}, [], true);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: []
|
||||
}, [flags.CORS_ALLOWED], true);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: []
|
||||
}, [], false);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED, flags.IP_LOCKED],
|
||||
disallowed: []
|
||||
}, [flags.CORS_ALLOWED, flags.IP_LOCKED], true);
|
||||
checkFeatures({
|
||||
requires: [flags.IP_LOCKED],
|
||||
disallowed: []
|
||||
}, [flags.CORS_ALLOWED], false);
|
||||
checkFeatures({
|
||||
requires: [flags.IP_LOCKED],
|
||||
disallowed: []
|
||||
}, [], false);
|
||||
});
|
||||
|
||||
it('should check disallowed correctly', () => {
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: []
|
||||
}, [], true);
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: [flags.CORS_ALLOWED]
|
||||
}, [], true);
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: [flags.CORS_ALLOWED]
|
||||
}, [flags.CORS_ALLOWED], false);
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: [flags.CORS_ALLOWED]
|
||||
}, [flags.IP_LOCKED], true);
|
||||
checkFeatures({
|
||||
requires: [],
|
||||
disallowed: [flags.CORS_ALLOWED, flags.IP_LOCKED]
|
||||
}, [flags.CORS_ALLOWED], false);
|
||||
});
|
||||
|
||||
it('should pass mixed tests', () => {
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: [flags.IP_LOCKED]
|
||||
}, [], false);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: [flags.IP_LOCKED]
|
||||
}, [flags.CORS_ALLOWED], true);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: [flags.IP_LOCKED]
|
||||
}, [flags.IP_LOCKED], false);
|
||||
checkFeatures({
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: [flags.IP_LOCKED]
|
||||
}, [flags.IP_LOCKED, flags.CORS_ALLOWED], false);
|
||||
});
|
||||
});
|
@@ -5,7 +5,7 @@ import { scrapeIndividualEmbed, scrapeInvidualSource } from '@/main/individualRu
|
||||
import { ScrapeMedia } from '@/main/media';
|
||||
import { MetaOutput, getAllEmbedMetaSorted, getAllSourceMetaSorted, getSpecificId } from '@/main/meta';
|
||||
import { RunOutput, runAllProviders } from '@/main/runner';
|
||||
import { Targets, getTargetFeatures } from '@/main/targets';
|
||||
import { Targets, flags, getTargetFeatures } from '@/main/targets';
|
||||
import { EmbedOutput, SourcererOutput } from '@/providers/base';
|
||||
import { getProviders } from '@/providers/get';
|
||||
|
||||
@@ -19,6 +19,10 @@ export interface ProviderBuilderOptions {
|
||||
|
||||
// target of where the streams will be used
|
||||
target: Targets;
|
||||
|
||||
// Set this to true, if the requests will have the same IP as
|
||||
// the device that the stream will be played on
|
||||
consistentIpForRequests?: boolean;
|
||||
}
|
||||
|
||||
export interface RunnerOptions {
|
||||
@@ -82,6 +86,7 @@ export interface ProviderControls {
|
||||
|
||||
export function makeProviders(ops: ProviderBuilderOptions): ProviderControls {
|
||||
const features = getTargetFeatures(ops.target);
|
||||
if (!ops.consistentIpForRequests) features.disallowed.push(flags.IP_LOCKED);
|
||||
const list = getProviders(features);
|
||||
const providerRunnerOps = {
|
||||
features,
|
||||
|
@@ -1,31 +1,51 @@
|
||||
export const flags = {
|
||||
NO_CORS: 'no-cors',
|
||||
// CORS are set to allow any origin
|
||||
CORS_ALLOWED: 'cors-allowed',
|
||||
|
||||
// the stream is locked on IP, so only works if
|
||||
// request maker is same as player (not compatible with proxies)
|
||||
IP_LOCKED: 'ip-locked',
|
||||
} as const;
|
||||
|
||||
export type Flags = (typeof flags)[keyof typeof flags];
|
||||
|
||||
export const targets = {
|
||||
// browser with CORS restrictions
|
||||
BROWSER: 'browser',
|
||||
|
||||
// browser, but no CORS restrictions through a browser extension
|
||||
BROWSER_EXTENSION: 'browser-extension',
|
||||
|
||||
// native app, so no restrictions in what can be played
|
||||
NATIVE: 'native',
|
||||
ALL: 'all',
|
||||
|
||||
// any target, no target restrictions
|
||||
ANY: 'any',
|
||||
} as const;
|
||||
|
||||
export type Targets = (typeof targets)[keyof typeof targets];
|
||||
|
||||
export type FeatureMap = {
|
||||
requires: readonly Flags[];
|
||||
requires: Flags[];
|
||||
disallowed: Flags[];
|
||||
};
|
||||
|
||||
export const targetToFeatures: Record<Targets, FeatureMap> = {
|
||||
browser: {
|
||||
requires: [flags.NO_CORS],
|
||||
requires: [flags.CORS_ALLOWED],
|
||||
disallowed: [],
|
||||
},
|
||||
'browser-extension': {
|
||||
requires: [],
|
||||
disallowed: [],
|
||||
},
|
||||
native: {
|
||||
requires: [],
|
||||
disallowed: [],
|
||||
},
|
||||
all: {
|
||||
any: {
|
||||
requires: [],
|
||||
disallowed: [],
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -36,5 +56,7 @@ export function getTargetFeatures(target: Targets): FeatureMap {
|
||||
export function flagsAllowedInFeatures(features: FeatureMap, inputFlags: Flags[]): boolean {
|
||||
const hasAllFlags = features.requires.every((v) => inputFlags.includes(v));
|
||||
if (!hasAllFlags) return false;
|
||||
const hasDisallowedFlag = features.disallowed.some((v) => inputFlags.includes(v));
|
||||
if (hasDisallowedFlag) return false;
|
||||
return true;
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ export const febboxHlsScraper = makeEmbed({
|
||||
return {
|
||||
stream: {
|
||||
type: 'hls',
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: await getSubtitles(ctx, id, firstStream.fid, type as MediaTypes, season, episode),
|
||||
playlist: `https://www.febbox.com/hls/main/${firstStream.oss_fid}.m3u8`,
|
||||
},
|
||||
|
@@ -43,7 +43,7 @@ export const febboxMp4Scraper = makeEmbed({
|
||||
captions: await getSubtitles(ctx, id, fid, type, episode, season),
|
||||
qualities,
|
||||
type: 'file',
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
},
|
||||
};
|
||||
},
|
||||
|
@@ -17,7 +17,7 @@ export const mp4uploadScraper = makeEmbed({
|
||||
return {
|
||||
stream: {
|
||||
type: 'file',
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
qualities: {
|
||||
'1080': {
|
||||
|
@@ -60,7 +60,7 @@ export const smashyStreamDScraper = makeEmbed({
|
||||
stream: {
|
||||
playlist: playlistRes,
|
||||
type: 'hls',
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
},
|
||||
};
|
||||
|
@@ -45,7 +45,7 @@ export const smashyStreamFScraper = makeEmbed({
|
||||
stream: {
|
||||
playlist: res.sourceUrls[0],
|
||||
type: 'hls',
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions,
|
||||
},
|
||||
};
|
||||
|
@@ -157,7 +157,7 @@ export const streamsbScraper = makeEmbed({
|
||||
return {
|
||||
stream: {
|
||||
type: 'file',
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
qualities,
|
||||
captions: [],
|
||||
},
|
||||
|
@@ -121,7 +121,7 @@ export const upcloudScraper = makeEmbed({
|
||||
stream: {
|
||||
type: 'hls',
|
||||
playlist: sources.file,
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions,
|
||||
},
|
||||
};
|
||||
|
@@ -24,7 +24,7 @@ export const upstreamScraper = makeEmbed({
|
||||
stream: {
|
||||
type: 'hls',
|
||||
playlist: link[1],
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
},
|
||||
};
|
||||
|
@@ -9,7 +9,7 @@ export const flixhqScraper = makeSourcerer({
|
||||
id: 'flixhq',
|
||||
name: 'FlixHQ',
|
||||
rank: 100,
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
async scrapeMovie(ctx) {
|
||||
const id = await getFlixhqId(ctx, ctx.media);
|
||||
if (!id) throw new NotFoundError('no search results match');
|
||||
|
@@ -13,7 +13,7 @@ export const goMoviesScraper = makeSourcerer({
|
||||
id: 'gomovies',
|
||||
name: 'GOmovies',
|
||||
rank: 110,
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
async scrapeShow(ctx) {
|
||||
const search = await ctx.proxiedFetcher<string>(`/ajax/search`, {
|
||||
method: 'POST',
|
||||
|
@@ -13,7 +13,7 @@ export const kissAsianScraper = makeSourcerer({
|
||||
id: 'kissasian',
|
||||
name: 'KissAsian',
|
||||
rank: 130,
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
disabled: true,
|
||||
|
||||
async scrapeShow(ctx) {
|
||||
|
@@ -8,7 +8,7 @@ export const remotestreamScraper = makeSourcerer({
|
||||
id: 'remotestream',
|
||||
name: 'Remote Stream',
|
||||
rank: 55,
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
async scrapeShow(ctx) {
|
||||
const seasonNumber = ctx.media.season.number;
|
||||
const episodeNumber = ctx.media.episode.number;
|
||||
@@ -26,7 +26,7 @@ export const remotestreamScraper = makeSourcerer({
|
||||
captions: [],
|
||||
playlist: playlistLink,
|
||||
type: 'hls',
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
},
|
||||
};
|
||||
},
|
||||
@@ -44,7 +44,7 @@ export const remotestreamScraper = makeSourcerer({
|
||||
captions: [],
|
||||
playlist: playlistLink,
|
||||
type: 'hls',
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
},
|
||||
};
|
||||
},
|
||||
|
@@ -47,7 +47,7 @@ export const showboxScraper = makeSourcerer({
|
||||
id: 'showbox',
|
||||
name: 'Showbox',
|
||||
rank: 300,
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
scrapeShow: comboScraper,
|
||||
scrapeMovie: comboScraper,
|
||||
});
|
||||
|
@@ -58,7 +58,7 @@ export const smashyStreamScraper = makeSourcerer({
|
||||
id: 'smashystream',
|
||||
name: 'SmashyStream',
|
||||
rank: 70,
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
scrapeMovie: universalScraper,
|
||||
scrapeShow: universalScraper,
|
||||
});
|
||||
|
@@ -7,7 +7,7 @@ export const zoechipScraper = makeSourcerer({
|
||||
id: 'zoechip',
|
||||
name: 'ZoeChip',
|
||||
rank: 200,
|
||||
flags: [flags.NO_CORS],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
scrapeMovie,
|
||||
scrapeShow,
|
||||
});
|
||||
|
Reference in New Issue
Block a user