Skip to content

Latest commit

 

History

History
866 lines (691 loc) · 61.1 KB

File metadata and controls

866 lines (691 loc) · 61.1 KB

🏛️ config.yml (Core System)

The config.yml is the primary configuration file of Tuliprox. It dictates the engine's core runtime behavior, memory management, caching mechanisms, background schedulers, and external integrations (like HDHomeRun, GeoIP, and the Web UI).

Top-level entries

process_parallel: false
disk_based_processing: false
storage_dir: ./data
default_user_agent: Tuliprox/...
backup_dir: ./data/backup
user_config_dir: ./data/user
mapping_path: mapping.yml
template_path: template.yml
update_on_boot: false
config_hot_reload: false
accept_insecure_ssl_certificates: false
sleep_timer_mins: null
connect_timeout_secs: 10
interner_gc_interval_secs: 180
interner_gc_min_pool_size: 100
user_access_control: false
custom_stream_response_path: null
custom_stream_response_timeout_secs: 0
custom_stream_response_enabled: true   # default: true (serve the fallback videos)
custom_stream_response_error_status: 502  # 4xx/5xx only; returned when custom_stream_response_enabled is false

api:
web_ui:
log:
schedules:
messaging:
video:
proxy:
ipcheck:
hdhomerun:
library:
reverse_proxy:
metadata_update:

Global System & Storage Settings (Flat Keys)

Parameter Type Required Default Technical Impact & Background
process_parallel Bool No false Activates multi-threading during playlist processing. Background: If you have 5 providers, Tuliprox processes them sequentially by default. Setting this to true processes all 5 simultaneously using multiple CPU cores. Warning: This establishes parallel downloads to your providers. If you process the same provider multiple times, each thread uses a connection. Keep in mind that you might hit the provider's max-connections limit!
disk_based_processing Bool No false Tradeoff Guidance: Normally, Tuliprox loads playlists into RAM. With true, every chunk is manipulated directly on disk (using a B+Tree database). Use this on low-end hardware (e.g., Raspberry Pi) or with massive playlists (>500k streams) to prevent Out-Of-Memory crashes. It significantly increases Disk I/O load, so it is slower but much safer for tight memory footprints.
storage_dir String No ./data Root directory for all runtime data (B+Tree databases, downloads, caches). Relative paths are resolved against the Tuliprox Home Directory. Be aware that different configurations (e.g. user bouquets) alongside the playlists are stored in this directory.
default_user_agent String No Tuliprox/... Fallback HTTP User-Agent used for upstream provider requests if the input definition or client request does not explicitly provide one.
backup_dir String No {storage_dir}/backup Storage location for config backups (e.g., triggered via "Save Configuration" in the Web UI).
user_config_dir String No {storage_dir}/user Storage location for user-specific configurations (like favorites or custom bouquets created via the Web UI).
mapping_path String No mapping.yml Path to the mapping file. Pro-Tip: If you specify a folder path here (e.g., ./config/mappings/), Tuliprox loads all .yml files in that folder in alphanumeric order and merges them. Note: This is a lexicographic sort, meaning m_10.yml comes before m_2.yml. Name files carefully (e.g., m_01.yml, m_02.yml).
template_path String No template.yml Path to the template macro file. Specifying a folder here is also possible and highly recommended (see above).
update_on_boot Bool No false Forces Tuliprox to immediately query all providers and rebuild all playlists upon startup. If false, the proxy serves the local DB cache from the last run until the scheduler triggers the next update.
config_hot_reload Bool No false Spawns a filesystem watcher for mapping.yml and api-proxy.yml. Upon saving, mappings and user credentials become active immediately without requiring a server restart. (See Bind-Mount Note below)
accept_insecure_ssl_certificates Bool No false Set to true if your upstream provider uses expired, self-signed, or improperly configured HTTPS certificates. Otherwise, the HTTP client drops the connection securely.
sleep_timer_mins Int No null Automatic kill-switch for proxied streams. Forcibly terminates active stream connections after X minutes (Protects against users falling asleep with the TV on).
connect_timeout_secs Int No 10 Maximum time (in seconds) Tuliprox waits to establish the initial TCP connection to a provider. 0 disables the timeout and the connection attempt continues until the provider closes it or a network timeout occurs (Warning: risk of hanging threads!).
interner_gc_interval_secs Int No 180 Interval in seconds between background string interner garbage-collection checks. Lower values reclaim unused interned strings sooner, but run the GC gate more often. Higher values reduce GC overhead, but can retain more memory for longer. Must be greater than 0.
interner_gc_min_pool_size Int No 100 Minimum number of interned strings required before the background interner GC runs. This avoids paying the interner write-lock cost when the pool is very small. Lower values favor aggressive cleanup; higher values favor throughput and lower lock contention at the cost of extra retained memory.
user_access_control Bool No false Security: If true, Tuliprox actively enforces status (Active/Banned), exp_date, and max_connections constraints for users defined in api-proxy.yml. If false, those fields are ignored.
custom_stream_response_path String No null Directory path where Tuliprox looks for custom fallback .ts files. See section Custom Stream Response for exact filenames.
custom_stream_response_timeout_secs Int No 0 Hard timeout (in seconds) that forces the fallback video stream to terminate to prevent infinite bandwidth usage. 0 means endless loop.
custom_stream_response_enabled Bool No true Enables configured custom MPEG-TS fallback videos for stream errors. When false, factories skip the video body and call sites return custom_stream_response_error_status; useful behind reverse proxies that intercept 4xx/5xx responses instead of keeping fallback sockets open.
custom_stream_response_error_status Int No 502 HTTP status code returned when custom_stream_response_enabled is false. Must be a 4xx or 5xx code (the prepare() step rejects anything outside that range; 0 is silently clamped to 502). Common choices: 404 (channel not found), 502 (bad gateway — upstream failed), 503 (service unavailable — overloaded).

