mirror of
https://github.com/movie-web/providers.git
synced 2025-09-13 12:43:25 +00:00
added ridomovies
This commit is contained in:
@@ -14,8 +14,11 @@ import { remotestreamScraper } from '@/providers/sources/remotestream';
|
||||
import { showboxScraper } from '@/providers/sources/showbox/index';
|
||||
import { zoechipScraper } from '@/providers/sources/zoechip';
|
||||
|
||||
import { closeLoadScraper } from './embeds/closeload';
|
||||
import { ridooScraper } from './embeds/ridoo';
|
||||
import { smashyStreamDScraper } from './embeds/smashystream/dued';
|
||||
import { smashyStreamFScraper } from './embeds/smashystream/video1';
|
||||
import { ridooMoviesScraper } from './sources/ridomovies';
|
||||
import { smashyStreamScraper } from './sources/smashystream';
|
||||
|
||||
export function gatherAllSources(): Array<Sourcerer> {
|
||||
@@ -29,6 +32,7 @@ export function gatherAllSources(): Array<Sourcerer> {
|
||||
zoechipScraper,
|
||||
lookmovieScraper,
|
||||
smashyStreamScraper,
|
||||
ridooMoviesScraper,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -44,5 +48,7 @@ export function gatherAllEmbeds(): Array<Embed> {
|
||||
mixdropScraper,
|
||||
smashyStreamFScraper,
|
||||
smashyStreamDScraper,
|
||||
ridooScraper,
|
||||
closeLoadScraper,
|
||||
];
|
||||
}
|
||||
|
67
src/providers/embeds/closeload.ts
Normal file
67
src/providers/embeds/closeload.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
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: 501,
|
||||
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: false,
|
||||
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],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
46
src/providers/embeds/ridoo.ts
Normal file
46
src/providers/embeds/ridoo.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { load } from 'cheerio';
|
||||
import { unpack } from 'unpacker';
|
||||
|
||||
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: 500,
|
||||
async scrape(ctx) {
|
||||
const res = await ctx.proxiedFetcher<string>(ctx.url, {
|
||||
headers: {
|
||||
referer,
|
||||
},
|
||||
});
|
||||
const $ = load(res);
|
||||
const evalCode = $('script')
|
||||
.filter((_, el) => {
|
||||
const script = $(el);
|
||||
return (script.attr('type') === 'text/javascript' && script.html()?.includes('eval')) ?? false;
|
||||
})
|
||||
.html();
|
||||
if (!evalCode) throw new Error(res);
|
||||
const decoded = unpack(evalCode);
|
||||
const regexPattern = /file:"([^"]+)"/g;
|
||||
const url = regexPattern.exec(decoded)?.[1];
|
||||
if (!url) throw new NotFoundError('Unable to find source url');
|
||||
|
||||
return {
|
||||
stream: [
|
||||
{
|
||||
id: 'primary',
|
||||
type: 'hls',
|
||||
playlist: url,
|
||||
captions: [],
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
74
src/providers/sources/ridomovies/index.ts
Normal file
74
src/providers/sources/ridomovies/index.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
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.fetcher<SearchResult>('/search', {
|
||||
baseUrl: ridoMoviesApiBase,
|
||||
query: {
|
||||
q: encodeURIComponent(ctx.media.title),
|
||||
},
|
||||
});
|
||||
const show = searchResult.data.items[0];
|
||||
|
||||
let iframeSourceUrl = `/${show.fullSlug}/videos`;
|
||||
|
||||
if (ctx.media.type === 'show') {
|
||||
const showPageResult = await ctx.fetcher<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.fetcher<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: 500,
|
||||
flags: [flags.CORS_ALLOWED],
|
||||
scrapeMovie: universalScraper,
|
||||
scrapeShow: universalScraper,
|
||||
});
|
78
src/providers/sources/ridomovies/types.ts
Normal file
78
src/providers/sources/ridomovies/types.ts
Normal 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;
|
||||
}[];
|
||||
};
|
Reference in New Issue
Block a user