├── .gitignore ├── README.md ├── __tests__ ├── embed-su.ts ├── vidlinkpro.ts └── vidsrcrip.ts ├── package.json ├── src ├── embed-su.ts ├── index.ts ├── vidlinkpro.ts ├── vidsrcicu.ts └── vidsrcrip.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | bun.lockb 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vidsrc-bypass 2 | 3 | vidsrc-bypass is a TypeScript utility library for interacting with vidsrc and embed.su APIs. It provides functions to fetch video details, stream URLs, and perform other related operations. 4 | 5 | ## Features 6 | 7 | - Fetch video details from embed.su 8 | - Get stream URLs from embed.su 9 | - Generate VRF (Verification) tokens for vidsrc.rip 10 | - Fetch video configurations from vidsrc.rip 11 | - Get stream URLs from vidsrc.rip 12 | - TypeScript support with type definitions 13 | - Get stream URLs from vidlink.pro 14 | - Get stream URLs and Manga from vidsrc.icu 15 | 16 | ## Installation 17 | 18 | To install the dependencies, run: 19 | 20 | ```bash 21 | npm install 22 | ``` 23 | 24 | ## Usage 25 | 26 | This library exports functions for both embed.su, vidsrc.rip and vidlink.pro. Here's a brief overview of the main functions: 27 | 28 | ### embed.su 29 | 30 | ```typescript 31 | import { getEmbedSuVideo, getEmbedSuStreamUrl } from 'vidsrc-bypass'; 32 | 33 | // Get video details (TMDB ID) 34 | const movieDetails = await getEmbedSuVideo(310131); // For movies 35 | const tvShowDetails = await getEmbedSuVideo(48891, 1, 1); // For TV shows (series ID, season, episode) 36 | 37 | // Get stream URL 38 | const streamDetails = await getEmbedSuStreamUrl(movieDetails.servers[0].hash); 39 | ``` 40 | 41 | ### vidsrc.rip 42 | 43 | ```typescript 44 | 45 | import { getVidSrcRipVideo, getVidSrcRipStreamUrl, generateVRF } from 'vidsrc-bypass'; 46 | 47 | // Get video configuration (TMDB/IMDB ID) 48 | const videoConfig = await getVidSrcRipVideo('872585'); 49 | 50 | // Get stream URL 51 | const streamUrl = await getVidSrcRipStreamUrl('flixhq', '872585'); 52 | ``` 53 | 54 | ### vidlink.pro 55 | 56 | ```typescript 57 | import { getVidLinkProVideo } from 'vidsrc-bypass'; 58 | 59 | // For movies (TMDB ID, type) 60 | const movieVideo = await getVidLinkProVideo({ id: "786892", type: "movie" }); 61 | // For TV shows (TMDB series ID, season, episode, type) 62 | const tvShowVideo = await getVidLinkProVideo({ id: "48891", season: 1, episode: 1, type: "tv"}); 63 | // For anime (MAL ID,episode, type, dub/sub, fallback) 64 | const animeVideo = getVidLinkProVideo({ id: "5", episode: 1, type: "anime", dub: true, fallback: true }); 65 | ``` 66 | 67 | ## License 68 | 69 | This project is open source. However, please note that it is intended for educational purposes only. Ensure you comply with all relevant laws and terms of service when using this library. 70 | 71 | ## Disclaimer 72 | 73 | This project is not affiliated with, endorsed by, or connected to vidsrc, embed.su, or any related services. It is an independent tool created for educational purposes. Use responsibly and at your own risk. -------------------------------------------------------------------------------- /__tests__/embed-su.ts: -------------------------------------------------------------------------------- 1 | import { getVideo, getStreamUrl, addCount } from "../src/embed-su"; 2 | 3 | async function runTests() { 4 | console.log("Testing embed-su.ts"); 5 | 6 | console.log("\nTesting getVideo:"); 7 | let movieConfig; 8 | let tvShowConfig; 9 | try { 10 | // Test for a movie 11 | movieConfig = await getVideo(310131); 12 | console.log("Movie config:", movieConfig); 13 | 14 | // Test for a TV show 15 | tvShowConfig = await getVideo(48891, 1, 1); 16 | console.log("TV Show config:", tvShowConfig); 17 | } catch (error) { 18 | console.error("Error in getVideo:", error); 19 | } 20 | 21 | console.log("\nTesting getStreamUrl:"); 22 | try { 23 | const streamDetails = await getStreamUrl(movieConfig.servers[0].hash); 24 | console.log("Stream details:", streamDetails); 25 | } catch (error) { 26 | console.error("Error in getStreamUrl:", error); 27 | } 28 | 29 | console.log("\nTesting addCount:"); 30 | try { 31 | await addCount("sheeeesh", "imasigma", "spicycontentinyourdmsgrrrr"); 32 | console.log("addCount completed successfully"); 33 | } catch (error) { 34 | console.error("Error in addCount:", error); 35 | } 36 | } 37 | 38 | runTests(); 39 | -------------------------------------------------------------------------------- /__tests__/vidlinkpro.ts: -------------------------------------------------------------------------------- 1 | import { getVideo } from "../src/vidlinkpro"; 2 | 3 | async function runTests() { 4 | console.log("Testing vidlinkpro.ts"); 5 | 6 | console.log("\nTesting getVideo for a movie:"); 7 | try { 8 | const movieConfig = await getVideo({ id: "786892", type: "movie" }); 9 | console.log("Movie config:", movieConfig); 10 | } catch (error) { 11 | console.error("Error in getVideo for movie:", error); 12 | } 13 | 14 | console.log("\nTesting getVideo for a TV show:"); 15 | try { 16 | const tvShowConfig = await getVideo({ id: "48891", season: 1, episode: 1, type: "tv"}); 17 | console.log("TV Show config:", tvShowConfig); 18 | } catch (error) { 19 | console.error("Error in getVideo for TV show:", error); 20 | } 21 | 22 | // Kinda lazy to test anime since the demo on vidlinkpro website doesn't work, but it should work 23 | // And it seems like the anime endpoint doesn't work because of a cors issue, vidlink.pro needs to fix it 24 | /* 25 | console.log("\nTesting getVideo for an anime:"); 26 | try { 27 | const animeConfig = await getVideo({ id: "5", episode: 1, type: "anime", dub: true, fallback: true }); 28 | console.log("Anime config:", animeConfig); 29 | } catch (error) { 30 | console.error("Error in getVideo for anime:", error); 31 | } 32 | */ 33 | } 34 | 35 | runTests(); -------------------------------------------------------------------------------- /__tests__/vidsrcrip.ts: -------------------------------------------------------------------------------- 1 | import { getVideo, getStreamUrl, generateVRF } from "../src/vidsrcrip"; // generateVRF is not exported since it's useless with the current implementation 2 | 3 | async function runTests() { 4 | console.log("Testing vidsrcrip.ts"); 5 | 6 | console.log("\nTesting getVideo:"); 7 | try { 8 | const videoConfig = await getVideo("872585"); 9 | console.log("Video config:", videoConfig); 10 | } catch (error) { 11 | console.error("Error in getVideo:", error); 12 | } 13 | 14 | // Kinda lazy to test tv shows since the demo on vidsrc website doesn't work, but it should work 15 | 16 | console.log("\nTesting getStreamUrl:"); 17 | try { 18 | const streamUrl = await getStreamUrl("flixhq", "872585"); 19 | console.log("Stream URL:", streamUrl); 20 | } catch (error) { 21 | console.error("Error in getStreamUrl:", error); 22 | } 23 | 24 | console.log("\nTesting generateVRF:"); 25 | const key = "testkey"; 26 | const message = "/api/source/flixhq/299536"; 27 | const vrf = generateVRF(key, message); 28 | console.log("Generated VRF:", vrf); 29 | } 30 | 31 | runTests(); 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vidsrc-utils", 3 | "version": "1.0.0", 4 | "description": "Utility functions for vidsrc and embed.su", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "exports": { 8 | ".": "./dist/index.js", 9 | "./embed-su": "./dist/embed-su.js", 10 | "./vidsrcrip": "./dist/vidsrcrip.js" 11 | }, 12 | "scripts": { 13 | "build": "tsc", 14 | "prepublishOnly": "npm run build" 15 | }, 16 | "module": "index.ts", 17 | "type": "module", 18 | "devDependencies": { 19 | "@types/bun": "latest" 20 | }, 21 | "peerDependencies": { 22 | "typescript": "^5.6.3" 23 | }, 24 | "dependencies": { 25 | "@types/crypto-js": "^4.2.2", 26 | "@types/node": "^22.7.5", 27 | "crypto-js": "^4.2.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/embed-su.ts: -------------------------------------------------------------------------------- 1 | interface VideoDetails { 2 | title: string; 3 | server: string; 4 | ref: string; 5 | xid: string; 6 | uwuId: string; // useless field, it's his ads script url. If you want to use it, use an atob() function to decode it. 7 | episodeId: string; 8 | hash: string; 9 | poster: string; 10 | servers?: Server[]; 11 | seasons?: Season[]; 12 | } 13 | 14 | interface Season { 15 | id: string; 16 | seasonNumber: string; 17 | episodes: Episode[]; 18 | } 19 | 20 | interface Episode { 21 | id: string; 22 | episodeNumber: string; 23 | title: string; 24 | } 25 | 26 | interface Server { 27 | name: string; 28 | hash: string; 29 | } 30 | 31 | const API_URL = "https://embed.su"; 32 | 33 | /* 34 | * Get the video details 35 | * @param id TMDB movie or TV show id 36 | * @param season The season number (for TV shows) 37 | * @param episode The episode number (for TV shows) 38 | * @returns The video details 39 | */ 40 | async function getVideo( 41 | id: number, 42 | season?: number, 43 | episode?: number 44 | ): Promise { 45 | let url: string; 46 | if (season !== undefined && episode !== undefined) { 47 | url = `${API_URL}/embed/tv/${id}/${season}/${episode}`; 48 | } else { 49 | url = `${API_URL}/embed/movie/${id}`; 50 | } 51 | 52 | const response: Response = await fetch(url); 53 | if (!response.ok) { 54 | console.error("Error fetching video details:", response.statusText); 55 | return; 56 | } 57 | const html = await response.text(); 58 | const match = html.match(/window\.vConfig = JSON\.parse\(atob\(`(.+?)`\)\)/); 59 | 60 | if (match && match[1]) { 61 | const decodedData: VideoDetails = JSON.parse( 62 | Buffer.from(match[1], "base64").toString() 63 | ); 64 | 65 | let firstDecode = atob(decodedData.hash).split(".").map(item => { return item.split("").reverse().join("")}) 66 | let secondDecode = JSON.parse(atob(firstDecode.join("").split("").reverse().join(""))) 67 | const servers = secondDecode.map((server: Server) => { return { name: server.name, hash: server.hash }}) 68 | 69 | return { 70 | ...decodedData, 71 | servers: servers, 72 | }; 73 | } 74 | console.error("Unable to extract video details"); 75 | } 76 | 77 | interface StreamDetails { 78 | source: string; 79 | subtitles: Subtitle[]; 80 | skips: any[]; // Too lazy to check a film / series with skips ngl 81 | format: string; 82 | } 83 | 84 | interface Subtitle { 85 | label: string; 86 | file: string; 87 | } 88 | 89 | /* 90 | * Get the stream URL 91 | * @param hash The server hash, not the video hash 92 | * @returns The stream URL 93 | */ 94 | async function getStreamUrl(hash: string): Promise { 95 | const url = `${API_URL}/api/e/${hash}`; 96 | 97 | const response: Response = await fetch(url); 98 | const data = await response.json(); 99 | if (response.status === 404) { 100 | console.error("Error fetching stream details:", data.error); 101 | } 102 | 103 | return { 104 | source: data.source, 105 | subtitles: data.subtitles, 106 | skips: data.skips, 107 | format: data.format, 108 | }; 109 | } 110 | 111 | // because why not even tho it's useless, it's just a count 112 | function addCount(player: string, referer: string, title: string) { 113 | const url = "https://pixel.embed.su/count"; 114 | 115 | const params = new URLSearchParams({ 116 | p: player, 117 | r: referer, 118 | t: title, 119 | }); 120 | 121 | fetch(url, { 122 | method: "POST", 123 | body: params, 124 | }).catch((error) => { 125 | console.error("Error adding count:", error); 126 | }); 127 | } 128 | 129 | export { getVideo, getStreamUrl, addCount }; 130 | export type { VideoDetails, StreamDetails, Subtitle }; 131 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { getStreamUrl as getEmbedSuStreamUrl, getVideo as getEmbedSuVideo } from './embed-su'; 2 | export { getStreamUrl as getVidSrcRipStreamUrl, getVideo as getVidSrcRipVideo } from './vidsrcrip'; 3 | export { getVideo as getVidLinkProVideo } from './vidlinkpro'; 4 | export { getData as getVidSrcIcuData } from './vidsrcicu'; 5 | export type { StreamDetails, Subtitle, VideoDetails } from './embed-su'; 6 | export type { Stream, VideoConfig } from './vidsrcrip'; 7 | export type { Caption, EncryptedData, Stream as VidLinkStream, Video, VideoParams, AnimeParams as VidLinkAnimeParams, MovieParams as VidLinkMovieParams, TVParams as VidLinkTVParams } from './vidlinkpro'; 8 | export type { Anime, AnimeParams as VidSrcIcuAnimeParams, Manga, MangaParams as VidSrcIcuMangaParams } from './vidsrcicu'; 9 | // don't want to test the package so if it doesn't work with javascript, it's not my problem 10 | // if you're using this it means you're a big boy and you know what you're doing + you're using typescript 11 | 12 | -------------------------------------------------------------------------------- /src/vidlinkpro.ts: -------------------------------------------------------------------------------- 1 | import { 2 | randomBytes, 3 | createDecipheriv, 4 | createCipheriv, 5 | pbkdf2Sync, 6 | } from "crypto"; 7 | 8 | interface EncryptedData { 9 | ct: string; 10 | iv: string; 11 | s: string; 12 | } 13 | 14 | interface Video { 15 | sourceID: string; 16 | stream: Stream; 17 | } 18 | 19 | interface Stream { 20 | id: string; 21 | type: string; 22 | playlist: string; 23 | flags: string[]; 24 | captions: Caption[]; 25 | } 26 | 27 | interface Caption { 28 | id: string; 29 | url: string; 30 | language: string; // I'm just too lazy to write all languages in an enum here ngl 31 | type: string; // could use an enum here but idk what the possible values are 32 | hasCorsRestrictions: boolean; 33 | } 34 | 35 | 36 | const API_URL = "https://vidlink.pro/api/b"; 37 | const keyHex: string = 38 | "2de6e6ea13a9df9503b11a6117fd7e51941e04a0c223dfeacfe8a1dbb6c52783"; 39 | // const keyClearKey: string = "1c80ed144253e87742a9d4563b8b650bbe8bd41729d31f112e90bc9b0458f122"; // Named it clear key because it's looking like widevine clear key 40 | const algo: string = "aes-256-cbc"; 41 | 42 | type MovieParams = { 43 | type: 'movie'; 44 | id: string; 45 | }; 46 | 47 | type TVParams = { 48 | type: 'tv'; 49 | id: string; 50 | season: number; 51 | episode: number; 52 | }; 53 | 54 | type AnimeParams = { 55 | type: 'anime'; 56 | id: string; 57 | episode: number; 58 | dub?: boolean; 59 | fallback?: boolean; 60 | }; 61 | 62 | type VideoParams = MovieParams | TVParams | AnimeParams; 63 | 64 | async function getVideo(params: VideoParams): Promise