⚠️ Important: config_hot_reload & Bind-Mounts

If you use Bind-Mounts (e.g., in fstab or Docker), the filesystem watcher may report the original source path instead of your mount point.

  • Example Setup: /home/tuliprox/config (Source) → /config (Mount Point).
  • Behavior: If you configure Tuliprox to watch /config, the watcher might still trigger events using the path /home/tuliprox/config.
  • Solution: Ensure your internal Tuliprox paths match the paths reported by the OS kernel to ensure the hot-reload trigger fires correctly.

Subsections (Object Keys)

Block Description Link
api Internal web server binding settings. See section
web_ui Web Dashboard, RBAC, and Authentication. See section
log Console output verbosity and sanitization. See section
schedules Automated background tasks (Cronjobs). See section
messaging Webhooks & Push-Notifications (Telegram, Discord, etc.). See section
video Extension mapping and Web UI download behavior. See section
proxy SOCKS5/HTTP proxy settings for outgoing requests. See section
ipcheck IP detection to verify in the Web UI which public IP Tuliprox is currently using. See section
hdhomerun Virtual DVB-C/T network tuner emulation. See section
library Local Media Library integration. See Local Library
reverse_proxy Streaming buffers, rate limits, caching. See Reverse Proxy
metadata_update TMDB matching, FFprobe processing, Job Queues. See Metadata Update

(Note: The advanced topics Local Library, Reverse Proxy and Metadata Update are extremely extensive and have their own dedicated subchapters. Here we cover the global base settings.)


1. API Server (api)

Controls the internal web server of Tuliprox. This does not dictate the public URLs given to clients (those belong in api-proxy.yml), but rather the physical socket binding on your host machine.

api:
  host: 0.0.0.0
  port: 8901
  web_root: ./web
Parameter Type Required Default Technical Impact & Background
host String No 0.0.0.0 Bind interface. 0.0.0.0 listens on all network cards. 127.0.0.1 restricts access to localhost (useful if you force traffic through a local Nginx/Traefik reverse proxy).
port Int No 8901 The listening port for proxy streams, the Web UI, and all REST APIs.
web_root String No ./web Physical path to the compiled Wasm/JS/CSS frontend assets of the Web UI.

2. Web UI & Administration (web_ui)

Tuliprox ships with a comprehensive Web Dashboard containing a Web Player, Playlist Editor, User Management, and Live Logs.

web_ui:
  enabled: true
  user_ui_enabled: true
  path: admin
  player_server: default
  kick_secs: 90
  combine_views_stats_streams: false
  landing_page: dashboard
  stream_info:
    hide_group: false
    hide_ip: false
    hide_country: false
    hide_shared: false
    hide_duration: false
    hide_bandwidth: false
    hide_transferred: false
    hide_player: false
    hide_user_comment: false
    hide_epg: false
  content_security_policy:
    enabled: true
    custom-attributes:
      - "style-src 'self' 'nonce-{nonce_b64}'"
      - "img-src 'self' data:"
  auth:
    enabled: true
    issuer: tuliprox
    secret: "YOUR_SECRET_JWT_KEY_HERE"
    token_ttl_mins: 30
    userfile: user.txt
    groupfile: groups.txt

2.1 Web UI Parameters

Parameter Type Default Technical Impact & Background
enabled Bool true Completely toggles the Web Dashboard and its REST API endpoints on or off.
user_ui_enabled Bool true Allows standard proxy users (not just admins) to log into the Web UI to manage their own favorites/bouquets.
path String "" Base path for the UI (e.g., admin). Critical for reverse proxy subfolder setups so assets load from example.com/admin/assets/.
player_server String default Determines which virtual server block from api-proxy.yml is used to construct the streaming URLs when playing a channel directly within the Web UI player.
kick_secs Int 90 Background: When you kick a user via the Dashboard, they are not only disconnected but hard-blocked at the IP/User level for X seconds. This prevents their IPTV player's auto-reconnect logic from instantly stealing the provider slot back.
combine_views_stats_streams Bool false Combines the "Server Stats" and "Active Streams" views into a single unified window in the UI.
landing_page String dashboard Set the initial landing page for the webui. Possible values are dashboard, stats, streams, stream_history, downloads, users, config, source_editor, playlist_update, playlist_settings, playlist_explorer, playlist_epg, rbac
stream_info Object null Optional visibility controls for fields shown in the active stream display. If omitted, or if all nested hide_* flags are false, the default dashboard view is unchanged.

