mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-28 01:32:27 +01:00
Merge pull request #253 from euzu/feature/epg_logo_override
epg auto_epg removed and logo_override added
This commit is contained in:
+12
-4
@@ -1,20 +1,27 @@
|
||||
# Changelog
|
||||
# 3.1.0 (2025-05-xx)
|
||||
|
||||
- !BREAKING_CHANGE! epg config. Added priority, url config is now renamed to sources, priority is `optional`
|
||||
The `priority` value determines the importance or order of processing. Lower numbers mean higher priority. That is:
|
||||
- !BREAKING_CHANGE! epg refactored
|
||||
- url config is now renamed to sources
|
||||
- Added `priority`, priority is `optional`
|
||||
- `auto_epg` is now removed, use `url: auto` instead.
|
||||
- Added `logo_override` to overwrite logo from epg.
|
||||
|
||||
**Npte:** The `priority` value determines the importance or order of processing. Lower numbers mean higher priority. That is:
|
||||
A `priority` of `0` is higher than `1`. **Negative numbers** are allowed and represent even higher priority
|
||||
|
||||
```yaml
|
||||
epg:
|
||||
sources:
|
||||
- url: "auto"
|
||||
priority: -2
|
||||
logo_override: true
|
||||
- url: "http://localhost:3001/xmltv.php?epg_id=1"
|
||||
priority: -1
|
||||
- url: "http://localhost:3001/xmltv.php?epg_id=2"
|
||||
priority: 3
|
||||
- url: "http://localhost:3001/xmltv.php?epg_id=3"
|
||||
priority: 0
|
||||
- url: "http://localhost:3001/xmltv.php?epg_id=4"
|
||||
priority: 1
|
||||
smart_match:
|
||||
enabled: true
|
||||
fuzzy_matching: true
|
||||
@@ -60,6 +67,7 @@ The template can now be used for sequence
|
||||
- '(?i)\bSD\b'
|
||||
```
|
||||
|
||||
|
||||
# 3.0.0 (2025-05-12)
|
||||
- !BREAKING_CHANGE! user has now the attribute `ui_enabled` to disable/enable web_ui for user.
|
||||
You need to migrate the user db if you have used `use_user_db:true`.
|
||||
|
||||
@@ -9,6 +9,8 @@ pub struct EpgSource {
|
||||
pub(crate) url: String,
|
||||
#[serde(default)]
|
||||
pub priority: i16,
|
||||
#[serde(default)]
|
||||
pub logo_override: bool,
|
||||
}
|
||||
|
||||
impl EpgSource {
|
||||
@@ -146,10 +148,6 @@ impl Default for EpgSmartMatchConfig {
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct EpgConfig {
|
||||
#[serde(default)]
|
||||
pub auto_epg: bool,
|
||||
#[serde(default)]
|
||||
pub auto_epg_priority: i16,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub sources: Option<Vec<EpgSource>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
|
||||
+30
-19
@@ -1,11 +1,11 @@
|
||||
use crate::tuliprox_error::{create_tuliprox_error_result, handle_tuliprox_error_result_list, info_err, TuliproxError, TuliproxErrorKind};
|
||||
use crate::model::{EpgConfig, EpgSource};
|
||||
use crate::model::{EpgConfig};
|
||||
use crate::utils::default_as_true;
|
||||
use crate::utils::get_trimmed_string;
|
||||
use crate::utils::request::{get_base_url_from_str, get_credentials_from_url, get_credentials_from_url_str};
|
||||
use enum_iterator::Sequence;
|
||||
use log::{debug, warn};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
@@ -295,26 +295,37 @@ impl ConfigInput {
|
||||
|
||||
if let Some(epg) = self.epg.as_mut() {
|
||||
let _ = epg.prepare(include_computed);
|
||||
if include_computed && epg.auto_epg {
|
||||
let (username, password) = if self.username.is_none() || self.password.is_none() {
|
||||
get_credentials_from_url_str(&self.url)
|
||||
} else {
|
||||
(self.username.clone(), self.password.clone())
|
||||
};
|
||||
if include_computed {
|
||||
let has_auto_epg = epg.t_sources.iter().any(|e| e.url.trim() == "auto");
|
||||
if has_auto_epg {
|
||||
let (username, password) = if self.username.is_none() || self.password.is_none() {
|
||||
get_credentials_from_url_str(&self.url)
|
||||
} else {
|
||||
(self.username.clone(), self.password.clone())
|
||||
};
|
||||
|
||||
if username.is_none() || password.is_none() {
|
||||
warn!("auto_epg is enabled for input {}, but no credentials could be extracted", self.name);
|
||||
} else if !self.t_base_url.is_empty() {
|
||||
let provider_epg_url = format!("{}/xmltv.php?username={}&password={}", self.t_base_url, username.unwrap_or_default(), password.unwrap_or_default());
|
||||
if ! epg.t_sources.iter().any(|e| e.url == provider_epg_url) {
|
||||
debug!("Added provider epg url {provider_epg_url} for input {}", self.name);
|
||||
epg.t_sources.push(EpgSource {
|
||||
url: provider_epg_url,
|
||||
priority: epg.auto_epg_priority,
|
||||
if username.is_none() || password.is_none() {
|
||||
warn!("auto_epg is enabled for input {}, but no credentials could be extracted", self.name);
|
||||
} else if !self.t_base_url.is_empty() {
|
||||
let provider_epg_url = format!("{}/xmltv.php?username={}&password={}", self.t_base_url, username.unwrap_or_default(), password.unwrap_or_default());
|
||||
|
||||
epg.t_sources.iter_mut().for_each(|epg_source| {
|
||||
if epg_source.url.trim() == "auto" {
|
||||
debug!("Added provider epg url {provider_epg_url} for input {}", self.name);
|
||||
epg_source.url.clone_from(&provider_epg_url);
|
||||
}
|
||||
});
|
||||
|
||||
epg.t_sources = {
|
||||
let mut seen_urls = HashSet::new();
|
||||
epg.t_sources
|
||||
.drain(..)
|
||||
.filter(|src| seen_urls.insert(src.url.clone()))
|
||||
.collect()
|
||||
};
|
||||
} else {
|
||||
warn!("auto_epg is enabled for input {}, but url could not be parsed {}", self.name, self.url);
|
||||
}
|
||||
} else {
|
||||
warn!("auto_epg is enabled for input {}, but url could not be parsed {}", self.name, self.url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ impl XmlTag {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Epg {
|
||||
pub priority: i16,
|
||||
pub logo_override: bool,
|
||||
pub attributes: Option<HashMap<String, String>>,
|
||||
pub children: Vec<XmlTag>,
|
||||
}
|
||||
@@ -82,6 +83,7 @@ impl Epg {
|
||||
pub struct PersistedEpgSource {
|
||||
pub file_path: PathBuf,
|
||||
pub priority: i16,
|
||||
pub logo_override: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@@ -96,6 +96,7 @@ impl TVGuide {
|
||||
let first_epg_attributes = epgs.get_mut(0).unwrap().attributes.take();
|
||||
let merged_children: Vec<XmlTag> = epgs.into_iter().flat_map(|epg| epg.children).collect();
|
||||
Some(Epg {
|
||||
logo_override: false,
|
||||
priority: 0,
|
||||
attributes: first_epg_attributes,
|
||||
children: merged_children,
|
||||
@@ -261,6 +262,7 @@ impl TVGuide {
|
||||
}
|
||||
|
||||
Some(Epg {
|
||||
logo_override: epg_source.logo_override,
|
||||
priority: epg_source.priority,
|
||||
attributes: tv_attributes,
|
||||
children,
|
||||
@@ -456,6 +458,7 @@ pub fn flatten_tvguide(tv_guides: &[Epg]) -> Option<Epg> {
|
||||
epg_children.lock().unwrap().extend(children);
|
||||
});
|
||||
let epg = Epg {
|
||||
logo_override: false,
|
||||
priority: 0,
|
||||
attributes: epg_attributes,
|
||||
children: mem::take(&mut *epg_children.lock().unwrap()),
|
||||
|
||||
@@ -137,8 +137,8 @@ fn assign_channel_epg(new_epg: &mut Vec<Epg>, fp: &mut FetchedPlaylist, id_cache
|
||||
if let Some(epg) = tv_guide.filter(id_cache) {
|
||||
// // icon tags
|
||||
let icon_tags: HashMap<&String, &XmlTag> = epg.children.iter()
|
||||
.filter(|tag| tag.icon.is_some() && tag.get_attribute_value(EPG_ATTRIB_ID).is_some())
|
||||
.map(|t| (t.get_attribute_value(EPG_ATTRIB_ID).unwrap(), t)).collect();
|
||||
.filter(|tag| tag.icon.is_some() && tag.get_attribute_value(EPG_ATTRIB_ID).is_some())
|
||||
.map(|t| (t.get_attribute_value(EPG_ATTRIB_ID).unwrap(), t)).collect();
|
||||
|
||||
let filter_live = |c: &&mut PlaylistItem| c.header.xtream_cluster == XtreamCluster::Live;
|
||||
// let filter_missing_epg_id = |chan: &mut PlaylistItem| chan.header.epg_channel_id.is_none() || chan.header.logo.is_empty() || chan.header.logo_small.is_empty();
|
||||
@@ -158,13 +158,13 @@ fn assign_channel_epg(new_epg: &mut Vec<Epg>, fp: &mut FetchedPlaylist, id_cache
|
||||
}
|
||||
}
|
||||
}
|
||||
if chan.header.epg_channel_id.is_some() && (chan.header.logo.is_empty() || chan.header.logo_small.is_empty()) {
|
||||
if chan.header.epg_channel_id.is_some() && (epg.logo_override || chan.header.logo.is_empty() || chan.header.logo_small.is_empty()) {
|
||||
if let Some(icon_tag) = icon_tags.get(chan.header.epg_channel_id.as_ref().unwrap()) {
|
||||
if let Some(icon) = icon_tag.icon.as_ref() {
|
||||
if chan.header.logo.is_empty() {
|
||||
if epg.logo_override || chan.header.logo.is_empty() {
|
||||
chan.header.logo = (*icon).to_string();
|
||||
}
|
||||
if chan.header.logo_small.is_empty() {
|
||||
if epg.logo_override || chan.header.logo_small.is_empty() {
|
||||
chan.header.logo_small = (*icon).to_string();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ pub async fn get_xmltv(client: Arc<reqwest::Client>, _cfg: &Config, input: &Conf
|
||||
for epg_source in &epg_config.t_sources {
|
||||
match download_epg_file(&epg_source.url, &client, input, working_dir).await {
|
||||
Ok(file_path) => {
|
||||
file_paths.push(PersistedEpgSource {file_path, priority: epg_source.priority});
|
||||
file_paths.push(PersistedEpgSource {file_path, priority: epg_source.priority, logo_override: epg_source.logo_override});
|
||||
}
|
||||
Err(err) => {
|
||||
errors.push(err);
|
||||
|
||||
Reference in New Issue
Block a user