Refresh idle leases before deciding terminal playback, and keep evicted
windows retryable while the manifest refresh is debounced.
Avoid the global access-lease write lock on healthy completions.
Revalidate failed attempts after acquiring lease-store and session locks.
Cover idle recovery in all startup modes and cleanup lock contention.
* fast get_series, memory-cache lists, consistent sort order
- skip series episode details on list decode and in memory cache
- serve Xtream lists from memory cache in canonical order
- keep sorted index valid after resolve writes
- cache verify_full per database identity
- resource proxy: single attempt, 15s timeout, 6 fetches per host
* Ship log records to an external syslog collector over UDP
Add opt-in log.syslog (off by default): RFC 5424, RFC 3164 or NDJSON
datagrams, optional remote log level independent of stdout and the
Web-UI, bounded queue with drop counters, dedicated worker thread, live
reload without restart.
* fix filter parse long filter chains without a stack limit error
pest 2.9.4 probes the native stack before parsing and reports only the
mapped stack region on static musl (~128 KiB), so a filter chain of a few
dozen terms failed with "stack limit reached" and restarted the container.
pest 2.9.5 limits the probe to targets whose stack bounds it can determine.
The expr rule now reads a chain as a flat operand list and folds it from the
right, so a long AND/OR chain no longer nests the parser stack while
grouping, NOT binding and results stay identical to the previous grammar.
* fix filter parse long filter chains without a stack limit error
pest 2.9.4 probes the native stack before parsing and reports only the
mapped stack region on static musl (~128 KiB), so a filter chain of a few
dozen terms failed with "stack limit reached" and restarted the container.
pest 2.9.5 limits the probe to targets whose stack bounds it can determine.
The expr rule now reads a chain as a flat operand list and folds it from the
right, so a long AND/OR chain no longer nests the parser stack while
grouping, NOT binding and results stay identical to the previous grammar.
* store the filter tree in an arena instead of nested boxes
Parsing, rendering, evaluating and dropping a filter no longer recurse per term,
so a long AND/OR chain no longer depends on the thread's stack.
* fix: accept ranged VOD responses mislabeled text/html
Skip the HTML content-type rejection for 206 and Content-Range
responses so valid media from providers with a wrong Content-Type
plays in reverse proxy mode.
* add playback_provider to bind provider profile
Lets mapped provider:// playback URLs resolve on inputs whose url and
aliases are plain http(s), fixing 503 "Provider config not found".
* hls: add origin transfer telemetry
Measure existing shared-HLS origin fetches (segment, map, key,
manifest) and expose per-input availability and transfer quality at
GET /api/v1/hls/origin-telemetry and via the MCP tool
get_hls_origin_telemetry. Off by default via
reverse_proxy.hls_origin_telemetry, configurable in the Web UI.
Also split the reverse proxy config page into tabs.
* hls: add origin transfer telemetry
Measure existing shared-HLS origin fetches (segment, map, key,
manifest) and expose per-input availability and transfer quality at
GET /api/v1/hls/origin-telemetry and via the MCP tool
get_hls_origin_telemetry. Off by default via
reverse_proxy.hls_origin_telemetry, configurable in the Web UI.
Also split the reverse proxy config page into tabs.
* hls: add origin transfer telemetry
Measure existing shared-HLS origin fetches (segment, map, key,
manifest) and expose per-input availability and transfer quality at
GET /api/v1/hls/origin-telemetry and via the MCP tool
get_hls_origin_telemetry. Off by default via
reverse_proxy.hls_origin_telemetry, configurable in the Web UI.
Also split the reverse proxy config page into tabs.
---------
Co-authored-by: euzu <euzu@proton.me>
The provider:// origin rewrite called get_user_info() before checking
whether a credential rewrite is needed. Token-only M3U accounts have no
username/password, so the media manifest failed with 503 before
Media-server items shared one UUID in duplicate_filter, so Jellyfin
catalogs collapsed to a single entry. Derive the UUID from the stable
media-server id. Set header.logo for movies, series and episodes so
Xtream and M3U clients show posters.
* Added
- MCP server with Web UI config, stdio bridge and docs
Fixes
- GET /api/v1/stream-history rejected the `search_field` parameter the Web UI
sends (400), because axum's Query cannot read repeated keys into a list.
Add a FormQuery extractor (serde_html_form) and use it there.
- hls tests were flaky: HlsProxyManager::new() put every test manager's
segment cache into the shared /tmp/tuliprox/cache/hls, and the orphan
session cleanup of one manager deleted the files of parallel tests
(surfacing as MissingTimestampAnchor / TerminalUnavailable). Each manager
now owns a private cache directory that is removed on drop.
* fixed documentation: db dump paths and flag usage in operations-debugging
* Logs is a standalone Web UI view.
* mcp playlist iterator
* mcp playlist iterator
* media server import uses own categories
* mcp playlist iterator
* Playlit Update view layout changed
* media-server scheme or jellyfin_emby_plex
select_provider_stream_url now accepts a media-server:// reference when
the input type is Emby, Jellyfin or Plex. Other input types still reject
it.