move ffprobe stuff to its own module

This commit is contained in:
chaos 2023-10-18 14:47:03 +01:00
parent 84e79f6cc6
commit bb4f776538
No known key found for this signature in database
8 changed files with 159 additions and 62 deletions

View file

@ -40,7 +40,6 @@ taglib = { path = "./modules/taglib", optional = true }
html-escape = "0.2"
urlencoding = "2"
# error handling
thiserror = "1"
string-error = "0.1"

View file

@ -28,7 +28,7 @@
version = "latest";
src = ./.;
cargoLock = {lockFile = ./Cargo.lock;};
cargoLock.lockFile = ./Cargo.lock;
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";

View file

@ -0,0 +1,35 @@
use std::{fmt, io, process};
#[derive(Debug)]
pub enum AnalyzeError {
FFProbeError(FFProbeError),
IOError(io::Error),
ParseError(serde_json::Error),
}
impl fmt::Display for AnalyzeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AnalyzeError::FFProbeError(err) => write!(f, "{}", err),
AnalyzeError::IOError(err) => write!(f, "{}", err),
AnalyzeError::ParseError(err) => write!(f, "{}", err),
}
}
}
#[derive(Debug, Clone)]
pub struct FFProbeError {
pub exit_status: process::ExitStatus,
pub stderr: String,
}
impl fmt::Display for FFProbeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"ffprobe exited with error code {}, stderr: {}",
self.exit_status.code().unwrap(),
self.stderr
)
}
}

View file

@ -0,0 +1,35 @@
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct FFProbeOutput {
pub format: FFProbeOutputFormat,
}
#[derive(Debug, Clone, Deserialize)]
pub struct FFProbeOutputFormat {
pub tags: FFProbeOutputTags,
}
#[derive(Debug, Clone, Deserialize)]
pub struct FFProbeOutputTags {
#[serde(alias = "TITLE")]
pub title: String,
#[serde(default, alias = "ARTIST")]
pub artist: String,
#[serde(default, alias = "REPLAYGAIN_TRACK_PEAK")]
pub replaygain_track_peak: Option<String>,
#[serde(default, alias = "REPLAYGAIN_TRACK_GAIN")]
pub replaygain_track_gain: Option<String>,
}
impl Default for FFProbeOutputTags {
fn default() -> Self {
FFProbeOutputTags {
title: "".to_string(),
artist: "".to_string(),
replaygain_track_peak: None,
replaygain_track_gain: None,
}
}
}

47
src/utils/ffprobe/mod.rs Normal file
View file

@ -0,0 +1,47 @@
mod ffprobe_output;
pub mod errors;
pub mod types;
use std::{
convert::Into,
path::PathBuf,
process::Command,
};
use self::errors::{AnalyzeError, FFProbeError};
pub fn analyze(path: &PathBuf) -> Result<types::FFProbeData, AnalyzeError> {
let output = Command::new(crate::meta::FFPROBE)
.args([
"-v",
"quiet",
"-print_format",
"json",
"-show_format",
path.to_str().unwrap(),
])
.output();
if let Err(err) = output {
return Err(AnalyzeError::IOError(err));
}
let output = output.unwrap();
if !output.status.success() {
return Err(AnalyzeError::FFProbeError(FFProbeError {
exit_status: output.status,
stderr: String::from_utf8(output.stderr).unwrap(),
}));
}
let output = String::from_utf8(output.stdout).unwrap();
let ffprobe_out: serde_json::Result<ffprobe_output::FFProbeOutput> =
serde_json::from_str(output.as_str());
let ffprobe_out = ffprobe_out.unwrap();
return Ok(types::FFProbeData {
tags: ffprobe_out.format.tags.into(),
});
}

View file

