url_preview/
preview_generator.rs1use crate::fetcher::FetchResult;
2use crate::{Cache, Fetcher, MetadataExtractor, Preview, PreviewError, PreviewGenerator};
3use async_trait::async_trait;
4use url::Url;
5
6#[derive(Clone)]
7pub struct UrlPreviewGenerator {
8 pub cache: Cache,
9 pub fetcher: Fetcher,
10 extractor: MetadataExtractor,
11}
12
13impl UrlPreviewGenerator {
14 pub fn new(cache_capacity: usize) -> Self {
15 Self {
16 cache: Cache::new(cache_capacity),
17 fetcher: Fetcher::new(),
18 extractor: MetadataExtractor::new(),
19 }
20 }
21
22 pub fn new_with_fetcher(cache_capacity: usize, fetcher: Fetcher) -> Self {
23 Self {
24 cache: Cache::new(cache_capacity),
25 fetcher,
26 extractor: MetadataExtractor::new(),
27 }
28 }
29}
30
31#[async_trait]
33impl PreviewGenerator for UrlPreviewGenerator {
34 async fn generate_preview(&self, url: &str) -> Result<Preview, PreviewError> {
35 if let Some(cached) = self.cache.get(url).await {
37 return Ok(cached);
38 }
39
40 let _ = Url::parse(url)?;
41 let content = self.fetcher.fetch(url).await?;
42
43 let mut preview = match content {
44 FetchResult::OEmbed(oembed) => self
45 .extractor
46 .extract_from_oembed(&oembed.html)
47 .ok_or_else(|| {
48 PreviewError::ExtractError("Failed to extract from oEmbed".into())
49 })?,
50 FetchResult::Html(html) => self.extractor.extract(&html, url)?,
51 };
52 preview.url = url.to_string();
53 self.cache.set(url.to_string(), preview.clone()).await;
54 Ok(preview)
55 }
56}