upgrades
This commit is contained in:
@@ -14,6 +14,8 @@ use diesel::r2d2;
|
||||
use error_chain::error_chain;
|
||||
use futures::future::join_all;
|
||||
use htmlentity::entity::{ICodedDataTrait, decode};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::vec;
|
||||
use wreq::Version;
|
||||
|
||||
@@ -41,15 +43,58 @@ error_chain! {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MissavProvider {
|
||||
url: String,
|
||||
tag_map: Arc<RwLock<HashMap<String, String>>>,
|
||||
}
|
||||
|
||||
impl MissavProvider {
|
||||
pub fn new() -> Self {
|
||||
MissavProvider {
|
||||
url: "https://missav.ws".to_string(),
|
||||
tag_map: Arc::new(RwLock::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_key(value: &str) -> String {
|
||||
value
|
||||
.trim()
|
||||
.to_ascii_lowercase()
|
||||
.replace(['_', '-'], " ")
|
||||
.split_whitespace()
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
fn humanize_slug(value: &str) -> String {
|
||||
value
|
||||
.trim_matches('/')
|
||||
.replace('-', " ")
|
||||
.split_whitespace()
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
fn insert_tag_mapping(&self, key: &str, path_or_url: &str) {
|
||||
let normalized = Self::normalize_key(key);
|
||||
if normalized.is_empty() || path_or_url.trim().is_empty() {
|
||||
return;
|
||||
}
|
||||
if let Ok(mut map) = self.tag_map.write() {
|
||||
map.insert(normalized, path_or_url.trim().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_query_url(&self, query: &str, page: u8, sort: &str) -> Option<String> {
|
||||
let normalized = Self::normalize_key(query);
|
||||
let mapped = self.tag_map.read().ok()?.get(&normalized)?.clone();
|
||||
let separator = if mapped.contains('?') { "&" } else { "?" };
|
||||
let mut url = format!("{mapped}{separator}page={page}");
|
||||
if !sort.is_empty() {
|
||||
url.push_str("&sort=");
|
||||
url.push_str(sort);
|
||||
}
|
||||
Some(url)
|
||||
}
|
||||
|
||||
fn build_channel(&self, _clientversion: ClientVersion) -> Channel {
|
||||
Channel {
|
||||
id: "missav".to_string(),
|
||||
@@ -248,10 +293,13 @@ impl MissavProvider {
|
||||
if !sort.is_empty() {
|
||||
sort = format!("&sort={}", sort);
|
||||
}
|
||||
let url_str = format!(
|
||||
let mut url_str = format!(
|
||||
"{}/{}/search/{}?page={}{}",
|
||||
self.url, language, search_string, page, sort
|
||||
);
|
||||
if let Some(mapped_url) = self.resolve_query_url(query, page, &sort.replace("&sort=", "")) {
|
||||
url_str = mapped_url;
|
||||
}
|
||||
|
||||
if let Some((time, items)) = cache.get(&url_str) {
|
||||
if time.elapsed().unwrap_or_default().as_secs() < 3600 {
|
||||
@@ -386,19 +434,54 @@ impl MissavProvider {
|
||||
|
||||
// 3. Extract Tags (Generic approach to avoid repetitive code)
|
||||
let mut tags = vec![];
|
||||
for (label, prefix) in [
|
||||
("Actress:", "@actress"),
|
||||
("Actor:", "@actor"),
|
||||
("Maker:", "@maker"),
|
||||
("Genre:", "@genre"),
|
||||
for (label, route_kind) in [
|
||||
("Actress:", "actress"),
|
||||
("Actor:", "actor"),
|
||||
("Maker:", "maker"),
|
||||
("Genre:", "genre"),
|
||||
] {
|
||||
let marker = format!("<span>{}</span>", label);
|
||||
if let Some(section) = extract(&vid, &marker, "</div>") {
|
||||
for part in section.split("class=\"text-nord13 font-medium\">").skip(1) {
|
||||
if let Some(val) = part.split('<').next() {
|
||||
let clean = val.trim();
|
||||
if !clean.is_empty() {
|
||||
tags.push(format!("{}:{}", prefix, clean));
|
||||
for anchor in section.split("<a ").skip(1) {
|
||||
let href = anchor
|
||||
.split("href=\"")
|
||||
.nth(1)
|
||||
.and_then(|value| value.split('"').next())
|
||||
.unwrap_or_default()
|
||||
.to_string();
|
||||
let title = anchor
|
||||
.split("class=\"text-nord13 font-medium\">")
|
||||
.nth(1)
|
||||
.and_then(|value| value.split('<').next())
|
||||
.map(str::trim)
|
||||
.unwrap_or_default()
|
||||
.to_string();
|
||||
if !title.is_empty() {
|
||||
tags.push(title.clone());
|
||||
if !href.is_empty() {
|
||||
let full_url = if href.starts_with("http://") || href.starts_with("https://") {
|
||||
href.clone()
|
||||
} else {
|
||||
format!("{}{}", self.url, href)
|
||||
};
|
||||
self.insert_tag_mapping(&title, &full_url);
|
||||
let slug = href
|
||||
.trim_matches('/')
|
||||
.rsplit('/')
|
||||
.next()
|
||||
.unwrap_or_default()
|
||||
.to_string();
|
||||
if !slug.is_empty() {
|
||||
self.insert_tag_mapping(&slug, &full_url);
|
||||
self.insert_tag_mapping(
|
||||
&format!("{route_kind}:{}", slug),
|
||||
&full_url,
|
||||
);
|
||||
self.insert_tag_mapping(
|
||||
&format!("{route_kind}:{}", Self::humanize_slug(&slug)),
|
||||
&full_url,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user