full revision added 2 more providers.

This commit is contained in:
Inside4ndroid
2025-04-10 18:35:27 +01:00
parent 74bd2a3c01
commit 4192b82612
12 changed files with 1538 additions and 383 deletions
+2
View File
@@ -0,0 +1,2 @@
TMDB_API_KEY="YOUR_TMDB_API_KEY_HERE"
PORT=3000
+28 -153
View File
@@ -1,10 +1,10 @@
# Unoffical vidsrc API! 👋 # 🍿🎥✮⋆˙ TMDB Embed API! 🍿🎥✮⋆˙
## Current Embed Providers: ## ℹ️ Current Embed Providers ℹ️
1. embedsu 1. embedsu
2. 2embed 2. 2embed
3. autoembed
<br> 4. vidsrcsu
Hello! I'm Inside4ndroid, a passionate Software Developer. Hello! I'm Inside4ndroid, a passionate Software Developer.
@@ -13,9 +13,7 @@ Hello! I'm Inside4ndroid, a passionate Software Developer.
--- ---
<br> ## 🤝 Sponsorship / Donations 🤝
## Sponsorship / Donations
Your sponsorship is vital in helping me achieve this mission. With your support, I can: Your sponsorship is vital in helping me achieve this mission. With your support, I can:
@@ -28,179 +26,56 @@ Every contribution, no matter the size, makes a significant impact.
Thank you for considering supporting my work! Thank you for considering supporting my work!
<br> ### ✨ Usage ✨
### USAGE:
This is an api for id's provided at [TMDB](https://www.themoviedb.org/). This is an api for id's provided at [TMDB](https://www.themoviedb.org/).
you must use the ID from the tmdb url like this : you must use the ID from the tmdb url like this :
so
``` ```
MOVIES: 🎬 MOVIES:
https://www.themoviedb.org/movie/1034541-terrifier-3?language=en-GB single provider - localhost:PORT/movie/{PROVIDER}/{TMDBID}
all providers - localhost:PORT/movie/{TMDBID}
TV SHOWS: 📺 TV SHOWS:
https://www.themoviedb.org/tv/124364-from?language=en-GB single provider - localhost:PORT/tv/{PROVIDER}/{TMDBID}?s={SEASON}&e={EPISODE}
``` all providers - localhost:PORT/tv/{TMDBID}?s={SEASON}&e={EPISODE}
would be
```
MOVIES:
`/{provider}/1034541`
TVSHOWS :
`/{provider}/124364?s=1&e=1` (s - Season / e - Episode)
``` ```
## Providers ## 📋 Providers 📋
The providers are currently : The providers are currently :
``` ```
embedsu embedsu
2embed 2embed
combined (use this as provider to return results for all providers) autoembed
vidsrcsu
``` ```
## Example Movie ## 🚀 Deployment 🚀
```
https://your-domain/embedsu/916224
```
## Example Show
```
https://your-domain/embedsu/1429?s=1&e=1
```
## Example JSON Response
<details>
<summary>Click me</summary>
```Json
{
"embedsu": {
"sources": [
{
"provider": "EmbedSu",
"files": [
{
"file": "https://embed.su/api/proxy/viper/mistydawn62.pro/file2/dCjXQHTrXL5VWmkFvGEEIrCyskIr6MZERXLYef0sUKuY12Ey+dX5hLYObC78qdmoop2iV8+MYm5wcOiFtAuZbcsp46BsOa1q5in7CNuEv70H5ZNZ34kEPH5I9FpN3v6qN7WhRBXq0ThSHefHVb94rMFoirhHjC4o2LRkwXoAiTA=/MTA4MA==/aW5kZXgubTN1OA==.m3u8",
"type": "hls",
"quality": "1080p",
"lang": "en"
},
{
"file": "https://embed.su/api/proxy/viper/mistydawn62.pro/file2/dCjXQHTrXL5VWmkFvGEEIrCyskIr6MZERXLYef0sUKuY12Ey+dX5hLYObC78qdmoop2iV8+MYm5wcOiFtAuZbcsp46BsOa1q5in7CNuEv70H5ZNZ34kEPH5I9FpN3v6qN7WhRBXq0ThSHefHVb94rMFoirhHjC4o2LRkwXoAiTA=/NzIw/aW5kZXgubTN1OA==.m3u8",
"type": "hls",
"quality": "720p",
"lang": "en"
},
{
"file": "https://embed.su/api/proxy/viper/mistydawn62.pro/file2/dCjXQHTrXL5VWmkFvGEEIrCyskIr6MZERXLYef0sUKuY12Ey+dX5hLYObC78qdmoop2iV8+MYm5wcOiFtAuZbcsp46BsOa1q5in7CNuEv70H5ZNZ34kEPH5I9FpN3v6qN7WhRBXq0ThSHefHVb94rMFoirhHjC4o2LRkwXoAiTA=/MzYw/aW5kZXgubTN1OA==.m3u8",
"type": "hls",
"quality": "360p",
"lang": "en"
}
],
"subtitles": [
{
"url": "https://cca.megafiles.store/1c/9e/1c9eb9aeb90915a2786400a748c8b6a4/eng-2.vtt",
"lang": "English"
},
{
"url": "https://cca.megafiles.store/1c/9e/1c9eb9aeb90915a2786400a748c8b6a4/eng-3.vtt",
"lang": "English"
},
{
"url": "https://cca.megafiles.store/1c/9e/1c9eb9aeb90915a2786400a748c8b6a4/fre-4.vtt",
"lang": "French"
},
{
"url": "https://cca.megafiles.store/1c/9e/1c9eb9aeb90915a2786400a748c8b6a4/spa-5.vtt",
"lang": "Spanish"
}
],
"headers": {
"Referer": "https://embed.su",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Origin": "https://embed.su"
}
}
]
},
"twoembed": {
"sources": {
"sources": [
{
"provider": "2Embed/Swish",
"files": [
{
"file": "https://j7fqjm25xt.premilkyway.com/hls2/01/05031/6z843r5do14n_,l,n,h,.urlset/index-f3-v1-a1.m3u8?t=T98eEbm347MS_kxTv3tPxGucVi-ZnV6omagdGNf-ZiA&s=1743805861&e=129600&f=25158304&srv=3FjgDmcnea8S35m&i=0.4&sp=500&p1=3FjgDmcnea8S35m&p2=3FjgDmcnea8S35m&asn=5378",
"type": "hls",
"quality": "1080p",
"lang": "en"
},
{
"file": "https://j7fqjm25xt.premilkyway.com/hls2/01/05031/6z843r5do14n_,l,n,h,.urlset/index-f2-v1-a1.m3u8?t=T98eEbm347MS_kxTv3tPxGucVi-ZnV6omagdGNf-ZiA&s=1743805861&e=129600&f=25158304&srv=3FjgDmcnea8S35m&i=0.4&sp=500&p1=3FjgDmcnea8S35m&p2=3FjgDmcnea8S35m&asn=5378",
"type": "hls",
"quality": "720p",
"lang": "en"
},
{
"file": "https://j7fqjm25xt.premilkyway.com/hls2/01/05031/6z843r5do14n_,l,n,h,.urlset/index-f1-v1-a1.m3u8?t=T98eEbm347MS_kxTv3tPxGucVi-ZnV6omagdGNf-ZiA&s=1743805861&e=129600&f=25158304&srv=3FjgDmcnea8S35m&i=0.4&sp=500&p1=3FjgDmcnea8S35m&p2=3FjgDmcnea8S35m&asn=5378",
"type": "hls",
"quality": "480p",
"lang": "en"
}
],
"subtitles": [
{
"url": "https://3FjgDmcnea8S35m.premilkyway.com/vtt/01/05031/6z843r5do14n_fre.vtt",
"lang": "French"
},
{
"url": "https://3FjgDmcnea8S35m.premilkyway.com/vtt/01/05031/6z843r5do14n_spa.vtt",
"lang": "Argentina"
},
{
"url": "https://3FjgDmcnea8S35m.premilkyway.com/vtt/01/05031/6z843r5do14n_eng.vtt",
"lang": "English"
}
],
"headers": {
"Referer": "https://uqloads.xyz",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Origin": "https://uqloads.xyz"
}
}
]
}
}
}
```
</details>
## Deployment
You can self host by doing the following : You can self host by doing the following :
1. `git clone https://github.com/Inside4ndroid/vidsrc-api-js.git` 1. `git clone https://github.com/Inside4ndroid/TMDB-Embed-API.git`
2. `cd vidsrc-api-js` 2. `cd TMDB-Embed-API`
3. `npm install` 3. `rename .env_example to .env`
4. `npm run main` 4. `edit .env and insert your preferred port and your tmdb api key`
5. `npm install`
6. `npm run start`
"This no longer works on vercel due to the source blocking vercel requests but will work on your own server self hosted." ## Contribute
## WARNING If you know how to code then please dont hesitate to conribute to this project by forking and making pull requests with your new providers or edits etc.
## <span style="color:red">⚠️ WARNING ⚠️</span>
Using this without a proxy may lead to your server ip being banned there are 3 ways to get around this : Using this without a proxy may lead to your server ip being banned there are 3 ways to get around this :
1. Use a proxy : [Find One Here](https://github.com/search?q=m3u8+proxy&type=repositories). 1. Use a proxy : [Find One Here](https://github.com/search?q=m3u8+proxy&type=repositories).
2. Get a server with rotating ip addresses or dynamic ip adresses and use the ips at random. 2. Get a server with rotating ip addresses or dynamic ip adresses and use the ips at random.
3. use a cloudflare proxy worker. 3. use a cloudflare proxy worker.
Some providers need cloudflare resolving and i am working on a method for this. but using correct headers etc in your network request when playing the media urls should suffice for now.
+154 -63
View File
@@ -1,91 +1,182 @@
import express from "express"; import express from "express";
import { getEmbedSu } from "./src/extractors/embedsu.js"; import { getMovie, getTv } from './src/api.js';
import { getTwoEmbed } from "./src/extractors/2Embed.js"; import { getMovieFromTmdb, getTvFromTmdb } from './src/workers/tmdb.js';
import cors from "cors";
const port = 3000; const PORT = process.env.PORT;
const app = express();
const app = express() app.use(cors());
app.get('/', (req, res) => { app.get('/', (req, res) => {
res.status(200).json({ res.status(200).json({
INTRO: "Welcome to the unofficial vidsrcPro provider", INTRO: "Welcome to the TMDB Embed API",
PROVIDERS: "2embed | embedsu | autoembed | vidsrcsu",
ROUTES: { ROUTES: {
movie: "/embedsu|2embed/:movieTMDBid", movie: "/movie/{PROVIDER}/{TMDBID}",
show: "/embedsu|2embed/:showTMDBid?s=seasonNumber&e=episodeNumber", show: "/tv/{PROVIDER}/{TMDBID}?s={SEASON}&e={EPISODE}",
all_movie: "/combined/:movieTMDBid", all_movie_providers: "/movie/{TMDBID}",
all_show: "/combined/:showTMDBid?s=seasonNumber&e=episodeNumber" all_show_providers: "/tv/{TMDBID}?s={SEASON}&e={EPISODE}"
}, },
AUTHOR: "This api is developed and created by Inside4ndroid Studios" INFORMATION: "This project is for educational purposes only. We do not host any kind of content. We provide only the links to already available content on the internet. We do not host, upload any videos, films or media files. We are not responsible for the accuracy, compliance, copyright, legality, decency, or any other aspect of the content of other linked sites. If you have any legal issues please contact the appropriate media file owners or host sites.",
SOURCE: "https://github.com/Inside4ndroid/TMDB-Embed-API"
}); });
}); });
app.get('/embedsu/:tmdbId', async (req, res) => { app.get('/movie/:tmdbId', async (req, res) => {
const id = req.params.tmdbId; if (isNaN(parseInt(req.params.tmdbId))) {
const season = req.query.s; res.status(405).json({
const episode = req.query.e; error: "Invalid movie id",
hint: "Check the documentation again to see how to use this endpoint"
});
return;
}
try { const media = await getMovieFromTmdb(req.params.tmdbId);
if (season && episode) {
const vidsrcresponse = await getEmbedSu(id, season, episode); if (media instanceof Error) {
res.status(200).json(vidsrcresponse); res.status(405).json({ error: media.message });
return;
}
let output = await getMovie(media);
if (output === null || output instanceof Error) {
res.status(404).json({
error: "No sources fond for this movie.",
hint: "If you know where to find this movie and know programming feel free to join us on GitHub: https://github.com/Inside4ndroid/TMDB-Embed-API to add it."
});
} else { } else {
const vidsrcresponse = await getEmbedSu(id); res.status(200).json(output);
res.status(200).json(vidsrcresponse);
}
} catch (error) {
console.error('Error fetching data:', error);
res.status(500).json({ error: 'Failed to fetch data' });
} }
}); });
app.get('/2embed/:tmdbId', async (req, res) => { app.get('/movie/:provider/:tmdbId', async (req, res) => {
const id = req.params.tmdbId; const allowedProviders = ['2embed', 'autoembed', 'embedsu', 'vidsrcsu'];
const season = req.query.s; if (!allowedProviders.includes(req.params.provider)) {
const episode = req.query.e; res.status(400).json({
error: "Invalid provider",
hint: `Provider must be one of: ${allowedProviders.join(', ')}`
});
return;
}
try { if (isNaN(parseInt(req.params.tmdbId))) {
if (season && episode) { res.status(400).json({
const vidsrcresponse = await getTwoEmbed(id, season, episode); error: "Invalid movie id",
res.status(200).json(vidsrcresponse); hint: "Check the documentation again to see how to use this endpoint"
});
return;
}
const media = await getMovieFromTmdb(req.params.tmdbId);
if (media instanceof Error) {
res.status(405).json({ error: media.message });
return;
}
let output = await getMovie(media, req.params.provider);
if (output === null || output instanceof Error) {
res.status(404).json({
error: "No sources fond for this movie.",
hint: "If you know where to find this movie and know programming feel free to join us on GitHub: https://github.com/Inside4ndroid/TMDB-Embed-API to add it."
});
} else { } else {
const vidsrcresponse = await getTwoEmbed(id, 0, 0); res.status(200).json(output);
res.status(200).json(vidsrcresponse);
}
} catch (error) {
console.error('Error fetching data:', error);
res.status(500).json({ error: 'Failed to fetch data' });
} }
}); });
app.get('/combined/:tmdbId', async (req, res) => { app.get('/tv/:tmdbId', async (req, res) => {
const id = req.params.tmdbId; if (!req.params.tmdbId || isNaN(parseInt(req.params.tmdbId)) || !req.query.s || isNaN(parseInt(req.query.s)) || !req.query.e || isNaN(parseInt(req.query.e))) {
const season = req.query.s; res.status(405).json({
const episode = req.query.e; error: "Invalid show id, season, or episode number",
hint: "Check the documentation again to see how to use this endpoint"
});
return;
}
try { const media = await getTvFromTmdb(req.params.tmdbId, req.query.s, req.query.e);
let embedSuResponse;
let twoEmbedResponse;
if (season && episode) { if (media instanceof Error) {
embedSuResponse = await getEmbedSu(id, season, episode); res.status(405).json({ error: media.message });
twoEmbedResponse = await getTwoEmbed(id, season, episode); return;
}
let output = await getTv(media, req.query.s, req.query.e);
if (output === null || output instanceof Error) {
res.status(404).json({
error: "No sources found for this show.",
hint: "If you know where to find this show and know programming feel free to join us on GitHub: https://github.com/Inside4ndroid/TMDB-Embed-API to add it."
});
} else { } else {
embedSuResponse = await getEmbedSu(id); res.status(200).json(output);
twoEmbedResponse = await getTwoEmbed(id, 0, 0);
}
const combinedResponse = {
embedsu: embedSuResponse,
twoembed: twoEmbedResponse,
};
res.status(200).json(combinedResponse);
} catch (error) {
console.error('Error fetching data:', error);
res.status(500).json({ error: 'Failed to fetch data' });
} }
}); });
app.listen(port, () => { app.get('/tv/:provider?/:tmdbId', async (req, res) => {
console.log(`Api listening on port http://localhost:${port}`); const allowedProviders = ['2embed', 'autoembed', 'embedsu', 'vidsrcsu'];
if (!allowedProviders.includes(req.params.provider)) {
res.status(400).json({
error: "Invalid provider",
hint: `Provider must be one of: ${allowedProviders.join(', ')}`
});
return;
}
if (isNaN(parseInt(req.params.tmdbId))) {
res.status(400).json({
error: "Invalid show id",
hint: "Check the documentation again to see how to use this endpoint",
});
return;
}
if (!req.query.s || isNaN(parseInt(req.query.s)) || !req.query.e || isNaN(parseInt(req.query.e))) {
return res.status(400).json({
error: "Invalid season, or episode number",
hint: "Check the documentation again to see how to use this endpoint"
});
}
const media = await getTvFromTmdb(req.params.tmdbId, req.query.s, req.query.e);
if (media instanceof Error) {
return res.status(405).json({ error: media.message });
}
let output = await getTv(media, req.query.s, req.query.e, req.params.provider);
if (output === null || output instanceof Error) {
return res.status(404).json({
error: "No sources found for this show.",
hint: "If you know where to find this show and know programming feel free to join us on GitHub: https://github.com/Inside4ndroid/TMDB-Embed-API to add it."
});
}
return res.status(200).json(output);
});
app.get('/movie/', (req, res) => {
res.status(405).json({
error: "Invalid movie id",
hint: "Check the documentation again to see how to use this endpoint"
});
});
app.get('/tv/', (req, res) => {
res.status(405).json({
error: "Invalid show id",
hint: "Check the documentation again to see how to use this endpoint"
});
});
app.get('*', (req, res) => {
res.status(404).json({ error: 'Not found', hint: 'Go to /' });
});
app.listen(PORT, () => {
console.log(`Server is running on port http://localhost:${PORT}`);
}); });
+287 -156
View File
@@ -1,15 +1,17 @@
{ {
"name": "vidsrc-api-v2", "name": "tmdb-embed-api",
"version": "1.0.0", "version": "1.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "vidsrc-api-v2", "name": "tmdb-embed-api",
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"cheerio": "^1.0.0", "cheerio": "^1.0.0",
"cors": "^2.8.5",
"dotenv": "^16.4.7",
"express": "^4.18.2", "express": "^4.18.2",
"fetch": "^1.1.0", "fetch": "^1.1.0",
"node-fetch": "^3.3.2" "node-fetch": "^3.3.2"
@@ -38,6 +40,7 @@
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/biskviit/-/biskviit-1.0.1.tgz", "resolved": "https://registry.npmjs.org/biskviit/-/biskviit-1.0.1.tgz",
"integrity": "sha512-VGCXdHbdbpEkFgtjkeoBN8vRlbj1ZRX2/mxhE8asCCRalUx2nBzOomLJv8Aw/nRt5+ccDb+tPKidg4XxcfGW4w==", "integrity": "sha512-VGCXdHbdbpEkFgtjkeoBN8vRlbj1ZRX2/mxhE8asCCRalUx2nBzOomLJv8Aw/nRt5+ccDb+tPKidg4XxcfGW4w==",
"license": "MIT",
"dependencies": { "dependencies": {
"psl": "^1.1.7" "psl": "^1.1.7"
}, },
@@ -46,9 +49,9 @@
} }
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "1.20.2", "version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bytes": "3.1.2", "bytes": "3.1.2",
@@ -59,7 +62,7 @@
"http-errors": "2.0.0", "http-errors": "2.0.0",
"iconv-lite": "0.4.24", "iconv-lite": "0.4.24",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"qs": "6.11.0", "qs": "6.13.0",
"raw-body": "2.5.2", "raw-body": "2.5.2",
"type-is": "~1.6.18", "type-is": "~1.6.18",
"unpipe": "1.0.0" "unpipe": "1.0.0"
@@ -69,6 +72,18 @@
"npm": "1.2.8000 || >= 1.4.16" "npm": "1.2.8000 || >= 1.4.16"
} }
}, },
"node_modules/body-parser/node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/boolbase": { "node_modules/boolbase": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -84,17 +99,27 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/call-bind": { "node_modules/call-bind-apply-helpers": {
"version": "1.0.7", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"function-bind": "^1.1.2", "function-bind": "^1.1.2"
"get-intrinsic": "^1.2.4", },
"set-function-length": "^1.2.1" "engines": {
"node": ">= 0.4"
}
},
"node_modules/call-bound": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
}, },
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -167,9 +192,9 @@
} }
}, },
"node_modules/cookie": { "node_modules/cookie": {
"version": "0.6.0", "version": "0.7.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@@ -181,6 +206,19 @@
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/css-select": { "node_modules/css-select": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
@@ -213,6 +251,7 @@
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 12" "node": ">= 12"
} }
@@ -226,23 +265,6 @@
"ms": "2.0.0" "ms": "2.0.0"
} }
}, },
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/depd": { "node_modules/depd": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -317,6 +339,32 @@
"url": "https://github.com/fb55/domutils?sponsor=1" "url": "https://github.com/fb55/domutils?sponsor=1"
} }
}, },
"node_modules/dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -324,9 +372,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/encodeurl": { "node_modules/encodeurl": {
"version": "1.0.2", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@@ -336,6 +384,7 @@
"version": "0.1.12", "version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
"integrity": "sha512-bl1LAgiQc4ZWr++pNYUdRe/alecaHFeHxIJ/pNciqGdKXghaTCOwKkbKp6ye7pKZGu/GcaSXFk8PBVhgs+dJdA==", "integrity": "sha512-bl1LAgiQc4ZWr++pNYUdRe/alecaHFeHxIJ/pNciqGdKXghaTCOwKkbKp6ye7pKZGu/GcaSXFk8PBVhgs+dJdA==",
"license": "MIT",
"dependencies": { "dependencies": {
"iconv-lite": "~0.4.13" "iconv-lite": "~0.4.13"
} }
@@ -353,13 +402,13 @@
"url": "https://github.com/fb55/encoding-sniffer?sponsor=1" "url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
} }
}, },
"node_modules/encoding-sniffer/node_modules/iconv-lite": { "node_modules/encoding/node_modules/iconv-lite": {
"version": "0.6.3", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0" "safer-buffer": ">= 2.1.2 < 3"
}, },
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@@ -378,13 +427,10 @@
} }
}, },
"node_modules/es-define-property": { "node_modules/es-define-property": {
"version": "1.0.0", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT", "license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.4"
},
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
} }
@@ -398,6 +444,18 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escape-html": { "node_modules/escape-html": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -414,37 +472,37 @@
} }
}, },
"node_modules/express": { "node_modules/express": {
"version": "4.19.2", "version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"accepts": "~1.3.8", "accepts": "~1.3.8",
"array-flatten": "1.1.1", "array-flatten": "1.1.1",
"body-parser": "1.20.2", "body-parser": "1.20.3",
"content-disposition": "0.5.4", "content-disposition": "0.5.4",
"content-type": "~1.0.4", "content-type": "~1.0.4",
"cookie": "0.6.0", "cookie": "0.7.1",
"cookie-signature": "1.0.6", "cookie-signature": "1.0.6",
"debug": "2.6.9", "debug": "2.6.9",
"depd": "2.0.0", "depd": "2.0.0",
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"etag": "~1.8.1", "etag": "~1.8.1",
"finalhandler": "1.2.0", "finalhandler": "1.3.1",
"fresh": "0.5.2", "fresh": "0.5.2",
"http-errors": "2.0.0", "http-errors": "2.0.0",
"merge-descriptors": "1.0.1", "merge-descriptors": "1.0.3",
"methods": "~1.1.2", "methods": "~1.1.2",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"path-to-regexp": "0.1.7", "path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7", "proxy-addr": "~2.0.7",
"qs": "6.11.0", "qs": "6.13.0",
"range-parser": "~1.2.1", "range-parser": "~1.2.1",
"safe-buffer": "5.2.1", "safe-buffer": "5.2.1",
"send": "0.18.0", "send": "0.19.0",
"serve-static": "1.15.0", "serve-static": "1.16.2",
"setprototypeof": "1.2.0", "setprototypeof": "1.2.0",
"statuses": "2.0.1", "statuses": "2.0.1",
"type-is": "~1.6.18", "type-is": "~1.6.18",
@@ -453,12 +511,17 @@
}, },
"engines": { "engines": {
"node": ">= 0.10.0" "node": ">= 0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
} }
}, },
"node_modules/fetch": { "node_modules/fetch": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/fetch/-/fetch-1.1.0.tgz", "resolved": "https://registry.npmjs.org/fetch/-/fetch-1.1.0.tgz",
"integrity": "sha512-5O8TwrGzoNblBG/jtK4NFuZwNCkZX6s5GfRNOaGtm+QGJEuNakSC/i2RW0R93KX6E0jVjNXm6O3CRN4Ql3K+yA==", "integrity": "sha512-5O8TwrGzoNblBG/jtK4NFuZwNCkZX6s5GfRNOaGtm+QGJEuNakSC/i2RW0R93KX6E0jVjNXm6O3CRN4Ql3K+yA==",
"license": "MIT",
"dependencies": { "dependencies": {
"biskviit": "1.0.1", "biskviit": "1.0.1",
"encoding": "0.1.12" "encoding": "0.1.12"
@@ -478,6 +541,7 @@
"url": "https://paypal.me/jimmywarting" "url": "https://paypal.me/jimmywarting"
} }
], ],
"license": "MIT",
"dependencies": { "dependencies": {
"node-domexception": "^1.0.0", "node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3" "web-streams-polyfill": "^3.0.3"
@@ -487,13 +551,13 @@
} }
}, },
"node_modules/finalhandler": { "node_modules/finalhandler": {
"version": "1.2.0", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"debug": "2.6.9", "debug": "2.6.9",
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"on-finished": "2.4.1", "on-finished": "2.4.1",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
@@ -508,6 +572,7 @@
"version": "4.0.10", "version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"license": "MIT",
"dependencies": { "dependencies": {
"fetch-blob": "^3.1.2" "fetch-blob": "^3.1.2"
}, },
@@ -543,16 +608,21 @@
} }
}, },
"node_modules/get-intrinsic": { "node_modules/get-intrinsic": {
"version": "1.2.4", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2", "function-bind": "^1.1.2",
"has-proto": "^1.0.1", "get-proto": "^1.0.1",
"has-symbols": "^1.0.3", "gopd": "^1.2.0",
"hasown": "^2.0.0" "has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
}, },
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -561,34 +631,23 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/gopd": { "node_modules/get-proto": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"get-intrinsic": "^1.1.3" "dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
}, },
"funding": { "engines": {
"url": "https://github.com/sponsors/ljharb" "node": ">= 0.4"
} }
}, },
"node_modules/has-property-descriptors": { "node_modules/gopd": {
"version": "1.0.2", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-proto": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -598,9 +657,9 @@
} }
}, },
"node_modules/has-symbols": { "node_modules/has-symbols": {
"version": "1.0.3", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -657,12 +716,12 @@
} }
}, },
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.4.24", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"safer-buffer": ">= 2.1.2 < 3" "safer-buffer": ">= 2.1.2 < 3.0.0"
}, },
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@@ -683,6 +742,15 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/media-typer": { "node_modules/media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -693,10 +761,13 @@
} }
}, },
"node_modules/merge-descriptors": { "node_modules/merge-descriptors": {
"version": "1.0.1", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"license": "MIT" "license": "MIT",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}, },
"node_modules/methods": { "node_modules/methods": {
"version": "1.1.2", "version": "1.1.2",
@@ -769,6 +840,7 @@
"url": "https://paypal.me/jimmywarting" "url": "https://paypal.me/jimmywarting"
} }
], ],
"license": "MIT",
"engines": { "engines": {
"node": ">=10.5.0" "node": ">=10.5.0"
} }
@@ -777,6 +849,7 @@
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
"license": "MIT",
"dependencies": { "dependencies": {
"data-uri-to-buffer": "^4.0.0", "data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4", "fetch-blob": "^3.1.4",
@@ -802,10 +875,19 @@
"url": "https://github.com/fb55/nth-check?sponsor=1" "url": "https://github.com/fb55/nth-check?sponsor=1"
} }
}, },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.13.2", "version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -873,9 +955,9 @@
} }
}, },
"node_modules/path-to-regexp": { "node_modules/path-to-regexp": {
"version": "0.1.7", "version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/proxy-addr": { "node_modules/proxy-addr": {
@@ -895,6 +977,7 @@
"version": "1.15.0", "version": "1.15.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
"integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
"license": "MIT",
"dependencies": { "dependencies": {
"punycode": "^2.3.1" "punycode": "^2.3.1"
}, },
@@ -906,17 +989,18 @@
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.11.0", "version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"side-channel": "^1.0.4" "side-channel": "^1.0.6"
}, },
"engines": { "engines": {
"node": ">=0.6" "node": ">=0.6"
@@ -949,6 +1033,18 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/raw-body/node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -976,9 +1072,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/send": { "node_modules/send": {
"version": "0.18.0", "version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"debug": "2.6.9", "debug": "2.6.9",
@@ -999,6 +1095,15 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/send/node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/send/node_modules/ms": { "node_modules/send/node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -1006,37 +1111,20 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/serve-static": { "node_modules/serve-static": {
"version": "1.15.0", "version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"encodeurl": "~1.0.2", "encodeurl": "~2.0.0",
"escape-html": "~1.0.3", "escape-html": "~1.0.3",
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"send": "0.18.0" "send": "0.19.0"
}, },
"engines": { "engines": {
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/setprototypeof": { "node_modules/setprototypeof": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -1044,15 +1132,69 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/side-channel": { "node_modules/side-channel": {
"version": "1.0.6", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"call-bind": "^1.0.7",
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"get-intrinsic": "^1.2.4", "object-inspect": "^1.13.3",
"object-inspect": "^1.13.1" "side-channel-list": "^1.0.0",
"side-channel-map": "^1.0.1",
"side-channel-weakmap": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-list": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-map": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-weakmap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3",
"side-channel-map": "^1.0.1"
}, },
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@@ -1132,6 +1274,7 @@
"version": "3.3.3", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
} }
@@ -1148,18 +1291,6 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/whatwg-encoding/node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/whatwg-mimetype": { "node_modules/whatwg-mimetype": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+10 -9
View File
@@ -1,17 +1,18 @@
{ {
"name": "vidsrc-api-v2", "name": "tmdb-embed-api",
"version": "1.0.0", "version": "1.0.0",
"description": "An api that scrapes vidsrc (f2cloud, filemoon) plus subtitles", "description": "An api to get embed sources using tmdbid.",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"main": "node --watch index.js"
},
"author": "Inside4ndroid Studios Ltd",
"license": "ISC", "license": "ISC",
"author": "Inside4ndroid Studios",
"type": "module",
"main": "index.js",
"scripts": {
"start": "node --watch index.js"
},
"dependencies": { "dependencies": {
"cheerio": "^1.0.0", "cheerio": "^1.0.0",
"cors": "^2.8.5",
"dotenv": "^16.4.7",
"express": "^4.18.2", "express": "^4.18.2",
"fetch": "^1.1.0", "fetch": "^1.1.0",
"node-fetch": "^3.3.2" "node-fetch": "^3.3.2"
+102
View File
@@ -0,0 +1,102 @@
import { getTwoEmbed } from "./workers/sites/2Embed.js";
import { getAutoembed } from "./workers/sites/AutoEmbed.js";
import { getEmbedSu } from "./workers/sites/Embedsu.js";
import { getVidSrcSu } from "./workers/sites/VidsrcSU.js";
export async function getMovie(media, provider = null) {
const combinedResponse = [];
const tmdb_id = media.tmdbId;
if (provider) {
try {
let result;
switch (provider) {
case '2embed':
result = await getTwoEmbed(tmdb_id);
break;
case 'embedsu':
result = await getEmbedSu(tmdb_id);
break;
case 'autoembed':
result = await getAutoembed(tmdb_id);
break;
case 'vidsrcsu':
result = await getVidSrcSu(tmdb_id);
break;
default:
throw new Error(`Unknown provider: ${provider}`);
}
if (result) combinedResponse.push(result);
} catch (e) {
console.error(`Error fetching from ${provider}:`, e);
}
return combinedResponse;
}
const providers = [
{ name: '2embed', func: getTwoEmbed },
{ name: 'embedsu', func: getEmbedSu },
{ name: 'autoembed', func: getAutoembed },
{ name: 'vidsrcsu', func: getVidSrcSu }
];
for (const { name, func } of providers) {
try {
const result = await func(tmdb_id);
if (result) combinedResponse.push(result);
} catch (e) {
console.error(`Error fetching from ${name}:`, e);
}
}
return combinedResponse;
}
export async function getTv(media, season, episode, provider = null) {
const combinedResponse = [];
const tmdb_id = media.tmdbId;
if (provider) {
try {
let result;
switch (provider) {
case '2embed':
result = await getTwoEmbed(tmdb_id, season, episode);
break;
case 'embedsu':
result = await getEmbedSu(tmdb_id, season, episode);
break;
case 'autoembed':
result = await getAutoembed(tmdb_id, season, episode);
break;
case 'vidsrcsu':
result = await getVidSrcSu(tmdb_id, season, episode);
break;
default:
throw new Error(`Unknown provider: ${provider}`);
}
if (result) combinedResponse.push(result);
} catch (e) {
console.error(`Error fetching from ${provider}:`, e);
}
return combinedResponse;
}
const providers = [
{ name: '2embed', func: getTwoEmbed },
{ name: 'embedsu', func: getEmbedSu },
{ name: 'autoembed', func: getAutoembed },
{ name: 'vidsrcsu', func: getVidSrcSu }
];
for (const { name, func } of providers) {
try {
const result = await func(tmdb_id, season, episode);
if (result) combinedResponse.push(result);
} catch (e) {
console.error(`Error fetching from ${name}:`, e);
}
}
return combinedResponse;
}
+386
View File
@@ -0,0 +1,386 @@
import fetch from "node-fetch";
import JsUnpacker from '../utils/jsunpack.js';
import * as cheerio from 'cheerio';
const DOMAIN = "https://www.2embed.cc";
const PLAYER_URL = "https://uqloads.xyz";
let subtitles = [];
let sources = [];
const headers = {
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
'Referer': DOMAIN,
'Origin': DOMAIN,
};
function parseQuality(qualityString) {
if (!qualityString) return 0;
const q = qualityString.toUpperCase();
if (q === '4K') return 4000;
if (q.includes('1080P')) return 1080;
if (q.includes('720P')) return 720;
const numMatch = q.match(/(\d+)/);
return numMatch ? parseInt(numMatch[1], 10) : 0;
}
function createErrorObject(errorMessage) {
return {
provider: "2Embed",
ERROR: [{
error: `ERROR`,
what_happened: errorMessage,
report_issue: 'https://github.com/Inside4ndroid/vidsrc-api-js/issues'
}]
};
}
export async function getTwoEmbed(tmdb_id, s, e) {
subtitles = [];
sources = [];
const tmdbId = tmdb_id;
const initialReferer = s && e ? `${DOMAIN}/embedtv/${tmdbId}&s=${s}&e=${e}` : `${DOMAIN}/embed/${tmdbId}`;
const url = initialReferer;
try {
const response = await fetch(url, {
method: "POST",
headers: {
Referer: url,
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": headers['User-Agent'],
},
body: "pls=pls"
});
if (!response.ok) {
return { sources: createErrorObject(`HTTP error fetching initial URL! Status: ${response.status}`) };
}
const data = await response.text();
let extractedValue = null;
let isSwishId = false;
let match = data.match(/swish\?id=(?<id>[\w\d]+)/);
if (match && match.groups && match.groups.id) {
extractedValue = match.groups.id;
isSwishId = true;
} else {
match = data.match(/'(.*?player4u.*?)'/);
if (match && match[1]) {
extractedValue = match[1];
} else {
return { sources: createErrorObject("No relevant swish ID or player4u URL found in initial data.") };
}
}
if (extractedValue) {
if (isSwishId) {
const streamUrl = await resolve(`${PLAYER_URL}/e/${extractedValue}`, DOMAIN);
if (!streamUrl) {
return { sources: createErrorObject(`Could not resolve stream URL for swish ID: ${extractedValue}`) };
}
const parsedSources = await parseM3U8(streamUrl, PLAYER_URL);
if (parsedSources.length > 0) {
return {
source: {
provider: "2Embed/Swish",
files: parsedSources,
subtitles: subtitles,
headers: {
"Referer": PLAYER_URL,
"User-Agent": headers['User-Agent'],
"Origin": PLAYER_URL
}
}
};
} else {
return { sources: createErrorObject("No valid sources found in M3U8 for swish ID") };
}
} else {
const listPageResponse = await fetch(extractedValue, {
headers: {
Referer: url,
"User-Agent": headers['User-Agent']
}
});
if (!listPageResponse.ok) {
return { sources: createErrorObject(`Failed to fetch player4u list page (${extractedValue}): ${listPageResponse.status}`) };
}
const listPageHtml = await listPageResponse.text();
const $ = cheerio.load(listPageHtml);
let highestQuality = -1;
let bestPartialUrl = null;
$('li.slide-toggle a.playbtnx').each((index, element) => {
const linkText = $(element).text();
const onclickAttr = $(element).attr('onclick');
if (!linkText || !onclickAttr) return;
const qualityMatch = linkText.match(/\s*(\d+p|4K)\s*/i);
const qualityString = qualityMatch ? qualityMatch[1].toUpperCase() : null;
const urlMatch = onclickAttr.match(/go\('([^']+)'\)/);
const partialUrl = urlMatch ? urlMatch[1] : null;
if (!qualityString || !partialUrl) return;
const qualityValue = parseQuality(qualityString);
if (qualityValue > highestQuality) {
highestQuality = qualityValue;
bestPartialUrl = partialUrl;
}
});
if (bestPartialUrl) {
const idMatch = bestPartialUrl.match(/\?id=([\w\d]+)/);
if (idMatch && idMatch[1]) {
const player4uId = idMatch[1];
const resolveUrl = `${PLAYER_URL}/e/${player4uId}`;
const streamUrl = await resolve(resolveUrl, extractedValue);
if (!streamUrl) {
return { sources: createErrorObject(`Could not resolve stream URL for player4u ID: ${player4uId}`) };
}
const parsedSources = await parseM3U8(streamUrl, PLAYER_URL);
if (parsedSources.length > 0) {
return {
source: {
provider: "2Embed/Player4u",
files: parsedSources,
subtitles: subtitles,
headers: {
"Referer": PLAYER_URL,
"User-Agent": headers['User-Agent'],
"Origin": PLAYER_URL
}
}
};
} else {
return { sources: createErrorObject("No valid sources found in M3U8 for player4u ID") };
}
} else {
return { sources: createErrorObject("Could not extract player4u ID from best quality URL") };
}
} else {
return { sources: createErrorObject("No valid quality options found on player4u page") };
}
}
}
return { sources: createErrorObject("No sources found after processing") };
} catch (error) {
return { sources: createErrorObject(`Unexpected error: ${error.message}`) };
}
}
async function resolve(url, referer) {
try {
const response = await fetch(url, {
headers: {
Referer: referer,
"User-Agent": headers['User-Agent']
}
});
if (!response.ok) {
console.error(`Resolve failed for ${url}: Status ${response.status}`);
return null;
}
const data = await response.text();
const packedDataRegex = /eval\(function(.*?)split.*\)\)\)/s;
const packedDataMatch = data.match(packedDataRegex);
if (packedDataMatch) {
const packedJS = packedDataMatch[0];
const unpacker = new JsUnpacker(packedJS);
if (unpacker.detect()) {
const unpackedJS = unpacker.unpack();
if (!unpackedJS) {
console.error("JsUnpacker failed to unpack");
return null;
}
await parseSubs(unpackedJS);
const docheck = unpackedJS.includes("\"hls2\":\"https");
if (docheck) {
const fileRegex = /links=.*hls2\":\"(.*?)\"};/;
const matchUri = unpackedJS.match(fileRegex);
if (matchUri && matchUri[1]) {
return matchUri[1];
} else {
console.error("Could not find file URL in unpacked JS");
return null;
}
} else {
const fileRegex = /sources\s*:\s*\[\s*\{\s*file\s*:\s*"([^"]+)"/;
const matchUri = unpackedJS.match(fileRegex);
if (matchUri && matchUri[1]) {
return matchUri[1];
} else {
console.error("Could not find file URL in unpacked JS");
return null;
}
}
} else {
console.error("JsUnpacker could not detect packed data in resolve response");
return null;
}
} else {
console.error("No packed JS data found in resolve response for:", url);
if (url.includes('.m3u8')) return url;
return null;
}
} catch (error) {
console.error(`Error during resolve for ${url}:`, error);
return null;
}
}
async function parseM3U8(m3u8Url, referer) {
const parsedSources = [];
try {
const response = await fetch(m3u8Url, {
headers: {
"User-Agent": headers['User-Agent'],
"Referer": referer
}
});
if (!response.ok) {
console.error(`Failed to fetch M3U8 ${m3u8Url}: Status ${response.status}`);
return [];
}
const m3u8Content = await response.text();
const lines = m3u8Content.split('\n');
let currentQuality = null;
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (line.startsWith('#EXT-X-STREAM-INF:')) {
currentQuality = null;
const resolutionMatch = line.match(/RESOLUTION=\d+x(\d+)/);
if (resolutionMatch && resolutionMatch[1]) {
currentQuality = resolutionMatch[1] + "p";
} else {
const bwMatch = line.match(/BANDWIDTH=(\d+)/);
if (bwMatch) {
currentQuality = `bw${bwMatch[1]}`;
}
}
} else if (currentQuality && (line.startsWith('http') || (line.includes('.m3u8') && !line.startsWith('#')))) {
let resolvedUrl = line;
if (!line.startsWith('http')) {
const baseUrl = new URL(m3u8Url);
resolvedUrl = new URL(line, baseUrl.origin + baseUrl.pathname.substring(0, baseUrl.pathname.lastIndexOf('/') + 1)).href;
}
parsedSources.push({
file: resolvedUrl,
type: 'hls',
quality: currentQuality,
lang: 'en'
});
currentQuality = null;
}
}
parsedSources.sort((a, b) => parseQuality(b.quality) - parseQuality(a.quality));
return parsedSources;
} catch (error) {
console.error(`Error parsing M3U8 ${m3u8Url}:`, error);
return [];
}
}
async function parseSubs(scriptstring) {
if (typeof subtitles === 'undefined') {
console.error("Subtitles array is not accessible in parseSubs");
return;
}
try {
const linksMatch = scriptstring.match(/var links\s*=\s*({[^;]*});/);
if (!linksMatch) {
console.error("Could not find links object in script");
return;
}
let linksStr = linksMatch[1]
.replace(/'/g, '"')
.replace(/([{,]\s*)([a-zA-Z0-9_$]+)(\s*:)/g, '$1"$2"$3');
const links = JSON.parse(linksStr);
const videoUrl = links.hls2;
const setupMatch = scriptstring.match(/jwplayer\(["']vplayer["']\)\.setup\((\{[\s\S]*?\})\);[\s\S]*?$/);
if (!setupMatch || !setupMatch[1]) {
console.error("Could not find JWPlayer setup configuration");
return;
}
let setupStr = setupMatch[1];
setupStr = setupStr.replace(/links\.hls4\s*\|\|\s*links\.hls2/g, `"${videoUrl}"`);
setupStr = setupStr
.replace(/\\'/g, "'")
.replace(/([{,]\s*)([a-zA-Z0-9_$]+)(\s*:)/g, '$1"$2"$3')
.replace(/'/g, '"')
.replace(/,\s*([}\]])/g, '$1')
.replace(/"true"/g, 'true')
.replace(/"false"/g, 'false')
.replace(/"null"/g, 'null');
let setupConfig;
try {
setupConfig = JSON.parse(setupStr);
} catch (err) {
console.error("JSON parse error:", err, "in string:", setupStr);
return;
}
if (!setupConfig.tracks) {
return;
}
const subtitleTracks = (setupConfig.tracks || []).filter(track =>
track && (track.kind === "captions" || track.kind === "subtitles") && track.file
).map(track => ({
url: track.file,
lang: track.label || track.kind
}));
subtitleTracks.forEach(newSub => {
if (!subtitles.some(existingSub => existingSub.url === newSub.url && existingSub.lang === newSub.lang)) {
subtitles.push(newSub);
}
});
} catch (error) {
console.error("Error during subtitle parsing:", error);
}
}
+144
View File
@@ -0,0 +1,144 @@
import fetch from "node-fetch";
const DOMAIN = "https://autoembed.cc/";
const headers = {
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
'Referer': DOMAIN,
'Origin': DOMAIN,
};
function createErrorObject(errorMessage) {
return {
provider: "AutoEmbed",
ERROR: [{
error: `ERROR`,
what_happened: errorMessage,
report_issue: 'https://github.com/Inside4ndroid/vidsrc-api-js/issues'
}]
};
};
export async function getAutoembed(tmdb_id, s, e) {
const providerName = "AutoEmbed";
const url = s && e
? `https://tom.autoembed.cc/api/getVideoSource?type=tv&id=${tmdb_id}/${s}/${e}`
: `https://tom.autoembed.cc/api/getVideoSource?type=movie&id=${tmdb_id}`;
try {
const response = await fetch(url, {
headers: {
'Referer': DOMAIN,
'User-Agent': headers['User-Agent']
}
});
if (!response.ok) {
return createErrorObject(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
if (data.error) {
return createErrorObject(data.error || "No stream with ID found");
}
if (!data.videoSource) {
return createErrorObject("No video source found in response");
}
const m3u8Url = data.videoSource;
try {
const m3u8Response = await fetch(m3u8Url);
if (!m3u8Response.ok) {
return createErrorObject(`Failed to fetch m3u8: HTTP ${m3u8Response.status}`);
}
const m3u8Content = await m3u8Response.text();
const sources = parseM3U8(m3u8Content);
if (!sources || sources.length === 0) {
return createErrorObject("No valid streams found in m3u8 file");
}
const formattedSources = sources.map(source => ({
file: source.url,
type: "hls",
quality: source.quality || 'unknown',
lang: 'en'
}));
const subs = data.subtitles ? mapSubtitles(data.subtitles) : [];
return {
source: {
provider: providerName,
files: formattedSources,
subtitles: subs,
headers: {
"Referer": DOMAIN,
"User-Agent": headers['User-Agent'],
"Origin": DOMAIN
}
}
};
} catch (m3u8Error) {
return createErrorObject(`Failed to process m3u8: ${m3u8Error.message}`);
}
} catch (error) {
return createErrorObject(`Network/API error: ${error.message}`);
}
}
function parseM3U8(m3u8Content) {
try {
const lines = m3u8Content.split('\n');
const sources = [];
let currentSource = {};
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (line.startsWith('#EXT-X-STREAM-INF:')) {
const resolutionMatch = line.match(/RESOLUTION=(\d+x\d+)/);
if (resolutionMatch) {
const resolution = resolutionMatch[1];
const quality = resolution.split('x')[1];
currentSource.quality = quality + 'p';
}
} else if (line.startsWith('http')) {
currentSource.url = line;
sources.push({ ...currentSource });
currentSource = {};
}
}
return sources;
} catch (error) {
console.error('Error parsing m3u8:', error);
return [];
}
}
function mapSubtitles(subtitles) {
try {
return subtitles.map(subtitle => {
const lang = (subtitle.label || 'unknown').split(' ')[0].toLowerCase();
const fileUrl = subtitle.file || '';
const fileExtension = fileUrl.split('.').pop().toLowerCase();
const type = fileExtension === 'vtt' ? 'vtt' : 'srt';
return {
url: fileUrl,
lang: lang,
type: type
};
}).filter(sub => sub.url);
} catch (error) {
console.error('Error mapping subtitles:', error);
return [];
}
}
+185
View File
@@ -0,0 +1,185 @@
import fetch from 'node-fetch';
function createErrorObject(errorMessage) {
return {
provider: "EmbedSU",
ERROR: [{
error: `ERROR`,
what_happened: errorMessage,
report_issue: 'https://github.com/Inside4ndroid/vidsrc-api-js/issues'
}]
};
}
export async function getEmbedSu(tmdb_id, s, e) {
const DOMAIN = "https://embed.su";
const headers = {
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
'Referer': DOMAIN,
'Origin': DOMAIN,
};
try {
const urlSearch = s && e ? `${DOMAIN}/embed/tv/${tmdb_id}/${s}/${e}` : `${DOMAIN}/embed/movie/${tmdb_id}`;
const htmlSearch = await fetch(urlSearch, { method: 'GET', headers });
if (!htmlSearch.ok) {
return { sources: [createErrorObject(`Failed to fetch initial page: HTTP ${htmlSearch.status}`)] };
}
const textSearch = await htmlSearch.text();
const hashEncodeMatch = textSearch.match(/JSON\.parse\(atob\(\`([^\`]+)/i);
const hashEncode = hashEncodeMatch ? hashEncodeMatch[1] : "";
if (!hashEncode) {
return { sources: [createErrorObject("No encoded hash found in initial page")] };
}
let hashDecode;
try {
hashDecode = JSON.parse(await stringAtob(hashEncode));
} catch (e) {
return { sources: [createErrorObject(`Failed to decode initial hash: ${e.message}`)] };
}
const mEncrypt = hashDecode.hash;
if (!mEncrypt) {
return { sources: [createErrorObject("No encrypted hash found in decoded data")] };
}
let firstDecode;
try {
firstDecode = (await stringAtob(mEncrypt)).split(".").map(item => item.split("").reverse().join(""));
} catch (e) {
return { sources: [createErrorObject(`Failed to decode first layer: ${e.message}`)] };
}
let secondDecode;
try {
secondDecode = JSON.parse(await stringAtob(firstDecode.join("").split("").reverse().join("")));
} catch (e) {
return { sources: [createErrorObject(`Failed to decode second layer: ${e.message}`)] };
}
if (!secondDecode || secondDecode.length === 0) {
return { sources: [createErrorObject("No valid sources found after decoding")] };
}
const sources = [];
const subtitles = [];
for (const item of secondDecode) {
try {
const urlDirect = `${DOMAIN}/api/e/${item.hash}`;
const dataDirect = await requestGet(urlDirect, {
"Referer": DOMAIN,
"User-Agent": headers['User-Agent'],
"Origin": DOMAIN
});
if (!dataDirect || !dataDirect.source) {
console.warn(`No source found for hash ${item.hash}`);
continue;
}
const tracks = (dataDirect.subtitles || []).map(sub => ({
url: sub.file,
lang: sub.label ? sub.label.split('-')[0].trim() : 'en'
})).filter(track => track.url);
const requestDirectSize = await fetch(dataDirect.source, { headers, method: "GET" });
if (!requestDirectSize.ok) {
console.warn(`Failed to fetch source ${dataDirect.source}: HTTP ${requestDirectSize.status}`);
continue;
}
const parseRequest = await requestDirectSize.text();
const patternSize = parseRequest.split('\n').filter(item => item.includes('/proxy/'));
const directQuality = patternSize.map(patternItem => {
try {
const sizeQuality = getSizeQuality(patternItem);
let dURL = `${DOMAIN}${patternItem}`;
dURL = dURL.replace(".png", ".m3u8");
return { file: dURL, type: 'hls', quality: `${sizeQuality}p`, lang: 'en' };
} catch (e) {
console.warn(`Failed to process quality for pattern: ${patternItem}`, e);
return null;
}
}).filter(item => item !== null);
if (!directQuality.length) {
console.warn(`No valid qualities found for source ${dataDirect.source}`);
continue;
}
return {
source: {
provider: "EmbedSu",
files: directQuality,
subtitles: tracks,
headers: {
"Referer": DOMAIN,
"User-Agent": headers['User-Agent'],
"Origin": DOMAIN
}
}
};
} catch (e) {
console.error(`Error processing item ${item.hash}:`, e);
// Continue to next item instead of failing entire request
}
}
if (sources.length === 0) {
return { sources: [createErrorObject("No valid sources found after processing all items")] };
}
return { sources };
} catch (e) {
return { sources: [createErrorObject(`Unexpected error: ${e.message}`)] };
}
}
function getSizeQuality(url) {
try {
const parts = url.split('/');
const base64Part = parts[parts.length - 2];
const decodedPart = atob(base64Part);
return Number(decodedPart) || 1080;
} catch (e) {
console.warn(`Failed to get size quality for URL ${url}:`, e);
return 720; // Default quality if parsing fails
}
}
async function stringAtob(input) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
let str = input.replace(/=+$/, '');
let output = '';
if (str.length % 4 === 1) {
throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");
}
for (let bc = 0, bs = 0, buffer, i = 0; buffer = str.charAt(i++); ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0) {
buffer = chars.indexOf(buffer);
}
return output;
}
async function requestGet(url, headers = {}) {
try {
const response = await fetch(url, { method: 'GET', headers });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error(`Request failed for ${url}:`, error);
return null;
}
}
+80
View File
@@ -0,0 +1,80 @@
import fetch from 'node-fetch';
const DOMAIN = "https://vidsrc.su/";
const headers = {
'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
'Referer': DOMAIN,
'Origin': DOMAIN,
};
function createErrorObject(errorMessage) {
return {
provider: "EmbedSU",
ERROR: [{
error: `ERROR`,
what_happened: errorMessage,
report_issue: 'https://github.com/Inside4ndroid/vidsrc-api-js/issues'
}]
};
};
export async function getVidSrcSu(tmdb_id, s, e) {
const embedUrl = s && e ? `https://vidsrc.su/embed/tv/${tmdb_id}/${s}/${e}` : `https://vidsrc.su/embed/movie/${tmdb_id}`;
try {
const response = await fetch(embedUrl, { headers });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const html = await response.text();
let subtitles = [];
const servers = [...html.matchAll(/label: 'Server (3|4|5|7|8|9|10|12|13|15|17|18|19)', url: '(https.*)'/g)].map(match => ({
file: match[2],
type: "hls",
lang: "en"
}));
const subtitlesMatch = html.match(/const subtitles = \[(.*)\];/g);
if (subtitlesMatch && subtitlesMatch[0]) {
try {
subtitles = JSON.parse(subtitlesMatch[0].replace('const subtitles = ', '').replaceAll(';', ''));
subtitles.shift();
subtitles = subtitles.map(subtitle => ({
url: subtitle.url,
lang: subtitle.language,
type: subtitle.format
}));
} catch (parseError) {
console.error("Error parsing subtitles:", parseError);
subtitles = [];
}
}
try {
servers.forEach(server => {
// smth
});
} catch (error) {
return createErrorObject("No valid video streams found after parsing all servers");
}
return {
source: {
provider: "VidsrcSU",
files: servers,
subtitles: subtitles,
headers: {
"Referer": DOMAIN,
"User-Agent": headers['User-Agent'],
"Origin": DOMAIN
}
}
};
} catch (error) {
return createErrorObject(`Unexpected error: ${error.message}`);
}
}
+52
View File
@@ -0,0 +1,52 @@
import dotenv from 'dotenv';
dotenv.config();
const apiKey = process.env.TMDB_API_KEY;
export async function getMovieFromTmdb(tmdb_id) {
try {
const url = `https://api.themoviedb.org/3/movie/${tmdb_id}?api_key=${apiKey}`;
const response = await fetch(url);
const data = await response.json();
if (new Date(data.release_date) > new Date().getTime()) {
return new Error("Media not released yet");
}
let info = {
type: "movie",
title: data.original_title,
releaseYear: Number(data.release_date.split("-")[0]),
tmdbId: tmdb_id,
imdbId: data.imdb_id
}
return info;
} catch (e) {
return new Error("An error occurred" + e);
}
}
export async function getTvFromTmdb(tmdb_id, season, episode) {
try {
const url = `https://api.themoviedb.org/3/tv/${tmdb_id}/season/${season}/episode/${episode}?api_key=${apiKey}&append_to_response=external_ids`;
const response = await fetch(url);
const data = await response.json();
if (new Date(data.air_date) > new Date().getTime()) {
return new Error("Not released yet");
}
let secondData = await fetch(`https://api.themoviedb.org/3/tv/${tmdb_id}?api_key=${apiKey}`);
secondData = await secondData.json();
let title = secondData.name;
let info = {
type: "tv",
title: title,
releaseYear: data.air_date.split("-")[0],
tmdbId: tmdb_id,
imdbId: data.external_ids.imdb_id,
season: season,
episode: episode,
episodeName: data.name
}
return info;
} catch (e) {
return new Error("An error occurred" + e);
}
}
+106
View File
@@ -0,0 +1,106 @@
export default class JsUnpacker {
static Unbase = class {
constructor(radix) {
this.ALPHABET_62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
this.ALPHABET_95 = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
this.alphabet = null;
this.dictionary = {};
this.radix = radix;
if (radix > 36) {
if (radix < 62) {
this.alphabet = this.ALPHABET_62.substring(0, radix);
} else if (radix > 62 && radix < 95) {
this.alphabet = this.ALPHABET_95.substring(0, radix);
} else if (radix === 62) {
this.alphabet = this.ALPHABET_62;
} else if (radix === 95) {
this.alphabet = this.ALPHABET_95;
}
for (let i = 0; i < this.alphabet.length; i++) {
this.dictionary[this.alphabet[i]] = i;
}
}
}
unbase(str) {
let ret = 0;
if (this.alphabet === null) {
ret = parseInt(str, this.radix);
} else {
const tmp = str.split('').reverse().join('');
for (let i = 0; i < tmp.length; i++) {
ret += Math.pow(this.radix, i) * this.dictionary[tmp[i]];
}
}
return ret;
}
};
constructor(packedJS) {
this.packedJS = packedJS;
}
detect() {
const js = this.packedJS.replace(/\s/g, '');
const regex = /eval\(function\(p,a,c,k,e,(?:r|d)/;
return regex.test(js);
}
unpack() {
let js = this.packedJS;
try {
const regex = /\}\s*\('(.*)',\s*(.*?),\s*(\d+),\s*'(.*?)'\.split\('\|'\)/s;
const match = js.match(regex);
if (match && match.length === 5) {
let payload = match[1].replace(/\\'/g, "'");
const radixStr = match[2];
const countStr = match[3];
const symtab = match[4].split('|');
let radix = 36;
let count = 0;
try {
radix = parseInt(radixStr);
} catch (e) {
}
try {
count = parseInt(countStr);
} catch (e) {
}
if (symtab.length !== count) {
throw new Error("Unknown p.a.c.k.e.r. encoding");
}
const unbase = new this.constructor.Unbase(radix);
const wordRegex = /\b\w+\b/g;
let decoded = payload;
let replaceOffset = 0;
let wordMatch;
while ((wordMatch = wordRegex.exec(payload)) !== null) {
const word = wordMatch[0];
const x = unbase.unbase(word);
let value = null;
if (x < symtab.length) {
value = symtab[x];
}
if (value && value.length > 0) {
const start = wordMatch.index + replaceOffset;
const end = start + word.length;
decoded = decoded.substring(0, start) + value + decoded.substring(end);
replaceOffset += (value.length - word.length);
}
}
return decoded;
}
} catch (e) {
return null;
}
return null;
}
}