Skip to content

Commit

Permalink
MP4: Merge existing atoms in Ilst::insert
Browse files Browse the repository at this point in the history
Now, when inserting an atom that already exists in a tag, the data is taken from the provided atom and merged with the existing value in the tag. This should ensure that the value that already exists in the tag will remain the dominant one.
  • Loading branch information
Serial-ATA committed Jul 25, 2023
1 parent acc3c9f commit e622a67
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **MP4**:
- `Ilst::remove` will now return all of the removed atoms
- `Ilst::insert_picture` will now combine all pictures into a single `covr` atom
- `Ilst::insert` will now merge atoms with the same identifier into a single atom

## [0.15.0] - 2023-07-11

Expand Down
33 changes: 31 additions & 2 deletions src/mp4/ilst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ impl Ilst {

/// Inserts an [`Atom`]
///
/// NOTE: Do not use this to replace atoms. This will take the value from the provided atom and
/// merge it into an atom of the same type, keeping any existing value(s). To ensure an atom
/// is replaced, use [`Ilst::replace_atom`].
///
/// # Examples
///
/// ```rust
Expand All @@ -142,7 +146,8 @@ impl Ilst {
/// let title = ilst.get(&TITLE_IDENTIFIER);
/// assert!(title.is_some());
/// ```
pub fn insert(&mut self, atom: Atom<'_>) {
#[allow(clippy::missing_panics_doc)] // Unwrap on an infallible
pub fn insert(&mut self, atom: Atom<'static>) {
if atom.ident == COVR && atom.data.is_pictures() {
for data in atom.data {
match data {
Expand All @@ -153,7 +158,14 @@ impl Ilst {
return;
}

self.atoms.push(atom.into_owned());
if let Some(existing) = self.get_mut(atom.ident()) {
existing.merge(atom).expect(
"Somehow the atom merge condition failed, despite the validation beforehand.",
);
return;
}

self.atoms.push(atom);
}

/// Inserts an [`Atom`], replacing any atom with the same [`AtomIdent`]
Expand Down Expand Up @@ -752,6 +764,7 @@ impl From<Tag> for Ilst {
#[cfg(test)]
mod tests {
use crate::mp4::ilst::atom::AtomDataStorage;
use crate::mp4::ilst::TITLE;
use crate::mp4::read::AtomReader;
use crate::mp4::{AdvisoryRating, Atom, AtomData, AtomIdent, Ilst, Mp4File};
use crate::tag::utils::test_utils;
Expand Down Expand Up @@ -1156,4 +1169,20 @@ mod tests {

assert_eq!(file.ilst(), Some(&Ilst::default()));
}

#[test]
fn merge_insert() {
let mut ilst = Ilst::new();

// Insert two titles
ilst.set_title(String::from("Foo"));
ilst.insert(Atom::new(TITLE, AtomData::UTF8(String::from("Bar"))));

// Title should still be the first value, but there should be two total values
assert_eq!(ilst.title().as_deref(), Some("Foo"));
assert_eq!(ilst.get(&TITLE).unwrap().data().count(), 2);

// Meaning we only have 1 atom
assert_eq!(ilst.len(), 1);
}
}

0 comments on commit e622a67

Please sign in to comment.