mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-11-10 06:34:18 +00:00
Add tag_writer
example
This commit is contained in:
parent
2273e4608f
commit
ea0f3007e8
4 changed files with 149 additions and 8 deletions
|
@ -32,6 +32,7 @@ riff_info_list = []
|
|||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3.5", features = ["html_reports"] }
|
||||
structopt = { version = "0.3.25", default-features = false }
|
||||
tempfile = "3.2.0"
|
||||
|
||||
[[bench]]
|
||||
|
|
|
@ -12,7 +12,7 @@ fn main() {
|
|||
let tags = tagged_file.tags();
|
||||
|
||||
if tags.is_empty() {
|
||||
println!("No tags found, exiting.");
|
||||
eprintln!("No tags found, exiting.");
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
|
@ -45,14 +45,14 @@ fn main() {
|
|||
}
|
||||
|
||||
input.clear();
|
||||
println!("Bad input")
|
||||
eprintln!("ERROR: Unexpected input")
|
||||
}
|
||||
|
||||
let tag_remove = available_tag_types[to_remove.unwrap()];
|
||||
|
||||
if tag_remove.remove_from_path(path) {
|
||||
println!("Removed tag: {:?}", tag_remove);
|
||||
println!("INFO: Removed tag: `{:?}`", tag_remove);
|
||||
} else {
|
||||
println!("Failed to remove the tag")
|
||||
eprintln!("ERROR: Failed to remove the tag")
|
||||
}
|
||||
}
|
||||
|
|
83
examples/tag_writer.rs
Normal file
83
examples/tag_writer.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
use lofty::{Accessor, Probe, Tag};
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "tag_writer", about = "A simple tag writer example")]
|
||||
struct Opt {
|
||||
#[structopt(short, long)]
|
||||
title: Option<String>,
|
||||
|
||||
#[structopt(short, long)]
|
||||
artist: Option<String>,
|
||||
|
||||
#[structopt(short = "A", long)]
|
||||
album: Option<String>,
|
||||
|
||||
#[structopt(short, long)]
|
||||
genre: Option<String>,
|
||||
|
||||
#[structopt(short, long)]
|
||||
path: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let opt = Opt::from_args();
|
||||
|
||||
let mut tagged_file = Probe::open(opt.path.as_str())
|
||||
.expect("Error: Bad path provided!")
|
||||
.read()
|
||||
.expect("Error: Failed to read file!");
|
||||
|
||||
let tag = match tagged_file.primary_tag_mut() {
|
||||
Some(primary_tag) => primary_tag,
|
||||
None => {
|
||||
if let Some(first_tag) = tagged_file.first_tag_mut() {
|
||||
first_tag
|
||||
} else {
|
||||
let tag_type = tagged_file.primary_tag_type();
|
||||
|
||||
eprintln!(
|
||||
"WARN: No tags found, creating a new tag of type `{:?}`",
|
||||
tag_type
|
||||
);
|
||||
tagged_file.insert_tag(Tag::new(tag_type));
|
||||
|
||||
tagged_file.primary_tag_mut().unwrap()
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if let Opt {
|
||||
title: None,
|
||||
artist: None,
|
||||
album: None,
|
||||
genre: None,
|
||||
..
|
||||
} = opt
|
||||
{
|
||||
eprintln!("ERROR: No options provided!");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if let Some(title) = opt.title {
|
||||
tag.set_title(title)
|
||||
}
|
||||
|
||||
if let Some(artist) = opt.artist {
|
||||
tag.set_artist(artist)
|
||||
}
|
||||
|
||||
if let Some(album) = opt.album {
|
||||
tag.set_album(album)
|
||||
}
|
||||
|
||||
if let Some(genre) = opt.genre {
|
||||
tag.set_genre(genre)
|
||||
}
|
||||
|
||||
tag.save_to_path(opt.path)
|
||||
.expect("ERROR: Failed to write the tag!");
|
||||
|
||||
println!("INFO: Tag successfully updated!");
|
||||
}
|
|
@ -4,6 +4,7 @@ use crate::error::{LoftyError, Result};
|
|||
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Seek};
|
||||
use std::path::Path;
|
||||
|
||||
|
@ -53,18 +54,21 @@ impl TaggedFile {
|
|||
/// | `FLAC`, `Opus`, `Vorbis` | `VorbisComments` |
|
||||
/// | `MP4` | `Mp4Ilst` |
|
||||
pub fn primary_tag(&self) -> Option<&Tag> {
|
||||
self.tag(&Self::primary_tag_type(self.ty))
|
||||
self.tag(&self.primary_tag_type())
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the file's "Primary tag"
|
||||
///
|
||||
/// See [`primary_tag`](Self::primary_tag) for an explanation
|
||||
pub fn primary_tag_mut(&mut self) -> Option<&mut Tag> {
|
||||
self.tag_mut(&Self::primary_tag_type(self.ty))
|
||||
self.tag_mut(&self.primary_tag_type())
|
||||
}
|
||||
|
||||
fn primary_tag_type(f_ty: FileType) -> TagType {
|
||||
match f_ty {
|
||||
/// Returns the file type's "primary" [`TagType`]
|
||||
///
|
||||
/// See [`primary_tag`](Self::primary_tag) for an explanation
|
||||
pub fn primary_tag_type(&self) -> TagType {
|
||||
match self.ty {
|
||||
#[cfg(feature = "id3v2")]
|
||||
FileType::AIFF | FileType::MP3 | FileType::WAV => TagType::Id3v2,
|
||||
#[cfg(feature = "ape")]
|
||||
|
@ -76,6 +80,11 @@ impl TaggedFile {
|
|||
}
|
||||
}
|
||||
|
||||
/// Determines whether the file supports the given [`TagType`]
|
||||
pub fn supports_tag_type(&self, tag_type: TagType) -> bool {
|
||||
self.ty.supports_tag_type(&tag_type)
|
||||
}
|
||||
|
||||
/// Returns all tags
|
||||
pub fn tags(&self) -> &[Tag] {
|
||||
self.tags.as_slice()
|
||||
|
@ -101,6 +110,32 @@ impl TaggedFile {
|
|||
self.tags.iter_mut().find(|i| i.tag_type() == tag_type)
|
||||
}
|
||||
|
||||
/// Inserts a [`Tag`]
|
||||
///
|
||||
/// If a tag is replaced, it will be returned
|
||||
pub fn insert_tag(&mut self, tag: Tag) -> Option<Tag> {
|
||||
let tag_type = *tag.tag_type();
|
||||
|
||||
if self.supports_tag_type(tag_type) {
|
||||
let ret = self.remove_tag(tag_type);
|
||||
self.tags.push(tag);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Removes a specific [`TagType`]
|
||||
///
|
||||
/// This will return the tag if it is removed
|
||||
pub fn remove_tag(&mut self, tag_type: TagType) -> Option<Tag> {
|
||||
self.tags
|
||||
.iter()
|
||||
.position(|t| t.tag_type() == &tag_type)
|
||||
.map(|pos| self.tags.remove(pos))
|
||||
}
|
||||
|
||||
/// Returns the file's [`FileType`]
|
||||
pub fn file_type(&self) -> &FileType {
|
||||
&self.ty
|
||||
|
@ -110,6 +145,28 @@ impl TaggedFile {
|
|||
pub fn properties(&self) -> &FileProperties {
|
||||
&self.properties
|
||||
}
|
||||
|
||||
/// Attempts to write all tags to a path
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// See [TaggedFile::save_to]
|
||||
pub fn save_to_path(&self, path: impl AsRef<Path>) -> Result<()> {
|
||||
self.save_to(&mut OpenOptions::new().read(true).write(true).open(path)?)
|
||||
}
|
||||
|
||||
/// Attempts to write all tags to a file
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// See [`Tag::save_to`], however this is applicable to every tag in the `TaggedFile`.
|
||||
pub fn save_to(&self, file: &mut File) -> Result<()> {
|
||||
for tag in &self.tags {
|
||||
tag.save_to(file)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Copy, Clone, Debug)]
|
||||
|
|
Loading…
Reference in a new issue