Update dependencies
This commit is contained in:
@ -1,8 +1,8 @@
|
||||
use std::process;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
|
||||
use structopt::StructOpt;
|
||||
use id3_image::embed_image;
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(name = "id3-image-embed")]
|
||||
@ -28,8 +28,9 @@ fn main() {
|
||||
let opt = Opt::from_args();
|
||||
let verbosity = if opt.quiet { -1 } else { opt.verbose };
|
||||
let music_filename = opt.music_filename;
|
||||
let image_filename = opt.image_filename.
|
||||
unwrap_or_else(|| music_filename.with_extension("jpg"));
|
||||
let image_filename = opt
|
||||
.image_filename
|
||||
.unwrap_or_else(|| music_filename.with_extension("jpg"));
|
||||
|
||||
if let Err(e) = embed_image(&music_filename, &image_filename) {
|
||||
if verbosity >= 0 {
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::process;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
|
||||
use structopt::StructOpt;
|
||||
use id3_image::extract_first_image;
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(name = "id3-image-embed")]
|
||||
@ -28,8 +28,10 @@ fn main() {
|
||||
let opt = Opt::from_args();
|
||||
let verbosity = if opt.quiet { -1 } else { opt.verbose };
|
||||
|
||||
let image_filename = opt.image_filename.clone().
|
||||
unwrap_or_else(|| opt.music_filename.with_extension("jpg"));
|
||||
let image_filename = opt
|
||||
.image_filename
|
||||
.clone()
|
||||
.unwrap_or_else(|| opt.music_filename.with_extension("jpg"));
|
||||
|
||||
if let Err(e) = extract_first_image(&opt.music_filename, &image_filename) {
|
||||
if verbosity >= 0 {
|
||||
@ -43,6 +45,9 @@ fn main() {
|
||||
println!("{}", image_filename.display());
|
||||
} else if verbosity >= 2 {
|
||||
// show a longer status message:
|
||||
println!("Extracted cover art from {:?} to {:?}", opt.music_filename, image_filename);
|
||||
println!(
|
||||
"Extracted cover art from {:?} to {:?}",
|
||||
opt.music_filename, image_filename
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::process;
|
||||
use std::io::{self, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
|
||||
use structopt::StructOpt;
|
||||
use id3_image::remove_images;
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
#[structopt(name = "id3-image-remove")]
|
||||
|
51
src/lib.rs
51
src/lib.rs
@ -3,9 +3,11 @@
|
||||
//! A command-line tool to embed images into mp3 files. The real work is done by the "id3" crate,
|
||||
//! but this project makes it easier to deal with embedded cover art in particular.
|
||||
|
||||
use std::io::Cursor;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use id3::TagLike;
|
||||
use image::DynamicImage;
|
||||
|
||||
/// Embed the image from `image_filename` into `music_filename`, in-place. Any errors reading ID3
|
||||
@ -15,8 +17,8 @@ use image::DynamicImage;
|
||||
/// Tags get written as ID3v2.3.
|
||||
///
|
||||
pub fn embed_image(music_filename: &Path, image_filename: &Path) -> anyhow::Result<()> {
|
||||
let image = image::open(&image_filename).
|
||||
map_err(|e| anyhow!("Error reading image {:?}: {}", image_filename, e))?;
|
||||
let image = image::open(&image_filename)
|
||||
.map_err(|e| anyhow!("Error reading image {:?}: {}", image_filename, e))?;
|
||||
|
||||
embed_image_from_memory(music_filename, &image)
|
||||
}
|
||||
@ -27,22 +29,33 @@ pub fn embed_image(music_filename: &Path, image_filename: &Path) -> anyhow::Resu
|
||||
/// The image is encoded as a JPEG with a 90% quality setting, and embedded as a "Front cover".
|
||||
/// Tags get written as ID3v2.3.
|
||||
///
|
||||
pub fn embed_image_from_memory(music_filename: &Path, image: &image::DynamicImage) -> anyhow::Result<()> {
|
||||
pub fn embed_image_from_memory(
|
||||
music_filename: &Path,
|
||||
image: &image::DynamicImage,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut tag = read_tag(music_filename)?;
|
||||
|
||||
let mut encoded_image_bytes = Vec::new();
|
||||
let mut encoded_image_bytes = Cursor::new(Vec::new());
|
||||
// Unwrap: Writing to a Vec should always succeed;
|
||||
image.write_to(&mut encoded_image_bytes, image::ImageOutputFormat::Jpeg(90)).unwrap();
|
||||
image
|
||||
.write_to(&mut encoded_image_bytes, image::ImageOutputFormat::Jpeg(90))
|
||||
.unwrap();
|
||||
|
||||
tag.add_picture(id3::frame::Picture {
|
||||
tag.add_frame(id3::frame::Picture {
|
||||
mime_type: "image/jpeg".to_string(),
|
||||
picture_type: id3::frame::PictureType::CoverFront,
|
||||
description: String::new(),
|
||||
data: encoded_image_bytes,
|
||||
data: encoded_image_bytes.into_inner(),
|
||||
});
|
||||
|
||||
tag.write_to_path(music_filename, id3::Version::Id3v23).
|
||||
map_err(|e| anyhow!("Error writing image to music file {:?}: {}", music_filename, e))?;
|
||||
tag.write_to_path(music_filename, id3::Version::Id3v23)
|
||||
.map_err(|e| {
|
||||
anyhow!(
|
||||
"Error writing image to music file {:?}: {}",
|
||||
music_filename,
|
||||
e
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -55,8 +68,8 @@ pub fn embed_image_from_memory(music_filename: &Path, image: &image::DynamicImag
|
||||
///
|
||||
pub fn extract_first_image(music_filename: &Path, image_filename: &Path) -> anyhow::Result<()> {
|
||||
extract_first_image_as_img(music_filename)?
|
||||
.save(&image_filename).
|
||||
map_err(|e| anyhow!("Couldn't write image file {:?}: {}", image_filename, e))
|
||||
.save(&image_filename)
|
||||
.map_err(|e| anyhow!("Couldn't write image file {:?}: {}", image_filename, e))
|
||||
}
|
||||
|
||||
/// Extract the first found embedded image from `music_filename` and return it as image object
|
||||
@ -69,8 +82,7 @@ pub fn extract_first_image_as_img(music_filename: &Path) -> anyhow::Result<Dynam
|
||||
let first_picture = tag.pictures().next();
|
||||
|
||||
if let Some(p) = first_picture {
|
||||
return image::load_from_memory(&p.data)
|
||||
.map_err(|e| anyhow!("Couldn't load image: {}", e));
|
||||
return image::load_from_memory(&p.data).map_err(|e| anyhow!("Couldn't load image: {}", e));
|
||||
} else {
|
||||
Err(anyhow!("No image found in music file"))
|
||||
}
|
||||
@ -85,15 +97,20 @@ pub fn remove_images(music_filename: &Path) -> anyhow::Result<()> {
|
||||
let mut tag = read_tag(music_filename)?;
|
||||
tag.remove("APIC");
|
||||
|
||||
tag.write_to_path(music_filename, id3::Version::Id3v23).
|
||||
map_err(|e| anyhow!("Error updating music file {:?}: {}", music_filename, e))?;
|
||||
tag.write_to_path(music_filename, id3::Version::Id3v23)
|
||||
.map_err(|e| anyhow!("Error updating music file {:?}: {}", music_filename, e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_tag(path: &Path) -> anyhow::Result<id3::Tag> {
|
||||
id3::Tag::read_from_path(&path).or_else(|e| {
|
||||
eprintln!("Warning: file metadata is corrupted, trying to read partial tag: {}", path.display());
|
||||
e.partial_tag.clone().ok_or_else(|| anyhow!("Error reading music file {:?}: {}", path, e))
|
||||
eprintln!(
|
||||
"Warning: file metadata is corrupted, trying to read partial tag: {}",
|
||||
path.display()
|
||||
);
|
||||
e.partial_tag
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("Error reading music file {:?}: {}", path, e))
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user