Merge pull request #52 from JorrinKievit/ridomovies

Added ridomovies with Ridoo and Closeload embed
This commit is contained in:
mrjvs
2024-01-28 21:23:13 +01:00
committed by GitHub
5 changed files with 264 additions and 0 deletions

View File

@@ -17,10 +17,13 @@ import { showboxScraper } from '@/providers/sources/showbox/index';
import { vidsrcScraper } from '@/providers/sources/vidsrc/index';
import { zoechipScraper } from '@/providers/sources/zoechip';
import { closeLoadScraper } from './embeds/closeload';
import { fileMoonScraper } from './embeds/filemoon';
import { ridooScraper } from './embeds/ridoo';
import { smashyStreamDScraper } from './embeds/smashystream/dued';
import { smashyStreamFScraper } from './embeds/smashystream/video1';
import { vidplayScraper } from './embeds/vidplay';
import { ridooMoviesScraper } from './sources/ridomovies';
import { smashyStreamScraper } from './sources/smashystream';
import { vidSrcToScraper } from './sources/vidsrcto';
@@ -36,6 +39,7 @@ export function gatherAllSources(): Array<Sourcerer> {
vidsrcScraper,
lookmovieScraper,
smashyStreamScraper,
ridooMoviesScraper,
vidSrcToScraper,
];
}
@@ -54,6 +58,8 @@ export function gatherAllEmbeds(): Array<Embed> {
streambucketScraper,
smashyStreamFScraper,
smashyStreamDScraper,
ridooScraper,
closeLoadScraper,
fileMoonScraper,
vidplayScraper,
];

View File

@@ -0,0 +1,71 @@
import { load } from 'cheerio';
import { unpack } from 'unpacker';
import { flags } from '@/entrypoint/utils/targets';
import { NotFoundError } from '@/utils/errors';
import { makeEmbed } from '../base';
import { Caption, getCaptionTypeFromUrl, labelToLanguageCode } from '../captions';
const referer = 'https://ridomovies.tv/';
export const closeLoadScraper = makeEmbed({
id: 'closeload',
name: 'CloseLoad',
rank: 106,
async scrape(ctx) {
const baseUrl = new URL(ctx.url).origin;
const iframeRes = await ctx.proxiedFetcher<string>(ctx.url, {
headers: { referer },
});
const iframeRes$ = load(iframeRes);
const captions: Caption[] = iframeRes$('track')
.map((_, el) => {
const track = iframeRes$(el);
const url = `${baseUrl}${track.attr('src')}`;
const label = track.attr('label') ?? '';
const language = labelToLanguageCode(label);
const captionType = getCaptionTypeFromUrl(url);
if (!language || !captionType) return null;
return {
id: url,
language,
hasCorsRestrictions: true,
type: captionType,
url,
};
})
.get()
.filter((x) => x !== null);
const evalCode = iframeRes$('script')
.filter((_, el) => {
const script = iframeRes$(el);
return (script.attr('type') === 'text/javascript' && script.html()?.includes('eval')) ?? false;
})
.html();
if (!evalCode) throw new Error("Couldn't find eval code");
const decoded = unpack(evalCode);
const regexPattern = /var\s+(\w+)\s*=\s*"([^"]+)";/g;
const base64EncodedUrl = regexPattern.exec(decoded)?.[2];
if (!base64EncodedUrl) throw new NotFoundError('Unable to find source url');
const url = atob(base64EncodedUrl);
return {
stream: [
{
id: 'primary',
type: 'hls',
playlist: url,
captions,
flags: [flags.IP_LOCKED],
headers: {
Referer: 'https://closeload.top/',
Origin: 'https://closeload.top',
},
},
],
};
},
});

View File

@@ -0,0 +1,34 @@
import { flags } from '@/entrypoint/utils/targets';
import { NotFoundError } from '@/utils/errors';
import { makeEmbed } from '../base';
const referer = 'https://ridomovies.tv/';
export const ridooScraper = makeEmbed({
id: 'ridoo',
name: 'Ridoo',
rank: 105,
async scrape(ctx) {
const res = await ctx.proxiedFetcher<string>(ctx.url, {
headers: {
referer,
},
});
const regexPattern = /file:"([^"]+)"/g;
const url = regexPattern.exec(res)?.[1];
if (!url) throw new NotFoundError('Unable to find source url');
return {
stream: [
{
id: 'primary',
type: 'hls',
playlist: url,
captions: [],
flags: [flags.CORS_ALLOWED],
},
],
};
},
});

