Fixed iptv player using live tv stream without /live/ context.

This commit is contained in:
euzu
2025-01-30 12:30:04 +01:00
parent 0b89b4c9c5
commit 50bed33aaa
10 changed files with 67 additions and 13 deletions
+2 -2
View File
@@ -7,7 +7,7 @@ use crate::api::model::provider_stream_factory::BufferStreamOptions;
use crate::api::model::request::UserApiRequest;
use crate::api::model::shared_stream::SharedStream;
use crate::api::model::stream_error::StreamError;
use crate::debug_if_enabled;
use crate::{debug_if_enabled, trace_if_enabled};
use crate::model::api_proxy::ProxyUserCredentials;
use crate::model::config::{ConfigInput, ConfigTarget};
use crate::model::playlist::PlaylistItemType;
@@ -212,7 +212,7 @@ pub async fn resource_response(app_state: &AppState, resource_url: &str, req: &H
}
}
}
debug_if_enabled!("Try to fetch resource {}", sanitize_sensitive_info(resource_url));
trace_if_enabled!("Try to fetch resource {}", sanitize_sensitive_info(resource_url));
if let Ok(url) = Url::parse(resource_url) {
let client = request_utils::get_client_request(&app_state.http_client, input.map(|i| &i.headers), &url, Some(&req_headers));
match client.send().await {
+8 -3
View File
@@ -7,7 +7,7 @@ use crate::debug_if_enabled;
use crate::model::config::ConfigInput;
use crate::model::playlist::PlaylistItemType;
use crate::utils::atomic_once_flag::AtomicOnceFlag;
use crate::utils::request_utils::{get_request_headers, sanitize_sensitive_info};
use crate::utils::request_utils::{classify_content_type, get_request_headers, sanitize_sensitive_info, MimeCategory};
use actix_web::HttpRequest;
use bytes::Bytes;
use futures::stream::{self, BoxStream};
@@ -307,7 +307,6 @@ fn create_provider_stream_options(stream_url: &Url,
}
}
pub async fn create_provider_stream(client: Arc<reqwest::Client>,
stream_url: &Url,
req: &HttpRequest,
@@ -326,8 +325,14 @@ pub async fn create_provider_stream(client: Arc<reqwest::Client>,
match get_initial_stream(Arc::clone(&client), &stream_options).await {
Some((init_stream, info)) => {
let is_video_stream = if let Some((headers, _)) = &info {
classify_content_type(headers) == MimeCategory::Video
} else {
true // don't know what it is but lets assume it is
};
let continue_signal = stream_options.get_continue_flag_clone();
if stream_options.should_reconnect() {
if is_video_stream && stream_options.should_reconnect() {
let client_signal = Arc::clone(&continue_signal);
let stream_options_provider = stream_options.clone();
let unfold: ResponseStream = stream::unfold((), move |()| {
+1 -1
View File
@@ -47,7 +47,7 @@ impl XtreamAuthorizationResponse {
Self {
user_info: XtreamUserInfo {
active_cons: "0".to_string(),
allowed_output_formats: Vec::from(["ts".to_string(), "m3u8".to_string(), "rtmp".to_string()]),
allowed_output_formats: Vec::from(["ts".to_string()]),
auth: 1,
created_at: (now - Duration::days(365)).timestamp(), // fake
exp_date: (now + Duration::days(365)).timestamp(), // fake
+4 -2
View File
@@ -82,6 +82,7 @@ macro_rules! try_result_bad_request {
};
}
#[derive(Debug)]
enum XtreamApiStreamContext {
LiveAlt,
Live,
@@ -91,7 +92,6 @@ enum XtreamApiStreamContext {
}
impl XtreamApiStreamContext {
const LIVE_ALT: &'static str = "";
const LIVE: &'static str = "live";
const MOVIE: &'static str = "movie";
const SERIES: &'static str = "series";
@@ -101,7 +101,7 @@ impl XtreamApiStreamContext {
impl Display for XtreamApiStreamContext {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match self {
Self::LiveAlt => Self::LIVE_ALT,
Self::LiveAlt => Self::LIVE,
Self::Live => Self::LIVE,
Self::Movie => Self::MOVIE,
Self::Series => Self::SERIES,
@@ -110,6 +110,7 @@ impl Display for XtreamApiStreamContext {
}
}
#[derive(Debug)]
struct XtreamApiStreamRequest<'a> {
context: XtreamApiStreamContext,
username: &'a str,
@@ -217,6 +218,7 @@ async fn xtream_player_api_stream(
stream_req.context.to_string().as_str(), &query_path, pli.url.as_str()),
true, format!("Cant find stream url for target {target_name}, context {}, stream_id {virtual_id}",
stream_req.context));
debug_if_enabled!("Streaming stream request from {}", sanitize_sensitive_info(&stream_url));
stream_response(app_state, &stream_url, req, Some(input), pli.item_type, target).await
}