Rename flags + rename targets + add disallowed section to feature mapping

This commit is contained in:
mrjvs
2023-12-24 19:18:46 +01:00
parent 0fe2fb40e1
commit a64a80cf12
20 changed files with 143 additions and 24 deletions

View File

@@ -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 = {

View File

@@ -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()', () => {

View 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);
});
});

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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`,
},

View File

@@ -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],
},
};
},

View File

@@ -17,7 +17,7 @@ export const mp4uploadScraper = makeEmbed({
return {
stream: {
type: 'file',
flags: [flags.NO_CORS],
flags: [flags.CORS_ALLOWED],
captions: [],
qualities: {
'1080': {

View File

@@ -60,7 +60,7 @@ export const smashyStreamDScraper = makeEmbed({
stream: {
playlist: playlistRes,
type: 'hls',
flags: [flags.NO_CORS],
flags: [flags.CORS_ALLOWED],
captions: [],
},
};

View File

@@ -45,7 +45,7 @@ export const smashyStreamFScraper = makeEmbed({
stream: {
playlist: res.sourceUrls[0],
type: 'hls',
flags: [flags.NO_CORS],
flags: [flags.CORS_ALLOWED],
captions,
},
};

View File

@@ -157,7 +157,7 @@ export const streamsbScraper = makeEmbed({
return {
stream: {
type: 'file',
flags: [flags.NO_CORS],
flags: [flags.CORS_ALLOWED],
qualities,
captions: [],
},

View File

@@ -121,7 +121,7 @@ export const upcloudScraper = makeEmbed({
stream: {
type: 'hls',
playlist: sources.file,
flags: [flags.NO_CORS],
flags: [flags.CORS_ALLOWED],
captions,
},
};

View File

@@ -24,7 +24,7 @@ export const upstreamScraper = makeEmbed({
stream: {
type: 'hls',
playlist: link[1],
flags: [flags.NO_CORS],
flags: [flags.CORS_ALLOWED],
captions: [],
},
};

View File

@@ -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');

View File

@@ -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',

View File

@@ -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) {

View File

@@ -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],
},
};
},

View File

@@ -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,
});

View File

@@ -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,
});

View File

@@ -7,7 +7,7 @@ export const zoechipScraper = makeSourcerer({
id: 'zoechip',
name: 'ZoeChip',
rank: 200,
flags: [flags.NO_CORS],
flags: [flags.CORS_ALLOWED],
scrapeMovie,
scrapeShow,
});