Refactoring to try to align to codebase

- also rip filemoon
This commit is contained in:
vlOd 2025-12-10 03:01:09 +02:00
parent 6c5af97081
commit cfb8da1366
10 changed files with 48 additions and 167 deletions

14
package-lock.json generated
View file

@ -1680,7 +1680,6 @@
"integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
"dev": true, "dev": true,
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/scope-manager": "7.18.0",
"@typescript-eslint/types": "7.18.0", "@typescript-eslint/types": "7.18.0",
@ -2358,7 +2357,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@ -3472,8 +3470,7 @@
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz",
"integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==",
"dev": true, "dev": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause"
"peer": true
}, },
"node_modules/diff-sequences": { "node_modules/diff-sequences": {
"version": "29.6.3", "version": "29.6.3",
@ -3892,7 +3889,6 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
@ -3979,7 +3975,6 @@
"integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"eslint-config-prettier": "bin/cli.js" "eslint-config-prettier": "bin/cli.js"
}, },
@ -4078,7 +4073,6 @@
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@rtsao/scc": "^1.1.0", "@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.9", "array-includes": "^3.1.9",
@ -6902,7 +6896,6 @@
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"
}, },
@ -7244,7 +7237,6 @@
"integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@types/estree": "1.0.8" "@types/estree": "1.0.8"
}, },
@ -8112,7 +8104,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@ -8340,7 +8331,6 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -8477,7 +8467,6 @@
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.21.3", "esbuild": "^0.21.3",
"postcss": "^8.4.43", "postcss": "^8.4.43",
@ -8589,7 +8578,6 @@
"integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==", "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@vitest/expect": "1.6.1", "@vitest/expect": "1.6.1",
"@vitest/runner": "1.6.1", "@vitest/runner": "1.6.1",

View file

@ -1,6 +1,4 @@
import { Embed, Sourcerer } from '@/providers/base'; import { Embed, Sourcerer } from '@/providers/base';
import { dopeboxEmbeds, dopeboxScraper } from '@/providers/custom/dopebox/index';
import { fsOnlineEmbeds, fsOnlineScraper } from '@/providers/custom/fsonline/index';
import { doodScraper } from '@/providers/embeds/dood'; import { doodScraper } from '@/providers/embeds/dood';
import { filemoonScraper } from '@/providers/embeds/filemoon'; import { filemoonScraper } from '@/providers/embeds/filemoon';
import { mixdropScraper } from '@/providers/embeds/mixdrop'; import { mixdropScraper } from '@/providers/embeds/mixdrop';
@ -8,8 +6,10 @@ import { serverMirrorEmbed } from '@/providers/embeds/server-mirrors';
import { turbovidScraper } from '@/providers/embeds/turbovid'; import { turbovidScraper } from '@/providers/embeds/turbovid';
import { upcloudScraper } from '@/providers/embeds/upcloud'; import { upcloudScraper } from '@/providers/embeds/upcloud';
import { autoembedScraper } from '@/providers/sources/autoembed'; import { autoembedScraper } from '@/providers/sources/autoembed';
import { dopeboxEmbeds, dopeboxScraper } from '@/providers/sources/dopebox/index';
import { ee3Scraper } from '@/providers/sources/ee3'; import { ee3Scraper } from '@/providers/sources/ee3';
import { fsharetvScraper } from '@/providers/sources/fsharetv'; import { fsharetvScraper } from '@/providers/sources/fsharetv';
import { fsOnlineEmbeds, fsOnlineScraper } from '@/providers/sources/fsonline/index';
import { insertunitScraper } from '@/providers/sources/insertunit'; import { insertunitScraper } from '@/providers/sources/insertunit';
import { mp4hydraScraper } from '@/providers/sources/mp4hydra'; import { mp4hydraScraper } from '@/providers/sources/mp4hydra';
import { nepuScraper } from '@/providers/sources/nepu'; import { nepuScraper } from '@/providers/sources/nepu';

View file

