added 3eyeddraven, cinemaarmy, movenerds, thugtv, vidy

This commit is contained in:
2026-10-11 16:04:29 -07:00
parent f3aa9fe7c7
commit 5e0a388056
10 changed files with 1230 additions and 12 deletions

441
package-lock.json generated
View File

@@ -1,17 +1,353 @@
{
"name": "@vyla-entertainment/sdk",
"version": "1.2.0",
"version": "1.15.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@vyla-entertainment/sdk",
"version": "1.2.0",
"version": "1.15.0",
"license": "CC-BY-NC-4.0",
"dependencies": {
"node-tls-client": "^2.1.0"
},
"devDependencies": {
"dotenv": "^17.4.2"
}
},
"node_modules/@napi-rs/nice": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz",
"integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
},
"optionalDependencies": {
"@napi-rs/nice-android-arm-eabi": "1.1.1",
"@napi-rs/nice-android-arm64": "1.1.1",
"@napi-rs/nice-darwin-arm64": "1.1.1",
"@napi-rs/nice-darwin-x64": "1.1.1",
"@napi-rs/nice-freebsd-x64": "1.1.1",
"@napi-rs/nice-linux-arm-gnueabihf": "1.1.1",
"@napi-rs/nice-linux-arm64-gnu": "1.1.1",
"@napi-rs/nice-linux-arm64-musl": "1.1.1",
"@napi-rs/nice-linux-ppc64-gnu": "1.1.1",
"@napi-rs/nice-linux-riscv64-gnu": "1.1.1",
"@napi-rs/nice-linux-s390x-gnu": "1.1.1",
"@napi-rs/nice-linux-x64-gnu": "1.1.1",
"@napi-rs/nice-linux-x64-musl": "1.1.1",
"@napi-rs/nice-openharmony-arm64": "1.1.1",
"@napi-rs/nice-win32-arm64-msvc": "1.1.1",
"@napi-rs/nice-win32-ia32-msvc": "1.1.1",
"@napi-rs/nice-win32-x64-msvc": "1.1.1"
}
},
"node_modules/@napi-rs/nice-android-arm-eabi": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz",
"integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-android-arm64": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz",
"integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-darwin-arm64": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz",
"integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-darwin-x64": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz",
"integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-freebsd-x64": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz",
"integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-linux-arm-gnueabihf": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz",
"integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-linux-arm64-gnu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz",
"integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-linux-arm64-musl": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz",
"integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-linux-ppc64-gnu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz",
"integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==",
"cpu": [
"ppc64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-linux-riscv64-gnu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz",
"integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==",
"cpu": [
"riscv64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-linux-s390x-gnu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz",
"integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==",
"cpu": [
"s390x"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-linux-x64-gnu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz",
"integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-linux-x64-musl": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz",
"integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-openharmony-arm64": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz",
"integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-win32-arm64-msvc": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz",
"integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-win32-ia32-msvc": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz",
"integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@napi-rs/nice-win32-x64-msvc": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz",
"integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/cookie": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie-parser": {
"version": "1.4.7",
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
"integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
"license": "MIT",
"dependencies": {
"cookie": "0.7.2",
"cookie-signature": "1.0.6"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT"
},
"node_modules/dotenv": {
"version": "17.4.2",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
@@ -24,6 +360,107 @@
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/koffi": {
"version": "2.16.3",
"resolved": "https://registry.npmjs.org/koffi/-/koffi-2.16.3.tgz",
"integrity": "sha512-E9y1AsgYGlaxMhcZzHr8y96QF2U5XzA12GGVAfbWqIubTwPNMXQarfBzePNXHe0xtIEtNd6ifAv3GAKYGUeBAQ==",
"hasInstallScript": true,
"license": "MIT",
"funding": {
"url": "https://liberapay.com/Koromix"
}
},
"node_modules/node-tls-client": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/node-tls-client/-/node-tls-client-2.1.0.tgz",
"integrity": "sha512-b1Y2WFdQ7BJXa5CT6qRafCFeaNiTsZP+UFqNy+8hrHExlPHe3ccEtFkKt3WDGzGIfNvb4Ws9EEQmzFS9Jztisg==",
"license": "GPL-3.0",
"dependencies": {
"cookie-parser": "^1.4.7",
"koffi": "^2.8.9",
"piscina": "^5.1.1",
"tough-cookie": "^4.1.4"
}
},
"node_modules/piscina": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/piscina/-/piscina-5.3.2.tgz",
"integrity": "sha512-vv7l/mM7B9WgrhDaudIqv1x6v4LOBRYYmpWGdWushhpbCmVHp11sUB2v4hj1CAeTGXVxuZFz6xOU1RalAiPKfQ==",
"license": "MIT",
"engines": {
"node": ">=20.x"
},
"optionalDependencies": {
"@napi-rs/nice": "^1.0.4"
}
},
"node_modules/psl": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
"integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
"license": "MIT",
"dependencies": {
"punycode": "^2.3.1"
},
"funding": {
"url": "https://github.com/sponsors/lupomontero"
}
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"license": "MIT"
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"license": "MIT"
},
"node_modules/tough-cookie": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
"license": "BSD-3-Clause",
"dependencies": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.2.0",
"url-parse": "^1.5.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/universalify": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"license": "MIT",
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"license": "MIT",
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
}
}
}

