diff options
| -rw-r--r-- | CHANGELOG.md | 6 | ||||
| -rw-r--r-- | Cargo.lock | 125 | ||||
| -rw-r--r-- | Cargo.toml | 5 | ||||
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | src/db.rs | 73 | ||||
| -rw-r--r-- | src/files.rs | 35 | ||||
| -rw-r--r-- | src/flac.rs | 209 |
7 files changed, 273 insertions, 181 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e9d1af8..0fd6aea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v0.3.0 +* removed claxon dep in favor of flac_codec, same for metaflac +* cleaned up code a bit + # v0.2.6-fix * remembered about changelog.md * fixed incorrect encoded_by tag match @@ -7,4 +11,4 @@ * added better bar incremental logic by passing it to threads * added graceful shutdown (albeit its a bit slow) * checks file if it exists before reencoding -* removes temporary file if it was left uncleaned from the previous session
\ No newline at end of file +* removes temporary file if it was left uncleaned from the previous session @@ -59,22 +59,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] name = "bitflags" version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] -name = "bumpalo" -version = "3.19.0" +name = "bitstream-io" +version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757" +dependencies = [ + "core2", +] [[package]] -name = "byteorder" -version = "1.5.0" +name = "bumpalo" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" @@ -135,11 +144,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] -name = "claxon" -version = "0.4.3" -source = "git+https://github.com/justjakka/claxon.git#919a0fe9902f2b4f2bd1152772cca746eb0df7d2" - -[[package]] name = "cmake" version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -168,6 +172,40 @@ dependencies = [ ] [[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] name = "ctrlc" version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -206,6 +244,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" [[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] name = "encode_unicode" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -239,19 +283,30 @@ dependencies = [ ] [[package]] +name = "flac-codec" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dba37ade3b9791d1a219ccb29826d06261538c523f38b5c5aadb44646b1d6a0" +dependencies = [ + "arrayvec", + "bitstream-io", + "md5", + "rayon", +] + +[[package]] name = "flac-reencoder" -version = "0.2.7" +version = "0.3.0" dependencies = [ "anyhow", "clap", "clap_complete", - "claxon", "console", "ctrlc", "directories", "flac-bound", + "flac-codec", "indicatif", - "metaflac", "rusqlite", "walkdir", ] @@ -292,12 +347,6 @@ dependencies = [ ] [[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] name = "indicatif" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -371,14 +420,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] -name = "metaflac" -version = "0.2.8" +name = "md5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf25a3451319c52a4a56d956475fbbb763bfb8420e2187d802485cb0fd8d965" -dependencies = [ - "byteorder", - "hex", -] +checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "nix" @@ -441,6 +492,26 @@ dependencies = [ ] [[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] name = "redox_users" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1,6 +1,6 @@ [package] name = "flac-reencoder" -version = "0.2.7" +version = "0.3.0" edition = "2024" repository = "https://github.com/justjakka/reencoder/" license = "BSD-3-Clause" @@ -18,12 +18,11 @@ flac-bound = { version = "0.5.0", default-features = false } indicatif = { version = "0.18.0", features = ["improved_unicode"] } walkdir = "2.5.0" console = { version = "0.16.0", features = ["windows-console-colors"] } -claxon = { git = "https://github.com/justjakka/claxon.git" } -metaflac = "0.2.8" rusqlite = { version = "0.36.0", default-features = false, features = [ "modern_sqlite", ] } ctrlc = "3.4.7" +flac-codec = { version = "1.2.0", features = ["rayon"] } [features] default = ["bundled"] @@ -2,7 +2,6 @@ scans a specified folder and reencodes flacs if they needed to be reencoded -currently this project uses [my own hacky fork of claxon](https://github.com/justjakka/claxon) ``` Usage: reencoder [OPTIONS] [path] @@ -22,21 +22,21 @@ const GET_MODTIME: &str = "SELECT modtime FROM flacs WHERE path = ?1"; pub trait Database { type Conn; - fn new(path: Option<impl AsRef<Path>>) -> Result<Self::Conn>; - fn insert_file(&self, filename: impl AsRef<Path>) -> Result<()>; - fn update_file(&self, filename: impl AsRef<Path>) -> Result<()>; - fn check_file(&self, filename: impl AsRef<Path>) -> Result<bool>; + fn new(path: Option<&PathBuf>) -> Result<Self::Conn>; + fn insert_file(&self, filename: &Path) -> Result<()>; + fn update_file(&self, filename: &Path) -> Result<()>; + fn check_file(&self, filename: &Path) -> Result<bool>; fn init_clean_files(&self) -> Result<Vec<PathBuf>, rusqlite::Error>; - fn remove_file(&self, filename: impl AsRef<Path>) -> Result<()>; + fn remove_file(&self, filename: &Path) -> Result<()>; fn get_toencode_files(&self) -> Result<Vec<PathBuf>, rusqlite::Error>; fn get_toencode_number(&self) -> Result<u64, rusqlite::Error>; - fn get_modtime(&self, file: impl AsRef<Path>) -> Result<u64>; + fn get_modtime(&self, file: &Path) -> Result<u64>; fn vacuum(&self) -> Result<()>; } impl Database for Connection { type Conn = Connection; - fn new(path: Option<impl AsRef<Path>>) -> Result<Self> { + fn new(path: Option<&PathBuf>) -> Result<Self> { let conn = if let Some(file) = path { Connection::open(file)? } else if let Some(base_dir) = BaseDirs::new() { @@ -49,11 +49,10 @@ impl Database for Connection { Ok(conn) } - fn insert_file(&self, filename: impl AsRef<Path>) -> Result<()> { + fn insert_file(&self, filename: &Path) -> Result<()> { let toencode = !matches!(get_vendor(&filename)?.as_str(), CURRENT_VENDOR); let modtime = filename - .as_ref() .metadata()? .modified()? .duration_since(UNIX_EPOCH)? @@ -61,15 +60,14 @@ impl Database for Connection { self.execute( ADD_ITEM, - params![filename.as_ref().to_str().unwrap(), toencode, modtime], + params![filename.to_str().unwrap(), toencode, modtime], )?; Ok(()) } - fn update_file(&self, filename: impl AsRef<Path>) -> Result<()> { + fn update_file(&self, filename: &Path) -> Result<()> { let modtime = filename - .as_ref() .metadata()? .modified()? .duration_since(UNIX_EPOCH)? @@ -77,21 +75,17 @@ impl Database for Connection { self.execute( UPDATE_ITEM, - params![filename.as_ref().to_str().unwrap(), false, modtime], + params![filename.to_str().unwrap(), false, modtime], )?; Ok(()) } - fn check_file(&self, filename: impl AsRef<Path>) -> Result<bool> { - if self.query_one( - CHECK_FILE, - params!(filename.as_ref().to_str().unwrap()), - |row| { - let num: bool = row.get(0)?; - Ok(num) - }, - )? { + fn check_file(&self, filename: &Path) -> Result<bool> { + if self.query_one(CHECK_FILE, params!(filename.to_str().unwrap()), |row| { + let num: bool = row.get(0)?; + Ok(num) + })? { Ok(true) } else { Ok(false) @@ -110,8 +104,8 @@ impl Database for Connection { Ok(files) } - fn remove_file(&self, filename: impl AsRef<Path>) -> Result<()> { - self.execute(REMOVE_FILE, params!(filename.as_ref().to_str().unwrap()))?; + fn remove_file(&self, filename: &Path) -> Result<()> { + self.execute(REMOVE_FILE, params!(filename.to_str().unwrap()))?; Ok(()) } @@ -133,15 +127,13 @@ impl Database for Connection { }) } - fn get_modtime(&self, file: impl AsRef<Path>) -> Result<u64> { - Ok(self.query_one( - GET_MODTIME, - params![file.as_ref().to_str().unwrap()], - |row| { + fn get_modtime(&self, file: &Path) -> Result<u64> { + Ok( + self.query_one(GET_MODTIME, params![file.to_str().unwrap()], |row| { let modtime: u64 = row.get(0)?; Ok(modtime) - }, - )?) + })?, + ) } fn vacuum(&self) -> Result<()> { @@ -157,7 +149,7 @@ mod tests { #[test] fn check_localfiles() { - let dbname = String::from("temp1.db"); + let dbname = PathBuf::from("temp1.db"); let filenames = [ "./samples/16bit.flac", "./samples/24bit.flac", @@ -166,7 +158,8 @@ mod tests { let mut counter = 0; let conn = Connection::new(Some(&dbname)).unwrap(); for file in filenames { - conn.insert_file(&file.to_string()).unwrap(); + let filename = PathBuf::from(file); + conn.insert_file(&filename).unwrap(); } let mut stmt = conn.prepare(TOENCODE_PATHS).unwrap(); let mut returned = stmt.query(()).unwrap(); @@ -180,7 +173,7 @@ mod tests { #[test] fn check_update() { - let dbname = String::from("temp2.db"); + let dbname = PathBuf::from("temp2.db"); let filenames = [ "./samples/16bit.flac", "./samples/24bit.flac", @@ -188,7 +181,7 @@ mod tests { ]; let conn = Connection::new(Some(&dbname)).unwrap(); for file in filenames { - conn.insert_file(Path::new(file).canonicalize().unwrap()) + conn.insert_file(&Path::new(file).canonicalize().unwrap()) .unwrap(); } @@ -206,14 +199,8 @@ mod tests { ) .unwrap(); - conn.update_file( - Path::new("./samples/16bit.flac") - .canonicalize() - .unwrap() - .to_str() - .unwrap(), - ) - .unwrap(); + conn.update_file(&Path::new("./samples/16bit.flac").canonicalize().unwrap()) + .unwrap(); let mut stmt = conn.prepare(TOENCODE_PATHS).unwrap(); let mut returned = stmt.query(()).unwrap(); diff --git a/src/files.rs b/src/files.rs index 0407469..afb42d7 100644 --- a/src/files.rs +++ b/src/files.rs @@ -29,9 +29,9 @@ struct FileError { } impl FileError { - fn new(file: impl AsRef<Path>, error: anyhow::Error) -> Self { + fn new(file: &Path, error: anyhow::Error) -> Self { FileError { - file: file.as_ref().to_path_buf(), + file: file.to_path_buf(), error, } } @@ -50,35 +50,34 @@ impl Display for FileError { impl Error for FileError {} -fn handle_file(file: impl AsRef<Path>, conn: &Connection) -> Result<()> { - if conn.check_file(&file)? { +fn handle_file(file: &Path, conn: &Connection) -> Result<()> { + if conn.check_file(file)? { let modtime = file - .as_ref() .metadata()? .modified()? .duration_since(UNIX_EPOCH)? .as_secs(); - let db_modtime = conn.get_modtime(&file)?; + let db_modtime = conn.get_modtime(file)?; if modtime != db_modtime { - conn.update_file(&file)?; + conn.update_file(file)?; } return Ok(()); } - conn.insert_file(&file)?; + conn.insert_file(file)?; Ok(()) } pub fn index_files_recursively( - path: impl AsRef<Path>, + path: &Path, conn: &Connection, handler: Arc<AtomicBool>, ) -> Result<()> { - if !path.as_ref().is_dir() { + if !path.is_dir() { return Err(anyhow!("Invalid root directory")); } - let abspath = path.as_ref().canonicalize()?; + let abspath = path.canonicalize()?; #[cfg(not(test))] let bar = ProgressBar::with_draw_target(Some(0), ProgressDrawTarget::stdout_with_hz(60)) @@ -108,7 +107,7 @@ pub fn index_files_recursively( } if path.extension().is_some_and(|x| x == "flac") { if let Err(error) = handle_file(&path, conn) { - eprintln!("{}", FileError::new(path, error)); + eprintln!("{}", FileError::new(&path, error)); } else { #[cfg(not(test))] bar.inc(1); @@ -172,7 +171,7 @@ pub fn reencode_files(conn: Connection, handler: Arc<AtomicBool>, threads: usize Err(error) => eprintln!("{}", FileError::new(&file, error)), Ok(false) => { if let Err(error) = lock.lock().unwrap().update_file(&file) { - eprintln!("{}", FileError::new(file, error)); + eprintln!("{}", FileError::new(&file, error)); } #[cfg(not(test))] bar.inc(1) @@ -205,6 +204,7 @@ pub fn clean_files(conn: &Connection, handler: Arc<AtomicBool>) -> Result<()> { spinner.tick(); files.iter().for_each(|file| { + #[allow(clippy::collapsible_if)] if handler.load(Ordering::SeqCst) && !file.exists() { if let Err(error) = conn.remove_file(file) { eprintln!("{}", FileError::new(file, error)) @@ -227,7 +227,7 @@ mod tests { #[test] fn test_index_lots_of_files() { - let dbname = "temp3.db"; + let dbname = PathBuf::from("temp3.db"); let handler = Arc::new(AtomicBool::new(true)); let conn = Connection::new(Some(&dbname)).unwrap(); index_files_recursively(Path::new("./testfiles"), &conn, handler).unwrap(); @@ -236,7 +236,7 @@ mod tests { #[test] fn test_clean_files() { - let dbname = "temp4.db"; + let dbname = PathBuf::from("temp4.db"); let handler = Arc::new(AtomicBool::new(true)); let conn = Connection::new(Some(&dbname)).unwrap(); let filenames = [ @@ -247,7 +247,8 @@ mod tests { ]; std::fs::copy("./samples/32bit.flac", "./samples/nonexisting.flac").unwrap(); for file in filenames { - conn.insert_file(&file).unwrap(); + let filename = PathBuf::from(file); + conn.insert_file(&filename).unwrap(); } std::fs::remove_file("./samples/nonexisting.flac").unwrap(); @@ -260,7 +261,7 @@ mod tests { #[test] fn test_reencode_lots_of_files() { - let dbname = "temp5.db"; + let dbname = PathBuf::from("temp5.db"); let handler = Arc::new(AtomicBool::new(true)); let conn = Connection::new(Some(&dbname)).unwrap(); let temp = handler.clone(); diff --git a/src/flac.rs b/src/flac.rs index 7b542ac..e882cd7 100644 --- a/src/flac.rs +++ b/src/flac.rs @@ -1,7 +1,9 @@ use anyhow::{Result, anyhow}; -use claxon::{FlacReader, FlacReaderOptions}; use flac_bound::FlacEncoder; -use metaflac::{Block, Tag}; +use flac_codec::{ + decode::{Metadata, verify}, + *, +}; use std::{ path::Path, sync::{ @@ -10,52 +12,63 @@ use std::{ }, }; -pub const CURRENT_VENDOR: &str = "reference libFLAC 1.5.0 20250211"; - +pub(crate) const CURRENT_VENDOR: &str = "reference libFLAC 1.5.0 20250211"; const BADTAGS: [&str; 3] = ["encoded_by", "encodedby", "encoder"]; -fn write_tags(filename: impl AsRef<Path>) -> Result<()> { - let tags = Tag::read_from_path(&filename)?; - let temp_name = filename.as_ref().with_extension("tmp"); - let mut output = Tag::read_from_path(&temp_name)?; - - for block in tags.blocks() { - match block { - Block::VorbisComment(block) => { - for (key, val) in block.comments.iter() { - if !BADTAGS.contains(&key.to_lowercase().as_str()) { - output.set_vorbis(key, val.to_owned()); - } - } - } - Block::Padding(_) => {} - _ => output.push_block(block.to_owned()), - } - } - - output.write_to_path(temp_name)?; - Ok(()) -} +fn encode_file(filename: &Path, handler: Arc<AtomicBool>) -> Result<bool> { + if verify(filename).is_err() { + return Err(anyhow!("corrupt file")); + }; -fn encode_file(filename: impl AsRef<Path>, handler: Arc<AtomicBool>) -> Result<bool> { - let temp_name = filename.as_ref().with_extension("tmp"); + let temp_name = filename.with_extension("tmp"); if temp_name.exists() { std::fs::remove_file(&temp_name)?; } - let mut decoder = FlacReader::open(&filename)?; - let streaminfo = decoder.streaminfo(); - let num_channels: usize = streaminfo.channels.try_into()?; + let mut reader = decode::FlacSampleReader::open(filename)?; + + let blocklist = reader.metadata(); + + let streaminfo = blocklist.streaminfo(); + + let channels = streaminfo.channel_count() as u32; + + let metadata = blocklist + .blocks() + .filter_map(|block| { + use metadata::Block; + use metadata::BlockRef::*; + match block { + SeekTable(table) => Some(Block::SeekTable(table.clone())), + Application(app) => Some(Block::Application(app.clone())), + Cuesheet(sheet) => Some(Block::Cuesheet(sheet.clone())), + Picture(picture) => Some(Block::Picture(picture.clone())), + VorbisComment(comments) => { + let mut cloned = comments.clone(); + for tag in BADTAGS { + cloned.remove(tag); + } + cloned.vendor_string = CURRENT_VENDOR.to_string(); + Some(Block::VorbisComment(cloned)) + } + _ => None, + } + }) + .collect::<Vec<metadata::Block>>(); let mut encoder = if let Some(encoder) = FlacEncoder::new() { - if let Ok(encoder) = encoder - .channels(streaminfo.channels) - .bits_per_sample(streaminfo.bits_per_sample) - .sample_rate(streaminfo.sample_rate) - .compression_level(8) - .verify(false) - .init_file(&temp_name) - { + if let Ok(encoder) = { + let mut encoder = encoder + .channels(streaminfo.channel_count() as u32) + .bits_per_sample(streaminfo.bits_per_sample()) + .sample_rate(streaminfo.sample_rate()) + .compression_level(8) + .verify(false); + if let Some(size) = reader.total_samples() { + encoder = encoder.total_samples_estimate(size) + } + encoder.init_file(&temp_name) + } { encoder } else { return Err(anyhow!("failed to create encoder")); @@ -64,28 +77,26 @@ fn encode_file(filename: impl AsRef<Path>, handler: Arc<AtomicBool>) -> Result<b return Err(anyhow!("failed to create encoder")); }; - let mut frame_reader = decoder.blocks(); - let mut buffer = Vec::new(); - let mut block_buffer = Vec::with_capacity(streaminfo.max_block_size as usize * num_channels); - while handler.load(Ordering::SeqCst) { - match frame_reader.read_next_or_eof(block_buffer) { - Ok(Some(block)) => { - for ch in 0..block.channels() { - buffer.push(block.channel(ch)); - } + match reader.fill_buf() { + Ok(buf) => { + if !buf.is_empty() { + let length = buf.len(); + if encoder + .process_interleaved(buf, length as u32 / channels) + .is_err() + { + return Err(anyhow!( + "Error while processing samples:\t{:?}", + encoder.state() + )); + }; - if encoder.process(&buffer).is_err() { - return Err(anyhow!( - "Error while processing samples:\t{:?}", - encoder.state() - )); - }; - buffer.clear(); - buffer = buffer.into_iter().map(|_| unreachable!()).collect(); - block_buffer = block.into_buffer(); + reader.consume(length); + } else { + break; + } } - Ok(None) => break, Err(error) => return Err(error.into()), } } @@ -99,32 +110,51 @@ fn encode_file(filename: impl AsRef<Path>, handler: Arc<AtomicBool>) -> Result<b if let Err(enc) = encoder.finish() { return Err(anyhow!("Encoding failed:\t{:?}", enc.state())); } - write_tags(&filename)?; - std::fs::rename(temp_name, filename)?; + + metadata::update(&temp_name, |blocklist| { + for block in metadata { + use metadata::Block::*; + match block { + Application(b) => { + let _ = blocklist.insert(b); + } + Picture(b) => { + let _ = blocklist.insert(b); + } + VorbisComment(b) => { + let _ = blocklist.insert(b); + } + Cuesheet(b) => { + let _ = blocklist.insert(b); + } + SeekTable(b) => { + let _ = blocklist.insert(b); + } + _ => {} + } + } + Ok::<(), flac_codec::Error>(()) + })?; + + std::fs::rename(&temp_name, filename)?; + Ok(false) } -pub fn handle_encode(filename: impl AsRef<Path>, handler: Arc<AtomicBool>) -> Result<bool> { - match encode_file(&filename, handler) { +pub fn handle_encode(filename: &Path, handler: Arc<AtomicBool>) -> Result<bool> { + match encode_file(filename, handler) { Err(error) => { - let _ = std::fs::remove_file(filename.as_ref().with_extension("tmp")); + let _ = std::fs::remove_file(filename.with_extension("tmp")); Err(error) } Ok(res) => Ok(res), } } -pub fn get_vendor(file: impl AsRef<Path>) -> Result<String> { - if let Some(vendor) = FlacReader::open_ext( - file, - FlacReaderOptions { - metadata_only: true, - read_vorbis_comment: true, - }, - )? - .vendor() - { - Ok(vendor.to_string()) +pub fn get_vendor(file: &Path) -> Result<String> { + let blocklist = metadata::BlockList::open(file)?; + if let Some(data) = blocklist.get::<metadata::VorbisComment>() { + Ok(data.vendor_string.to_owned()) } else { Err(anyhow!("Vendor string not found")) } @@ -133,17 +163,18 @@ pub fn get_vendor(file: impl AsRef<Path>) -> Result<String> { #[cfg(test)] mod tests { use super::*; + use std::path::PathBuf; #[test] fn bit16() { - let name = "./samples/16bit.flac"; - let tempname = "./samples/16bit.flac.temp"; - std::fs::copy(name, tempname).unwrap(); + let name = PathBuf::from("./samples/16bit.flac"); + let tempname = PathBuf::from("./samples/16bit.flac.temp"); + std::fs::copy(&name, &tempname).unwrap(); let handler = Arc::new(AtomicBool::new(true)); - encode_file(name, handler).unwrap(); + encode_file(&name, handler).unwrap(); let output = std::process::Command::new("flac") .arg("-wts") - .arg(name) + .arg(&name) .status(); std::fs::rename(tempname, name).unwrap(); assert!(output.unwrap().success()); @@ -151,14 +182,14 @@ mod tests { #[test] fn bit24() { - let name = "./samples/24bit.flac"; - let tempname = "./samples/24bit.flac.temp"; - std::fs::copy(name, tempname).unwrap(); + let name = PathBuf::from("./samples/24bit.flac"); + let tempname = PathBuf::from("./samples/24bit.flac.temp"); + std::fs::copy(&name, &tempname).unwrap(); let handler = Arc::new(AtomicBool::new(true)); - encode_file(name, handler).unwrap(); + encode_file(&name, handler).unwrap(); let output = std::process::Command::new("flac") .arg("-wts") - .arg(name) + .arg(&name) .status(); std::fs::rename(tempname, name).unwrap(); assert!(output.unwrap().success()); @@ -166,14 +197,14 @@ mod tests { #[test] fn bit32() { - let name = "./samples/32bit.flac"; - let tempname = "./samples/32bit.flac.temp"; - std::fs::copy(name, tempname).unwrap(); + let name = PathBuf::from("./samples/32bit.flac"); + let tempname = PathBuf::from("./samples/32bit.flac.temp"); + std::fs::copy(&name, &tempname).unwrap(); let handler = Arc::new(AtomicBool::new(true)); - encode_file(name, handler).unwrap(); + encode_file(&name, handler).unwrap(); let output = std::process::Command::new("flac") .arg("-wts") - .arg(name) + .arg(&name) .status(); std::fs::rename(tempname, name).unwrap(); assert!(output.unwrap().success()); |