2.2 Stream Display Visibility (stream_info)

Use this optional block to hide selected fields in the active stream display shown in the dashboard.

web_ui:
  stream_info:
    hide_group: true
    hide_ip: true
    hide_epg: true
Parameter Type Default Technical Impact & Background
hide_group Bool false Hides the stream group/category label.
hide_ip Bool false Hides the client IP shown for an active stream.
hide_country Bool false Hides the detected client country flag/code.
hide_shared Bool false Hides the shared-stream indicator.
hide_duration Bool false Hides the running playback duration.
hide_bandwidth Bool false Hides the live bandwidth badge when metrics are available.
hide_transferred Bool false Hides the transferred-bytes badge when metrics are available.
hide_player Bool false Hides the player / user-agent field.
hide_user_comment Bool false Hides the user comment next to the active stream title.
hide_epg Bool false Hides per-stream EPG information and skips the associated dashboard EPG fetch/update work for that display.
  • If every hide_* flag is false, Tuliprox treats the whole stream_info block as empty/default.
  • This setting is global for the Web UI. It is not currently per-user.

2.3 Content Security Policy (content_security_policy)

This block enhances security by restricting which resources the browser is allowed to load.

  • Default Directives: When enabled: true, Tuliprox automatically applies:
    • default-src 'self'
    • script-src 'self' 'wasm-unsafe-eval' 'nonce-{nonce_b64}'
    • frame-ancestors 'none'
  • Customization: Use custom-attributes to add specific rules (e.g., allowing external channel logos via img-src).

2.4 Authentication & RBAC (auth)

Tuliprox features a robust Role-Based Access Control (RBAC) system.

Parameter Type Default Technical Impact & Background
enabled Bool true Master switch for UI authentication. Disabling this exposes the dashboard to anyone with network access.
issuer String tuliprox The identifier for the JWT "iss" field.
secret String (Random) Critical for JWT encryption. Use a static 64-character hex string using Node.js (see Secret Generation) to keep sessions valid across restarts. If omitted, Tuliprox generates one in-memory, but all active logins will invalidate on every server restart!
token_ttl_mins Int 30 How long a login session remains valid. Setting this to 0 makes the token effectively valid for 100 years (Extreme Security Risk!).
userfile String user.txt The file storing Admins and Web Users.
groupfile String groups.txt The RBAC (Role-Based Access Control) definition file.

Technical Background

  • File Resolution: If userfile is not defined with an absolute path, Tuliprox automatically looks for it within your global config_dir. Ensure the process has sufficient read permissions for this directory.
  • RBAC (Role-Based Access Control): This system manages Web UI access levels (e.g., Admins vs. Bouquet-Editors) by assigning users to specific permission groups defined in groups.txt.

Structure of user.txt

This file stores users, Argon2 password hashes, and RBAC groups. Generate secure passwords via CLI: ./tuliprox --genpwd. The userfile has the following format per line: username:argon2_hash[:group1,group2]

Example:


# A normal Admin (No group specified = Fallback to built-in Admin role)
admin:$argon2id$v=19$m=19456,t=2,p=1$QUp...

# An Editor assigned to specific permission groups
editor:$argon2id$v=19$m=19456,t=2,p=1$Y2F...:playlist_manager,user_manager

Structure of groups.txt

Define group permissions here. An editor might be allowed to update playlists (playlist.write) but forbidden from viewing or changing config.yml (config.read). Format: group_name:permission1,permission2,...

viewer:config.read,source.read,playlist.read,system.read,library.read
playlist_manager:playlist.read,playlist.write,source.read

Available Permissions: config.read/write, source.read/write, user.read/write, playlist.read/write, library.read/write, system.read/write, epg.read/write, download.read/write. Note: Write does not imply Read. A group must explicitly grant both if users need to view and edit content.

Generating Passwords

To ensure security, Tuliprox does not store plain-text passwords. You must generate an encrypted hash using the built-in generator:

Local Installation:

./tuliprox --genpwd

Docker Installation:

docker container exec -it tuliprox ./tuliprox --genpwd

After running the command, copy the generated Argon2id string and manually paste it into your userfile next to the desired username.

JWT Secret Generation

As mentioned in the table above, a static secret is required to keep sessions valid across restarts. You can generate a secure 32-byte (64-character hex) key using Node.js:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Troubleshooting Access

  • File Location: If Tuliprox cannot find the file, check your storage_dir or provide an absolute path in the userfile parameter.
  • Permissions: Ensure the Tuliprox process has read access to the userfile and groupfile.
  • Session Invalidated: If you change the secret in config.yml, all currently logged-in users will be forced to log in again.

