fixed syntax issues

This commit is contained in:
2026-11-14 19:05:02 -08:00
parent 2cec85a8f3
commit 36b2b33ecc
29 changed files with 842 additions and 977 deletions

View File

@@ -4,40 +4,29 @@
## Overview
Stream API includes a built-in cryptographic key management and rate-limiting system backed by SQLite. When enabled, client applications must supply an authenticated key to establish Server-Sent Events connections or request proxied media streams.
Stream API includes a key management and rate-limiting system backed by SQLite. When enabled, client apps must supply an authenticated key to establish SSE streams or request proxied media.
---
## Key Structure & Prefixes
## Key Tiers
API keys are 32-character hexadecimal strings generated with a specific prefix indicating the client tier:
| Key Prefix | Key Type | Intended Use Case | Default Rate Limit |
| :--- | :--- | :--- | :--- |
| **`pk_`** | **Partner Key** | Verified high-volume partner frontends and applications | 1,000 req / minute |
| **`sk_`** | **Standard Key** | Private self-hosters and internal client instances | 500 req / minute |
| **`pub_`** | **Public Key** | Anonymous public trial access or open community frontends | 10 req / minute |
- **`pk_` (Partner Key)**: For high-volume frontends. Default: 1,000 req/min.
- **`sk_` (Standard Key)**: For private self-hosters and internal client apps. Default: 500 req/min.
- **`pub_` (Public Key)**: For public trial access or open community frontends. Default: 10 req/min.
---
## Generating API Keys via CLI
## Creating Keys
The Stream API repository includes a CLI tool (`add-key.mjs`) to generate and insert keys into the active SQLite database:
Generate keys using the CLI tool in the Stream API directory:
```bash
# Syntax: node add-key.mjs <type> <rate_limit_per_min> <client_name>
# 1. Create a Standard Key for a personal desktop client:
node add-key.mjs standard 500 my-desktop-client
# 2. Create a Partner Key for a high-traffic community player:
node add-key.mjs partner 1000 partner-frontend
# 3. Create a restricted Public Key:
node add-key.mjs public 10 public-guest
```
### CLI Output Example
### Output Example
```
Generated Key: sk_8f14b2d39a7e4c5b10e9f8a7b6c5d4e3
Type: standard
@@ -45,19 +34,18 @@ Limit: 500 req/min
Client: my-desktop-client
Status: Active
```
The key is printed once upon creation. Copy and deliver it to your client application securely.
---
## Managing Keys via JSON Database Export
## Database Export & Sync
For automated deployments or bulk key management, you can export the database to a JSON file:
For automated deployments, export the database to JSON:
### 1. Export Database
```bash
node export-db.mjs
```
This dumps the active SQLite database tables into `db.json`:
This dumps active keys to `db.json`:
```json
{
"keys": [
@@ -73,41 +61,40 @@ This dumps the active SQLite database tables into `db.json`:
}
```
### 2. Modify and Re-Import
Edit `db.json` to add, revoke, or modify limits, then commit the changes back to SQLite:
To sync edits from `db.json` back into SQLite:
```bash
node update-db.mjs
```
---
## Client Authorization Headers
## Client Authorization
Clients can authenticate requests by passing the key in one of the following locations:
Clients can send their key via headers or query parameters:
### 1. Authorization Header (Recommended)
### Authorization Header
```http
GET /movie?id=155 HTTP/1.1
Host: your-api.example.com
Host: api.vyla.cc
Authorization: Bearer sk_8f14b2d39a7e4c5b10e9f8a7b6c5d4e3
```
### 2. Custom API Key Header
### Custom Header
```http
X-API-Key: sk_8f14b2d39a7e4c5b10e9f8a7b6c5d4e3
```
### 3. Query Parameter (for EventSource & HTML5 Video)
Because native browser `EventSource` and `<video>` tags do not support custom request headers, you can pass the key as a query parameter:
### Query Parameter
Used for browser `EventSource` and native `<video>` elements that do not support custom request headers:
```http
GET /movie?id=155&key=sk_8f14b2d39a7e4c5b10e9f8a7b6c5d4e3 HTTP/1.1
```
---
## Rate Limit Headers
## Rate Limit Responses
When requests are evaluated, Stream API returns standard rate-limiting headers:
Responses include standard rate-limiting headers:
```http
HTTP/1.1 200 OK
@@ -116,7 +103,7 @@ X-RateLimit-Remaining: 498
X-RateLimit-Reset: 1731614460
```
If a client exceeds their tier quota, Stream API responds with HTTP 429:
When a quota is exceeded, Stream API returns HTTP `429`:
```json
{
"error": "Rate limit exceeded. Please retry in 32 seconds.",

View File

@@ -1,41 +1,34 @@
# Self-Hosting Stream API
<p class="page-description">Complete production self-hosting guide for Stream API: Docker, Node.js systemd, PM2, and Nginx reverse proxy configuration with SSE streaming support.</p>
<p class="page-description">Production self-hosting guide for Stream API using Docker, systemd, and Nginx with SSE streaming support.</p>
## Overview
Stream API is designed to be completely self-hostable on any Linux virtual private server (VPS), home server, or Docker container environment. Running your own instance gives you private access, eliminates shared IP rate limits, and allows you to tune worker concurrency to your hardware.
Stream API can be self-hosted on any Linux VPS, home server, or container environment. Self-hosting eliminates shared IP rate limits and allows custom worker tuning.
---
## Environment Variables
## Configuration
Configure your environment variables via a `.env` file in the project root:
Configure environment variables via a `.env` file in the project root:
| Variable | Required | Default | Description |
| :--- | :--- | :--- | :--- |
| `PORT` | Optional | `7860` | HTTP port on which the server binds. |
| `TMDB_API_KEY` | **Recommended** | `""` | The Movie Database v3 API key. Required for scrapers that resolve metadata via IMDb ID or episode titles. |
| `WORKER_COUNT` | Optional | `os.cpus().length` | Number of worker processes to fork in cluster mode. |
| `ENABLE_DEBUG_ROUTE` | Optional | `false` | Enables deep diagnostic traces at `/debug/:source`. Keep `false` in production. |
| `GA_MEASUREMENT_ID` | Optional | `""` | Google Analytics 4 Measurement ID for private usage telemetry. |
| `GA_API_SECRET` | Optional | `""` | Google Analytics 4 Measurement Protocol API Secret. |
| `FALLBACK_BASE` | Optional | `""` | Secondary Stream API instance URL used for failover redirects. |
| `IS_HF` | Optional | `false` | Enables HuggingFace Spaces compatibility constraints. |
- `PORT` *(number, optional)* — Bind port. Default: `7860`.
- `TMDB_API_KEY` *(string, recommended)* — TMDB v3 API key for metadata lookups.
- `WORKER_COUNT` *(number, optional)* — Number of cluster workers. Default: available CPU count.
- `ENABLE_DEBUG_ROUTE` *(boolean, optional)* — Enables `/debug/:source`. Keep `false` in production.
- `FALLBACK_BASE` *(string, optional)* — Secondary Stream API URL for failover redirects.
- `IS_HF` *(boolean, optional)* — Enables HuggingFace Spaces compatibility.
---
## Deployment Option 1: Docker (Recommended)
### 1. Dockerfile
Create a `Dockerfile` in the project directory:
## Deployment Option 1: Docker
### Dockerfile
```dockerfile
FROM node:20-alpine
WORKDIR /app
# Install native dependencies required for TLS and encryption
RUN apk add --no-cache python3 make g++
COPY package*.json ./
@@ -49,9 +42,7 @@ EXPOSE 7860
CMD ["node", "server.js"]
```
### 2. Docker Compose
Create a `docker-compose.yml` file:
### Docker Compose
```yaml
version: '3.8'
@@ -76,28 +67,23 @@ services:
max-file: "3"
```
Start the container in detached mode:
Start the container:
```bash
docker compose up -d
```
---
## Deployment Option 2: Direct Node.js & Systemd
## Deployment Option 2: Systemd
### 1. Installation
### 1. Install
```bash
# Clone the repository
git clone https://gitlab.com/vyla-entertainment/stream-api.git /opt/stream-api
cd /opt/stream-api
# Install dependencies
npm ci --omit=dev
```
### 2. Create Systemd Service
Create `/etc/systemd/system/stream-api.service`:
### 2. Service File: `/etc/systemd/system/stream-api.service`
```ini
[Unit]
Description=Vyla Stream API Service
@@ -115,7 +101,6 @@ Environment=PORT=7860
Environment=TMDB_API_KEY=your_tmdb_api_key_here
Environment=WORKER_COUNT=4
# Security Hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
@@ -124,7 +109,7 @@ ProtectSystem=full
WantedBy=multi-user.target
```
Enable and start the service:
Enable and start:
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now stream-api
@@ -133,34 +118,30 @@ sudo systemctl status stream-api
---
## Reverse Proxy: Nginx Configuration
## Reverse Proxy: Nginx
Because Stream API utilizes **Server-Sent Events (SSE)** and large **HLS video streams**, your reverse proxy must disable proxy buffering. Standard buffering will delay SSE events until the buffer fills, breaking progressive playback.
Disable proxy buffering so Server-Sent Events (SSE) stream progressively to clients.
Create an Nginx configuration at `/etc/nginx/sites-available/stream-api.conf`:
Create `/etc/nginx/sites-available/stream-api.conf`:
```nginx
server {
server_name stream-api.yourdomain.com;
# Maximum upload size for DB syncs
client_max_body_size 20M;
location / {
proxy_pass http://127.0.0.1:7860;
proxy_http_version 1.1;
# Mandatory for Server-Sent Events (SSE)
proxy_set_header Connection '';
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding off;
# Keep-Alive & Timeouts for long media streams
proxy_read_timeout 90s;
proxy_send_timeout 90s;
# Forward Client Identifiers for Geo-Token Verification
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@@ -171,24 +152,20 @@ server {
}
```
Enable the configuration and obtain a free SSL certificate via Certbot:
Enable and provision SSL:
```bash
sudo ln -s /etc/nginx/sites-available/stream-api.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
# Install Let's Encrypt SSL
sudo certbot --nginx -d stream-api.yourdomain.com
```
---
## Verifying Your Deployment
## Health Check
Once deployed, verify the installation by testing the `/health` endpoint:
Verify the deployment:
```bash
curl -i https://stream-api.yourdomain.com/health
```
You should receive an HTTP 200 (or 207) with JSON detailing the cluster status, cache count, and source probe results.

View File

@@ -6,62 +6,53 @@
## Overview
**Stream API** is the dedicated backend gateway for the Vyla ecosystem. While the Vyla SDK executes directly in Node.js environments, web browsers, mobile applications, and smart TVs require a standard HTTP/SSE bridge to communicate with upstream providers, circumvent browser CORS restrictions, and decrypt video streams.
**Stream API** is the streaming gateway for the Vyla ecosystem. While the Vyla SDK executes directly in Node.js, browsers, mobile devices, and TVs require an HTTP/SSE bridge to communicate with scrapers, bypass browser CORS, and decrypt video streams.
Stream API wraps `@vyla-entertainment/sdk` in a high-concurrency, self-hostable service designed for maximum throughput and zero playback stutter.
Stream API wraps `@vyla-entertainment/sdk` in a high-concurrency service built for real-time progressive playback.
---
## Architectural Highlights
## Core Capabilities
| Cluster Role | Process Type | Responsibilities & Functions |
| :--- | :--- | :--- |
| **Primary Process** | Node.js Cluster Master | Spawns and supervises worker processes across CPU cores, manages the shared 1,500-entry in-memory LRU cache (5-minute TTL), coordinates IPC messages (`cache:get` / `cache:set`), and executes cache cleanup every 30 seconds. |
| **Inter-Process Channel** | Node.js IPC | High-throughput bi-directional message pipe (`process.send` and `cluster.on('message')`) synchronizing cache entries across workers without Redis or external database overhead. |
| **Worker Processes** | Forked HTTP Workers (`0..N`) | Runs native HTTP request routers (`http.createServer`), pushes progressive Server-Sent Events (SSE), executes universal reverse proxying with live M3U8/key rewriting, and strips 120-byte image obfuscation masks. |
### Multi-Core Cluster
Stream API uses Node's native `cluster` module to fork workers across all available CPU cores. If an upstream network timeout occurs on one worker, other workers continue handling client traffic without interruption.
### 1. Multi-Core Cluster Architecture
Stream API leverages Node's native `cluster` module to fork independent worker processes across available CPU cores. If one worker experiences a heavy upstream network timeout, other workers continue handling client requests without interruption.
### Progressive Server-Sent Events (SSE)
Instead of waiting 20 seconds for all 60 scrapers to finish:
- **Instant Metadata**: Title info and subtitles arrive in the first `meta` event.
- **Progressive Sources**: Each verified source is pushed immediately as a `source` event.
- **Clean Finish**: A `done` event signals stream completion.
### 2. Progressive Streaming over Server-Sent Events (SSE)
Rather than blocking HTTP requests for 20 seconds while 60 providers resolve, Stream API utilizes Server-Sent Events:
- **Instant Metadata**: Title info and subtitle tracks arrive in the first event (`type: "meta"`).
- **Progressive Sources**: As each provider scraper finishes verification, a `type: "source"` event is pushed immediately.
- **Completion Signal**: When all sources complete, a `type: "done"` event closes the stream cleanly.
### Shared In-Memory Cache
- **Capacity**: 1,500 entries with LRU eviction.
- **TTL**: 5 minutes (300,000 ms).
- **Lookup Latency**: < 2 ms for active titles.
### 3. Shared In-Memory LRU Cache
All cluster workers communicate with a centralized in-memory cache managed by the primary process:
- **Cache TTL**: 5 minutes (300,000 ms).
- **Capacity**: 1,500 items max with LRU eviction.
- **Cache Hit Latency**: < 2 milliseconds for frequently requested titles.
### 4. Reverse Proxy & Chunk De-Obfuscator
- Transparently proxies HLS playlists (`/api?url=...`), rewriting AES encryption keys and `.ts` chunk URIs to inject permissive CORS headers.
- Strips 120-byte fake image headers prepended to video chunks by ByteDance/TikTok-based content delivery networks.
- Supports HTTP Range headers (`206 Partial Content`) for seeking large MP4 and MKV media containers.
### Reverse Proxy & Chunk Stripper
- Proxies HLS playlists (`/api?url=...`), rewriting AES encryption keys and `.ts` chunk URIs to inject permissive CORS headers.
- Strips 120-byte fake image headers prepended to video chunks by ByteDance and TikTok-based CDNs.
- Supports HTTP Range requests (`206 Partial Content`) for seeking MP4 and MKV containers.
---
## Route Overview
## Key Routes
| Route | Protocol | Primary Purpose | Reference |
| :--- | :--- | :--- | :--- |
| **`/movie?id=:id`** | GET (SSE) | Progressive movie source resolution | [Paths Reference](/stream-api/reference/paths) |
| **`/tv?id=:id&season=:s&episode=:e`** | GET (SSE) | Progressive TV episode source resolution | [Paths Reference](/stream-api/reference/paths) |
| **`/subtitles/movie/:id`** | GET (REST) | Multi-language subtitle tracks for movies | [Media Data Reference](/stream-api/reference/media-data) |
| **`/subtitles/tv/:id/:s/:e`** | GET (REST) | Subtitle tracks for TV episodes | [Media Data Reference](/stream-api/reference/media-data) |
| **`/downloads/movie/:id`** | GET (REST) | Direct media download packages for movies | [Media Data Reference](/stream-api/reference/media-data) |
| **`/downloads/tv/:id/:s/:e`** | GET (REST) | Direct media download packages for TV | [Media Data Reference](/stream-api/reference/media-data) |
| **`/api?url=:url`** | GET (Proxy) | Universal HLS & video chunk proxy | [Paths Reference](/stream-api/reference/paths) |
| **`/health`** | GET (REST) | Cluster status, cache size, source health | [Operations Reference](/stream-api/reference/operations) |
| **`/test/:source`** | GET (REST) | Direct test harness for individual sources | [Operations Reference](/stream-api/reference/operations) |
- `GET /movie?id=:id` — Progressive movie source resolution via SSE. [Docs](/stream-api/reference/paths)
- `GET /tv?id=:id&season=:s&episode=:e` — Progressive TV episode source resolution via SSE. [Docs](/stream-api/reference/paths)
- `GET /api?url=:url` — Universal HLS and video chunk reverse proxy. [Docs](/stream-api/reference/paths)
- `GET /subtitles/movie/:id` — Multi-language subtitle tracks for movies. [Docs](/stream-api/reference/media-data)
- `GET /subtitles/tv/:id/:s/:e` — Subtitle tracks for TV episodes. [Docs](/stream-api/reference/media-data)
- `GET /downloads/movie/:id` — Direct media download packages for movies. [Docs](/stream-api/reference/media-data)
- `GET /downloads/tv/:id/:s/:e` — Direct media download packages for TV. [Docs](/stream-api/reference/media-data)
- `GET /health` — Cluster status, cache metrics, and scraper health. [Docs](/stream-api/reference/operations)
- `GET /test/:source` — Direct test harness for individual scrapers. [Docs](/stream-api/reference/operations)
---
## Stream API Documentation Index
## Documentation Sections
- **[Paths & Playback Events](/stream-api/reference/paths)**: Complete SSE payload contracts, parameters, and proxy options.
- **[Subtitles & Media Downloads](/stream-api/reference/media-data)**: REST endpoints for subtitle extraction and direct media files.
- **[Operations, Health & Testing](/stream-api/reference/operations)**: Cluster health monitoring, probe IDs, and debug routes.
- **[API Keys & Authentication](/stream-api/authentication)**: Key management, SQLite database, and partner keys.
- **[Production Self-Hosting Guide](/stream-api/deployment/self-hosting)**: Docker containerization, PM2, systemd, and Nginx reverse proxy configurations.
- **[Subtitles & Media Downloads](/stream-api/reference/media-data)**: REST endpoints for subtitle extraction and direct downloads.
- **[Operations & Health](/stream-api/reference/operations)**: Cluster monitoring, probe IDs, and debug routes.
- **[API Keys & Authentication](/stream-api/authentication)**: Key management, SQLite database, and rate limiting.
- **[Self-Hosting Guide](/stream-api/deployment/self-hosting)**: Docker containerization, PM2, and Nginx reverse proxy setup.

View File

@@ -4,25 +4,22 @@
## Subtitle Endpoints
Stream API provides dedicated REST endpoints to fetch subtitle tracks independently from video streams. Subtitles are discovered and parsed into web-standard `.vtt` or `.srt` formats.
Retrieve subtitle tracks independently from video streams in `.vtt` or `.srt` formats.
---
### 1. Movie Subtitles
### 1. Movie Subtitles: `GET /subtitles/movie/:id`
```http
GET /subtitles/movie/:id HTTP/1.1
Host: your-api.example.com
GET /subtitles/movie/155 HTTP/1.1
Host: api.vyla.cc
```
#### Path Parameters
| Parameter | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| `id` | `integer` | Required | Numeric TMDB Movie ID (e.g. `155`) |
**Parameters:**
- `id` *(number, required)* — TMDB Movie ID (e.g. `155`).
#### Example Request & Response
```bash
curl https://your-api.example.com/subtitles/movie/155
curl https://api.vyla.cc/subtitles/movie/155
```
```json
@@ -30,21 +27,15 @@ curl https://your-api.example.com/subtitles/movie/155
"subtitles": [
{
"label": "English",
"file": "https://your-api.example.com/api?url=https%3A%2F%2Fsubtitles.org%2Fen.vtt",
"file": "https://api.vyla.cc/api?url=https%3A%2F%2Fsubtitles.org%2Fen.vtt",
"type": "vtt",
"source": "opensubtitles"
},
{
"label": "Spanish",
"file": "https://your-api.example.com/api?url=https%3A%2F%2Fsubtitles.org%2Fes.vtt",
"file": "https://api.vyla.cc/api?url=https%3A%2F%2Fsubtitles.org%2Fes.vtt",
"type": "vtt",
"source": "opensubtitles"
},
{
"label": "French",
"file": "https://your-api.example.com/api?url=https%3A%2F%2Fsubtitles.org%2Ffr.srt",
"type": "srt",
"source": "subdl"
}
]
}
@@ -52,41 +43,37 @@ curl https://your-api.example.com/subtitles/movie/155
---
### 2. Television Episode Subtitles
### 2. Television Episode Subtitles: `GET /subtitles/tv/:id/:season/:episode`
```http
GET /subtitles/tv/:id/:season/:episode HTTP/1.1
Host: your-api.example.com
GET /subtitles/tv/1396/1/1 HTTP/1.1
Host: api.vyla.cc
```
#### Path Parameters
| Parameter | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| `id` | `integer` | Required | Numeric TMDB TV Series ID (e.g. `1396`) |
| `season` | `integer` | Required | Season number (e.g. `1`) |
| `episode` | `integer` | Required | Episode number (e.g. `1`) |
**Parameters:**
- `id` *(number, required)* — TMDB Series ID (e.g. `1396`).
- `season` *(number, required)* — Season number (e.g. `1`).
- `episode` *(number, required)* — Episode number (e.g. `1`).
#### Example Request
```bash
curl https://your-api.example.com/subtitles/tv/1396/1/1
curl https://api.vyla.cc/subtitles/tv/1396/1/1
```
---
## Download Endpoints
## Direct Download Endpoints
Stream API resolves high-speed direct media download packages and torrent/debrid links. Download lookups are separated from playback streams to allow offline caching or background download managers.
Fetch direct video files and torrent/debrid download packages.
---
### 1. Movie Downloads
### 1. Movie Downloads: `GET /downloads/movie/:id`
```http
GET /downloads/movie/:id HTTP/1.1
Host: your-api.example.com
GET /downloads/movie/155 HTTP/1.1
Host: api.vyla.cc
```
#### Example Response
```json
{
"downloads": [
@@ -95,14 +82,14 @@ Host: your-api.example.com
"size": 2450882194,
"type": "mkv",
"active": true,
"url": "https://fast-cdn.example.com/download/the-dark-knight-1080p.mkv"
"url": "https://cdn.example.com/download/the-dark-knight-1080p.mkv"
},
{
"quality": "720p",
"size": 1150428190,
"type": "mkv",
"active": true,
"url": "https://fast-cdn.example.com/download/the-dark-knight-720p.mkv"
"url": "https://cdn.example.com/download/the-dark-knight-720p.mkv"
}
]
}
@@ -110,14 +97,13 @@ Host: your-api.example.com
---
### 2. Television Episode Downloads
### 2. Television Episode Downloads: `GET /downloads/tv/:id/:season/:episode`
```http
GET /downloads/tv/:id/:season/:episode HTTP/1.1
Host: your-api.example.com
GET /downloads/tv/1396/1/1 HTTP/1.1
Host: api.vyla.cc
```
#### Example Response
```json
{
"downloads": [
@@ -126,7 +112,7 @@ Host: your-api.example.com
"size": 1420882194,
"type": "mkv",
"active": true,
"url": "https://fast-cdn.example.com/download/breaking-bad-s01e01-1080p.mkv"
"url": "https://cdn.example.com/download/breaking-bad-s01e01-1080p.mkv"
}
]
}
@@ -134,8 +120,8 @@ Host: your-api.example.com
---
## Best Practices for Clients
## Client Integration Notes
1. **Do Not Block Initial Playback**: Initiate subtitle and download queries asynchronously. The video player should start playback immediately on the first candidate stream, and subtitles should be attached dynamically as they arrive.
2. **CORS Handling**: Subtitle files proxied through `/api?url=...` are served with `Access-Control-Allow-Origin: *`, ensuring HTML5 `<track>` elements load cleanly in cross-origin browser contexts.
3. **Format Support**: While most modern players prefer `.vtt`, some tracks are returned in `.srt`. If your player strictly requires WebVTT, convert SRT timestamps (`00:01:20,500` -> `00:01:20.500`) client-side before loading.
- **Non-blocking Loading**: Fetch subtitles in the background while video playback begins immediately on the first candidate stream.
- **CORS Permissive**: Subtitle tracks proxied through `/api?url=...` include `Access-Control-Allow-Origin: *`, allowing HTML5 `<track>` elements to render in any browser context.
- **Format Conversion**: If your web player requires WebVTT, convert SRT commas to dots (`00:01:20,500` -> `00:01:20.500`) client-side before loading.

