feat: Detect animation in image files for fetch_preview (#574)

* Implement animated metadata TODOs for database and thumbnailing.

Signed-off-by: Assisting <erik@eriklabine.com>

* Run linter for code changes

Signed-off-by: Assisting <erik@eriklabine.com>

---------

Signed-off-by: Assisting <erik@eriklabine.com>
This commit is contained in:
Erik LaBine
2026-03-23 01:07:22 -04:00
committed by GitHub
parent 5191bd16b2
commit 3fa0abf47f
9 changed files with 149 additions and 12 deletions

View File

@@ -380,7 +380,7 @@ async fn fetch_preview(
let hash = file.as_hash(&db).await?;
let is_animated = hash.content_type == "image/gif"; // TODO: extract this data from files
let is_animated = matches!(hash.metadata, Metadata::Image { animated: true, .. });
// Only process image files and don't process GIFs if not avatar or icon
if !matches!(hash.metadata, Metadata::Image { .. })

View File

@@ -16,7 +16,11 @@ pub async fn strip_metadata(
mime: &str,
) -> Result<(Vec<u8>, Metadata)> {
match &metadata {
Metadata::Image { width, height } => match mime {
Metadata::Image {
width,
height,
animated,
} => match mime {
// // little_exif does not appear to parse JPEGs correctly? had 2/2 files fail
// "image/jpeg" | "image/png" => {
// // use little_exif to strip metadata except for orientation and colour profile
@@ -93,7 +97,14 @@ pub async fn strip_metadata(
_ => (*width, *height),
};
Ok((bytes, Metadata::Image { width, height }))
Ok((
bytes,
Metadata::Image {
width,
height,
animated: *animated,
},
))
}
// JXLs store EXIF data but we don't have the ability to write them
"image/jxl" => Ok((buf, metadata)),

View File

@@ -1,7 +1,7 @@
use std::io::Cursor;
use revolt_database::Metadata;
use revolt_files::{image_size, video_size};
use revolt_files::{image_size, is_animated, video_size};
use tempfile::NamedTempFile;
/// Intersection of what infer can detect and what image-rs supports
@@ -26,6 +26,7 @@ pub fn generate_metadata(f: &NamedTempFile, mime_type: &str) -> Metadata {
.map(|(width, height)| Metadata::Image {
width: width as isize,
height: height as isize,
animated: is_animated(f, mime_type).unwrap_or(false),
})
.unwrap_or_default()
} else if mime_type.starts_with("video/") {