mirror of
https://github.com/movie-web/providers.git
synced 2025-09-13 13:33:25 +00:00
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## What is `@movie-web/providers`?
|
## What is `@movie-web/providers`?
|
||||||
|
|
||||||
`@movie-web/providers` is the soul of [movie-web.app](https://movie-web.app). It's a collection of scrapers of various streaming sites. It extracts the raw streams from those sites, so you can watch them without any extra fluff from the original sites.
|
`@movie-web/providers` is the soul of [movie-web](https://github.com/movie-web/movie-web). It's a collection of scrapers of various streaming sites. It extracts the raw streams from those sites, so you can watch them without any extra fluff from the original sites.
|
||||||
|
|
||||||
## What can I use this on?
|
## What can I use this on?
|
||||||
|
|
||||||
|
@@ -2,6 +2,12 @@
|
|||||||
title: 'Changelog'
|
title: 'Changelog'
|
||||||
---
|
---
|
||||||
|
|
||||||
|
# Version 2.2.2
|
||||||
|
- Fix subtitles not appearing if the name of the subtitle is in its native tongue.
|
||||||
|
- Remove references to the old domain
|
||||||
|
- Fixed ridomovies not working for some shows and movies
|
||||||
|
- Fixed Showbox not working in react-native.
|
||||||
|
|
||||||
# Version 2.2.1
|
# Version 2.2.1
|
||||||
- Fixed Closeload scraper
|
- Fixed Closeload scraper
|
||||||
|
|
||||||
|
@@ -17,7 +17,7 @@ import { makeProviders, makeStandardFetcher, targets } from '@movie-web/provider
|
|||||||
|
|
||||||
const providers = makeProviders({
|
const providers = makeProviders({
|
||||||
fetcher: makeStandardFetcher(fetch),
|
fetcher: makeStandardFetcher(fetch),
|
||||||
target: chooseYourself, // check out https://providers.docs.movie-web.app/essentials/targets
|
target: chooseYourself, // check out https://movie-web.github.io/providers/essentials/targets
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2
.github/SECURITY.md
vendored
2
.github/SECURITY.md
vendored
@@ -11,4 +11,4 @@ Support is not provided for any forks or mirrors of movie-web.
|
|||||||
|
|
||||||
There are two ways you can contact the movie-web maintainers to report a vulnerability:
|
There are two ways you can contact the movie-web maintainers to report a vulnerability:
|
||||||
- Email [security@movie-web.app](mailto:security@movie-web.app)
|
- Email [security@movie-web.app](mailto:security@movie-web.app)
|
||||||
- Report the vulnerability in the [movie-web Discord server](https://discord.movie-web.app)
|
- Report the vulnerability in the [movie-web Discord server](https://movie-web.github.io/links/discord)
|
||||||
|
@@ -7,8 +7,8 @@ features:
|
|||||||
- scrape popular streaming websites
|
- scrape popular streaming websites
|
||||||
- works in both browser and server-side
|
- works in both browser and server-side
|
||||||
|
|
||||||
Visit documentation here: https://providers.docs.movie-web.app/
|
Visit documentation here: https://movie-web.github.io/providers/
|
||||||
|
|
||||||
## How to run locally or test my changes
|
## How to run locally or test my changes
|
||||||
|
|
||||||
These topics are also covered in the documentation, [read about it here](https://providers.docs.movie-web.app/extra-topics/development).
|
These topics are also covered in the documentation, [read about it here](https://movie-web.github.io/providers/extra-topics/development).
|
||||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@movie-web/providers",
|
"name": "@movie-web/providers",
|
||||||
"version": "2.2.0",
|
"version": "2.2.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@movie-web/providers",
|
"name": "@movie-web/providers",
|
||||||
"version": "2.2.0",
|
"version": "2.2.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cheerio": "^1.0.0-rc.12",
|
"cheerio": "^1.0.0-rc.12",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@movie-web/providers",
|
"name": "@movie-web/providers",
|
||||||
"version": "2.2.1",
|
"version": "2.2.2",
|
||||||
"description": "Package that contains all the providers of movie-web",
|
"description": "Package that contains all the providers of movie-web",
|
||||||
"main": "./lib/index.umd.js",
|
"main": "./lib/index.umd.js",
|
||||||
"types": "./lib/index.d.ts",
|
"types": "./lib/index.d.ts",
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/movie-web/providers/issues"
|
"url": "https://github.com/movie-web/providers/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://providers.docs.movie-web.app/",
|
"homepage": "https://movie-web.github.io/providers/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build && tsc --noEmit",
|
"build": "vite build && tsc --noEmit",
|
||||||
"cli": "ts-node ./src/dev-cli/index.ts",
|
"cli": "ts-node ./src/dev-cli/index.ts",
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import FormData from 'form-data';
|
import FormData from 'form-data';
|
||||||
|
|
||||||
import { FetcherOptions } from '@/fetchers/types';
|
import { FetcherOptions } from '@/fetchers/types';
|
||||||
|
import { isReactNative } from '@/utils/native';
|
||||||
|
|
||||||
export interface SeralizedBody {
|
export interface SeralizedBody {
|
||||||
headers: Record<string, string>;
|
headers: Record<string, string>;
|
||||||
@@ -8,11 +9,20 @@ export interface SeralizedBody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function serializeBody(body: FetcherOptions['body']): SeralizedBody {
|
export function serializeBody(body: FetcherOptions['body']): SeralizedBody {
|
||||||
if (body === undefined || typeof body === 'string' || body instanceof URLSearchParams || body instanceof FormData)
|
if (body === undefined || typeof body === 'string' || body instanceof URLSearchParams || body instanceof FormData) {
|
||||||
|
if (body instanceof URLSearchParams && isReactNative()) {
|
||||||
|
return {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
body: body.toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
headers: {},
|
headers: {},
|
||||||
body,
|
body,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// serialize as JSON
|
// serialize as JSON
|
||||||
return {
|
return {
|
||||||
|
@@ -9,7 +9,7 @@ export const doodScraper = makeEmbed({
|
|||||||
name: 'dood',
|
name: 'dood',
|
||||||
rank: 173,
|
rank: 173,
|
||||||
async scrape(ctx) {
|
async scrape(ctx) {
|
||||||
const baseUrl = 'https://do0od.com';
|
const baseUrl = 'https://d0000d.com';
|
||||||
|
|
||||||
const id = ctx.url.split('/d/')[1] || ctx.url.split('/e/')[1];
|
const id = ctx.url.split('/d/')[1] || ctx.url.split('/e/')[1];
|
||||||
|
|
||||||
@@ -18,18 +18,17 @@ export const doodScraper = makeEmbed({
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dataForLater = doodData.match(/a\+"\?token=([^"]+)/)?.[1];
|
const dataForLater = doodData.match(/\?token=([^&]+)&expiry=/)?.[1];
|
||||||
const path = doodData.match(/\$\.get\('\/pass_md5([^']+)/)?.[1];
|
const path = doodData.match(/\$\.get\('\/pass_md5([^']+)/)?.[1];
|
||||||
|
|
||||||
const doodPage = await ctx.proxiedFetcher<string>(`/pass_md5/${path}`, {
|
const doodPage = await ctx.proxiedFetcher<string>(`/pass_md5${path}`, {
|
||||||
headers: {
|
headers: {
|
||||||
referer: `${baseUrl}/e/${id}`,
|
Referer: `${baseUrl}/e/${id}`,
|
||||||
},
|
},
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
baseUrl,
|
baseUrl,
|
||||||
});
|
});
|
||||||
|
const downloadURL = `${doodPage}${nanoid()}?token=${dataForLater}&expiry=${Date.now()}`;
|
||||||
const downloadURL = `${doodPage}${nanoid()}?token=${dataForLater}${Date.now()}`;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stream: [
|
stream: [
|
||||||
@@ -42,10 +41,10 @@ export const doodScraper = makeEmbed({
|
|||||||
unknown: {
|
unknown: {
|
||||||
type: 'mp4',
|
type: 'mp4',
|
||||||
url: downloadURL,
|
url: downloadURL,
|
||||||
|
},
|
||||||
|
},
|
||||||
headers: {
|
headers: {
|
||||||
referer: 'https://do0od.com/',
|
Referer: 'https://d0000d.com/',
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@@ -110,7 +110,7 @@ export const upcloudScraper = makeEmbed({
|
|||||||
if (track.kind !== 'captions') return;
|
if (track.kind !== 'captions') return;
|
||||||
const type = getCaptionTypeFromUrl(track.file);
|
const type = getCaptionTypeFromUrl(track.file);
|
||||||
if (!type) return;
|
if (!type) return;
|
||||||
const language = labelToLanguageCode(track.label);
|
const language = labelToLanguageCode(track.label.split(' ')[0]);
|
||||||
if (!language) return;
|
if (!language) return;
|
||||||
captions.push({
|
captions.push({
|
||||||
id: track.file,
|
id: track.file,
|
||||||
|
@@ -10,18 +10,28 @@ export async function getEmbeds(ctx: ScrapeContext, id: string): Promise<EmbedsR
|
|||||||
baseUrl: baseUrl2,
|
baseUrl: baseUrl2,
|
||||||
headers: {
|
headers: {
|
||||||
Referer: baseUrl,
|
Referer: baseUrl,
|
||||||
|
cookie: '',
|
||||||
},
|
},
|
||||||
readHeaders: ['Set-Cookie'],
|
readHeaders: ['Set-Cookie'],
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
|
|
||||||
const cookies = parseSetCookie(data.headers.get('Set-Cookie') || '');
|
const cookies = parseSetCookie(data.headers.get('Set-Cookie') || '');
|
||||||
const aGoozCookie = cookies.aGooz.value;
|
|
||||||
|
|
||||||
const $ = load(data.body);
|
|
||||||
const RandomCookieName = data.body.split(`_3chk('`)[1].split(`'`)[0];
|
const RandomCookieName = data.body.split(`_3chk('`)[1].split(`'`)[0];
|
||||||
const RandomCookieValue = data.body.split(`_3chk('`)[1].split(`'`)[2];
|
const RandomCookieValue = data.body.split(`_3chk('`)[1].split(`'`)[2];
|
||||||
|
|
||||||
|
let aGoozCookie = '';
|
||||||
|
let cookie = '';
|
||||||
|
if (cookies && cookies.aGooz && RandomCookieName && RandomCookieValue) {
|
||||||
|
aGoozCookie = cookies.aGooz.value;
|
||||||
|
cookie = makeCookieHeader({
|
||||||
|
aGooz: aGoozCookie,
|
||||||
|
[RandomCookieName]: RandomCookieValue,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const $ = load(data.body);
|
||||||
|
|
||||||
const embedRedirectURLs = $('a')
|
const embedRedirectURLs = $('a')
|
||||||
.map((index, element) => $(element).attr('href'))
|
.map((index, element) => $(element).attr('href'))
|
||||||
.get()
|
.get()
|
||||||
@@ -33,10 +43,7 @@ export async function getEmbeds(ctx: ScrapeContext, id: string): Promise<EmbedsR
|
|||||||
ctx.fetcher
|
ctx.fetcher
|
||||||
.full(url, {
|
.full(url, {
|
||||||
headers: {
|
headers: {
|
||||||
cookie: makeCookieHeader({
|
cookie,
|
||||||
aGooz: aGoozCookie,
|
|
||||||
[RandomCookieName]: RandomCookieValue,
|
|
||||||
}),
|
|
||||||
Referer: baseUrl2,
|
Referer: baseUrl2,
|
||||||
},
|
},
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
@@ -21,7 +21,7 @@ async function universalScraper(ctx: ShowScrapeContext | MovieScrapeContext): Pr
|
|||||||
|
|
||||||
export const goojaraScraper = makeSourcerer({
|
export const goojaraScraper = makeSourcerer({
|
||||||
id: 'goojara',
|
id: 'goojara',
|
||||||
name: 'goojara',
|
name: 'Goojara',
|
||||||
rank: 225,
|
rank: 225,
|
||||||
flags: [],
|
flags: [],
|
||||||
scrapeShow: universalScraper,
|
scrapeShow: universalScraper,
|
||||||
|
@@ -49,7 +49,6 @@ export async function searchAndFindMedia(
|
|||||||
});
|
});
|
||||||
|
|
||||||
const result = results.find((res: Result) => compareMedia(media, res.title, Number(res.year)));
|
const result = results.find((res: Result) => compareMedia(media, res.title, Number(res.year)));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,19 +66,7 @@ export async function scrapeIds(
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
headers: headersData,
|
headers: headersData,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
query: { s: media.season.number.toString() },
|
||||||
|
|
||||||
const $1 = load(data);
|
|
||||||
|
|
||||||
const dataId = $1('#seon').attr('data-id');
|
|
||||||
|
|
||||||
if (!dataId) throw new NotFoundError('Not found');
|
|
||||||
|
|
||||||
data = await ctx.fetcher<string>(`/xhrc.php`, {
|
|
||||||
baseUrl,
|
|
||||||
headers: headersData,
|
|
||||||
method: 'POST',
|
|
||||||
body: new URLSearchParams({ s: media.season.number.toString(), t: dataId }),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let episodeId = '';
|
let episodeId = '';
|
||||||
@@ -89,7 +76,6 @@ export async function scrapeIds(
|
|||||||
$2('.seho').each((index, element) => {
|
$2('.seho').each((index, element) => {
|
||||||
// Extracting the episode number as a string
|
// Extracting the episode number as a string
|
||||||
const episodeNumber = $2(element).find('.seep .sea').text().trim();
|
const episodeNumber = $2(element).find('.seep .sea').text().trim();
|
||||||
|
|
||||||
// Comparing with the desired episode number as a string
|
// Comparing with the desired episode number as a string
|
||||||
if (parseInt(episodeNumber, 10) === media.episode.number) {
|
if (parseInt(episodeNumber, 10) === media.episode.number) {
|
||||||
const href = $2(element).find('.snfo h1 a').attr('href');
|
const href = $2(element).find('.snfo h1 a').attr('href');
|
||||||
|
@@ -28,9 +28,9 @@ const universalScraper = async (ctx: MovieScrapeContext | ShowScrapeContext) =>
|
|||||||
const showPageResult = await ctx.proxiedFetcher<string>(`/${show.fullSlug}`, {
|
const showPageResult = await ctx.proxiedFetcher<string>(`/${show.fullSlug}`, {
|
||||||
baseUrl: ridoMoviesBase,
|
baseUrl: ridoMoviesBase,
|
||||||
});
|
});
|
||||||
const fullEpisodeSlug = `${show.fullSlug}/season-${ctx.media.season.number}/episode-${ctx.media.episode.number}`;
|
const fullEpisodeSlug = `season-${ctx.media.season.number}/episode-${ctx.media.episode.number}`;
|
||||||
const regexPattern = new RegExp(
|
const regexPattern = new RegExp(
|
||||||
`\\\\"id\\\\":\\\\"(\\d+)\\\\"(?=.*?\\\\\\"fullSlug\\\\\\":\\\\\\"${fullEpisodeSlug}\\\\\\")`,
|
`\\\\"id\\\\":\\\\"(\\d+)\\\\"(?=.*?\\\\\\"fullSlug\\\\\\":\\\\\\"[^"]*${fullEpisodeSlug}[^"]*\\\\\\")`,
|
||||||
'g',
|
'g',
|
||||||
);
|
);
|
||||||
const matches = [...showPageResult.matchAll(regexPattern)];
|
const matches = [...showPageResult.matchAll(regexPattern)];
|
||||||
|
9
src/utils/native.ts
Normal file
9
src/utils/native.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export const isReactNative = () => {
|
||||||
|
try {
|
||||||
|
// eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
|
||||||
|
require('react-native');
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
Reference in New Issue
Block a user