mirror of
https://github.com/movie-web/providers.git
synced 2025-09-13 13:03:25 +00:00
EPIC GOOJARA LESS FUCKING GO
This commit is contained in:
1
src/.env copy
Normal file
1
src/.env copy
Normal file
@@ -0,0 +1 @@
|
|||||||
|
MOVIE_WEB_TMDB_API_KEY="045e3dc79db2f0cbaa9ef67397afca39"
|
@@ -16,11 +16,14 @@ import { remotestreamScraper } from '@/providers/sources/remotestream';
|
|||||||
import { showboxScraper } from '@/providers/sources/showbox/index';
|
import { showboxScraper } from '@/providers/sources/showbox/index';
|
||||||
import { vidsrcScraper } from '@/providers/sources/vidsrc/index';
|
import { vidsrcScraper } from '@/providers/sources/vidsrc/index';
|
||||||
import { zoechipScraper } from '@/providers/sources/zoechip';
|
import { zoechipScraper } from '@/providers/sources/zoechip';
|
||||||
|
import { doodScraper } from '@/providers/embeds/dood';
|
||||||
|
|
||||||
import { fileMoonScraper } from './embeds/filemoon';
|
import { fileMoonScraper } from './embeds/filemoon';
|
||||||
import { smashyStreamDScraper } from './embeds/smashystream/dued';
|
import { smashyStreamDScraper } from './embeds/smashystream/dued';
|
||||||
import { smashyStreamFScraper } from './embeds/smashystream/video1';
|
import { smashyStreamFScraper } from './embeds/smashystream/video1';
|
||||||
import { vidplayScraper } from './embeds/vidplay';
|
import { vidplayScraper } from './embeds/vidplay';
|
||||||
|
import { wootlyScraper } from './embeds/wootly';
|
||||||
|
import { goojaraScraper } from './sources/goojara';
|
||||||
import { smashyStreamScraper } from './sources/smashystream';
|
import { smashyStreamScraper } from './sources/smashystream';
|
||||||
import { vidSrcToScraper } from './sources/vidsrcto';
|
import { vidSrcToScraper } from './sources/vidsrcto';
|
||||||
|
|
||||||
@@ -37,6 +40,7 @@ export function gatherAllSources(): Array<Sourcerer> {
|
|||||||
lookmovieScraper,
|
lookmovieScraper,
|
||||||
smashyStreamScraper,
|
smashyStreamScraper,
|
||||||
vidSrcToScraper,
|
vidSrcToScraper,
|
||||||
|
goojaraScraper,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,5 +60,7 @@ export function gatherAllEmbeds(): Array<Embed> {
|
|||||||
smashyStreamDScraper,
|
smashyStreamDScraper,
|
||||||
fileMoonScraper,
|
fileMoonScraper,
|
||||||
vidplayScraper,
|
vidplayScraper,
|
||||||
|
wootlyScraper,
|
||||||
|
doodScraper
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
75
src/providers/embeds/dood.ts
Normal file
75
src/providers/embeds/dood.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import { load } from 'cheerio';
|
||||||
|
|
||||||
|
import { flags } from '@/entrypoint/utils/targets';
|
||||||
|
import { makeEmbed } from '@/providers/base';
|
||||||
|
|
||||||
|
export const doodScraper = makeEmbed({
|
||||||
|
id: 'dood',
|
||||||
|
name: 'dood',
|
||||||
|
rank: 173,
|
||||||
|
async scrape(ctx) {
|
||||||
|
function makeTheFunny() {
|
||||||
|
let result = '';
|
||||||
|
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
const charactersLength = characters.length;
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseUrl = 'https://do0od.com';
|
||||||
|
|
||||||
|
const id = ctx.url.split('/d/')[1] || ctx.url.split('/e/')[1];
|
||||||
|
console.log(id);
|
||||||
|
|
||||||
|
const doodData = await ctx.proxiedFetcher<string>(`/e/${id}`, {
|
||||||
|
method: 'GET',
|
||||||
|
baseUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log(doodData);
|
||||||
|
|
||||||
|
const dataForLater = doodData.split(`a+"?token=`)[1].split(`"`)[0];
|
||||||
|
const path = doodData.split(`$.get('/pass_md5`)[1].split(`'`)[0];
|
||||||
|
|
||||||
|
const doodPage = await ctx.proxiedFetcher<string>(`/pass_md5/${path}`, {
|
||||||
|
headers: {
|
||||||
|
referer: `${baseUrl}/e/${id}`,
|
||||||
|
},
|
||||||
|
method: 'GET',
|
||||||
|
baseUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`${baseUrl}/pass_md5/${path}`);
|
||||||
|
|
||||||
|
console.log(doodPage);
|
||||||
|
|
||||||
|
// const doodPage = await ctx.proxiedFetcher<string>(`/download/${path}`, { method: 'GET', baseUrl });
|
||||||
|
// console.log(doodPage);
|
||||||
|
const downloadURL = `${doodPage}${makeTheFunny()}?token=${dataForLater}${Date.now()}`;
|
||||||
|
|
||||||
|
if (downloadURL) {
|
||||||
|
return {
|
||||||
|
stream: [
|
||||||
|
{
|
||||||
|
id: 'primary',
|
||||||
|
type: 'hls',
|
||||||
|
playlist: downloadURL,
|
||||||
|
flags: [flags.CORS_ALLOWED],
|
||||||
|
captions: [],
|
||||||
|
preferredHeaders: {
|
||||||
|
referer: 'https://do0od.com/',
|
||||||
|
'content-type': 'video/mp4',
|
||||||
|
range: 'bytes=0-',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('wootly source not found');
|
||||||
|
},
|
||||||
|
});
|
77
src/providers/embeds/wootly.ts
Normal file
77
src/providers/embeds/wootly.ts
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { load } from 'cheerio';
|
||||||
|
|
||||||
|
import { flags } from '@/entrypoint/utils/targets';
|
||||||
|
import { makeEmbed } from '@/providers/base';
|
||||||
|
|
||||||
|
export const wootlyScraper = makeEmbed({
|
||||||
|
id: 'wootly',
|
||||||
|
name: 'wootly',
|
||||||
|
rank: 172,
|
||||||
|
async scrape(ctx) {
|
||||||
|
const baseUrl = 'https://www.wootly.ch';
|
||||||
|
|
||||||
|
const wootlyData = await ctx.proxiedFetcher.full<string>(ctx.url, {
|
||||||
|
method: 'GET',
|
||||||
|
readHeaders: ['Set-Cookie'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const wootssesCookie = wootlyData.headers.get('Set-Cookie')?.split(';')[0].split('wootsses=')[1];
|
||||||
|
|
||||||
|
let $ = load(wootlyData.body); // load the html data
|
||||||
|
const iframeSrc = $('iframe').attr('src') ?? '';
|
||||||
|
|
||||||
|
const woozCookieRequest = await ctx.proxiedFetcher.full<string>(iframeSrc, {
|
||||||
|
method: 'GET',
|
||||||
|
readHeaders: ['Set-Cookie'],
|
||||||
|
headers: {
|
||||||
|
cookie: `wootsses=${wootssesCookie};`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const woozCookie = woozCookieRequest.headers.get('Set-Cookie')?.split(';')[0].split('wooz=')[1];
|
||||||
|
|
||||||
|
const iframeData = await ctx.proxiedFetcher<string>(iframeSrc, {
|
||||||
|
method: 'POST',
|
||||||
|
body: new URLSearchParams({ qdf: '1' }),
|
||||||
|
headers: {
|
||||||
|
cookie: `wooz=${woozCookie}`,
|
||||||
|
Referer: iframeSrc,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
$ = load(iframeData);
|
||||||
|
|
||||||
|
const scriptText = $('script').html() ?? '';
|
||||||
|
|
||||||
|
// Regular expressions to match the variables
|
||||||
|
|
||||||
|
const tk = scriptText.split('tk=')[1].split(';')[0].replaceAll('"', '').replaceAll(' ', '');
|
||||||
|
const vd = scriptText.split('vd=')[1].split(',')[0].replaceAll('"', '').replaceAll(' ', '');
|
||||||
|
const cv = scriptText.split('cv=')[1].split(',')[0].replaceAll('"', '').replaceAll(' ', '');
|
||||||
|
|
||||||
|
const url = await ctx.proxiedFetcher<string>(`/grabd`, {
|
||||||
|
baseUrl,
|
||||||
|
query: { t: tk, id: vd },
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
cookie: `wooz=${woozCookie}; wootsses=${wootssesCookie};`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
return {
|
||||||
|
stream: [
|
||||||
|
{
|
||||||
|
id: 'primary',
|
||||||
|
type: 'hls',
|
||||||
|
playlist: url,
|
||||||
|
flags: [flags.CORS_ALLOWED, flags.IP_LOCKED],
|
||||||
|
captions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('wootly source not found');
|
||||||
|
},
|
||||||
|
});
|
52
src/providers/sources/goojara/getEmbeds.ts
Normal file
52
src/providers/sources/goojara/getEmbeds.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { load } from 'cheerio';
|
||||||
|
|
||||||
|
import { ScrapeContext } from '@/utils/context';
|
||||||
|
|
||||||
|
import { EmbedsResult } from './type';
|
||||||
|
|
||||||
|
export async function getEmbeds(ctx: ScrapeContext, id: string): Promise<EmbedsResult> {
|
||||||
|
const data = await ctx.fetcher.full(`/${id}`, {
|
||||||
|
baseUrl: 'https://ww1.goojara.to',
|
||||||
|
headers: {
|
||||||
|
accept: '*/*',
|
||||||
|
'content-type': 'application/x-www-form-urlencoded',
|
||||||
|
Referer: 'https://www.goojara.to/',
|
||||||
|
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
||||||
|
},
|
||||||
|
readHeaders: ['Set-Cookie'],
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
|
||||||
|
const aGoozCookie = data.headers.get('Set-Cookie')?.split(';')[0].split('aGooz=')[1];
|
||||||
|
const $ = load(data.body);
|
||||||
|
const RandomCookieName = data.body.split(`_3chk('`)[1].split(`'`)[0];
|
||||||
|
const RandomCookieValue = data.body.split(`_3chk('`)[1].split(`'`)[2];
|
||||||
|
|
||||||
|
const embedRedirectURLs = $('a')
|
||||||
|
.map((index, element) => $(element).attr('href'))
|
||||||
|
.get()
|
||||||
|
.filter((href) => href && href.includes('https://ww1.goojara.to/go.php'));
|
||||||
|
|
||||||
|
const embeds = await Promise.all(
|
||||||
|
embedRedirectURLs.map((url) =>
|
||||||
|
ctx.fetcher
|
||||||
|
.full(url, {
|
||||||
|
headers: {
|
||||||
|
cookie: `aGooz=${aGoozCookie}; ${RandomCookieName}=${RandomCookieValue};`,
|
||||||
|
Referer: 'https://ww1.goojara.to/eJwD5z',
|
||||||
|
},
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (result) {
|
||||||
|
const embedId = ['wootly', 'upstream', 'mixdrop', 'dood'].find((a) => result.finalUrl.includes(a));
|
||||||
|
return embedId ? { embedId, url: result.finalUrl } : null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.catch(() => null),
|
||||||
|
),
|
||||||
|
).then((results) => results.filter((result) => result !== null) as EmbedsResult);
|
||||||
|
|
||||||
|
return embeds;
|
||||||
|
}
|
30
src/providers/sources/goojara/index.ts
Normal file
30
src/providers/sources/goojara/index.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { SourcererOutput, makeSourcerer } from '@/providers/base';
|
||||||
|
import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context';
|
||||||
|
import { NotFoundError } from '@/utils/errors';
|
||||||
|
|
||||||
|
import { scrapeIds, searchAndFindMedia } from './util';
|
||||||
|
|
||||||
|
async function universalScraper(ctx: ShowScrapeContext | MovieScrapeContext): Promise<SourcererOutput> {
|
||||||
|
const goojaraData = await searchAndFindMedia(ctx, ctx.media);
|
||||||
|
if (!goojaraData) throw new NotFoundError('Media not found');
|
||||||
|
|
||||||
|
ctx.progress(30);
|
||||||
|
const embeds = await scrapeIds(ctx, ctx.media, goojaraData);
|
||||||
|
if (embeds?.length === 0) throw new NotFoundError('No embeds found');
|
||||||
|
|
||||||
|
|
||||||
|
ctx.progress(60);
|
||||||
|
|
||||||
|
return {
|
||||||
|
embeds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const goojaraScraper = makeSourcerer({
|
||||||
|
id: 'goojara',
|
||||||
|
name: 'goojara',
|
||||||
|
rank: 69,
|
||||||
|
flags: [],
|
||||||
|
scrapeShow: universalScraper,
|
||||||
|
scrapeMovie: universalScraper,
|
||||||
|
});
|
35
src/providers/sources/goojara/type.ts
Normal file
35
src/providers/sources/goojara/type.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// ! Types
|
||||||
|
interface BaseConfig {
|
||||||
|
/** The website's slug. Formatted as `1839578-person-of-interest-2011` */
|
||||||
|
slug: string;
|
||||||
|
/** Type of request */
|
||||||
|
type: 'show' | 'movie';
|
||||||
|
/** Hash */
|
||||||
|
hash: string;
|
||||||
|
/** Hash expiry */
|
||||||
|
expires: number;
|
||||||
|
}
|
||||||
|
interface TvConfig extends BaseConfig {
|
||||||
|
/** Type of request */
|
||||||
|
type: 'show';
|
||||||
|
/** The episode ID for a TV show. Given in search and URL */
|
||||||
|
episodeId: string;
|
||||||
|
}
|
||||||
|
interface MovieConfig extends BaseConfig {
|
||||||
|
/** Type of request */
|
||||||
|
type: 'movie';
|
||||||
|
/** Movie's id */
|
||||||
|
slug: string;
|
||||||
|
}
|
||||||
|
export type Config = MovieConfig | TvConfig;
|
||||||
|
|
||||||
|
export type EmbedsResult = { embedId: string; url: string; }[]
|
||||||
|
|
||||||
|
export interface Result {
|
||||||
|
title: string;
|
||||||
|
slug: any;
|
||||||
|
year: string;
|
||||||
|
type: string;
|
||||||
|
id_movie?: string;
|
||||||
|
id_show?: string;
|
||||||
|
}
|
111
src/providers/sources/goojara/util.ts
Normal file
111
src/providers/sources/goojara/util.ts
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import { load } from 'cheerio';
|
||||||
|
|
||||||
|
import { MovieMedia, ShowMedia } from '@/entrypoint/utils/media';
|
||||||
|
import { compareMedia } from '@/utils/compare';
|
||||||
|
import { ScrapeContext } from '@/utils/context';
|
||||||
|
import { NotFoundError } from '@/utils/errors';
|
||||||
|
|
||||||
|
import { getEmbeds } from './getEmbeds';
|
||||||
|
import { Result, EmbedsResult } from './type';
|
||||||
|
|
||||||
|
const headersData = {
|
||||||
|
accept: '*/*',
|
||||||
|
'accept-language': 'en-US,en;q=0.9',
|
||||||
|
'content-type': 'application/x-www-form-urlencoded',
|
||||||
|
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
|
||||||
|
'sec-ch-ua-mobile': '?0',
|
||||||
|
'sec-ch-ua-platform': '"Windows"',
|
||||||
|
'sec-fetch-dest': 'empty',
|
||||||
|
'sec-fetch-mode': 'cors',
|
||||||
|
'sec-fetch-site': 'same-origin',
|
||||||
|
cookie: `aGooz=t9pmkdtef1b3lg3pmo1u2re816; bd9aa48e=0d7b89e8c79844e9df07a2; _b414=2151C6B12E2A88379AFF2C0DD65AC8298DEC2BF4; 9d287aaa=8f32ad589e1c4288fe152f`,
|
||||||
|
Referer: 'https://www.goojara.to/',
|
||||||
|
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function searchAndFindMedia(
|
||||||
|
ctx: ScrapeContext,
|
||||||
|
media: MovieMedia | ShowMedia,
|
||||||
|
): Promise<Result | undefined> {
|
||||||
|
const data = await ctx.fetcher<string>(`/xhrr.php`, {
|
||||||
|
baseUrl: 'https://www.goojara.to',
|
||||||
|
headers: headersData,
|
||||||
|
method: 'POST',
|
||||||
|
body: `q=${media.title}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
const $ = load(data);
|
||||||
|
|
||||||
|
const results: Result[] = [];
|
||||||
|
|
||||||
|
$('.mfeed > li').each((index, element) => {
|
||||||
|
const title = $(element).find('strong').text();
|
||||||
|
const yearMatch = $(element)
|
||||||
|
.text()
|
||||||
|
.match(/\((\d{4})\)/);
|
||||||
|
const typeDiv = $(element).find('div').attr('class');
|
||||||
|
const type = typeDiv === 'it' ? 'show' : typeDiv === 'im' ? 'movie' : '';
|
||||||
|
const year = yearMatch ? yearMatch[1] : '';
|
||||||
|
const slug = $(element).find('a').attr('href')?.split('/')[3];
|
||||||
|
|
||||||
|
if (media.type === type) {
|
||||||
|
results.push({ title, year, slug, type });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = results.find((res: Result) => compareMedia(media, res.title, Number(res.year)));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function scrapeIds(ctx: ScrapeContext, media: MovieMedia | ShowMedia, result: Result): Promise<EmbedsResult> {
|
||||||
|
// Find the relevant id
|
||||||
|
let id = null;
|
||||||
|
if (media.type === 'movie') {
|
||||||
|
id = result.slug;
|
||||||
|
} else if (media.type === 'show') {
|
||||||
|
const data = await ctx.fetcher<string>(`/${result.slug}`, {
|
||||||
|
baseUrl: 'https://www.goojara.to',
|
||||||
|
headers: headersData,
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
|
||||||
|
const $1 = load(data);
|
||||||
|
|
||||||
|
const dataId = $1('#seon').data('id');
|
||||||
|
|
||||||
|
const data2 = await ctx.fetcher<string>(`/xhrc.php`, {
|
||||||
|
baseUrl: 'https://ww1.goojara.to',
|
||||||
|
headers: headersData,
|
||||||
|
method: 'POST',
|
||||||
|
body: `s=${media.season.number}&t=${dataId}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
let episodeId = '';
|
||||||
|
|
||||||
|
const $2 = load(data2);
|
||||||
|
|
||||||
|
$2('.seho').each((index, element) => {
|
||||||
|
// Extracting the episode number as a string
|
||||||
|
const episodeNumber = $2(element).find('.seep .sea').text().trim();
|
||||||
|
|
||||||
|
// Comparing with the desired episode number as a string
|
||||||
|
if (parseInt(episodeNumber, 10) === media.episode.number) {
|
||||||
|
const href = $2(element).find('.snfo h1 a').attr('href');
|
||||||
|
const idMatch = href?.match(/\/([a-zA-Z0-9]+)$/);
|
||||||
|
if (idMatch && idMatch[1]) {
|
||||||
|
episodeId = idMatch[1];
|
||||||
|
return false; // Break out of the loop once the episode is found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
id = episodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check ID
|
||||||
|
if (id === null) throw new NotFoundError('Not found');
|
||||||
|
|
||||||
|
const embeds = await getEmbeds(ctx, id);
|
||||||
|
return embeds;
|
||||||
|
}
|
Reference in New Issue
Block a user