hsex page >1 fix

This commit is contained in:
Simon
2026-03-18 12:56:11 +00:00
parent ce1afd9873
commit 21ef0ebf17

View File

@@ -10,14 +10,16 @@ use crate::util::requester::Requester;
use crate::util::time::parse_time_to_seconds; use crate::util::time::parse_time_to_seconds;
use crate::videos::{ServerOptions, VideoFormat, VideoItem}; use crate::videos::{ServerOptions, VideoFormat, VideoItem};
use async_trait::async_trait; use async_trait::async_trait;
use chrono::{DateTime, Duration, NaiveDate, Utc}; use chrono::{DateTime, Duration as ChronoDuration, NaiveDate, Utc};
use error_chain::error_chain; use error_chain::error_chain;
use futures::stream::{self, StreamExt}; use futures::stream::{self, StreamExt};
use htmlentity::entity::{ICodedDataTrait, decode}; use htmlentity::entity::{ICodedDataTrait, decode};
use regex::Regex; use regex::Regex;
use scraper::{ElementRef, Html, Selector}; use scraper::{ElementRef, Html, Selector};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use std::time::Duration as StdDuration;
use std::{thread, vec}; use std::{thread, vec};
use tokio::time::timeout;
use url::Url; use url::Url;
use wreq::Version; use wreq::Version;
@@ -546,11 +548,11 @@ impl HsexProvider {
let unit = captures.get(2)?.as_str(); let unit = captures.get(2)?.as_str();
let now = Utc::now(); let now = Utc::now();
let timestamp = match unit { let timestamp = match unit {
"分钟" => now - Duration::minutes(amount), "分钟" => now - ChronoDuration::minutes(amount),
"小时" => now - Duration::hours(amount), "小时" => now - ChronoDuration::hours(amount),
"" => now - Duration::days(amount), "" => now - ChronoDuration::days(amount),
"" => now - Duration::days(amount * 30), "" => now - ChronoDuration::days(amount * 30),
"" => now - Duration::days(amount * 365), "" => now - ChronoDuration::days(amount * 365),
_ => return None, _ => return None,
}; };
Some(timestamp.timestamp() as u64) Some(timestamp.timestamp() as u64)
@@ -786,8 +788,13 @@ impl HsexProvider {
async fn enrich_video(&self, item: VideoItem, options: &ServerOptions) -> VideoItem { async fn enrich_video(&self, item: VideoItem, options: &ServerOptions) -> VideoItem {
let mut requester = requester_or_default(options, CHANNEL_ID, "enrich_video"); let mut requester = requester_or_default(options, CHANNEL_ID, "enrich_video");
match self.fetch_html(&mut requester, &item.url, &format!("{}/", self.url)).await { let detail_fetch = timeout(
Ok(html) => match self.apply_detail_video(item.clone(), &html, &item.url) { StdDuration::from_secs(6),
self.fetch_html(&mut requester, &item.url, &format!("{}/", self.url)),
)
.await;
match detail_fetch {
Ok(Ok(html)) => match self.apply_detail_video(item.clone(), &html, &item.url) {
Ok(enriched) => enriched, Ok(enriched) => enriched,
Err(error) => { Err(error) => {
report_provider_error_background( report_provider_error_background(
@@ -798,10 +805,14 @@ impl HsexProvider {
item item
} }
}, },
Err(error) => { Ok(Err(error)) => {
report_provider_error_background(CHANNEL_ID, "fetch_detail", &error.to_string()); report_provider_error_background(CHANNEL_ID, "fetch_detail", &error.to_string());
item item
} }
Err(_) => {
report_provider_error_background(CHANNEL_ID, "fetch_detail_timeout", &item.url);
item
}
} }
} }
@@ -810,6 +821,7 @@ impl HsexProvider {
cache: VideoCache, cache: VideoCache,
url: String, url: String,
per_page_limit: usize, per_page_limit: usize,
enrich_details: bool,
options: &ServerOptions, options: &ServerOptions,
) -> Result<Vec<VideoItem>> { ) -> Result<Vec<VideoItem>> {
if let Some((time, items)) = cache.get(&url) { if let Some((time, items)) = cache.get(&url) {
@@ -819,7 +831,12 @@ impl HsexProvider {
} }
let mut requester = requester_or_default(options, CHANNEL_ID, "fetch_items_for_url"); let mut requester = requester_or_default(options, CHANNEL_ID, "fetch_items_for_url");
let html = self.fetch_html(&mut requester, &url, &format!("{}/", self.url)).await?; let html = timeout(
StdDuration::from_secs(10),
self.fetch_html(&mut requester, &url, &format!("{}/", self.url)),
)
.await
.map_err(|_| Error::from(format!("list request timed out for {url}")))??;
let list_items = self.parse_list_videos(&html)?; let list_items = self.parse_list_videos(&html)?;
if list_items.is_empty() { if list_items.is_empty() {
return Ok(vec![]); return Ok(vec![]);
@@ -830,6 +847,11 @@ impl HsexProvider {
.take(per_page_limit.max(1)) .take(per_page_limit.max(1))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if !enrich_details {
cache.insert(url, limited_items.clone());
return Ok(limited_items);
}
let items = stream::iter(limited_items.into_iter().map(|item| { let items = stream::iter(limited_items.into_iter().map(|item| {
let provider = self.clone(); let provider = self.clone();
let options = options.clone(); let options = options.clone();
@@ -856,7 +878,7 @@ impl HsexProvider {
) -> Result<Vec<VideoItem>> { ) -> Result<Vec<VideoItem>> {
let target = self.resolve_option_target(&options, sort); let target = self.resolve_option_target(&options, sort);
let url = self.build_url_for_target(&target, page); let url = self.build_url_for_target(&target, page);
self.fetch_items_for_url(cache, url, per_page_limit, &options) self.fetch_items_for_url(cache, url, per_page_limit, page <= 1, &options)
.await .await
} }
@@ -871,7 +893,7 @@ impl HsexProvider {
) -> Result<Vec<VideoItem>> { ) -> Result<Vec<VideoItem>> {
let target = self.resolve_query_target(query, sort); let target = self.resolve_query_target(query, sort);
let url = self.build_url_for_target(&target, page); let url = self.build_url_for_target(&target, page);
self.fetch_items_for_url(cache, url, per_page_limit, &options) self.fetch_items_for_url(cache, url, per_page_limit, page <= 1, &options)
.await .await
} }
} }
@@ -917,6 +939,8 @@ impl Provider for HsexProvider {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::util::cache::VideoCache;
use crate::util::requester::Requester;
fn provider() -> HsexProvider { fn provider() -> HsexProvider {
HsexProvider { HsexProvider {
@@ -995,4 +1019,32 @@ mod tests {
Some("https://cdn1.hdcdn.online/hls/1183662/index.m3u8") Some("https://cdn1.hdcdn.online/hls/1183662/index.m3u8")
); );
} }
#[tokio::test]
#[ignore]
async fn fetches_page_two_items() {
let provider = provider();
let options = ServerOptions {
featured: None,
category: None,
sites: None,
filter: Some("new".to_string()),
language: None,
public_url_base: None,
requester: Some(Requester::new()),
network: None,
stars: None,
categories: None,
duration: None,
sort: Some("new".to_string()),
sexuality: None,
};
let videos = provider
.get(VideoCache::new(), 2, "new", 10, options)
.await
.expect("page 2 should load");
assert!(!videos.is_empty(), "page 2 should return items");
}
} }