3. Logging (log)

Controls console output verbosity and sanitization.

log:
  sanitize_sensitive_info: true
  log_active_user: false
  log_level: info
  runtime_config_report_enabled: false
  runtime_config_report_format: yaml
Parameter Type Default Technical Impact & Background
log_level String info Verbosity. Possible values: trace, debug, info, warn, error. Can be overridden per-module (e.g., tuliprox=debug,hyper_util=warn).
sanitize_sensitive_info Bool true Critical: Masks passwords, provider URLs, and external client IPs in the logs with ***. Highly recommended to keep true so you can safely share logs on GitHub/Discord for support without leaking credentials.
log_active_user Bool false Periodically writes the current active client connection count as an INFO message to the log file.
runtime_config_report_enabled Bool false Opt-in startup dump of the complete effective runtime configuration after defaults, path resolution, and runtime preparation have been applied. Sensitive values such as passwords, secrets, tokens, and API keys are masked as ***.
runtime_config_report_format String yaml Output format for the runtime config report. Supported values: json and yaml. Both formats are emitted as pretty, multi-line output. Ignored unless runtime_config_report_enabled is true.

If enabled, Tuliprox keeps the existing startup summary and prints the additional full runtime report once during startup. The report includes:

  • prepared config.yml
  • prepared source.yml
  • loaded mappings/templates/api-proxy sections when present
  • resolved runtime paths

The report is intended for diagnostics and verification of effective defaults. Sensitive values are redacted before logging.


4. Schedules (schedules)

Automate your background updates to keep your playlists, library, and Geo-IP data synchronized.

⚠️ Provider Safety Warning: Do not schedule updates to run every second or minute. Excessive requests can lead to your IP being banned by your provider. Updating twice a day is generally sufficient for most use cases.

Cron Syntax

Tuliprox uses a standard cron syntax but strictly requires 7 fields, starting with seconds:

# ┌──────────────────────────── second (0 - 59)
# │   ┌──────────────────────── minute (0 - 59)
# │   │   ┌──────────────────── hour (0 - 23)
# │   │   │    ┌─────────────── day of month (1 - 31)
# │   │   │    │   ┌─────────── month (1 - 12)
# │   │   │    │   │   ┌─────── day of week (0 - 6) (Sunday to Saturday; 7 is also Sunday)
# │   │   │    │   │   │   ┌─── year (optional, e.g., 2026)
# │   │   │    │   │   │   │
# sec min hour dom mon dow year
  0   0   8    *   *   *   *

Configuration

In current versions, schedules are defined as a list of tasks.

schedules:
  # Every morning at 08:00:00 (Playlist Update for specific targets)
  - schedule: "0 0 8 * * * *"
    type: PlaylistUpdate
    targets: [ "m3u_target", "xtream_target" ]

  # Every evening at 20:00:00 (Full Library Scan)
  - schedule: "0 0 20 * * * *"
    type: LibraryScan

  # Every Monday at 04:00:00 (Geo-IP Database Refresh)
  - schedule: "0 0 4 * * 1 *"
    type: GeoIpUpdate

  # Every 1st of the month at 04:00:00
  - schedule: "0 0 4 1 * * *"
    type: GeoIpUpdate
Parameter Type Default Description
schedule String - Cron expression with 7 fields (Seconds included at the start).
type Enum PlaylistUpdate The task to execute. See Task Types below.
targets List - (Optional, only for PlaylistUpdate) List of target names to restrict the update to. If omitted, all enabled targets are updated.

Task Types

  • PlaylistUpdate: Triggers the processing pipeline for your target playlists. It downloads provider data, applies filters/maps, and updates the local databases.
  • LibraryScan: Initiates a scan of the local media library. Note: This requires the library configuration to be enabled.
  • GeoIpUpdate: Downloads the latest MaxMind/Geo-IP database and rebuilds the internal binary file. Note: Requires reverse_proxy.geoip.enabled: true.

5. Messaging (messaging)

Tuliprox can proactively notify you via Push-Notifications when updates fail, finish, or when specific channels are added/removed from a watched group. Why is this useful? Because it allows you to instantly detect upstream provider issues or simply let you know when new movies are added to your playlist.

5.1 Configuration & Opt-In

Messaging is strictly opt-in. You must explicitly define which event types should trigger a notification using the notify_on list.

Available Event Types:

  • info: General operational information.
  • stats: Summary of processed items and performance metrics after a run.
  • error: Alerts when processing or source fetching fails.
  • watch: Triggered by changes in monitored groups/targets.
