This commit is contained in:
Tianyi 2020-10-27 02:40:57 +00:00
parent dfc8f4f395
commit d2d1bedafa
9 changed files with 115 additions and 40 deletions

View file

@ -1,4 +1,8 @@
## [0.2.2] 2020-10-28
## [0.2.3] 2020-10-27
- multiple artists
## [0.2.2] 2020-10-27
- Conversion between tag types without macro; removed the macro introduced in v0.2.0

View file

@ -1,6 +1,6 @@
[package]
name = "audiotags"
version = "0.2.2"
version = "0.2.3"
authors = ["Tianyi <ShiTianyi2001@outlook.com>"]
edition = "2018"
description = "Unified IO for different types of audio metadata"

View file

@ -87,13 +87,22 @@ fn main() {
mp4tag.write_to_path(M4A_FILE).unwrap();
// reload the tag from the m4a file; this time specifying the tag type (you can also use `default()`)
let mp4tag_reload = Tag::with_tag_type(TagType::Mp4)
let mut mp4tag = Tag::with_tag_type(TagType::Mp4)
.read_from_path(M4A_FILE)
.unwrap();
// the tag originated from an mp3 file is successfully written to an m4a file!
assert_eq!(mp4tag_reload.title(), Some("title from mp3 file"));
assert_eq!(mp4tag.title(), Some("title from mp3 file"));
// multiple artists
mp4tag.add_artist("artist1 of mp4");
mp4tag.add_artist("artist2 of mp4");
assert_eq!(
mp4tag.artists(),
Some(vec!["artist1 of mp4", "artist2 of mp4"])
);
// convert to id3 tag, which does not support multiple artists
let mp3tag = mp4tag.into_tag(TagType::Id3v2);
assert_eq!(mp3tag.artist(), Some("artist1 of mp4;artist2 of mp4"));
}
```
## Supported Formats

View file

@ -9,22 +9,26 @@ impl<'a> From<AnyTag<'a>> for FlacTag {
fn from(inp: AnyTag<'a>) -> Self {
let mut t = FlacTag::default();
inp.title().map(|v| t.set_title(v));
inp.artists().map(|i| {
inp.artists()
.map(|i| {
i.iter().fold(String::new(), |mut v, a| {
v.push_str(&a);
v.push_str(SEP_ARTIST);
v
})
});
})
.map(|v| t.set_artist(&v[..v.len() - 1]));
inp.year.map(|v| t.set_year(v));
inp.album_title().map(|v| t.set_album_title(v));
inp.album_artists().map(|i| {
inp.album_artists()
.map(|i| {
i.iter().fold(String::new(), |mut v, a| {
v.push_str(&a);
v.push_str(SEP_ARTIST);
v
})
});
})
.map(|v| t.set_album_artist(&v[..v.len() - 1]));
inp.track_number().map(|v| t.set_track_number(v));
inp.total_tracks().map(|v| t.set_total_tracks(v));
inp.disc_number().map(|v| t.set_disc_number(v));

View file

@ -64,22 +64,26 @@ impl<'a> From<AnyTag<'a>> for id3::Tag {
fn from(inp: AnyTag<'a>) -> Self {
let mut t = id3::Tag::new();
inp.title().map(|v| t.set_title(v));
inp.artists().map(|i| {
inp.artists()
.map(|i| {
i.iter().fold(String::new(), |mut v, a| {
v.push_str(&a);
v.push_str(SEP_ARTIST);
v
})
});
})
.map(|v| t.set_artist(&v[..v.len() - 1]));
inp.year.map(|v| t.set_year(v));
inp.album_title().map(|v| t.set_album(v));
inp.album_artists().map(|i| {
inp.album_artists()
.map(|i| {
i.iter().fold(String::new(), |mut v, a| {
v.push_str(&a);
v.push_str(SEP_ARTIST);
v
})
});
})
.map(|v| t.set_album_artist(&v[..v.len() - 1]));
inp.track_number().map(|v| t.set_track(v as u32));
inp.total_tracks().map(|v| t.set_total_tracks(v as u32));
inp.disc_number().map(|v| t.set_disc(v as u32));

View file

@ -400,6 +400,13 @@ pub trait AudioTagIo {
fn set_artist(&mut self, artist: &str);
fn remove_artist(&mut self);
fn artists(&self) -> Option<Vec<&str>> {
self.artist().map(|v| vec![v])
}
fn add_artist(&mut self, artist: &str) {
self.set_artist(artist);
}
fn year(&self) -> Option<i32>;
fn set_year(&mut self, year: i32);
fn remove_year(&mut self);
@ -438,6 +445,13 @@ pub trait AudioTagIo {
fn set_album_artist(&mut self, v: &str);
fn remove_album_artist(&mut self);
fn album_artists(&self) -> Option<Vec<&str>> {
self.artist().map(|v| vec![v])
}
fn add_album_artist(&mut self, artist: &str) {
self.set_album_artist(artist);
}
fn album_cover(&self) -> Option<Picture>;
fn set_album_cover(&mut self, cover: Picture);
fn remove_album_cover(&mut self);

View file

@ -117,6 +117,20 @@ impl AudioTagIo for Mp4Tag {
fn set_artist(&mut self, artist: &str) {
self.inner.set_artist(artist)
}
fn artists(&self) -> Option<Vec<&str>> {
let v = self.inner.artists().fold(Vec::new(), |mut v, a| {
v.push(a);
v
});
if v.len() > 0 {
Some(v)
} else {
None
}
}
fn add_artist(&mut self, v: &str) {
self.inner.add_artist(v);
}
fn year(&self) -> Option<i32> {
self.inner.year().and_then(|x| str::parse(x).ok())
@ -139,6 +153,21 @@ impl AudioTagIo for Mp4Tag {
self.inner.set_album_artist(v)
}
fn album_artists(&self) -> Option<Vec<&str>> {
let v = self.inner.album_artists().fold(Vec::new(), |mut v, a| {
v.push(a);
v
});
if v.len() > 0 {
Some(v)
} else {
None
}
}
fn add_album_artist(&mut self, v: &str) {
self.inner.add_album_artist(v);
}
fn album_cover(&self) -> Option<Picture> {
use mp4ameta::Data::*;
self.inner.artwork().and_then(|data| match data {

View file

@ -14,9 +14,19 @@ fn test_convert_mp3_to_mp4() {
mp4tag.write_to_path(M4A_FILE).unwrap();
// reload the tag from the m4a file; this time specifying the tag type (you can also use `default()`)
let mp4tag_reload = Tag::with_tag_type(TagType::Mp4)
let mut mp4tag = Tag::with_tag_type(TagType::Mp4)
.read_from_path(M4A_FILE)
.unwrap();
// the tag originated from an mp3 file is successfully written to an m4a file!
assert_eq!(mp4tag_reload.title(), Some("title from mp3 file"));
assert_eq!(mp4tag.title(), Some("title from mp3 file"));
// multiple artists
mp4tag.add_artist("artist1 of mp4");
mp4tag.add_artist("artist2 of mp4");
assert_eq!(
mp4tag.artists(),
Some(vec!["artist1 of mp4", "artist2 of mp4"])
);
// convert to id3 tag, which does not support multiple artists
let mp3tag = mp4tag.into_tag(TagType::Id3v2);
assert_eq!(mp3tag.artist(), Some("artist1 of mp4;artist2 of mp4"));
}

View file

@ -1,4 +1,5 @@
use audiotags::{MimeType, Picture, Tag};
use beef::lean::Cow;
macro_rules! test_file {
( $function:ident, $file:expr ) => {
@ -35,16 +36,16 @@ macro_rules! test_file {
assert!(tags.album_artist().is_none());
tags.remove_album_artist();
// let cover = Picture {
// mime_type: MimeType::Jpeg,
// data: vec![0u8; 10],
// };
let cover = Picture {
mime_type: MimeType::Jpeg,
data: Cow::owned(vec![0u8; 10]),
};
// tags.set_album_cover(cover.clone());
// assert_eq!(tags.album_cover(), Some(cover));
// tags.remove_album_cover();
// assert!(tags.album_cover().is_none());
// tags.remove_album_cover();
tags.set_album_cover(cover.clone());
assert_eq!(tags.album_cover(), Some(cover));
tags.remove_album_cover();
assert!(tags.album_cover().is_none());
tags.remove_album_cover();
}
};
}