mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-20 06:42:20 +02:00
rewrite resource urls for webui (#629)
* rewrite resource urls for webui * fix for dbviewer * added metadata update new field
This commit is contained in:
@@ -14,7 +14,9 @@ pub use self::xtream::*;
|
||||
pub use self::xtream_vod::*;
|
||||
pub use self::xtream_series::*;
|
||||
pub use self::stream_probe::*;
|
||||
use crate::api::model::ProviderHandle;
|
||||
use shared::create_bitset;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
create_bitset!(u8, ResolveOptionsFlags, Resolve, TmdbMissing, Probe, Background);
|
||||
|
||||
@@ -47,6 +49,15 @@ pub(crate) const FOREGROUND_BATCH_SIZE: usize = 200;
|
||||
pub(crate) const FOREGROUND_RETRY_BATCH_MAX_SIZE: usize = FOREGROUND_BATCH_SIZE * 4;
|
||||
pub(crate) const FOREGROUND_MIN_RETRY_DELAY_SECS: u64 = 1;
|
||||
|
||||
pub(crate) fn select_cancel_token<'a>(
|
||||
acquired_handle: Option<&'a ProviderHandle>,
|
||||
active_handle: Option<&'a ProviderHandle>,
|
||||
) -> Option<&'a CancellationToken> {
|
||||
acquired_handle
|
||||
.and_then(|h| h.cancel_token.as_ref())
|
||||
.or_else(|| active_handle.and_then(|h| h.cancel_token.as_ref()))
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// fn get_resolve_<cluster>_options(target: &ConfigTarget, fpl: &FetchedPlaylist) -> bool
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::api::model::ActiveProviderManager;
|
||||
use crate::model::ConfigInput;
|
||||
use crate::model::{AppConfig};
|
||||
use crate::processing::processor::select_cancel_token;
|
||||
use crate::repository::{get_input_m3u_playlist_file_path, get_input_storage_path, get_input_local_library_playlist_file_path, xtream_get_file_path, BPlusTreeUpdate};
|
||||
use crate::utils::{debug_if_enabled, ffmpeg};
|
||||
use crate::utils::ffmpeg::{ProbeFailureKind, ProbeUrlOutcome};
|
||||
@@ -115,14 +116,17 @@ pub async fn update_generic_stream_metadata(
|
||||
|
||||
debug_if_enabled!("Probing Generic Stream '{unique_id}'");
|
||||
|
||||
let probe_data = ffmpeg::probe_url(
|
||||
let cancel_token = select_cancel_token(acquired_handle.as_ref(), active_handle);
|
||||
let probe_data = ffmpeg::probe_url_with_cancel(
|
||||
&probe_url,
|
||||
user_agent.as_deref(),
|
||||
analyze_duration,
|
||||
probe_size,
|
||||
ffprobe_timeout,
|
||||
config.proxy.as_ref(),
|
||||
).await;
|
||||
cancel_token,
|
||||
)
|
||||
.await;
|
||||
|
||||
if let Some(handle) = acquired_handle {
|
||||
active_provider.release_handle(&handle).await;
|
||||
@@ -138,6 +142,10 @@ pub async fn update_generic_stream_metadata(
|
||||
warn!("Probe failed or timed out for generic stream: {unique_id}");
|
||||
return Ok(GenericProbeOutcome::ProbeFailed);
|
||||
}
|
||||
ProbeUrlOutcome::Failed(ProbeFailureKind::Cancelled) => {
|
||||
warn!("Probe cancelled for generic stream: {unique_id}");
|
||||
return Ok(GenericProbeOutcome::ProbeFailed);
|
||||
}
|
||||
};
|
||||
|
||||
// Hold the async file lock while the blocking DB update runs in a blocking thread.
|
||||
|
||||
@@ -164,6 +164,10 @@ pub async fn update_live_stream_metadata(
|
||||
warn!("Probe failed for Live Stream ID {} (Input: {})", display_id, input.name);
|
||||
// We still persist the updated last_probed_timestamp so we don't retry immediately
|
||||
}
|
||||
ProbeUrlOutcome::Failed(ProbeFailureKind::Cancelled) => {
|
||||
warn!("Probe cancelled for Live Stream ID {} (Input: {})", display_id, input.name);
|
||||
// We still persist the updated last_probed_timestamp so we don't retry immediately
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Persist
|
||||
|
||||
@@ -8,8 +8,8 @@ use crate::processing::parser::xtream::create_xtream_series_episode_url;
|
||||
use crate::processing::parser::xtream::parse_xtream_series_info;
|
||||
use crate::processing::processor::playlist::{PlaylistProcessingContext, ProcessingPipe};
|
||||
use crate::processing::processor::{
|
||||
create_resolve_options_function_for_xtream_target, process_foreground_retry_once, ResolveOptions,
|
||||
ResolveOptionsFlags, FOREGROUND_BATCH_SIZE as BATCH_SIZE, FOREGROUND_MIN_RETRY_DELAY_SECS,
|
||||
create_resolve_options_function_for_xtream_target, process_foreground_retry_once, select_cancel_token,
|
||||
ResolveOptions, ResolveOptionsFlags, FOREGROUND_BATCH_SIZE as BATCH_SIZE, FOREGROUND_MIN_RETRY_DELAY_SECS,
|
||||
FOREGROUND_RETRY_BATCH_MAX_SIZE as RETRY_BATCH_MAX_SIZE,
|
||||
};
|
||||
use crate::ptt::ptt_parse_title;
|
||||
@@ -30,6 +30,7 @@ use shared::model::{
|
||||
};
|
||||
use shared::model::{PlaylistGroup, PlaylistItemType, XtreamCluster};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
@@ -524,6 +525,7 @@ async fn update_series_info_immediate(
|
||||
reasons.contains(ResolveReason::Probe),
|
||||
probe_settings,
|
||||
db_query,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -620,6 +622,7 @@ pub async fn update_series_metadata(
|
||||
do_probe: bool,
|
||||
probe_settings: SeriesProbeSettings,
|
||||
db_query: Option<Arc<Mutex<BPlusTreeQuery<u32, XtreamPlaylistItem>>>>,
|
||||
tmdb_and_date_present_out: Option<&AtomicBool>,
|
||||
) -> Result<Option<SeriesStreamProperties>, TuliproxError> {
|
||||
let working_dir = &app_config.config.load().working_dir;
|
||||
let storage_path = get_input_storage_path(&input.name, working_dir)
|
||||
@@ -818,6 +821,13 @@ pub async fn update_series_metadata(
|
||||
}
|
||||
}
|
||||
|
||||
// Report whether TMDB and release date are present (regardless of whether we updated them this call).
|
||||
if let Some(out) = tmdb_and_date_present_out {
|
||||
let has_tmdb = properties.tmdb.is_some();
|
||||
let has_date = properties.release_date.is_some();
|
||||
out.store(has_tmdb && has_date, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
// 3. Probe Episodes (if enabled)
|
||||
if do_probe && app_config.is_ffprobe_enabled().await {
|
||||
if let Some(details) = properties.details.as_mut() {
|
||||
@@ -863,13 +873,15 @@ pub async fn update_series_metadata(
|
||||
ep.title, ep.season, ep.episode_num, missing_reason
|
||||
);
|
||||
|
||||
match crate::utils::ffmpeg::probe_url(
|
||||
let cancel_token = select_cancel_token(temp_handle.as_ref(), active_handle);
|
||||
match crate::utils::ffmpeg::probe_url_with_cancel(
|
||||
&episode_url,
|
||||
user_agent.as_deref(),
|
||||
probe_settings.analyze_duration_micros,
|
||||
probe_settings.probe_size_bytes,
|
||||
probe_settings.timeout_secs,
|
||||
config.proxy.as_ref(),
|
||||
cancel_token,
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -892,6 +904,11 @@ pub async fn update_series_metadata(
|
||||
probe_failure = Some(ProbeFailureKind::Other);
|
||||
}
|
||||
}
|
||||
ProbeUrlOutcome::Failed(ProbeFailureKind::Cancelled) => {
|
||||
if probe_failure.is_none() {
|
||||
probe_failure = Some(ProbeFailureKind::Cancelled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(h) = temp_handle {
|
||||
@@ -923,6 +940,7 @@ pub async fn update_series_metadata(
|
||||
shared::error::info_err!("Probe failed with 404 Not Found for Series {display_id}")
|
||||
}
|
||||
ProbeFailureKind::Other => shared::error::info_err!("Probe failed for Series {display_id}"),
|
||||
ProbeFailureKind::Cancelled => shared::error::info_err!("Probe cancelled for Series {display_id}"),
|
||||
};
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ use crate::model::{AppConfig, ConfigTarget};
|
||||
use crate::model::{ConfigInput, ConfigInputFlags};
|
||||
use crate::processing::processor::playlist::PlaylistProcessingContext;
|
||||
use crate::processing::processor::{
|
||||
create_resolve_options_function_for_xtream_target, process_foreground_retry_once, ResolveOptions,
|
||||
ResolveOptionsFlags, FOREGROUND_BATCH_SIZE as BATCH_SIZE, FOREGROUND_MIN_RETRY_DELAY_SECS,
|
||||
create_resolve_options_function_for_xtream_target, process_foreground_retry_once, select_cancel_token,
|
||||
ResolveOptions, ResolveOptionsFlags, FOREGROUND_BATCH_SIZE as BATCH_SIZE, FOREGROUND_MIN_RETRY_DELAY_SECS,
|
||||
FOREGROUND_RETRY_BATCH_MAX_SIZE as RETRY_BATCH_MAX_SIZE,
|
||||
};
|
||||
use crate::ptt::ptt_parse_title;
|
||||
@@ -27,6 +27,7 @@ use shared::model::{
|
||||
VideoStreamProperties, XtreamCluster, XtreamPlaylistItem, XtreamVideoInfo,
|
||||
};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
@@ -479,6 +480,7 @@ async fn update_vod_info_immediate(
|
||||
resolve_tmdb,
|
||||
reasons.contains(ResolveReason::Probe),
|
||||
db_query,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -505,6 +507,7 @@ pub async fn update_vod_metadata(
|
||||
resolve_tmdb: bool,
|
||||
do_probe: bool,
|
||||
db_query: Option<Arc<Mutex<BPlusTreeQuery<u32, XtreamPlaylistItem>>>>,
|
||||
tmdb_resolved_out: Option<&AtomicBool>,
|
||||
) -> Result<Option<VideoStreamProperties>, TuliproxError> {
|
||||
let working_dir = &app_config.config.load().working_dir;
|
||||
let storage_path = get_input_storage_path(&input.name, working_dir)
|
||||
@@ -747,6 +750,17 @@ pub async fn update_vod_metadata(
|
||||
}
|
||||
}
|
||||
|
||||
// Report whether TMDB data is present (regardless of whether we updated it this call).
|
||||
if let Some(out) = tmdb_resolved_out {
|
||||
let has_tmdb = properties.tmdb.is_some();
|
||||
let has_date = properties
|
||||
.details
|
||||
.as_ref()
|
||||
.and_then(|d| d.release_date.as_ref())
|
||||
.is_some();
|
||||
out.store(has_tmdb && has_date, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
// 3. Probe (if enabled globally in config)
|
||||
let ffprobe_enabled = app_config.is_ffprobe_enabled().await;
|
||||
if do_probe && ffprobe_enabled {
|
||||
@@ -793,13 +807,15 @@ pub async fn update_vod_metadata(
|
||||
|
||||
if active_handle.is_some() || temp_handle.is_some() {
|
||||
debug_if_enabled!("Probing VOD '{}' (ID: {})", display_title, display_id);
|
||||
match crate::utils::ffmpeg::probe_url(
|
||||
let cancel_token = select_cancel_token(temp_handle.as_ref(), active_handle);
|
||||
match crate::utils::ffmpeg::probe_url_with_cancel(
|
||||
&stream_url,
|
||||
user_agent.as_deref(),
|
||||
analyze_duration,
|
||||
probe_size,
|
||||
ffprobe_timeout,
|
||||
config.proxy.as_ref(),
|
||||
cancel_token,
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -823,6 +839,11 @@ pub async fn update_vod_metadata(
|
||||
probe_failure = Some(ProbeFailureKind::Other);
|
||||
}
|
||||
}
|
||||
ProbeUrlOutcome::Failed(ProbeFailureKind::Cancelled) => {
|
||||
if probe_failure.is_none() {
|
||||
probe_failure = Some(ProbeFailureKind::Cancelled);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(h) = temp_handle {
|
||||
active_provider.release_handle(&h).await;
|
||||
@@ -841,6 +862,7 @@ pub async fn update_vod_metadata(
|
||||
shared::error::info_err!("Probe failed with 404 Not Found for VOD {display_id}")
|
||||
}
|
||||
ProbeFailureKind::Other => shared::error::info_err!("Probe failed for VOD {display_id}"),
|
||||
ProbeFailureKind::Cancelled => shared::error::info_err!("Probe cancelled for VOD {display_id}"),
|
||||
};
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user