mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-05-16 21:59:26 +00:00
docs: update API and configuration documentation with example service tags
This commit is contained in:
34
docs/API.md
34
docs/API.md
@@ -72,7 +72,7 @@ Search for titles from a streaming service.
|
||||
**Required parameters:**
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `service` | string | Service tag (e.g., `NF`, `AMZN`, `ATV`) |
|
||||
| `service` | string | Service tag |
|
||||
| `query` | string | Search query |
|
||||
|
||||
**Optional parameters:**
|
||||
@@ -85,18 +85,18 @@ Search for titles from a streaming service.
|
||||
```bash
|
||||
curl -X POST http://localhost:8786/api/search \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"service": "ATV", "query": "hijack"}'
|
||||
-d '{"service": "EXAMPLE", "query": "example show"}'
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{
|
||||
"id": "umc.cmc.1dg08zn0g3zx52hs8npoj5qe3",
|
||||
"title": "Hijack",
|
||||
"id": "abc123def456",
|
||||
"title": "Example Show",
|
||||
"description": null,
|
||||
"label": "TV Show",
|
||||
"url": "https://tv.apple.com/us/show/hijack/umc.cmc.1dg08zn0g3zx52hs8npoj5qe3"
|
||||
"url": "https://example.com/show/abc123def456"
|
||||
}
|
||||
],
|
||||
"count": 1
|
||||
@@ -118,7 +118,7 @@ Get available titles (seasons/episodes/movies) for a service and title ID.
|
||||
```bash
|
||||
curl -X POST http://localhost:8786/api/list-titles \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"service": "ATV", "title_id": "umc.cmc.1dg08zn0g3zx52hs8npoj5qe3"}'
|
||||
-d '{"service": "EXAMPLE", "title_id": "abc123def456"}'
|
||||
```
|
||||
|
||||
```json
|
||||
@@ -126,12 +126,12 @@ curl -X POST http://localhost:8786/api/list-titles \
|
||||
"titles": [
|
||||
{
|
||||
"type": "episode",
|
||||
"name": "Final Call",
|
||||
"series_title": "Hijack",
|
||||
"name": "Pilot",
|
||||
"series_title": "Example Show",
|
||||
"season": 1,
|
||||
"number": 1,
|
||||
"year": 2023,
|
||||
"id": "umc.cmc.4levibvvz01hl4zsm0jdk5v2p"
|
||||
"year": 2024,
|
||||
"id": "abc123def789"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -161,8 +161,8 @@ Get video, audio, and subtitle tracks for a title.
|
||||
curl -X POST http://localhost:8786/api/list-tracks \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"service": "ATV",
|
||||
"title_id": "umc.cmc.1dg08zn0g3zx52hs8npoj5qe3",
|
||||
"service": "EXAMPLE",
|
||||
"title_id": "abc123def456",
|
||||
"wanted": ["S01E01"]
|
||||
}'
|
||||
```
|
||||
@@ -261,8 +261,8 @@ Start a download job. Returns immediately with a job ID (HTTP 202).
|
||||
curl -X POST http://localhost:8786/api/download \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"service": "ATV",
|
||||
"title_id": "umc.cmc.1dg08zn0g3zx52hs8npoj5qe3",
|
||||
"service": "EXAMPLE",
|
||||
"title_id": "abc123def456",
|
||||
"wanted": ["S01E01"],
|
||||
"quality": [1080, 2160],
|
||||
"vcodec": ["H265"],
|
||||
@@ -303,7 +303,7 @@ curl http://localhost:8786/api/download/jobs
|
||||
curl "http://localhost:8786/api/download/jobs?status=completed"
|
||||
|
||||
# Filter by service
|
||||
curl "http://localhost:8786/api/download/jobs?service=ATV"
|
||||
curl "http://localhost:8786/api/download/jobs?service=EXAMPLE"
|
||||
```
|
||||
|
||||
---
|
||||
@@ -321,8 +321,8 @@ curl http://localhost:8786/api/download/jobs/504db959-80b0-446c-a764-7924b761d61
|
||||
"job_id": "504db959-80b0-446c-a764-7924b761d613",
|
||||
"status": "completed",
|
||||
"created_time": "2026-02-27T18:00:00.000000",
|
||||
"service": "ATV",
|
||||
"title_id": "umc.cmc.1dg08zn0g3zx52hs8npoj5qe3",
|
||||
"service": "EXAMPLE",
|
||||
"title_id": "abc123def456",
|
||||
"progress": 100.0,
|
||||
"parameters": { ... },
|
||||
"started_time": "2026-02-27T18:00:01.000000",
|
||||
|
||||
@@ -62,9 +62,9 @@ Example mapping:
|
||||
|
||||
```yaml
|
||||
downloader:
|
||||
NF: requests
|
||||
AMZN: n_m3u8dl_re
|
||||
DSNP: n_m3u8dl_re
|
||||
EXAMPLE: requests
|
||||
EXAMPLE2: n_m3u8dl_re
|
||||
EXAMPLE3: n_m3u8dl_re
|
||||
default: requests
|
||||
```
|
||||
|
||||
@@ -131,11 +131,11 @@ downloads: 4
|
||||
workers: 16
|
||||
```
|
||||
|
||||
to set `--bitrate=CVBR` for the AMZN service,
|
||||
to set `--bitrate=CVBR` for a specific service,
|
||||
|
||||
```yaml
|
||||
lang: de
|
||||
AMZN:
|
||||
EXAMPLE:
|
||||
bitrate: CVBR
|
||||
```
|
||||
|
||||
@@ -229,9 +229,9 @@ dl:
|
||||
lang: en
|
||||
downloads: 4
|
||||
workers: 16
|
||||
AMZN:
|
||||
EXAMPLE:
|
||||
bitrate: CVBR
|
||||
NF:
|
||||
EXAMPLE2:
|
||||
worst: true
|
||||
quality: 1080
|
||||
```
|
||||
@@ -307,8 +307,8 @@ Example mapping:
|
||||
|
||||
```yaml
|
||||
decryption:
|
||||
ATVP: mp4decrypt
|
||||
AMZN: shaka
|
||||
EXAMPLE: mp4decrypt
|
||||
EXAMPLE2: shaka
|
||||
default: shaka
|
||||
```
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ for a matching file.
|
||||
For example,
|
||||
|
||||
```yaml
|
||||
AMZN: chromecdm_903_l3
|
||||
NF: nexus_6_l1
|
||||
EXAMPLE: chromecdm_903_l3
|
||||
EXAMPLE2: nexus_6_l1
|
||||
```
|
||||
|
||||
You may also specify this device based on the profile used.
|
||||
@@ -21,9 +21,9 @@ You may also specify this device based on the profile used.
|
||||
For example,
|
||||
|
||||
```yaml
|
||||
AMZN: chromecdm_903_l3
|
||||
NF: nexus_6_l1
|
||||
DSNP:
|
||||
EXAMPLE: chromecdm_903_l3
|
||||
EXAMPLE2: nexus_6_l1
|
||||
EXAMPLE3:
|
||||
john_sd: chromecdm_903_l3
|
||||
jane_uhd: nexus_5_l1
|
||||
```
|
||||
@@ -35,8 +35,8 @@ For example, the following has the same result as the previous example, as well
|
||||
services and profiles being pre-defined to use `chromecdm_903_l3`.
|
||||
|
||||
```yaml
|
||||
NF: nexus_6_l1
|
||||
DSNP:
|
||||
EXAMPLE2: nexus_6_l1
|
||||
EXAMPLE3:
|
||||
jane_uhd: nexus_5_l1
|
||||
default: chromecdm_903_l3
|
||||
```
|
||||
@@ -56,12 +56,12 @@ EXAMPLE:
|
||||
You can mix profiles and quality thresholds in the same service:
|
||||
|
||||
```yaml
|
||||
NETFLIX:
|
||||
john: netflix_l3_profile # Profile-based selection
|
||||
"<=720": netflix_mobile_l3 # Quality-based selection
|
||||
"1080": netflix_standard_l3 # Exact match for 1080p
|
||||
">=1440": netflix_premium_l1 # Quality-based selection
|
||||
default: netflix_standard_l3 # Fallback
|
||||
EXAMPLE:
|
||||
john: example_l3_profile # Profile-based selection
|
||||
"<=720": example_mobile_l3 # Quality-based selection
|
||||
"1080": example_standard_l3 # Exact match for 1080p
|
||||
">=1440": example_premium_l1 # Quality-based selection
|
||||
default: example_standard_l3 # Fallback
|
||||
```
|
||||
|
||||
---
|
||||
@@ -311,8 +311,8 @@ Or configure per-service with a `DEFAULT` fallback:
|
||||
```yaml
|
||||
decryption:
|
||||
DEFAULT: shaka
|
||||
AMZN: mp4decrypt
|
||||
NF: shaka
|
||||
EXAMPLE: mp4decrypt
|
||||
EXAMPLE2: shaka
|
||||
```
|
||||
|
||||
Service keys are case-insensitive (normalized to uppercase internally).
|
||||
|
||||
@@ -56,10 +56,10 @@ output_template:
|
||||
```
|
||||
|
||||
Example outputs:
|
||||
- Scene movies: `The.Matrix.1999.1080p.NF.WEB-DL.DDP5.1.H.264-EXAMPLE`
|
||||
- Scene movies (REPACK): `Dune.2021.REPACK.2160p.HBO.WEB-DL.DDP5.1.H.265-EXAMPLE`
|
||||
- Scene series: `Breaking.Bad.2008.S01E01.Pilot.1080p.NF.WEB-DL.DDP5.1.H.264-EXAMPLE`
|
||||
- Plex movies: `The Matrix (1999) 1080p`
|
||||
- Scene movies: `Example.Movie.2024.1080p.EXAMPLE.WEB-DL.DDP5.1.H.264-TAG`
|
||||
- Scene movies (REPACK): `Example.Movie.2024.REPACK.2160p.EXAMPLE.WEB-DL.DDP5.1.H.265-TAG`
|
||||
- Scene series: `Example.Show.2024.S01E01.Pilot.1080p.EXAMPLE.WEB-DL.DDP5.1.H.264-TAG`
|
||||
- Plex movies: `Example Movie (2024) 1080p`
|
||||
|
||||
---
|
||||
|
||||
@@ -106,10 +106,10 @@ output_template:
|
||||
```
|
||||
|
||||
Example outputs:
|
||||
- Danish audio: `Show.S01E01.DANiSH.1080p.NF.WEB-DL.DDP5.1.H.264-TAG`
|
||||
- English audio + multiple Nordic subs: `Show.S01E01.NORDiC.1080p.NF.WEB-DL.DDP5.1.H.264-TAG`
|
||||
- English audio + Danish subs only: `Show.S01E01.DKsubs.1080p.NF.WEB-DL.DDP5.1.H.264-TAG`
|
||||
- No matching languages: `Show.S01E01.1080p.NF.WEB-DL.DDP5.1.H.264-TAG`
|
||||
- Danish audio: `Example.Show.S01E01.DANiSH.1080p.EXAMPLE.WEB-DL.DDP5.1.H.264-TAG`
|
||||
- English audio + multiple Nordic subs: `Example.Show.S01E01.NORDiC.1080p.EXAMPLE.WEB-DL.DDP5.1.H.264-TAG`
|
||||
- English audio + Danish subs only: `Example.Show.S01E01.DKsubs.1080p.EXAMPLE.WEB-DL.DDP5.1.H.264-TAG`
|
||||
- No matching languages: `Example.Show.S01E01.1080p.EXAMPLE.WEB-DL.DDP5.1.H.264-TAG`
|
||||
|
||||
### Example: Other regional tags
|
||||
|
||||
|
||||
@@ -1,283 +0,0 @@
|
||||
# Remote Services — Client ↔ Server Architecture
|
||||
|
||||
The `--remote` flag on the `dl` command connects to a remote unshackle server
|
||||
(`unshackle serve`) that holds service plugins. The client never has service
|
||||
code — it sends credentials/cookies, the server authenticates and fetches
|
||||
titles/tracks, and the client handles downloading, decryption, and muxing locally.
|
||||
|
||||
## How It Works
|
||||
|
||||
The `RemoteService` adapter in `remote_service.py` implements the same interface
|
||||
as a local `Service`. From dl.py's perspective, it's just another service — the
|
||||
entire download pipeline runs unchanged.
|
||||
|
||||
```
|
||||
unshackle dl --remote [-s server_name] SERVICE_TAG TITLE_ID [options]
|
||||
```
|
||||
|
||||
## Session Lifecycle
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as Client (dl --remote)
|
||||
participant Server as Server (serve API)
|
||||
participant Service as Service Plugin
|
||||
|
||||
Note over Client: Load credentials/cookies locally
|
||||
Note over Client: Detect client region via IP check
|
||||
|
||||
Client->>Server: POST /api/session/create
|
||||
Note right of Client: {service, title_id, credentials,<br/>cookies, client_region, profile}
|
||||
|
||||
Note over Server: Check if server region matches client<br/>Skip proxy if same region
|
||||
Server->>Service: authenticate(cookies, credential)
|
||||
Service-->>Server: Authenticated session
|
||||
Server-->>Client: {session_id, service}
|
||||
|
||||
Client->>Server: GET /api/session/{id}/titles
|
||||
Server->>Service: get_titles(title_id)
|
||||
Server-->>Client: Serialized titles (episodes/movies)
|
||||
|
||||
Note over Client: dl.py filters by --wanted
|
||||
|
||||
Client->>Server: POST /api/session/{id}/tracks
|
||||
Server->>Service: get_tracks(title)
|
||||
Server->>Service: get_chapters(title)
|
||||
Note over Server: Extract manifest XML as base64<br/>Extract service session cookies/headers<br/>Detect server CDM type from track DRM + config
|
||||
Server-->>Client: Tracks + manifests + chapters +<br/>session cookies + server_cdm_type
|
||||
|
||||
Note over Client: Re-parse manifest locally (DASH/ISM)<br/>HLS tracks download from URL directly
|
||||
Note over Client: Match tracks by ID to populate track.data
|
||||
Note over Client: dl.py runs full track selection pipeline
|
||||
|
||||
rect rgb(40, 40, 60)
|
||||
Note over Client: Licensing (depends on mode)
|
||||
end
|
||||
|
||||
rect rgb(40, 60, 40)
|
||||
Note over Client: Download + Post-Processing (all local)
|
||||
Note over Client: Concurrent downloads via ThreadPoolExecutor
|
||||
Note over Client: Decrypt (mp4decrypt / Shaka Packager)
|
||||
Note over Client: FFMPEG repack
|
||||
Note over Client: Subtitle conversion
|
||||
Note over Client: Hybrid HDR10+DV injection (dovi_tool)
|
||||
Note over Client: Per-resolution muxing (mkvmerge)
|
||||
Note over Client: Output naming from template
|
||||
Note over Client: Tagging (TMDB/IMDB/TVDB)
|
||||
end
|
||||
|
||||
Client->>Server: DELETE /api/session/{id}
|
||||
Server-->>Client: Session cleaned up
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Licensing Modes
|
||||
|
||||
### Proxy Mode (`server_cdm: false` — default)
|
||||
|
||||
The client has its own CDM (WVD/PRD file). The server only proxies the license
|
||||
request through the authenticated service session.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as Client
|
||||
participant Server as Server
|
||||
participant Service as Service Plugin
|
||||
participant CDM as Client CDM (local WVD/PRD)
|
||||
|
||||
Note over Client: track.download() discovers DRM<br/>(PSSH from manifest/init data)
|
||||
|
||||
Client->>CDM: Generate challenge from PSSH
|
||||
CDM-->>Client: Challenge bytes
|
||||
|
||||
Client->>Server: POST /api/session/{id}/license
|
||||
Note right of Client: {track_id, challenge (base64),<br/>drm_type, pssh}
|
||||
|
||||
Server->>Service: get_widevine_license(challenge, title, track)<br/>or get_playready_license(challenge, title, track)
|
||||
Service-->>Server: Raw license response bytes
|
||||
|
||||
Server-->>Client: {license: base64_encoded_bytes}
|
||||
|
||||
Client->>CDM: Parse license response
|
||||
CDM-->>Client: Content keys (KID:KEY)
|
||||
|
||||
Note over Client: Keys stored in local vaults
|
||||
Note over Client: Decrypt track with keys
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
|
||||
- Client must have a local CDM device file (`.wvd` or `.prd`)
|
||||
- Server never sees decryption keys — only forwards encrypted license blob
|
||||
- Client parses the license locally to extract keys
|
||||
- Keys are cached in local vaults for future use
|
||||
|
||||
### Server-CDM Mode (`server_cdm: true`)
|
||||
|
||||
The server handles all CDM operations using its own devices. The client does
|
||||
not need a local CDM. There are two paths depending on when DRM is discovered:
|
||||
|
||||
#### Path A: Pre-fetch (DASH services with manifest DRM)
|
||||
|
||||
For services where DRM info is in the manifest (ContentProtection elements),
|
||||
the server resolves keys before downloads start.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as Client
|
||||
participant Server as Server
|
||||
participant Service as Service Plugin
|
||||
participant CDM as Server CDM (WVD/PRD)
|
||||
|
||||
Note over Client: dl.py calls service.resolve_server_keys()<br/>before downloads start
|
||||
|
||||
Client->>Server: POST /api/session/{id}/license
|
||||
Note right of Client: {track_ids: [...], mode: "server_cdm",<br/>drm_type from server_cdm_type}
|
||||
|
||||
loop Per track with DRM
|
||||
Note over Server: Extract PSSH from track manifest<br/>ContentProtection elements
|
||||
Server->>CDM: Load device from serve.users config
|
||||
Server->>CDM: Generate challenge from PSSH
|
||||
Server->>Service: get_license(challenge, title, track)
|
||||
Service-->>Server: License response
|
||||
Server->>CDM: Parse license → extract keys
|
||||
end
|
||||
|
||||
Server-->>Client: {keys: {track_id: {kid: key, ...}}}
|
||||
|
||||
Note over Client: Inject keys into track.drm.content_keys
|
||||
Note over Client: prepare_drm finds keys → skips CDM call
|
||||
Note over Client: Keys stored in local vaults
|
||||
```
|
||||
|
||||
#### Path B: On-demand (HLS services / late DRM discovery)
|
||||
|
||||
For services like ATV where DRM is only discovered during download (from init
|
||||
segments or EXT-X-KEY tags), keys are fetched per-track during download.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as Client
|
||||
participant Server as Server
|
||||
participant Service as Service Plugin
|
||||
participant CDM as Server CDM (WVD/PRD)
|
||||
|
||||
Note over Client: track.download() discovers DRM<br/>(PSSH from init data / EXT-X-KEY)
|
||||
Note over Client: prepare_drm calls licence callback
|
||||
|
||||
Client->>Server: POST /api/session/{id}/license
|
||||
Note right of Client: {track_id, pssh, drm_type,<br/>mode: "server_cdm"}
|
||||
|
||||
Server->>CDM: Load device (Widevine or PlayReady)
|
||||
Server->>CDM: Generate challenge from PSSH
|
||||
Server->>Service: get_license(challenge, title, track)
|
||||
Service-->>Server: License response
|
||||
Server->>CDM: Parse license → extract keys
|
||||
CDM-->>Server: Content keys
|
||||
|
||||
Server-->>Client: {keys: {kid: key, ...}}
|
||||
|
||||
Note over Client: Inject keys into track.drm.content_keys
|
||||
Note over Client: prepare_drm sees keys → skips re-raise
|
||||
Note over Client: Keys stored in local vaults
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
|
||||
- Client does NOT need a local CDM device file
|
||||
- Server uses devices from `serve.users.{api_key}.devices` (Widevine) and
|
||||
`serve.users.{api_key}.playready_devices` (PlayReady)
|
||||
- Server detects DRM type from actual track DRM objects and available devices
|
||||
- Keys are returned as `{kid_hex: key_hex}` pairs
|
||||
- Keys are still cached in client's local vaults (unless `--cdm-only` is used)
|
||||
- `prepare_drm` skips local CDM if all KIDs already have keys
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Client (`unshackle.yaml`)
|
||||
|
||||
```yaml
|
||||
remote_services:
|
||||
my_server:
|
||||
url: "https://server:8786"
|
||||
api_key: "your-secret-key"
|
||||
server_cdm: true # server handles licensing (optional, default: false)
|
||||
services: # per-service overrides (optional)
|
||||
EXAMPLE:
|
||||
downloader: n_m3u8dl_re
|
||||
decryption: mp4decrypt
|
||||
EXAMPLE2:
|
||||
downloader: n_m3u8dl_re
|
||||
```
|
||||
|
||||
### Server (`unshackle.yaml`)
|
||||
|
||||
```yaml
|
||||
serve:
|
||||
api_secret: "your-secret-key"
|
||||
users:
|
||||
"your-secret-key":
|
||||
username: api_user
|
||||
devices: # Widevine CDMs
|
||||
- xiaomi_mi_a1_15.0.0_l3
|
||||
playready_devices: # PlayReady CDMs
|
||||
- qingdao_haier_tv_sl3000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Manifest Data Transfer
|
||||
|
||||
Track manifests (DASH XML, ISM XML) cannot be JSON-serialized directly (they
|
||||
contain lxml Element objects). The server serializes them as base64 strings in
|
||||
the `/tracks` response. The client decodes and re-parses them locally.
|
||||
|
||||
| Manifest | Serialization | Client Re-parse | Notes |
|
||||
| -------- | --------------------------- | ---------------------------------------------- | --------------------------------- |
|
||||
| **DASH** | `etree.tostring()` → base64 | `DASH(etree.fromstring(xml), url).to_tracks()` | Match by track ID (crc32 hash) |
|
||||
| **HLS** | Not needed | Downloads playlist from `track.url` directly | `HLS.download_track()` re-fetches |
|
||||
| **ISM** | `etree.tostring()` → base64 | `ISM(etree.fromstring(xml), url).to_tracks()` | Match by track ID |
|
||||
|
||||
The `/tracks` response also includes:
|
||||
|
||||
- `session_headers` / `session_cookies` — for CDN authentication
|
||||
- `server_cdm_type` — "widevine" or "playready" (detected from track DRM + config)
|
||||
|
||||
---
|
||||
|
||||
## Region & Proxy Handling
|
||||
|
||||
1. Client detects its own country via `get_cached_ip_info()`
|
||||
2. Sends `client_region` in session create (no IP sent, just country code)
|
||||
3. Server checks its own region — if it matches, no proxy needed
|
||||
4. If regions differ, server resolves a proxy from its own providers
|
||||
5. Client can also send explicit `--proxy` which takes precedence
|
||||
|
||||
---
|
||||
|
||||
## Comparison: Proxy vs Server-CDM
|
||||
|
||||
| | Proxy Mode (default) | Server-CDM Mode |
|
||||
| ----------------------- | ----------------------------- | -------------------------------- |
|
||||
| **Client needs CDM** | Yes (WVD/PRD file) | No |
|
||||
| **License request** | Client sends challenge bytes | Client sends PSSH (or track IDs) |
|
||||
| **License response** | Raw license bytes | KID:KEY pairs |
|
||||
| **Key extraction** | Client CDM parses license | Server CDM parses license |
|
||||
| **What leaves server** | Encrypted license blob | Decryption keys |
|
||||
| **Vault caching** | Client caches keys | Client caches keys |
|
||||
| **`--cdm-only` effect** | Skip vaults, CDM only | Skip vaults, server CDM only |
|
||||
| **Config** | `server_cdm: false` (default) | `server_cdm: true` |
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Endpoint | Method | Purpose |
|
||||
| --------------------------- | ------ | --------------------------------- |
|
||||
| `/api/session/create` | POST | Authenticate, create session |
|
||||
| `/api/session/{id}/titles` | GET | Get titles for session |
|
||||
| `/api/session/{id}/tracks` | POST | Get tracks + manifests + chapters |
|
||||
| `/api/session/{id}/license` | POST | License proxy or server-CDM keys |
|
||||
| `/api/session/{id}` | GET | Check session validity |
|
||||
| `/api/session/{id}` | DELETE | Cleanup session |
|
||||
@@ -17,7 +17,7 @@ a dictionary.
|
||||
For example,
|
||||
|
||||
```yaml
|
||||
NOW:
|
||||
EXAMPLE:
|
||||
client:
|
||||
auth_scheme: MESSO
|
||||
# ... more sensitive data
|
||||
@@ -55,20 +55,20 @@ Specify login credentials to use for each Service, and optionally per-profile.
|
||||
For example,
|
||||
|
||||
```yaml
|
||||
ALL4: jane@gmail.com:LoremIpsum100 # directly
|
||||
AMZN: # or per-profile, optionally with a default
|
||||
EXAMPLE: jane@example.tld:LoremIpsum100 # directly
|
||||
EXAMPLE2: # or per-profile, optionally with a default
|
||||
default: jane@example.tld:LoremIpsum99 # <-- used by default if -p/--profile is not used
|
||||
james: james@gmail.com:TheFriend97
|
||||
james: james@example.tld:TheFriend97
|
||||
john: john@example.tld:LoremIpsum98
|
||||
NF: # the `default` key is not necessary, but no credential will be used by default
|
||||
john: john@gmail.com:TheGuyWhoPaysForTheNetflix69420
|
||||
EXAMPLE3: # the `default` key is not necessary, but no credential will be used by default
|
||||
john: john@example.tld:SecretPassword123
|
||||
```
|
||||
|
||||
The value should be in string form, i.e. `john@gmail.com:password123` or `john:password123`.
|
||||
The value should be in string form, i.e. `john@example.tld:password123` or `john:password123`.
|
||||
Any arbitrary values can be used on the left (username/password/phone) and right (password/secret).
|
||||
You can also specify these in list form, i.e., `["john@gmail.com", ":PasswordWithAColon"]`.
|
||||
You can also specify these in list form, i.e., `["john@example.tld", ":PasswordWithAColon"]`.
|
||||
|
||||
If you specify multiple credentials with keys like the `AMZN` and `NF` example above, then you should
|
||||
If you specify multiple credentials with keys like the `EXAMPLE2` and `EXAMPLE3` example above, then you should
|
||||
use a `default` key or no credential will be loaded automatically unless you use `-p/--profile`. You
|
||||
do not have to use a `default` key at all.
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ async def search(request: web.Request) -> web.Response:
|
||||
properties:
|
||||
service:
|
||||
type: string
|
||||
description: Service tag (e.g., NF, AMZN, ATV)
|
||||
description: Service tag
|
||||
query:
|
||||
type: string
|
||||
description: Search query string
|
||||
|
||||
Reference in New Issue
Block a user