Enhanced Metadata Resolution, Stream Analysis & Improved STRM-Output. Added connection priority management.

**Description:**
This PR introduces a major overhaul of how streams are analyzed and connections are managed. It integrates `ffprobe` for deep stream analysis, adds a background task queue for metadata resolution to prevent UI blocking, introduces a connection priority system, and adds support for Live TV probing.

### 🚀 Key Features

*   **FFprobe Integration & Live TV Probing**:
    *   Automatically probes streams (VOD/Series **and now Live TV**) to determine resolution, codecs (HEVC/AV1), dynamic range (HDR/DV), bit depth, and audio channels.
    *   **Safe Probing**: Probing strictly respects the provider's `max_connections` limit.
    *   Docker images now include static `ffmpeg/ffprobe` binaries.

*   **Smart Connection Management (Priority System)**:
    *   Introduced a priority system for connections to manage provider limits intelligently.
    *   **Preemption**: Users with higher priority can preempt (kick) lower priority connections when provider slots are full.
    *   **Background Queue**: Metadata resolution and stream analysis run as background tasks (Priority 0). They only run when connection slots are idle and yield immediately if a real user needs to stream.

*   **Enhanced Metadata Resolution**:
    *   **Fallback Logic**: If a provider is missing the TMDB ID or Release Date, the system resolves them via the TMDB API.
    *   **Smart Title Cleaning**: Implemented a centralized cleaner to strip common IPTV prefixes before attempting metadata matches or generating filenames, significantly improving match rates.

*   **Improved Output**:
    *   **Quality Tags**: Filenames in STRM files now include detailed tags (e.g., `Movie - [4K HEVC HDR].strm`).
    *   **Flat Grouping**: `flat: true` now correctly groups multi-version movies into single folders based on TMDB ID.
    *   **Global Series Date**: Ensures consistent series folder naming even if episodes have different years.
This commit is contained in:
euzu
2026-02-12 15:06:57 +01:00
committed by GitHub
parent f78c142cba
commit fc0f1f32aa
89 changed files with 7581 additions and 1460 deletions
+56 -9
View File
@@ -1,29 +1,76 @@
pub mod playlist;
mod playlist;
mod xtream;
// mod affix;
mod xtream_vod;
mod xtream_series;
pub mod epg;
mod epg;
mod sort;
pub mod trakt;
mod trakt;
mod library;
mod stream_probe;
pub use self::playlist::*;
pub use self::epg::*;
pub use self::xtream::*;
pub use self::xtream_vod::*;
pub use self::xtream_series::*;
pub use self::stream_probe::*;
use shared::create_bit_set;
create_bit_set!(u16, ResolveOptionsFlags, Resolve, TmdbMissing, Probe, Background);
pub struct ResolveOptions {
pub flags: ResolveOptionsFlagsSet,
pub resolve_delay: u16,
}
impl Default for ResolveOptions {
fn default() -> Self {
Self {
flags: ResolveOptionsFlagsSet::from_variants(&[ResolveOptionsFlags::Background]),
resolve_delay: 0,
}
}
}
//
// fn get_resolve_<cluster>_options(target: &ConfigTarget, fpl: &FetchedPlaylist) -> (bool, u16)
// fn get_resolve_<cluster>_options(target: &ConfigTarget, fpl: &FetchedPlaylist) -> bool
//
#[macro_export]
macro_rules! create_resolve_options_function_for_xtream_target {
($cluster:ident) => {
paste::paste! {
fn [<get_resolve_ $cluster _options>](target: &ConfigTarget, fpl: &FetchedPlaylist) -> (bool, u16) {
fn [<get_resolve_ $cluster _options>](target: &ConfigTarget, fpl: &FetchedPlaylist) -> $crate::processing::processor::ResolveOptions {
// Get input options
let (resolve_tmdb_missing, probe_requested) = fpl.input.options.as_ref().map_or_else(||(false, false), |o| (o.resolve_tmdb, o.probe_stream));
match target.get_xtream_output() {
Some(xtream_output) => (xtream_output.[<resolve_ $cluster>] && fpl.input.input_type == InputType::Xtream,
xtream_output.[<resolve_ $cluster _delay>]),
None => (false, 0)
Some(xtream_output) => {
let mut flags = $crate::processing::processor::ResolveOptionsFlagsSet::new();
// Map config flags to resolve options flags
if xtream_output.flags.contains($crate::model::XtreamTargetFlags::[<Resolve $cluster:camel>]) && fpl.input.input_type.is_xtream() {
flags.add($crate::processing::processor::ResolveOptionsFlags::Resolve);
}
if resolve_tmdb_missing {
flags.add($crate::processing::processor::ResolveOptionsFlags::TmdbMissing);
}
if probe_requested
&& fpl.input.input_type.is_xtream()
&& xtream_output.flags.contains($crate::model::XtreamTargetFlags::[<Probe $cluster:camel>]) {
flags.add($crate::processing::processor::ResolveOptionsFlags::Probe);
}
if xtream_output.flags.contains($crate::model::XtreamTargetFlags::ResolveBackground) {
flags.add($crate::processing::processor::ResolveOptionsFlags::Background);
}
$crate::processing::processor::ResolveOptions {
flags,
resolve_delay: xtream_output.resolve_delay,
}
},
None => $crate::processing::processor::ResolveOptions::default(),
}
}
}
};
}
use create_resolve_options_function_for_xtream_target;