diff --git a/CHANGELOG.md b/CHANGELOG.md index 07f4d5bba..f6713ad4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ # Changelog +# 3.1.4 (2025-06-xx) +- fixed custom stream loop # 3.1.3 (2025-06-06) - Fixed xtream codes series info duplicate fields problem. diff --git a/src/model/xmltv.rs b/src/model/xmltv.rs index a9066b585..d21f6049f 100644 --- a/src/model/xmltv.rs +++ b/src/model/xmltv.rs @@ -2,6 +2,7 @@ use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::{Error, Writer}; use std::collections::HashMap; use std::path::PathBuf; +use crate::model::xmltv::XmlTagIcon::Undefined; pub const EPG_TAG_TV: &str = "tv"; pub const EPG_TAG_PROGRAMME: &str = "programme"; @@ -13,13 +14,23 @@ pub const EPG_TAG_ICON: &str = "icon"; // https://github.com/XMLTV/xmltv/blob/master/xmltv.dtd + +#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Default)] +pub enum XmlTagIcon { + #[default] + Undefined, + Src(String), + Exists, +} + #[derive(Debug, Clone)] pub struct XmlTag { pub name: String, pub value: Option, pub attributes: Option>, pub children: Option>, - pub icon: Option, + pub icon: XmlTagIcon, pub normalized_epg_ids: Option>, } @@ -30,7 +41,7 @@ impl XmlTag { value: None, attributes: attribs, children: None, - icon: None, + icon: Undefined, normalized_epg_ids: None, } } @@ -43,7 +54,7 @@ impl XmlTag { let mut elem = BytesStart::new(self.name.as_str()); // empty icon not processed - if self.icon.is_none() && self.name.eq(EPG_TAG_ICON) { + if self.icon == Undefined && self.name.eq(EPG_TAG_ICON) { return Ok(()); } diff --git a/src/processing/parser/xmltv.rs b/src/processing/parser/xmltv.rs index 5352a247e..913013890 100644 --- a/src/processing/parser/xmltv.rs +++ b/src/processing/parser/xmltv.rs @@ -1,4 +1,4 @@ -use crate::model::{Epg, TVGuide, XmlTag, EPG_ATTRIB_CHANNEL, EPG_ATTRIB_ID, EPG_TAG_CHANNEL, EPG_TAG_DISPLAY_NAME, EPG_TAG_ICON, EPG_TAG_PROGRAMME, EPG_TAG_TV}; +use crate::model::{Epg, TVGuide, XmlTag, XmlTagIcon, EPG_ATTRIB_CHANNEL, EPG_ATTRIB_ID, EPG_TAG_CHANNEL, EPG_TAG_DISPLAY_NAME, EPG_TAG_ICON, EPG_TAG_PROGRAMME, EPG_TAG_TV}; use crate::model::{EpgNamePrefix, EpgSmartMatchConfig, PersistedEpgSource}; use crate::processing::processor::epg::EpgIdCache; use crate::utils::compressed_file_reader::CompressedFileReader; @@ -90,6 +90,7 @@ pub fn normalize_channel_name(name: &str, normalize_config: &EpgSmartMatchConfig } } + impl TVGuide { pub fn merge(mut epgs: Vec) -> Option { if let Some(first_epg) = epgs.get_mut(0) { @@ -122,7 +123,8 @@ impl TVGuide { EPG_TAG_ICON => { if let Some(src) = child.get_attribute_value("src") { if !src.is_empty() { - tag.icon = Some(src.to_string()); + tag.icon = XmlTagIcon::Src(src.to_string()); + child.icon = XmlTagIcon::Exists; } } } diff --git a/src/processing/processor/epg.rs b/src/processing/processor/epg.rs index c2c4f3cfa..30557c6cd 100644 --- a/src/processing/processor/epg.rs +++ b/src/processing/processor/epg.rs @@ -1,4 +1,4 @@ -use crate::model::{Epg, TVGuide, XmlTag, EPG_ATTRIB_ID}; +use crate::model::{Epg, TVGuide, XmlTag, XmlTagIcon, EPG_ATTRIB_ID}; use crate::model::{EpgConfig, EpgSmartMatchConfig}; use crate::model::{FetchedPlaylist, PlaylistItem, XtreamCluster}; use crate::processing::parser::xmltv::normalize_channel_name; @@ -141,7 +141,7 @@ fn assign_channel_epg(new_epg: &mut Vec, fp: &mut FetchedPlaylist, id_cache for epg_source in epg_sources { // icon tags let icon_tags: HashMap<&String, &XmlTag> = epg_source.children.iter() - .filter(|tag| tag.icon.is_some() && tag.get_attribute_value(EPG_ATTRIB_ID).is_some()) + .filter(|tag| tag.icon != XmlTagIcon::Undefined && tag.get_attribute_value(EPG_ATTRIB_ID).is_some()) .map(|t| (t.get_attribute_value(EPG_ATTRIB_ID).unwrap(), t)).collect(); let assign_values = |chan: &mut PlaylistItem| { @@ -165,7 +165,7 @@ fn assign_channel_epg(new_epg: &mut Vec, fp: &mut FetchedPlaylist, id_cache if !icon_assigned.contains(epg_channel_id) && (epg_source.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 let XmlTagIcon::Src(icon) = &icon_tag.icon { icon_assigned.insert(epg_channel_id.to_string()); if epg_source.logo_override || chan.header.logo.is_empty() { trace!("Matched channel {} to epg icon {icon}", chan.header.name);