use feed_rs::model::Entry; use feed_rs::parser; use reqwest::blocking::get; use scraper::{Html, Selector}; use std::error::Error; pub fn fetch_feed(url: &str) -> Result, Box> { let content = get(url)?.text()?; let feed = parser::parse(content.as_bytes())?; if feed.entries.is_empty() { log::warn!("Feed {url} returned no items!"); } else { log::info!("Feed {} returned {} items", url, feed.entries.len()); } Ok(feed.entries) } pub fn fetch_social_image(url: String) -> Result> { let html = reqwest::blocking::get(url)?.text()?; let document = Html::parse_document(&html); let selector = Selector::parse("meta[property=\"og:image\"]").unwrap(); let image_url = document .select(&selector) .next() .and_then(|element| element.value().attr("content")); if let Some(url) = image_url { Ok(url.to_string()) } else { Err("No social image found".into()) } } pub fn is_valid_image_url(url: &str) -> Result> { let client = reqwest::blocking::Client::new(); let response = client.head(url).send()?; let status = response.status(); let content_type = response.headers().get(reqwest::header::CONTENT_TYPE); Ok(status.is_success() && content_type.is_some_and(|ct| ct.to_str().is_ok_and(|s| s.starts_with("image/")))) } pub fn is_valid_url(url: &str) -> bool { let client = reqwest::blocking::Client::new(); client.get(url).send().is_ok() }