Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ItemKey: Add ItemKey::TrackArtists #454

Merged
merged 3 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- **ItemKey**: `ItemKey::TrackArtists`, available for ID3v2, Vorbis Comments, APE, and MP4 Ilst ([PR](https://github.com/Serial-ATA/lofty-rs/issues/454))
- This is a multi-value item that stores each artist for a track. It should be retrieved with `Tag::get_strings` or `Tag::take_strings`.
- For example, a track has `ItemKey::TrackArtist` = "Foo & Bar", then `ItemKey::TrackArtists` = ["Foo", "Bar"].
- See <https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html#artists>

### Fixed
- **MusePack**: Fix potential panic when the beginning silence makes up the entire sample count ([PR](https://github.com/Serial-ATA/lofty-rs/pull/449))
- **Timestamp**: Support timestamps without separators (ex. "20240906" vs "2024-09-06") ([issue](https://github.com/Serial-ATA/lofty-rs/issues/452)) ([PR](https://github.com/Serial-ATA/lofty-rs/issues/453))
- **ID3v2**: `ItemKey::Director` will now be written correctly as a TXXX frame ([PR](https://github.com/Serial-ATA/lofty-rs/issues/454))

## [0.21.1] - 2024-08-28

Expand Down
19 changes: 18 additions & 1 deletion lofty/src/id3/v2/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1379,7 +1379,6 @@ impl MergeTag for SplitTagRemainder {
&ItemKey::Composer,
&ItemKey::Conductor,
&ItemKey::Writer,
&ItemKey::Director,
&ItemKey::Lyricist,
&ItemKey::MusicianCredits,
&ItemKey::InternetRadioStationName,
Expand All @@ -1402,6 +1401,23 @@ impl MergeTag for SplitTagRemainder {
}
}

// Multi-valued TXXX key-to-frame mappings
for item_key in [
&ItemKey::TrackArtists,
&ItemKey::Director,
&ItemKey::CatalogNumber,
] {
let frame_id = item_key
.map_key(TagType::Id3v2, false)
.expect("valid frame id");
if let Some(text) = join_text_items(&mut tag, [item_key]) {
let frame = new_user_text_frame(String::from(frame_id), text);
// Optimization: No duplicate checking according to the preconditions
debug_assert!(!merged.frames.contains(&frame));
merged.frames.push(frame);
}
}

// Multi-valued Label/Publisher key-to-frame mapping
{
let frame_id = ItemKey::Label
Expand Down Expand Up @@ -1507,6 +1523,7 @@ impl MergeTag for SplitTagRemainder {
));
}

// iTunes advisory rating
'rate: {
if let Some(advisory_rating) = tag.take_strings(&ItemKey::ParentalAdvisory).next() {
let Ok(rating) = advisory_rating.parse::<u8>() else {
Expand Down
20 changes: 20 additions & 0 deletions lofty/src/id3/v2/tag/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1534,3 +1534,23 @@ fn split_tdrc_on_id3v23_save() {
.expect("Expected TIME frame");
assert_eq!(time, "1408");
}

#[test_log::test]
fn artists_tag_conversion() {
const ARTISTS: &[&str] = &["Foo", "Bar", "Baz"];

let mut tag = Tag::new(TagType::Id3v2);

for artist in ARTISTS {
tag.push(TagItem::new(
ItemKey::TrackArtists,
ItemValue::Text((*artist).to_string()),
));
}

let tag: Id3v2Tag = tag.into();
let txxx_artists = tag.get_user_text("ARTISTS").unwrap();
let id3v2_artists = txxx_artists.split('\0').collect::<Vec<_>>();

assert_eq!(id3v2_artists, ARTISTS);
}
12 changes: 12 additions & 0 deletions lofty/src/tag/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ gen_map!(
"ARTISTSORT" => TrackArtistSortOrder,
"Album Artist" | "ALBUMARTIST" => AlbumArtist,
"Artist" => TrackArtist,
"Artists" => TrackArtists,
"Arranger" => Arranger,
"Writer" => Writer,
"Composer" => Composer,
Expand Down Expand Up @@ -154,6 +155,7 @@ gen_map!(
"TSOC" => ComposerSortOrder,
"TPE2" => AlbumArtist,
"TPE1" => TrackArtist,
"ARTISTS" => TrackArtists,
"TEXT" => Writer,
"TCOM" => Composer,
"TPE3" => Conductor,
Expand Down Expand Up @@ -249,6 +251,7 @@ gen_map!(
"soco" => ComposerSortOrder,
"aART" => AlbumArtist,
"\u{a9}ART" => TrackArtist,
"----:com.apple.iTunes:ARTISTS" => TrackArtists,
"\u{a9}wrt" => Composer,
"\u{a9}dir" => Director,
"----:com.apple.iTunes:CONDUCTOR" => Conductor,
Expand Down Expand Up @@ -349,6 +352,7 @@ gen_map!(
"ARTISTSORT" => TrackArtistSortOrder,
"ALBUMARTIST" => AlbumArtist,
"ARTIST" => TrackArtist,
"ARTISTS" => TrackArtists,
"ARRANGER" => Arranger,
"AUTHOR" | "WRITER" => Writer,
"COMPOSER" => Composer,
Expand Down Expand Up @@ -520,6 +524,14 @@ gen_item_keys!(
// People & Organizations
AlbumArtist,
TrackArtist,
/// The name of each credited artist
///
/// This tag is meant to appear multiple times in a tag, so it should be retrieved with
/// [`Tag::get_strings`] or [`Tag::take_strings`].
///
/// [`Tag::get_strings`]: crate::tag::Tag::get_strings
/// [`Tag::take_strings`]: crate::tag::Tag::take_strings
TrackArtists,
Arranger,
Writer,
Composer,
Expand Down