noodlemagazine proxy implementation
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
use ntex::web;
|
||||
|
||||
use crate::proxies::noodlemagazine::NoodlemagazineProxy;
|
||||
use crate::proxies::spankbang::SpankbangProxy;
|
||||
use crate::{proxies::sxyprn::SxyprnProxy, util::requester::Requester};
|
||||
|
||||
pub mod hanimecdn;
|
||||
pub mod hqpornerthumb;
|
||||
pub mod javtiful;
|
||||
pub mod noodlemagazine;
|
||||
pub mod spankbang;
|
||||
pub mod sxyprn;
|
||||
|
||||
@@ -14,6 +16,7 @@ pub enum AnyProxy {
|
||||
Sxyprn(SxyprnProxy),
|
||||
Javtiful(javtiful::JavtifulProxy),
|
||||
Spankbang(SpankbangProxy),
|
||||
Noodlemagazine(NoodlemagazineProxy),
|
||||
}
|
||||
|
||||
pub trait Proxy {
|
||||
@@ -26,6 +29,7 @@ impl Proxy for AnyProxy {
|
||||
AnyProxy::Sxyprn(p) => p.get_video_url(url, requester).await,
|
||||
AnyProxy::Javtiful(p) => p.get_video_url(url, requester).await,
|
||||
AnyProxy::Spankbang(p) => p.get_video_url(url, requester).await,
|
||||
AnyProxy::Noodlemagazine(p) => p.get_video_url(url, requester).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
110
src/proxies/noodlemagazine.rs
Normal file
110
src/proxies/noodlemagazine.rs
Normal file
@@ -0,0 +1,110 @@
|
||||
use ntex::web;
|
||||
use serde_json::Value;
|
||||
use wreq::Version;
|
||||
|
||||
use crate::util::requester::Requester;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NoodlemagazineProxy {}
|
||||
|
||||
impl NoodlemagazineProxy {
|
||||
pub fn new() -> Self {
|
||||
NoodlemagazineProxy {}
|
||||
}
|
||||
|
||||
fn extract_playlist(text: &str) -> Option<&str> {
|
||||
text.split("window.playlist = ").nth(1)?.split(';').next()
|
||||
}
|
||||
|
||||
fn source_score(source: &Value) -> (u8, u32) {
|
||||
let file = source["file"].as_str().unwrap_or_default();
|
||||
let label = source["label"].as_str().unwrap_or_default();
|
||||
let is_hls = u8::from(file.contains(".m3u8"));
|
||||
let quality = label
|
||||
.chars()
|
||||
.filter(|c| c.is_ascii_digit())
|
||||
.collect::<String>()
|
||||
.parse::<u32>()
|
||||
.unwrap_or(0);
|
||||
|
||||
(is_hls, quality)
|
||||
}
|
||||
|
||||
fn select_best_source(playlist: &str) -> Option<String> {
|
||||
let json: Value = serde_json::from_str(playlist).ok()?;
|
||||
let sources = json["sources"].as_array()?;
|
||||
|
||||
sources
|
||||
.iter()
|
||||
.filter(|source| {
|
||||
source["file"]
|
||||
.as_str()
|
||||
.map(|file| !file.is_empty())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.max_by_key(|source| Self::source_score(source))
|
||||
.and_then(|source| source["file"].as_str())
|
||||
.map(str::to_string)
|
||||
}
|
||||
|
||||
pub async fn get_video_url(
|
||||
&self,
|
||||
url: String,
|
||||
requester: web::types::State<Requester>,
|
||||
) -> String {
|
||||
let mut requester = requester.get_ref().clone();
|
||||
let url = if url.starts_with("http://") || url.starts_with("https://") {
|
||||
url
|
||||
} else {
|
||||
format!("https://{}", url.trim_start_matches('/'))
|
||||
};
|
||||
let text = requester
|
||||
.get(&url, Some(Version::HTTP_2))
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
if text.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
|
||||
let Some(playlist) = Self::extract_playlist(&text) else {
|
||||
return String::new();
|
||||
};
|
||||
|
||||
Self::select_best_source(playlist).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::NoodlemagazineProxy;
|
||||
|
||||
#[test]
|
||||
fn extracts_playlist_from_page() {
|
||||
let html = r#"
|
||||
<script>
|
||||
window.playlist = {"sources":[{"file":"https://cdn.example/360.mp4","label":"360p"}]};
|
||||
</script>
|
||||
"#;
|
||||
|
||||
assert_eq!(
|
||||
NoodlemagazineProxy::extract_playlist(html),
|
||||
Some(r#"{"sources":[{"file":"https://cdn.example/360.mp4","label":"360p"}]}"#)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prefers_hls_then_highest_quality() {
|
||||
let playlist = r#"{
|
||||
"sources": [
|
||||
{"file":"https://cdn.example/360.mp4","label":"360p"},
|
||||
{"file":"https://cdn.example/720.mp4","label":"720p"},
|
||||
{"file":"https://cdn.example/master.m3u8","label":"1080p"}
|
||||
]
|
||||
}"#;
|
||||
|
||||
assert_eq!(
|
||||
NoodlemagazineProxy::select_best_source(playlist).as_deref(),
|
||||
Some("https://cdn.example/master.m3u8")
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user