Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18888eae5f | ||
|
|
f31020fb6e | ||
|
|
bb202079e0 |
@@ -167,7 +167,7 @@ pub fn decode_image<R: Read + BufRead + Seek>(reader: &mut R, mime: &str) -> Res
|
|||||||
jxl_image.height(),
|
jxl_image.height(),
|
||||||
frame.image().buf().to_vec(),
|
frame.image().buf().to_vec(),
|
||||||
)
|
)
|
||||||
.ok_or_else(|| create_error!(LabelMe))?,
|
.ok_or_else(|| create_error!(ImageProcessingFailed))?,
|
||||||
)
|
)
|
||||||
.to_rgb8(),
|
.to_rgb8(),
|
||||||
)),
|
)),
|
||||||
@@ -178,14 +178,14 @@ pub fn decode_image<R: Read + BufRead + Seek>(reader: &mut R, mime: &str) -> Res
|
|||||||
jxl_image.height(),
|
jxl_image.height(),
|
||||||
frame.image().buf().to_vec(),
|
frame.image().buf().to_vec(),
|
||||||
)
|
)
|
||||||
.ok_or_else(|| create_error!(LabelMe))?,
|
.ok_or_else(|| create_error!(ImageProcessingFailed))?,
|
||||||
)
|
)
|
||||||
.to_rgba8(),
|
.to_rgba8(),
|
||||||
)),
|
)),
|
||||||
_ => Err(create_error!(LabelMe)),
|
_ => Err(create_error!(ImageProcessingFailed)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(create_error!(LabelMe))
|
Err(create_error!(ImageProcessingFailed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Read image using resvg
|
// Read image using resvg
|
||||||
@@ -197,7 +197,7 @@ pub fn decode_image<R: Read + BufRead + Seek>(reader: &mut R, mime: &str) -> Res
|
|||||||
let tree = report_internal_error!(usvg::Tree::from_data(&buf, &Default::default()))?;
|
let tree = report_internal_error!(usvg::Tree::from_data(&buf, &Default::default()))?;
|
||||||
let size = tree.size();
|
let size = tree.size();
|
||||||
let mut pixmap = Pixmap::new(size.width() as u32, size.height() as u32)
|
let mut pixmap = Pixmap::new(size.width() as u32, size.height() as u32)
|
||||||
.ok_or_else(|| create_error!(LabelMe))?;
|
.ok_or_else(|| create_error!(ImageProcessingFailed))?;
|
||||||
|
|
||||||
let mut pixmap_mut = pixmap.as_mut();
|
let mut pixmap_mut = pixmap.as_mut();
|
||||||
resvg::render(&tree, Default::default(), &mut pixmap_mut);
|
resvg::render(&tree, Default::default(), &mut pixmap_mut);
|
||||||
@@ -208,7 +208,7 @@ pub fn decode_image<R: Read + BufRead + Seek>(reader: &mut R, mime: &str) -> Res
|
|||||||
size.height() as u32,
|
size.height() as u32,
|
||||||
pixmap.data().to_vec(),
|
pixmap.data().to_vec(),
|
||||||
)
|
)
|
||||||
.ok_or_else(|| create_error!(LabelMe))?,
|
.ok_or_else(|| create_error!(ImageProcessingFailed))?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
// Check if we can read using image-rs crate
|
// Check if we can read using image-rs crate
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use axum::{http::StatusCode, response::IntoResponse, Json};
|
use axum::{http::StatusCode, response::IntoResponse, Json};
|
||||||
|
use rocket::http::Status;
|
||||||
|
|
||||||
use crate::{Error, ErrorType};
|
use crate::{Error, ErrorType};
|
||||||
|
|
||||||
@@ -78,6 +79,7 @@ impl IntoResponse for Error {
|
|||||||
ErrorType::FileTooSmall => StatusCode::UNPROCESSABLE_ENTITY,
|
ErrorType::FileTooSmall => StatusCode::UNPROCESSABLE_ENTITY,
|
||||||
ErrorType::FileTooLarge { .. } => StatusCode::UNPROCESSABLE_ENTITY,
|
ErrorType::FileTooLarge { .. } => StatusCode::UNPROCESSABLE_ENTITY,
|
||||||
ErrorType::FileTypeNotAllowed => StatusCode::BAD_REQUEST,
|
ErrorType::FileTypeNotAllowed => StatusCode::BAD_REQUEST,
|
||||||
|
ErrorType::ImageProcessingFailed => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
(status, Json(&self)).into_response()
|
(status, Json(&self)).into_response()
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ pub enum ErrorType {
|
|||||||
max: usize,
|
max: usize,
|
||||||
},
|
},
|
||||||
FileTypeNotAllowed,
|
FileTypeNotAllowed,
|
||||||
|
ImageProcessingFailed,
|
||||||
|
|
||||||
// ? Legacy errors
|
// ? Legacy errors
|
||||||
VosoUnavailable,
|
VosoUnavailable,
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ impl<'r> Responder<'r, 'static> for Error {
|
|||||||
ErrorType::FileTooSmall => Status::UnprocessableEntity,
|
ErrorType::FileTooSmall => Status::UnprocessableEntity,
|
||||||
ErrorType::FileTooLarge { .. } => Status::UnprocessableEntity,
|
ErrorType::FileTooLarge { .. } => Status::UnprocessableEntity,
|
||||||
ErrorType::FileTypeNotAllowed => Status::BadRequest,
|
ErrorType::FileTypeNotAllowed => Status::BadRequest,
|
||||||
|
ErrorType::ImageProcessingFailed => Status::InternalServerError,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Serialize the error data structure into JSON.
|
// Serialize the error data structure into JSON.
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ impl Request {
|
|||||||
let Request { response, mime } = Request::new(url).await?;
|
let Request { response, mime } = Request::new(url).await?;
|
||||||
|
|
||||||
if matches!(mime.type_(), mime::IMAGE | mime::VIDEO) {
|
if matches!(mime.type_(), mime::IMAGE | mime::VIDEO) {
|
||||||
let bytes = response.bytes().await.map_err(|_| create_error!(LabelMe));
|
let bytes = report_internal_error!(response.bytes().await)?;
|
||||||
|
|
||||||
let result = match bytes {
|
let result = match bytes {
|
||||||
Ok(bytes) => {
|
Ok(bytes) => {
|
||||||
@@ -77,7 +77,7 @@ impl Request {
|
|||||||
if is_valid_image(reader, "image/gif") {
|
if is_valid_image(reader, "image/gif") {
|
||||||
Ok(("image/gif".to_owned(), bytes.to_vec()))
|
Ok(("image/gif".to_owned(), bytes.to_vec()))
|
||||||
} else {
|
} else {
|
||||||
Err(create_error!(LabelMe))
|
Err(create_error!(FileTypeNotAllowed))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok((
|
Ok((
|
||||||
@@ -96,7 +96,7 @@ impl Request {
|
|||||||
if video_size(&file).is_some() {
|
if video_size(&file).is_some() {
|
||||||
Ok((mime.to_string(), bytes.to_vec()))
|
Ok((mime.to_string(), bytes.to_vec()))
|
||||||
} else {
|
} else {
|
||||||
Err(create_error!(LabelMe))
|
Err(create_error!(FileTypeNotAllowed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ impl Request {
|
|||||||
PROXY_CACHE.insert(url.to_owned(), result.clone()).await;
|
PROXY_CACHE.insert(url.to_owned(), result.clone()).await;
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
Err(create_error!(LabelMe))
|
Err(create_error!(FileTypeNotAllowed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ impl Request {
|
|||||||
if matches!(mime.type_(), mime::IMAGE) {
|
if matches!(mime.type_(), mime::IMAGE) {
|
||||||
response
|
response
|
||||||
} else {
|
} else {
|
||||||
return Err(create_error!(LabelMe));
|
return Err(create_error!(FileTypeNotAllowed));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ impl Request {
|
|||||||
if matches!(mime.type_(), mime::VIDEO) {
|
if matches!(mime.type_(), mime::VIDEO) {
|
||||||
response
|
response
|
||||||
} else {
|
} else {
|
||||||
return Err(create_error!(LabelMe));
|
return Err(create_error!(FileTypeNotAllowed));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,34 +9,38 @@ use scraper::{Html, Selector};
|
|||||||
|
|
||||||
/// Create website metadata from URL and document
|
/// Create website metadata from URL and document
|
||||||
pub async fn create_website_embed(original_url: &str, document: &str) -> Option<WebsiteMetadata> {
|
pub async fn create_website_embed(original_url: &str, document: &str) -> Option<WebsiteMetadata> {
|
||||||
let document = Html::parse_document(document);
|
let (mut meta, mut link) = {
|
||||||
|
let document = Html::parse_document(document);
|
||||||
|
|
||||||
// create selectors
|
// create selectors
|
||||||
let meta_selector = Selector::parse("meta").ok()?;
|
let meta_selector = Selector::parse("meta").ok()?;
|
||||||
let link_selector = Selector::parse("link").ok()?;
|
let link_selector = Selector::parse("link").ok()?;
|
||||||
|
|
||||||
// extract meta tags
|
// extract meta tags
|
||||||
let mut meta = HashMap::new();
|
let mut meta = HashMap::new();
|
||||||
for el in document.select(&meta_selector) {
|
for el in document.select(&meta_selector) {
|
||||||
let node = el.value();
|
let node = el.value();
|
||||||
|
|
||||||
if let (Some(property), Some(content)) = (
|
if let (Some(property), Some(content)) = (
|
||||||
node.attr("property").or_else(|| node.attr("name")),
|
node.attr("property").or_else(|| node.attr("name")),
|
||||||
node.attr("content"),
|
node.attr("content"),
|
||||||
) {
|
) {
|
||||||
meta.insert(property.to_string(), content.to_string());
|
meta.insert(property.to_string(), content.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// extract rel links
|
// extract rel links
|
||||||
let mut link = HashMap::new();
|
let mut link = HashMap::new();
|
||||||
for el in document.select(&link_selector) {
|
for el in document.select(&link_selector) {
|
||||||
let node = el.value();
|
let node = el.value();
|
||||||
|
|
||||||
if let (Some(property), Some(content)) = (node.attr("rel"), node.attr("href")) {
|
if let (Some(property), Some(content)) = (node.attr("rel"), node.attr("href")) {
|
||||||
link.insert(property.to_string(), content.to_string());
|
link.insert(property.to_string(), content.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
(meta, link)
|
||||||
|
};
|
||||||
|
|
||||||
// build metadata
|
// build metadata
|
||||||
let mut metadata = WebsiteMetadata {
|
let mut metadata = WebsiteMetadata {
|
||||||
@@ -137,32 +141,36 @@ pub async fn create_website_embed(original_url: &str, document: &str) -> Option<
|
|||||||
};
|
};
|
||||||
|
|
||||||
// populate extra metadata for popular websites
|
// populate extra metadata for popular websites
|
||||||
populate_special(original_url.to_owned(), &mut metadata);
|
populate_special(original_url.to_owned(), &mut metadata).await;
|
||||||
|
|
||||||
// TODO: these do not work because compiler is tripping:
|
|
||||||
|
|
||||||
// fetch video size if missing
|
// fetch video size if missing
|
||||||
// if let Some(Video { width, height, url }) = &metadata.video {
|
if metadata.special.is_none() {
|
||||||
// if width == &0 || height == &0 {
|
if let Some(Video { width, height, url }) = &metadata.video {
|
||||||
// metadata.video = match crate::requests::Request::fetch_video_metadata(url, None).await {
|
if width == &0 || height == &0 {
|
||||||
// Ok(Some(video)) => Some(video),
|
metadata.video =
|
||||||
// _ => None,
|
match crate::requests::Request::fetch_video_metadata(url, None).await {
|
||||||
// }
|
Ok(Some(video)) => Some(video),
|
||||||
// }
|
_ => None,
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// fetch image size if missing
|
// fetch image size if missing
|
||||||
// if let Some(Image {
|
if metadata.special.is_none() && metadata.image.is_none() {
|
||||||
// width, height, url, ..
|
if let Some(Image {
|
||||||
// }) = &metadata.image
|
width, height, url, ..
|
||||||
// {
|
}) = &metadata.image
|
||||||
// if width == &0 || height == &0 {
|
{
|
||||||
// metadata.image = match crate::requests::Request::fetch_image_metadata(url, None).await {
|
if width == &0 || height == &0 {
|
||||||
// Ok(Some(image)) => Some(image),
|
metadata.image =
|
||||||
// _ => None,
|
match crate::requests::Request::fetch_image_metadata(url, None).await {
|
||||||
// }
|
Ok(Some(image)) => Some(image),
|
||||||
// }
|
_ => None,
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// truncate data
|
// truncate data
|
||||||
metadata.truncate();
|
metadata.truncate();
|
||||||
@@ -175,7 +183,7 @@ pub async fn create_website_embed(original_url: &str, document: &str) -> Option<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn populate_special(original_url: String, metadata: &mut WebsiteMetadata) {
|
pub async fn populate_special(original_url: String, metadata: &mut WebsiteMetadata) {
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref RE_YOUTUBE: Regex = Regex::new("^(?:(?:https?:)?//)?(?:(?:www|m)\\.)?(?:(?:youtube\\.com|youtu.be))(?:/(?:[\\w\\-]+\\?v=|embed/|v/)?)([\\w\\-]+)(?:\\S+)?$").unwrap();
|
static ref RE_YOUTUBE: Regex = Regex::new("^(?:(?:https?:)?//)?(?:(?:www|m)\\.)?(?:(?:youtube\\.com|youtu.be))(?:/(?:[\\w\\-]+\\?v=|embed/|v/)?)([\\w\\-]+)(?:\\S+)?$").unwrap();
|
||||||
|
|
||||||
@@ -223,15 +231,14 @@ pub fn populate_special(original_url: String, metadata: &mut WebsiteMetadata) {
|
|||||||
metadata.site_name.take();
|
metadata.site_name.take();
|
||||||
|
|
||||||
// Verify the video exists
|
// Verify the video exists
|
||||||
// TODO: breaks axum :(
|
if !crate::requests::Request::exists(&format!(
|
||||||
// if !crate::requests::Request::exists(&format!(
|
"http://img.youtube.com/vi/{}/sddefault.jpg",
|
||||||
// "http://img.youtube.com/vi/{}/sddefault.jpg",
|
id
|
||||||
// id
|
))
|
||||||
// ))
|
.await
|
||||||
// .await
|
{
|
||||||
// {
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(timestamp_captures) = RE_TIMESTAMP.captures_iter(url).next() {
|
if let Some(timestamp_captures) = RE_TIMESTAMP.captures_iter(url).next() {
|
||||||
|
|||||||
Reference in New Issue
Block a user