mirror of
https://git.asonix.dog/asonix/pict-rs
synced 2024-12-22 19:31:35 +00:00
Better identify video uploads with ffprobe
This commit is contained in:
parent
21e3e63ac3
commit
5449bb82f1
3 changed files with 67 additions and 10 deletions
|
@ -2,47 +2,58 @@ use crate::{
|
||||||
error::{Error, UploadError},
|
error::{Error, UploadError},
|
||||||
process::Process,
|
process::Process,
|
||||||
store::Store,
|
store::Store,
|
||||||
|
magick::ValidInputType,
|
||||||
};
|
};
|
||||||
use actix_web::web::Bytes;
|
use actix_web::web::Bytes;
|
||||||
use tokio::io::AsyncRead;
|
use tokio::io::{AsyncRead, AsyncReadExt};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub(crate) enum InputFormat {
|
pub(crate) enum InputFormat {
|
||||||
Gif,
|
Gif,
|
||||||
Mp4,
|
Mp4,
|
||||||
|
Webm,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub(crate) enum ThumbnailFormat {
|
pub(crate) enum ThumbnailFormat {
|
||||||
Jpeg,
|
Jpeg,
|
||||||
// Webp,
|
// Webp,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputFormat {
|
impl InputFormat {
|
||||||
fn to_ext(&self) -> &'static str {
|
fn to_ext(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
InputFormat::Gif => ".gif",
|
InputFormat::Gif => ".gif",
|
||||||
InputFormat::Mp4 => ".mp4",
|
InputFormat::Mp4 => ".mp4",
|
||||||
|
InputFormat::Webm => ".webm",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_valid_input_type(self) -> ValidInputType {
|
||||||
|
match self {
|
||||||
|
Self::Gif => ValidInputType::Gif,
|
||||||
|
Self::Mp4 => ValidInputType::Mp4,
|
||||||
|
Self::Webm => ValidInputType::Webm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThumbnailFormat {
|
impl ThumbnailFormat {
|
||||||
fn as_codec(&self) -> &'static str {
|
fn as_codec(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
ThumbnailFormat::Jpeg => "mjpeg",
|
ThumbnailFormat::Jpeg => "mjpeg",
|
||||||
// ThumbnailFormat::Webp => "webp",
|
// ThumbnailFormat::Webp => "webp",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_ext(&self) -> &'static str {
|
fn to_ext(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
ThumbnailFormat::Jpeg => ".jpeg",
|
ThumbnailFormat::Jpeg => ".jpeg",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_format(&self) -> &'static str {
|
fn as_format(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
ThumbnailFormat::Jpeg => "image2",
|
ThumbnailFormat::Jpeg => "image2",
|
||||||
// ThumbnailFormat::Webp => "webp",
|
// ThumbnailFormat::Webp => "webp",
|
||||||
|
@ -50,6 +61,48 @@ impl ThumbnailFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FORMAT_MAPPINGS: &[(&str, InputFormat)] = &[
|
||||||
|
("gif", InputFormat::Gif),
|
||||||
|
("mp4", InputFormat::Mp4),
|
||||||
|
("webm", InputFormat::Webm),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub(crate) async fn input_type_bytes(
|
||||||
|
input: Bytes,
|
||||||
|
) -> Result<Option<InputFormat>, Error> {
|
||||||
|
let input_file = crate::tmp_file::tmp_file(None);
|
||||||
|
let input_file_str = input_file.to_str().ok_or(UploadError::Path)?;
|
||||||
|
crate::store::file_store::safe_create_parent(&input_file).await?;
|
||||||
|
|
||||||
|
let mut tmp_one = crate::file::File::create(&input_file).await?;
|
||||||
|
tmp_one.write_from_bytes(input).await?;
|
||||||
|
tmp_one.close().await?;
|
||||||
|
|
||||||
|
let process = Process::run("ffprobe", &[
|
||||||
|
"-v",
|
||||||
|
"quiet",
|
||||||
|
"-show_entries",
|
||||||
|
"format=format_name",
|
||||||
|
"-of",
|
||||||
|
"default=noprint_wrappers=1:nokey=1",
|
||||||
|
input_file_str,
|
||||||
|
])?;
|
||||||
|
|
||||||
|
let mut output = Vec::new();
|
||||||
|
process.read().read_to_end(&mut output).await?;
|
||||||
|
let formats = String::from_utf8_lossy(&output);
|
||||||
|
|
||||||
|
tracing::info!("FORMATS: {}", formats);
|
||||||
|
|
||||||
|
for (k, v) in FORMAT_MAPPINGS {
|
||||||
|
if formats.contains(k) {
|
||||||
|
return Ok(Some(*v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(name = "Convert to Mp4", skip(input))]
|
#[tracing::instrument(name = "Convert to Mp4", skip(input))]
|
||||||
pub(crate) async fn to_mp4_bytes(
|
pub(crate) async fn to_mp4_bytes(
|
||||||
input: Bytes,
|
input: Bytes,
|
||||||
|
|
|
@ -68,7 +68,7 @@ where
|
||||||
let span = tracing::error_span!("Error deleting files");
|
let span = tracing::error_span!("Error deleting files");
|
||||||
span.in_scope(|| {
|
span.in_scope(|| {
|
||||||
for error in errors {
|
for error in errors {
|
||||||
tracing::error!("{}", format!("{}" error));
|
tracing::error!("{}", format!("{}", error));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,11 @@ pub(crate) async fn validate_image_bytes(
|
||||||
enable_full_video: bool,
|
enable_full_video: bool,
|
||||||
validate: bool,
|
validate: bool,
|
||||||
) -> Result<(ValidInputType, impl AsyncRead + Unpin), Error> {
|
) -> Result<(ValidInputType, impl AsyncRead + Unpin), Error> {
|
||||||
let input_type = crate::magick::input_type_bytes(bytes.clone()).await?;
|
let input_type = if let Some(input_type) = crate::ffmpeg::input_type_bytes(bytes.clone()).await? {
|
||||||
|
input_type.to_valid_input_type()
|
||||||
|
} else {
|
||||||
|
crate::magick::input_type_bytes(bytes.clone()).await?
|
||||||
|
};
|
||||||
|
|
||||||
if !validate {
|
if !validate {
|
||||||
return Ok((input_type, Either::left(UnvalidatedBytes::new(bytes))));
|
return Ok((input_type, Either::left(UnvalidatedBytes::new(bytes))));
|
||||||
|
@ -80,7 +84,7 @@ pub(crate) async fn validate_image_bytes(
|
||||||
Ok((
|
Ok((
|
||||||
ValidInputType::Mp4,
|
ValidInputType::Mp4,
|
||||||
Either::right(Either::left(
|
Either::right(Either::left(
|
||||||
crate::ffmpeg::to_mp4_bytes(bytes, InputFormat::Mp4, enable_full_video).await?,
|
crate::ffmpeg::to_mp4_bytes(bytes, InputFormat::Webm, enable_full_video).await?,
|
||||||
)),
|
)),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue