CLI options, and better path/string handling
This commit is contained in:
parent
711314fe57
commit
432ee8f8b6
@ -1,21 +1,33 @@
|
||||
use std::env;
|
||||
use std::process;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use structopt::StructOpt;
|
||||
use id3_image::embed_image;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(name = "id3-image-embed")]
|
||||
struct Opt {
|
||||
/// Verbose mode (-v, -vv, -vvv, etc.)
|
||||
#[structopt(short = "v", long = "verbose", parse(from_occurrences))]
|
||||
verbose: u8,
|
||||
|
||||
/// Music file to embed image into
|
||||
#[structopt(name = "music-file.mp3", required = true, parse(from_os_str))]
|
||||
music_filename: PathBuf,
|
||||
|
||||
/// Image file to embed
|
||||
#[structopt(name = "image-file.jpg", required = true, parse(from_os_str))]
|
||||
image_filename: PathBuf,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<_> = env::args().collect();
|
||||
let opt = Opt::from_args();
|
||||
|
||||
if args.len() < 3 {
|
||||
eprintln!("USAGE: id3-image-embed <mp3-file> <image-file>");
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let music_filename = args[1].clone();
|
||||
let image_filename = args[2].clone();
|
||||
|
||||
if let Err(e) = embed_image(&music_filename, &image_filename) {
|
||||
if let Err(e) = embed_image(&opt.music_filename, &opt.image_filename) {
|
||||
eprintln!("{}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
if opt.verbose >= 1 {
|
||||
println!("Embedded {:?} into {:?}", opt.image_filename, opt.music_filename);
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,41 @@
|
||||
use std::env;
|
||||
use std::process;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use structopt::StructOpt;
|
||||
use id3_image::extract_image;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(name = "id3-image-embed")]
|
||||
struct Opt {
|
||||
/// Verbose mode (-v, -vv, -vvv, etc.)
|
||||
#[structopt(short = "v", long = "verbose", parse(from_occurrences))]
|
||||
verbose: u8,
|
||||
|
||||
/// Music file to extract image from
|
||||
#[structopt(name = "music-file.mp3", required = true, parse(from_os_str))]
|
||||
music_filename: PathBuf,
|
||||
|
||||
/// (Optional) Output image: defaults to music filename with .jpg extension
|
||||
#[structopt(name = "image-file.jpg", parse(from_os_str))]
|
||||
image_filename: Option<PathBuf>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<_> = env::args().collect();
|
||||
let opt = Opt::from_args();
|
||||
|
||||
if args.len() < 2 {
|
||||
eprintln!("USAGE: id3-image-extract <mp3-file> [image-file]");
|
||||
process::exit(1);
|
||||
}
|
||||
let image_filename = opt.image_filename.clone().
|
||||
unwrap_or_else(|| opt.music_filename.with_extension("jpg"));
|
||||
|
||||
let music_filename = args[1].clone();
|
||||
let image_filename = args.get(2).cloned().unwrap_or_else(|| replace_extension(&music_filename, "jpg"));
|
||||
|
||||
if let Err(e) = extract_image(&music_filename, &image_filename) {
|
||||
if let Err(e) = extract_image(&opt.music_filename, &image_filename) {
|
||||
eprintln!("{}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_extension(path: &str, replacement: &str) -> String {
|
||||
let mut path = PathBuf::from(&path);
|
||||
path.set_extension(replacement);
|
||||
path.to_string_lossy().to_string()
|
||||
if opt.verbose == 1 {
|
||||
// then just print the output filename for scripting purposes:
|
||||
println!("{}", image_filename.display());
|
||||
} else if opt.verbose >= 2 {
|
||||
// show a longer status message:
|
||||
println!("Extracted cover art from {:?} to {:?}", opt.music_filename, image_filename);
|
||||
}
|
||||
}
|
||||
|
22
src/lib.rs
22
src/lib.rs
@ -1,11 +1,12 @@
|
||||
use std::path::Path;
|
||||
use std::error::Error;
|
||||
|
||||
pub fn embed_image(music_filename: &str, image_filename: &str) -> Result<(), Box<Error>> {
|
||||
pub fn embed_image(music_filename: &Path, image_filename: &Path) -> Result<(), Box<Error>> {
|
||||
let mut tag = id3::Tag::read_from_path(&music_filename).
|
||||
map_err(|e| format!("Error reading music file {}: {}", music_filename, e))?;
|
||||
map_err(|e| format!("Error reading music file {:?}: {}", music_filename, e))?;
|
||||
|
||||
let image = image::open(&image_filename).
|
||||
map_err(|e| format!("Error reading image {}: {}", image_filename, e))?;
|
||||
map_err(|e| format!("Error reading image {:?}: {}", image_filename, e))?;
|
||||
|
||||
let mut encoded_image_bytes = Vec::new();
|
||||
// Unwrap: Writing to a Vec should always succeed;
|
||||
@ -19,14 +20,14 @@ pub fn embed_image(music_filename: &str, image_filename: &str) -> Result<(), Box
|
||||
});
|
||||
|
||||
tag.write_to_path(music_filename, id3::Version::Id3v23).
|
||||
map_err(|e| format!("Error writing image to music file {}: {}", music_filename, e))?;
|
||||
map_err(|e| format!("Error writing image to music file {:?}: {}", music_filename, e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn extract_image(music_filename: &str, image_filename: &str) -> Result<(), Box<Error>> {
|
||||
pub fn extract_image(music_filename: &Path, image_filename: &Path) -> Result<(), Box<Error>> {
|
||||
let tag = id3::Tag::read_from_path(&music_filename).
|
||||
map_err(|e| format!("Error reading music file {}: {}", music_filename, e))?;
|
||||
map_err(|e| format!("Error reading music file {:?}: {}", music_filename, e))?;
|
||||
|
||||
let first_picture = tag.pictures().next();
|
||||
|
||||
@ -34,8 +35,7 @@ pub fn extract_image(music_filename: &str, image_filename: &str) -> Result<(), B
|
||||
match image::load_from_memory(&p.data) {
|
||||
Ok(image) => {
|
||||
image.save(&image_filename).
|
||||
map_err(|e| format!("Couldn't write image file {}: {}", image_filename, e))?;
|
||||
println!("{}", image_filename);
|
||||
map_err(|e| format!("Couldn't write image file {:?}: {}", image_filename, e))?;
|
||||
},
|
||||
Err(e) => return Err(format!("Couldn't load image: {}", e).into()),
|
||||
};
|
||||
@ -44,14 +44,14 @@ pub fn extract_image(music_filename: &str, image_filename: &str) -> Result<(), B
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_images(music_filename: &str) -> Result<(), Box<Error>> {
|
||||
pub fn remove_images(music_filename: &Path) -> Result<(), Box<Error>> {
|
||||
let mut tag = id3::Tag::read_from_path(&music_filename).
|
||||
map_err(|e| format!("Error reading music file {}: {}", music_filename, e))?;
|
||||
map_err(|e| format!("Error reading music file {:?}: {}", music_filename, e))?;
|
||||
|
||||
tag.remove("APIC");
|
||||
|
||||
tag.write_to_path(music_filename, id3::Version::Id3v23).
|
||||
map_err(|e| format!("Error updating music file {}: {}", music_filename, e))?;
|
||||
map_err(|e| format!("Error updating music file {:?}: {}", music_filename, e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -18,10 +18,10 @@ impl AsRef<Path> for Fixture {
|
||||
}
|
||||
|
||||
impl Deref for Fixture {
|
||||
type Target = str;
|
||||
type Target = Path;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.path_buf.to_str().unwrap()
|
||||
self.path_buf.deref()
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ macro_rules! fixture {
|
||||
}
|
||||
}
|
||||
|
||||
fn read_tag(path: &str) -> id3::Tag {
|
||||
fn read_tag(path: &Path) -> id3::Tag {
|
||||
id3::Tag::read_from_path(path).unwrap()
|
||||
}
|
||||
|
||||
@ -54,9 +54,9 @@ fn test_unsuccessful_image_embedding() {
|
||||
let image = fixture!("attempt_1.jpg");
|
||||
|
||||
// Nonexistent files
|
||||
assert!(embed_image(&song, "nonexisting.jpg").is_err());
|
||||
assert!(embed_image("nonexisting.mp3", &image).is_err());
|
||||
assert!(embed_image("nonexisting.mp3", "nonexisting.jpg").is_err());
|
||||
assert!(embed_image(&song, &PathBuf::from("nonexistent.jpg")).is_err());
|
||||
assert!(embed_image(&PathBuf::from("nonexistent.mp3"), &image).is_err());
|
||||
assert!(embed_image(&PathBuf::from("nonexistent.mp3"), &PathBuf::from("nonexistent.jpg")).is_err());
|
||||
|
||||
// Wrong kinds of files
|
||||
assert!(embed_image(&image, &song).is_err());
|
||||
|
Loading…
Reference in New Issue
Block a user