messaging:
  notify_on: [ "info", "stats", "error", "watch" ]

  # Telegram: Supports Markdown and Group Topics
  telegram:
    markdown: true
    bot_token: "<TOKEN>"
    chat_ids:
      - "<CHAT_ID>"
      - "<CHAT_ID>:<MESSAGE_THREAD_ID>" # Use colon to target specific Discord-like topics/threads
    templates:
      stats: 'file:///config/messaging_templates/telegram_stats.templ'

  # Discord: Webhook integration
  discord:
    url: "<WEBHOOK_URL>"
    templates:
      info: '{"content": "🚀 Tuliprox Info: {{message}}"}'

  # Pushover: Simple mobile push alerts
  pushover:
    token: "<API_TOKEN>"
    user: "<USER_KEY>"
    # url: "https://api.pushover.net/1/messages.json" # Optional default

  # REST: Generic Webhook/API support
  rest:
    url: "https://my-api.local/alert"
    method: "POST" # Optional, defaults to POST
    headers:
      - "Content-Type: application/json"
    templates:
      error: '{"text": "Alert: {{message}}", "type": "{{kind}}"}'

5.2 Templating (Handlebars)

For Telegram, Discord, and REST, Tuliprox uses Handlebars to format message bodies. This allows for rich, structured notifications (e.g., Discord Embeds or Markdown tables).

