mirror of
https://gitlab.com/vyla-entertainment/documentation.git
synced 2026-11-14 22:47:26 -05:00
huge rewrite
This commit is contained in:
125
stream-api/authentication/index.md
Normal file
125
stream-api/authentication/index.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# API Keys & Authentication
|
||||
|
||||
<p class="page-description">Managing API keys, rate limits, SQLite database synchronization, and authorization headers in Stream API.</p>
|
||||
|
||||
## 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.
|
||||
|
||||
---
|
||||
|
||||
## Key Structure & Prefixes
|
||||
|
||||
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 |
|
||||
|
||||
---
|
||||
|
||||
## Generating API Keys via CLI
|
||||
|
||||
The Stream API repository includes a CLI tool (`add-key.mjs`) to generate and insert keys into the active SQLite database:
|
||||
|
||||
```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
|
||||
```
|
||||
Generated Key: sk_8f14b2d39a7e4c5b10e9f8a7b6c5d4e3
|
||||
Type: standard
|
||||
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
|
||||
|
||||
For automated deployments or bulk key management, you can export the database to a JSON file:
|
||||
|
||||
### 1. Export Database
|
||||
```bash
|
||||
node export-db.mjs
|
||||
```
|
||||
This dumps the active SQLite database tables into `db.json`:
|
||||
```json
|
||||
{
|
||||
"keys": [
|
||||
{
|
||||
"key": "sk_8f14b2d39a7e4c5b10e9f8a7b6c5d4e3",
|
||||
"type": "standard",
|
||||
"limit": 500,
|
||||
"client": "my-desktop-client",
|
||||
"active": 1,
|
||||
"created_at": "2026-11-14T12:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Modify and Re-Import
|
||||
Edit `db.json` to add, revoke, or modify limits, then commit the changes back to SQLite:
|
||||
```bash
|
||||
node update-db.mjs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Client Authorization Headers
|
||||
|
||||
Clients can authenticate requests by passing the key in one of the following locations:
|
||||
|
||||
### 1. Authorization Header (Recommended)
|
||||
```http
|
||||
GET /movie?id=155 HTTP/1.1
|
||||
Host: your-api.example.com
|
||||
Authorization: Bearer sk_8f14b2d39a7e4c5b10e9f8a7b6c5d4e3
|
||||
```
|
||||
|
||||
### 2. Custom API Key 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:
|
||||
```http
|
||||
GET /movie?id=155&key=sk_8f14b2d39a7e4c5b10e9f8a7b6c5d4e3 HTTP/1.1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rate Limit Headers
|
||||
|
||||
When requests are evaluated, Stream API returns standard rate-limiting headers:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
X-RateLimit-Limit: 500
|
||||
X-RateLimit-Remaining: 498
|
||||
X-RateLimit-Reset: 1731614460
|
||||
```
|
||||
|
||||
If a client exceeds their tier quota, Stream API responds with HTTP 429:
|
||||
```json
|
||||
{
|
||||
"error": "Rate limit exceeded. Please retry in 32 seconds.",
|
||||
"retry_after": 32
|
||||
}
|
||||
```
|
||||
@@ -1,121 +1,194 @@
|
||||
# Self-host Stream API
|
||||
# Self-Hosting Stream API
|
||||
|
||||
<p class="page-description">Deploy the optional Stream API when your clients need an HTTP/SSE layer.</p>
|
||||
<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>
|
||||
|
||||
## Overview
|
||||
|
||||
Stream API is a **self-hosted Node.js** application that you run on infrastructure you control. It does not provide a public hosted instance. The service runs as a Node.js process, uses in-memory caching, and can fork workers through Node's built-in `cluster` module. No database is required by the service itself.
|
||||
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.
|
||||
|
||||
:::callout-warning
|
||||
Stream API is self-hosted only. There is no public Vyla streaming endpoint. You only need it when your architecture requires an HTTP/SSE layer; Node.js applications can use [Vyla SDK](/sdk) directly.
|
||||
:::
|
||||
---
|
||||
|
||||
## Requirements
|
||||
## Environment Variables
|
||||
|
||||
- Node.js 18 or later
|
||||
- A TMDB API key if you want title validation and metadata lookups
|
||||
Configure your environment variables via a `.env` file in the project root:
|
||||
|
||||
## Environment variables
|
||||
| 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. |
|
||||
|
||||
Create a `.env` file in the project root:
|
||||
---
|
||||
|
||||
## Deployment Option 1: Docker (Recommended)
|
||||
|
||||
### 1. Dockerfile
|
||||
Create a `Dockerfile` in the project directory:
|
||||
|
||||
```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 ./
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
COPY . .
|
||||
|
||||
ENV PORT=7860
|
||||
EXPOSE 7860
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
### 2. Docker Compose
|
||||
Create a `docker-compose.yml` file:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
stream-api:
|
||||
build: .
|
||||
container_name: vyla-stream-api
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:7860:7860"
|
||||
environment:
|
||||
- PORT=7860
|
||||
- TMDB_API_KEY=your_tmdb_api_key_here
|
||||
- WORKER_COUNT=4
|
||||
- ENABLE_DEBUG_ROUTE=false
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
```
|
||||
|
||||
Start the container in detached mode:
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment Option 2: Direct Node.js & Systemd
|
||||
|
||||
### 1. Installation
|
||||
```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`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Vyla Stream API Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=www-data
|
||||
WorkingDirectory=/opt/stream-api
|
||||
ExecStart=/usr/bin/node /opt/stream-api/server.js
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
Environment=NODE_ENV=production
|
||||
Environment=PORT=7860
|
||||
Environment=TMDB_API_KEY=your_tmdb_api_key_here
|
||||
Environment=WORKER_COUNT=4
|
||||
|
||||
# Security Hardening
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=full
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Enable and start the service:
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now stream-api
|
||||
sudo systemctl status stream-api
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Reverse Proxy: Nginx Configuration
|
||||
|
||||
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.
|
||||
|
||||
Create an Nginx configuration at `/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;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
listen 80;
|
||||
}
|
||||
```
|
||||
|
||||
Enable the configuration and obtain a free SSL certificate via Certbot:
|
||||
```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
|
||||
|
||||
Once deployed, verify the installation by testing the `/health` endpoint:
|
||||
|
||||
```bash
|
||||
TMDB_API_KEY=
|
||||
PORT=7860
|
||||
WORKER_COUNT=1
|
||||
ENABLE_DEBUG_ROUTE=false
|
||||
PROXY_STREAMS=false
|
||||
PROXY_URL=
|
||||
|
||||
GA_MEASUREMENT_ID=
|
||||
GA_API_SECRET=
|
||||
curl -i https://stream-api.yourdomain.com/health
|
||||
```
|
||||
|
||||
<div class="card">
|
||||
<div class="card-title">Variable reference</div>
|
||||
<div class="card-body">
|
||||
|
||||
| Variable | Required | Description |
|
||||
| --- | --- | --- |
|
||||
| `TMDB_API_KEY` | Yes | Enables TMDB-based ID validation, metadata lookups, and anime detection. Some sources will not work without it. |
|
||||
| `GA_MEASUREMENT_ID` / `GA_API_SECRET` | No | Enables Google Analytics event reporting. Leave blank to disable. |
|
||||
| `PORT` | No | Port the server listens on. Defaults to `7860`. |
|
||||
| `WORKER_COUNT` | No | Number of cluster workers to fork. Defaults to `1` locally. |
|
||||
| `ENABLE_DEBUG_ROUTE` | No | Set to `true` to enable `/api/debug/:id`. Keep this `false` in production - it exposes upstream request/response headers and raw source output. |
|
||||
| `PROXY_STREAMS` | No | Set to `true` to route stream playback through your own server's `/api` proxy endpoint instead of direct URLs. |
|
||||
| `PROXY_URL` | No | An external proxy base URL to use instead of the built-in `/api` proxy. Only used if `PROXY_STREAMS` is enabled. |
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Installing and running
|
||||
|
||||
```bash
|
||||
git clone https://gitlab.com/vyla-entertainment/stream-api
|
||||
cd stream-api
|
||||
npm install
|
||||
node server.js
|
||||
```
|
||||
|
||||
The server listens on:
|
||||
|
||||
```
|
||||
http://localhost:7860
|
||||
```
|
||||
|
||||
Visit `/health` to confirm it is running and check which sources are currently reachable from your host.
|
||||
|
||||
## Running with multiple workers
|
||||
|
||||
Setting `WORKER_COUNT` above `1` forks additional worker processes via `cluster`.
|
||||
|
||||
The primary process holds a shared in-memory cache (capped at 1500 entries, pruned every 30 seconds) and relays cache reads/writes between workers over IPC, allowing cached stream results to be shared rather than duplicated.
|
||||
|
||||
```bash
|
||||
WORKER_COUNT=4
|
||||
node server.js
|
||||
```
|
||||
|
||||
Each worker independently loads source modules and handles outbound requests. Only shared cache operations and concurrency limits are coordinated through the primary process.
|
||||
|
||||
## Network considerations
|
||||
|
||||
Several sources are documented in `config.js` as blocked on datacenter IPs. This commonly affects cloud hosting providers and VPS environments.
|
||||
|
||||
If a source's `getStream` consistently returns nothing from your server but works from a residential connection, the cause is usually upstream blocking based on IP reputation. For the best experience, run Vyla API on a residential connection or use a residential proxy.
|
||||
|
||||
When running on a local desktop environment, you should have minimal issues with source availability since you're using a residential IP address.
|
||||
|
||||
## Reverse proxy / TLS
|
||||
|
||||
The server runs over plain HTTP. For public deployments, place it behind a reverse proxy such as Caddy, Nginx, or Cloudflare Tunnel to terminate TLS and forward requests to the configured `PORT`.
|
||||
|
||||
CORS is already configured at the application layer with:
|
||||
|
||||
```
|
||||
Access-Control-Allow-Origin: *
|
||||
```
|
||||
|
||||
No additional CORS configuration is required on the proxy.
|
||||
|
||||
## Verifying your deployment
|
||||
|
||||
Run these checks in order:
|
||||
|
||||
1. `GET /health`
|
||||
|
||||
Confirms the process is running and reports per-source reachability from your host.
|
||||
|
||||
2. `GET /api/test/155?source=vidrock`
|
||||
|
||||
Runs a real source resolution using a known TMDB movie ID and returns whether the source succeeded.
|
||||
|
||||
3. `GET /api/debug/155?source=vidrock`
|
||||
|
||||
Only available when `ENABLE_DEBUG_ROUTE=true`.
|
||||
|
||||
Returns request traces, headers, and raw candidate URLs for debugging source failures.
|
||||
|
||||
:::callout-warning
|
||||
Leave `ENABLE_DEBUG_ROUTE` disabled on public deployments. The debug route exposes upstream request information and raw stream URLs, which can leak internal details.
|
||||
:::
|
||||
You should receive an HTTP 200 (or 207) with JSON detailing the cluster status, cache count, and source probe results.
|
||||
|
||||
@@ -1,36 +1,67 @@
|
||||
# Stream API
|
||||
# Stream API Overview
|
||||
|
||||
<p class="page-description">An optional self-hosted HTTP and SSE layer built on top of Vyla SDK.</p>
|
||||
<p class="page-description">A self-hosted Node.js HTTP and Server-Sent Events (SSE) streaming gateway for progressive source discovery, HLS proxying, and subtitle extraction.</p>
|
||||
|
||||
## Use this only when HTTP is the right boundary
|
||||
<img class="vyla-banner" src="/src/assets/images/devices.webp" alt="Vyla Stream API infrastructure across client devices" loading="lazy" decoding="async" fetchpriority="low" />
|
||||
|
||||
Stream API packages Vyla SDK behind a small Node.js HTTP service. It is useful when a browser, mobile app, or another process needs progressive playback candidates over HTTP. It is not required to use Vyla, and it is not the primary integration for a Node.js application-use [Vyla SDK](/sdk) directly in that case.
|
||||
## Overview
|
||||
|
||||
The service accepts TMDB IDs, asks configured SDK providers for candidates, verifies results, and emits usable sources as they arrive. A player can start with the first source while retaining later sources as fallbacks.
|
||||
**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.
|
||||
|
||||
## What it provides
|
||||
Stream API wraps `@vyla-entertainment/sdk` in a high-concurrency, self-hostable service designed for maximum throughput and zero playback stutter.
|
||||
|
||||
| Capability | Endpoint family | Why it exists |
|
||||
| --- | --- | --- |
|
||||
| Progressive playback | `/movie`, `/tv` | Stream metadata and verified source candidates with SSE |
|
||||
| Supplemental media | `/subtitles`, `/downloads` | Fetch tracks or downloadable candidates separately |
|
||||
| Operations | `/health`, `/test`, `/debug` | Check source status and investigate a provider |
|
||||
---
|
||||
|
||||
## Start a local instance
|
||||
## Architectural Highlights
|
||||
|
||||
```bash
|
||||
git clone https://gitlab.com/vyla-entertainment/stream-api
|
||||
cd stream-api
|
||||
npm install
|
||||
TMDB_API_KEY=your_key
|
||||
node server.js
|
||||
```
|
||||
| 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. |
|
||||
|
||||
The default local address is `http://localhost:7860`. For remote access, place the service behind TLS and your own access controls. Full configuration is in [Self-hosting](/stream-api/deployment/self-hosting).
|
||||
### 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.
|
||||
|
||||
## Lifecycle of a playback request
|
||||
### 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.
|
||||
|
||||
1. A client opens `/movie?id=:tmdbId` or `/tv?id=:tmdbId&season=:season&episode=:episode`.
|
||||
2. The API returns an SSE response and emits a `meta` event with title metadata and subtitle tracks.
|
||||
3. Active SDK providers resolve in parallel; verified results arrive as individual `source` events.
|
||||
4. The server sends `done` after all source attempts finish or time out.
|
||||
### 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.
|
||||
|
||||
---
|
||||
|
||||
## Route Overview
|
||||
|
||||
| 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) |
|
||||
|
||||
---
|
||||
|
||||
## Stream API Documentation Index
|
||||
|
||||
- **[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.
|
||||
|
||||
@@ -1,54 +1,141 @@
|
||||
# Subtitles and downloads
|
||||
# Subtitles & Media Downloads
|
||||
|
||||
<p class="page-description">Unified media-data paths for movies and TV episodes.</p>
|
||||
<p class="page-description">REST API reference for retrieving subtitle tracks and direct media download packages for movies and television series.</p>
|
||||
|
||||
## Subtitle paths
|
||||
## Subtitle Endpoints
|
||||
|
||||
| Media | Path |
|
||||
| --- | --- |
|
||||
| Movie | `GET /subtitles/movie/:id` |
|
||||
| TV episode | `GET /subtitles/tv/:id/:season/:episode` |
|
||||
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.
|
||||
|
||||
The same routes are available under `/api/subtitles`. A successful response is a JSON array of tracks; a missing result returns `404` with an error object.
|
||||
---
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"label": "English",
|
||||
"file": "https://example.invalid/subtitles/en.vtt",
|
||||
"type": "vtt",
|
||||
"source": "v1"
|
||||
}
|
||||
]
|
||||
### 1. Movie Subtitles
|
||||
|
||||
```http
|
||||
GET /subtitles/movie/:id HTTP/1.1
|
||||
Host: your-api.example.com
|
||||
```
|
||||
|
||||
`file` is the track URL, `type` is normally `vtt` or `srt`, and `source` identifies the subtitle backend. Prefer the tracks included in the playback `meta` event when you are already opening a playback stream; use these paths when subtitles are fetched separately.
|
||||
#### Path Parameters
|
||||
| Parameter | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `id` | `integer` | Required | Numeric TMDB Movie ID (e.g. `155`) |
|
||||
|
||||
## Download paths
|
||||
|
||||
| Media | Path |
|
||||
| --- | --- |
|
||||
| Movie | `GET /downloads/movie/:id` |
|
||||
| TV episode | `GET /downloads/tv/:id/:season/:episode` |
|
||||
|
||||
The `/api/downloads` prefix is also supported. A successful response is an array; an empty array simply means no candidates were found.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"url": "https://example.invalid/file.mp4",
|
||||
"quality": "1080p",
|
||||
"size": "2.14 GB",
|
||||
"format": "MP4"
|
||||
}
|
||||
]
|
||||
#### Example Request & Response
|
||||
```bash
|
||||
curl https://your-api.example.com/subtitles/movie/155
|
||||
```
|
||||
|
||||
Download URLs are provider results, not durable Vyla-hosted files. Display quality and size as informational fields, and handle expired or unavailable links in your client.
|
||||
```json
|
||||
{
|
||||
"subtitles": [
|
||||
{
|
||||
"label": "English",
|
||||
"file": "https://your-api.example.com/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",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Request and response rules
|
||||
---
|
||||
|
||||
- IDs are TMDB IDs; TV paths additionally require season and episode numbers.
|
||||
- Both families return JSON, unlike the SSE playback paths.
|
||||
- Handle `404` for missing subtitles and `500` for an upstream or resolver failure.
|
||||
- Do not block first playback on either call. Fetch them in parallel or after the player has started.
|
||||
### 2. Television Episode Subtitles
|
||||
|
||||
```http
|
||||
GET /subtitles/tv/:id/:season/:episode HTTP/1.1
|
||||
Host: your-api.example.com
|
||||
```
|
||||
|
||||
#### 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`) |
|
||||
|
||||
#### Example Request
|
||||
```bash
|
||||
curl https://your-api.example.com/subtitles/tv/1396/1/1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
|
||||
---
|
||||
|
||||
### 1. Movie Downloads
|
||||
|
||||
```http
|
||||
GET /downloads/movie/:id HTTP/1.1
|
||||
Host: your-api.example.com
|
||||
```
|
||||
|
||||
#### Example Response
|
||||
```json
|
||||
{
|
||||
"downloads": [
|
||||
{
|
||||
"quality": "1080p",
|
||||
"size": 2450882194,
|
||||
"type": "mkv",
|
||||
"active": true,
|
||||
"url": "https://fast-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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Television Episode Downloads
|
||||
|
||||
```http
|
||||
GET /downloads/tv/:id/:season/:episode HTTP/1.1
|
||||
Host: your-api.example.com
|
||||
```
|
||||
|
||||
#### Example Response
|
||||
```json
|
||||
{
|
||||
"downloads": [
|
||||
{
|
||||
"quality": "1080p",
|
||||
"size": 1420882194,
|
||||
"type": "mkv",
|
||||
"active": true,
|
||||
"url": "https://fast-cdn.example.com/download/breaking-bad-s01e01-1080p.mkv"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices for Clients
|
||||
|
||||
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.
|
||||
|
||||
@@ -1,37 +1,107 @@
|
||||
# Health, testing, and safe operations
|
||||
# Operations, Health & Diagnostics
|
||||
|
||||
<p class="page-description">Observe SDK providers and diagnose a Stream API deployment without making debug data public.</p>
|
||||
<p class="page-description">Monitoring, cluster diagnostics, live health probing, and testing endpoints in Stream API.</p>
|
||||
|
||||
## Health
|
||||
## The Health Check Endpoint: `GET /health`
|
||||
|
||||
`GET /health` (or `/api/health`) probes active providers and returns a JSON summary. It includes a status, timestamp, TMDB-key presence, cache size, and a map of provider keys to `{ ok, ms }` results.
|
||||
Stream API provides an automated health probe endpoint that executes live responsiveness checks across all registered scraper modules.
|
||||
|
||||
Health is a signal, not a promise of playback. Provider behavior can differ by title, client network, and the moment of the request. Use it for observability and source selection-not as a guarantee that a viewer will receive a stream.
|
||||
|
||||
## Test one provider
|
||||
|
||||
`GET /test/:id?source=:providerKey` resolves a single provider for a movie. Add `season` and `episode` (or `s` and `e`) for TV.
|
||||
|
||||
```bash
|
||||
curl "YOUR_API_URL/test/155?source=provider-key"
|
||||
curl "YOUR_API_URL/test/1396?season=1&episode=1&source=provider-key"
|
||||
```http
|
||||
GET /health HTTP/1.1
|
||||
Host: your-api.example.com
|
||||
```
|
||||
|
||||
Use source keys reported by the running deployment. A test result reports whether resolution and verification succeeded; clients should inspect the result body rather than relying only on a transport success.
|
||||
### 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.
|
||||
|
||||
## Debug route
|
||||
### Example 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,
|
||||
"cache": 142,
|
||||
"probe_id": 155,
|
||||
"sources": {
|
||||
"vidlink": { "ok": true, "ms": 420 },
|
||||
"vixsrc": { "ok": true, "ms": 610 },
|
||||
"cinecat": { "ok": true, "ms": 890 },
|
||||
"movy": { "ok": false, "ms": null }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`GET /debug/:id?source=:providerKey` offers detailed candidate and request traces, but it is only available when `ENABLE_DEBUG_ROUTE=true`.
|
||||
#### 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`). |
|
||||
|
||||
---
|
||||
|
||||
## Direct Source Testing: `GET /test/:source`
|
||||
|
||||
To test an individual scraper directly without querying all 60 providers:
|
||||
|
||||
```http
|
||||
GET /test/vidlink?id=155 HTTP/1.1
|
||||
```
|
||||
|
||||
For television episodes, pass season and episode query parameters:
|
||||
```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:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "vidlink",
|
||||
"url": "https://upstream.example.com/playlist.m3u8",
|
||||
"quality": "1080p",
|
||||
"type": "hls",
|
||||
"server": "vidlink-cf"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deep Debug Route: `GET /debug/:source`
|
||||
|
||||
When `ENABLE_DEBUG_ROUTE=true` is set in your environment variables, Stream API exposes a comprehensive diagnostic route:
|
||||
|
||||
```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.
|
||||
|
||||
:::callout-warning
|
||||
Do not enable the debug route on a public deployment. It can expose upstream request data, raw candidates, and headers. Enable it temporarily in a controlled environment, then disable it again.
|
||||
**Security Note**: Keep `ENABLE_DEBUG_ROUTE=false` in public production environments to avoid leaking internal scraper tokens or upstream endpoints.
|
||||
:::
|
||||
|
||||
## Production checklist
|
||||
---
|
||||
|
||||
- Set `TMDB_API_KEY` when metadata-dependent sources are required.
|
||||
- Keep `ENABLE_DEBUG_ROUTE=false` outside controlled troubleshooting.
|
||||
- Use TLS and enforce your own access policy before making the service remotely reachable.
|
||||
- Monitor health trends and playback failures separately.
|
||||
- Run updates and provider changes through your normal deployment process.
|
||||
- Build player fallbacks instead of assuming a specific provider is always available.
|
||||
## 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.
|
||||
|
||||
@@ -1,72 +1,156 @@
|
||||
# Paths and playback events
|
||||
# Paths & Playback Events
|
||||
|
||||
<p class="page-description">The complete Stream API playback contract, unified for movies and TV episodes.</p>
|
||||
<p class="page-description">Detailed API reference for Stream API streaming endpoints, Server-Sent Events contracts, and proxy query parameters.</p>
|
||||
|
||||
## Playback paths
|
||||
## Progressive Playback Endpoints
|
||||
|
||||
The API supports both the short paths below and `/api`-prefixed equivalents. A movie needs only `id`; a TV episode also needs `season` and `episode`.
|
||||
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.
|
||||
|
||||
| Media | Path | Response |
|
||||
| --- | --- | --- |
|
||||
| Movie | `GET /movie?id=:id` | Server-Sent Events |
|
||||
| TV episode | `GET /tv?id=:id&season=:season&episode=:episode` | Server-Sent Events |
|
||||
---
|
||||
|
||||
`id` is a TMDB ID. For example:
|
||||
### 1. Movie Stream Endpoint: `GET /movie` (or `/api/movie`)
|
||||
|
||||
```bash
|
||||
curl -N "YOUR_API_URL/movie?id=155"
|
||||
curl -N "YOUR_API_URL/tv?id=1396&season=1&episode=1"
|
||||
Establishes an SSE event stream for a movie.
|
||||
|
||||
```http
|
||||
GET /movie?id=155 HTTP/1.1
|
||||
Host: your-api.example.com
|
||||
Accept: text/event-stream
|
||||
```
|
||||
|
||||
## Event contract
|
||||
#### Query Parameters
|
||||
| Parameter | Type | Required | Description | Example |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | `integer` | Required | Numeric TMDB Movie ID | `155` (The Dark Knight) |
|
||||
|
||||
Playback routes use `text/event-stream`, not a single JSON document. Read each `data: ` line as JSON.
|
||||
---
|
||||
|
||||
### `meta`
|
||||
### 2. Television Stream Endpoint: `GET /tv` (or `/api/tv`)
|
||||
|
||||
Sent before source resolution completes. It can include TMDB metadata and an array of subtitle tracks.
|
||||
Establishes an SSE event stream for a television series episode.
|
||||
|
||||
```http
|
||||
GET /tv?id=1396&season=1&episode=1 HTTP/1.1
|
||||
Host: your-api.example.com
|
||||
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` |
|
||||
|
||||
---
|
||||
|
||||
## Server-Sent Events (SSE) Contract
|
||||
|
||||
Connections to `/movie` and `/tv` return `Content-Type: text/event-stream` and emit events sequentially:
|
||||
|
||||
### Event 1: `meta` (Emitted Immediately)
|
||||
Delivers title metadata and parsed subtitle tracks while scrapers are still running.
|
||||
|
||||
```json
|
||||
{
|
||||
data: {
|
||||
"type": "meta",
|
||||
"meta": { "id": 155, "title": "The Dark Knight" },
|
||||
"subtitles": [{ "label": "English", "file": "https://…", "type": "vtt", "source": "v1" }]
|
||||
"meta": {
|
||||
"title": "The Dark Knight",
|
||||
"year": 2008,
|
||||
"tmdb_id": 155,
|
||||
"imdb_id": "tt0468569",
|
||||
"poster": "https://image.tmdb.org/t/p/w500/...",
|
||||
"backdrop": "https://image.tmdb.org/t/p/original/..."
|
||||
},
|
||||
"subtitles": [
|
||||
{
|
||||
"label": "English",
|
||||
"file": "https://your-api.example.com/api?url=...",
|
||||
"type": "vtt",
|
||||
"source": "opensubtitles"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `source`
|
||||
|
||||
One event for each candidate that passes the service's verification pipeline.
|
||||
### Event 2..N: `source` (Emitted Progressively)
|
||||
Emitted as each provider scraper successfully resolves and passes two-phase verification.
|
||||
|
||||
```json
|
||||
{
|
||||
data: {
|
||||
"type": "source",
|
||||
"source": {
|
||||
"source": "provider-key",
|
||||
"label": "Provider name",
|
||||
"url": "YOUR_API_URL/api?url=…"
|
||||
"source": "vidlink",
|
||||
"label": "VidLink Primary",
|
||||
"url": "https://your-api.example.com/api?url=https%3A%2F%2Fupstream.cdn%2Fmaster.m3u8&vl=1",
|
||||
"server": "vidlink-cf",
|
||||
"quality": "1080p",
|
||||
"type": "hls",
|
||||
"headers": {
|
||||
"User-Agent": "Mozilla/5.0 ...",
|
||||
"Referer": "https://vidlink.pro/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `url` is ready for a player. HLS sources may be wrapped by Vyla's proxy so manifest segments and keys can be fetched with the appropriate upstream headers. Some configured sources bypass proxying. Do not assume a filename extension alone determines playback behavior.
|
||||
|
||||
### `done`
|
||||
|
||||
Sent after the configured attempts are complete.
|
||||
### 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.
|
||||
|
||||
```json
|
||||
{ "type": "done", "total": 3 }
|
||||
data: {
|
||||
"type": "done",
|
||||
"total": 5
|
||||
}
|
||||
```
|
||||
|
||||
`total: 0` means no playable sources were produced for that request. The SSE connection itself can still be successful.
|
||||
---
|
||||
|
||||
## Client rules
|
||||
## The Universal Reverse Proxy: `GET /api`
|
||||
|
||||
1. Start playback as soon as the first `source` arrives.
|
||||
2. Queue every later source for manual switching or automatic fallback.
|
||||
3. Attach subtitle tracks from `meta` without blocking playback.
|
||||
4. Treat an empty result as a normal product state, not a malformed response.
|
||||
5. Abort the request when the viewer leaves the page or chooses another title.
|
||||
The `/api` route handles media proxying, M3U8 rewriting, segment stripping, and TMDB queries.
|
||||
|
||||
The [integration guide](/guides/integrations) contains a practical player pattern; [error handling](/guides/error-handling) covers fallback behavior.
|
||||
### 1. Media Proxying: `/api?url=:encoded_url`
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
#### 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. |
|
||||
|
||||
#### 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.
|
||||
|
||||
---
|
||||
|
||||
### 2. Active Sources Listing: `/api?sources_meta=1`
|
||||
|
||||
Returns the list of active streaming sources currently loaded into the instance:
|
||||
|
||||
```json
|
||||
{
|
||||
"sources": [
|
||||
{ "key": "vidlink", "label": "VidLink", "timeout": 12000 },
|
||||
{ "key": "vixsrc", "label": "VixSrc", "timeout": 10000 },
|
||||
{ "key": "cinecat", "label": "CineCat", "timeout": 15000 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## HTTP Status Codes & Error Responses
|
||||
|
||||
| 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"}` |
|
||||
|
||||
Reference in New Issue
Block a user