Modern, configurable streaming metadata + source aggregation API with a secure admin panel and multi-key TMDB rotation.
-
MultiβTMDB Key Rotation β Supply multiple API keys; one is chosen randomly per request.
-
Provider Aggregation β Pluggable providers (Showbox, 4khdhub, MoviesMod, MP4Hydra, VidZee, Vixsrc, UHDMovies) with perβprovider enable toggles + default selection.
-
π₯ Plugin System β Drop new provider files in
providers/
and add its exported function to the registry map (providers/registry.js
βproviderFunctionMap
). -
Dynamic Filtering β Minimum quality presets, custom JSON quality map, codec exclusion rules (presets + JSON).
-
Runtime Overrides UI β Fully interactive web admin at
/
(login protected) writing toutils/user-config.json
. -
Session Auth + Rate Limiting β Login system with bruteβforce lockouts, logout, password change.
-
Status & Health Panel β Live metrics, provider status, endpoint list, functional provider checks.
-
Config Propagation β Overrides mirrored to
process.env
for legacy compatibility (no.env
required after first save). -
BackβNavigation Safe β Cache-control + visibility/session revalidation.
-
Extensible β Simple drop-in provider plugin system.
-
Optional Stream Proxy Layer β When enabled, rewrites returned stream URLs so HLS playlists, TS segments, and subtitles are served through internal endpoints (
/m3u8-proxy
,/ts-proxy
,/sub-proxy
) allowing uniform headers, origin shielding, and optional segment caching. When active the API omits per-streamheaders
objects from responses (they're no longer needed by clients) to avoid leaking upstream header requirements.Proxy Tuning Parameters (query flags accepted by
/ts-proxy
β defaults shown):clampOpen
(on) β If a client sends an ambiguousRange: bytes=0-
, constrain it to an initial window ofopenChunkKB
(default 4096 KB) to avoid huge first reads.openChunkKB=4096
β Size (KB) used for both clamp window and each progressive expansion increment.progressiveOpen
(on) β Grow successive ambiguous head requests (bytes=0-
) incrementally instead of one large span. Maintains a perβURL expansion map.initChunkKB=512
β Size used for a synthetic initial partial (206) when no client range is provided and progressive growth is disabled. Capped 64β2048 KB.noSynth=1
β Disable synthetic initial partial generation (forces passβthrough behavior).force200=1
β Normalize upstream 206 responses to 200 (diagnostics / edge player testing).tailPrefetch
(on) β Enable asynchronous tail fetch of the fileβs last bytes to satisfy rapid player tail probes.tailPrefetchKB=256
β Tail window size (64β2048 KB). Cached in memory with TTL cleanup. Behavior Notes:- Synthetic partials autoβdisable when
progressiveOpen
is active (real progressive ranges preferred). - Player tail probes (e.g., VLC metadata scans) are accelerated by the cached tail window.
- Forced 200 mode strips
Content-Range
to emulate full responses for troubleshooting. - Host Overrides:
pixeldrain.*
andvideo-downloads.googleusercontent.com
URLs are routed through/ts-proxy
regardless of extension to ensure correct range + MIME handling.
# 1. Install dependencies
npm install
# 2. (Optional) Copy example env if you want an initial TMDB key
cp .env.example .env # then edit TMDB_API_KEY=
# 3. Start API with automatic restarts (recommended for local dev)
npm start
# Or production-style single run
# node apiServer.js
# 4. Open the Admin UI (login page) in browser
http://localhost:8787/
# 5. Health check
curl http://localhost:8787/api/health
If you just want to run it (no building):
docker pull inside4ndroid/tmdb-embed-api:latest
docker run --name tmdb-embed-api -p 8787:8787 \
-e TMDB_API_KEY=YOUR_TMDB_KEY \
inside4ndroid/tmdb-embed-api:latest
Or the minimal quick-test run:
docker run -it -p 8787:8787 inside4ndroid/tmdb-embed-api:latest
Persist overrides (Windows PowerShell example) by mounting a local file:
New-Item -ItemType File -Path .\utils\user-config.json -Force | Out-Null
docker run --name tmdb-embed-api -p 8787:8787 `
-e TMDB_API_KEY=YOUR_TMDB_KEY `
-v ${PWD}/utils/user-config.json:/app/utils/user-config.json `
inside4ndroid/tmdb-embed-api:latest
docker build -t tmdb-embed-api .
docker run --name tmdb-embed -p 8787:8787 \
-e TMDB_API_KEY=YOUR_TMDB_KEY \
-v "$(pwd)/utils/user-config.json:/app/utils/user-config.json" \
tmdb-embed-api
After first login + save, the UI writes overrides into the mounted user-config.json
so they persist across container restarts.
An example docker-compose.yml
is included. Start with:
docker compose up -d --build
Environment variables can be supplied via a .env
file in the same directory (Compose automatically loads it). Example .env
:
TMDB_API_KEY=first_key
FEBBOX_COOKIES=cookie1,cookie2
To stop & remove:
docker compose down
Either set TMDB_API_KEYS
to a JSON array string:
docker run -p 8787:8787 \
-e TMDB_API_KEYS='["KEY1","KEY2","KEY3"]' \
tmdb-embed-api
or add / remove keys inside the Admin UI (Keys panel) and save.
Variable | Purpose | Notes |
---|---|---|
API_PORT |
Port the server listens on | Defaults to 8787 |
TMDB_API_KEY |
Single TMDB key (legacy) | Use if you only have one key |
TMDB_API_KEYS |
JSON array of keys | Overrides single key when present |
FEBBOX_COOKIES |
Comma separated FebBox cookies | Enables Showbox provider immediately |
PASSWORD_HASH |
Pre-seed admin password hash | Optional (UI can set) |
ADMIN_USERNAME |
Override default username | Default: admin |
If both TMDB_API_KEY
and TMDB_API_KEYS
are provided, rotation uses the array. Clearing the array in the UI also clears the legacy key.
docker compose pull # if using an external registry (future)
docker compose up -d --build
### Restart from Admin UI
The Admin panel includes a Restart Server control.
- Local (nodemon): the backend writes a `restart.trigger` file and exits; nodemon detects the change and restarts automatically.
- Docker Compose: the container exits and is restarted by `restart: unless-stopped`.
Container health relies on GET /api/health
. If you disable or modify that route, adjust the Dockerfile / compose healthcheck accordingly.
The root (/
) serves the login page. After successful login a session cookie (session
) is issued (HttpOnly; 12h lifetime). All admin pages (e.g. config.html
) require an active session.
Endpoint | Method | Purpose |
---|---|---|
/auth/login |
POST | Authenticate (JSON: { username, password } ) |
/auth/logout |
POST | Destroy session |
/auth/session |
GET | Check session status |
/auth/change-password |
POST | Update password (requires session) |
Repeated failed logins trigger exponential lockouts (Retry-After header emitted).
All runtime state collapses into a merged object displayed in the UI (Live Config panel). Source order:
- Initial environment variables / optional
.env
- JSON overrides:
utils/user-config.json
Saving in the UI writes only changed keys. Setting a field to empty removes the override (reverting to env/default). Removing all TMDB keys (and saving) clears tmdbApiKeys
and the legacy tmdbApiKey
.
Override File: utils/user-config.json
{
"defaultProviders": ["showbox","4khdhub"],
"tmdbApiKeys": ["KEY_A","KEY_B"],
"enableShowboxProvider": true
}
Panel | Summary |
---|---|
Core | Port, default providers, default region |
Quality / Filters | Min quality presets & codec exclusion JSON |
Keys | Add/remove TMDB API keys (rotated randomly) |
FebBox / PStream | Manage FebBox cookies powering Showbox provider |
Advanced | Provider toggles, cache & validation flags |
Server Status | Live metrics, provider functional checks |
Live Config | View merged + override JSON snapshots |
Session is revalidated on visibility and back/forward navigation to prevent stale access.
The API supports a plugin system. Drop a new provider file in the providers/
folder and register its exported function in providers/registry.js
under providerFunctionMap
.
showbox
- Showbox/PStream integration4khdhub
- 4KHDHub streamsmoviesmod
- MoviesMod streamsmp4hydra
- MP4Hydra streamsvidzee
- VidZee streamsvixsrc
- Vixsrc streamsuhdmovies
- UHD Movies streams
- Create
providers/yourprovider.js
with your stream fetching logic - Export a function like
getYourproviderStreams(tmdbId, mediaType, season, episode)
- Register it in
providers/registry.js
βproviderFunctionMap
:// providers/registry.js const providerFunctionMap = { 'Showbox.js': 'getStreamsFromTmdbId', '4khdhub.js': 'get4KHDHubStreams', 'moviesmod.js': 'getMoviesModStreams', 'MP4Hydra.js': 'getMP4HydraStreams', 'VidZee.js': 'getVidZeeStreams', 'vixsrc.js': 'getVixsrcStreams',
'uhdmovies.js': 'getUHDMoviesStreams', 'yourprovider.js': 'getYourproviderStreams' };
4. The provider will appear in the admin UI with an enable/disable toggle.
**Example Provider (Unified Output):**
```javascript
async function getYourproviderStreams(tmdbId, mediaType, season, episode) {
// Your scraping/API logic here
return [{
title: "Fight Club - 1080p [YourProvider #1]",
url: "https://stream.url/video.mp4",
quality: "1080p",
provider: "yourprovider",
headers: { "User-Agent": "Mozilla/5.0" }
}];
}
module.exports = { getYourproviderStreams };
β οΈ Important: All providers must return streams in the unified JSON format to ensure compatibility with filtering and aggregation.
The system automatically:
- β Detects new provider files
- β Adds enable/disable toggles in the admin UI
- β Includes them in stream aggregation
- β Applies filtering and quality controls
- β No core file edits required!
Endpoint | Description |
---|---|
GET /api/health |
Basic heartbeat |
GET /api/metrics |
Runtime counters & summary |
GET /api/status |
Metrics + providers + endpoints list |
GET /api/providers |
Enabled providers summary |
GET /api/providers/:name |
Single provider status |
GET /api/streams/:type/:tmdbId |
Aggregate streams (type = movie |
GET /api/streams/:provider/:type/:tmdbId |
Provider-specific streams |
GET /api/config |
{ merged, override } |
POST /api/config |
Apply override patch |
Aggregate endpoint auto-resolves IMDb when needed and merges provider output before filtering.
{
"title": "Fight Club - 1080p [MP4Hydra #2]",
"url": "https://stream.url/video.mp4",
"quality": "1080p",
"provider": "mp4hydra",
"headers": { "User-Agent": "Mozilla/5.0" }
}
Filtering passes through applyFilters
to enforce min quality + codec exclusions.
Note: When the
enableProxy
flag is turned on, provider-specific request headers are stripped from each stream object before responding. Clients should use the proxied URL directly without adding custom Referer/Origin headers.
Flag | Default | Purpose |
---|---|---|
disableCache | false | Disables internal caches (Showbox + proxy segment cache) |
enablePStreamApi | true | Enables Showbox PStream-specific handling |
disableUrlValidation | false | Skip general URL pattern validation checks |
disable4khdhubUrlValidation | false | Skip 4khdhub-specific URL validation |
enableProxy | false | Mounts proxy routes and rewrites stream URLs through them |
Toggle enableProxy
to activate the internal proxy. This adds lightweight playlist/segment/subtitle rewriting without modifying provider code. Disable it to return direct upstream URLs.
- Presets:
all
,480p
,720p
,1080p
,1440p
,2160p
. - Custom quality JSON example:
{ "default": "900p", "showbox": "1080p" }
- Codec exclusion JSON example:
{ "excludeDV": true, "excludeHDR": false }
- Admin UI requires login; session cookie is HttpOnly.
- Cache-control headers disable storing sensitive pages.
- Login is rate limited with escalating lockouts.
- Password change endpoint enforces minimum length.
Aspect | Recommendation |
---|---|
Node Version | 18+ LTS |
Reverse Proxy | Terminate TLS (e.g., Nginx) and forward to API port |
Persistent Config | Mount / persist utils/user-config.json |
Logs | Pipe stdout to centralized logger |
Scaling | Use a single instance unless providers are CPU bound |
For ephemeral platforms (e.g., Vercel) note that some providers use temporary directories; avoid enabling disk-heavy cache directories.
Symptom | Cause / Fix |
---|---|
No streams from Showbox | Missing FebBox cookies |
TMDB quota issues | Add more keys under Keys panel |
Provider missing in matrix | Ensure its enable flag exists & UI updated |
Empty merged config after restart | user-config.json deleted or unreadable |
Streams low quality | Adjust min quality preset or custom JSON |
PRs welcome. Keep changes focused and avoid unrelated formatting churn. For new providers include:
- A short rationale
- Retry / timeout safeguards
- Respect for existing filtering structure
If this project helps you, consider sponsoring to support continued development & maintenance:
β‘οΈ GitHub Sponsors: https://github.com/sponsors/Inside4ndroid
Every contribution accelerates feature delivery & sustainability.
MIT. See LICENSE
.
Inspired by community scraping/stream aggregation efforts. Credits also to the original NuvioStreamsAddon work for earlier concepts.
Happy streaming & hacking! β¨