Loading Methods

  1. Raw String: Define the template directly in your config.yaml (best for simple one-liners).
  2. URI: Reference a local file (file://...) or a remote resource (http://...).

Note: If you save your configuration via the Web UI, raw template strings are automatically moved to individual files in /config/messaging_templates/ to keep your main configuration clean.

Available Context Variables

The Handlebars engine provides a rich context object. Depending on the kind of notification, different variables are populated:

  • {{message}}: The primary text payload. Used for human-readable info messages or the summary of an error.
  • {{kind}}: The event category (info, stats, error, watch). Use this in Handlebars helpers (e.g., {{#if (eq kind "error")}}) to create conditional layouts.
  • {{timestamp}}: The event occurrence time in UTC (ISO 8601 / RFC3339 format).
  • {{stats}}: Execution Metrics & Performance. A comprehensive list of statistics for the last update cycle, covering both ingestion and generation phases.
    • Structure: A nested list containing inputs (Source-level metrics) and targets (Output-level metrics).
    • Access: Iterate over the main list to access individual source or target reports. Use nested loops for detailed input/target breakdowns: {{#each stats}} {{#each inputs}} ... {{/each}} {{/each}}.
    • Key Properties:
      • Metadata: Access name, type, and took (execution duration) for each entry.
      • Error Tracking: errors provides a count of failed items or connection issues during that specific phase.
      • Filtering Delta: Compare raw counts (total items received from the provider) vs. processed counts ( items that survived your Mapping DSL and filters) to monitor your "Red Thread" efficiency.
  • {{processing}}: Engine State & Telemetry. Provides insight into the internal execution environment during the task. It includes data on memory allocation peaks, active worker threads, and non-blocking diagnostic warnings.
    • Access: Access properties directly via dot-notation (e.g., {{processing.memory_peak_mb}}). Use this to monitor system health and resource consumption during heavy mapping cycles.
  • {{watch}}: Change Tracking Data. Specifically available for the watch event kind. It contains a diff-style object showing exactly which groups or channels were added, removed, or modified compared to the previous state.
    • Access: Iterate over the change sets using loops. Common keys include added, removed, and modified.
    • Example: Use {{#each watch.added}} • {{name}} {{/each}} to list all new channels detected in the monitored groups.

Template Examples

Telegram (Markdown Report):

*🔄 Playlist Update Report*

{{#each stats}}
*📥 Source Stats*
{{#each inputs}}
• *{{name}}* (`{{type}}`)
  ⏱️ Took: `{{took}}` | ❌ Errors: `{{errors}}`
  📊 `{{raw.groups}}`/`{{raw.channels}}` ➔ *`{{processed.groups}}`*/*`{{processed.channels}}`*
{{/each}}
{{/each}}

Discord (Complex Embed):

{
  "content": "Tuliprox Notification",
  "embeds": [{
    "title": "Event: {{kind}}",
    "description": "{{message}}",
    "color": 3447003,
    "fields": [
      {{#each stats}}
      { "name": "Source {{@index}}", "value": "Processed {{#each inputs}}{{name}} {{/each}}", "inline": false }
      {{/each}}
    ],
    "footer": { "text": "Reported at {{timestamp}}" }
  }]
}

5.3 Disk-Space Alerts (messaging.disk_alert)

Tuliprox monitors the free space on the current working directory's mount and notifies you via the standard messaging channels (Telegram, Discord, Pushover, REST) before the disk fills up. The feature is opt-in: no disk_alert block means no monitoring and no notifications.

How it works: A background loop in backend/src/api/sys_usage.rs ticks every 2 seconds (fixed sampling interval — see SYSTEM_USAGE_INTERVAL in that file, not configurable) and compares the current working directory's percent-used against two thresholds. The DiskAlertMonitor state machine (backend/src/api/sys_usage.rs::DiskAlertMonitor) decides when to emit a DiskAlert:

Level Default Trigger Operator Action
Normal < warn_percent All good.
Warn warn_percent (default 80.0) Plan a cleanup.
Critical critical_percent (default 95.0) Cleanup is urgent; stream generation may fail.

A DiskAlert is emitted whenever the level is non-Normal and either:

  1. the level just changed (Normal → Warn, Warn → Critical, or any step back down), or
  2. the disk has stayed in the same alert state for at least repeat_interval_secs seconds since the previous notification.

This periodic re-notification is intentional: a long-running full-disk situation that nobody fixes would otherwise go silent after the first transition, defeating the purpose of the feature. With the default repeat_interval_secs: 3600 (1 hour), a stuck-at-87% disk produces one Warn notification per hour instead of a single one-shot alert.

messaging:
  notify_on: [ "info", "stats", "error", "watch" ]

  # Disk-space alerts are sent through the channels above. Configure the
  # thresholds and the re-arm interval here. The 2-second sampling tick is
  # internal and not configurable.
  disk_alert:
    # Percent-used at which the Warn level is reached. Default: 80.0.
    # Must be in [0, 100].
    warn_percent: 80.0
    # Percent-used at which the Critical level is reached. Default: 95.0.
    # Must be in (warn_percent, 100].
    critical_percent: 95.0
    # Re-arm interval in seconds. While the disk stays in the same alert
    # state, the alert is re-sent after this many seconds. Default: 3600
    # (1 hour). This is NOT the sampling interval — sampling is fixed at
    # 2 seconds and is not currently configurable.
    repeat_interval_secs: 3600

  telegram:
    bot_token: "<TOKEN>"
    chat_ids: [ "<CHAT_ID>" ]
    templates:
      # Custom templates per level. Plain-text defaults are used if omitted.
      disk_alert_warn: "⚠️ Disk is {{percent}}% full (Warn threshold)."
      disk_alert_critical: "🚨 Disk is {{percent}}% full — cleanup now!"
      disk_alert_normal: "✅ Disk back to normal at {{percent}}%."

Note on mounts: Earlier drafts of this section described a mounts config field. The current implementation has no such field — the disk probe is hard-coded to sample the current working directory's mount (see DiskProbe::for_cwd() in backend/src/api/sys_usage.rs). If you need to monitor a different path, change the working directory of the Tuliprox process.

Available Handlebars Variables (all disk_alert_* templates):

  • {{level}} — The new level after the transition (Warn, Critical, or Normal).
  • {{percent}} — Current percent-used, rounded to one decimal place.
  • {{free_bytes}} / {{total_bytes}} / {{used_bytes}} — Raw byte counts for the sampled mount.
  • {{timestamp}} — Event time in UTC (ISO 8601 / RFC3339).

Available template keys per channel (Handlebars): disk_alert_warn, disk_alert_critical, disk_alert_normal. If a template is not configured for a level, Tuliprox falls back to a clear plain-text default line, e.g.:

[WARN] Disk is 82.3% full (free=3.4GB total=19.0GB). Note: Disk alerts are sent through every configured messaging channel. If you want a channel to ignore disk alerts, simply do not declare the matching disk_alert_* template key for it and it will still receive the plain-text default. Use the standard notify_on list to control which event kinds are sent at all.


6. Video & Web Search (video)

Optional video-related behaviors, mostly utilized by the Web UI.

video:
  web_search: "https://www.imdb.com/search/title/?title={}"
  extensions: [ "mkv", "mp4", "avi", "ts", "webm" ]
  download:
    directory: /tmp/tuliprox_downloads
    headers:
      User-Agent: "AppleTV/tvOS/9.1.1"
      Accept: "video/*"
    organize_into_directories: true
    episode_pattern: '.*(?P<episode>[Ss]\d{1,2}(.*?)[Ee]\d{1,2}).*'
  • web_search: A template URL used in the Web UI to quickly search for a movie title (replaces {} with the title).
  • extensions: Defines which file endings Tuliprox categorizes as VOD/Video content when transforming M3U to Xtream.
  • download: Configuration for the Web UI download and recording manager.
    • directory: Where downloaded files and recordings are saved.
    • headers (optional): Custom HTTP headers used for the download request. This is useful for bypassing basic user-agent filters or setting specific media types.
    • organize_into_directories: If true, Tuliprox automatically creates neat subfolders for series.
    • episode_pattern: Crucial for the directory organization. It uses the mandatory Named Capture Group (?P<episode>...) in the Regex to identify and strip the episode identifier (e.g., S01E01) from the filename, ensuring all episodes of a show land in the same base-show folder.
    • download_priority: Default provider priority for VOD/series/episode downloads. Lower values mean higher priority.
    • recording_priority: Default provider priority for live recordings. Lower values mean higher priority.
    • reserve_slots_for_users: Keeps provider headroom for normal foreground users before background-priority transfers may consume the last slots.
    • max_background_per_provider: Limits how many background-priority transfers may run in parallel against one provider.
    • retry_backoff_initial_secs: Initial retry delay for transient download/recording failures.
    • retry_backoff_multiplier: Growth factor applied to each later retry delay.
    • retry_backoff_max_secs: Maximum retry delay once the backoff curve reaches its cap.
    • retry_backoff_jitter_percent: Randomizes retry delays to avoid retry spikes after shared upstream problems.
    • retry_max_attempts: Maximum number of transient retries before a transfer is marked as failed.

Tuliprox handles these transfers like provider-bound background streams:

  • They respect provider limits, user priorities, and connection preemption instead of bypassing normal stream capacity.
  • Waiting for provider capacity is notify-based, not polling-based.
  • The Web UI loads an initial transfer snapshot and then stays synchronized through websocket updates.
  • Changes to video.download participate in hot config reloads. The background scheduler restarts and active transfers are
    re-queued so they continue under the updated download configuration.
  • RBAC integration is explicit:
    • download.read allows opening the downloads view and receiving transfer snapshots.
    • download.write allows queueing, pausing, cancelling, retrying, and removing transfers.
  • Persisted queue recovery is tolerant of corruption. If downloads_state.json cannot be deserialized,
    Tuliprox renames it to a timestamped *_corrupt.*.json backup and starts with an empty transfer queue instead of aborting server boot.

Note: The named capture group (?P<episode>...) is mandatory for this to function correctly.

Example: .*(?P<episode>[Ss]\d{1,2}(.*?)[Ee]\d{1,2}).*


7. Outgoing Proxy (proxy)

If Tuliprox itself must operate behind a corporate proxy or VPN (e.g., a Gluetun WireGuard container):

proxy:
  url: socks5://192.168.1.6:8123
  username: "opt_user"
  password: "opt_password"

Setting this forces every outgoing request (Playlist downloads, TMDB API calls, FFprobe stream analysis, and Reverse-Proxy Video Streaming) through this proxy.


8. IP-Check (ipcheck)

To verify in the Web UI which public IP Tuliprox is currently using (crucial when verifying VPN routing or diagnosing geo-blocks), Tuliprox queries external detection APIs. This ensures that your traffic is actually routed through the intended gateway or VPN tunnel.

ipcheck:
  url: "[https://api64.ipify.org?format=json](https://api64.ipify.org?format=json)" # Generic URL for both IP versions
  url_ipv4: "[https://ipinfo.io/ip](https://ipinfo.io/ip)"          # Dedicated IPv4 fetch
  url_ipv6: "[https://v6.ident.me](https://v6.ident.me)"           # Dedicated IPv6 fetch
  pattern_ipv4: '(?:\d{1,3}\.){3}\d{1,3}'   # Optional Regex for extraction
  pattern_ipv6: '([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}'
Parameter Type Technical Impact
url String A generic endpoint that may return both IPv4 and IPv6 in a single response (often JSON).
url_ipv4 String A dedicated URL to fetch only the public IPv4 address.
url_ipv6 String A dedicated URL to fetch only the public IPv6 address.
pattern_ipv4 Regex Optional regex pattern to extract the IPv4 string from complex API responses (e.g., if the API returns a full JSON object).
pattern_ipv6 Regex Optional regex pattern to extract the IPv6 string from complex API responses.

Technical Background

  • VPN Validation: This feature is primarily used to confirm that Tuliprox is successfully using a VPN or Proxy. If the displayed IP in the Web UI matches your home ISP instead of your VPN provider, your routing is likely misconfigured.
  • Regex Extraction: If your preferred IP-API returns data in a format like {"ip": "1.2.3.4", "city": "Berlin"}, you can use the pattern_ipv4 to isolate just the IP address for the Tuliprox UI.
  • Execution: The check is performed periodically or on-demand when accessing the Dashboard to provide real-time connectivity status.

9. HDHomeRun Emulation (hdhomerun)

Deep-Dive Feature: Tuliprox can masquerade on the local network as a physical SiliconDust HDHomeRun DVB-C/S/T network tuner. Media servers like Plex, Jellyfin, Emby, or TVHeadend will automatically discover Tuliprox via UPnP as a real hardware antenna and ingest Live-TV natively into their Live-DVR systems.

Tuliprox utilizes standardized UPnP/SSDP (UDP Port 1900) for broad compatibility and the proprietary SiliconDust protocol (UDP Port 65001) for compatibility with official HDHomeRun tools.

hdhomerun:
  enabled: true
  auth: false # If true, lineup.json requires Basic Auth (using the assigned user's credentials)
  devices:
    - name: hdhr1             # MUST match the 'device' name in the source.yml hdhomerun output!
      tuner_count: 4          # Number of concurrent streams the client thinks are available
      port: 5004              # Unique TCP Port for this specific virtual tuner API
      device_id: "107ABCDF"   # 8-char hex code (Port 65001). If left blank, Tuliprox generates a valid one with correct checksums.
      device_udn: "uuid:..."  # Unique Device Name (Port 1900). Recommended to leave blank for auto-generation.
      friendly_name: "Tuliprox Living Room"

Configuration Parameters

Parameter Type Default Description
enabled Bool false Master switch for the entire emulation engine.
auth Bool false Requires HTTP Basic Auth for the /lineup.json endpoint using the assigned user's credentials.
devices List [] A list of virtual HDHomeRun devices to emulate.

9.1. Device-Specific Fields

Parameter Type Default Technical Impact & Background
name String Required Unique internal identifier. Must match the device field in your source.yml target mapping.
tuner_count Int 1 Number of virtual tuners reported to the client. Defines how many concurrent streams Plex/Emby thinks the "hardware" can handle.
port Int API+1 TCP port for the HTTP API (/device.xml, /lineup.json). Each virtual device must have a unique port.
friendly_name String (Auto) The display name in client applications (e.g., "Tuliprox Living Room").
device_id Hex (Auto) 8-char hex ID for SiliconDust protocol (Port 65001). Tuliprox automatically corrects invalid IDs by calculating the required checksum.
device_udn UUID (Auto) Unique Device Name for UPnP/SSDP (Port 1900). Recommended to leave blank for auto-generation.
manufacturer String SiliconDust Customizes the manufacturer string reported to clients.
model_name String HDTC-2US Mimics a specific hardware model for maximum compatibility with official apps.
firmware_name String hdhomerun3_atsc The firmware type reported during the discovery handshake.

Note: Advanced metadata fields like model_number and firmware_version can also be overridden but are safe to leave at their defaults to ensure the best "plug-and-play" experience with media servers.

9.2. Linking Devices to Playlists

The name of each device in config.yml must correspond to a device reference in a hdhomerun output target within your source.yml.

Example source.yml snippet:

targets:
  - name: my-tv-lineup
    output:
      - type: hdhomerun
        device: hdhr1      # Link to the device defined above
        username: local    # The user whose credentials/playlist will be served

Discovery Protocols: A Technical Distinction

To satisfy both official SiliconDust hardware scanners and generic third-party UPnP discovery, Tuliprox handles two distinct layers:

  1. device_id (Port 65001): Used by proprietary SiliconDust tools. It requires a specific hexadecimal format and checksum.
  2. device_udn (Port 1900): Used by the standard SSDP/UPnP protocol (e.g., by Plex or VLC). This identifies the device as a unique UUID on the network.

Pro-Tip: If Plex fails to find your device, ensure that the UDP ports 1900 and 65001 are not blocked by your firewall and that Tuliprox is running on the same network subnet as your media server.

 

Additional Information

Custom Stream Responses (Fallback Videos)

When a stream fails to load at the provider (HTTP 404/502) or a user reaches their connection limit, Tuliprox can seamlessly substitute a fallback info-video (as a .ts stream) instead of brutally closing the TCP connection. Dropping connections often causes hardware players or Smart TVs to freeze.

custom_stream_response_path: /home/tuliprox/resources
custom_stream_response_timeout_secs: 20
Name Type Default Technical Impact & Background
custom_stream_response_path String (Empty) Directory path where Tuliprox looks for exactly named .ts files.
custom_stream_response_timeout_secs Int 0 Hard timeout (in seconds) that forces the fallback video stream to terminate to prevent infinite bandwidth usage. 0 means the fallback loops endlessly until the user switches channels.

Filenames searched for in the directory:

  • channel_unavailable.ts (Provider returns 404/502/Timeout)
  • user_connections_exhausted.ts (User hit their max_connections limit)
  • provider_connections_exhausted.ts (Provider has no free slots left)
  • low_priority_preempted.ts (User was kicked by an Admin with higher priority)
  • user_account_expired.ts (User's exp_date reached)
  • panel_api_provisioning.ts (Loops while a new Provider Account is generated via Panel API)
  • hls_session_or_lease_expired.ts (Shared-HLS session or access lease expired; restart stream)

Note: These Video files are all available in the docker image.

How to create your own fallback video stream: You can simply convert an image with ffmpeg.

ffmpeg -y -nostdin -loop 1 -framerate 30 -i blank_screen.jpg -f lavfi \
  -i anullsrc=channel_layout=stereo:sample_rate=48000 -t 10 -shortest -c:v libx264 \
  -pix_fmt yuv420p -preset veryfast -crf 23 -x264-params "keyint=30:min-keyint=30:scenecut=0:bframes=0:open_gop=0" \
  -c:a aac -b:a 128k -ac 2 -ar 48000 -mpegts_flags +resend_headers -muxdelay 0 -muxpreload 0 -f mpegts blank_screen.ts

The filename identifies the file inside the path custom_stream_response_path.

How it works: Tuliprox searches the specified folder for exactly named .ts files. If found, they are looped back to the client. The custom_stream_response_timeout_secs parameter hard-kills the fallback stream after X seconds to prevent infinite bandwidth usage.