summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author4censord <49623362+4censord@users.noreply.github.com>2023-11-27 23:22:48 +0100
committerGitHub <noreply@github.com>2023-11-27 23:22:48 +0100
commitee78fc2aacdc1fb32b1d05dcc2838df5264363a6 (patch)
treed535a132ae01b8c476a70892c3e7aa7897fdf2bf
parent1f4d6bd7fc09f7f1b39b8ce9e13e807b81ef0729 (diff)
Add mkv duration extractor (#140)
-rw-r--r--src/util/duration/mkv.rs60
-rw-r--r--src/util/duration/mod.rs5
2 files changed, 64 insertions, 1 deletions
diff --git a/src/util/duration/mkv.rs b/src/util/duration/mkv.rs
new file mode 100644
index 0000000..297f6db
--- /dev/null
+++ b/src/util/duration/mkv.rs
@@ -0,0 +1,60 @@
+use mp3_metadata::MP3Metadata;
+use std::fs::File;
+use std::io;
+use std::path::Path;
+
+use crate::util::duration::DurationExtractor;
+use crate::util::Duration;
+
+use matroska::MatroskaError;
+
+pub struct MkvDurationExtractor;
+
+impl DurationExtractor for MkvDurationExtractor {
+ fn supports_ext(&self, ext_lowercase: &str) -> bool {
+ "mkv" == ext_lowercase || "webm" == ext_lowercase
+ }
+
+ fn try_read_duration(
+ &self,
+ path: &Path,
+ _: &Option<MP3Metadata>,
+ ) -> io::Result<Option<Duration>> {
+ let fd = File::open(path)?;
+ let matroska = matroska::Matroska::open(fd).map_err(|err| match err {
+ MatroskaError::Io(io) => io,
+ MatroskaError::UTF8(utf8) => io::Error::new(io::ErrorKind::InvalidData, utf8),
+ e => io::Error::new(io::ErrorKind::InvalidData, e),
+ })?;
+
+ match matroska.info.duration {
+ Some(duration) => {
+ return Ok(Some(Duration {
+ length: duration.as_secs() as usize,
+ }))
+ }
+ None => return Ok(None),
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::MkvDurationExtractor;
+ use crate::util::duration::DurationExtractor;
+ use crate::util::Duration;
+ use std::error::Error;
+ use std::path::PathBuf;
+
+ #[test]
+ fn test_success() -> Result<(), Box<dyn Error>> {
+ let path_string =
+ std::env::var("CARGO_MANIFEST_DIR")? + "/resources/test/" + "video/rust-logo-blk.mkv";
+ let path = PathBuf::from(path_string);
+ assert_eq!(
+ MkvDurationExtractor.try_read_duration(&path, &None)?,
+ Some(Duration { length: 1 }),
+ );
+ Ok(())
+ }
+}
diff --git a/src/util/duration/mod.rs b/src/util/duration/mod.rs
index 0a4e7a3..8353e49 100644
--- a/src/util/duration/mod.rs
+++ b/src/util/duration/mod.rs
@@ -1,5 +1,6 @@
use std::io;
+mod mkv;
mod mp3;
mod mp4;
@@ -7,6 +8,7 @@ use std::path::Path;
use mp3_metadata::MP3Metadata;
+use mkv::MkvDurationExtractor;
use mp3::Mp3DurationExtractor;
use mp4::Mp4DurationExtractor;
@@ -20,9 +22,10 @@ pub trait DurationExtractor {
fn try_read_duration(&self, path: &Path, mp3_metadata: &Option<MP3Metadata>) -> io::Result<Option<Duration>>;
}
-const EXTRACTORS: [&dyn DurationExtractor; 2] = [
+const EXTRACTORS: [&dyn DurationExtractor; 3] = [
&Mp3DurationExtractor,
&Mp4DurationExtractor,
+ &MkvDurationExtractor,
];
pub fn get_duration<T: AsRef<Path>>(path: T, mp3_metadata: &Option<MP3Metadata>) -> Option<Duration> {