diff --git a/src/providers/hentaimama.rs b/src/providers/hentaimama.rs index 0a0dbd7..1ed8a0d 100644 --- a/src/providers/hentaimama.rs +++ b/src/providers/hentaimama.rs @@ -344,13 +344,13 @@ impl HentaimamaProvider { .collect()) } - fn last_episode_url(html: &str) -> Result> { + fn episode_urls(html: &str) -> Result> { let document = Html::parse_document(html); let selector = Self::selector("a.dt-se-item")?; Ok(document .select(&selector) .filter_map(|e: ElementRef| e.value().attr("href").map(|s| s.to_string())) - .last()) + .collect()) } fn post_id_regex() -> &'static Regex { @@ -484,13 +484,25 @@ impl HentaimamaProvider { Some(item) } - /// Search/genre/studio archives only expose series (show) cards, so a match - /// is represented by its most recent episode - the same shape the latest - /// feed already returns, just reached through one extra hop. - async fn resolve_series_to_item(requester: &mut Requester, series_url: &str) -> Option { - let html = Self::fetch_html(requester, series_url, BASE_URL).await.ok()?; - let episode_url = Self::last_episode_url(&html).ok().flatten()?; - Self::resolve_episode_url(requester, &episode_url).await + /// Search/genre/studio archives only expose series (show) cards, so each + /// match is expanded into every episode of that series - the same shape + /// the latest feed already returns per-episode, just reached through one + /// extra hop. + async fn resolve_series_to_items(requester: &mut Requester, series_url: &str) -> Vec { + let Ok(html) = Self::fetch_html(requester, series_url, BASE_URL).await else { + return vec![]; + }; + let Ok(episode_urls) = Self::episode_urls(&html) else { + return vec![]; + }; + stream::iter(episode_urls.into_iter().map(|episode_url| { + let mut req = requester.clone(); + async move { Self::resolve_episode_url(&mut req, &episode_url).await } + })) + .buffer_unordered(4) + .filter_map(|item| async move { item }) + .collect::>() + .await } async fn resolve_episode_url(requester: &mut Requester, episode_url: &str) -> Option { @@ -574,10 +586,10 @@ impl HentaimamaProvider { let urls = Self::parse_series_card_urls(&html)?; stream::iter(urls.into_iter().take(per_page.max(1)).map(|url| { let mut req = requester.clone(); - async move { Self::resolve_series_to_item(&mut req, &url).await } + async move { Self::resolve_series_to_items(&mut req, &url).await } })) .buffer_unordered(4) - .filter_map(|item| async move { item }) + .flat_map(stream::iter) .collect::>() .await } diff --git a/src/providers/hornyleak.rs b/src/providers/hornyleak.rs index fafecbb..03aebca 100644 --- a/src/providers/hornyleak.rs +++ b/src/providers/hornyleak.rs @@ -663,9 +663,16 @@ impl HornyleakProvider { listing_referer: String, mut requester: Requester, ) -> VideoItem { - // The page URL is yt-dlp-resolvable, so enrichment is only used for tags - // and uploader fields. The HLS embed chain (kept as a private helper - // for future use) is intentionally not invoked here. + // yt-dlp's generic extractor on the page URL grabs the site's own + // `728x90-1.mp4` banner-ad `