pict-rs/src/details.rs

128 lines
3.5 KiB
Rust
Raw Normal View History

use crate::{
error::Error,
ffmpeg::InputFormat,
magick::{video_mp4, video_webm, ValidInputType},
serde_str::Serde,
store::Store,
};
2022-03-24 22:09:15 +00:00
use actix_web::web;
#[derive(Copy, Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(untagged)]
enum MaybeHumanDate {
HumanDate(#[serde(with = "time::serde::rfc3339")] time::OffsetDateTime),
OldDate(#[serde(serialize_with = "time::serde::rfc3339::serialize")] time::OffsetDateTime),
}
2022-03-24 22:09:15 +00:00
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub(crate) struct Details {
width: usize,
height: usize,
2022-09-25 22:36:07 +00:00
frames: Option<usize>,
2022-03-24 22:09:15 +00:00
content_type: Serde<mime::Mime>,
created_at: MaybeHumanDate,
2022-03-24 22:09:15 +00:00
}
impl Details {
pub(crate) fn is_motion(&self) -> bool {
self.content_type.type_() == "video"
|| self.content_type.type_() == "image" && self.content_type.subtype() == "gif"
}
#[tracing::instrument("Details from bytes", skip(input))]
pub(crate) async fn from_bytes(input: web::Bytes, hint: ValidInputType) -> Result<Self, Error> {
let details = if hint.is_video() {
crate::ffmpeg::details_bytes(input.clone()).await?
} else {
None
};
let details = if let Some(details) = details {
details
} else {
crate::magick::details_bytes(input, Some(hint)).await?
};
2022-03-24 22:09:15 +00:00
Ok(Details::now(
details.width,
details.height,
details.mime_type,
2022-09-25 22:36:07 +00:00
details.frames,
2022-03-24 22:09:15 +00:00
))
}
#[tracing::instrument("Details from store")]
pub(crate) async fn from_store<S: Store + 'static>(
2022-03-24 22:09:15 +00:00
store: S,
identifier: S::Identifier,
expected_format: Option<ValidInputType>,
) -> Result<Self, Error> {
let details = if expected_format.map(|t| t.is_video()).unwrap_or(true) {
crate::ffmpeg::details_store(&store, &identifier).await?
} else {
None
};
let details = if let Some(details) = details {
details
} else {
crate::magick::details_store(store, identifier, expected_format).await?
};
2022-03-24 22:09:15 +00:00
Ok(Details::now(
details.width,
details.height,
details.mime_type,
2022-09-25 22:36:07 +00:00
details.frames,
2022-03-24 22:09:15 +00:00
))
}
pub(crate) fn now(
width: usize,
height: usize,
content_type: mime::Mime,
frames: Option<usize>,
) -> Self {
2022-03-24 22:09:15 +00:00
Details {
width,
height,
2022-09-25 22:36:07 +00:00
frames,
2022-03-24 22:09:15 +00:00
content_type: Serde::new(content_type),
created_at: MaybeHumanDate::HumanDate(time::OffsetDateTime::now_utc()),
2022-03-24 22:09:15 +00:00
}
}
pub(crate) fn content_type(&self) -> mime::Mime {
(*self.content_type).clone()
}
pub(crate) fn system_time(&self) -> std::time::SystemTime {
self.created_at.into()
}
pub(crate) fn to_input_format(&self) -> Option<InputFormat> {
if *self.content_type == mime::IMAGE_GIF {
return Some(InputFormat::Gif);
}
if *self.content_type == video_mp4() {
return Some(InputFormat::Mp4);
}
if *self.content_type == video_webm() {
return Some(InputFormat::Webm);
}
None
}
2022-03-24 22:09:15 +00:00
}
impl From<MaybeHumanDate> for std::time::SystemTime {
fn from(this: MaybeHumanDate) -> Self {
match this {
MaybeHumanDate::OldDate(old) => old.into(),
MaybeHumanDate::HumanDate(human) => human.into(),
}
}
}