mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-01 05:22:28 +02:00
IPCheck and config refactor
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use crate::model::config::{ConfigInput, InputAffix, AFFIX_FIELDS, valid_property};
|
||||
use crate::model::playlist::{FetchedPlaylist, FieldGetAccessor, FieldSetAccessor, PlaylistItem};
|
||||
use crate::model::{ConfigInput, InputAffix, AFFIX_FIELDS, valid_property};
|
||||
use crate::model::{FetchedPlaylist, FieldGetAccessor, FieldSetAccessor, PlaylistItem};
|
||||
use crate::utils::{debug_if_enabled};
|
||||
|
||||
type AffixProcessor<'a> = Box<dyn Fn(&mut PlaylistItem) + 'a>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::model::config::{EpgConfig, EpgSmartMatchConfig};
|
||||
use crate::model::playlist::{FetchedPlaylist, PlaylistItem, XtreamCluster};
|
||||
use crate::model::xmltv::{Epg, XmlTag, EPG_ATTRIB_ID};
|
||||
use crate::model::{EpgConfig, EpgSmartMatchConfig};
|
||||
use crate::model::{FetchedPlaylist, PlaylistItem, XtreamCluster};
|
||||
use crate::model::{Epg, XmlTag, EPG_ATTRIB_ID};
|
||||
use crate::processing::parser::xmltv::normalize_channel_name;
|
||||
use log::debug;
|
||||
use rphonetic::{DoubleMetaphone, Encoder};
|
||||
|
||||
@@ -4,6 +4,7 @@ mod affix;
|
||||
mod xtream_vod;
|
||||
mod xtream_series;
|
||||
pub mod epg;
|
||||
mod sort;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! handle_error {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use crate::model::config::{ConfigInput, ConfigRename, SortOrder};
|
||||
use crate::utils::network::epg;
|
||||
use crate::utils::network::m3u;
|
||||
use crate::utils::network::xtream;
|
||||
use crate::model::{ConfigInput, ConfigRename};
|
||||
use crate::utils::epg;
|
||||
use crate::utils::m3u;
|
||||
use crate::utils::xtream;
|
||||
use crate::Config;
|
||||
use core::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
@@ -13,26 +12,26 @@ use tokio::sync::Mutex;
|
||||
use crate::foundation::filter::{get_field_value, set_field_value, MockValueProcessor, ValueProvider};
|
||||
use crate::m3u_filter_error::{get_errors_notify_message, notify_err, M3uFilterError, M3uFilterErrorKind};
|
||||
use crate::messaging::{send_message, MsgKind};
|
||||
use crate::model::config::{ConfigSortChannel, ConfigSortGroup, ConfigTarget, InputType,
|
||||
ItemField, ProcessTargets, ProcessingOrder};
|
||||
use crate::model::mapping::{CounterModifier, Mapping, MappingValueProcessor};
|
||||
use crate::model::playlist::{FetchedPlaylist, FieldGetAccessor, FieldSetAccessor, PlaylistEntry, PlaylistGroup, PlaylistItem, UUIDType, XtreamCluster};
|
||||
use crate::model::stats::{InputStats, PlaylistStats, SourceStats, TargetStats};
|
||||
use crate::model::{ConfigTarget, InputType, ItemField, ProcessTargets, ProcessingOrder};
|
||||
use crate::model::{CounterModifier, Mapping, MappingValueProcessor};
|
||||
use crate::model::{FetchedPlaylist, FieldGetAccessor, FieldSetAccessor, PlaylistEntry, PlaylistGroup, PlaylistItem, UUIDType, XtreamCluster};
|
||||
use crate::model::{InputStats, PlaylistStats, SourceStats, TargetStats};
|
||||
use crate::processing::playlist_watch::process_group_watch;
|
||||
use crate::processing::processor::affix::apply_affixes;
|
||||
use crate::processing::processor::xtream_series::playlist_resolve_series;
|
||||
use crate::processing::processor::xtream_vod::playlist_resolve_vod;
|
||||
use crate::repository::playlist_repository::persist_playlist;
|
||||
use crate::utils::default_utils::default_as_default;
|
||||
use crate::utils::default_as_default;
|
||||
use crate::utils::debug_if_enabled;
|
||||
use deunicode::deunicode;
|
||||
use log::{debug, error, info, log_enabled, trace, warn, Level};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::model::xmltv::Epg;
|
||||
use crate::model::Epg;
|
||||
use crate::processing::parser::xmltv::flatten_tvguide;
|
||||
use crate::processing::processor::epg::process_playlist_epg;
|
||||
use crate::utils::step_measure::StepMeasure;
|
||||
use crate::processing::processor::sort::sort_playlist;
|
||||
use crate::utils::StepMeasure;
|
||||
|
||||
fn is_valid(pli: &PlaylistItem, target: &ConfigTarget) -> bool {
|
||||
let provider = ValueProvider { pli };
|
||||
@@ -59,138 +58,8 @@ fn filter_playlist(playlist: &mut [PlaylistGroup], target: &ConfigTarget) -> Opt
|
||||
Some(new_playlist)
|
||||
}
|
||||
|
||||
fn playlist_comparator(
|
||||
sequence: Option<&Vec<regex::Regex>>,
|
||||
order: &SortOrder,
|
||||
value_a: &str,
|
||||
value_b: &str,
|
||||
) -> Ordering {
|
||||
if let Some(regex_list) = sequence {
|
||||
let mut match_a = None;
|
||||
let mut match_b = None;
|
||||
|
||||
for (i, regex) in regex_list.iter().enumerate() {
|
||||
if match_a.is_none() {
|
||||
if let Some(caps) = regex.captures(value_a) {
|
||||
match_a = Some((i, caps));
|
||||
}
|
||||
}
|
||||
if match_b.is_none() {
|
||||
if let Some(caps) = regex.captures(value_b) {
|
||||
match_b = Some((i, caps));
|
||||
}
|
||||
}
|
||||
|
||||
// If both matches found → break
|
||||
if match_a.is_some() && match_b.is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
match (match_a, match_b) {
|
||||
(Some((idx_a, caps_a)), Some((idx_b, caps_b))) => {
|
||||
// Different regex indices → sort by their sequence order.
|
||||
if idx_a != idx_b {
|
||||
return match order {
|
||||
SortOrder::Asc => idx_a.cmp(&idx_b),
|
||||
SortOrder::Desc => idx_b.cmp(&idx_a),
|
||||
};
|
||||
}
|
||||
|
||||
// Same regex → sort by captures (c1, c2, …)
|
||||
let mut named: Vec<_> = regex_list[idx_a]
|
||||
.capture_names()
|
||||
.flatten()
|
||||
.filter(|name| name.starts_with('c'))
|
||||
.collect();
|
||||
|
||||
named.sort_by_key(|name| name[1..].parse::<u32>().unwrap_or(0));
|
||||
|
||||
for name in named {
|
||||
let va = caps_a.name(name).map(|m| m.as_str());
|
||||
let vb = caps_b.name(name).map(|m| m.as_str());
|
||||
if let (Some(va), Some(vb)) = (va, vb) {
|
||||
let o = va.cmp(vb);
|
||||
if o != Ordering::Equal {
|
||||
return match order {
|
||||
SortOrder::Asc => o,
|
||||
SortOrder::Desc => o.reverse(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ordering::Equal
|
||||
}
|
||||
(Some(_), None) => match order {
|
||||
SortOrder::Asc => Ordering::Less,
|
||||
SortOrder::Desc => Ordering::Greater,
|
||||
},
|
||||
(None, Some(_)) => match order {
|
||||
SortOrder::Asc => Ordering::Greater,
|
||||
SortOrder::Desc => Ordering::Less,
|
||||
},
|
||||
(None, None) => {
|
||||
// NP match → fallback
|
||||
let o = value_a.cmp(value_b);
|
||||
match order {
|
||||
SortOrder::Asc => o,
|
||||
SortOrder::Desc => o.reverse(),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No Regex-Sequence defined → fallback
|
||||
let o = value_a.cmp(value_b);
|
||||
match order {
|
||||
SortOrder::Asc => o,
|
||||
SortOrder::Desc => o.reverse(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn playlistgroup_comparator(a: &PlaylistGroup, b: &PlaylistGroup, group_sort: &ConfigSortGroup, match_as_ascii: bool) -> Ordering {
|
||||
let value_a = if match_as_ascii { deunicode(&a.title) } else { a.title.to_string() };
|
||||
let value_b = if match_as_ascii { deunicode(&b.title) } else { b.title.to_string() };
|
||||
|
||||
playlist_comparator(group_sort.t_sequence.as_ref(), &group_sort.order, &value_a, &value_b)
|
||||
}
|
||||
|
||||
fn playlistitem_comparator(
|
||||
a: &PlaylistItem,
|
||||
b: &PlaylistItem,
|
||||
channel_sort: &ConfigSortChannel,
|
||||
match_as_ascii: bool,
|
||||
) -> Ordering {
|
||||
let raw_value_a = get_field_value(a, &channel_sort.field);
|
||||
let raw_value_b = get_field_value(b, &channel_sort.field);
|
||||
let value_a = if match_as_ascii { deunicode(&raw_value_a) } else { raw_value_a };
|
||||
let value_b = if match_as_ascii { deunicode(&raw_value_b) } else { raw_value_b };
|
||||
|
||||
playlist_comparator(channel_sort.t_sequence.as_ref(), &channel_sort.order, &value_a, &value_b)
|
||||
}
|
||||
|
||||
fn sort_playlist(target: &ConfigTarget, new_playlist: &mut [PlaylistGroup]) {
|
||||
if let Some(sort) = &target.sort {
|
||||
let match_as_ascii = sort.match_as_ascii;
|
||||
if let Some(group_sort) = &sort.groups {
|
||||
new_playlist.sort_by(|a, b| playlistgroup_comparator(a, b, group_sort, match_as_ascii));
|
||||
}
|
||||
if let Some(channel_sorts) = &sort.channels {
|
||||
for channel_sort in channel_sorts {
|
||||
let regexp = channel_sort.t_re_group_pattern.as_ref().unwrap();
|
||||
for group in new_playlist.iter_mut() {
|
||||
let group_title = if match_as_ascii { deunicode(&group.title) } else { group.title.to_string() };
|
||||
if regexp.is_match(group_title.as_str()) {
|
||||
group.channels.sort_by(|chan1, chan2| playlistitem_comparator(chan1, chan2, channel_sort, match_as_ascii));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn channel_no_playlist(new_playlist: &mut [PlaylistGroup]) {
|
||||
fn assign_channel_no_playlist(new_playlist: &mut [PlaylistGroup]) {
|
||||
let assigned_chnos: HashSet<u32> = new_playlist.iter().flat_map(|g| &g.channels)
|
||||
.filter(|c| !c.header.chno.is_empty())
|
||||
.map(|c| c.header.chno.as_str())
|
||||
@@ -618,7 +487,7 @@ async fn process_playlist_for_target(client: Arc<reqwest::Client>,
|
||||
step.tick("Sorted playlists");
|
||||
sort_playlist(target, &mut flat_new_playlist);
|
||||
step.tick("Assigned channel number");
|
||||
channel_no_playlist(&mut flat_new_playlist);
|
||||
assign_channel_no_playlist(&mut flat_new_playlist);
|
||||
step.tick("Assigned channel counter");
|
||||
map_playlist_counter(target, &mut flat_new_playlist);
|
||||
step.tick("Processed group watches");
|
||||
@@ -696,34 +565,4 @@ mod tests {
|
||||
// // println!("sorensen dice {:?}", strsim::sorensen_dice(data.0, data.1));
|
||||
// }
|
||||
|
||||
use crate::model::config::{ConfigSortChannel, ItemField, SortOrder};
|
||||
use crate::model::playlist::{PlaylistItem, PlaylistItemHeader};
|
||||
use crate::processing::processor::playlist::playlistitem_comparator;
|
||||
use regex::Regex;
|
||||
|
||||
#[test]
|
||||
fn test_sort() {
|
||||
let mut channels: Vec<PlaylistItem> = vec![
|
||||
("D", "HD"), ("A", "FHD"), ("Z", "HD"), ("K", "HD"), ("B", "HD"), ("A", "HD"),
|
||||
("K", "UHD"), ("C", "HD"), ("L", "FHD"), ("R", "UHD"), ("T", "SD"), ("A", "FHD"),
|
||||
].into_iter().map(|(name, quality)| PlaylistItem { header: PlaylistItemHeader { title: format!("Chanel {name} [{quality}]"), ..Default::default() } }).collect::<Vec<PlaylistItem>>().into();
|
||||
|
||||
let channel_sort = ConfigSortChannel {
|
||||
field: ItemField::Caption,
|
||||
group_pattern: ".*".to_string(),
|
||||
order: SortOrder::Asc,
|
||||
sequence: None,
|
||||
t_sequence: Some(vec![
|
||||
Regex::new(r"(?P<c1>.*?)\bUHD\b").unwrap(),
|
||||
Regex::new(r"(?P<c1>.*?)\bFHD\b").unwrap(),
|
||||
Regex::new(r"(?P<c1>.*?)\bHD\b").unwrap(),
|
||||
]),
|
||||
t_re_group_pattern: Some(Regex::new(".*").unwrap()),
|
||||
};
|
||||
|
||||
channels.sort_by(|chan1, chan2| playlistitem_comparator(chan1, chan2, &channel_sort, true));
|
||||
let expected = vec!["Chanel K [UHD]", "Chanel R [UHD]", "Chanel A [FHD]", "Chanel A [FHD]", "Chanel L [FHD]", "Chanel A [HD]", "Chanel B [HD]", "Chanel C [HD]", "Chanel D [HD]", "Chanel K [HD]", "Chanel Z [HD]", "Chanel T [SD]"];
|
||||
let sorted = channels.into_iter().map(|pli| pli.header.title.clone()).collect::<Vec<String>>();
|
||||
assert_eq!(expected, sorted);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
use std::cmp::Ordering;
|
||||
use deunicode::deunicode;
|
||||
use crate::foundation::filter::get_field_value;
|
||||
use crate::model::{ConfigSortChannel, ConfigSortGroup, ConfigTarget, SortOrder};
|
||||
use crate::model::{PlaylistGroup, PlaylistItem};
|
||||
|
||||
fn playlist_comparator(
|
||||
sequence: Option<&Vec<regex::Regex>>,
|
||||
order: &SortOrder,
|
||||
value_a: &str,
|
||||
value_b: &str,
|
||||
) -> Ordering {
|
||||
if let Some(regex_list) = sequence {
|
||||
let mut match_a = None;
|
||||
let mut match_b = None;
|
||||
|
||||
for (i, regex) in regex_list.iter().enumerate() {
|
||||
if match_a.is_none() {
|
||||
if let Some(caps) = regex.captures(value_a) {
|
||||
match_a = Some((i, caps));
|
||||
}
|
||||
}
|
||||
if match_b.is_none() {
|
||||
if let Some(caps) = regex.captures(value_b) {
|
||||
match_b = Some((i, caps));
|
||||
}
|
||||
}
|
||||
|
||||
// If both matches found → break
|
||||
if match_a.is_some() && match_b.is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
match (match_a, match_b) {
|
||||
(Some((idx_a, caps_a)), Some((idx_b, caps_b))) => {
|
||||
// Different regex indices → sort by their sequence order.
|
||||
if idx_a != idx_b {
|
||||
return match order {
|
||||
SortOrder::Asc => idx_a.cmp(&idx_b),
|
||||
SortOrder::Desc => idx_b.cmp(&idx_a),
|
||||
};
|
||||
}
|
||||
|
||||
// Same regex → sort by captures (c1, c2, …)
|
||||
let mut named: Vec<_> = regex_list[idx_a]
|
||||
.capture_names()
|
||||
.flatten()
|
||||
.filter(|name| name.starts_with('c'))
|
||||
.collect();
|
||||
|
||||
named.sort_by_key(|name| name[1..].parse::<u32>().unwrap_or(0));
|
||||
|
||||
for name in named {
|
||||
let va = caps_a.name(name).map(|m| m.as_str());
|
||||
let vb = caps_b.name(name).map(|m| m.as_str());
|
||||
if let (Some(va), Some(vb)) = (va, vb) {
|
||||
let o = va.cmp(vb);
|
||||
if o != Ordering::Equal {
|
||||
return match order {
|
||||
SortOrder::Asc => o,
|
||||
SortOrder::Desc => o.reverse(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ordering::Equal
|
||||
}
|
||||
(Some(_), None) => match order {
|
||||
SortOrder::Asc => Ordering::Less,
|
||||
SortOrder::Desc => Ordering::Greater,
|
||||
},
|
||||
(None, Some(_)) => match order {
|
||||
SortOrder::Asc => Ordering::Greater,
|
||||
SortOrder::Desc => Ordering::Less,
|
||||
},
|
||||
(None, None) => {
|
||||
// NP match → fallback
|
||||
let o = value_a.cmp(value_b);
|
||||
match order {
|
||||
SortOrder::Asc => o,
|
||||
SortOrder::Desc => o.reverse(),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No Regex-Sequence defined → fallback
|
||||
let o = value_a.cmp(value_b);
|
||||
match order {
|
||||
SortOrder::Asc => o,
|
||||
SortOrder::Desc => o.reverse(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn playlistgroup_comparator(a: &PlaylistGroup, b: &PlaylistGroup, group_sort: &ConfigSortGroup, match_as_ascii: bool) -> Ordering {
|
||||
let value_a = if match_as_ascii { deunicode(&a.title) } else { a.title.to_string() };
|
||||
let value_b = if match_as_ascii { deunicode(&b.title) } else { b.title.to_string() };
|
||||
|
||||
playlist_comparator(group_sort.t_sequence.as_ref(), &group_sort.order, &value_a, &value_b)
|
||||
}
|
||||
|
||||
fn playlistitem_comparator(
|
||||
a: &PlaylistItem,
|
||||
b: &PlaylistItem,
|
||||
channel_sort: &ConfigSortChannel,
|
||||
match_as_ascii: bool,
|
||||
) -> Ordering {
|
||||
let raw_value_a = get_field_value(a, &channel_sort.field);
|
||||
let raw_value_b = get_field_value(b, &channel_sort.field);
|
||||
let value_a = if match_as_ascii { deunicode(&raw_value_a) } else { raw_value_a };
|
||||
let value_b = if match_as_ascii { deunicode(&raw_value_b) } else { raw_value_b };
|
||||
|
||||
playlist_comparator(channel_sort.t_sequence.as_ref(), &channel_sort.order, &value_a, &value_b)
|
||||
}
|
||||
|
||||
pub(in crate::processing::processor) fn sort_playlist(target: &ConfigTarget, new_playlist: &mut [PlaylistGroup]) {
|
||||
if let Some(sort) = &target.sort {
|
||||
let match_as_ascii = sort.match_as_ascii;
|
||||
if let Some(group_sort) = &sort.groups {
|
||||
new_playlist.sort_by(|a, b| playlistgroup_comparator(a, b, group_sort, match_as_ascii));
|
||||
}
|
||||
if let Some(channel_sorts) = &sort.channels {
|
||||
for channel_sort in channel_sorts {
|
||||
let regexp = channel_sort.t_re_group_pattern.as_ref().unwrap();
|
||||
for group in new_playlist.iter_mut() {
|
||||
let group_title = if match_as_ascii { deunicode(&group.title) } else { group.title.to_string() };
|
||||
if regexp.is_match(group_title.as_str()) {
|
||||
group.channels.sort_by(|chan1, chan2| playlistitem_comparator(chan1, chan2, channel_sort, match_as_ascii));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::model::{ConfigSortChannel, ItemField, SortOrder};
|
||||
use crate::model::{PlaylistItem, PlaylistItemHeader};
|
||||
use regex::Regex;
|
||||
use crate::processing::processor::sort::playlistitem_comparator;
|
||||
|
||||
#[test]
|
||||
fn test_sort() {
|
||||
let mut channels: Vec<PlaylistItem> = vec![
|
||||
("D", "HD"), ("A", "FHD"), ("Z", "HD"), ("K", "HD"), ("B", "HD"), ("A", "HD"),
|
||||
("K", "UHD"), ("C", "HD"), ("L", "FHD"), ("R", "UHD"), ("T", "SD"), ("A", "FHD"),
|
||||
].into_iter().map(|(name, quality)| PlaylistItem { header: PlaylistItemHeader { title: format!("Chanel {name} [{quality}]"), ..Default::default() } }).collect::<Vec<PlaylistItem>>().into();
|
||||
|
||||
let channel_sort = ConfigSortChannel {
|
||||
field: ItemField::Caption,
|
||||
group_pattern: ".*".to_string(),
|
||||
order: SortOrder::Asc,
|
||||
sequence: None,
|
||||
t_sequence: Some(vec![
|
||||
Regex::new(r"(?P<c1>.*?)\bUHD\b").unwrap(),
|
||||
Regex::new(r"(?P<c1>.*?)\bFHD\b").unwrap(),
|
||||
Regex::new(r"(?P<c1>.*?)\bHD\b").unwrap(),
|
||||
]),
|
||||
t_re_group_pattern: Some(Regex::new(".*").unwrap()),
|
||||
};
|
||||
|
||||
channels.sort_by(|chan1, chan2| playlistitem_comparator(chan1, chan2, &channel_sort, true));
|
||||
let expected = vec!["Chanel K [UHD]", "Chanel R [UHD]", "Chanel A [FHD]", "Chanel A [FHD]", "Chanel L [FHD]", "Chanel A [HD]", "Chanel B [HD]", "Chanel C [HD]", "Chanel D [HD]", "Chanel K [HD]", "Chanel Z [HD]", "Chanel T [SD]"];
|
||||
let sorted = channels.into_iter().map(|pli| pli.header.title.clone()).collect::<Vec<String>>();
|
||||
assert_eq!(expected, sorted);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::m3u_filter_error::{info_err, notify_err};
|
||||
use crate::m3u_filter_error::{str_to_io_error, to_io_error, M3uFilterError, M3uFilterErrorKind};
|
||||
use crate::model::config::{Config, ConfigInput};
|
||||
use crate::model::playlist::{FetchedPlaylist, PlaylistEntry, PlaylistItem, PlaylistItemType, XtreamCluster};
|
||||
use crate::model::{Config, ConfigInput};
|
||||
use crate::model::{FetchedPlaylist, PlaylistEntry, PlaylistItem, PlaylistItemType, XtreamCluster};
|
||||
use crate::repository::storage::get_input_storage_path;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
@@ -9,12 +9,11 @@ use std::fs::File;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use crate::model::xtream_const;
|
||||
use crate::repository::bplustree::BPlusTree;
|
||||
use crate::repository::storage_const;
|
||||
use crate::repository::xtream_repository::xtream_get_record_file_path;
|
||||
use crate::utils::file::file_utils::append_or_crate_file;
|
||||
use crate::utils::network::xtream;
|
||||
use crate::utils::file_utils::append_or_crate_file;
|
||||
use crate::utils::xtream;
|
||||
|
||||
pub(in crate::processing) async fn playlist_resolve_download_playlist_item(client: Arc<reqwest::Client>, pli: &PlaylistItem, input: &ConfigInput, errors: &mut Vec<M3uFilterError>, resolve_delay: u16, cluster: XtreamCluster) -> Option<String> {
|
||||
let mut result = None;
|
||||
@@ -47,7 +46,7 @@ pub(in crate::processing) fn write_info_content_to_wal_file(writer: &mut BufWrit
|
||||
pub(in crate::processing) fn create_resolve_episode_wal_files(cfg: &Config, input: &ConfigInput) -> Option<(File, PathBuf)> {
|
||||
match get_input_storage_path(&input.name, &cfg.working_dir) {
|
||||
Ok(storage_path) => {
|
||||
let info_path = storage_path.join(format!("{}.{}", xtream_const::XC_FILE_SERIES_EPISODE_RECORD, storage_const::FILE_SUFFIX_WAL));
|
||||
let info_path = storage_path.join(format!("{}.{}", crate::model::XC_FILE_SERIES_EPISODE_RECORD, storage_const::FILE_SUFFIX_WAL));
|
||||
let info_file = append_or_crate_file(&info_path).ok()?;
|
||||
Some((info_file, info_path))
|
||||
}
|
||||
@@ -60,8 +59,8 @@ pub(in crate::processing) fn create_resolve_info_wal_files(cfg: &Config, input:
|
||||
Ok(storage_path) => {
|
||||
if let Some(file_prefix) = match cluster {
|
||||
XtreamCluster::Live => None,
|
||||
XtreamCluster::Video => Some(xtream_const::XC_FILE_VOD_INFO),
|
||||
XtreamCluster::Series => Some(xtream_const::XC_FILE_SERIES_INFO)
|
||||
XtreamCluster::Video => Some(crate::model::XC_FILE_VOD_INFO),
|
||||
XtreamCluster::Series => Some(crate::model::XC_FILE_SERIES_INFO)
|
||||
} {
|
||||
let content_path = storage_path.join(format!("{file_prefix}_content.{}", storage_const::FILE_SUFFIX_WAL));
|
||||
let info_path = storage_path.join(format!("{file_prefix}_record.{}", storage_const::FILE_SUFFIX_WAL));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::m3u_filter_error::{M3uFilterError, M3uFilterErrorKind};
|
||||
use crate::model::config::{Config, ConfigTarget, InputType};
|
||||
use crate::model::playlist::{FetchedPlaylist, PlaylistGroup, PlaylistItem, PlaylistItemType, XtreamCluster};
|
||||
use crate::model::{Config, ConfigTarget, InputType};
|
||||
use crate::model::{FetchedPlaylist, PlaylistGroup, PlaylistItem, PlaylistItemType, XtreamCluster};
|
||||
use crate::processing::processor::playlist::ProcessingPipe;
|
||||
use crate::processing::parser::xtream::parse_xtream_series_info;
|
||||
use crate::processing::processor::xtream::{create_resolve_episode_wal_files, create_resolve_info_wal_files, playlist_resolve_download_playlist_item, read_processed_info_ids, should_update_info, write_info_content_to_wal_file};
|
||||
@@ -15,10 +15,9 @@ use std::io::{BufWriter, Write};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use log::{info, log_enabled, Level};
|
||||
use crate::model::xtream::{XtreamSeriesEpisode, XtreamSeriesInfoEpisode};
|
||||
use crate::model::xtream_const;
|
||||
use crate::utils::bincode_utils::bincode_serialize;
|
||||
use crate::utils::file::file_utils::file_writer;
|
||||
use crate::model::{XtreamSeriesEpisode, XtreamSeriesInfoEpisode};
|
||||
use crate::utils::bincode_serialize;
|
||||
use crate::utils::file_utils::file_writer;
|
||||
|
||||
create_resolve_options_function_for_xtream_target!(series);
|
||||
|
||||
@@ -52,7 +51,7 @@ fn write_series_episode_record_to_wal_file(
|
||||
}
|
||||
|
||||
fn should_update_series_info(pli: &mut PlaylistItem, processed_provider_ids: &HashMap<u32, u64>) -> (bool, u32, u64) {
|
||||
should_update_info(pli, processed_provider_ids, xtream_const::XC_TAG_SERIES_INFO_LAST_MODIFIED)
|
||||
should_update_info(pli, processed_provider_ids, crate::model::XC_TAG_SERIES_INFO_LAST_MODIFIED)
|
||||
}
|
||||
|
||||
async fn playlist_resolve_series_info(client: Arc<reqwest::Client>, cfg: &Config, errors: &mut Vec<M3uFilterError>,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use crate::m3u_filter_error::{M3uFilterError, M3uFilterErrorKind};
|
||||
use crate::model::config::{Config, ConfigTarget, InputType};
|
||||
use crate::model::playlist::{FetchedPlaylist, PlaylistItem, PlaylistItemType, XtreamCluster};
|
||||
use crate::model::{Config, ConfigTarget, InputType};
|
||||
use crate::model::{FetchedPlaylist, PlaylistItem, PlaylistItemType, XtreamCluster};
|
||||
use crate::processing::processor::xtream::{create_resolve_info_wal_files, playlist_resolve_download_playlist_item, read_processed_info_ids, should_update_info, write_info_content_to_wal_file};
|
||||
use crate::repository::xtream_repository::{xtream_update_input_info_file, xtream_update_input_vod_record_from_wal_file, InputVodInfoRecord};
|
||||
use crate::m3u_filter_error::{notify_err};
|
||||
use crate::processing::processor::{handle_error, handle_error_and_return, create_resolve_options_function_for_xtream_target};
|
||||
use crate::utils::json_utils::{get_u32_from_serde_value, get_u64_from_serde_value};
|
||||
use crate::utils::{get_u32_from_serde_value, get_u64_from_serde_value};
|
||||
use serde_json::{Map, Value};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
@@ -13,8 +13,7 @@ use std::io::{BufWriter, Write};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use log::{info, log_enabled, Level};
|
||||
use crate::model::xtream_const;
|
||||
use crate::utils::file::file_utils::file_writer;
|
||||
use crate::utils::file_utils::file_writer;
|
||||
|
||||
create_resolve_options_function_for_xtream_target!(vod);
|
||||
|
||||
@@ -25,18 +24,18 @@ async fn read_processed_vod_info_ids(cfg: &Config, errors: &mut Vec<M3uFilterErr
|
||||
fn extract_info_record_from_vod_info(content: &str) -> Option<(u32, InputVodInfoRecord)> {
|
||||
let doc = serde_json::from_str::<Map<String, Value>>(content).ok()?;
|
||||
|
||||
let movie_data = doc.get(xtream_const::XC_TAG_VOD_INFO_MOVIE_DATA)?.as_object()?;
|
||||
let movie_data = doc.get(crate::model::XC_TAG_VOD_INFO_MOVIE_DATA)?.as_object()?;
|
||||
let provider_id = get_u32_from_serde_value(
|
||||
movie_data.get(xtream_const::XC_TAG_VOD_INFO_STREAM_ID)?,
|
||||
movie_data.get(crate::model::XC_TAG_VOD_INFO_STREAM_ID)?,
|
||||
)?;
|
||||
|
||||
let added = movie_data
|
||||
.get(xtream_const::XC_TAG_VOD_INFO_ADDED)
|
||||
.get(crate::model::XC_TAG_VOD_INFO_ADDED)
|
||||
.and_then(get_u64_from_serde_value)
|
||||
.unwrap_or(0);
|
||||
|
||||
let tmdb_id = doc.get(xtream_const::XC_TAG_VOD_INFO_INFO)?.as_object()
|
||||
.and_then(|info| info.get(xtream_const::XC_TAG_VOD_INFO_TMDB_ID))
|
||||
let tmdb_id = doc.get(crate::model::XC_TAG_VOD_INFO_INFO)?.as_object()
|
||||
.and_then(|info| info.get(crate::model::XC_TAG_VOD_INFO_TMDB_ID))
|
||||
.and_then(get_u32_from_serde_value)
|
||||
.unwrap_or(0);
|
||||
|
||||
@@ -58,7 +57,7 @@ fn write_vod_info_record_to_wal_file(
|
||||
}
|
||||
|
||||
fn should_update_vod_info(pli: &mut PlaylistItem, processed_provider_ids: &HashMap<u32, u64>) -> (bool, u32, u64) {
|
||||
should_update_info(pli, processed_provider_ids, xtream_const::XC_TAG_VOD_INFO_ADDED)
|
||||
should_update_info(pli, processed_provider_ids, crate::model::XC_TAG_VOD_INFO_ADDED)
|
||||
}
|
||||
|
||||
pub async fn playlist_resolve_vod(client: Arc<reqwest::Client>, cfg: &Config, target: &ConfigTarget, errors: &mut Vec<M3uFilterError>, fpl: &mut FetchedPlaylist<'_>) {
|
||||
|
||||
Reference in New Issue
Block a user