├── .gitignore ├── eslint.config.js ├── src ├── providers │ ├── upcloud.ts │ ├── megacloudrabbitstream.ts │ ├── fmcloud.ts │ └── f2cloud.ts ├── main.ts ├── sources │ ├── viewvault.org.ts │ ├── flixhq.ts │ ├── myflixerz.ts │ ├── vidsrc.pro.ts │ ├── vidsrc.me.ts │ ├── embed.su.ts │ ├── vidsrc.cc.ts │ ├── vidsrc.ts │ ├── vidstream.to.ts │ ├── aniwave.ts │ └── watchseries.ts ├── utils.ts └── getkeys.ts ├── eslint.config.mjs ├── tsconfig.json ├── LICENSE ├── package.json ├── .github └── workflows │ └── main.yml ├── README.md └── dist └── keys.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import globals from "globals"; 2 | import pluginJs from "@eslint/js"; 3 | 4 | 5 | export default [ 6 | { languageOptions: { globals: globals.browser } }, 7 | pluginJs.configs.recommended, 8 | ]; 9 | 10 | -------------------------------------------------------------------------------- /src/providers/upcloud.ts: -------------------------------------------------------------------------------- 1 | import { Provider, Stream } from '../utils'; 2 | import RabbitStream from './rabbitstream.js' 3 | 4 | export const UpCloud: Provider = { 5 | ALT_HOSTS: [], 6 | async stream(url: string): Promise { 7 | const id = url.split("/").at(-1)!.split("?").at(0); 8 | return (await RabbitStream.stream(id)) as Stream; 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/providers/megacloudrabbitstream.ts: -------------------------------------------------------------------------------- 1 | import { Provider, Stream } from '../utils.js'; 2 | import RabbitStream from './rabbitstream.js' 3 | 4 | export const MegaCloudRabbitStream: Provider = { 5 | ALT_HOSTS: [], 6 | async stream(url: string): Promise { 7 | const id = url.split("/").at(-1)!.split("?").at(0); 8 | return await RabbitStream.stream(id, 1); 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | 2 | import eslint from '@eslint/js'; 3 | import tseslint from 'typescript-eslint'; 4 | 5 | let myrules = [{ 6 | rules: { 7 | "no-unused-vars": "off", 8 | "@typescript-eslint/no-unused-vars": ["error", { 9 | argsIgnorePattern: "^_", 10 | varsIgnorePattern: "^_", 11 | caughtErrorsIgnorePattern: "^_", 12 | }], 13 | }, 14 | }]; 15 | 16 | export default tseslint.config( 17 | eslint.configs.recommended, 18 | ...tseslint.configs.recommended, 19 | ...myrules 20 | ); 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2022", 4 | "esModuleInterop": true, 5 | "allowSyntheticDefaultImports": true, 6 | "target": "es6", 7 | "noImplicitAny": true, 8 | "moduleResolution": "node", 9 | "sourceMap": true, 10 | "outDir": "dist", 11 | "baseUrl": "src/types", 12 | "allowJs": true, 13 | "paths": { 14 | "*": [ 15 | "node_modules/*", 16 | "src/*" 17 | ] 18 | }, 19 | "lib": [ 20 | "es2021", 21 | "dom" 22 | ], 23 | "noUnusedLocals": false, 24 | "noUnusedParameters": false 25 | }, 26 | "include": [ 27 | "src/**/*" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /src/providers/fmcloud.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import { Provider, Stream } from '../utils'; 3 | 4 | const ALT_HOSTS: Array = []; 5 | async function stream(url: string): Promise { 6 | const resp: string = (await (await fetch(url)).text()); 7 | const reg: RegExp = new RegExp(/(.*?)<\/script>/gm); 8 | let script: string = reg.exec(resp.match(reg)!.at(-1)!)![1]; 9 | script = eval(script.replace('eval', '')); 10 | const sources: string = "{" + (/videop.setup\(\{(.*?)\}\);/gm).exec(script)![1] + "}"; 11 | const data: Stream = eval(`let s = ${sources}; s`); 12 | return data; 13 | } 14 | 15 | export const FMCloud: Provider = { stream, ALT_HOSTS }; 16 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { Aniwave } from './sources/aniwave.js'; 2 | import { Vidsrc } from './sources/vidsrc.js'; 3 | import { Watchseries } from './sources/watchseries.js'; 4 | import { FlixHQ } from './sources/flixhq.js'; 5 | import { Myflixerz } from './sources/myflixerz.js'; 6 | import { VidsrcPro } from './sources/vidsrc.pro.js'; 7 | import { VidStream } from './sources/vidstream.to.js'; 8 | import { VidsrcMe } from './sources/vidsrc.me.js'; 9 | import { VidsrcCC } from './sources/vidsrc.cc.js'; 10 | import { EmbedSu } from './sources/embed.su.js'; 11 | 12 | async function main() { 13 | 14 | // Last Edit 28/01/2025 15 | EmbedSu.test() 16 | 17 | // Not Maintained since 30/09/2024 18 | //FlixHQ.test(); 19 | //Myflixerz.test(); 20 | //VidsrcPro.test(); 21 | // sometimes fails due to cloudflare 22 | //VidsrcMe.test(); 23 | //VidStream.test(); 24 | //VidsrcCC.test(); 25 | 26 | // Dead since 26/08/2024 27 | //Watchseries.test(); 28 | //Vidsrc.test(); 29 | //Aniwave.test(); 30 | } 31 | 32 | main(); 33 | 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 xgampx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "scripts": { 4 | "build": "tsc", 5 | "start": "node dist/main.js", 6 | "keys": "node dist/getkeys.js", 7 | "lint": "eslint --ignore-pattern src/providers/rabbitstream.js src", 8 | "fix": "eslint --fix --ignore-pattern src/providers/rabbitstream.js src" 9 | }, 10 | "devDependencies": { 11 | "@eslint/js": "^9.9.1", 12 | "@types/eslint__js": "^8.42.3", 13 | "@typescript-eslint/eslint-plugin": "^8.2.0", 14 | "eslint": "^9.9.1", 15 | "lint": "^0.8.19", 16 | "typescript": "^5.5.4", 17 | "typescript-eslint": "^8.2.0" 18 | }, 19 | "dependencies": { 20 | "@babel/generator": "^7.25.5", 21 | "@babel/parser": "^7.25.4", 22 | "@babel/traverse": "^7.25.4", 23 | "@babel/types": "^7.25.4", 24 | "@types/babel__core": "^7.20.5", 25 | "@types/babel__traverse": "^7.20.6", 26 | "@types/node": "^22.5.0", 27 | "@types/node-fetch": "^2.6.11", 28 | "@types/puppeteer": "^5.4.7", 29 | "browser-env": "^3.3.0", 30 | "crypto-js": "^4.2.0", 31 | "node-fetch": "^3.3.2", 32 | "puppeteer": "^23.1.1", 33 | "puppeteer-extra": "^3.3.6", 34 | "puppeteer-extra-plugin-stealth": "^2.11.2", 35 | "webcrack": "^2.14.1" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Generate keys 2 | on: 3 | workflow_dispatch: 4 | jobs: 5 | installDependencies: 6 | name: Generate keys 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v3 10 | - name: Install Dependencies 11 | uses: actions/setup-node@v2 12 | env: 13 | PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: "true" 14 | with: 15 | args: install 16 | - name: npm ci and npm run keys 17 | run: | 18 | npm ci 19 | npm run keys 20 | env: 21 | CI: true 22 | - name: checking status 23 | run: git status 24 | - name: setting identity 25 | run: | 26 | git config --global user.email "rovelli.gianmarai@gmail.com" 27 | git config --global user.name "Gianmaria Rovelli" 28 | - name: stage keys file 29 | run: git add src/keys.json 30 | - name: commit keys 31 | run: git commit -am "Updating keys.json" || true 32 | - name: switching from HTTPS to SSH 33 | run: git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} 34 | - name: push code to main 35 | run: git push origin main || true 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VideoGatherer 2 | 3 | Scraping movies and tv series from: 4 | - embed.su (28/01/2025) 5 | - flixhq.to (not maintained since 30/09/2024) 6 | - myflixerz.to (not maintained since 30/09/2024) 7 | - vidsrc.net (not maintained since 30/09/2024) 8 | - vidsrc.pro (moved to embed.su) 9 | - vidsrc.cc (not maintained since 30/09/2024) 10 | - vidstream.to (not maintained since 30/09/2024) 11 | - vidsrc.to (not maintained since 30/09/2024) 12 | - aniwave.to (dead) 13 | - watchseriesx.to (dead) 14 | 15 | At the moment the purpose of this repository is to expose methods used 16 | to scrape websites. 17 | 18 | In the future it could be developed a user interface to allow regular users 19 | to easily watch movies/tv series. 20 | 21 | ### Read read read 22 | 23 | vidsrc.to, watchseriesx.to, aniwave.to are DOWN (26/08/2024, DD-MM-YYYY) 24 | The project keeps their scrapers as learning material, please do not open an ISSUE about this. 25 | 26 | ### How to install it 27 | 28 | ```sh 29 | git clone git@github.com:giammirove/videogatherer.git 30 | cd videogatherer 31 | npm i 32 | npm run build # to build 33 | npm run keys # to get the keys 34 | npm run start # to execute 35 | ``` 36 | 37 | ### How to run it 38 | 39 | ```sh 40 | npm run build # if not done yet 41 | npm run start 42 | ``` 43 | 44 | Examples of how to request an episode/movie can be found in the `test` function 45 | of each module in `src/sources`. 46 | 47 | ### What if it does not work 48 | 49 | Those website are not 100% stable, it is normal if they have downtime. 50 | 51 | What you can do is to manually open the browser and check whether the website 52 | is working correctly. 53 | If it is working, maybe the keys (see `dist/keys.json`) are changed. 54 | To fix that you can run 55 | ```sh 56 | npm run keys 57 | ``` 58 | Then retry ... :) 59 | 60 | If it still does not work .. well we tried folks. 61 | 62 | ### Note 63 | 64 | This project is intended as proof of concept, 65 | the distribution of program is intended for educational purposes ONLY. 66 | -------------------------------------------------------------------------------- /src/sources/viewvault.org.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import { Source, Stream, ServerListItem, try_stream, isJSON, log, error, debug } from '../utils.js'; 3 | 4 | type EpisodeJson = { 5 | link: string; 6 | } 7 | 8 | type MovieJson = { 9 | link: string; 10 | } 11 | 12 | const HOST = 'viewvault.org'; 13 | const ALT_HOSTS = [HOST]; 14 | const SERVERS: Array = [ 15 | ]; 16 | const ID = "FH"; 17 | 18 | async function episode(data_id: string, _server?: string): Promise { 19 | let url = `https://${HOST}/ajax/episode/servers/${data_id}`; 20 | const resp: string = (await (await fetch(url)).text()).replace(/\n/g, ''); 21 | const new_data_id = (new RegExp(`data-id="(.*?)".*title=".*?${_server}"`, 'g')).exec(resp)![1]; 22 | url = `https://${HOST}/ajax/episode/sources/${new_data_id}`; 23 | const json_data: EpisodeJson = await (await fetch(url)).json() as EpisodeJson; 24 | return await try_stream(SERVERS, _server, json_data.link); 25 | }; 26 | 27 | async function movie(id: string, _server?: string) { 28 | let movie_id = id.split("-").at(-1); 29 | let url = `https://${HOST}/ajax/episode/list/${movie_id}`; 30 | const resp = (await (await fetch(url)).text()).replace(/\n/g, ''); 31 | movie_id = (new RegExp(`data-linkid="(.*?)".*title="${_server}"`, 'gs')).exec(resp)![1]; 32 | url = `https://${HOST}/ajax/episode/sources/${movie_id}`; 33 | const json_data = await (await fetch(url)).json() as MovieJson; 34 | return await try_stream(SERVERS, _server, json_data.link); 35 | } 36 | 37 | async function tv(id: string, s: number = 1, e: number = 1, _server?: string) { 38 | const url = `https://${HOST}/episode/${id}/${s}-${e}`; 39 | const resp = await (await fetch(url)).text(); 40 | let data_id = (/data-id="(.*?)"/gm).exec(resp)![s]; 41 | const resp2 = await (await fetch(`https://${HOST}/ajax/season/episodes/${data_id}`)).text(); 42 | data_id = (/data-id="(.*?)"/gm).exec(resp2)![e]; 43 | return await episode(data_id, _server); 44 | } 45 | 46 | async function test() { 47 | try { 48 | const tests = [movie("watch-the-pastor-111166"), tv("watch-the-big-bang-theory-39508", 1, 1)]; 49 | const results = await Promise.all(tests); 50 | for (const r of results) { 51 | if (!isJSON(r)) 52 | throw `${JSON.stringify(r)} is not json`; 53 | debug(ID, JSON.stringify(r)); 54 | } 55 | log(ID, `${HOST} passed the tests`); 56 | } catch (e: unknown) { 57 | error(ID, `${HOST} failed the tests`, (e as Error)); 58 | } 59 | } 60 | 61 | export const FlixHQ: Source = { HOST, ALT_HOSTS, SERVERS, ID, movie, tv, test }; 62 | 63 | -------------------------------------------------------------------------------- /src/providers/f2cloud.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import { debug, mapp, reverse, subst_, subst, rc4, get_keys, dec_with_order, enc_with_order, get_encrypt_order, ScrapeConfig, Stream, Provider, TransformText } from '../utils.js'; 3 | 4 | type StreamJson = { 5 | result: string; 6 | } 7 | 8 | // alternative hosts 9 | const HOST = "vid2v11.site"; 10 | const ALT_HOSTS = [HOST, "vid2faf.site"]; 11 | const ID = "F2"; 12 | 13 | const SCRAPE_CONFIG: ScrapeConfig = { 14 | ID: ID, 15 | USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36, Playstation', 16 | EXPECTED_KEYS: 19, 17 | INJECT_URLS: [ 18 | ], 19 | // input of encrypt function 20 | ENTRY: new RegExp(`https://.*?/e/(.*?)\\?`.replace(/\//g, '/')), 21 | // output of encrypt function 22 | OUT: new RegExp(`https://.*?/mediainfo/(.*?)[&\\?]`.replace(/\//g, '/')), 23 | INIT_URL: `https://${HOST}/`, 24 | BTN_ID: "", 25 | } 26 | 27 | function enc(inp: string): string { 28 | const keys: Array = get_keys(ALT_HOSTS); 29 | const order: Array = get_encrypt_order(ALT_HOSTS); 30 | if (order.length > 0) 31 | return enc_with_order(keys, order, inp); 32 | let a: string = mapp(inp, keys[0], keys[1]); 33 | a = reverse(a); 34 | a = rc4(keys[2], a); 35 | a = subst(a); 36 | a = reverse(a); 37 | a = mapp(a, keys[3], keys[4]); 38 | a = rc4(keys[5], a); 39 | a = subst(a); 40 | a = rc4(keys[6], a); 41 | a = subst(a); 42 | a = reverse(a); 43 | a = mapp(a, keys[7], keys[8]); 44 | a = subst(a); 45 | return a; 46 | } 47 | 48 | function dec(inp: string): string { 49 | const keys: Array = get_keys(ALT_HOSTS); 50 | const order: Array = get_encrypt_order(ALT_HOSTS); 51 | if (order.length > 0) 52 | return dec_with_order(keys, order, inp); 53 | let a: string = subst_(inp); 54 | a = mapp(a, keys[8], keys[7]); 55 | a = reverse(a); 56 | a = subst_(a); 57 | a = rc4(keys[6], a); 58 | a = subst_(a); 59 | a = rc4(keys[5], a); 60 | a = mapp(a, keys[4], keys[3]); 61 | a = reverse(a); 62 | a = subst_(a); 63 | a = rc4(keys[2], a); 64 | a = reverse(a); 65 | a = mapp(a, keys[1], keys[0]); 66 | return a; 67 | } 68 | 69 | async function stream(iurl: string): Promise { 70 | const url: URL = new URL(iurl); 71 | const embed_id: string = url.pathname.split("/")[2]; 72 | debug(ID, embed_id); 73 | const mediainfo_url: string = `https://${url.host}/mediainfo/${enc(embed_id)}${url.search}&ads=0`; 74 | debug(ID, mediainfo_url); 75 | const resp: StreamJson = await (await fetch(mediainfo_url)).json() as StreamJson; 76 | debug(ID, JSON.stringify(resp)); 77 | const playlist = dec(resp.result)?.replace(/\\\//g, "/"); 78 | debug(ID, playlist); 79 | return JSON.parse(playlist) as Stream; 80 | } 81 | 82 | export const F2Cloud: Provider = { SCRAPE_CONFIG, ALT_HOSTS, stream }; 83 | 84 | -------------------------------------------------------------------------------- /src/sources/flixhq.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import { Source, Stream, ServerListItem, try_stream, isJSON, log, error, debug } from '../utils.js'; 3 | import { UpCloud } from '../providers/upcloud.js'; 4 | 5 | type EpisodeJson = { 6 | link: string; 7 | } 8 | 9 | type MovieJson = { 10 | link: string; 11 | } 12 | 13 | const HOST = 'flixhq.to'; 14 | const ALT_HOSTS = [HOST]; 15 | const SERVER_UPCLOUD: string = 'UpCloud'; 16 | const SERVER_VIDCLOUD: string = 'Vidcloud'; 17 | const SERVER_UPSTREAM: string = 'Upstream'; 18 | const SERVERS: Array = [ 19 | { id: SERVER_UPCLOUD, handler: UpCloud }, 20 | { id: SERVER_VIDCLOUD, handler: UpCloud }, 21 | { id: SERVER_UPSTREAM, handler: UpCloud }, 22 | ]; 23 | const ID = "FH"; 24 | 25 | async function episode(data_id: string, server = SERVER_UPCLOUD): Promise { 26 | let url = `https://${HOST}/ajax/episode/servers/${data_id}`; 27 | const resp: string = (await (await fetch(url)).text()).replace(/\n/g, ''); 28 | const new_data_id = (new RegExp(`data-id="(.*?)".*title=".*?${server}"`, 'g')).exec(resp)![1]; 29 | url = `https://${HOST}/ajax/episode/sources/${new_data_id}`; 30 | const json_data: EpisodeJson = await (await fetch(url)).json() as EpisodeJson; 31 | return await try_stream(SERVERS, server, json_data.link); 32 | }; 33 | 34 | async function movie(id: string, server = SERVER_UPCLOUD) { 35 | let movie_id = id.split("-").at(-1); 36 | let url = `https://${HOST}/ajax/episode/list/${movie_id}`; 37 | const resp = (await (await fetch(url)).text()).replace(/\n/g, ''); 38 | movie_id = (new RegExp(`data-linkid="(.*?)".*title="${server}"`, 'gs')).exec(resp)![1]; 39 | url = `https://${HOST}/ajax/episode/sources/${movie_id}`; 40 | const json_data = await (await fetch(url)).json() as MovieJson; 41 | return await try_stream(SERVERS, server, json_data.link); 42 | } 43 | 44 | async function tv(id: string, s: number = 1, e: number = 1, server = SERVER_UPCLOUD) { 45 | const tv_id = id.split("-").at(-1); 46 | let resp = await (await fetch(`https://${HOST}/ajax/season/list/${tv_id}`)).text(); 47 | let data_id = (/data-id="(.*?)"/gm).exec(resp)![s]; 48 | resp = await (await fetch(`https://${HOST}/ajax/season/episodes/${data_id}`)).text(); 49 | data_id = (/data-id="(.*?)"/gm).exec(resp)![e]; 50 | return await episode(data_id, server); 51 | } 52 | 53 | async function test() { 54 | try { 55 | const tests = [movie("watch-the-pastor-111166"), tv("watch-the-big-bang-theory-39508", 1, 1)]; 56 | const results = await Promise.all(tests); 57 | for (const r of results) { 58 | if (!isJSON(r)) 59 | throw `${JSON.stringify(r)} is not json`; 60 | debug(ID, JSON.stringify(r)); 61 | } 62 | log(ID, `${HOST} passed the tests`); 63 | } catch (e: unknown) { 64 | error(ID, `${HOST} failed the tests`, (e as Error)); 65 | } 66 | } 67 | 68 | export const FlixHQ: Source = { HOST, ALT_HOSTS, SERVERS, ID, movie, tv, test }; 69 | 70 | -------------------------------------------------------------------------------- /src/sources/myflixerz.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import { error, debug, isJSON, log, Source, try_stream } from '../utils.js'; 3 | import { MegaCloudRabbitStream } from '../providers/megacloudrabbitstream.js'; 4 | import { UpCloud } from '../providers/upcloud.js'; 5 | 6 | type EpisodeJson = { 7 | link: string; 8 | } 9 | 10 | type MovieJson = { 11 | link: string; 12 | } 13 | 14 | const HOST = 'myflixerz.to'; 15 | const ALT_HOSTS = [HOST]; 16 | const SERVER_UPCLOUD = 'UpCloud'; 17 | const SERVER_MEGACLOUD = 'MegaCloud'; 18 | const SERVER_UPSTREAM = 'Upstream'; 19 | const SERVERS = [ 20 | { id: SERVER_UPCLOUD, handler: MegaCloudRabbitStream }, 21 | { id: SERVER_MEGACLOUD, handler: MegaCloudRabbitStream }, 22 | { id: SERVER_UPSTREAM, handler: UpCloud }, 23 | ] 24 | const ID = "FE"; 25 | 26 | async function episode(data_id: string, server: string = SERVER_UPCLOUD) { 27 | let url = `https://${HOST}/ajax/episode/servers/${data_id}`; 28 | const resp = (await (await fetch(url)).text()).replace(/\n/g, ''); 29 | const new_data_id = (new RegExp(`data-id="(.*?)".*title=".*?${server}"`, 'gms')).exec(resp)![1]; 30 | url = `https://${HOST}/ajax/episode/sources/${new_data_id}`; 31 | const json_data = await (await fetch(url)).json() as EpisodeJson; 32 | return await try_stream(SERVERS, server, json_data.link); 33 | } 34 | 35 | async function movie(id: string, server: string = SERVER_UPCLOUD) { 36 | let movie_id = id.split("-").at(-1); 37 | let url = `https://${HOST}/ajax/episode/list/${movie_id}`; 38 | const resp = (await (await fetch(url)).text()).replace(/\n/g, ''); 39 | movie_id = (new RegExp(`data-linkid="(.*?)".*title="${server}"`, 'gs')).exec(resp)![1]; 40 | url = `https://${HOST}/ajax/episode/sources/${movie_id}`; 41 | const json_data = await (await fetch(url)).json() as MovieJson; 42 | return await try_stream(SERVERS, server, json_data.link); 43 | } 44 | 45 | async function tv(id: string, s: number = 1, e: number = 1, server: string = SERVER_UPCLOUD) { 46 | const tv_id = id.split("-").at(-1)!.split(".").at(0); 47 | let resp = await (await fetch(`https://${HOST}/ajax/season/list/${tv_id}`)).text(); 48 | let data_id = (/data-id="(.*?)"/gm).exec(resp)![s]; 49 | resp = await (await fetch(`https://${HOST}/ajax/season/episodes/${data_id}`)).text(); 50 | data_id = (/data-id="(.*?)"/gm).exec(resp)![e]; 51 | return await episode(data_id, server); 52 | } 53 | 54 | async function test() { 55 | try { 56 | const tests = [movie("watch-the-pastor-111166"), tv("the-big-bang-theory-39508.4857451", 1, 1, SERVER_UPSTREAM)]; 57 | const results = await Promise.all(tests); 58 | for (const r of results) { 59 | if (!isJSON(r)) 60 | throw `${JSON.stringify(r)} is not json`; 61 | debug(ID, JSON.stringify(r)); 62 | } 63 | log(ID, `${HOST} passed the tests`); 64 | } catch (e: unknown) { 65 | error(ID, `${HOST} failed the tests`, (e as Error)); 66 | } 67 | } 68 | 69 | export const Myflixerz: Source = { HOST, ALT_HOSTS, SERVERS, ID, movie, tv, test }; 70 | 71 | -------------------------------------------------------------------------------- /src/sources/vidsrc.pro.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import { mapp, reverse, rc4, subst, subst_, debug, get_keys, error, log, isJSON, get_encrypt_order, enc_with_order, dec_with_order, ScrapeConfig, Stream, Source, ServerListItem, TransformText } from '../utils.js'; 3 | 4 | const HOST: string = 'vidsrc.pro'; 5 | const ALT_HOSTS: Array = [HOST]; 6 | const ID: string = 'VSP'; 7 | 8 | type EpisodeJson = { 9 | source: string, 10 | format: string, 11 | subtitles: [ 12 | { label: string, file: string } 13 | ] 14 | } 15 | type SourceJson = { 16 | result: { url: string } 17 | } 18 | type VConfig = { 19 | title: string, 20 | server: string, 21 | hash: string, 22 | referer: string, 23 | xid: string, 24 | episodeId: string, 25 | captchaKey: string, 26 | v: string, 27 | uwuId: string, 28 | } 29 | type ServerVidSrc = { 30 | name: string, 31 | hash: string 32 | } 33 | 34 | const SCRAPE_CONFIG: ScrapeConfig = { 35 | ID: ID, 36 | USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36;', 37 | EXPECTED_KEYS: 0, 38 | INJECT_URLS: [ 39 | ], 40 | // input of encrypt function 41 | ENTRY: new RegExp(''), 42 | // output of encrypt function 43 | OUT: new RegExp(''), 44 | INIT_URL: `https://${HOST}/embed/movie/385687`, 45 | BTN_ID: "", 46 | MAX_TIMEOUT: 2500 47 | } 48 | 49 | const SERVERS: Array = [ 50 | ]; 51 | 52 | const HEADERS = { 53 | Referer: `https://${HOST}` 54 | } 55 | 56 | function dec(inp: string): string { 57 | return atob(inp.split("").reverse().join("")); 58 | } 59 | 60 | async function episode(hash: string): Promise { 61 | const servers: Array = JSON.parse(dec(hash)); 62 | const server: ServerVidSrc = servers[0]; 63 | const url: string = `https://vidsrc.pro/api/e/${server.hash}`; 64 | debug(ID, url); 65 | const resp = await (await fetch(url)).json() as EpisodeJson; 66 | return { stream: resp.source, subtitles: resp.subtitles } as Stream; 67 | } 68 | 69 | async function movie(id: string): Promise { 70 | const url = `https://${HOST}/embed/movie/${id}`; 71 | const resp = (await (await fetch(url, { headers: HEADERS })).text()).replace(/ /g, '').replace(/\n/g, ''); 72 | const config: VConfig = JSON.parse((/window.vConfig=({.*?})<\/script>/g).exec(resp)![1]) as VConfig; 73 | debug(ID, config.hash); 74 | return await episode(config.hash); 75 | } 76 | 77 | async function tv(id: string, s: number = 1, e: number = 1): Promise { 78 | const url = `https://${HOST}/embed/tv/${id}/${s}/${e}`; 79 | const resp = (await (await fetch(url, { headers: HEADERS })).text()).replace(/ /g, '').replace(/\n/g, ''); 80 | const config: VConfig = JSON.parse((/window.vConfig=({.*?})<\/script>/g).exec(resp)![1]) as VConfig; 81 | debug(ID, config.hash); 82 | return await episode(config.hash); 83 | } 84 | 85 | async function test() { 86 | try { 87 | const tests: Array> = [movie("385687"), tv("tt0944947", 1, 1), tv("tt1190634", 1, 1)]; 88 | const results = await Promise.all(tests); 89 | for (const r of results) { 90 | if (!isJSON(r)) 91 | throw `${JSON.stringify(r)} is not json`; 92 | debug(ID, JSON.stringify(r)); 93 | } 94 | log(ID, `${HOST} passed the tests`); 95 | } catch (e: unknown) { 96 | error(ID, `${HOST} failed the tests`, (e as Error)); 97 | } 98 | } 99 | 100 | export const VidsrcPro: Source = { HOST, ALT_HOSTS, SERVERS, ID, movie, tv, test, SCRAPE_CONFIG }; 101 | -------------------------------------------------------------------------------- /src/sources/vidsrc.me.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import { webcrack } from 'webcrack'; 3 | import vm from 'node:vm'; 4 | 5 | import { Source, Stream, ServerListItem, isJSON, log, error, debug, NO_STREAM_ERROR } from '../utils.js'; 6 | import { RequestInit } from 'node-fetch'; 7 | 8 | 9 | 10 | const HOST = 'vidsrc.xyz'; 11 | const ALT_HOSTS = [HOST, 'vidsrc.me', 'vidsrc.net']; 12 | const SERVERS: Array = [ 13 | ]; 14 | const ID = "VDM"; 15 | const REFERER = `http://${HOST}`; 16 | const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'; 17 | let js_context = vm.createContext(globalThis); 18 | 19 | const sleep = (ms: number) => new Promise(r => setTimeout(r, ms)); 20 | 21 | async function fetchReferer(url: URL | string, args: RequestInit = { headers: {} }) { 22 | if (args.headers == undefined) 23 | args.headers = {}; 24 | if ((args.headers as Record)['Referer'] == undefined && (args.headers as Record)['Referer'] != "") 25 | (args.headers as Record)['Referer'] = REFERER; 26 | (args.headers as Record)['User-Agent'] = USER_AGENT; 27 | return fetch(url, args); 28 | } 29 | 30 | async function episode(data_id: string, _server?: string): Promise { 31 | const url = `https://${HOST}/embed/${data_id}`; 32 | debug(ID, url); 33 | const res = await (await fetchReferer(url)).text(); 34 | let script = ""; 35 | let enc_url = ""; 36 | let script_id = ""; 37 | for (let i = 0; i < 10; i++) { 38 | try { 39 | const url2 = 'https:' + (/id="player_iframe" src="(.*?)"/gm).exec(res)[1].trim(); 40 | const res2 = await (await fetchReferer(url2)).text(); 41 | const host = (new URL(url2)).host; 42 | const srcrcpLink = /src:\s*'(.*?)'/gm.exec(res2)![1]; 43 | const url3 = `https://${host}${srcrcpLink}`; 44 | // sometimes it returns 404 45 | const res3 = await (await fetch(url3)).text(); 46 | enc_url = (/