feat: video duration / bitrate

This commit is contained in:
kieran 2025-01-27 21:19:11 +00:00
parent 5fbe40faae
commit 3ba5e7bc4c
No known key found for this signature in database
GPG Key ID: DE71CEB3925BE941
6 changed files with 45 additions and 5 deletions

View File

@ -0,0 +1,4 @@
-- Add migration script here
alter table uploads
add column duration float,
add column bitrate integer unsigned;

View File

@ -139,6 +139,8 @@ async fn migrate_file(
},
blur_hash: None,
alt: f.description.clone(),
duration: None,
bitrate: None,
};
db.add_file(&fu, uid).await?;
Ok(())

View File

@ -25,6 +25,10 @@ pub struct FileUpload {
pub blur_hash: Option<String>,
/// Alt text of the media
pub alt: Option<String>,
/// Duration of media in seconds
pub duration: Option<f32>,
/// Average bitrate in bits/s
pub bitrate: Option<u32>,
#[sqlx(skip)]
#[cfg(feature = "labels")]
@ -43,6 +47,8 @@ impl From<&NewFileResult> for FileUpload {
height: value.height,
blur_hash: value.blur_hash.clone(),
alt: None,
duration: value.duration,
bitrate: value.bitrate,
#[cfg(feature = "labels")]
labels: value.labels.clone(),
}
@ -145,7 +151,7 @@ impl Database {
pub async fn add_file(&self, file: &FileUpload, user_id: u64) -> Result<(), Error> {
let mut tx = self.pool.begin().await?;
let q = sqlx::query("insert ignore into \
uploads(id,name,size,mime_type,blur_hash,width,height,alt,created) values(?,?,?,?,?,?,?,?,?)")
uploads(id,name,size,mime_type,blur_hash,width,height,alt,created,duration,bitrate) values(?,?,?,?,?,?,?,?,?,?,?)")
.bind(&file.id)
.bind(&file.name)
.bind(file.size)
@ -154,7 +160,9 @@ impl Database {
.bind(file.width)
.bind(file.height)
.bind(&file.alt)
.bind(file.created);
.bind(file.created)
.bind(file.duration)
.bind(file.bitrate);
tx.execute(q).await?;
let q2 = sqlx::query("insert ignore into user_uploads(file,user_id) values(?,?)")

View File

@ -1,5 +1,6 @@
#[cfg(feature = "labels")]
use crate::db::FileLabel;
use crate::processing::can_compress;
#[cfg(feature = "labels")]
use crate::processing::labeling::label_frame;
#[cfg(feature = "media-compression")]
@ -36,6 +37,8 @@ pub struct NewFileResult {
pub width: Option<u32>,
pub height: Option<u32>,
pub blur_hash: Option<String>,
pub duration: Option<f32>,
pub bitrate: Option<u32>,
#[cfg(feature = "labels")]
pub labels: Vec<FileLabel>,
}
@ -74,7 +77,7 @@ impl FileStore {
return Ok(FileSystemResult::AlreadyExists(hash));
}
let mut res = if compress {
let mut res = if compress && can_compress(mime_type) {
#[cfg(feature = "media-compression")]
{
let res = match self.compress_file(&temp_file, mime_type).await {
@ -92,7 +95,7 @@ impl FileStore {
anyhow::bail!("Compression not supported!");
}
} else {
let (width, height, mime_type) = {
let (width, height, mime_type, duration, bitrate) = {
#[cfg(feature = "media-compression")]
{
let probe = probe_file(&temp_file).ok();
@ -102,10 +105,18 @@ impl FileStore {
v_stream.map(|v| v.width as u32),
v_stream.map(|v| v.height as u32),
mime,
probe.as_ref().map(|p| p.duration),
probe.as_ref().map(|p| p.bitrate as u32),
)
}
#[cfg(not(feature = "media-compression"))]
(None, None, Self::infer_mime_type(mime_type, &temp_file))
(
None,
None,
Self::infer_mime_type(mime_type, &temp_file),
None,
None,
)
};
NewFileResult {
path: temp_file,
@ -115,6 +126,8 @@ impl FileStore {
width,
height,
blur_hash: None,
duration,
bitrate,
}
};
@ -194,6 +207,8 @@ impl FileStore {
height: Some(compressed_result.height as u32),
blur_hash: None,
mime_type: compressed_result.mime_type,
duration: Some(compressed_result.duration),
bitrate: Some(compressed_result.bitrate),
#[cfg(feature = "labels")]
labels,
})

View File

@ -66,6 +66,8 @@ impl WebpProcessor {
mime_type: "image/webp".to_string(),
width: image_stream.width,
height: image_stream.height,
duration: probe.duration,
bitrate: probe.bitrate as u32,
})
}
}
@ -126,6 +128,8 @@ pub struct NewFileProcessorResult {
pub mime_type: String,
pub width: usize,
pub height: usize,
pub duration: f32,
pub bitrate: u32,
}
pub fn can_compress(mime_type: &str) -> bool {

View File

@ -81,6 +81,13 @@ impl Nip94Event {
if let (Some(w), Some(h)) = (upload.width, upload.height) {
tags.push(vec!["dim".to_string(), format!("{}x{}", w, h)])
}
if let Some(d) = &upload.duration {
tags.push(vec!["duration".to_string(), d.to_string()]);
}
if let Some(b) = &upload.bitrate {
tags.push(vec!["bitrate".to_string(), b.to_string()]);
}
#[cfg(feature = "labels")]
for l in &upload.labels {
let val = if l.label.contains(',') {