mirror of
https://github.com/sussy-code/providers.git
synced 2026-08-14 19:25:12 +00:00
add rive
This commit is contained in:
parent
aef3887293
commit
b618e2387c
3 changed files with 337 additions and 0 deletions
|
|
@ -1,6 +1,20 @@
|
|||
import { Embed, Sourcerer } from '@/providers/base';
|
||||
import { doodScraper } from '@/providers/embeds/dood';
|
||||
import { mixdropScraper } from '@/providers/embeds/mixdrop';
|
||||
import {
|
||||
riveAsiacloudScraper,
|
||||
riveEe3Scraper,
|
||||
riveFastxScraper,
|
||||
riveFilmechoScraper,
|
||||
riveG1Scraper,
|
||||
riveG2Scraper,
|
||||
riveGhostScraper,
|
||||
riveGuruScraper,
|
||||
riveHydraxScraper,
|
||||
riveKageScraper,
|
||||
riveNovaScraper,
|
||||
rivePutafilmeScraper,
|
||||
} from '@/providers/embeds/rive';
|
||||
import { turbovidScraper } from '@/providers/embeds/turbovid';
|
||||
import { upcloudScraper } from '@/providers/embeds/upcloud';
|
||||
import { autoembedScraper } from '@/providers/sources/autoembed';
|
||||
|
|
@ -9,6 +23,7 @@ import { ee3Scraper } from '@/providers/sources/ee3';
|
|||
import { fsharetvScraper } from '@/providers/sources/fsharetv';
|
||||
import { insertunitScraper } from '@/providers/sources/insertunit';
|
||||
import { mp4hydraScraper } from '@/providers/sources/mp4hydra';
|
||||
import { riveScraper } from '@/providers/sources/rive';
|
||||
import { tugaflixScraper } from '@/providers/sources/tugaflix';
|
||||
import { vidsrcsuScraper } from '@/providers/sources/vidsrcsu';
|
||||
|
||||
|
|
@ -88,6 +103,7 @@ export function gatherAllSources(): Array<Sourcerer> {
|
|||
coitusScraper,
|
||||
streamboxScraper,
|
||||
nunflixScraper,
|
||||
riveScraper,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -134,5 +150,17 @@ export function gatherAllEmbeds(): Array<Embed> {
|
|||
FedAPIPrivateScraper,
|
||||
FedAPISharedScraper,
|
||||
FedDBScraper,
|
||||
riveAsiacloudScraper,
|
||||
riveEe3Scraper,
|
||||
riveFastxScraper,
|
||||
riveFilmechoScraper,
|
||||
riveG1Scraper,
|
||||
riveG2Scraper,
|
||||
riveGhostScraper,
|
||||
riveGuruScraper,
|
||||
riveHydraxScraper,
|
||||
riveKageScraper,
|
||||
riveNovaScraper,
|
||||
rivePutafilmeScraper,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
113
src/providers/embeds/rive.ts
Normal file
113
src/providers/embeds/rive.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import { flags } from '@/entrypoint/utils/targets';
|
||||
import { makeEmbed } from '@/providers/base';
|
||||
|
||||
const providers = [
|
||||
{
|
||||
id: 'rive-hydrax',
|
||||
rank: 270,
|
||||
},
|
||||
{
|
||||
id: 'rive-fastx',
|
||||
rank: 269,
|
||||
},
|
||||
{
|
||||
id: 'rive-filmecho',
|
||||
rank: 268,
|
||||
},
|
||||
{
|
||||
id: 'rive-nova',
|
||||
rank: 267,
|
||||
},
|
||||
{
|
||||
id: 'rive-guru',
|
||||
rank: 266,
|
||||
},
|
||||
{
|
||||
id: 'rive-g1',
|
||||
rank: 265,
|
||||
},
|
||||
{
|
||||
id: 'rive-g2',
|
||||
rank: 264,
|
||||
},
|
||||
{
|
||||
id: 'rive-ee3',
|
||||
rank: 263,
|
||||
},
|
||||
{
|
||||
id: 'rive-ghost',
|
||||
rank: 262,
|
||||
},
|
||||
{
|
||||
id: 'rive-putafilme',
|
||||
rank: 261,
|
||||
},
|
||||
{
|
||||
id: 'rive-asiacloud',
|
||||
rank: 260,
|
||||
},
|
||||
{
|
||||
id: 'rive-kage',
|
||||
rank: 259,
|
||||
},
|
||||
];
|
||||
|
||||
function embed(provider: { id: string; rank: number; disabled?: boolean }) {
|
||||
return makeEmbed({
|
||||
id: provider.id,
|
||||
name: provider.id
|
||||
.split('-')
|
||||
.map((word) => word[0].toUpperCase() + word.slice(1))
|
||||
.join(' '),
|
||||
disabled: provider.disabled,
|
||||
rank: provider.rank,
|
||||
async scrape(ctx) {
|
||||
const isHLS = ctx.url.includes('.m3u8') || ctx.url.includes('hls') || ctx.url.includes('playlist');
|
||||
|
||||
if (isHLS) {
|
||||
return {
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'hls',
|
||||
playlist: ctx.url,
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
return {
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'file',
|
||||
qualities: {
|
||||
unknown: {
|
||||
type: 'mp4',
|
||||
url: ctx.url,
|
||||
},
|
||||
},
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
captions: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const [
|
||||
riveHydraxScraper,
|
||||
riveFastxScraper,
|
||||
riveFilmechoScraper,
|
||||
riveNovaScraper,
|
||||
riveGuruScraper,
|
||||
riveG1Scraper,
|
||||
riveG2Scraper,
|
||||
riveEe3Scraper,
|
||||
riveGhostScraper,
|
||||
rivePutafilmeScraper,
|
||||
riveAsiacloudScraper,
|
||||
riveKageScraper,
|
||||
] = providers.map(embed);
|
||||
196
src/providers/sources/rive.ts
Normal file
196
src/providers/sources/rive.ts
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
import { flags } from '@/entrypoint/utils/targets';
|
||||
import { SourcererEmbed, SourcererOutput, makeSourcerer } from '@/providers/base';
|
||||
import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context';
|
||||
import { NotFoundError } from '@/utils/errors';
|
||||
|
||||
const baseUrl = 'https://rivestream.org';
|
||||
|
||||
function generateSecretKey(id: number | string) {
|
||||
const keyArray = [
|
||||
'I',
|
||||
'3LZu',
|
||||
'M2V3',
|
||||
'4EXX',
|
||||
's4',
|
||||
'yRy',
|
||||
'oqMz',
|
||||
'ysE',
|
||||
'RT',
|
||||
'iSI',
|
||||
'zlc',
|
||||
'H',
|
||||
'YNp',
|
||||
'5vR6',
|
||||
'h9S',
|
||||
'R',
|
||||
'jo',
|
||||
'F',
|
||||
'h2',
|
||||
'W8',
|
||||
'i',
|
||||
'sz09',
|
||||
'Xom',
|
||||
'gpU',
|
||||
'q',
|
||||
'6Qvg',
|
||||
'Cu',
|
||||
'5Zaz',
|
||||
'VK',
|
||||
'od',
|
||||
'FGY4',
|
||||
'eu',
|
||||
'D5Q',
|
||||
'smH',
|
||||
'11eq',
|
||||
'QrXs',
|
||||
'3',
|
||||
'L3',
|
||||
'YhlP',
|
||||
'c',
|
||||
'Z',
|
||||
'YT',
|
||||
'bnsy',
|
||||
'5',
|
||||
'fcL',
|
||||
'L22G',
|
||||
'r8',
|
||||
'J',
|
||||
'4',
|
||||
'gnK',
|
||||
];
|
||||
|
||||
// Handle undefined/null input
|
||||
if (typeof id === 'undefined' || id === null) {
|
||||
return 'rive';
|
||||
}
|
||||
|
||||
// Convert to number and calculate array index
|
||||
const numericId = typeof id === 'string' ? parseInt(id, 10) : Number(id);
|
||||
const index = numericId % keyArray.length;
|
||||
|
||||
// Handle NaN cases (invalid number conversion)
|
||||
if (Number.isNaN(index)) {
|
||||
return 'rive';
|
||||
}
|
||||
|
||||
return keyArray[index];
|
||||
}
|
||||
|
||||
function processProxiedURL(url: string): string {
|
||||
if (url.includes('orbitproxy')) {
|
||||
try {
|
||||
const urlParts = url.split(/orbitproxy\.[^/]+\//);
|
||||
if (urlParts.length >= 2) {
|
||||
const encryptedPart = urlParts[1].split('.m3u8')[0];
|
||||
try {
|
||||
const decodedData = Buffer.from(encryptedPart, 'base64').toString('utf-8');
|
||||
|
||||
const jsonData = JSON.parse(decodedData);
|
||||
const originalUrl = jsonData.u;
|
||||
const referer = jsonData.r || '';
|
||||
|
||||
const encodedUrl = encodeURIComponent(originalUrl);
|
||||
const encodedHeaders = encodeURIComponent(
|
||||
JSON.stringify({
|
||||
referer,
|
||||
}),
|
||||
);
|
||||
|
||||
const proxyUrl = `https://m3u8.wafflehacker.io/m3u8-proxy?url=${encodedUrl}&headers=${encodedHeaders}`;
|
||||
return proxyUrl;
|
||||
} catch (jsonError) {
|
||||
console.error('Error decoding/parsing orbitproxy data:', jsonError);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing orbitproxy URL:', error);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
async function comboScraper(ctx: MovieScrapeContext | ShowScrapeContext): Promise<SourcererOutput> {
|
||||
const tmdbId = ctx.media.tmdbId;
|
||||
const secret = generateSecretKey(tmdbId);
|
||||
|
||||
const servers = [
|
||||
'hydrax',
|
||||
'fastx',
|
||||
'filmecho',
|
||||
'nova',
|
||||
'guru',
|
||||
'g1',
|
||||
'g2',
|
||||
'ee3',
|
||||
'ghost',
|
||||
'putafilme',
|
||||
'asiacloud',
|
||||
'kage',
|
||||
];
|
||||
|
||||
const route =
|
||||
ctx.media.type === 'show'
|
||||
? `/api/backendfetch?requestID=tvVideoProvider&id=${tmdbId}&season=${ctx.media.season.number}&episode=${ctx.media.episode.number}&secretKey=${secret}&service=`
|
||||
: `/api/backendfetch?requestID=movieVideoProvider&id=${tmdbId}&secretKey=${secret}&service=`;
|
||||
|
||||
ctx.progress(20);
|
||||
|
||||
const embeds: SourcererEmbed[] = [];
|
||||
const processedServers = new Set<string>();
|
||||
|
||||
await Promise.all(
|
||||
servers.map(async (server) => {
|
||||
try {
|
||||
const url = baseUrl + route + server;
|
||||
|
||||
const response = await ctx.proxiedFetcher(url, {
|
||||
headers: {
|
||||
Referer: baseUrl,
|
||||
},
|
||||
});
|
||||
|
||||
const data = typeof response === 'string' ? JSON.parse(response) : response;
|
||||
|
||||
if (!data?.data || !data?.data?.sources?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.data.sources.forEach((source: any) => {
|
||||
const processedUrl = processProxiedURL(source.url);
|
||||
|
||||
const serverKey = `rive-${server}`;
|
||||
|
||||
if (!processedServers.has(serverKey)) {
|
||||
processedServers.add(serverKey);
|
||||
|
||||
embeds.push({
|
||||
embedId: serverKey,
|
||||
url: processedUrl,
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Error fetching Rive ${server}:`, error);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
ctx.progress(90);
|
||||
|
||||
if (!embeds.length) {
|
||||
throw new NotFoundError('No embeds found from Rive');
|
||||
}
|
||||
|
||||
return {
|
||||
embeds,
|
||||
};
|
||||
}
|
||||
|
||||
export const riveScraper = makeSourcerer({
|
||||
id: 'rive',
|
||||
name: 'Rive',
|
||||
rank: 130,
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
scrapeMovie: comboScraper,
|
||||
scrapeShow: comboScraper,
|
||||
});
|
||||
Loading…
Reference in a new issue