videos fixing protocol

This commit is contained in:
Simon
2026-05-20 05:19:23 +00:00
committed by ForgeCode
parent 3e41945fab
commit 6cc56a710c
2 changed files with 109 additions and 35 deletions

View File

@@ -1,6 +1,10 @@
use std::sync::Arc;
use ntex::web;
use url::Url;
use serde_json::json;
use wreq::cookie::Jar;
use wreq::redirect::Policy;
use wreq_util::Emulation;
use crate::util::{dean_edwards, requester::Requester};
@@ -20,8 +24,9 @@ impl LulustreamProxy {
let detail_url = if endpoint.starts_with("http://") || endpoint.starts_with("https://") {
endpoint.to_string()
} else if endpoint.starts_with("lulustream.com/") || endpoint.starts_with("www.lulustream.com/") ||
endpoint.starts_with("luluvdo.com/")
} else if endpoint.starts_with("lulustream.com/")
|| endpoint.starts_with("www.lulustream.com/")
|| endpoint.starts_with("luluvid.com/")
{
format!("https://{endpoint}")
} else {
@@ -33,9 +38,7 @@ impl LulustreamProxy {
}
let parsed = Url::parse(&detail_url).ok()?;
let video_id = parsed.path_segments()?
.last()
.map(ToOwned::to_owned)?;
let video_id = parsed.path_segments()?.last().map(ToOwned::to_owned)?;
Some((detail_url, video_id))
}
@@ -50,40 +53,82 @@ impl LulustreamProxy {
let Some(host) = parsed.host_str() else {
return false;
};
(host == "lulustream.com" || host == "www.lulustream.com" || host == "luluvdo.com")
&& !parsed.path().is_empty() && parsed.path() != "/"
(host == "lulustream.com" || host == "www.lulustream.com" || host == "luluvid.com")
&& !parsed.path().is_empty()
&& parsed.path() != "/"
}
pub async fn get_video_url(
&self,
url: String,
requester: web::types::State<Requester>,
) -> String {
let mut requester = requester.get_ref().clone();
let Some((detail_url, video_id)) = Self::normalize_detail_request(&url) else {
return String::new();
};
println!("LulustreamProxy: Normalized detail URL: {:?}", format!("https://luluvid.com/e/{video_id}"));
let mut text = requester.get(format!("https://luluvid.com/e/{video_id}").as_str(), None).await.unwrap_or_default();
if !text.contains("[{file:\"") {
let packedtext = text.split("<script type='text/javascript'>").nth(1).and_then(|t| t.split("</script>").next()).unwrap_or_default();
text = dean_edwards::unpack(&packedtext).unwrap_or_default();
// Chrome120 emulation bypasses Cloudflare on luluvid.com (Firefox136 gets blocked).
fn build_chrome_client() -> Option<wreq::Client> {
let jar = Arc::new(Jar::default());
wreq::Client::builder()
.cert_verification(false)
.emulation(Emulation::Chrome120)
.cookie_provider(jar)
.redirect(Policy::default())
.build()
.ok()
}
fn extract_media_url(html: &str) -> Option<String> {
// Fast path: file URL present in plain text (no packing)
if html.contains("[{file:\"") {
let url = html
.split("[{file:\"")
.nth(1)
.and_then(|s| s.split('"').next())?
.to_string();
if !url.is_empty() {
return Some(url);
}
}
let video_url = text.split("[{file:\"")
// Unpack the Dean Edwards p,a,c,k,e,d script that embeds the player config.
// The packed payload encodes the jwplayer setup call; after decoding it contains
// `sources:[{file:"https://cdn*.cdn-tnmr.org/hls2/.../master.m3u8?..."}]`.
let packed = html
.split("<script type='text/javascript'>")
.nth(1)
.and_then(|t| t.split("</script>").next())?;
let unpacked = dean_edwards::unpack(packed).ok()?;
unpacked
.split("[{file:\"")
.nth(1)
.and_then(|s| s.split('"').next())
.unwrap_or_default()
.to_string();
println!("LulustreamProxy: Extracted video URL: {}", video_url);
let test_request = requester.get_raw_with_headers(video_url.as_str(), vec![
("Accept-Language".to_string(), "en-US,en;q=0.9".to_string()),
("Referer".to_string(), detail_url.clone()),
("User-Agent".to_string(), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36".to_string())
]).await.unwrap();
println!("LulustreamProxy: Test request status: {}", test_request.status());
.map(|s| s.to_string())
.filter(|s| !s.is_empty())
}
video_url
// return "https://cdn1004.cdn-tnmr.org/hls2/01/03256/cssckmym0ibf_h/master.m3u8?t=Y2jXSIPERwSec0L6RSAOIPFAW53dQ0UgslngqGnF0go&s=1778507711&e=28800&f=16283923&i=0.3&sp=0".to_string();
async fn try_chrome_extraction(embed_url: &str) -> Option<String> {
let client = Self::build_chrome_client()?;
let response = client.get(embed_url).send().await.ok()?;
if !response.status().is_success() {
return None;
}
let html = response.text().await.ok()?;
Self::extract_media_url(&html)
}
}
impl crate::proxies::Proxy for LulustreamProxy {
async fn get_video_url(&self, url: String, requester: web::types::State<Requester>) -> String {
let Some((_detail_url, video_id)) = Self::normalize_detail_request(&url) else {
return String::new();
};
let embed_url = format!("https://luluvid.com/e/{video_id}");
// Chrome120 emulation bypasses Cloudflare; try it first.
if let Some(media_url) = Self::try_chrome_extraction(&embed_url).await {
return media_url;
}
// Fallback: standard requester (Firefox136 + optional FlareSolverr).
let mut requester = requester.get_ref().clone();
let html = requester.get(&embed_url, None).await.unwrap_or_default();
Self::extract_media_url(&html).unwrap_or_default()
}
}
@@ -107,4 +152,33 @@ mod tests {
assert_eq!(url, "https://lulustream.com/d/s484n23k8opy");
assert_eq!(video_id, "s484n23k8opy");
}
#[test]
fn normalizes_luluvid_url() {
let (url, video_id) =
LulustreamProxy::normalize_detail_request("https://luluvid.com/e/s484n23k8opy")
.expect("detail request should parse");
assert_eq!(url, "https://luluvid.com/e/s484n23k8opy");
assert_eq!(video_id, "s484n23k8opy");
}
#[test]
fn extracts_media_url_from_plain_html() {
let html = r#"[{file:"https://cdn1007.cdn-tnmr.org/hls2/02/02723/abc_h/master.m3u8?t=TOKEN&s=12345&e=28800&f=999&i=0.3&sp=0"}]"#;
assert_eq!(
LulustreamProxy::extract_media_url(html).as_deref(),
Some("https://cdn1007.cdn-tnmr.org/hls2/02/02723/abc_h/master.m3u8?t=TOKEN&s=12345&e=28800&f=999&i=0.3&sp=0")
);
}
#[test]
fn extracts_media_url_from_packed_script() {
// Minimal valid packed script that decodes to a jwplayer sources array.
// Original: jwplayer("vplayer").setup({sources:[{file:"https://cdn.example.com/video.m3u8"}]})
// We fake it with a trivial packer (base 10, a few words).
let fake_packed = r#"eval(function(p,a,c,k,e,d){while(c--)if(k[c])p=p.replace(new RegExp('\b'+c.toString(a)+'\b','g'),k[c]);return p}('0("[{1:\"https://cdn.example.com/video.m3u8\"}]")',10,2,'sources|file'.split('|'),0,{}))"#;
let html = format!("<script type='text/javascript'>{fake_packed}</script>");
let url = LulustreamProxy::extract_media_url(&html);
assert!(url.is_some(), "should extract a URL from packed script");
}
}

View File

@@ -275,7 +275,7 @@ impl VideoFormat {
abr: None,
vbr: None,
container: None,
protocol: Some("m3u8_native".to_string()),
protocol: Some("https".to_string()),
audio_ext: Some("none".to_string()),
video_ext: Some("mp4".to_string()),
resolution: None,