View File

@@ -2,23 +2,22 @@
<p class="page-description">Monitoring, cluster diagnostics, live health probing, and testing endpoints in Stream API.</p>
## The Health Check Endpoint: `GET /health`
## Health Check: `GET /health`
Stream API provides an automated health probe endpoint that executes live responsiveness checks across all registered scraper modules.
Runs responsiveness checks across registered scraper modules.
```http
GET /health HTTP/1.1
Host: your-api.example.com
Host: api.vyla.cc
```
### Response Status Codes
- **`200 OK`**: All active provider sources passed their health probes.
- **`207 Multi-Status`**: One or more providers failed their probes (degraded state), but the API gateway remains functional.
### Status Codes
- `200 OK`: All active scrapers passed their health probes.
- `207 Multi-Status`: One or more providers failed (degraded state), but the gateway is functional.
### Example Response Payload
### Response Payload
```json
{
"note": "This is a health check endpoint. This is extremely unreliable, be sure to test sources directly.",
"status": "ok",
"timestamp": "2026-11-14T20:30:00.000Z",
"tmdb": true,
@@ -33,33 +32,31 @@ Host: your-api.example.com
}
```
#### Response Fields
| Field | Type | Description |
| :--- | :--- | :--- |
| `status` | `string` | Overall system state (`"ok"` or `"degraded"`). |
| `timestamp` | `string` | ISO 8601 timestamp of probe completion. |
| `tmdb` | `boolean` | `true` if `TMDB_API_KEY` is configured and valid in the environment. |
| `cache` | `integer` | Current number of active cached titles in the primary LRU cache. |
| `probe_id` | `integer` | The standard TMDB ID used to probe source responsiveness. |
| `sources` | `object` | Dictionary of per-source availability (`ok`) and roundtrip latency in milliseconds (`ms`). |
**Key Fields:**
- `status`: Overall state (`"ok"` or `"degraded"`).
- `timestamp`: ISO 8601 probe timestamp.
- `tmdb`: True if `TMDB_API_KEY` is configured and responding.
- `cache`: Current number of active cached titles in LRU memory.
- `probe_id`: The TMDB ID used for the probe query.
- `sources`: Dictionary of per-source availability (`ok`) and roundtrip latency in milliseconds (`ms`).
---
## Direct Source Testing: `GET /test/:source`
To test an individual scraper directly without querying all 60 providers:
Tests a single scraper directly without triggering all other providers:
```http
GET /test/vidlink?id=155 HTTP/1.1
```
For television episodes, pass season and episode query parameters:
For television episodes, include season and episode:
```http
GET /test/vixsrc?id=1396&s=1&e=1 HTTP/1.1
```
### Response
Returns the raw resolved candidate object directly from the provider scraper:
Returns the raw candidate stream resolved by that scraper:
```json
{
@@ -75,33 +72,28 @@ Returns the raw resolved candidate object directly from the provider scraper:
## Deep Debug Route: `GET /debug/:source`
When `ENABLE_DEBUG_ROUTE=true` is set in your environment variables, Stream API exposes a comprehensive diagnostic route:
Exposes diagnostic internals when `ENABLE_DEBUG_ROUTE=true` is set:
```http
GET /debug/vidlink?id=155 HTTP/1.1
```
### Diagnostic Output Includes:
1. **Raw Scraper Payload**: Unmodified JSON or HTML received from the upstream host.
2. **Extraction Timings**: Milliseconds spent parsing DOM, solving tokens, and resolving URLs.
3. **Phase 1 Verification**: Status code, response headers, and latency of the `HEAD` request.
4. **Phase 2 Verification**: First 500 bytes of the master M3U8 playlist and test chunk fetch status.
5. **Rewritten URLs**: Preview of how chunk URIs will be rewritten by the proxy.
**Output details:**
- Raw HTML or JSON received from upstream hosts.
- Time spent solving tokens and parsing DOM.
- Status code and headers from Phase 1 verification (`HEAD` check).
- First 500 bytes of the master M3U8 manifest.
- Preview of rewritten segment URLs.
:::callout-warning
**Security Note**: Keep `ENABLE_DEBUG_ROUTE=false` in public production environments to avoid leaking internal scraper tokens or upstream endpoints.
Keep `ENABLE_DEBUG_ROUTE=false` in production to prevent leaking upstream tokens or credentials.
:::
---
## Cluster & Cache Architecture
### Primary Supervisor & Worker Pool Architecture
- **Central In-Memory Cache**: Holds up to 1,500 verified title entries in a shared LRU table with a 5-minute TTL.
- **Periodic Pruner**: Runs every 30 seconds to clean expired keys and enforce memory ceilings.
- **Worker Lifecycle Supervisor**: Spawns and supervises $N$ worker processes matching CPU core count, automatically restarting terminated workers.
- **IPC Message Dispatcher**: Routes `cache:get` and `cache:set` messages between worker threads and the primary process.
1. **IPC Cache Synchronization**: When a worker resolves a title, it sends a `cache:set` message to the primary process. When another worker receives a request for the same title, it sends a `cache:get` message and receives an instant `cache:hit` without re-scraping upstream hosts.
2. **Cache Pruning**: The primary process evicts stale items older than 300,000ms (5 minutes). If total cache size exceeds 1,500 items, the oldest entries are evicted immediately.
3. **Worker Auto-Restart**: If a worker process exits unexpectedly or exceeds memory limits, the primary cluster supervisor automatically spawns a replacement worker.
- **In-Memory Cache**: Up to 1,500 verified titles stored in an LRU cache with a 5-minute TTL.
- **Cache Pruner**: Runs every 30 seconds to evict expired keys.
- **Worker Lifecycle**: The supervisor process maintains workers matching CPU core count, automatically replacing crashed processes.
- **IPC Messaging**: Workers coordinate via `cache:get` and `cache:set` messages, allowing instant cache hits across worker boundaries without an external database.

View File

@@ -1,55 +1,51 @@
# Paths & Playback Events
<p class="page-description">Detailed API reference for Stream API streaming endpoints, Server-Sent Events contracts, and proxy query parameters.</p>
<p class="page-description">API reference for Stream API endpoints, Server-Sent Events contracts, and proxy query parameters.</p>
## Progressive Playback Endpoints
Stream API uses Server-Sent Events (SSE) to deliver real-time discovery events directly to player clients. This eliminates long HTTP timeouts and allows players to begin buffering the moment the first candidate resolves.
Stream API uses Server-Sent Events (SSE) so players can start buffering as soon as the first candidate source is verified.
---
### 1. Movie Stream Endpoint: `GET /movie` (or `/api/movie`)
### 1. Movie Stream: `GET /movie`
Establishes an SSE event stream for a movie.
Establishes an SSE stream for a movie.
```http
GET /movie?id=155 HTTP/1.1
Host: your-api.example.com
Host: api.vyla.cc
Accept: text/event-stream
```
#### Query Parameters
| Parameter | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `id` | `integer` | Required | Numeric TMDB Movie ID | `155` (The Dark Knight) |
**Parameters:**
- `id` *(number, required)* — Numeric TMDB Movie ID (e.g. `155` for The Dark Knight).
---
### 2. Television Stream Endpoint: `GET /tv` (or `/api/tv`)
### 2. TV Series Stream: `GET /tv`
Establishes an SSE event stream for a television series episode.
Establishes an SSE stream for a television series episode.
```http
GET /tv?id=1396&season=1&episode=1 HTTP/1.1
Host: your-api.example.com
Host: api.vyla.cc
Accept: text/event-stream
```
#### Query Parameters
| Parameter | Type | Required | Description | Example |
| :--- | :--- | :--- | :--- | :--- |
| `id` | `integer` | Required | Numeric TMDB TV Series ID | `1396` (Breaking Bad) |
| `season` | `integer` | Required | Season number | `1` |
| `episode` | `integer` | Required | Episode number | `1` |
**Parameters:**
- `id` *(number, required)* — Numeric TMDB TV Series ID (e.g. `1396` for Breaking Bad).
- `season` *(number, required)* — Season number (e.g. `1`).
- `episode` *(number, required)* — Episode number (e.g. `1`).
---
## Server-Sent Events (SSE) Contract
## SSE Event Lifecycle
Connections to `/movie` and `/tv` return `Content-Type: text/event-stream` and emit events sequentially:
Connections return `Content-Type: text/event-stream` and emit events in sequence:
### Event 1: `meta` (Emitted Immediately)
Delivers title metadata and parsed subtitle tracks while scrapers are still running.
### Event 1: `meta`
Sent immediately with title metadata and subtitle tracks while scrapers are still running.
```json
data: {
@@ -59,13 +55,13 @@ data: {
"year": 2008,
"tmdb_id": 155,
"imdb_id": "tt0468569",
"poster": "https://image.tmdb.org/t/p/w500/...",
"backdrop": "https://image.tmdb.org/t/p/original/..."
"poster": "https://image.tmdb.org/t/p/w500/sample.jpg",
"backdrop": "https://image.tmdb.org/t/p/original/sample.jpg"
},
"subtitles": [
{
"label": "English",
"file": "https://your-api.example.com/api?url=...",
"file": "https://api.vyla.cc/api?url=https%3A%2F%2Fsubtitles.org%2Fen.vtt",
"type": "vtt",
"source": "opensubtitles"
}
@@ -73,15 +69,15 @@ data: {
}
```
### Event 2..N: `source` (Emitted Progressively)
Emitted as each provider scraper successfully resolves and passes two-phase verification.
### Event 2..N: `source`
Emitted progressively as each provider scraper completes two-phase verification.
```json
data: {
"type": "source",
"source": "vidlink",
"label": "VidLink Primary",
"url": "https://your-api.example.com/api?url=https%3A%2F%2Fupstream.cdn%2Fmaster.m3u8&vl=1",
"url": "https://api.vyla.cc/api?url=https%3A%2F%2Fupstream.cdn%2Fmaster.m3u8&vl=1",
"server": "vidlink-cf",
"quality": "1080p",
"type": "hls",
@@ -92,8 +88,8 @@ data: {
}
```
### Event Final: `done` (Stream Closes)
Emitted when all enabled scrapers have finished resolving or reached their maximum timeout. The server closes the SSE connection immediately after.
### Event Final: `done`
Emitted when all enabled scrapers have finished or timed out. The server closes the SSE connection immediately after.
```json
data: {
@@ -104,34 +100,30 @@ data: {
---
## The Universal Reverse Proxy: `GET /api`
## Media Reverse Proxy: `GET /api`
The `/api` route handles media proxying, M3U8 rewriting, segment stripping, and TMDB queries.
### 1. Media Proxying: `/api?url=:encoded_url`
The `/api` route handles media proxying, M3U8 playlist rewriting, header spoofing, and byte stripping.
```http
GET /api?url=https%3A%2F%2Fcdn.example.com%2Fvideo.m3u8&proxyHeaders=%7B%22Referer%22%3A%22https%3A%2F%2Fsite.com%22%7D HTTP/1.1
GET /api?url=https%3A%2F%2Fcdn.example.com%2Fvideo.m3u8&vl=1 HTTP/1.1
```
#### Query Parameters
| Parameter | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| `url` (or `proxy`) | `string` | Required | URL-encoded destination target. |
| `proxyHeaders` | `string` | Optional | URL-encoded JSON dictionary of custom headers to forward upstream. |
| `<source_flag>` | `string` | Optional | Provider flag matching `proxyParam` (e.g. `&vl=1`, `&vx=1`) to apply source-specific referer rules. |
| `tt` | `string` | Optional | Forces the 120-byte image de-masking routine on MPEG-TS video chunks. |
**Parameters:**
- `url` *(string, required)* — URL-encoded target URL to fetch.
- `proxyHeaders` *(string, optional)* — URL-encoded JSON object of custom headers to forward.
- `<source_flag>` *(string, optional)* — Source flag matching configuration (e.g. `&vl=1`, `&vx=1`) to apply source-specific referer rules.
- `tt` *(string, optional)* — Forces the 120-byte image header stripping routine on MPEG-TS video chunks.
#### Proxy Behaviors
- **M3U8 Playlists**: Rewrites all `.ts` chunk lines and AES `#EXT-X-KEY` URIs so that player requests route through the proxy with permissive CORS headers.
- **Obfuscated Chunks**: If chunks begin with PNG (`0x89`), JPEG (`0xFF`), or null (`0x00`) fake headers, Stream API automatically slices off the leading 120 bytes.
- **Range Seeking**: Forwards `Range: bytes=start-end` headers to upstream servers and returns HTTP `206 Partial Content`, enabling smooth scrubbing in MP4/MKV media.
**Proxy Features:**
- **M3U8 Rewriting**: Rewrites all `.ts` chunk URIs and `#EXT-X-KEY` AES encryption endpoints to route through the proxy with CORS headers (`Access-Control-Allow-Origin: *`).
- **Obfuscation Stripping**: Slices off the 120-byte image header if chunks start with PNG (`0x89`), JPEG (`0xFF`), or null (`0x00`) bytes.
- **Range Seeking**: Forwards `Range: bytes=start-end` headers and returns HTTP `206 Partial Content` for video seeking.
---
### 2. Active Sources Listing: `/api?sources_meta=1`
## Active Sources Listing: `GET /api?sources_meta=1`
Returns the list of active streaming sources currently loaded into the instance:
Returns all provider scrapers currently loaded into the instance:
```json
{
@@ -145,12 +137,10 @@ Returns the list of active streaming sources currently loaded into the instance:
---
## HTTP Status Codes & Error Responses
## HTTP Status Codes
| Status Code | Description | Example Payload |
| :--- | :--- | :--- |
| **`200 OK`** | Request succeeded or SSE stream opened | `text/event-stream` or JSON payload |
| **`206 Partial Content`** | Byte-range media response for video scrubbing | Binary video stream chunk |
| **`400 Bad Request`** | Missing required parameters or invalid TMDB ID | `{"error": "missing id", "route": "/movie?id=:tmdb_id"}` |
| **`404 Not Found`** | Unknown route | `{"error": "not found"}` |
| **`502 Bad Gateway`** | Upstream provider connection failed or timed out | `{"error": "upstream connection timeout"}` |
- `200 OK` — Request succeeded or SSE stream opened.
- `206 Partial Content` — Byte-range media response for video scrubbing.
- `400 Bad Request` — Missing parameters or invalid ID (`{"error": "missing id"}`).
- `404 Not Found` — Unknown route (`{"error": "not found"}`).
- `502 Bad Gateway` — Upstream provider connection failed or timed out.