This commit is contained in:
Simon
2026-03-20 22:12:40 +00:00
parent 1b32df0c35
commit 403ad6f103

View File

@@ -86,6 +86,17 @@ impl HentaihavenProvider {
} }
} }
fn has_playable_formats(item: &VideoItem) -> bool {
item.formats
.as_ref()
.is_some_and(|formats| formats.iter().any(|format| !format.url.trim().is_empty()))
}
fn decode_cached_video(cached: &str) -> Option<VideoItem> {
let item = VideoItem::from(cached.to_string()).ok()?;
Self::has_playable_formats(&item).then_some(item)
}
async fn get( async fn get(
&self, &self,
cache: VideoCache, cache: VideoCache,
@@ -353,12 +364,13 @@ impl HentaihavenProvider {
drop(conn); drop(conn);
match db_result { match db_result {
Ok(Some(video)) => { Ok(Some(video)) => {
let video_item = VideoItem::from(video); if let Some(item) = Self::decode_cached_video(&video) {
match video_item { return Ok(item);
Ok(item) => return Ok(item),
Err(e) => {
eprint!("Failed to convert video from DB result: {}\n", e);
} }
eprint!("Ignoring stale hentaihaven DB cache entry without playable formats\n");
if let Ok(mut conn) = pool.get() {
let _ = db::delete_video(&mut conn, video_url.clone());
} }
} }
Ok(None) => { Ok(None) => {
@@ -530,6 +542,49 @@ impl HentaihavenProvider {
} }
} }
#[cfg(test)]
mod tests {
use super::HentaihavenProvider;
use crate::videos::{VideoFormat, VideoItem};
#[test]
fn accepts_cached_items_with_playable_formats() {
let cached = serde_json::to_string(
&VideoItem::new(
"id".to_string(),
"title".to_string(),
"https://hentaihaven.xxx/video/test/".to_string(),
"hentaihaven".to_string(),
"https://example.com/thumb.jpg".to_string(),
0,
)
.formats(vec![VideoFormat::new(
"https://cdn.example/master.m3u8".to_string(),
"1080p".to_string(),
"m3u8".to_string(),
)]),
)
.expect("serializes");
assert!(HentaihavenProvider::decode_cached_video(&cached).is_some());
}
#[test]
fn rejects_cached_items_without_formats() {
let cached = serde_json::to_string(&VideoItem::new(
"id".to_string(),
"title".to_string(),
"https://hentaihaven.xxx/video/test/".to_string(),
"hentaihaven".to_string(),
"https://example.com/thumb.jpg".to_string(),
0,
))
.expect("serializes");
assert!(HentaihavenProvider::decode_cached_video(&cached).is_none());
}
}
#[async_trait] #[async_trait]
impl Provider for HentaihavenProvider { impl Provider for HentaihavenProvider {
async fn get_videos( async fn get_videos(