View File

@@ -0,0 +1,75 @@
import { load } from 'cheerio';
import { flags } from '@/entrypoint/utils/targets';
import { SourcererEmbed, makeSourcerer } from '@/providers/base';
import { closeLoadScraper } from '@/providers/embeds/closeload';
import { ridooScraper } from '@/providers/embeds/ridoo';
import { MovieScrapeContext, ShowScrapeContext } from '@/utils/context';
import { NotFoundError } from '@/utils/errors';
import { IframeSourceResult, SearchResult } from './types';
const ridoMoviesBase = `https://ridomovies.tv`;
const ridoMoviesApiBase = `${ridoMoviesBase}/core/api`;
const universalScraper = async (ctx: MovieScrapeContext | ShowScrapeContext) => {
const searchResult = await ctx.proxiedFetcher<SearchResult>('/search', {
baseUrl: ridoMoviesApiBase,
query: {
q: ctx.media.title,
},
});
const show = searchResult.data.items[0];
if (!show) throw new NotFoundError('No watchable item found');
let iframeSourceUrl = `/${show.fullSlug}/videos`;
if (ctx.media.type === 'show') {
const showPageResult = await ctx.proxiedFetcher<string>(`/${show.fullSlug}`, {
baseUrl: ridoMoviesBase,
});
const fullEpisodeSlug = `${show.fullSlug}/season-${ctx.media.season.number}/episode-${ctx.media.episode.number}`;
const regexPattern = new RegExp(
`\\\\"id\\\\":\\\\"(\\d+)\\\\"(?=.*?\\\\\\"fullSlug\\\\\\":\\\\\\"${fullEpisodeSlug}\\\\\\")`,
'g',
);
const matches = [...showPageResult.matchAll(regexPattern)];
const episodeIds = matches.map((match) => match[1]);
if (episodeIds.length === 0) throw new NotFoundError('No watchable item found');
const episodeId = episodeIds.at(-1);
iframeSourceUrl = `/episodes/${episodeId}/videos`;
}
const iframeSource = await ctx.proxiedFetcher<IframeSourceResult>(iframeSourceUrl, {
baseUrl: ridoMoviesApiBase,
});
const iframeSource$ = load(iframeSource.data[0].url);
const iframeUrl = iframeSource$('iframe').attr('data-src');
if (!iframeUrl) throw new NotFoundError('No watchable item found');
const embeds: SourcererEmbed[] = [];
if (iframeUrl.includes('closeload')) {
embeds.push({
embedId: closeLoadScraper.id,
url: iframeUrl,
});
}
if (iframeUrl.includes('ridoo')) {
embeds.push({
embedId: ridooScraper.id,
url: iframeUrl,
});
}
return {
embeds,
};
};
export const ridooMoviesScraper = makeSourcerer({
id: 'ridomovies',
name: 'RidoMovies',
rank: 105,
flags: [flags.CORS_ALLOWED],
scrapeMovie: universalScraper,
scrapeShow: universalScraper,
});

View File

@@ -0,0 +1,78 @@
export interface Content {
id: string;
type: string;
slug: string;
title: string;
metaTitle: any;
metaDescription: any;
usersOnly: boolean;
userLevel: number;
vipOnly: boolean;
copyrighted: boolean;
status: string;
publishedAt: string;
createdAt: string;
updatedAt: string;
fullSlug: string;
}
export interface Contentable {
id: string;
contentId: string;
revisionId: any;
originalTitle: string;
overview: string;
releaseDate: string;
releaseYear: string;
videoNote: any;
posterNote: any;
userRating: number;
imdbRating: number;
imdbVotes: number;
imdbId: string;
duration: number;
countryCode: string;
posterPath: string;
backdropPath: string;
apiPosterPath: string;
apiBackdropPath: string;
trailerUrl: string;
mpaaRating: string;
tmdbId: number;
manual: number;
directorId: number;
createdAt: string;
updatedAt: string;
content: Content;
}
export interface SearchResultItem {
id: string;
type: string;
slug: string;
title: string;
metaTitle: any;
metaDescription: any;
usersOnly: boolean;
userLevel: number;
vipOnly: boolean;
copyrighted: boolean;
status: string;
publishedAt: string;
createdAt: string;
updatedAt: string;
fullSlug: string;
contentable: Contentable;
}
export type SearchResult = {
data: {
items: SearchResultItem[];
};
};
export type IframeSourceResult = {
data: {
url: string;
}[];
};