#[cfg(any(feature = "images", feature = "documents"))]
use mimetype_detector::detect;
#[cfg(any(feature = "images", feature = "documents"))]
fn get_mime_from_extension(ext: &str) -> Option<&'static str> {
match ext.to_lowercase().as_str() {
"jpg" | "jpeg" => Some("image/jpeg"),
"png" => Some("image/png"),
"gif" => Some("image/gif"),
"webp" => Some("image/webp"),
"svg" => Some("image/svg+xml"),
"ico" => Some("image/x-icon"),
"bmp" => Some("image/bmp"),
"tiff" | "tif" => Some("image/tiff"),
"pdf" => Some("application/pdf"),
"doc" => Some("application/msword"),
"docx" => Some("application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
"xls" => Some("application/vnd.ms-excel"),
"xlsx" => Some("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
"ppt" => Some("application/vnd.ms-powerpoint"),
"pptx" => Some("application/vnd.openxmlformats-officedocument.presentationml.presentation"),
"csv" => Some("text/csv"),
"odt" => Some("application/vnd.oasis.opendocument.text"),
"ods" => Some("application/vnd.oasis.opendocument.spreadsheet"),
"odp" => Some("application/vnd.oasis.opendocument.presentation"),
"epub" => Some("application/epub+zip"),
"rtf" => Some("application/rtf"),
"txt" => Some("text/plain"),
"json" => Some("application/json"),
"xml" => Some("application/xml"),
_ => None,
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AssetType {
Image,
Document,
Unknown,
}
impl AssetType {
pub fn is_image(&self) -> bool {
matches!(self, AssetType::Image)
}
pub fn is_document(&self) -> bool {
matches!(self, AssetType::Document)
}
}
#[allow(dead_code)]
const IMAGE_MIMES: &[&str] = &[
"image/jpeg",
"image/png",
"image/gif",
"image/webp",
"image/svg+xml",
"image/bmp",
"image/tiff",
"image/x-icon",
];
#[allow(dead_code)]
const DOCUMENT_MIMES: &[&str] = &[
"application/pdf",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"text/csv",
"application/vnd.oasis.opendocument.text",
"application/vnd.oasis.opendocument.spreadsheet",
"application/epub+zip",
"application/rtf",
"application/json",
"application/xml",
"text/xml",
];
const IMAGE_EXTENSIONS: &[&str] = &[
"jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico", "tiff", "tif",
];
const DOCUMENT_EXTENSIONS: &[&str] = &[
"pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "csv", "odt", "ods", "odp", "epub", "rtf",
"json", "xml",
];
#[cfg(any(feature = "images", feature = "documents"))]
pub fn detect_from_url(url: &str) -> AssetType {
if let Ok(parsed) = url::Url::parse(url) {
let path = parsed.path();
return detect_from_path(path);
}
AssetType::Unknown
}
#[cfg(not(any(feature = "images", feature = "documents")))]
pub fn detect_from_url(url: &str) -> AssetType {
if let Ok(parsed) = url::Url::parse(url) {
let path = parsed.path();
return detect_from_path(path);
}
AssetType::Unknown
}
pub fn detect_from_path(path: &str) -> AssetType {
let extension = path
.rsplit('.')
.next()
.map(|e| e.to_lowercase())
.unwrap_or_default();
if IMAGE_EXTENSIONS.contains(&extension.as_str()) {
AssetType::Image
} else if DOCUMENT_EXTENSIONS.contains(&extension.as_str()) {
AssetType::Document
} else {
AssetType::Unknown
}
}
#[cfg(any(feature = "images", feature = "documents"))]
pub fn detect_from_bytes(data: &[u8]) -> AssetType {
if data.is_empty() {
return AssetType::Unknown;
}
let mime = detect(data);
if IMAGE_MIMES.contains(&mime.mime()) {
AssetType::Image
} else if DOCUMENT_MIMES.contains(&mime.mime()) {
AssetType::Document
} else {
AssetType::Unknown
}
}
#[cfg(not(any(feature = "images", feature = "documents")))]
pub fn detect_from_bytes(_data: &[u8]) -> AssetType {
AssetType::Unknown
}
pub fn is_image_url(url: &str) -> bool {
detect_from_url(url).is_image()
}
pub fn is_document_url(url: &str) -> bool {
detect_from_url(url).is_document()
}
pub fn is_asset_url(url: &str) -> bool {
let asset_type = detect_from_url(url);
asset_type.is_image() || asset_type.is_document()
}
pub fn get_extension(url: &str) -> Option<String> {
url::Url::parse(url)
.ok()
.and_then(|parsed| parsed.path().rsplit('.').next().map(|e| e.to_lowercase()))
}
#[cfg(not(any(feature = "images", feature = "documents")))]
pub fn get_mime_type(url: &str) -> Option<&'static str> {
let ext = get_extension(url)?;
match ext.as_str() {
"jpg" | "jpeg" => Some("image/jpeg"),
"png" => Some("image/png"),
"gif" => Some("image/gif"),
"webp" => Some("image/webp"),
"svg" => Some("image/svg+xml"),
"pdf" => Some("application/pdf"),
"doc" => Some("application/msword"),
"docx" => Some("application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
"xls" => Some("application/vnd.ms-excel"),
"xlsx" => Some("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
"csv" => Some("text/csv"),
"json" => Some("application/json"),
"xml" => Some("application/xml"),
_ => None,
}
}
#[cfg(any(feature = "images", feature = "documents"))]
pub fn get_mime_type(url: &str) -> Option<&'static str> {
let ext = get_extension(url)?;
get_mime_from_extension(&ext)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_detect_image_from_url() {
assert!(is_image_url("https://example.com/image.png"));
assert!(is_image_url("https://example.com/photo.jpg"));
assert!(is_image_url("https://example.com/diagram.webp"));
}
#[test]
fn test_detect_document_from_url() {
assert!(is_document_url("https://example.com/document.pdf"));
assert!(is_document_url("https://example.com/report.docx"));
assert!(is_document_url("https://example.com/data.xlsx"));
}
#[test]
fn test_is_asset_url() {
assert!(is_asset_url("https://example.com/image.png"));
assert!(is_asset_url("https://example.com/doc.pdf"));
assert!(!is_asset_url("https://example.com/page.html"));
}
#[test]
fn test_get_extension() {
assert_eq!(
get_extension("https://example.com/file.png"),
Some("png".to_string())
);
assert_eq!(
get_extension("https://example.com/archive.tar.gz"),
Some("gz".to_string())
);
}
#[test]
fn test_get_mime_type() {
assert_eq!(
get_mime_type("https://example.com/file.png"),
Some("image/png")
);
assert_eq!(
get_mime_type("https://example.com/file.pdf"),
Some("application/pdf")
);
}
}