removed raw epg access when no url given.

This commit is contained in:
euzu
2024-11-01 15:40:45 +01:00
parent a29165fa1c
commit 4de5ea5a67
3 changed files with 31 additions and 79 deletions
+6 -57
View File
@@ -2,9 +2,8 @@ use std::fs::File;
use std::path::{Path, PathBuf};
use actix_web::{HttpRequest, HttpResponse, web, http::header};
use log::{debug, info};
use log::{info};
use quick_xml::{Reader, Writer};
use url::{ParseError};
use flate2::write::GzEncoder;
use flate2::Compression;
use quick_xml::events::{BytesStart, Event};
@@ -13,13 +12,13 @@ use chrono::{Duration, NaiveDateTime, TimeDelta};
use crate::api::api_model::{AppState, UserApiRequest};
use crate::api::api_utils::{get_user_target, serve_file};
use crate::model::api_proxy::{ProxyType, ProxyUserCredentials};
use crate::model::config::{Config, ConfigInput, ConfigTarget};
use crate::model::api_proxy::{ProxyUserCredentials};
use crate::model::config::{Config, ConfigTarget};
use crate::model::config::TargetType;
use crate::repository::m3u_repository::m3u_get_epg_file_path;
use crate::repository::storage::get_target_storage_path;
use crate::repository::xtream_repository::{xtream_get_epg_file_path, xtream_get_storage_path};
use crate::utils::{file_utils, request_utils};
use crate::utils::{file_utils};
fn time_correct(date_time: &str, correction: &TimeDelta) -> String {
// Split the dateTime string into date and time parts
@@ -194,11 +193,8 @@ async fn xmltv_api(
if let Some((user, target)) = get_user_target(&api_req, &app_state) {
match get_epg_path_for_target(&app_state.config, target) {
None => {
// No epg configured, we try to figure out an epg url and redirect.
// No processing or timeshift
if let Some(value) = get_xmltv_raw_epg(&app_state.config, &user, &target.name).await {
return value;
}
// No epg configured, No processing or timeshift, epg can't be mapped to the channels.
// we do not deliver epg
}
Some(epg_path) => return serve_epg(&epg_path, &req, &user).await
}
@@ -207,53 +203,6 @@ async fn xmltv_api(
r#"<?xml version="1.0" encoding="utf-8" ?><!DOCTYPE tv SYSTEM "xmltv.dtd"><tv generator-info-name="Xtream Codes" generator-info-url=""></tv>"#)
}
fn get_xmltv_epg_url(input: &ConfigInput) -> Result<String, ParseError> {
let epg_url = input.epg_url.as_ref().map_or(String::new(), std::borrow::ToOwned::to_owned);
if epg_url.is_empty() {
if let Some(user_info) = input.get_user_info() {
let url = user_info.base_url.as_str();
let username = user_info.username.as_str();
let password = user_info.password.as_str();
Ok(format!("{url}/xmltv.php?username={username}&password={password}"))
} else {
Err(ParseError::EmptyHost)
}
} else {
Ok(epg_url)
}
}
async fn get_xmltv_raw_epg(config: &Config, user: &ProxyUserCredentials, target_name: &str) -> Option<HttpResponse> {
// If no epg_url is provided for input, we did not process the xmltv for our channels.
// We are now delivering the original untouched xmltv.
// If you want to use xmltv then provide the url in the config to filter unnecessary content.
// If you have multiple xtream sources, no response because of mapped ids
// if you want epg for multi xtream input, then provide epg_url.
if let Some(inputs) = config.get_inputs_for_target(target_name) {
if inputs.len() == 1 {
if let Some(&input) = inputs.first() {
if let Ok(url) = get_xmltv_epg_url(input) {
if user.proxy == ProxyType::Redirect {
debug!("Redirecting epg request to {}", url.as_str());
return Some(HttpResponse::Found().insert_header(("Location", url.as_str())).finish());
}
match request_utils::download_text_content(input, url.as_str(), None).await {
Ok(content) => return Some(HttpResponse::Ok().content_type(mime::TEXT_XML).body(content)),
Err(err) => {
debug!("Could not generate epg url for {target_name} {err}");
}
}
} else {
debug!("Could not generate epg url for {target_name}");
}
}
} else {
debug!("No epg_url is provided for target {target_name}, multi input requires epg_url");
}
}
None
}
pub(crate) fn xmltv_api_register(cfg: &mut web::ServiceConfig) {
cfg.service(web::resource("/xmltv.php").route(web::get().to(xmltv_api)))
.service(web::resource("/epg").route(web::get().to(xmltv_api)));
+19 -19
View File
@@ -437,17 +437,17 @@ impl ConfigSource {
Ok(index + (self.inputs.len() as u16))
}
pub(crate) fn get_inputs_for_target(&self, target_name: &str) -> Option<Vec<&ConfigInput>> {
for target in &self.targets {
if target.name.eq(target_name) {
let inputs = self.inputs.iter().filter(|&i| i.enabled).collect::<Vec<&ConfigInput>>();
if !inputs.is_empty() {
return Some(inputs);
}
}
}
None
}
// pub(crate) fn get_inputs_for_target(&self, target_name: &str) -> Option<Vec<&ConfigInput>> {
// for target in &self.targets {
// if target.name.eq(target_name) {
// let inputs = self.inputs.iter().filter(|&i| i.enabled).collect::<Vec<&ConfigInput>>();
// if !inputs.is_empty() {
// return Some(inputs);
// }
// }
// }
// None
// }
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
@@ -840,14 +840,14 @@ impl Config {
}
}
pub(crate) fn get_inputs_for_target(&self, target_name: &str) -> Option<Vec<&ConfigInput>> {
for source in &self.sources {
if let Some(cfg) = source.get_inputs_for_target(target_name) {
return Some(cfg);
}
}
None
}
// pub(crate) fn get_inputs_for_target(&self, target_name: &str) -> Option<Vec<&ConfigInput>> {
// for source in &self.sources {
// if let Some(cfg) = source.get_inputs_for_target(target_name) {
// return Some(cfg);
// }
// }
// None
// }
pub fn get_target_for_user(&self, username: &str, password: &str) -> Option<(ProxyUserCredentials, &ConfigTarget)> {
match self.t_api_proxy.read().unwrap().as_ref() {
+6 -3
View File
@@ -14,6 +14,9 @@ use crate::m3u_filter_error::{M3uFilterError, M3uFilterErrorKind};
use crate::model::config::ConfigInput;
use crate::utils::file_utils::{get_file_path, persist_file};
const ENCODING_GZIP: &str = "gzip";
const ENCODING_DEFLATE: &str = "deflate";
fn is_gzip(bytes: &[u8]) -> bool {
// Gzip files start with the bytes 0x1F 0x8B
bytes.len() >= 2 && bytes[0] == 0x1F && bytes[1] == 0x8B
@@ -144,19 +147,19 @@ async fn get_remote_content(input: &ConfigInput, url: &Url) -> Result<String, Er
match response.bytes().await {
Ok(bytes) => {
if bytes.len() >= 2 && is_gzip(&bytes[0..2]) {
encoding = Some("gzip".to_string());
encoding = Some(ENCODING_GZIP.to_string());
}
let mut decode_buffer = String::new();
if let Some(encoding_type) = encoding {
match encoding_type.as_str() {
"gzip" => {
ENCODING_GZIP => {
let mut decoder = GzDecoder::new(&bytes[..]);
match decoder.read_to_string(&mut decode_buffer) {
Ok(_) => {}
Err(err) => return Err(std::io::Error::new(ErrorKind::Other, format!("failed to decode gzip content {err}")))
};
}
"deflate" => {
ENCODING_DEFLATE => {
let mut decoder = ZlibDecoder::new(&bytes[..]);
match decoder.read_to_string(&mut decode_buffer) {
Ok(_) => {}