provider refactors and fixes

This commit is contained in:
Simon
2026-03-05 13:28:38 +00:00
parent 060d8e7937
commit 8157e223fe
33 changed files with 3051 additions and 1694 deletions

View File

@@ -1,6 +1,6 @@
use crate::DbPool;
use crate::api::ClientVersion;
use crate::providers::Provider;
use crate::providers::{Provider, report_provider_error_background};
use crate::status::*;
use crate::util::cache::VideoCache;
use crate::util::time::parse_time_to_seconds;
@@ -21,8 +21,13 @@ error_chain! {
fn is_valid_date(s: &str) -> bool {
// Regex: strict yyyy-mm-dd (no validation of real calendar dates, just format)
let re = Regex::new(r"^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$").unwrap();
re.is_match(s)
match Regex::new(r"^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$") {
Ok(re) => re.is_match(s),
Err(e) => {
report_provider_error_background("xxdbx", "is_valid_date.regex", &e.to_string());
false
}
}
}
#[derive(Debug, Clone)]
@@ -104,8 +109,14 @@ impl XxdbxProvider {
}
};
let mut requester = options.requester.clone().unwrap();
let text = requester.get(&video_url, None).await.unwrap();
let mut requester = crate::providers::requester_or_default(&options, module_path!(), "missing_requester");
let text = match requester.get(&video_url, None).await {
Ok(text) => text,
Err(e) => {
report_provider_error_background("xxdbx", "get.request", &e.to_string());
return Ok(old_items);
}
};
let video_items: Vec<VideoItem> = self.get_video_items_from_html(text.clone());
if !video_items.is_empty() {
cache.remove(&video_url);
@@ -126,9 +137,31 @@ impl XxdbxProvider {
let search_string = query.trim().to_string();
let mut search_type = "search";
if self.channels.read().unwrap().iter().map(|s|s.to_ascii_lowercase()).collect::<Vec<String>>().contains(&search_string.to_ascii_lowercase()) {
if self
.channels
.read()
.map(|channels| {
channels
.iter()
.map(|s| s.to_ascii_lowercase())
.collect::<Vec<String>>()
.contains(&search_string.to_ascii_lowercase())
})
.unwrap_or(false)
{
search_type = "channels";
} else if self.stars.read().unwrap().iter().map(|s|s.to_ascii_lowercase()).collect::<Vec<String>>().contains(&search_string.to_ascii_lowercase()) {
} else if self
.stars
.read()
.map(|stars| {
stars
.iter()
.map(|s| s.to_ascii_lowercase())
.collect::<Vec<String>>()
.contains(&search_string.to_ascii_lowercase())
})
.unwrap_or(false)
{
search_type = "stars";
} else if is_valid_date(&search_string){
search_type = "dates";
@@ -153,9 +186,15 @@ impl XxdbxProvider {
}
};
let mut requester = options.requester.clone().unwrap();
let mut requester = crate::providers::requester_or_default(&options, module_path!(), "missing_requester");
let text = requester.get(&video_url, None).await.unwrap();
let text = match requester.get(&video_url, None).await {
Ok(text) => text,
Err(e) => {
report_provider_error_background("xxdbx", "query.request", &e.to_string());
return Ok(old_items);
}
};
let video_items: Vec<VideoItem> = self.get_video_items_from_html(text.clone());
if !video_items.is_empty() {
cache.remove(&video_url);
@@ -171,9 +210,9 @@ impl XxdbxProvider {
return vec![];
}
let mut items: Vec<VideoItem> = Vec::new();
let raw_videos = html.split("</article>").collect::<Vec<&str>>()[0]
let raw_videos = html.split("</article>").collect::<Vec<&str>>().get(0).copied().unwrap_or_default()
.split("<div class=\"vids\">")
.collect::<Vec<&str>>()[1]
.collect::<Vec<&str>>().get(1).copied().unwrap_or_default()
.split("<div class=\"v\">")
.collect::<Vec<&str>>()[1..]
.to_vec();
@@ -182,52 +221,68 @@ impl XxdbxProvider {
// for (index, line) in vid.iter().enumerate() {
// println!("Line {}: {}\n\n", index, line);
// }
let video_url: String = format!("{}{}", self.url, video_segment.split("<a href=\"").collect::<Vec<&str>>()[1]
let video_url: String = format!("{}{}", self.url, video_segment.split("<a href=\"").collect::<Vec<&str>>().get(1).copied().unwrap_or_default()
.split("\"")
.collect::<Vec<&str>>()[0]
.collect::<Vec<&str>>().get(0).copied().unwrap_or_default()
.to_string());
let mut title = video_segment
.split("<div class=\"v_title\">")
.collect::<Vec<&str>>()[1]
.collect::<Vec<&str>>().get(1).copied().unwrap_or_default()
.split("<")
.collect::<Vec<&str>>()[0]
.collect::<Vec<&str>>().get(0).copied().unwrap_or_default()
.trim()
.to_string();
// html decode
title = decode(title.as_bytes()).to_string().unwrap_or(title);
let id = video_url.split("/").collect::<Vec<&str>>()[4].to_string();
let id = video_url.split("/").collect::<Vec<&str>>().get(4).copied().unwrap_or_default().to_string();
let thumb = format!("https:{}", video_segment.split("<img ").collect::<Vec<&str>>()[1]
.split("src=\"").collect::<Vec<&str>>().last().unwrap()
let thumb = format!("https:{}", video_segment.split("<img ").collect::<Vec<&str>>().get(1).copied().unwrap_or_default()
.split("src=\"").collect::<Vec<&str>>().last().copied().unwrap_or_default()
.split("\"")
.collect::<Vec<&str>>()[0]
.collect::<Vec<&str>>().get(0).copied().unwrap_or_default()
.to_string());
let raw_duration = video_segment
.split("<div class=\"v_dur\">")
.collect::<Vec<&str>>()[1]
.collect::<Vec<&str>>().get(1).copied().unwrap_or_default()
.split("<")
.collect::<Vec<&str>>()[0]
.collect::<Vec<&str>>().get(0).copied().unwrap_or_default()
.to_string();
let duration = parse_time_to_seconds(raw_duration.as_str()).unwrap_or(0) as u32;
let preview = format!("https:{}",video_segment
.split("data-preview=\"")
.collect::<Vec<&str>>()[1]
.collect::<Vec<&str>>().get(1).copied().unwrap_or_default()
.split("\"")
.collect::<Vec<&str>>()[0]
.collect::<Vec<&str>>().get(0).copied().unwrap_or_default()
.to_string());
let tags = video_segment.split("<div class=\"v_tags\">").collect::<Vec<&str>>()[1]
.split("</div>").collect::<Vec<&str>>()[0]
let tags = video_segment.split("<div class=\"v_tags\">").collect::<Vec<&str>>().get(1).copied().unwrap_or_default()
.split("</div>").collect::<Vec<&str>>().get(0).copied().unwrap_or_default()
.split("<a href=\"")
.collect::<Vec<&str>>()[1..]
.into_iter().map(|s| s.split("\"").collect::<Vec<&str>>()[0].replace("%20"," ").to_string()).collect::<Vec<String>>();
.into_iter().map(|s| s.split("\"").collect::<Vec<&str>>().get(0).copied().unwrap_or_default().replace("%20"," ").to_string()).collect::<Vec<String>>();
for tag in tags.clone() {
let shorted_tag = tag.split("/").collect::<Vec<&str>>()[2].to_string();
if tag.contains("channels") && self.channels.read().unwrap().contains(&shorted_tag) == false {
self.channels.write().unwrap().push(shorted_tag.clone());
let shorted_tag = tag.split("/").collect::<Vec<&str>>().get(2).copied().unwrap_or_default().to_string();
if tag.contains("channels")
&& self
.channels
.read()
.map(|channels| !channels.contains(&shorted_tag))
.unwrap_or(false)
{
if let Ok(mut channels) = self.channels.write() {
channels.push(shorted_tag.clone());
}
}
if tag.contains("stars") && self.stars.read().unwrap().contains(&shorted_tag) == false {
self.stars.write().unwrap().push(shorted_tag.clone());
if tag.contains("stars")
&& self
.stars
.read()
.map(|stars| !stars.contains(&shorted_tag))
.unwrap_or(false)
{
if let Ok(mut stars) = self.stars.write() {
stars.push(shorted_tag.clone());
}
}
}
let video_item = VideoItem::new(
@@ -238,7 +293,7 @@ impl XxdbxProvider {
thumb,
duration,
)
.tags(tags.into_iter().map(|s| s.split("/").collect::<Vec<&str>>().last().unwrap().to_string()).collect::<Vec<String>>())
.tags(tags.into_iter().map(|s| s.split("/").collect::<Vec<&str>>().last().copied().unwrap_or_default().to_string()).collect::<Vec<String>>())
.preview(preview);
items.push(video_item);
}