@ -0,0 +1,27 @@
use serde::Serialize;
use super::ffprobe_output;
#[derive(Debug, Clone, Serialize)]
pub struct FFProbeTags {
pub title: String,
pub artist: String,
pub replaygain_track_peak: Option<String>,
pub replaygain_track_gain: Option<String>,
}
impl Into<FFProbeTags> for ffprobe_output::FFProbeOutputTags {
fn into(self) -> FFProbeTags {
FFProbeTags {
title: self.title,
artist: self.artist,
replaygain_track_peak: self.replaygain_track_peak,
replaygain_track_gain: self.replaygain_track_gain,
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct FFProbeData {
pub tags: FFProbeTags,
}

View file

@ -3,12 +3,11 @@ use std::{
process::Command,
};
use serde::Deserialize;
use string_error::static_err;
use string_error::into_err;
use crate::{
types::{AudioFileInfo, ReplayGainData, ReplayGainRawData, Tags},
utils::format_detection::FileFormat,
utils::{format_detection::FileFormat, ffprobe},
};
use super::{AudioContainerFormat, AudioFormatError, BoxedError};
@ -26,40 +25,6 @@ struct ExtractedData {
replaygain_data: Option<ReplayGainData>,
}
#[derive(Debug, Clone, Deserialize)]
struct FFProbeOutput {
pub format: FFProbeFormat,
}
#[derive(Debug, Clone, Deserialize)]
struct FFProbeFormat {
pub tags: FFProbeTags,
}
#[derive(Debug, Clone, Deserialize)]
struct FFProbeTags {
#[serde(alias = "TITLE")]
pub title: String,
#[serde(default, alias = "ARTIST")]
pub artist: String,
#[serde(default, alias = "REPLAYGAIN_TRACK_PEAK")]
pub replaygain_track_peak: Option<String>,
#[serde(default, alias = "REPLAYGAIN_TRACK_GAIN")]
pub replaygain_track_gain: Option<String>,
}
impl Default for FFProbeTags {
fn default() -> Self {
FFProbeTags {
title: "".to_string(),
artist: "".to_string(),
replaygain_track_peak: None,
replaygain_track_gain: None,
}
}
}
pub struct GenericFFMpegAudioFormat {
format_type: FileFormat,
path: Box<PathBuf>,
@ -70,36 +35,23 @@ pub struct GenericFFMpegAudioFormat {
impl GenericFFMpegAudioFormat {
fn analyze(&mut self) -> Result<(), BoxedError> {
let output = Command::new(crate::meta::FFPROBE)
.args([
"-v",
"quiet",
"-print_format",
"json",
"-show_format",
&self.path.to_string_lossy(),
])
.output()?;
let output = ffprobe::analyze(&self.path);
if !output.status.success() {
print!("{:?}", String::from_utf8(output.stderr).unwrap());
return Err(static_err("FFprobe Crashed"));
if let Err(err) = output {
return Err(into_err(format!("{}", err)));
}
let output_str = String::from_utf8(output.stdout).unwrap();
let ffprobe_out: FFProbeOutput = serde_json::from_str(output_str.as_str())?;
let tags = ffprobe_out.format.tags;
let output = output.unwrap();
self.extracted_data.tags = Tags {
title: tags.title,
artist: tags.artist,
title: output.tags.title,
artist: output.tags.artist,
};
if tags.replaygain_track_gain.is_some() && tags.replaygain_track_peak.is_some() {
if output.tags.replaygain_track_gain.is_some() && output.tags.replaygain_track_peak.is_some() {
self.extracted_data.replaygain_data = Some(ReplayGainData {
track_gain: tags.replaygain_track_gain.unwrap(),
track_peak: tags.replaygain_track_peak.unwrap(),
track_gain: output.tags.replaygain_track_gain.unwrap(),
track_peak: output.tags.replaygain_track_peak.unwrap(),
});
} else {
self.extracted_data.replaygain_data = None;
@ -234,6 +186,7 @@ pub fn new_generic_ffmpeg_format_handler(
extracted_data: ExtractedData::default(),
changes: Changes::default(),
};
handler.analyze()?;
Ok(handler)

View file

@ -2,6 +2,7 @@ pub mod ascii_reduce;
pub mod format_detection;
pub mod replaygain;
pub mod transcoder;
pub mod ffprobe;
pub mod formats;
pub(self) mod music_scanner;