url_preview/
preview_generator.rs1use crate::fetcher::FetchResult;
2#[cfg(feature = "cache")]
3use crate::Cache;
4use crate::{Fetcher, MetadataExtractor, Preview, PreviewError, PreviewGenerator};
5use async_trait::async_trait;
6use url::Url;
7
8#[derive(Clone, Copy, Default)]
9pub enum CacheStrategy {
10 #[default]
11 UseCache,
12 NoCache,
13 ForceUpdate,
14}
15
16#[derive(Clone)]
17pub struct UrlPreviewGenerator {
18 #[cfg(feature = "cache")]
19 pub cache: Cache,
20 pub cache_strategy: CacheStrategy,
21 pub fetcher: Fetcher,
22 extractor: MetadataExtractor,
23}
24
25impl UrlPreviewGenerator {
26 pub fn new(
27 #[allow(unused_variables)] cache_capacity: usize,
28 cache_strategy: CacheStrategy,
29 ) -> Self {
30 Self {
31 #[cfg(feature = "cache")]
32 cache: Cache::new(cache_capacity),
33 cache_strategy,
34 fetcher: Fetcher::new(),
35 extractor: MetadataExtractor::new(),
36 }
37 }
38
39 pub fn new_with_fetcher(
40 #[allow(unused_variables)] cache_capacity: usize,
41 cache_strategy: CacheStrategy,
42 fetcher: Fetcher,
43 ) -> Self {
44 Self {
45 #[cfg(feature = "cache")]
46 cache: Cache::new(cache_capacity),
47 cache_strategy,
48 fetcher,
49 extractor: MetadataExtractor::new(),
50 }
51 }
52}
53
54#[async_trait]
56impl PreviewGenerator for UrlPreviewGenerator {
57 async fn generate_preview(&self, url: &str) -> Result<Preview, PreviewError> {
58 #[cfg(feature = "cache")]
59 if let CacheStrategy::UseCache = self.cache_strategy {
60 if let Some(cached) = self.cache.get(url).await {
61 return Ok(cached);
62 };
63 };
64
65 let _ = Url::parse(url)?;
66 let content = self.fetcher.fetch(url).await?;
67
68 let mut preview = match content {
69 FetchResult::OEmbed(oembed) => self
70 .extractor
71 .extract_from_oembed(&oembed.html)
72 .ok_or_else(|| {
73 PreviewError::ExtractError("Failed to extract from oEmbed".into())
74 })?,
75 FetchResult::Html(html) => self.extractor.extract(&html, url)?,
76 };
77 preview.url = url.to_string();
78 #[cfg(feature = "cache")]
79 if let CacheStrategy::UseCache = self.cache_strategy {
80 self.cache.set(url.to_string(), preview.clone()).await;
81 };
82 Ok(preview)
83 }
84}