Use ffprobe to read meta-data if not compiled against libav

Closes #18
This commit is contained in:
CDrummond 2025-03-05 18:39:54 +00:00
parent 751dca7091
commit 32610f22b7
3 changed files with 61 additions and 7 deletions

View File

@ -11,8 +11,7 @@
flags.
6. Add option to write analysis results to files, and use for future scans.
7. If log level set to 'trace' then set this level for the Bliss library too.
8. Enable support for '.dsf' files, but only if compiled against ffmpeg
libraries.
8. Enable support for '.dsf' files.
0.2.3
-----

View File

@ -40,11 +40,7 @@ use bliss_audio::{decoder::Decoder, BlissResult, Song};
const DONT_ANALYSE: &str = ".notmusic";
const MAX_ERRORS_TO_SHOW: usize = 100;
const MAX_TAG_ERRORS_TO_SHOW: usize = 50;
#[cfg(feature = "libav")]
const VALID_EXTENSIONS: [&str; 7] = ["m4a", "mp3", "ogg", "flac", "opus", "wv", "dsf"];
#[cfg(not(feature = "libav"))]
const VALID_EXTENSIONS: [&str; 6] = ["m4a", "mp3", "ogg", "flac", "opus", "wv"];
fn get_file_list(db: &mut db::Db, mpath: &Path, path: &Path, track_paths: &mut Vec<String>, cue_tracks:&mut Vec<cue::CueTrack>, file_count:&mut usize, max_num_files: usize, use_tags: bool, tagged_file_count:&mut usize, dry_run: bool) {
if !path.is_dir() {
@ -285,7 +281,10 @@ fn analyse_new_files(db: &db::Db, mpath: &PathBuf, track_paths: Vec<String>, max
match result {
Ok(track) => {
let cpath = String::from(path.to_string_lossy());
let meta = tags::read(&cpath, false);
let mut meta = tags::read(&cpath, false);
if meta.is_empty() {
meta = ffmpeg::read_tags(&cpath);
}
if meta.is_empty() {
tag_error.push(sname.clone());
}

View File

@ -6,6 +6,7 @@
*
**/
use crate::db;
use bliss_audio::decoder::Decoder as DecoderTrait;
use bliss_audio::decoder::PreAnalyzedSong;
use bliss_audio::{BlissError, BlissResult};
@ -13,6 +14,8 @@ use std::path::Path;
use std::process::{Child, Command, Stdio};
use std::io;
use std::io::Read;
use std::io::BufRead;
use std::io::BufReader;
use std::time::Duration;
pub const TIME_SEP:&str = "<TIME>";
@ -41,6 +44,59 @@ fn handle_command(mut child: Child) -> BlissResult<PreAnalyzedSong> {
Ok(decoded_song)
}
fn get_val(line: String) -> String {
let parts = line.split("=");
let mut resp:Vec<String> = Vec::new();
let mut first =true;
for part in parts {
if !first {
resp.push(String::from(part));
}
first = false
}
resp.join("=")
}
pub fn read_tags(path: &String) -> db::Metadata {
let mut meta = db::Metadata {
duration: 0,
..db::Metadata::default()
};
if let Ok(child) = Command::new("ffprobe")
.arg("-hide_banner")
.arg("-v").arg("quiet")
.arg("-show_entries").arg("format")
.arg(path)
.stdout(Stdio::piped())
.spawn() {
let out = child.stdout.unwrap();
let lines = BufReader::new(out).lines().filter_map(|line| line.ok());
for line in lines {
if line.starts_with("duration=") {
let val = get_val(line);
match val.parse::<f32>() {
Ok(v) => {
meta.duration = v as u32;
},
Err(_) => { }
}
} else if line.starts_with("TAG:title=") {
meta.title = get_val(line);
} else if line.starts_with("TAG:artist=") {
meta.artist = get_val(line);
} else if line.starts_with("TAG:album=") {
meta.album = get_val(line);
} else if line.starts_with("TAG:album_artist=") {
meta.album_artist = get_val(line);
} else if line.starts_with("TAG:genre=") {
meta.genre = get_val(line);
}
}
}
meta
}
impl DecoderTrait for FFmpegCmdDecoder {
fn decode(path: &Path) -> BlissResult<PreAnalyzedSong> {
let binding = path.to_string_lossy();