mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-20 06:42:20 +02:00
clippy pedantic fixes
This commit is contained in:
@@ -53,14 +53,14 @@ fn get_affix_processor(input: &ConfigInput) -> Option<AffixProcessor> {
|
||||
}
|
||||
|
||||
pub fn apply_affixes(fetched_playlists: &mut [FetchedPlaylist]) {
|
||||
fetched_playlists.iter_mut().for_each(|fetched_playlist| {
|
||||
for fetched_playlist in fetched_playlists.iter_mut() {
|
||||
let FetchedPlaylist { input, playlist, epg: _ } = fetched_playlist;
|
||||
if let Some(affix_processor) = get_affix_processor(input) {
|
||||
playlist.iter_mut().for_each(|group| {
|
||||
for group in playlist.iter_mut() {
|
||||
group.channels.iter_mut().for_each(|channel| {
|
||||
affix_processor(channel);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ fn token_value(it: &mut std::str::Chars) -> String {
|
||||
return get_value(it);
|
||||
}
|
||||
}
|
||||
String::from("")
|
||||
String::new()
|
||||
}
|
||||
|
||||
fn get_value(it: &mut std::str::Chars) -> String {
|
||||
@@ -34,11 +34,10 @@ fn token_till(it: &mut std::str::Chars, stop_char: char) -> Option<String> {
|
||||
break;
|
||||
} else if ch.is_whitespace() && result.is_empty() {
|
||||
continue;
|
||||
} else {
|
||||
result.push(ch);
|
||||
}
|
||||
result.push(ch);
|
||||
}
|
||||
if !result.is_empty() { Some(result.iter().collect::<String>()) } else { None }
|
||||
if result.is_empty() { None } else { Some(result.iter().collect::<String>()) }
|
||||
}
|
||||
|
||||
fn skip_digit(it: &mut std::str::Chars) -> Option<char> {
|
||||
@@ -54,7 +53,7 @@ fn skip_digit(it: &mut std::str::Chars) -> Option<char> {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_empty_playlistitem_header(input_id: u16, url: String) -> PlaylistItemHeader {
|
||||
fn create_empty_playlistitem_header(input_id: u16, url: &str) -> PlaylistItemHeader {
|
||||
PlaylistItemHeader {
|
||||
id: default_as_empty_rc_str(),
|
||||
stream_id: default_as_empty_rc_str(),
|
||||
@@ -67,7 +66,7 @@ fn create_empty_playlistitem_header(input_id: u16, url: String) -> PlaylistItemH
|
||||
audio_track: default_as_empty_rc_str(),
|
||||
time_shift: default_as_empty_rc_str(),
|
||||
rec: default_as_empty_rc_str(),
|
||||
url: Rc::new(url),
|
||||
url: Rc::new(url.to_owned()),
|
||||
epg_channel_id: None,
|
||||
item_type: default_playlist_item_type(),
|
||||
xtream_cluster: default_stream_cluster(),
|
||||
@@ -89,8 +88,8 @@ macro_rules! process_header_fields {
|
||||
};
|
||||
}
|
||||
|
||||
fn process_header(input: &ConfigInput, video_suffixes: &Vec<&str>, content: &str, url: String) -> PlaylistItemHeader {
|
||||
let mut plih = create_empty_playlistitem_header(input.id, url.clone());
|
||||
fn process_header(input: &ConfigInput, video_suffixes: &Vec<&str>, content: &str, url: &str) -> PlaylistItemHeader {
|
||||
let mut plih = create_empty_playlistitem_header(input.id, url);
|
||||
let mut it = content.chars();
|
||||
let line_token = token_till(&mut it, ':');
|
||||
if line_token == Some(String::from("#EXTINF")) {
|
||||
@@ -99,13 +98,13 @@ fn process_header(input: &ConfigInput, video_suffixes: &Vec<&str>, content: &str
|
||||
if c.is_none() {
|
||||
break;
|
||||
}
|
||||
match c.unwrap() {
|
||||
',' => plih.title = Rc::new(get_value(&mut it)),
|
||||
_ => {
|
||||
let token = token_till(&mut it, '=');
|
||||
if let Some(t) = token {
|
||||
let value = token_value(&mut it);
|
||||
process_header_fields!(plih, t.as_str(),
|
||||
if let ',' = c.unwrap() {
|
||||
plih.title = Rc::new(get_value(&mut it));
|
||||
} else {
|
||||
let token = token_till(&mut it, '=');
|
||||
if let Some(t) = token {
|
||||
let value = token_value(&mut it);
|
||||
process_header_fields!(plih, t.as_str(),
|
||||
(id, "tvg-id"),
|
||||
(group, "group-title"),
|
||||
(name, "tvg-name"),
|
||||
@@ -114,14 +113,13 @@ fn process_header(input: &ConfigInput, video_suffixes: &Vec<&str>, content: &str
|
||||
(logo, "tvg-logo"),
|
||||
(logo_small, "tvg-logo-small"),
|
||||
(time_shift, "timeshift"),
|
||||
(rec, "tvg-rec"); value)
|
||||
}
|
||||
(rec, "tvg-rec"); value);
|
||||
}
|
||||
}
|
||||
c = it.next();
|
||||
}
|
||||
if plih.id.is_empty() {
|
||||
if let Some(chanid) = extract_id_from_url(url.as_str()) {
|
||||
if let Some(chanid) = extract_id_from_url(url) {
|
||||
plih.id = Rc::new(chanid);
|
||||
}
|
||||
}
|
||||
@@ -151,7 +149,7 @@ fn process_header(input: &ConfigInput, video_suffixes: &Vec<&str>, content: &str
|
||||
|
||||
fn extract_id_from_url(url: &str) -> Option<String> {
|
||||
if let Some(filename) = url.split('/').last() {
|
||||
return filename.rsplit('.').next().map(|stem| stem.to_string());
|
||||
return filename.rsplit('.').next().map(std::string::ToString::to_string);
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -160,7 +158,7 @@ pub(crate) fn consume_m3u<F: FnMut(PlaylistItem)>(cfg: &Config, input: &ConfigIn
|
||||
let mut header: Option<String> = None;
|
||||
let mut group: Option<String> = None;
|
||||
|
||||
let video_suffixes = cfg.video.as_ref().unwrap().extensions.iter().map(|ext| ext.as_str()).collect();
|
||||
let video_suffixes = cfg.video.as_ref().unwrap().extensions.iter().map(std::string::String::as_str).collect();
|
||||
for line in lines {
|
||||
if line.starts_with("#EXTINF") {
|
||||
header = Some(line);
|
||||
@@ -174,13 +172,13 @@ pub(crate) fn consume_m3u<F: FnMut(PlaylistItem)>(cfg: &Config, input: &ConfigIn
|
||||
continue;
|
||||
}
|
||||
if let Some(header_value) = header {
|
||||
let item = PlaylistItem { header: RefCell::new(process_header(input, &video_suffixes, &header_value, line)) };
|
||||
let item = PlaylistItem { header: RefCell::new(process_header(input, &video_suffixes, &header_value, &line)) };
|
||||
let mut header = item.header.borrow_mut();
|
||||
if header.group.is_empty() {
|
||||
if let Some(group_value) = group {
|
||||
header.group = Rc::new(group_value);
|
||||
} else {
|
||||
let current_title = header.title.to_owned();
|
||||
let current_title = header.title.clone();
|
||||
header.group = Rc::new(string_utils::get_title_group(current_title.as_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,17 +26,18 @@ use crate::processing::xmltv_parser::flatten_tvguide;
|
||||
use crate::processing::xtream_processor::playlist_resolve_series;
|
||||
use crate::repository::playlist_repository::persist_playlist;
|
||||
use crate::utils::download;
|
||||
use crate::utils::default_utils:: default_as_default;
|
||||
use crate::utils::default_utils::default_as_default;
|
||||
|
||||
fn is_valid(pli: &PlaylistItem, target: &ConfigTarget) -> bool {
|
||||
let provider = ValueProvider { pli: RefCell::new(pli) };
|
||||
target.filter(&provider)
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
fn filter_playlist(playlist: &mut [PlaylistGroup], target: &ConfigTarget) -> Option<Vec<PlaylistGroup>> {
|
||||
debug!("Filtering {} groups", playlist.len());
|
||||
let mut new_playlist = Vec::new();
|
||||
playlist.iter_mut().for_each(|pg| {
|
||||
for pg in playlist.iter_mut() {
|
||||
let channels = pg.channels.iter()
|
||||
.filter(|&pli| is_valid(pli, target)).cloned().collect::<Vec<PlaylistItem>>();
|
||||
debug!("Filtered group {} has now {}/{} items", pg.title, channels.len(), pg.channels.len());
|
||||
@@ -48,7 +49,7 @@ fn filter_playlist(playlist: &mut [PlaylistGroup], target: &ConfigTarget) -> Opt
|
||||
xtream_cluster: pg.xtream_cluster.clone(),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
Some(new_playlist)
|
||||
}
|
||||
|
||||
@@ -81,15 +82,15 @@ fn sort_playlist(target: &ConfigTarget, new_playlist: &mut [PlaylistGroup]) {
|
||||
new_playlist.sort_by(|a, b| playlistgroup_comparator(a, b, group_sort, match_as_ascii));
|
||||
}
|
||||
if let Some(channel_sorts) = &sort.channels {
|
||||
channel_sorts.iter().for_each(|channel_sort| {
|
||||
for channel_sort in channel_sorts {
|
||||
let regexp = channel_sort.re.as_ref().unwrap();
|
||||
new_playlist.iter_mut().for_each(|group| {
|
||||
for group in new_playlist.iter_mut() {
|
||||
let group_title = if match_as_ascii { Rc::new(unidecode(&group.title)) } else { Rc::clone(&group.title) };
|
||||
if regexp.is_match(group_title.as_str()) {
|
||||
group.channels.sort_by(|chan1, chan2| playlistitem_comparator(chan1, chan2, channel_sort, match_as_ascii));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,14 +159,14 @@ fn map_channel(channel: PlaylistItem, mapping: &Mapping) -> PlaylistItem {
|
||||
let mut mock_processor = MockValueProcessor {};
|
||||
for m in &mapping.mapper {
|
||||
let mut processor = MappingValueProcessor { pli: ref_chan.clone(), mapper: m };
|
||||
match &m._filter {
|
||||
match &m.t_filter {
|
||||
Some(filter) => {
|
||||
if filter.filter(&provider, &mut mock_processor) {
|
||||
apply_pattern!(&m._pattern, &provider, &mut processor);
|
||||
apply_pattern!(&m.t_pattern, &provider, &mut processor);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
apply_pattern!(&m._pattern, &provider, &mut processor);
|
||||
apply_pattern!(&m.t_pattern, &provider, &mut processor);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -174,10 +175,10 @@ fn map_channel(channel: PlaylistItem, mapping: &Mapping) -> PlaylistItem {
|
||||
}
|
||||
|
||||
fn map_playlist(playlist: &mut [PlaylistGroup], target: &ConfigTarget) -> Option<Vec<PlaylistGroup>> {
|
||||
if target._mapping.is_some() {
|
||||
if target.t_mapping.is_some() {
|
||||
let new_playlist: Vec<PlaylistGroup> = playlist.iter().map(|playlist_group| {
|
||||
let mut grp = playlist_group.clone();
|
||||
let mappings = target._mapping.as_ref().unwrap();
|
||||
let mappings = target.t_mapping.as_ref().unwrap();
|
||||
mappings.iter().filter(|&mapping| !mapping.mapper.is_empty()).for_each(|mapping|
|
||||
grp.channels = grp.channels.drain(..).map(|chan| map_channel(chan, mapping)).collect());
|
||||
grp
|
||||
@@ -191,17 +192,16 @@ fn map_playlist(playlist: &mut [PlaylistGroup], target: &ConfigTarget) -> Option
|
||||
for channel in &playlist_group.channels {
|
||||
let cluster = &channel.header.borrow().xtream_cluster;
|
||||
let title = &channel.header.borrow().group;
|
||||
match new_groups.iter_mut().find(|x| *x.title == **title) {
|
||||
Some(grp) => grp.channels.push(channel.clone()),
|
||||
_ => {
|
||||
grp_id += 1;
|
||||
new_groups.push(PlaylistGroup {
|
||||
id: grp_id,
|
||||
title: Rc::clone(title),
|
||||
channels: vec![channel.clone()],
|
||||
xtream_cluster: cluster.clone(),
|
||||
})
|
||||
}
|
||||
if let Some(grp) = new_groups.iter_mut().find(|x| *x.title == **title) {
|
||||
grp.channels.push(channel.clone());
|
||||
} else {
|
||||
grp_id += 1;
|
||||
new_groups.push(PlaylistGroup {
|
||||
id: grp_id,
|
||||
title: Rc::clone(title),
|
||||
channels: vec![channel.clone()],
|
||||
xtream_cluster: cluster.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,7 +255,7 @@ async fn process_source(cfg: Arc<Config>, source_idx: usize, user_targets: Arc<P
|
||||
.sum();
|
||||
if playlist.is_empty() {
|
||||
info!("source is empty {}", input.url);
|
||||
errors.push(M3uFilterError::new(M3uFilterErrorKind::Notify, format!("source is empty {}", input_name)));
|
||||
errors.push(M3uFilterError::new(M3uFilterErrorKind::Notify, format!("source is empty {input_name}")));
|
||||
} else {
|
||||
all_playlist.push(
|
||||
FetchedPlaylist {
|
||||
@@ -284,7 +284,7 @@ async fn process_source(cfg: Arc<Config>, source_idx: usize, user_targets: Arc<P
|
||||
if log_enabled!(Level::Debug) {
|
||||
debug!("Source at index {} input is empty", source_idx);
|
||||
}
|
||||
errors.push(M3uFilterError::new(M3uFilterErrorKind::Notify, format!("Source at {} input is empty", source_idx)));
|
||||
errors.push(M3uFilterError::new(M3uFilterErrorKind::Notify, format!("Source at {source_idx} input is empty")));
|
||||
} else {
|
||||
if log_enabled!(Level::Debug) {
|
||||
debug!("Input has {} groups", all_playlist.len());
|
||||
@@ -292,7 +292,7 @@ async fn process_source(cfg: Arc<Config>, source_idx: usize, user_targets: Arc<P
|
||||
for target in &source.targets {
|
||||
if is_target_enabled(target, &user_targets) {
|
||||
match process_playlist(&mut all_playlist, target, &cfg, &mut stats, &mut errors).await {
|
||||
Ok(_) => {}
|
||||
Ok(()) => {}
|
||||
Err(mut err) => err.drain(..).for_each(|e| errors.push(e))
|
||||
}
|
||||
}
|
||||
@@ -327,7 +327,7 @@ async fn process_sources(config: Arc<Config>, user_targets: Arc<ProcessTargets>)
|
||||
.for_each(|stat| shared_stats.lock().unwrap().push(stat));
|
||||
};
|
||||
handles.push(thread::spawn(process));
|
||||
if handles.len() as u8 >= thread_num {
|
||||
if handles.len() >= thread_num as usize {
|
||||
handles.drain(..).for_each(|handle| { let _ = handle.join(); });
|
||||
}
|
||||
} else {
|
||||
@@ -414,38 +414,40 @@ async fn process_playlist<'a>(playlists: &mut [FetchedPlaylist<'a>],
|
||||
}
|
||||
});
|
||||
|
||||
if !new_playlist.is_empty() {
|
||||
if new_playlist.is_empty() {
|
||||
info!("Playlist is empty: {}", &target.name);
|
||||
Ok(())
|
||||
} else {
|
||||
sort_playlist(target, &mut new_playlist);
|
||||
|
||||
if target._watch_re.is_some() {
|
||||
if target.t_watch_re.is_some() {
|
||||
if default_as_default().eq_ignore_ascii_case(&target.name) {
|
||||
error!("cant watch a target with no unique name");
|
||||
} else {
|
||||
let watch_re = target._watch_re.as_ref().unwrap();
|
||||
new_playlist.iter().for_each(|pl| {
|
||||
let watch_re = target.t_watch_re.as_ref().unwrap();
|
||||
for pl in &new_playlist {
|
||||
if watch_re.iter().any(|r| r.is_match(&pl.title)) {
|
||||
process_group_watch(cfg, &target.name, pl)
|
||||
process_group_watch(cfg, &target.name, pl);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
persist_playlist(&mut new_playlist, flatten_tvguide(&new_epg), target, cfg)
|
||||
} else {
|
||||
info!("Playlist is empty: {}", &target.name);
|
||||
Ok(())
|
||||
persist_playlist(&mut new_playlist, flatten_tvguide(&new_epg).as_ref(), target, cfg)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn exec_processing(cfg: Arc<Config>, targets: Arc<ProcessTargets>) {
|
||||
let (stats, errors) = process_sources(cfg.to_owned(), targets.to_owned()).await;
|
||||
let stats_msg = format!("{{\"stats\": {}}}", stats.iter().map(|stat| stat.to_string()).collect::<Vec<String>>().join("\n"));
|
||||
let (stats, errors) = process_sources(cfg.clone(), targets.clone()).await;
|
||||
let stats_msg = format!("{{\"stats\": {}}}", stats.iter().map(std::string::ToString::to_string).collect::<Vec<String>>().join("\n"));
|
||||
// print stats
|
||||
info!("{}", stats_msg);
|
||||
// send stats
|
||||
send_message(&MsgKind::Stats, &cfg.messaging, stats_msg.as_str());
|
||||
// log errors
|
||||
errors.iter().for_each(|err| error!("{}", err.message));
|
||||
for err in &errors {
|
||||
error!("{}", err.message);
|
||||
}
|
||||
// send errors
|
||||
if let Some(message) = get_errors_notify_message!(errors, 255) {
|
||||
let error_msg = format!("{{\"errors\": \"{}\"}}", message.as_str());
|
||||
|
||||
@@ -23,29 +23,26 @@ pub(crate) fn process_group_watch(cfg: &Config, target_name: &str, pl: &Playlist
|
||||
let save_path = path.clone();
|
||||
let mut changed = false;
|
||||
if path.exists() {
|
||||
match load_watch_tree(&path) {
|
||||
Some(loaded_tree) => {
|
||||
// Find elements in set2 but not in set1
|
||||
let added_difference: BTreeSet<String> = new_tree.difference(&loaded_tree).cloned().collect();
|
||||
let removed_difference: BTreeSet<String> = loaded_tree.difference(&new_tree).cloned().collect();
|
||||
if !added_difference.is_empty() || !removed_difference.is_empty() {
|
||||
changed = true;
|
||||
handle_watch_notification(cfg, added_difference, removed_difference, target_name, &pl.title);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
error!("failed to load watch_file {}", &path.to_str().unwrap_or_default());
|
||||
if let Some(loaded_tree) = load_watch_tree(&path) {
|
||||
// Find elements in set2 but not in set1
|
||||
let added_difference: BTreeSet<String> = new_tree.difference(&loaded_tree).cloned().collect();
|
||||
let removed_difference: BTreeSet<String> = loaded_tree.difference(&new_tree).cloned().collect();
|
||||
if !added_difference.is_empty() || !removed_difference.is_empty() {
|
||||
changed = true;
|
||||
handle_watch_notification(cfg, &added_difference, &removed_difference, target_name, &pl.title);
|
||||
}
|
||||
} else {
|
||||
error!("failed to load watch_file {}", &path.to_str().unwrap_or_default());
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
changed = true;
|
||||
}
|
||||
if changed {
|
||||
match save_watch_tree(&save_path, new_tree) {
|
||||
Ok(_) => {}
|
||||
match save_watch_tree(&save_path, &new_tree) {
|
||||
Ok(()) => {}
|
||||
Err(err) => {
|
||||
error!("failed to write watch_file {}: {}", &save_path.to_str().unwrap_or_default(), err)
|
||||
error!("failed to write watch_file {}: {}", &save_path.to_str().unwrap_or_default(), err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,9 +53,9 @@ pub(crate) fn process_group_watch(cfg: &Config, target_name: &str, pl: &Playlist
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_watch_notification(cfg: &Config, added: BTreeSet<String>, removed: BTreeSet<String>, target_name: &str, group_name: &str) {
|
||||
let added_entries = added.iter().map(|name| name.to_string()).collect::<Vec<String>>().join("\n\t");
|
||||
let removed_entries = removed.iter().map(|name| name.to_string()).collect::<Vec<String>>().join("\n\t");
|
||||
fn handle_watch_notification(cfg: &Config, added: &BTreeSet<String>, removed: &BTreeSet<String>, target_name: &str, group_name: &str) {
|
||||
let added_entries = added.iter().map(std::string::ToString::to_string).collect::<Vec<String>>().join("\n\t");
|
||||
let removed_entries = removed.iter().map(std::string::ToString::to_string).collect::<Vec<String>>().join("\n\t");
|
||||
|
||||
let mut message = vec![];
|
||||
if !added_entries.is_empty() {
|
||||
@@ -89,7 +86,7 @@ fn load_watch_tree(path: &Path) -> Option<BTreeSet<String>> {
|
||||
}
|
||||
}
|
||||
|
||||
fn save_watch_tree(path: &Path, tree: BTreeSet<String>) -> std::io::Result<()> {
|
||||
fn save_watch_tree(path: &Path, tree: &BTreeSet<String>) -> std::io::Result<()> {
|
||||
let encoded: Vec<u8> = bincode::serialize(&tree).unwrap();
|
||||
std::fs::write(path, encoded)
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ pub(crate) fn parse_tvguide(content: &str) -> Option<TVGuide> {
|
||||
Ok(Event::Eof) => break,
|
||||
Ok(Event::Start(e)) => {
|
||||
let name = String::from_utf8_lossy(e.name().as_ref()).to_string();
|
||||
let attributes = e.attributes().filter_map(|a| a.ok())
|
||||
let attributes = e.attributes().filter_map(std::result::Result::ok)
|
||||
.filter_map(|a| {
|
||||
let key = String::from_utf8_lossy(a.key.as_ref()).to_string();
|
||||
let value = String::from(a.unescape_value().unwrap().as_ref()).to_string();
|
||||
if !value.is_empty() {
|
||||
Some((key, value))
|
||||
} else {
|
||||
if value.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some((key, value))
|
||||
}
|
||||
}).collect::<HashMap<String, String>>();
|
||||
let tag = XmlTag {
|
||||
@@ -78,7 +78,7 @@ pub(crate) fn flatten_tvguide(tv_guides: &[Epg]) -> Option<Epg> {
|
||||
children: vec![],
|
||||
};
|
||||
let mut channel_ids: Vec<&String> = vec![];
|
||||
tv_guides.iter().for_each(|guide| {
|
||||
for guide in tv_guides {
|
||||
if epg.attributes.is_none() {
|
||||
epg.attributes.clone_from(&guide.attributes);
|
||||
}
|
||||
@@ -87,7 +87,7 @@ pub(crate) fn flatten_tvguide(tv_guides: &[Epg]) -> Option<Epg> {
|
||||
if let Some(chan_id) = c.get_attribute_value(EPG_ID) {
|
||||
if !channel_ids.contains(&chan_id) {
|
||||
channel_ids.push(chan_id);
|
||||
epg.children.push(c.clone())
|
||||
epg.children.push(c.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ pub(crate) fn flatten_tvguide(tv_guides: &[Epg]) -> Option<Epg> {
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
Some(epg)
|
||||
}
|
||||
}
|
||||
@@ -39,23 +39,23 @@ pub(crate) fn parse_xtream_series_info(info: &Value, group_title: &str, input: &
|
||||
let result: Vec<PlaylistItem> = series_info.episodes.values().flatten().map(|episode|
|
||||
PlaylistItem {
|
||||
header: RefCell::new(PlaylistItemHeader {
|
||||
id: Rc::new(episode.id.to_owned()),
|
||||
stream_id: Rc::new(episode.id.to_owned()),
|
||||
name: Rc::new(episode.title.to_owned()),
|
||||
logo: Rc::new(episode.info.movie_image.to_owned()),
|
||||
id: Rc::new(episode.id.clone()),
|
||||
stream_id: Rc::new(episode.id.clone()),
|
||||
name: Rc::new(episode.title.clone()),
|
||||
logo: Rc::new(episode.info.movie_image.clone()),
|
||||
logo_small: default_as_empty_rc_str(),
|
||||
group: Rc::new(group_title.to_string()),
|
||||
title: Rc::new(episode.title.to_owned()),
|
||||
title: Rc::new(episode.title.clone()),
|
||||
parent_code: default_as_empty_rc_str(),
|
||||
audio_track: default_as_empty_rc_str(),
|
||||
time_shift: default_as_empty_rc_str(),
|
||||
rec: default_as_empty_rc_str(),
|
||||
url: if episode.direct_source.is_empty() {
|
||||
let ext = episode.container_extension.to_owned();
|
||||
let ext = episode.container_extension.clone();
|
||||
let stream_base_url = format!("{}/series/{}/{}/{}.{}", url, username, password, episode.id.as_str(), ext);
|
||||
Rc::new(stream_base_url)
|
||||
} else {
|
||||
Rc::new(episode.direct_source.to_owned())
|
||||
Rc::new(episode.direct_source.clone())
|
||||
},
|
||||
epg_channel_id: None,
|
||||
item_type: PlaylistItemType::Series,
|
||||
|
||||
Reference in New Issue
Block a user