View File

@@ -29,5 +29,8 @@
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"node-tls-client": "^2.1.0"
}
}

View File

@@ -1,11 +1,23 @@
// Currently active sources reported on 6:18:22 PM PST 9/13/2026
// None Anime Tested: 936075
// Anime Tested: 37854
// Fshare/Fsonic Tested: 155 ( they don't have Michael )
export const SOURCES = [
{
key: '3eyedraven',
label: '3eyedraven',
sourceFile: '3eyedraven',
proxyParam: '3er',
timeout: 25000,
jitter: 500,
retries: 2,
multiUrl: false,
skipProxy: true,
cdnHeaders: [{
pattern: /3eyedraven\.watch/i,
headers: {
Referer: 'https://3eyedraven.watch/',
Origin: 'https://3eyedraven.watch',
},
}],
},
{
key: '123anime',
label: '123Anime',
@@ -106,6 +118,25 @@ export const SOURCES = [
}],
},
{
key: 'cinemaarmy',
label: 'CinemaArmy',
sourceFile: 'cinemaarmy',
proxyParam: 'ca',
timeout: 30000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
cdnHeaders: [{
pattern: /cinema\.army/i,
headers: {
Referer: 'https://cinema.army/',
Origin: 'https://cinema.army',
},
}],
},
{
key: 'dulo',
label: 'Dulo',
@@ -191,6 +222,25 @@ export const SOURCES = [
},
},
{
key: 'movenerds',
label: 'MoverNerds',
sourceFile: 'movenerds',
proxyParam: 'mnr',
timeout: 30000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
cdnHeaders: [{
pattern: /movenerds\.space/i,
headers: {
Referer: 'https://movenerds.space/',
Origin: 'https://movenerds.space',
},
}],
},
{
key: 'movienight',
label: 'MovieNight',
@@ -293,6 +343,26 @@ export const SOURCES = [
},
}],
},
{
key: 'thugtv',
label: 'ThugTV',
sourceFile: 'thugtv',
proxyParam: 'tv',
timeout: 30000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
cdnHeaders: [{
pattern: /thugtv\.online|thuktv\.onrender\.com/i,
headers: {
Referer: 'https://thugtv.online/',
Origin: 'https://thugtv.online',
},
}],
},
{
key: 'vidapi',
label: 'VidAPI',
@@ -426,6 +496,25 @@ export const SOURCES = [
multiUrl: true,
},
{
key: 'vidy',
label: 'Vidy',
sourceFile: 'vidy',
proxyParam: 'vy',
timeout: 25000,
jitter: 500,
retries: 2,
multiUrl: true,
skipProxy: true,
cdnHeaders: [{
pattern: /wecollege\.net|vidy\.st/i,
headers: {
Referer: 'https://www.vidy.st/',
Origin: 'https://www.vidy.st',
},
}],
},
{
key: 'vidzee',
label: 'VidZee',

136
src/sources/3eyedraven.js Normal file
View File

@@ -0,0 +1,136 @@
import { getUA } from "../utils/helpers.js";
const BASE_URL = "https://3eyedraven.watch";
const API_BASE = "https://3eyedraven.watch/api";
function getHeaders() {
return {
"User-Agent": getUA(),
Accept: "application/json",
Referer: `${BASE_URL}/`,
Origin: BASE_URL,
};
}
function resolveApiKey(args) {
return (
args?.tmdbApiKey ||
args?.sdk?.tmdbApiKey ||
process.env.TMDB_API_KEY ||
null
);
}
async function getTitle(id, isTv, apiKey) {
if (!apiKey) return null;
const type = isTv ? "tv" : "movie";
try {
const res = await fetch(
`https://api.themoviedb.org/3/${type}/${id}?api_key=${apiKey}`,
{ signal: AbortSignal.timeout(5000) }
);
if (!res.ok) return null;
const data = await res.json();
return isTv ? data.name : data.title;
} catch {
return null;
}
}
function slugify(text) {
return text
.toLowerCase()
.normalize("NFKD")
.replace(/[\u0300-\u036f]/g, "")
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-|-$/g, "");
}
function absolute(url) {
if (!url) return "";
if (/^https?:\/\//.test(url)) return url;
return `${BASE_URL}${url.startsWith("/") ? "" : "/"}${url}`;
}
export async function getStream(args) {
const { id, s = null, e = null } = args;
const isTv = s != null && e != null;
const apiKey = resolveApiKey(args);
const title = await getTitle(id, isTv, apiKey);
if (!title) {
if (process.env.DEBUG_CAUSE) {
console.error(
`[3eyedraven] Could not resolve title for ${isTv ? "tv" : "movie"} ${id} ` +
`(tmdbApiKey ${apiKey ? "present" : "MISSING"})`
);
}
return null;
}
const identifier = `${slugify(title)}-${id}`;
const url = isTv
? `${API_BASE}/stream/${identifier}?season=${s}&episode=${e}`
: `${API_BASE}/stream/${identifier}`;
try {
const res = await fetch(url, {
headers: getHeaders(),
signal: AbortSignal.timeout(15000),
});
if (!res.ok) {
if (process.env.DEBUG_CAUSE) {
console.error(`[3eyedraven] HTTP ${res.status} for ${url}`);
}
return null;
}
const data = await res.json();
const stream = data?.stream;
if (!stream?.url) {
if (process.env.DEBUG_CAUSE) {
console.error(`[3eyedraven] No stream.url in response for ${url}`);
}
return null;
}
const streamUrl = absolute(stream.url);
if (!/^https?:\/\//.test(streamUrl)) return null;
const subtitles = (stream.subtitles || [])
.map(sub => {
const subUrl = absolute(sub.url);
if (!subUrl) return null;
return {
label: sub.label || sub.language || "Subtitle",
file: subUrl,
type: "vtt",
source: "3eyedraven",
};
})
.filter(Boolean);
return {
url: streamUrl,
headers: {
"User-Agent": getUA(),
Referer: `${BASE_URL}/`,
Origin: BASE_URL,
},
server: "3eyedraven",
quality: "1080p",
type: stream.format === "hls" ? "hls" : "mp4",
subtitles,
skipProxy: true,
};
} catch (err) {
if (process.env.DEBUG_CAUSE) {
console.error(`[3eyedraven] fetch error for ${url}:`, err.message);
if (err.cause) console.error(" cause:", err.cause.code, err.cause.message);
}
return null;
}
}

181
src/sources/cinemaarmy.js Normal file
View File

@@ -0,0 +1,181 @@
import crypto from "crypto";
import { Session, ClientIdentifier, initTLS, destroyTLS } from "node-tls-client";
const BASE_URL = "https://cinema.army";
const API_BASE = "https://cinema.army/api";
const XOR_KEY = "f16a6b92fcd6eed3e9476297f893f2505c32f79bc6efef9b6c95496aa5914548";
const HMAC_KEY = "a2cfc9eaa2a3690b5d4f6b5f958dbdeae52a097283d375bd253ee7c7062524f5";
const UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
const SERVERS = [
{ key: "cookiebakers", method: "POST", label: "CookieBakers" },
{ key: "tcloud", method: "GET", label: "TCloud" },
{ key: "ipcloud", method: "GET", label: "IPcloud" },
{ key: "dcloud", method: "GET", label: "Dcloud" },
];
let tlsInitialized = false;
let session = null;
async function ensureSession() {
if (!tlsInitialized) {
await initTLS();
tlsInitialized = true;
}
if (!session) {
session = new Session({
clientIdentifier: ClientIdentifier.chrome_131,
timeout: 15000,
insecureSkipVerify: false,
});
}
return session;
}
function getHeaders(token, id, isTv, s, e) {
const referer = isTv
? `${BASE_URL}/watch?id=${id}&type=tv&season=${s}&episode=${e}`
: `${BASE_URL}/watch?id=${id}&type=movie`;
return {
"User-Agent": UA,
"Accept": "application/json",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Cache-Control": "no-cache",
"Pragma": "no-cache",
"Referer": referer,
"Origin": BASE_URL,
"Sec-Ch-Ua": '"Chromium";v="131", "Not_A Brand";v="24"',
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": '"Windows"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Priority": "u=1, i",
"X-Stream-Token": token,
};
}
function generateToken(id) {
try {
const minute = Math.floor(Date.now() / 1000 / 60);
return crypto
.createHmac("sha256", HMAC_KEY)
.update(`${id}:${minute}`)
.digest("hex");
} catch {
return "";
}
}
function decryptStreamUrl(encoded) {
if (!encoded) return "";
if (encoded.startsWith("http://") || encoded.startsWith("https://")) return encoded;
try {
const decoded = Buffer.from(encoded, "base64").toString("binary");
let out = "";
for (let i = 0; i < decoded.length; i++) {
out += String.fromCharCode(
decoded.charCodeAt(i) ^ XOR_KEY.charCodeAt(i % XOR_KEY.length)
);
}
return out;
} catch {
return encoded;
}
}
export async function getStream(args) {
const { id, s = null, e = null } = args;
const isTv = s != null && e != null;
const token = generateToken(id);
const headers = getHeaders(token, id, isTv, s, e);
const sess = await ensureSession();
const requests = SERVERS.map(server => {
const path = isTv
? `/${server.key}/tv/${id}/${s}/${e}`
: `/${server.key}/movie/${id}`;
return { url: `${API_BASE}${path}`, server };
});
const results = await Promise.allSettled(
requests.map(async ({ url, server }) => {
try {
const res = server.method === "POST"
? await sess.post(url, { headers })
: await sess.get(url, { headers });
if (res.status !== 200) {
if (process.env.DEBUG_CAUSE) {
console.error(`[CinemaArmy ${server.key}] HTTP ${res.status}`);
}
return null;
}
const text = await res.text();
let data;
try {
data = JSON.parse(text);
} catch {
return null;
}
const encrypted = data?.stream?.url;
if (!encrypted) return null;
const streamUrl = decryptStreamUrl(encrypted);
if (!streamUrl || !/^https?:\/\//.test(streamUrl)) return null;
return {
url: streamUrl,
headers: {
"User-Agent": UA,
Referer: `${BASE_URL}/`,
Origin: BASE_URL,
},
server: `CinemaArmy (${server.label})`,
quality: "1080p",
type: streamUrl.includes(".m3u8") ? "hls" : "mp4",
};
} catch (err) {
if (process.env.DEBUG_CAUSE) {
console.error(`[CinemaArmy ${server.key}] ${err.message}`);
if (err.cause) {
console.error(` cause.code: ${err.cause.code || "n/a"}`);
console.error(` cause.message: ${err.cause.message || err.cause}`);
}
}
return null;
}
})
);
const allUrls = results
.filter(r => r.status === "fulfilled" && r.value)
.map(r => r.value);
if (!allUrls.length) return null;
return { allUrls };
}
export async function cleanup() {
if (session) {
try {
await session.close();
} catch { }
session = null;
}
if (tlsInitialized) {
try {
await destroyTLS();
} catch { }
tlsInitialized = false;
}
}

125
src/sources/movenerds.js Normal file
View File

@@ -0,0 +1,125 @@
import { getUA } from "../utils/helpers.js";
const API_BASE = "https://api.movenerds.space/api";
function getHeaders() {
return {
"User-Agent": getUA(),
Accept: "application/json",
Referer: "https://movenerds.space/",
Origin: "https://movenerds.space",
};
}
function resolveApiKey(args) {
return (
args?.tmdbApiKey ||
args?.sdk?.tmdbApiKey ||
process.env.TMDB_API_KEY ||
null
);
}
async function getMeta(id, isTv, apiKey) {
if (!apiKey) return null;
const type = isTv ? "tv" : "movie";
try {
const res = await fetch(
`https://api.themoviedb.org/3/${type}/${id}?api_key=${apiKey}`,
{ signal: AbortSignal.timeout(5000) }
);
if (!res.ok) return null;
const data = await res.json();
const title = isTv ? data.name : data.title;
const date = isTv ? data.first_air_date : data.release_date;
const year = date ? parseInt(date.slice(0, 4), 10) : null;
return { title, year };
} catch {
return null;
}
}
function mapSource(source) {
if (!source || !source.url) return null;
if (source.type !== "hls" && source.type !== "mp4") return null;
if (!/^https?:\/\//.test(source.url)) return null;
return {
url: source.url,
headers: {
"User-Agent": source.headers?.["User-Agent"] || getUA(),
Referer: source.headers?.Referer || "https://movenerds.space/",
Origin: source.headers?.Origin || "https://movenerds.space",
},
server: source.name || source.providerName || "MoverNerds",
quality: source.quality || "1080p",
type: source.type,
skipProxy: true,
};
}
export async function getStream(args) {
const { id, s = null, e = null } = args;
const isTv = s != null && e != null;
const apiKey = resolveApiKey(args);
const meta = await getMeta(id, isTv, apiKey);
if (!meta?.title) {
if (process.env.DEBUG_CAUSE) {
console.error(
`[movenerds] Could not resolve title for ${isTv ? "tv" : "movie"} ${id} ` +
`(tmdbApiKey ${apiKey ? "present" : "MISSING"})`
);
}
return null;
}
const params = new URLSearchParams({
tmdbId: String(id),
type: isTv ? "tv" : "movie",
title: meta.title,
});
if (meta.year) params.set("year", String(meta.year));
if (isTv) {
params.set("season", String(s));
params.set("episode", String(e));
params.set("language", "en");
}
const url = `${API_BASE}/stream?${params.toString()}`;
try {
const res = await fetch(url, {
headers: getHeaders(),
signal: AbortSignal.timeout(20000),
});
if (!res.ok) {
if (process.env.DEBUG_CAUSE) {
console.error(`[movenerds] HTTP ${res.status} for ${url}`);
}
return null;
}
const data = await res.json();
const primary = Array.isArray(data?.primarySources) ? data.primarySources : [];
if (!primary.length) {
if (process.env.DEBUG_CAUSE) {
console.error(`[movenerds] No primarySources in response for ${url}`);
}
return null;
}
const allUrls = primary.map(mapSource).filter(Boolean);
if (!allUrls.length) return null;
return { allUrls };
} catch (err) {
if (process.env.DEBUG_CAUSE) {
console.error(`[movenerds] fetch error for ${url}:`, err.message);
if (err.cause) console.error(" cause:", err.cause.code, err.cause.message);
}
return null;
}
}

View File

@@ -1,5 +1,3 @@
// im being salty
import { USER_AGENT, fetchJson } from '../utils/helpers.js';
const C_ARRAY = [

62
src/sources/thugtv.js Normal file
View File

@@ -0,0 +1,62 @@
import { getUA } from "../utils/helpers.js";
const API_BASE = "https://thuktv.onrender.com/api";
function getHeaders() {
return {
"User-Agent": getUA(),
Accept: "application/json",
Referer: "https://thugtv.online/",
Origin: "https://thugtv.online",
};
}
function mapSource(source) {
if (!source || !source.url) return null;
if (source.type !== "hls" && source.type !== "mp4") return null;
if (!/^https?:\/\//.test(source.url)) return null;
return {
url: source.url,
headers: {
"User-Agent": getUA(),
Referer: "https://thugtv.online/",
Origin: "https://thugtv.online",
},
server: source.name || source.label || "ThugTV",
quality: source.quality || "1080p",
type: source.type,
skipProxy: true,
};
}
export async function getStream(args) {
const { id, s = null, e = null } = args;
const isTv = s != null && e != null;
const url = isTv
? `${API_BASE}/stream/tv/${id}/${s}/${e}`
: `${API_BASE}/stream/movie/${id}`;
try {
const res = await fetch(url, {
headers: getHeaders(),
signal: AbortSignal.timeout(15000),
});
if (!res.ok) return null;
const data = await res.json();
const sources = Array.isArray(data?.sources) ? data.sources : [];
if (!sources.length) return null;
const allUrls = sources
.map(mapSource)
.filter(Boolean);
if (!allUrls.length) return null;
return { allUrls };
} catch {
return null;
}
}

187
src/sources/vidy.js Normal file
View File

@@ -0,0 +1,187 @@
import { getUA } from "../utils/helpers.js";
const API_URL = "https://api.wecollege.net";
const SERVERS = ["miami", "atlanta", "seattle", "denver", "dallas", "tampa"];
const MAGIC = [109, 118, 109, 49];
function imul(a, b) {
return Math.imul(a | 0, b | 0) >>> 0;
}
function pFn(e) {
e = e >>> 0;
e = (e ^ (e >>> 16)) >>> 0;
e = imul(e, 2246822507);
e = (e ^ (e >>> 13)) >>> 0;
e = imul(e, 3266489909);
e = (e ^ (e >>> 16)) >>> 0;
return e;
}
function gFn(e, t) {
e = e >>> 0;
t = t & 31;
if (t === 0) return e;
return ((e << t) | (e >>> (32 - t))) >>> 0;
}
function decryptVidy(ciphertext, seedStr, mediaId) {
let padded = ciphertext.replace(/-/g, "+").replace(/_/g, "/");
while (padded.length % 4) padded += "=";
const raw = new Uint8Array(Buffer.from(padded, "base64"));
const length = raw.length;
let tFnv = 2166136261;
for (let i = 0; i < seedStr.length; i++) {
tFnv = imul((tFnv ^ seedStr.charCodeAt(i)) >>> 0, 16777619);
}
const fnvRes = pFn(tFnv);
const innerArg = (((mediaId >>> 0) ^ 2654435769) >>> 0);
const inner = pFn(innerArg);
let n = pFn(((fnvRes ^ inner) >>> 0));
const S = {};
for (let e = 0; e < 8; e++) {
const t = n % 61;
n = gFn((n + 2654435769) >>> 0, 7 + (7 & e));
S[t] = ((n ^ pFn(n)) >>> 0);
n = pFn((n + t) >>> 0);
}
let acc = pFn(((2779096485 ^ n) >>> 0));
const keystream = new Uint8Array(length);
let sCnt = 0;
let idx = 0;
while (idx < length) {
const sVal = acc;
const o = sVal % 61;
const hasO = Object.prototype.hasOwnProperty.call(S, o);
const iVal = hasO ? -1 : 0;
const d = hasO ? S[o] : 0;
const nTerm = ((d ^ imul(2654435769, sCnt + 1)) >>> 0);
sCnt += 1;
const aTerm = sVal;
let lVal = (((aTerm ^ nTerm) | (aTerm & nTerm & iVal)) >>> 0);
const term1 = gFn((lVal + sVal) >>> 0, 31 & o);
const term2 = gFn(sVal, (31 & imul(o, 7)) >>> 0);
lVal = ((term1 ^ term2) >>> 0);
const newS = pFn((lVal + 2654435769) >>> 0);
S[o] = newS;
acc = newS;
const tVal = newS;
keystream[idx++] = tVal & 0xFF;
if (idx < length) keystream[idx++] = (tVal >>> 8) & 0xFF;
if (idx < length) keystream[idx++] = (tVal >>> 16) & 0xFF;
if (idx < length) keystream[idx++] = (tVal >>> 24) & 0xFF;
}
for (let i = 0; i < length; i++) {
raw[i] ^= keystream[i];
}
for (let i = 0; i < MAGIC.length; i++) {
if (raw[i] !== MAGIC[i]) {
throw new Error("Vidy decrypt failed: magic header mismatch");
}
}
return new TextDecoder().decode(raw.slice(MAGIC.length));
}
export async function getStream(args) {
const { id, s = null, e = null } = args;
const isTv = s != null && e != null;
const mediaId = Number(id);
const headers = {
"User-Agent": getUA(),
Referer: "https://www.vidy.st/",
Origin: "https://www.vidy.st",
};
try {
const seedUrl = new URL(`${API_URL}/seed`);
seedUrl.searchParams.set("mediaId", String(id));
const seedRes = await fetch(seedUrl.toString(), {
headers,
signal: AbortSignal.timeout(6000),
});
if (!seedRes.ok) return null;
const seedData = await seedRes.json();
const seed = seedData?.seed;
if (!seed) return null;
for (const server of SERVERS) {
try {
const srcUrl = new URL(`${API_URL}/${server}/sources`);
srcUrl.searchParams.set("mediaType", isTv ? "tv" : "movie");
srcUrl.searchParams.set("tmdbId", String(id));
srcUrl.searchParams.set("enc", "2");
srcUrl.searchParams.set("seed", seed);
if (isTv) {
srcUrl.searchParams.set("seasonId", String(s));
srcUrl.searchParams.set("episodeId", String(e));
}
const res = await fetch(srcUrl.toString(), {
headers,
signal: AbortSignal.timeout(6000),
});
if (!res.ok) continue;
const text = await res.text();
let data;
try {
data = JSON.parse(decryptVidy(text, seed, mediaId));
} catch {
continue;
}
const sources = data?.sources || [];
const playlist = data?.playlist || "";
if (!sources.length && !playlist) continue;
let streamUrl = playlist;
let quality = "1080p";
for (const src of sources) {
if (src?.quality === "1080p" && src?.url) {
streamUrl = src.url;
quality = "1080p";
break;
}
}
if (!streamUrl && sources.length) {
streamUrl = sources[0]?.url || "";
quality = sources[0]?.quality || "";
}
if (!streamUrl) continue;
return {
url: streamUrl,
headers: {
"User-Agent": getUA(),
Referer: "https://www.vidy.st/",
Origin: "https://www.vidy.st",
},
server: "Vidy",
quality,
type: streamUrl.includes(".m3u8") ? "hls" : "mp4",
};
} catch {
continue;
}
}
return null;
} catch {
return null;
}
}

View File

@@ -189,4 +189,4 @@ if (CONFIG.TEST_TV) {
}
} else {
console.log("\nSkipped Stream Test");
}
}