Skip to content

Commit

Permalink
fix(content): Only replace / in the frames mentioned in the spec
Browse files Browse the repository at this point in the history
  • Loading branch information
Holzhaus authored and polyfloyd committed Nov 27, 2024
1 parent 22497d9 commit 441dfe1
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 6 deletions.
30 changes: 26 additions & 4 deletions src/stream/frame/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,18 @@ pub fn decode(
Ok(content)
}
"IPLS" | "IPL" | "TMCL" | "TIPL" => decoder.involved_people_list(),
// According to the ID3v2.2.0/ID3v2.3.0 specifications, these text frames may contain
// multiple values that 'are seperated with the "/" character'. Hence, the "/" character is
// replaced with a null byte for these frames, so that the values can be accessed
// separately using the `text_values()` method.
//
// All other frames do not support multiple values in these ID3 versions and therefore their
// contents are read verbatim. Note that when trying to write multiple values, the values
// will be joined using "/" for *all* tags, because the alternative would be to just throw
// an error.
"TCOM" | "TCM" | "TEXT" | "TXT" | "TOLY" | "TOL" | "TOPE" | "TOA" | "TPE1" | "TP1" => {
decoder.text_content_multiple()
}
id if id.starts_with('T') => decoder.text_content(),
id if id.starts_with('W') => decoder.link_content(),
"GRP1" => decoder.text_content(),
Expand Down Expand Up @@ -519,13 +531,23 @@ impl<'a> Decoder<'a> {
},
};
let text = encoding.decode(self.bytes(end)?)?;
let text = match self.version {
Version::Id3v22 | Version::Id3v23 => text.replace('/', "\0"),
Version::Id3v24 => text,
};
Ok(Content::Text(text))
}

fn text_content_multiple(self) -> crate::Result<Content> {
let version = self.version;
self.text_content().map(|content| match content {
Content::Text(text) => {
let text = match version {
Version::Id3v22 | Version::Id3v23 => text.replace('/', "\0"),
Version::Id3v24 => text,
};
Content::Text(text)
}
content => content,
})
}

fn involved_people_list(mut self) -> crate::Result<Content> {
let encoding = self.encoding()?;
let end = match self.version {
Expand Down
2 changes: 1 addition & 1 deletion src/stream/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ mod tests {
tag.set_artist("Artist");
tag.set_genre("Genre");
tag.add_frame(Frame::with_content(
"TPE4",
"TPE1",
Content::new_text_values(["artist 1", "artist 2", "artist 3"]),
));
tag.set_duration(1337);
Expand Down
2 changes: 1 addition & 1 deletion src/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,7 @@ mod tests {
let genres = tag.genres();
let artists = tag.artists();

assert_eq!(genres, Some(vec!["Pop", "Trip-Hop"]));
assert_eq!(genres, Some(vec!["Pop/Trip-Hop"]));
assert_eq!(artists, Some(vec!["First", "Secondary"]));
}

Expand Down

0 comments on commit 441dfe1

Please sign in to comment.