Merge pull request #2 from ztpn/ee3

ee3
This commit is contained in:
TPN 2024-07-16 13:35:08 +05:30 committed by GitHub
commit 3d0207a0db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 183 additions and 1 deletions

View File

@ -16,6 +16,7 @@ import { vTubeScraper } from '@/providers/embeds/vtube';
import { astraScraper, novaScraper } from '@/providers/embeds/whvx'; import { astraScraper, novaScraper } from '@/providers/embeds/whvx';
import { autoembedScraper } from '@/providers/sources/autoembed'; import { autoembedScraper } from '@/providers/sources/autoembed';
import { catflixScraper } from '@/providers/sources/catflix'; import { catflixScraper } from '@/providers/sources/catflix';
import { ee3Scraper } from '@/providers/sources/ee3';
import { flixhqScraper } from '@/providers/sources/flixhq/index'; import { flixhqScraper } from '@/providers/sources/flixhq/index';
import { goMoviesScraper } from '@/providers/sources/gomovies/index'; import { goMoviesScraper } from '@/providers/sources/gomovies/index';
import { insertunitScraper } from '@/providers/sources/insertunit'; import { insertunitScraper } from '@/providers/sources/insertunit';
@ -93,6 +94,7 @@ export function gatherAllSources(): Array<Sourcerer> {
soaperTvScraper, soaperTvScraper,
autoembedScraper, autoembedScraper,
tugaflixScraper, tugaflixScraper,
ee3Scraper,
whvxScraper, whvxScraper,
]; ];
} }

View File

@ -0,0 +1,7 @@
export const useAltEndpoint: boolean = false;
export const baseUrl = useAltEndpoint ? 'https://rips.cc' : 'https://ee3.me';
export const username = '_sf_';
export const password = 'defonotscraping';

View File

@ -0,0 +1,97 @@
import { flags } from '@/entrypoint/utils/targets';
import { SourcererOutput, makeSourcerer } from '@/providers/base';
import { Caption } from '@/providers/captions';
import { compareMedia } from '@/utils/compare';
import { MovieScrapeContext } from '@/utils/context';
import { makeCookieHeader } from '@/utils/cookie';
import { NotFoundError } from '@/utils/errors';
import { baseUrl, password, username } from './common';
import { itemDetails, renewResponse } from './types';
import { login, parseSearch } from './utils';
// this source only has movies
async function comboScraper(ctx: MovieScrapeContext): Promise<SourcererOutput> {
const pass = await login(username, password, ctx);
if (!pass) throw new Error('Login failed');
const search = parseSearch(
await ctx.proxiedFetcher<string>('/get', {
baseUrl,
method: 'POST',
body: new URLSearchParams({ query: ctx.media.title, action: 'search' }),
headers: {
cookie: makeCookieHeader({ PHPSESSID: pass }),
},
}),
);
const id = search.find((v) => v && compareMedia(ctx.media, v.title, v.year))?.id;
if (!id) throw new NotFoundError('No watchable item found');
const details: itemDetails = JSON.parse(
await ctx.proxiedFetcher<string>('/get', {
baseUrl,
method: 'POST',
body: new URLSearchParams({ id, action: 'get_movie_info' }),
headers: {
cookie: makeCookieHeader({ PHPSESSID: pass }),
},
}),
);
if (!details.message.video) throw new Error('Failed to get the stream');
const keyParams: renewResponse = JSON.parse(
await ctx.proxiedFetcher<string>('/renew', {
baseUrl,
method: 'POST',
headers: {
cookie: makeCookieHeader({ PHPSESSID: pass }),
},
}),
);
if (!keyParams.k) throw new Error('Failed to get the key');
const server = details.message.server === '1' ? 'https://vid.ee3.me/vid/' : 'https://vault.rips.cc/video/';
const k = keyParams.k;
const url = `${server}${details.message.video}?${new URLSearchParams({ k })}`;
const captions: Caption[] = [];
// this how they actually deal with subtitles
if (details.message.subs?.toLowerCase() === 'yes' && details.message.imdbID) {
captions.push({
id: `https://rips.cc/subs/${details.message.imdbID}.vtt`,
url: `https://rips.cc/subs/${details.message.imdbID}.vtt`,
type: 'vtt',
hasCorsRestrictions: false,
language: 'en',
});
}
return {
embeds: [],
stream: [
{
id: 'primary',
type: 'file',
flags: [flags.CORS_ALLOWED],
captions,
qualities: {
// should be unknown, but all the videos are 720p
720: {
type: 'mp4',
url,
},
},
},
],
};
}
export const ee3Scraper = makeSourcerer({
id: 'ee3',
name: 'EE3',
rank: 111,
flags: [flags.CORS_ALLOWED],
scrapeMovie: comboScraper,
});

View File

@ -0,0 +1,31 @@
export interface itemDetails {
status: number;
message: {
id: string;
imdbID: string;
title: string;
video: string;
server: string;
year: string;
image: string;
glow: string;
rating: string;
watch_count: string;
datetime?: string | null;
requested_by?: string | null;
subs?: string | null;
time?: string | null;
duration?: string | null;
};
}
export interface renewResponse {
k: string;
msg?: string | null;
status: number | string | null;
}
export interface loginResponse {
status: number;
message: string;
}

View File

@ -0,0 +1,46 @@
import { load } from 'cheerio';
import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context';
import { parseSetCookie } from '@/utils/cookie';
import { baseUrl } from './common';
import { loginResponse } from './types';
export async function login(
user: string,
pass: string,
ctx: ShowScrapeContext | MovieScrapeContext,
): Promise<string | null> {
const req = await ctx.proxiedFetcher.full<string>('/login', {
baseUrl,
method: 'POST',
body: new URLSearchParams({ user, pass, action: 'login' }),
readHeaders: ['Set-Cookie'],
});
const res: loginResponse = JSON.parse(req.body);
const cookie = parseSetCookie(
// It retruns a cookie even when the login failed
// I have the backup cookie here just in case
res.status === 1 ? (req.headers.get('Set-Cookie') ?? '') : 'PHPSESSID=mk2p73c77qc28o5i5120843ruu;',
);
return cookie.PHPSESSID.value;
}
export function parseSearch(body: string): { title: string; year: number; id: string }[] {
const result: { title: string; year: number; id: string }[] = [];
const $ = load(body);
$('div').each((_, element) => {
const title = $(element).find('.title').text().trim();
const year = parseInt($(element).find('.details span').first().text().trim(), 10);
const id = $(element).find('.control-buttons').attr('data-id');
if (title && year && id) {
result.push({ title, year, id });
}
});
return result;
}

View File

@ -1,6 +1,5 @@
import { load } from 'cheerio'; import { load } from 'cheerio';
import { flags } from '@/entrypoint/utils/targets';
import { SourcererOutput, makeSourcerer } from '@/providers/base'; import { SourcererOutput, makeSourcerer } from '@/providers/base';
import { compareTitle } from '@/utils/compare'; import { compareTitle } from '@/utils/compare';
import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context'; import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context';