use std::collections::HashMap;
use crispy_iptv_types::PlaylistEntry;
pub fn apply_template(main: &[PlaylistEntry], template: &[PlaylistEntry]) -> Vec<PlaylistEntry> {
let template_map: HashMap<&str, &PlaylistEntry> = template
.iter()
.filter_map(|t| t.tvg_id.as_deref().map(|id| (id, t)))
.collect();
main.iter()
.map(|entry| {
let tvg_id = entry.tvg_id.as_deref().unwrap_or("");
if tvg_id.is_empty() {
return entry.clone();
}
match template_map.get(tvg_id) {
Some(tmpl) => {
let mut merged = entry.clone();
if tmpl.name.is_some() {
merged.name = tmpl.name.clone();
}
if tmpl.group_title.is_some() {
merged.group_title = tmpl.group_title.clone();
}
if tmpl.tvg_logo.is_some() {
merged.tvg_logo = tmpl.tvg_logo.clone();
}
if tmpl.tvg_name.is_some() {
merged.tvg_name = tmpl.tvg_name.clone();
}
for (k, v) in &tmpl.extras {
merged.extras.insert(k.clone(), v.clone());
}
merged
}
None => entry.clone(),
}
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
fn make_entry(name: &str, tvg_id: &str, url: &str, group: &str) -> PlaylistEntry {
PlaylistEntry {
name: Some(name.to_string()),
tvg_id: if tvg_id.is_empty() {
None
} else {
Some(tvg_id.to_string())
},
url: Some(url.to_string()),
group_title: if group.is_empty() {
None
} else {
Some(group.to_string())
},
..Default::default()
}
}
#[test]
fn template_overrides_matching_entry() {
let main = vec![make_entry("Old Name", "bbc.uk", "http://a.com/1", "News")];
let template = vec![make_entry("BBC One", "bbc.uk", "", "UK Channels")];
let result = apply_template(&main, &template);
assert_eq!(result.len(), 1);
assert_eq!(result[0].name.as_deref(), Some("BBC One"));
assert_eq!(result[0].group_title.as_deref(), Some("UK Channels"));
assert_eq!(result[0].url.as_deref(), Some("http://a.com/1"));
}
#[test]
fn entries_without_match_kept_as_is() {
let main = vec![
make_entry("BBC One", "bbc.uk", "http://a.com/1", "News"),
make_entry("CNN", "cnn.us", "http://a.com/2", "News"),
];
let template = vec![make_entry("BBC HD", "bbc.uk", "", "UK HD")];
let result = apply_template(&main, &template);
assert_eq!(result.len(), 2);
assert_eq!(result[0].name.as_deref(), Some("BBC HD"));
assert_eq!(result[1].name.as_deref(), Some("CNN"));
assert_eq!(result[1].group_title.as_deref(), Some("News"));
}
#[test]
fn entries_without_tvg_id_are_untouched() {
let main = vec![make_entry("No ID", "", "http://a.com/1", "Group")];
let template = vec![make_entry("Template", "some.id", "", "Other")];
let result = apply_template(&main, &template);
assert_eq!(result.len(), 1);
assert_eq!(result[0].name.as_deref(), Some("No ID"));
}
#[test]
fn empty_template_is_identity() {
let main = vec![make_entry("BBC One", "bbc.uk", "http://a.com/1", "News")];
let result = apply_template(&main, &[]);
assert_eq!(result.len(), 1);
assert_eq!(result[0].name.as_deref(), Some("BBC One"));
}
}