@ -1,122 +0,0 @@
import * as cheerio from 'cheerio';
import type { CheerioAPI } from 'cheerio';
import { FetcherResponse } from '@/fetchers/types';
import { EmbedScrapeContext, ScrapeContext } from '@/utils/context';
import { ORIGIN_HOST, fetchIFrame, throwOnResponse } from './utils';
import { EmbedOutput } from '../../base';
const LOG_PREFIX = `[Filemoon]`;
const UNPACK_PARAMS_PATERN = /eval\(.+?}\(('.+'),(\d+),(\d+),('.+')\.split\('(.)'\).+/;
function unpack(payload: string, radix: number, id: number, map: string[]) {
while (id--) {
if (map[id]) {
payload = payload.replace(new RegExp(`\\b${id.toString(radix)}\\b`, 'g'), map[id]);
}
}
return payload;
}
function deobfuscatePlayerCfg(data: string): string | undefined {
const match = data.match(UNPACK_PARAMS_PATERN);
if (!match) {
return undefined;
}
const obfPayload: string = match[1];
const radix: number = Number.parseInt(match[2]);
const id: number = Number.parseInt(match[3]);
const obfMap: string = match[4];
const mapChar: string = match[5];
return unpack(obfPayload, radix, id, obfMap.split(mapChar));
}
async function getStream(ctx: ScrapeContext, url: string): Promise<string | undefined> {
console.log(LOG_PREFIX, 'Fetching iframe');
let $: CheerioAPI;
let vpReferer: string;
try {
const response: FetcherResponse | undefined = await fetchIFrame(ctx, url);
if (!response) {
return undefined;
}
$ = cheerio.load(await response.body);
vpReferer = response.finalUrl;
} catch (error) {
console.error(LOG_PREFIX, 'Failed to fetch iframe', error);
return undefined;
}
const videoPlayerURL: string | undefined = $('#iframe-holder').find('iframe').first().attr('src');
if (!videoPlayerURL) {
console.error(LOG_PREFIX, 'Could not find video player URL');
return undefined;
}
console.log(LOG_PREFIX, 'Video player URL', videoPlayerURL);
try {
const response: FetcherResponse = await ctx.proxiedFetcher.full(videoPlayerURL, {
headers: {
Referer: vpReferer,
Origin: ORIGIN_HOST,
},
});
throwOnResponse(response);
$ = cheerio.load(await response.body);
} catch (error) {
console.error(LOG_PREFIX, 'Failed to fetch video player', error);
return undefined;
}
let streamURL: string | undefined;
$('script').each((_, script) => {
if (streamURL) {
return;
}
const cfgScript = deobfuscatePlayerCfg($(script).text());
if (!cfgScript) {
return undefined;
}
const url = cfgScript.match('file:"(https?://.+?)"')?.[1];
if (!url) {
return;
}
streamURL = url;
});
console.log(LOG_PREFIX, 'Stream URL', streamURL);
return streamURL;
}
export async function scrapeFilemoonEmbed(ctx: EmbedScrapeContext): Promise<EmbedOutput> {
console.log(LOG_PREFIX, 'Scraping stream URL', ctx.url);
let streamURL: string | undefined;
try {
streamURL = await getStream(ctx, ctx.url);
} catch (error) {
console.warn(LOG_PREFIX, 'Failed to get stream', error);
throw error;
}
if (!streamURL) {
return {
stream: [],
};
}
return {
stream: [
{
type: 'hls',
id: 'primary',
flags: ['cors-allowed'],
captions: [],
playlist: streamURL,
headers: {
Referer: ORIGIN_HOST,
Origin: ORIGIN_HOST,
},
},
],
};
}

View file

@ -78,7 +78,7 @@ async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promis
export const dopeboxScraper = makeSourcerer({ export const dopeboxScraper = makeSourcerer({
id: 'dopebox', id: 'dopebox',
name: 'Dopebox', name: 'Dopebox',
rank: 600, rank: 210,
flags: ['cors-allowed'], flags: ['cors-allowed'],
scrapeMovie: comboScraper, scrapeMovie: comboScraper,
scrapeShow: comboScraper, scrapeShow: comboScraper,
@ -88,8 +88,8 @@ export const dopeboxEmbeds = [
makeEmbed({ makeEmbed({
id: 'dopebox-upcloud', id: 'dopebox-upcloud',
name: 'UpCloud', name: 'UpCloud',
rank: 6001, rank: 2101,
flags: [], flags: ['cors-allowed'],
scrape: scrapeUpCloudEmbed, scrape: scrapeUpCloudEmbed,
}), }),
]; ];

View file

@ -123,19 +123,19 @@ export async function scrapeUpCloudEmbed(ctx: EmbedScrapeContext): Promise<Embed
if (!embedURL) { if (!embedURL) {
throw new Error('Failed to get embed URL (invalid movie?)'); throw new Error('Failed to get embed URL (invalid movie?)');
} }
console.log('Embed URL', embedURL.href); // console.log('Embed URL', embedURL.href);
const embedID = embedURL.pathname.split('/').pop(); const embedID = embedURL.pathname.split('/').pop();
if (!embedID) { if (!embedID) {
throw new Error('Failed to get embed ID'); throw new Error('Failed to get embed ID');
} }
console.log('Embed ID', embedID); // console.log('Embed ID', embedID);
const clientKey = await getClientKey(ctx, embedURL.href); const clientKey = await getClientKey(ctx, embedURL.href);
if (!clientKey) { if (!clientKey) {
throw new Error('Failed to get client key'); throw new Error('Failed to get client key');
} }
console.log('Client key', clientKey); // console.log('Client key', clientKey);
const response = await ctx.proxiedFetcher.full(`${FETCH_SOURCES_URL}?id=${embedID}&_k=${clientKey}`, { const response = await ctx.proxiedFetcher.full(`${FETCH_SOURCES_URL}?id=${embedID}&_k=${clientKey}`, {
headers: { headers: {

View file

@ -43,7 +43,7 @@ function extractStreamInfo($: CheerioAPI): [string | undefined, string | undefin
} }
async function getStream(ctx: ScrapeContext, url: string): Promise<[string, string] | undefined> { async function getStream(ctx: ScrapeContext, url: string): Promise<[string, string] | undefined> {
console.log(LOG_PREFIX, 'Fetching iframe'); // console.log(LOG_PREFIX, 'Fetching iframe');
let $: CheerioAPI; let $: CheerioAPI;
let streamHost: string; let streamHost: string;
@ -66,7 +66,7 @@ async function getStream(ctx: ScrapeContext, url: string): Promise<[string, stri
console.error(LOG_PREFIX, "Couldn't find stream info", streamReq, tokenParams); console.error(LOG_PREFIX, "Couldn't find stream info", streamReq, tokenParams);
return undefined; return undefined;
} }
console.log(LOG_PREFIX, 'Stream info', streamReq, tokenParams); // console.log(LOG_PREFIX, 'Stream info', streamReq, tokenParams);
let streamURL: string; let streamURL: string;
try { try {
@ -83,13 +83,13 @@ async function getStream(ctx: ScrapeContext, url: string): Promise<[string, stri
console.error(LOG_PREFIX, 'Failed to request stream URL', error); console.error(LOG_PREFIX, 'Failed to request stream URL', error);
return undefined; return undefined;
} }
console.log(LOG_PREFIX, 'Stream URL', streamURL); // console.log(LOG_PREFIX, 'Stream URL', streamURL);
return [streamURL, streamHost]; return [streamURL, streamHost];
} }
export async function scrapeDoodstreamEmbed(ctx: EmbedScrapeContext): Promise<EmbedOutput> { export async function scrapeDoodstreamEmbed(ctx: EmbedScrapeContext): Promise<EmbedOutput> {
console.log(LOG_PREFIX, 'Scraping stream URL', ctx.url); // console.log(LOG_PREFIX, 'Scraping stream URL', ctx.url);
let streamURL: string | undefined; let streamURL: string | undefined;
let streamHost: string | undefined; let streamHost: string | undefined;
try { try {

View file

@ -6,13 +6,12 @@ import { SourcererEmbed, SourcererOutput, makeEmbed, makeSourcerer } from '@/pro
import { MovieScrapeContext, ScrapeContext, ShowScrapeContext } from '@/utils/context'; import { MovieScrapeContext, ScrapeContext, ShowScrapeContext } from '@/utils/context';
import { scrapeDoodstreamEmbed } from './doodstream'; import { scrapeDoodstreamEmbed } from './doodstream';
import { scrapeFilemoonEmbed } from './filemoon'; import { EMBED_URL, ORIGIN_HOST, fetchENTMDBName, getMoviePageURL, throwOnResponse } from './utils';
import { EMBED_URL, ORIGIN_HOST, getMoviePageURL, throwOnResponse } from './utils';
export const LOG_PREFIX = '[FSOnline]'; export const LOG_PREFIX = '[FSOnline]';
async function getMovieID(ctx: ScrapeContext, url: string): Promise<string | undefined> { async function getMovieID(ctx: ScrapeContext, url: string): Promise<string | undefined> {
console.log(LOG_PREFIX, 'Scraping movie ID from', url); // console.log(LOG_PREFIX, 'Scraping movie ID from', url);
let $: CheerioAPI; let $: CheerioAPI;
try { try {
@ -34,13 +33,13 @@ async function getMovieID(ctx: ScrapeContext, url: string): Promise<string | und
console.error(LOG_PREFIX, 'Could not find movie ID', url); console.error(LOG_PREFIX, 'Could not find movie ID', url);
return undefined; return undefined;
} }
console.log(LOG_PREFIX, 'Movie ID', movieID); // console.log(LOG_PREFIX, 'Movie ID', movieID);
return movieID; return movieID;
} }
async function getMovieSources(ctx: ScrapeContext, id: string, refererHeader: string): Promise<Map<string, string>> { async function getMovieSources(ctx: ScrapeContext, id: string, refererHeader: string): Promise<Map<string, string>> {
console.log(LOG_PREFIX, 'Scraping movie sources for', id); // console.log(LOG_PREFIX, 'Scraping movie sources for', id);
const sources: Map<string, string> = new Map<string, string>(); const sources: Map<string, string> = new Map<string, string>();
let $: CheerioAPI; let $: CheerioAPI;
@ -69,7 +68,7 @@ async function getMovieSources(ctx: ScrapeContext, id: string, refererHeader: st
console.warn(LOG_PREFIX, 'Skipping invalid source', name); console.warn(LOG_PREFIX, 'Skipping invalid source', name);
return; return;
} }
console.log(LOG_PREFIX, 'Found movie source for', id, name, url); // console.log(LOG_PREFIX, 'Found movie source for', id, name, url);
sources.set(name, url); sources.set(name, url);
}); });
@ -88,13 +87,13 @@ function addEmbedFromSources(name: string, sources: Map<string, string>, embeds:
} }
async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise<SourcererOutput> { async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise<SourcererOutput> {
// always use the english title const movieName = await fetchENTMDBName(Number(ctx.media.tmdbId), ctx.media.type);
const moviePageURL = getMoviePageURL( const moviePageURL = getMoviePageURL(
ctx.media.type === 'movie' ? `${ctx.media.title} ${ctx.media.releaseYear}` : ctx.media.title, ctx.media.type === 'movie' ? `${movieName} ${ctx.media.releaseYear}` : movieName,
ctx.media.type === 'show' ? ctx.media.season.number : undefined, ctx.media.type === 'show' ? ctx.media.season.number : undefined,
ctx.media.type === 'show' ? ctx.media.episode.number : undefined, ctx.media.type === 'show' ? ctx.media.episode.number : undefined,
); );
console.log(LOG_PREFIX, 'Movie page URL', moviePageURL); // console.log(LOG_PREFIX, 'Movie page URL', moviePageURL);
const movieID = await getMovieID(ctx, moviePageURL); const movieID = await getMovieID(ctx, moviePageURL);
if (!movieID) { if (!movieID) {
@ -121,7 +120,7 @@ async function comboScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promis
export const fsOnlineScraper = makeSourcerer({ export const fsOnlineScraper = makeSourcerer({
id: 'fsonline', id: 'fsonline',
name: 'FSOnline', name: 'FSOnline',
rank: 500, rank: 200,
flags: ['cors-allowed'], flags: ['cors-allowed'],
scrapeMovie: comboScraper, scrapeMovie: comboScraper,
scrapeShow: comboScraper, scrapeShow: comboScraper,
@ -131,15 +130,15 @@ export const fsOnlineEmbeds = [
makeEmbed({ makeEmbed({
id: 'fsonline-doodstream', id: 'fsonline-doodstream',
name: 'Doodstream', name: 'Doodstream',
rank: 5001, rank: 2001,
scrape: scrapeDoodstreamEmbed, scrape: scrapeDoodstreamEmbed,
flags: ['cors-allowed'], flags: ['cors-allowed'],
}), }),
makeEmbed({ // makeEmbed({
id: 'fsonline-filemoon', // id: 'fsonline-filemoon',
name: 'Filemoon', // name: 'Filemoon',
rank: 5002, // rank: 2002,
scrape: scrapeFilemoonEmbed, // scrape: scrapeFilemoonEmbed,
flags: ['cors-allowed'], // flags: ['cors-allowed'],
}), // }),
]; ];

View file

@ -5,6 +5,7 @@ export const ORIGIN_HOST = 'https://www3.fsonline.app';
export const MOVIE_PAGE_URL = 'https://www3.fsonline.app/film/'; export const MOVIE_PAGE_URL = 'https://www3.fsonline.app/film/';
export const SHOW_PAGE_URL = 'https://www3.fsonline.app/episoade/{{MOVIE}}-sezonul-{{SEASON}}-episodul-{{EPISODE}}/'; export const SHOW_PAGE_URL = 'https://www3.fsonline.app/episoade/{{MOVIE}}-sezonul-{{SEASON}}-episodul-{{EPISODE}}/';
export const EMBED_URL = 'https://www3.fsonline.app/wp-admin/admin-ajax.php'; export const EMBED_URL = 'https://www3.fsonline.app/wp-admin/admin-ajax.php';
const TMDB_API_KEY = 'a500049f3e06109fe3e8289b06cf5685';
export function throwOnResponse(response: FetcherResponse) { export function throwOnResponse(response: FetcherResponse) {
if (response.statusCode >= 400) { if (response.statusCode >= 400) {
@ -29,11 +30,26 @@ export function getMoviePageURL(name: string, season?: number, episode?: number)
return `${MOVIE_PAGE_URL}${name}/`; return `${MOVIE_PAGE_URL}${name}/`;
} }
export async function fetchENTMDBName(tmdbId: number, mediaType: 'movie' | 'show'): Promise<string> {
const endpoint =
mediaType === 'movie'
? `https://api.themoviedb.org/3/movie/${tmdbId}?api_key=${TMDB_API_KEY}&language=en-US`
: `https://api.themoviedb.org/3/tv/${tmdbId}?api_key=${TMDB_API_KEY}&language=en-US`;
const response = await fetch(endpoint);
if (!response.ok) {
throw new Error(`Error fetching TMDB data: ${response.statusText}`);
}
const tmdbData = await response.json();
return mediaType === 'movie' ? tmdbData.title : tmdbData.name;
}
export async function fetchIFrame(ctx: ScrapeContext, url: string): Promise<FetcherResponse | undefined> { export async function fetchIFrame(ctx: ScrapeContext, url: string): Promise<FetcherResponse | undefined> {
const response: FetcherResponse = await ctx.proxiedFetcher.full(url, { const response: FetcherResponse = await ctx.proxiedFetcher.full(url, {
headers: { headers: {
Referer: `${ORIGIN_HOST}/`, Referer: ORIGIN_HOST,
// Origin: ORIGIN_HOST, Origin: ORIGIN_HOST,
'sec-fetch-dest': 'iframe', 'sec-fetch-dest': 'iframe',
'sec-fetch-mode': 'navigate', 'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'cross-site', 'sec-fetch-site': 'cross-site',