Tag: Preserve Ilst special items by default

This commit is contained in:
Serial 2024-05-01 13:04:17 -04:00 committed by Alex
parent 843fc0d666
commit 4b2fc06192
4 changed files with 94 additions and 6 deletions

View file

@ -1288,4 +1288,14 @@ fn special_items_roundtrip() {
let tag_re_read = read_tag_raw(&tag_bytes[..]);
assert_eq!(tag, tag_re_read);
// Now write from `Tag`
let tag: Tag = tag.into();
let mut tag_bytes = Vec::new();
tag.dump_to(&mut tag_bytes, WriteOptions::default())
.unwrap();
let generic_tag_re_read = read_tag_raw(&tag_bytes[..]);
assert_eq!(tag_re_read, generic_tag_re_read);
}

View file

@ -5,10 +5,11 @@ mod r#ref;
pub(crate) mod write;
use super::AtomIdent;
use crate::config::WriteOptions;
use crate::config::{global_options, WriteOptions};
use crate::error::LoftyError;
use crate::mp4::ilst::atom::AtomDataStorage;
use crate::picture::{Picture, PictureType, TOMBSTONE_PICTURE};
use crate::tag::companion_tag::CompanionTag;
use crate::tag::{
try_parse_year, Accessor, ItemKey, ItemValue, MergeTag, SplitTag, Tag, TagExt, TagItem, TagType,
};
@ -771,12 +772,24 @@ impl MergeTag for SplitTagRemainder {
impl From<Ilst> for Tag {
fn from(input: Ilst) -> Self {
input.split_tag().1
let (remainder, mut tag) = input.split_tag();
if unsafe { global_options().preserve_format_specific_items } && remainder.0.len() > 0 {
tag.companion_tag = Some(CompanionTag::Ilst(remainder.0));
}
tag
}
}
impl From<Tag> for Ilst {
fn from(input: Tag) -> Self {
fn from(mut input: Tag) -> Self {
if unsafe { global_options().preserve_format_specific_items } {
if let Some(companion) = input.companion_tag.take().and_then(CompanionTag::ilst) {
return SplitTagRemainder(companion).merge_tag(input);
}
}
SplitTagRemainder::default().merge_tag(input)
}
}
@ -797,9 +810,13 @@ mod tests {
fn read_ilst(path: &str, parse_mode: ParsingMode) -> Ilst {
let tag = std::fs::read(path).unwrap();
let len = tag.len();
read_ilst_raw(&tag, parse_mode)
}
let cursor = Cursor::new(tag);
fn read_ilst_raw(bytes: &[u8], parse_mode: ParsingMode) -> Ilst {
let len = bytes.len();
let cursor = Cursor::new(bytes);
let mut reader = AtomReader::new(cursor, parse_mode).unwrap();
super::read::parse_ilst(&mut reader, parse_mode, len as u64).unwrap()
@ -1273,4 +1290,52 @@ mod tests {
&AtomData::Bool(false)
);
}
#[test]
fn special_items_roundtrip() {
let mut tag = Ilst::new();
let atom = Atom::new(
AtomIdent::Fourcc(*b"SMTH"),
AtomData::Unknown {
code: 0,
data: b"Meaningless Data".to_vec(),
},
);
tag.insert(atom.clone());
tag.set_artist(String::from("Foo Artist")); // Some value that we *can* represent generically
let tag: Tag = tag.into();
assert_eq!(tag.len(), 1);
assert_eq!(tag.artist().as_deref(), Some("Foo Artist"));
let tag: Ilst = tag.into();
assert_eq!(tag.atoms.len(), 2);
assert_eq!(tag.artist().as_deref(), Some("Foo Artist"));
assert_eq!(tag.get(&AtomIdent::Fourcc(*b"SMTH")), Some(&atom));
let mut tag_bytes = Vec::new();
tag.dump_to(&mut tag_bytes, WriteOptions::default())
.unwrap();
tag_bytes.drain(..8); // Remove the ilst identifier and size for `read_ilst`
let tag_re_read = read_ilst_raw(&tag_bytes[..], ParsingMode::Strict);
assert_eq!(tag, tag_re_read);
// Now write from `Tag`
let tag: Tag = tag.into();
let mut tag_bytes = Vec::new();
tag.dump_to(&mut tag_bytes, WriteOptions::default())
.unwrap();
tag_bytes.drain(..8); // Remove the ilst identifier and size for `read_ilst`
let generic_tag_re_read = read_ilst_raw(&tag_bytes[..], ParsingMode::Strict);
assert_eq!(tag_re_read, generic_tag_re_read);
}
}

View file

@ -1,8 +1,10 @@
use crate::id3::v2::Id3v2Tag;
use crate::mp4::Ilst;
#[derive(Debug, Clone)]
pub(crate) enum CompanionTag {
Id3v2(Id3v2Tag),
Ilst(Ilst),
}
impl CompanionTag {
@ -12,4 +14,11 @@ impl CompanionTag {
_ => None,
}
}
pub(crate) fn ilst(self) -> Option<Ilst> {
match self {
CompanionTag::Ilst(tag) => Some(tag),
_ => None,
}
}
}

View file

@ -253,7 +253,11 @@ impl Tag {
/// tag.re_map(TagType::AiffText);
/// assert!(tag.is_empty());
pub fn re_map(&mut self, tag_type: TagType) {
self.companion_tag = None;
if let Some(companion_tag) = self.companion_tag.take() {
log::warn!("Discarding format-specific items due to remap");
drop(companion_tag);
}
self.retain(|i| i.re_map(tag_type));
self.tag_type = tag_type
}