From d0cc0f85638d02bc92ecbf8369c4b72f22202e16 Mon Sep 17 00:00:00 2001 From: Inside4ndroid Date: Thu, 1 Aug 2024 09:20:16 +0100 Subject: [PATCH] vidsrcto converted to vidsrc.cc --- index.js | 15 ++-- package-lock.json | 91 ++++++++++++++++++++ package.json | 1 + src/filemoon.js | 137 ------------------------------ src/getKeys.js | 24 ------ src/vidsrcto.js | 206 +++++++++++++++++----------------------------- 6 files changed, 176 insertions(+), 298 deletions(-) delete mode 100644 src/filemoon.js delete mode 100644 src/getKeys.js diff --git a/index.js b/index.js index 2ba4d76..357ae68 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,5 @@ import express from "express"; import { getvmovie, getvserie } from "./src/vidsrcto.js"; -import { getfmovie, getfserie } from "./src/filemoon.js"; const port = 3000; @@ -9,7 +8,7 @@ const app = express() app.get('/', (req, res) => { res.status(200).json({ - intro: "Welcome to the unofficial vidsrc provider: check the provider website @ https://vidsrc.to/ ", + intro: "Welcome to the unofficial vidsrc provider: check the provider website @ https://${host}/ ", routes: { movie: "/vidsrc/:movieTMDBid", show: "/vidsrc/:showTMDBid?s=seasonNumber&e=episodeNumber" @@ -26,14 +25,10 @@ app.get('/vidsrc/:tmdbId', async (req, res) => { try { if (season && episode) { const vidsrcresponse = await getvserie(id, season, episode); - const filemoonresponse = await getfserie(id, season, episode); - const combinedResponse = { ...filemoonresponse, ...vidsrcresponse }; - res.status(200).json(combinedResponse); + res.status(200).json(vidsrcresponse); } else { const vidsrcresponse = await getvmovie(id); - const filemoonresponse = await getfmovie(id); - const combinedResponse = { ...filemoonresponse, ...vidsrcresponse }; - res.status(200).json(combinedResponse); + res.status(200).json(vidsrcresponse); } } catch (error) { console.error('Error fetching data:', error); @@ -41,6 +36,10 @@ app.get('/vidsrc/:tmdbId', async (req, res) => { } }); +function wait(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + app.listen(port, () => { console.log(`Example app listening on port http://localhost:${port}`); }); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b9c145d..ef3983a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "express": "^4.18.2", + "node-fetch": "^3.3.2", "unpacker": "^1.0.1" } }, @@ -120,6 +121,15 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -258,6 +268,29 @@ "node": ">= 0.10.0" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -276,6 +309,18 @@ "node": ">= 0.8" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -497,6 +542,43 @@ "node": ">= 0.6" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/object-inspect": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", @@ -763,6 +845,15 @@ "engines": { "node": ">= 0.8" } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } } } } diff --git a/package.json b/package.json index af92bcb..3383cf5 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "license": "ISC", "dependencies": { "express": "^4.18.2", + "node-fetch": "^3.3.2", "unpacker": "^1.0.1" } } diff --git a/src/filemoon.js b/src/filemoon.js deleted file mode 100644 index 78843e4..0000000 --- a/src/filemoon.js +++ /dev/null @@ -1,137 +0,0 @@ -import { getKeys } from './getKeys.js'; -import { unpack } from 'unpacker'; - -const keys = await getKeys(); - -function rc4(key, inp) { - let e = []; - e[4] = []; - e[3] = 0; - let i = 0; - e[8] = ''; - for (i = 0; i < 256; i++) { - e[4][i] = i; - } - for (i = 0; i < 256; i++) { - e[3] = (e[3] + e[4][i] + key.charCodeAt(i % key.length)) % 256; - e[2] = e[4][i]; - e[4][i] = e[4][e[3]]; - e[4][e[3]] = e[2]; - } - i = 0; - e[3] = 0; - let j = 0; - for (j = 0; j < inp.length; j++) { - i = (i + 1) % 256; - e[3] = (e[3] + e[4][i]) % 256; - e[2] = e[4][i]; - e[4][i] = e[4][e[3]]; - e[4][e[3]] = e[2]; - e[8] += String.fromCharCode(inp.charCodeAt(j) ^ e[4][(e[4][i] + e[4][e[3]]) % 256]); - } - return e[8]; -} - -function enc(inp) { - inp = encodeURIComponent(inp); - const e = rc4(keys[0], inp); - const out = btoa(e).replace(/\//g, '_').replace(/\+/g, '-'); - return out; -} - -function dec(inp) { - const i = atob(inp.replace(/_/g, '/').replace(/-/g, '+')); - let e = rc4(keys[3], i); - e = decodeURIComponent(e); - return e; -} - -async function episode(data_id) { - let url = `https://vidsrc.to/ajax/embed/episode/${data_id}/sources?token=${encodeURIComponent(enc(data_id))}`; - let resp = await fetch(url); - resp = await resp.json(); - - let filemoon_id = resp.result[1].id; - url = `https://vidsrc.to/ajax/embed/source/${filemoon_id}?token=${encodeURIComponent(enc(filemoon_id))}`; - resp = await fetch(url); - resp = await resp.json(); - - let filemoon_url = resp.result.url; - let filemoon_url_dec = dec(filemoon_url); - const parsedUrl = new URL(filemoon_url_dec); - - const SRC_URL = parsedUrl.origin + parsedUrl.pathname; - const queryParams = parsedUrl.search.substring(1); - const params = new URLSearchParams(queryParams); - const subtitleLink = params.get('sub.info'); - - console.log(SRC_URL); - console.log(subtitleLink); - - const data = await fetch(SRC_URL); - const dataText = await data.text(); - const match = /eval\(function\(p,a,c,k,e,d\).+\)\)\)/g.exec(dataText); - - if (match) { - const packed = match[0]; - const unpacked = unpack(packed); - const hlsMatch = /sources:\[\s*{\s*file:"([^"]*)"/g.exec(unpacked); - const subs = await getSubtitles(subtitleLink); - const sources = hlsMatch[1]; - - if (!sources) { - const data = { - source: null, - subtitles: null - }; - return { filemoon: data }; - } else { - const data = { - source: sources, - subtitles: subs - }; - return { filemoon: data }; - } - } else { - console.error('Packed data not found'); - } -} - -async function getSubtitles(subtitleLink) { - if (subtitleLink) { - const subtitlesFetch = await fetch(subtitleLink); - const subtitles = await subtitlesFetch.json(); - - return subtitles.map(subtitle => ({ - file: subtitle.file, - lang: subtitle.label, - })); - } else { - console.error('Subtitle link not found in params'); - return null; - } -} - -export async function getfmovie(id) { - let resp = await fetch(`https://vidsrc.to/embed/movie/${id}`); - let respText = await resp.text(); - const match = /data-id="(.*?)"/g.exec(respText); - - if (match) { - let data_id = match[1]; - return episode(data_id); - } else { - console.error('Data ID not found'); - } -} - -export async function getfserie(id, s, e) { - let resp = await (await fetch(`https://vidsrc.to/embed/tv/${id}/${s}/${e}`)).text(); - let match = (/data-id="(.*?)"/g).exec(resp)[1]; - if (match) { - let data_id = match[1]; - return episode(data_id); - } else { - console.error('Data ID not found'); - } - } diff --git a/src/getKeys.js b/src/getKeys.js deleted file mode 100644 index e16a8df..0000000 --- a/src/getKeys.js +++ /dev/null @@ -1,24 +0,0 @@ -export const getKeys = async () => { - const url = "https://raw.githubusercontent.com/Ciarands/vidsrc-keys/main/keys.json"; - - try { - const response = await fetch(url); - if (response.status !== 200) { - console.error("Failed to fetch decryption keys:", response.statusText); - return null; - } - - const keys = await response.json(); - - if (keys && keys.encrypt && keys.decrypt) { - const allKeys = [...keys.encrypt, ...keys.decrypt]; - return allKeys; - } else { - console.error("Keys object is empty or malformed"); - return null; - } - } catch (error) { - console.error("Error:", error.message); - return null; - } -}; diff --git a/src/vidsrcto.js b/src/vidsrcto.js index 961a968..88960da 100644 --- a/src/vidsrcto.js +++ b/src/vidsrcto.js @@ -1,142 +1,90 @@ -import { getKeys } from './getKeys.js'; +const HOST = 'vidsrc.cc'; -const keys = await getKeys(); +async function episode(data_id_1, data_id_2, type, s, e) { + if (type == 'movie') { + const url = `https://${HOST}/api/episodes/${data_id_2}/servers?id=${data_id_1}&type=${type}`; + let resp = await (await fetch(url)).json(); + let id1 = resp['data'][0]['hash']; + let id2 = resp['data'][1]['hash']; + const url1 = `https://${HOST}/api/source/${id1}`; + console.log(url1); + const resp1 = await (await fetch(url1)).json(); + const url2 = `https://${HOST}/api/source/${id2}`; + console.log(url2); + const resp2 = await (await fetch(url2)).json(); + const result_1 = { + source1: resp1 + }; + const result_2 = { + source2: resp2 + }; + const combinedResponse = { ...result_1, ...result_2 }; + console.log(`combinedResponse : ${JSON.stringify(combinedResponse, null, 2)}`); + return combinedResponse; + }; -function rc4(key, inp) { - let e = []; - e[4] = []; - e[3] = 0; - let i = 0; - e[8] = ""; - for (i = 0; i < 256; i++) { - e[4][i] = i; + if (type == 'tv') { + const url = `https://${HOST}/api/episodes/${data_id_2}/servers?id=${data_id_1}&type=tv&season=${s}&episode=${e}`; + console.log(url); + let resp = await (await fetch(url)).json(); + let id1 = resp['data'][0]['hash']; + let id2 = resp['data'][1]['hash']; + const url1 = `https://${HOST}/api/source/${id1}`; + console.log(url1); + const resp1 = await (await fetch(url1)).json(); + const url2 = `https://${HOST}/api/source/${id2}`; + console.log(url2); + const resp2 = await (await fetch(url2)).json(); + const result_1 = { + source1: resp1 + }; + const result_2 = { + source2: resp2 + }; + const combinedResponse = { ...result_1, ...result_2 }; + console.log(`combinedResponse : ${JSON.stringify(combinedResponse, null, 2)}`); + return combinedResponse; } - for (i = 0; i < 256; i++) { - e[3] = (e[3] + e[4][i] + key.charCodeAt(i % key.length)) % 256; - e[2] = e[4][i]; - e[4][i] = e[4][e[3]]; - e[4][e[3]] = e[2]; - } - i = 0; - e[3] = 0; - let j = 0; - for (j = 0; j < inp.length; j++) { - i = (i + 1) % 256; - e[3] = (e[3] + e[4][i]) % 256; - e[2] = e[4][i]; - e[4][i] = e[4][e[3]]; - e[4][e[3]] = e[2]; - e[8] += String.fromCharCode(inp.charCodeAt(j) ^ e[4][(e[4][i] + e[4][e[3]]) % 256]); - } - return e[8]; -} - -function enc(inp) { - inp = encodeURIComponent(inp); - const e = rc4(keys[0], inp); - const out = btoa(e).replace(/\//g, "_").replace(/\+/g, '-'); - return out; -} - -function embed_enc(inp) { - inp = encodeURIComponent(inp); - const e = rc4(keys[1], inp); - const out = btoa(e).replace(/\//g, "_").replace(/\+/g, '-'); - return out; -} - -function h_enc(inp) { - inp = encodeURIComponent(inp); - const e = rc4(keys[2], inp); - const out = btoa(e).replace(/\//g, "_").replace(/\+/g, '-'); - return out; -} - -function dec(inp) { - const i = atob((inp).replace(/_/g, "/").replace(/-/g, "+")); - let e = rc4(keys[3], i); - e = decodeURIComponent(e); - return e; -} - -function embed_dec(inp) { - const i = atob((inp).replace(/_/g, "/").replace(/-/g, "+")); - let e = rc4(keys[4], i); - e = decodeURIComponent(e); - return e; -} - -async function episode(data_id) { - let url = `https://vidsrc.to/ajax/embed/episode/${data_id}/sources?token=${encodeURIComponent(enc(data_id))}`; - let resp = await (await fetch(url)).json(); - - console.log(resp); - - let f2cloud_id = resp['result'][0]['id']; - - console.log(f2cloud_id); - - url = `https://vidsrc.to/ajax/embed/source/${f2cloud_id}?token=${encodeURIComponent(enc(f2cloud_id))}`; - resp = await (await fetch(url)).json(); - - let f2cloud_url = resp['result']['url']; - let f2cloud_url_dec = dec(f2cloud_url); - - const subs = await getSubtitles(f2cloud_url_dec); - - url = new URL(f2cloud_url_dec); - let embed_id = url.pathname.split("/")[2]; - let h = h_enc(embed_id); - let mediainfo_url = `https://vid2v11.site/mediainfo/${embed_enc(embed_id)}${url.search}&ads=0&h=${encodeURIComponent(h)}`; - resp = await (await fetch(mediainfo_url)).json(); - - let playlist = embed_dec(resp['result']); - if (typeof playlist === 'string') { - playlist = JSON.parse(playlist); - } - - const sources = playlist.sources?.[0]?.file; - - if (!sources) { - const data = { - source: null, - subtitles: null - }; - return { vidsrc: data }; - } else { - const data = { - source: sources, - subtitles: subs - }; - return { vidsrc: data }; - } } export async function getvmovie(id) { - - let resp = await (await fetch(`https://vidsrc.to/embed/movie/${id}`)).text(); - const match = (/data-id="(.*?)"/g).exec(resp); - let data_id = match[1]; - return episode(data_id); + console.log(`https://${HOST}/v2/embed/movie/${id}`); + let resp = await (await fetch(`https://${HOST}/v2/embed/movie/${id}`)).text(); + + let regex = /data-id="(.*?)"/g; + let matches = []; + let match; + + while ((match = regex.exec(resp)) !== null) { + matches.push(match[1]); + } + + if (matches.length >= 2) { + let data_id_1 = matches[0]; + let data_id_2 = matches[1]; + return await episode(data_id_1, data_id_2, 'movie'); + } else { + throw new Error("Failed to find two data-id values in response."); + } } export async function getvserie(id, s, e) { - let resp = await (await fetch(`https://vidsrc.to/embed/tv/${id}/${s}/${e}`)).text(); - let data_id = (/data-id="(.*?)"/g).exec(resp)[1]; - return episode(data_id); -} + console.log(`https://${HOST}/v2/embed/tv/${id}/${s}/${e}`); + let resp = await (await fetch(`https://${HOST}/v2/embed/tv/${id}/${s}/${e}`)).text(); + let regex = /data-id="(.*?)"/g; + let matches = []; + let match; -async function getSubtitles(vidplayLink) { - if (vidplayLink.includes('sub.info=')) { - const subtitleLink = vidplayLink.split('?sub.info=')[1].split('&')[0]; - const subtitlesFetch = await (await fetch(decodeURIComponent(subtitleLink))).json(); + while ((match = regex.exec(resp)) !== null) { + matches.push(match[1]); + } - const subtitles = subtitlesFetch.map(subtitle => ({ - file: subtitle.file, - lang: subtitle.label - })); - - return subtitles; - } + if (matches.length >= 2) { + let data_id_1 = matches[0]; + let data_id_2 = matches[1]; + return await episode(data_id_1, data_id_2, 'tv', s, e); + } else { + throw new Error("Failed to find two data-id values in response."); + } } \ No newline at end of file