Allow embeds and videos to return multiple streams + add identifiers to list returns
This commit is contained in:
parent
d44320e362
commit
0affe83d24
|
@ -1,9 +1,9 @@
|
|||
import { mockEmbeds, mockSources } from '@/__test__/providerTests';
|
||||
import { FeatureMap } from '@/main/targets.ts';
|
||||
import { FeatureMap } from '@/main/targets';
|
||||
import { getProviders } from '@/providers/get';
|
||||
import { vi, describe, it, expect, afterEach } from 'vitest';
|
||||
|
||||
const mocks = await vi.hoisted(async () => (await import('../providerTests.ts')).makeProviderMocks());
|
||||
const mocks = await vi.hoisted(async () => (await import('../providerTests')).makeProviderMocks());
|
||||
vi.mock('@/providers/all', () => mocks);
|
||||
|
||||
const features: FeatureMap = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { mockEmbeds, mockSources } from '@/__test__/providerTests';
|
||||
import { makeProviders } from '@/main/builder';
|
||||
import { targets } from '@/main/targets.ts';
|
||||
import { targets } from '@/main/targets';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const mocks = await vi.hoisted(async () => (await import('../providerTests.ts')).makeProviderMocks());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { mockEmbeds, mockSources } from '@/__test__/providerTests';
|
||||
import { makeProviders } from '@/main/builder';
|
||||
import { targets } from '@/main/targets.ts';
|
||||
import { targets } from '@/main/targets';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const mocks = await vi.hoisted(async () => (await import('../providerTests.ts')).makeProviderMocks());
|
||||
|
|
|
@ -9,7 +9,9 @@ describe('isValidStream()', () => {
|
|||
it('should pass valid streams', () => {
|
||||
expect(isValidStream({
|
||||
type: "file",
|
||||
id: "a",
|
||||
flags: [],
|
||||
captions: [],
|
||||
qualities: {
|
||||
"1080": {
|
||||
type: "mp4",
|
||||
|
@ -19,7 +21,9 @@ describe('isValidStream()', () => {
|
|||
})).toBe(true);
|
||||
expect(isValidStream({
|
||||
type: "hls",
|
||||
id: "a",
|
||||
flags: [],
|
||||
captions: [],
|
||||
playlist: "hello-world"
|
||||
})).toBe(true);
|
||||
});
|
||||
|
@ -27,7 +31,9 @@ describe('isValidStream()', () => {
|
|||
it('should detect empty qualities', () => {
|
||||
expect(isValidStream({
|
||||
type: "file",
|
||||
id: "a",
|
||||
flags: [],
|
||||
captions: [],
|
||||
qualities: {}
|
||||
})).toBe(false);
|
||||
});
|
||||
|
@ -35,7 +41,9 @@ describe('isValidStream()', () => {
|
|||
it('should detect empty stream urls', () => {
|
||||
expect(isValidStream({
|
||||
type: "file",
|
||||
id: "a",
|
||||
flags: [],
|
||||
captions: [],
|
||||
qualities: {
|
||||
"1080": {
|
||||
type: "mp4",
|
||||
|
@ -48,7 +56,9 @@ describe('isValidStream()', () => {
|
|||
it('should detect emtpy HLS playlists', () => {
|
||||
expect(isValidStream({
|
||||
type: "hls",
|
||||
id: "a",
|
||||
flags: [],
|
||||
captions: [],
|
||||
playlist: "",
|
||||
})).toBe(false);
|
||||
});
|
||||
|
|
|
@ -18,13 +18,13 @@ export type RunOutput = {
|
|||
|
||||
export type SourceRunOutput = {
|
||||
sourceId: string;
|
||||
stream?: Stream;
|
||||
stream: Stream[];
|
||||
embeds: [];
|
||||
};
|
||||
|
||||
export type EmbedRunOutput = {
|
||||
embedId: string;
|
||||
stream?: Stream;
|
||||
stream: Stream[];
|
||||
};
|
||||
|
||||
export type ProviderRunnerOptions = {
|
||||
|
|
|
@ -47,7 +47,7 @@ export const targetToFeatures: Record<Targets, FeatureMap> = {
|
|||
requires: [],
|
||||
disallowed: [],
|
||||
},
|
||||
} as const;
|
||||
};
|
||||
|
||||
export function getTargetFeatures(target: Targets): FeatureMap {
|
||||
return targetToFeatures[target];
|
||||
|
|
|
@ -9,7 +9,7 @@ export type SourcererEmbed = {
|
|||
|
||||
export type SourcererOutput = {
|
||||
embeds: SourcererEmbed[];
|
||||
stream?: Stream;
|
||||
stream?: Stream[];
|
||||
};
|
||||
|
||||
export type Sourcerer = {
|
||||
|
@ -27,7 +27,7 @@ export function makeSourcerer(state: Sourcerer): Sourcerer {
|
|||
}
|
||||
|
||||
export type EmbedOutput = {
|
||||
stream: Stream;
|
||||
stream: Stream[];
|
||||
};
|
||||
|
||||
export type Embed = {
|
||||
|
|
|
@ -8,6 +8,7 @@ export type CaptionType = keyof typeof captionTypes;
|
|||
|
||||
export type Caption = {
|
||||
type: CaptionType;
|
||||
id: string; // only unique per stream
|
||||
url: string;
|
||||
hasCorsRestrictions: boolean;
|
||||
language: string;
|
||||
|
|
|
@ -36,12 +36,15 @@ export const febboxHlsScraper = makeEmbed({
|
|||
ctx.progress(70);
|
||||
|
||||
return {
|
||||
stream: {
|
||||
type: 'hls',
|
||||
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`,
|
||||
},
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'hls',
|
||||
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`,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -39,12 +39,15 @@ export const febboxMp4Scraper = makeEmbed({
|
|||
ctx.progress(70);
|
||||
|
||||
return {
|
||||
stream: {
|
||||
captions: await getSubtitles(ctx, id, fid, type, episode, season),
|
||||
qualities,
|
||||
type: 'file',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
},
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
captions: await getSubtitles(ctx, id, fid, type, episode, season),
|
||||
qualities,
|
||||
type: 'file',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -54,6 +54,7 @@ export async function getSubtitles(
|
|||
if (!validCode) return;
|
||||
|
||||
output.push({
|
||||
id: subtitleFilePath,
|
||||
language: subtitle.lang,
|
||||
hasCorsRestrictions: true,
|
||||
type: subtitleType,
|
||||
|
|
|
@ -33,21 +33,24 @@ export const mixdropScraper = makeEmbed({
|
|||
const url = link[1];
|
||||
|
||||
return {
|
||||
stream: {
|
||||
type: 'file',
|
||||
flags: [],
|
||||
captions: [],
|
||||
qualities: {
|
||||
unknown: {
|
||||
type: 'mp4',
|
||||
url: url.startsWith('http') ? url : `https:${url}`, // URLs don't always start with the protocol
|
||||
headers: {
|
||||
// MixDrop requires this header on all streams
|
||||
Referer: 'https://mixdrop.co/',
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'file',
|
||||
flags: [],
|
||||
captions: [],
|
||||
qualities: {
|
||||
unknown: {
|
||||
type: 'mp4',
|
||||
url: url.startsWith('http') ? url : `https:${url}`, // URLs don't always start with the protocol
|
||||
headers: {
|
||||
// MixDrop requires this header on all streams
|
||||
Referer: 'https://mixdrop.co/',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -15,17 +15,20 @@ export const mp4uploadScraper = makeEmbed({
|
|||
if (!streamUrl) throw new Error('Stream url not found in embed code');
|
||||
|
||||
return {
|
||||
stream: {
|
||||
type: 'file',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
qualities: {
|
||||
'1080': {
|
||||
type: 'mp4',
|
||||
url: streamUrl,
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'file',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
qualities: {
|
||||
'1080': {
|
||||
type: 'mp4',
|
||||
url: streamUrl,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -57,12 +57,15 @@ export const smashyStreamDScraper = makeEmbed({
|
|||
);
|
||||
|
||||
return {
|
||||
stream: {
|
||||
playlist: playlistRes,
|
||||
type: 'hls',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
},
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
playlist: playlistRes,
|
||||
type: 'hls',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -30,6 +30,7 @@ export const smashyStreamFScraper = makeEmbed({
|
|||
const captionType = getCaptionTypeFromUrl(url);
|
||||
if (!languageCode || !captionType) return null;
|
||||
return {
|
||||
id: url,
|
||||
url: url.replace(',', ''),
|
||||
language: languageCode,
|
||||
type: captionType,
|
||||
|
@ -42,12 +43,15 @@ export const smashyStreamFScraper = makeEmbed({
|
|||
.filter((x): x is Caption => x !== null) ?? [];
|
||||
|
||||
return {
|
||||
stream: {
|
||||
playlist: res.sourceUrls[0],
|
||||
type: 'hls',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions,
|
||||
},
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
playlist: res.sourceUrls[0],
|
||||
type: 'hls',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -155,12 +155,15 @@ export const streamsbScraper = makeEmbed({
|
|||
}, {} as Record<string, StreamFile>);
|
||||
|
||||
return {
|
||||
stream: {
|
||||
type: 'file',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
qualities,
|
||||
captions: [],
|
||||
},
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'file',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
qualities,
|
||||
captions: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -110,6 +110,7 @@ export const upcloudScraper = makeEmbed({
|
|||
const language = labelToLanguageCode(track.label);
|
||||
if (!language) return;
|
||||
captions.push({
|
||||
id: track.file,
|
||||
language,
|
||||
hasCorsRestrictions: false,
|
||||
type,
|
||||
|
@ -118,12 +119,15 @@ export const upcloudScraper = makeEmbed({
|
|||
});
|
||||
|
||||
return {
|
||||
stream: {
|
||||
type: 'hls',
|
||||
playlist: sources.file,
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions,
|
||||
},
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'hls',
|
||||
playlist: sources.file,
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -21,12 +21,15 @@ export const upstreamScraper = makeEmbed({
|
|||
|
||||
if (link) {
|
||||
return {
|
||||
stream: {
|
||||
type: 'hls',
|
||||
playlist: link[1],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
},
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'hls',
|
||||
playlist: link[1],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,15 @@ async function universalScraper(ctx: MovieScrapeContext | ShowScrapeContext): Pr
|
|||
|
||||
return {
|
||||
embeds: [],
|
||||
stream: {
|
||||
playlist: videoUrl,
|
||||
type: 'hls',
|
||||
flags: [flags.IP_LOCKED],
|
||||
captions: [],
|
||||
},
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
playlist: videoUrl,
|
||||
type: 'hls',
|
||||
flags: [flags.IP_LOCKED],
|
||||
captions: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -22,12 +22,15 @@ export const remotestreamScraper = makeSourcerer({
|
|||
|
||||
return {
|
||||
embeds: [],
|
||||
stream: {
|
||||
captions: [],
|
||||
playlist: playlistLink,
|
||||
type: 'hls',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
},
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
captions: [],
|
||||
playlist: playlistLink,
|
||||
type: 'hls',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
async scrapeMovie(ctx) {
|
||||
|
@ -40,12 +43,15 @@ export const remotestreamScraper = makeSourcerer({
|
|||
|
||||
return {
|
||||
embeds: [],
|
||||
stream: {
|
||||
captions: [],
|
||||
playlist: playlistLink,
|
||||
type: 'hls',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
},
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
captions: [],
|
||||
playlist: playlistLink,
|
||||
type: 'hls',
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -11,6 +11,7 @@ export type Qualities = 'unknown' | '360' | '480' | '720' | '1080' | '4k';
|
|||
|
||||
export type FileBasedStream = {
|
||||
type: 'file';
|
||||
id: string; // only unique per output
|
||||
flags: Flags[];
|
||||
qualities: Partial<Record<Qualities, StreamFile>>;
|
||||
captions: Caption[];
|
||||
|
@ -18,6 +19,7 @@ export type FileBasedStream = {
|
|||
|
||||
export type HlsBasedStream = {
|
||||
type: 'hls';
|
||||
id: string; // only unique per output
|
||||
flags: Flags[];
|
||||
playlist: string;
|
||||
captions: Caption[];
|
||||
|
|
Loading…
Reference in New Issue