DVR Feature (#819)

feat: complete DVR and improve streaming, security, configuration, and UI

Complete the Digital Video Recorder subsystem and add a broad set of
reliability, security, streaming, configuration, processing, and Web UI
improvements across Tuliprox.

DVR:

* complete live recording and provider-aware VOD download support
* add recording queue, workers, scheduling, and recurring recording rules
* add conflict detection and capacity-aware scheduling
* add pause, resume, retry, edit, cancel, and delete workflows
* add recording quotas and configurable retention policies
* add crash recovery and startup reconciliation
* add durable lifecycle notifications with per-channel retries
* add DVR health monitoring and diagnostic tooling
* add secure access to recordings, thumbnails, and subtitles
* add WebSocket notifications for recording and rule changes
* add Web UI management for recordings, rules, progress, and task state
* add RBAC, configuration, documentation, and i18n support

Streaming and HLS:

* fix shared-stream idle handling and release dead provider streams correctly
* stop tee streams when both client and cache consumers are gone
* cancel provisioning probes when client streams terminate
* fix transient HLS origin work accounting and intermittent 503 responses
* make stream buffer byte limits configurable
* make shared subscriber idle timeout configurable
* make initial HLS manifest wait timeout configurable
* add configurable TS chunk packet count
* add configurable HLS refresh failure backoff
* centralize redirect limits and retry jitter handling
* improve provider DNS refresh behavior and failover tuning
* preserve UTF-8 characters in catchup templates
* improve stream history validation and persistence error handling

Security:

* use constant-time credential comparisons
* harden library and media path handling against traversal and symlink escapes
* only trust forwarded client IP headers from configured trusted proxies
* redact credentials and sensitive URL data from logs
* reject invalid authentication status-code configuration
* deny users with unresolved plans or invalid content filters
* improve authentication error handling across proxy and HLS endpoints

Configuration and reliability:

* prevent invalid api-proxy.yml reloads from terminating the running server
* fully validate API proxy configuration before persisting changes
* log configuration and EPG cleanup failures instead of silently discarding them
* keep the last valid configuration active after failed hot reloads
* align backend and shared media-server validation
* remove duplicated path and normalization logic
* improve DNS-store recovery and Windows rename fallback handling
* reject invalid duration, timestamp, and numeric conversions safely
* fix playlist bouquet save error handling
* fix provider record update detection
* fix cache boundary handling
* improve startup and persistence failure diagnostics

Filtering, search, sorting, and processing:

* add field-scoped playlist explorer search
* centralize shared stream-history search field definitions
* extend the filter DSL with string, set, and numeric operators
* add EPG ID, channel number, and detected quality as filterable fields
* add filter dry-run preview API with match statistics and samples
* report filter syntax errors with line and column information
* add natural numeric-aware sorting
* add quality-aware channel deduplication
* add accent-independent deduplication
* move natural sorting and quality detection helpers into shared code
* persist explorer search-field selection across reloads

User plans and content access:

* add reusable API user plans for capability tiers
* support inherited cluster and connection limits with per-user overrides
* add plan-level and user-level content filters
* enforce content filters across Xtream, M3U, direct playback, resource access,
  stream info, short EPG, categories, and XMLTV
* add trial plans with automatic expiry and Trial status
* add plan selection and content filtering to the user editor
* add full plan management to the API configuration Web UI
* migrate the API user database to schema V7 with plan and filter persistence

Web UI and accessibility:

* add live logging console to the stats page
* improve login error handling and prevent duplicate authentication requests
* add keyboard navigation to tabs, menus, tables, and search
* add ARIA roles, labels, validation state, and live-region feedback
* add confirmation dialogs for destructive actions
* add unsaved-change warnings and Ctrl/Cmd+S shortcuts
* add loading, progress, empty, and in-flight states across views
* improve dropdown and single-selection behavior
* add clipboard and credential-copy helpers
* persist table pagination and explorer search preferences
* improve error recovery when UI context providers are unavailable
* remove multiple panic-prone unwrap and browser API paths
* replace remaining hardcoded UI strings with translation keys

Maintenance:

* resolve backend and frontend compiler and Clippy warnings
* update packages and test fixtures
* consolidate duplicated helpers and validation logic
* improve documentation for configuration, filters, plans, DVR, and REST APIs
* add and update tests for migrations, filters, deduplication, sorting,
  configuration, streaming, and accessibility behavior
This commit is contained in:
euzu
2026-08-21 14:50:12 +02:00
committed by GitHub
parent df961e4bf7
commit 16d32d1298
270 changed files with 37731 additions and 2607 deletions
+59
View File
@@ -12,6 +12,7 @@ specific permissions, proxy modes, and priorities.
auth_error_status: 403
use_user_db: false
server:
plans:
user:
```
@@ -22,6 +23,7 @@ user:
| `auth_error_status` | Int | No | `403` | The HTTP status code Tuliprox returns when a player sends invalid credentials or tokens. (Only applies to [Xtream/M3U API Endpoints](#api-endpoints-for-clients-players), stream paths, and resource paths, NOT the Web UI / REST API). |
| `use_user_db` | Bool | No | `false` | If set to `true`, Tuliprox migrates all users from this YAML file into a highly performant SQLite database (`api_user.db`). **From then on, Tuliprox ignores the users in the YAML file!** You **must** subsequently manage users entirely via the Web UI Dashboard. Switching the option to `false` or `true` automatically migrates users back to the corresponding file (`false` → `api-proxy.yml`, `true` → `api_user.db`). |
| `server` | List | Yes | `[]` | See [Server Definitions](#1-server-definitions-server) for how to define servers. |
| `plans` | List | No | `[]` | Reusable user capability tiers. See [User Plans](#3-user-plans-plans). |
| `user` | List | No | `[]` | See [User Definitions](#2-user-definitions-user) for how to define users & permissions. |
### Subsections (Object Keys)
@@ -30,6 +32,7 @@ user:
|:---------|:------------------------------------------------------|:--------------------------------------------|
| `server` | Virtual server endpoints exposed to clients. | [See section](#1-server-definitions-server) |
| `user` | User credentials, proxy modes, and access management. | [See section](#2-user-definitions-user) |
| `plans` | Reusable capability tiers referenced by users. | [See section](#3-user-plans-plans) |
---
@@ -128,6 +131,8 @@ in your `config.yml`. Without it, these fields are purely cosmetic!
| `ui_enabled` | Bool | No | `true` | Allows this specific user to log into the Web UI to manage their own favorites/bouquets. |
| `priority` | Int (i8) | No | `0` | Stream preemption priority. Priority range: `-128` to `127`, where `-128` has the highest priority. Negative numbers are explicitly allowed for top-tier access. (see [user priority](#user-priorities-priority) below) |
| `network_access` | Block | No | `None` | Per-user network/country access restrictions. Uses OR logic — matching ANY `allowed_networks` (CIDR) OR ANY `allowed_countries` grants access. Requires GeoIP for country checks. Client IP from `X-Real-IP` / `X-Forwarded-For`. See [Network Access Restrictions](#network-access-restrictions) below. |
| `plan` | String | No | `None` | Name of a [user plan](#3-user-plans-plans). Unset user values (`output_clusters`, `max_connections`, `soft_connections`) inherit from the plan; explicit user values always win. The plan's content `filter` is always applied. |
| `filter` | String | No | `None` | Filter DSL expression restricting which content this user sees. AND-combined with the plan filter when both are set, so a user filter can only narrow a plan, never widen it. |
---
@@ -583,6 +588,60 @@ aired - that's controlled by your IPTV provider.
---
## 3. User Plans (`plans`)
Plans are reusable capability tiers. Instead of repeating limits per user, define a plan once and reference it
via the user's `plan` field. Plans can be managed in the Web UI (Config → API, edit mode) or directly in this file.
```yaml
plans:
- name: basic
output_clusters: [live]
max_connections: 1
filter: 'NOT Group ~ "^(VIP|PPV).*" AND Quality <= 3'
comment: Live-only starter tier, FHD max, no premium groups
- name: premium
output_clusters: [live, vod, series]
max_connections: 3
user:
- target: main
credentials:
- username: joe
password: secret
plan: basic
- username: vip
password: secret2
plan: premium
max_connections: 5 # explicit user value overrides the plan
```
### Plan Parameters
| Parameter | Type | Required | Default | Technical Impact & Background |
|:-------------------|:-------|:--------:|:--------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` | String | Yes | | Unique plan identifier referenced by `user[].credentials[].plan`. |
| `output_clusters` | List | No | `None` | Cluster tier (`live`, `vod`, `series`). Inherited by members that don't set their own `output_clusters`. |
| `max_connections` | Int | No | `0` | Concurrent stream limit for members whose own `max_connections` is `0`/unset. Enforcement still requires `user_access_control: true`. |
| `soft_connections` | Int | No | `0` | Soft connection allowance inherited the same way. |
| `filter` | String | No | `None` | Filter DSL expression restricting the content visible to plan members (e.g. group allow/deny lists, `Quality <= 3` caps). AND-combined with a member's own `filter` if both exist. |
| `trial.duration` | String | No | `None` | Trial window with unit (`24h`, `7d`). When a **new** user is created on this plan without an explicit `exp_date`, the expiry is set to now + duration and the status defaults to `Trial`. Enforcement of the expiry requires `user_access_control: true`. |
| `comment` | String | No | `None` | Free-form description. |
### Resolution Rules
- Explicit user value > plan value > global default. "Unset" means `output_clusters` omitted or `max_connections`/`soft_connections` at `0`.
- Filters combine as `(plan filter) AND (user filter)` — a user filter can only narrow the plan.
- Templates (`!NAME!`) are **not** available in api-proxy filters; write the expression inline.
- Trial windows apply only at user creation (Web UI/API); existing users and YAML-defined users are not modified.
After expiry the standard `exp_date` enforcement blocks the user; automatic downgrade to another plan is not supported.
- Plan changes take effect on config reload for YAML users and on the next load for database users; running streams are not interrupted.
- The content filter hides entries from playlists and stream lists, blocks direct stream access to filtered items,
hides categories whose content is fully filtered out from the Xtream category actions, and removes hidden channels
from the user's XMLTV output. The Web UI bouquet editor category list is not thinned.
---
&nbsp;
## Additional Information