From c57a48db8a5a3a7837d705c4f35aaf2df2207252 Mon Sep 17 00:00:00 2001 From: asonix Date: Sun, 25 Sep 2022 17:36:07 -0500 Subject: [PATCH] Start introducing more video controls --- src/config/commandline.rs | 16 +++++++++++++++- src/config/defaults.rs | 4 ++++ src/config/file.rs | 4 ++++ src/details.rs | 6 +++++- src/error.rs | 3 +++ src/magick.rs | 14 ++++++++++++++ 6 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/config/commandline.rs b/src/config/commandline.rs index 1b017be..bdf752c 100644 --- a/src/config/commandline.rs +++ b/src/config/commandline.rs @@ -51,7 +51,9 @@ impl Args { media_max_height, media_max_area, media_max_file_size, + media_max_frame_count, media_enable_silent_video, + media_enable_full_video, media_filters, media_format, media_cache_duration, @@ -69,7 +71,9 @@ impl Args { max_height: media_max_height, max_area: media_max_area, max_file_size: media_max_file_size, + max_frame_count: media_max_frame_count, enable_silent_video: media_enable_silent_video, + enable_full_video: media_enable_full_video, filters: media_filters, format: media_format, cache_duration: media_cache_duration, @@ -312,8 +316,12 @@ struct Media { #[serde(skip_serializing_if = "Option::is_none")] max_file_size: Option, #[serde(skip_serializing_if = "Option::is_none")] + max_frame_count: Option, + #[serde(skip_serializing_if = "Option::is_none")] enable_silent_video: Option, #[serde(skip_serializing_if = "Option::is_none")] + enable_full_video: Option, + #[serde(skip_serializing_if = "Option::is_none")] filters: Option>, #[serde(skip_serializing_if = "Option::is_none")] format: Option, @@ -412,9 +420,15 @@ struct Run { /// The maximum size, in megabytes, for uploaded media #[clap(long)] media_max_file_size: Option, - /// Whether to enable GIF and silent MP4 uploads. Full videos are unsupported + /// The maximum number of frames allowed for uploaded GIF and MP4s. + #[clap(long)] + media_max_frame_count: Option, + /// Whether to enable GIF and silent MP4 uploads #[clap(long)] media_enable_silent_video: Option, + /// Whether to enable full MP4 uploads + #[clap(long)] + media_enable_full_video: Option, /// Which media filters should be enabled on the `process` endpoint #[clap(long)] media_filters: Option>, diff --git a/src/config/defaults.rs b/src/config/defaults.rs index 9cf4180..fce6f28 100644 --- a/src/config/defaults.rs +++ b/src/config/defaults.rs @@ -65,7 +65,9 @@ struct MediaDefaults { max_height: usize, max_area: usize, max_file_size: usize, + max_frame_count: usize, enable_silent_video: bool, + enable_full_video: bool, filters: Vec, skip_validate_imports: bool, cache_duration: i64, @@ -150,7 +152,9 @@ impl Default for MediaDefaults { max_height: 10_000, max_area: 40_000_000, max_file_size: 40, + max_frame_count: 3_600, enable_silent_video: true, + enable_full_video: false, filters: vec![ "blur".into(), "crop".into(), diff --git a/src/config/file.rs b/src/config/file.rs index 0c3c8fb..9a43206 100644 --- a/src/config/file.rs +++ b/src/config/file.rs @@ -98,8 +98,12 @@ pub(crate) struct Media { pub(crate) max_file_size: usize, + pub(crate) max_frame_count: usize, + pub(crate) enable_silent_video: bool, + pub(crate) enable_full_video: bool, + pub(crate) filters: BTreeSet, #[serde(skip_serializing_if = "Option::is_none")] diff --git a/src/details.rs b/src/details.rs index 1fc5e27..d4ab6e1 100644 --- a/src/details.rs +++ b/src/details.rs @@ -12,6 +12,7 @@ enum MaybeHumanDate { pub(crate) struct Details { width: usize, height: usize, + frames: Option, content_type: Serde, created_at: MaybeHumanDate, } @@ -33,6 +34,7 @@ impl Details { details.width, details.height, details.mime_type, + details.frames, )) } @@ -48,13 +50,15 @@ impl Details { details.width, details.height, details.mime_type, + details.frames, )) } - pub(crate) fn now(width: usize, height: usize, content_type: mime::Mime) -> Self { + pub(crate) fn now(width: usize, height: usize, content_type: mime::Mime, frames: Option) -> Self { Details { width, height, + frames, content_type: Serde::new(content_type), created_at: MaybeHumanDate::HumanDate(time::OffsetDateTime::now_utc()), } diff --git a/src/error.rs b/src/error.rs index fe1bfd2..4c2fa1c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -99,6 +99,9 @@ pub(crate) enum UploadError { #[error("Invalid media dimensions")] Dimensions, + #[error("Too many frames")] + Frames, + #[error("Unable to download image, bad response {0}")] Download(actix_web::http::StatusCode), diff --git a/src/magick.rs b/src/magick.rs index 29a6a57..afb77b8 100644 --- a/src/magick.rs +++ b/src/magick.rs @@ -86,6 +86,7 @@ pub(crate) struct Details { pub(crate) mime_type: mime::Mime, pub(crate) width: usize, pub(crate) height: usize, + pub(crate) frames: Option, } #[tracing::instrument(name = "Clear Metadata", skip(input))] @@ -210,6 +211,8 @@ pub(crate) async fn details_file(path_str: &str) -> Result { } fn parse_details(s: std::borrow::Cow<'_, str>) -> Result { + let frames = s.lines().count(); + let mut lines = s.lines(); let first = lines.next().ok_or(UploadError::UnsupportedFormat)?; @@ -257,6 +260,11 @@ fn parse_details(s: std::borrow::Cow<'_, str>) -> Result { mime_type, width, height, + frames: if frames > 1 { + Some(frames) + } else { + None + }, }) } @@ -307,6 +315,12 @@ impl Details { return Err(UploadError::Dimensions.into()); } + if let Some(frames) = self.frames { + if frames > crate::CONFIG.media.max_frame_count { + return Err(UploadError::Frames.into()); + } + } + let input_type = match (self.mime_type.type_(), self.mime_type.subtype()) { (mime::VIDEO, mime::MP4 | mime::MPEG) => ValidInputType::Mp4, (mime::IMAGE, mime::GIF) => ValidInputType::Gif,