Feature/panel api update (#524)

Panel Api update
This commit is contained in:
euzu
2026-01-20 18:51:46 +01:00
committed by GitHub
parent 14b7361fed
commit cc2e50549d
88 changed files with 8249 additions and 1605 deletions
+2 -3
View File
@@ -27,9 +27,8 @@ use crate::processing::processor::sort::sort_playlist;
use crate::processing::processor::trakt::process_trakt_categories_for_target;
use crate::processing::processor::xtream_series::playlist_resolve_series;
use crate::processing::processor::xtream_vod::playlist_resolve_vod;
use crate::repository::playlist_repository::{load_input_playlist, persist_input_playlist, persist_playlist};
use crate::repository::xtream_repository::CategoryKey;
use crate::repository::{MemoryPlaylistSource, PlaylistSource};
use crate::repository::{load_input_playlist, persist_input_playlist, persist_playlist};
use crate::repository::{CategoryKey, MemoryPlaylistSource, PlaylistSource};
use crate::utils::StepMeasure;
use crate::utils::{debug_if_enabled, trace_if_enabled};
use futures::StreamExt;
+24 -12
View File
@@ -45,7 +45,6 @@ fn playlist_comparator(
match (match_a, match_b) {
(Some((idx_a, caps_a)), Some((idx_b, caps_b))) => {
// Different regex indices → sort by their sequence order.
if idx_a != idx_b {
return match order {
SortOrder::Asc => idx_a.cmp(&idx_b),
@@ -66,15 +65,19 @@ fn playlist_comparator(
for name in named {
let va = caps_a.name(name).map(|m| m.as_str());
let vb = caps_b.name(name).map(|m| m.as_str());
if let (Some(va), Some(vb)) = (va, vb) {
let o = va.cmp(vb);
if !matches!(o, Ordering::Equal) {
return match order {
SortOrder::Asc => o,
SortOrder::Desc => o.reverse(),
SortOrder::None => Ordering::Equal,
};
}
let o = match (va, vb) {
(Some(a), Some(b)) => a.cmp(b),
(Some(_), None) => Ordering::Greater,
(None, Some(_)) => Ordering::Less,
_ => Ordering::Equal,
};
if o != Ordering::Equal {
return match order {
SortOrder::Asc => o,
SortOrder::Desc => o.reverse(),
SortOrder::None => Ordering::Equal,
};
}
}
@@ -205,15 +208,24 @@ fn sort_channels_in_groups(
let va = vp_a.get(rule.field.as_str());
let vb = vp_b.get(rule.field.as_str());
let ord = match (va, vb) {
let ord = match (&va, &vb) {
(None, None) => Ordering::Equal,
(Some(_), None) => direction(rule.order, Ordering::Less),
(None, Some(_)) => direction(rule.order, Ordering::Greater),
(Some(va), Some(vb)) => {
playlist_comparator(rule.sequence.as_ref(), rule.order, &va, &vb)
playlist_comparator(rule.sequence.as_ref(), rule.order, va, vb)
}
};
if ord == Ordering::Equal {
if let (Some(va), Some(vb)) = (&va, &vb) {
let fallback = direction(rule.order, va.cmp(vb));
if fallback != Ordering::Equal {
return fallback;
}
}
}
if ord != Ordering::Equal {
return ord;
}
+10 -2
View File
@@ -4,12 +4,20 @@ use crate::model::{ConfigInput, InputSource};
use shared::model::{PlaylistEntry, PlaylistItem, XtreamCluster};
use crate::utils::xtream;
pub(in crate::processing) async fn playlist_resolve_download_playlist_item(client: &reqwest::Client, pli: &PlaylistItem, input: &ConfigInput, errors: &mut Vec<TuliproxError>, resolve_delay: u16, cluster: XtreamCluster) -> Option<String> {
pub(in crate::processing) async fn playlist_resolve_download_playlist_item(
client: &reqwest::Client,
pli: &PlaylistItem,
input: &ConfigInput,
errors: &mut Vec<TuliproxError>,
resolve_delay: u16,
cluster: XtreamCluster,
default_user_agent: Option<&str>,
) -> Option<String> {
let mut result = None;
let provider_id = pli.get_provider_id()?;
if let Some(info_url) = xtream::get_xtream_player_api_info_url(input, cluster, provider_id) {
let input_source = InputSource::from(input).with_url(info_url);
result = match xtream::get_xtream_stream_info_content(client, &input_source, true).await {
result = match xtream::get_xtream_stream_info_content(client, &input_source, true, default_user_agent).await {
Ok(content) => Some(content),
Err(err) => {
errors.push(info_err!("{err}"));
@@ -4,9 +4,7 @@ use crate::processing::parser::xtream::parse_xtream_series_info;
use crate::processing::processor::create_resolve_options_function_for_xtream_target;
use crate::processing::processor::playlist::ProcessingPipe;
use crate::processing::processor::xtream::playlist_resolve_download_playlist_item;
use crate::repository::storage::get_input_storage_path;
use crate::repository::xtream_repository::persist_input_series_info_batch;
use crate::repository::{MemoryPlaylistSource, PlaylistSource};
use crate::repository::{get_input_storage_path, persist_input_series_info_batch, MemoryPlaylistSource, PlaylistSource};
use log::{error, info, log_enabled, Level};
use shared::error::TuliproxError;
use shared::model::{InputType, PlaylistEntry, SeriesStreamProperties, StreamProperties, XtreamSeriesInfo};
@@ -50,6 +48,7 @@ async fn playlist_resolve_series_info(app_config: &Arc<AppConfig>, client: &reqw
let mut processed_series_info_count = 0;
let mut group_series: HashMap<u32, PlaylistGroup> = HashMap::new();
let mut batch = Vec::with_capacity(BATCH_SIZE);
let default_user_agent = app_config.config.load().default_user_agent.clone();
let input = fpl.input;
for pli in fpl.items_mut() {
@@ -66,7 +65,17 @@ async fn playlist_resolve_series_info(app_config: &Arc<AppConfig>, client: &reqw
let should_download = resolve_series && !pli.has_details();
if should_download {
processed_series_info_count += 1;
if let Some(content) = playlist_resolve_download_playlist_item(client, pli, input, errors, resolve_delay, XtreamCluster::Series).await {
if let Some(content) = playlist_resolve_download_playlist_item(
client,
pli,
input,
errors,
resolve_delay,
XtreamCluster::Series,
default_user_agent.as_deref(),
)
.await
{
if !content.is_empty() {
match serde_json::from_str::<XtreamSeriesInfo>(&content) {
Ok(info) => {
+14 -3
View File
@@ -2,8 +2,8 @@ use crate::model::FetchedPlaylist;
use crate::model::{AppConfig, ConfigTarget};
use crate::processing::processor::create_resolve_options_function_for_xtream_target;
use crate::processing::processor::xtream::playlist_resolve_download_playlist_item;
use crate::repository::storage::get_input_storage_path;
use crate::repository::xtream_repository::persist_input_vod_info_batch;
use crate::repository::get_input_storage_path;
use crate::repository::persist_input_vod_info_batch;
use log::{error, info, log_enabled, Level};
use shared::error::TuliproxError;
use shared::model::{InputType, PlaylistEntry, StreamProperties, VideoStreamProperties, XtreamVideoInfo};
@@ -41,6 +41,7 @@ pub async fn playlist_resolve_vod(app_config: &Arc<AppConfig>,
let mut last_log_time = Instant::now();
let mut processed_vod_info_count = 0;
let mut batch = Vec::with_capacity(BATCH_SIZE);
let default_user_agent = app_config.config.load().default_user_agent.clone();
provider_fpl.source.release_resources(XtreamCluster::Video);
@@ -54,7 +55,17 @@ pub async fn playlist_resolve_vod(app_config: &Arc<AppConfig>,
let Some(provider_id) = pli.get_provider_id() else { continue; };
processed_vod_info_count += 1;
if provider_id != 0 {
if let Some(content) = playlist_resolve_download_playlist_item(client, pli, input, errors, resolve_delay, XtreamCluster::Video).await {
if let Some(content) = playlist_resolve_download_playlist_item(
client,
pli,
input,
errors,
resolve_delay,
XtreamCluster::Video,
default_user_agent.as_deref(),
)
.await
{
if content.is_empty() { continue; }
match serde_json::from_str::<XtreamVideoInfo>(&content) {
Ok(info) => {