url_preview/lib.rs
1//! # url-preview
2//!
3//! A high-performance Rust library for generating rich URL previews with specialized support
4//! for Twitter/X and GitHub.
5//!
6//! ## Features
7//!
8//! - **High Performance**: Optimized with concurrent processing and smart caching
9//! - **Platform Support**: Specialized handlers for Twitter/X and GitHub
10//! - **Rich Metadata**: Extract titles, descriptions, images, and more
11//! - **Error Handling**: Detailed error types for better debugging
12//! - **Flexible Configuration**: Customize timeouts, user agents, and caching
13//!
14//! ## Quick Start
15//!
16//! ```rust,no_run
17//! use url_preview::{PreviewService, PreviewError};
18//!
19//! #[tokio::main]
20//! async fn main() -> Result<(), PreviewError> {
21//! let service = PreviewService::new();
22//! let preview = service.generate_preview("https://www.rust-lang.org").await?;
23//!
24//! println!("Title: {:?}", preview.title);
25//! println!("Description: {:?}", preview.description);
26//! Ok(())
27//! }
28//! ```
29//!
30//! ## Error Handling (New in v0.4.0)
31//!
32//! The library now provides specific error types:
33//!
34//! ```rust,no_run
35//! use url_preview::{PreviewService, PreviewError};
36//!
37//! # async fn example() {
38//! let service = PreviewService::new();
39//! match service.generate_preview("https://invalid.url").await {
40//! Ok(preview) => { /* handle preview */ },
41//! Err(PreviewError::NotFound(msg)) => println!("404: {}", msg),
42//! Err(PreviewError::DnsError(msg)) => println!("DNS failed: {}", msg),
43//! Err(PreviewError::TimeoutError(msg)) => println!("Timeout: {}", msg),
44//! Err(PreviewError::ServerError { status, message }) => {
45//! println!("Server error {}: {}", status, message)
46//! },
47//! Err(e) => println!("Other error: {}", e),
48//! }
49//! # }
50//! ```
51
52use async_trait::async_trait;
53
54#[cfg(feature = "cache")]
55mod cache;
56mod error;
57mod extractor;
58mod fetcher;
59#[cfg(feature = "github")]
60mod github_types;
61#[cfg(feature = "logging")]
62mod logging;
63mod preview_generator;
64mod preview_service;
65mod utils;
66
67#[cfg(feature = "cache")]
68pub use cache::Cache;
69pub use error::PreviewError;
70pub use extractor::MetadataExtractor;
71pub use fetcher::{FetchResult, Fetcher, FetcherConfig};
72#[cfg(feature = "github")]
73pub use github_types::{is_github_url, GitHubBasicPreview, GitHubDetailedInfo, GitHubRepository};
74#[cfg(feature = "logging")]
75pub use logging::{log_error_card, log_preview_card, setup_logging, LogConfig, LogLevelGuard};
76pub use preview_generator::{CacheStrategy, UrlPreviewGenerator};
77pub use preview_service::{PreviewService, PreviewServiceConfig, MAX_CONCURRENT_REQUESTS};
78
79#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
80pub struct Preview {
81 pub url: String,
82 pub title: Option<String>,
83 pub description: Option<String>,
84 pub image_url: Option<String>,
85 pub favicon: Option<String>,
86 pub site_name: Option<String>,
87}
88
89#[async_trait]
90pub trait PreviewGenerator {
91 async fn generate_preview(&self, url: &str) -> Result<Preview, PreviewError>;
92}
93
94#[cfg(feature = "twitter")]
95pub fn is_twitter_url(url: &str) -> bool {
96 url.contains("twitter.com") || url.contains("x.com")
97}
98
99#[cfg(not(feature = "twitter"))]
100pub fn is_twitter_url(_url: &str) -> bool {
101 false
102}