Skip to content

Commit

Permalink
ID3v2: Add Id3v2Tag::remove_user_text
Browse files Browse the repository at this point in the history
  • Loading branch information
Serial-ATA committed Jul 11, 2023
1 parent 58cad46 commit cc338a3
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 3 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **ID3v2**:
- `Id3v2ErrorKind::UnsupportedFrameId` ([PR](https://github.com/Serial-ATA/lofty-rs/pull/212))
- `FrameValue::KeyValue` for TIPL/TMCL frames ([PR](https://github.com/Serial-ATA/lofty-rs/pull/214))
- `Id3v2Tag::get_user_text` and `Id3v2Tag::insert_user_text` for working with TXXX frames ([PR](https://github.com/Serial-ATA/lofty-rs/pull/232))
- `Id3v2Tag::get_user_text`, `Id3v2Tag::insert_user_text`, and `Id3v2Tag::remove_user_text` for working with TXXX frames ([PR](https://github.com/Serial-ATA/lofty-rs/pull/232))
- **ParseOptions**: `ParseOptions::max_junk_bytes`, allowing the parser to sift through junk bytes to find required information, rather than
immediately declare a file invalid. ([discussion](https://github.com/Serial-ATA/lofty-rs/discussions/219)) ([PR](https://github.com/Serial-ATA/lofty-rs/pull/227))
- **WavPack**: `WavPackProperties` now contains the channel mask, accessible through `WavPackProperties::channel_mask()` ([PR](https://github.com/Serial-ATA/lofty-rs/pull/230))
Expand Down
53 changes: 51 additions & 2 deletions src/id3/v2/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,42 @@ impl Id3v2Tag {
replaced
}

/// Removes a user-defined text frame (`TXXX`) by its description
///
/// This will return the matching frame.
///
/// # Examples
///
/// ```rust
/// use lofty::id3::v2::Id3v2Tag;
/// use lofty::TagExt;
///
/// let mut tag = Id3v2Tag::new();
/// assert!(tag.is_empty());
///
/// // Add a new "TXXX" frame identified by "SOME_DESCRIPTION"
/// let _ = tag.insert_user_text(String::from("SOME_DESCRIPTION"), String::from("Some value"));
/// assert!(!tag.is_empty());
///
/// // Now we can remove it by its description
/// let value = tag.remove_user_text("SOME_DESCRIPTION");
/// assert!(tag.is_empty());
/// ```
pub fn remove_user_text(&mut self, description: &str) -> Option<Frame<'static>> {
self.frames
.iter()
.position(|frame| {
matches!(frame, Frame {
value:
FrameValue::UserText(ExtendedTextFrame {
description: desc, ..
}),
..
} if desc == description)
})
.map(|pos| self.frames.remove(pos))
}

/// Removes a [`Frame`] by id
pub fn remove(&mut self, id: &str) {
self.frames.retain(|f| f.id_str() != id)
Expand Down Expand Up @@ -2198,6 +2234,8 @@ mod tests {
fn get_set_user_defined_text() {
let description = String::from("FOO_BAR");
let content = String::from("Baz!\0Qux!");
let description2 = String::from("FOO_BAR_2");
let content2 = String::new();

let mut id3v2 = Id3v2Tag::default();
let txxx_frame = Frame::new(
Expand All @@ -2218,8 +2256,8 @@ mod tests {
"TXXX",
ExtendedTextFrame {
encoding: TextEncoding::UTF8,
description: String::from("FOO_BAR_2"),
content: String::new(),
description: description2.clone(),
content: content2.clone(),
},
FrameFlags::default(),
)
Expand All @@ -2238,6 +2276,17 @@ mod tests {
assert!(id3v2
.insert_user_text(description.clone(), content.clone())
.is_none());
assert!(id3v2
.insert_user_text(description2.clone(), content2.clone())
.is_none());
assert_eq!(id3v2.get_user_text(description.as_str()), Some(&*content));

// Remove one frame
assert!(id3v2.remove_user_text(&description).is_some());
assert!(!id3v2.is_empty());

// Now clear the remaining item
assert!(id3v2.remove_user_text(&description2).is_some());
assert!(id3v2.is_empty());
}
}

0 comments on commit cc338a3

Please sign in to comment.