Add accessors to manipulate MP4 tags without modifying the internal structure

This brings the MP4 API in line closer to other tag formats and makes it
possible to access the tag data from const functions.

"ItemListMap" has been renamed to "ItemMap" (with the old version
deprecated).  It seems that the "ListMap" notion was copied probably
from Allan's ApeTag implementation, which incorrectly copied the term
from the XiphTag.  Notably, in XiphTag, because a field can have multiple
values, the "ListMap" is a map of lists.  Calling things a "ListMap" where
there can be only one value doesn't fit.

Closes #255
This commit is contained in:
Scott Wheeler
2015-05-18 21:18:33 +02:00
parent 451d23ca37
commit bba562b557
3 changed files with 100 additions and 40 deletions

View File

@ -71,7 +71,7 @@ public:
CPPUNIT_ASSERT(!t1.isEmpty());
MP4::Tag t2;
t2.itemListMap()["foo"] = "bar";
t2.setItem("foo", "bar");
CPPUNIT_ASSERT(!t2.isEmpty());
}
@ -128,14 +128,15 @@ public:
string filename = copy.fileName();
MP4::File *f = new MP4::File(filename.c_str());
CPPUNIT_ASSERT(f->tag()->itemListMap().contains("----:com.apple.iTunes:iTunNORM"));
f->tag()->itemListMap()["----:org.kde.TagLib:Foo"] = StringList("Bar");
CPPUNIT_ASSERT(f->tag()->contains("----:com.apple.iTunes:iTunNORM"));
f->tag()->setItem("----:org.kde.TagLib:Foo", StringList("Bar"));
f->save();
delete f;
f = new MP4::File(filename.c_str());
CPPUNIT_ASSERT(f->tag()->itemListMap().contains("----:org.kde.TagLib:Foo"));
CPPUNIT_ASSERT_EQUAL(String("Bar"), f->tag()->itemListMap()["----:org.kde.TagLib:Foo"].toStringList()[0]);
CPPUNIT_ASSERT(f->tag()->contains("----:org.kde.TagLib:Foo"));
CPPUNIT_ASSERT_EQUAL(String("Bar"),
f->tag()->item("----:org.kde.TagLib:Foo").toStringList().front());
f->save();
delete f;
}
@ -146,14 +147,16 @@ public:
string filename = copy.fileName();
MP4::File *f = new MP4::File(filename.c_str());
CPPUNIT_ASSERT_EQUAL(String("82,164"), f->tag()->itemListMap()["----:com.apple.iTunes:replaygain_track_minmax"].toStringList()[0]);
CPPUNIT_ASSERT_EQUAL(String("82,164"),
f->tag()->item("----:com.apple.iTunes:replaygain_track_minmax").toStringList().front());
CPPUNIT_ASSERT_EQUAL(String("Pearl Jam"), f->tag()->artist());
f->tag()->setComment("foo");
f->save();
delete f;
f = new MP4::File(filename.c_str());
CPPUNIT_ASSERT_EQUAL(String("82,164"), f->tag()->itemListMap()["----:com.apple.iTunes:replaygain_track_minmax"].toStringList()[0]);
CPPUNIT_ASSERT_EQUAL(String("82,164"),
f->tag()->item("----:com.apple.iTunes:replaygain_track_minmax").toStringList().front());
CPPUNIT_ASSERT_EQUAL(String("Pearl Jam"), f->tag()->artist());
CPPUNIT_ASSERT_EQUAL(String("foo"), f->tag()->comment());
delete f;
@ -165,20 +168,20 @@ public:
string filename = copy.fileName();
MP4::File *f = new MP4::File(filename.c_str());
CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["cpil"].toBool());
CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemMap()["cpil"].toBool());
MP4::Atoms *atoms = new MP4::Atoms(f);
MP4::Atom *moov = atoms->atoms[0];
CPPUNIT_ASSERT_EQUAL(long(77), moov->length);
f->tag()->itemListMap()["pgap"] = true;
f->tag()->setItem("pgap", true);
f->save();
delete atoms;
delete f;
f = new MP4::File(filename.c_str());
CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["cpil"].toBool());
CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["pgap"].toBool());
CPPUNIT_ASSERT_EQUAL(true, f->tag()->item("cpil").toBool());
CPPUNIT_ASSERT_EQUAL(true, f->tag()->item("pgap").toBool());
atoms = new MP4::Atoms(f);
moov = atoms->atoms[0];
@ -198,8 +201,8 @@ public:
void testCovrRead()
{
MP4::File *f = new MP4::File(TEST_FILE_PATH_C("has-tags.m4a"));
CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr"));
MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList();
CPPUNIT_ASSERT(f->tag()->contains("covr"));
MP4::CoverArtList l = f->tag()->item("covr").toCoverArtList();
CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), l.size());
CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format());
CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size());
@ -214,16 +217,16 @@ public:
string filename = copy.fileName();
MP4::File *f = new MP4::File(filename.c_str());
CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr"));
MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList();
CPPUNIT_ASSERT(f->tag()->contains("covr"));
MP4::CoverArtList l = f->tag()->item("covr").toCoverArtList();
l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo"));
f->tag()->itemListMap()["covr"] = l;
f->tag()->setItem("covr", l);
f->save();
delete f;
f = new MP4::File(filename.c_str());
CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr"));
l = f->tag()->itemListMap()["covr"].toCoverArtList();
CPPUNIT_ASSERT(f->tag()->contains("covr"));
l = f->tag()->item("covr").toCoverArtList();
CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), l.size());
CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format());
CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size());
@ -237,8 +240,8 @@ public:
void testCovrRead2()
{
MP4::File *f = new MP4::File(TEST_FILE_PATH_C("covr-junk.m4a"));
CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr"));
MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList();
CPPUNIT_ASSERT(f->tag()->contains("covr"));
MP4::CoverArtList l = f->tag()->item("covr").toCoverArtList();
CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), l.size());
CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format());
CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size());
@ -264,26 +267,26 @@ public:
tags = f.properties();
CPPUNIT_ASSERT(f.tag()->itemListMap().contains("trkn"));
CPPUNIT_ASSERT_EQUAL(2, f.tag()->itemListMap()["trkn"].toIntPair().first);
CPPUNIT_ASSERT_EQUAL(4, f.tag()->itemListMap()["trkn"].toIntPair().second);
CPPUNIT_ASSERT(f.tag()->contains("trkn"));
CPPUNIT_ASSERT_EQUAL(2, f.tag()->item("trkn").toIntPair().first);
CPPUNIT_ASSERT_EQUAL(4, f.tag()->item("trkn").toIntPair().second);
CPPUNIT_ASSERT_EQUAL(StringList("2/4"), tags["TRACKNUMBER"]);
CPPUNIT_ASSERT(f.tag()->itemListMap().contains("disk"));
CPPUNIT_ASSERT_EQUAL(3, f.tag()->itemListMap()["disk"].toIntPair().first);
CPPUNIT_ASSERT_EQUAL(5, f.tag()->itemListMap()["disk"].toIntPair().second);
CPPUNIT_ASSERT(f.tag()->contains("disk"));
CPPUNIT_ASSERT_EQUAL(3, f.tag()->item("disk").toIntPair().first);
CPPUNIT_ASSERT_EQUAL(5, f.tag()->item("disk").toIntPair().second);
CPPUNIT_ASSERT_EQUAL(StringList("3/5"), tags["DISCNUMBER"]);
CPPUNIT_ASSERT(f.tag()->itemListMap().contains("tmpo"));
CPPUNIT_ASSERT_EQUAL(123, f.tag()->itemListMap()["tmpo"].toInt());
CPPUNIT_ASSERT(f.tag()->contains("tmpo"));
CPPUNIT_ASSERT_EQUAL(123, f.tag()->item("tmpo").toInt());
CPPUNIT_ASSERT_EQUAL(StringList("123"), tags["BPM"]);
CPPUNIT_ASSERT(f.tag()->itemListMap().contains("\251ART"));
CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), f.tag()->itemListMap()["\251ART"].toStringList());
CPPUNIT_ASSERT(f.tag()->contains("\251ART"));
CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), f.tag()->item("\251ART").toStringList());
CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), tags["ARTIST"]);
CPPUNIT_ASSERT(f.tag()->itemListMap().contains("cpil"));
CPPUNIT_ASSERT_EQUAL(true, f.tag()->itemListMap()["cpil"].toBool());
CPPUNIT_ASSERT(f.tag()->contains("cpil"));
CPPUNIT_ASSERT_EQUAL(true, f.tag()->item("cpil").toBool());
CPPUNIT_ASSERT_EQUAL(StringList("1"), tags["COMPILATION"]);
tags["COMPILATION"] = StringList("0");
@ -291,8 +294,8 @@ public:
tags = f.properties();
CPPUNIT_ASSERT(f.tag()->itemListMap().contains("cpil"));
CPPUNIT_ASSERT_EQUAL(false, f.tag()->itemListMap()["cpil"].toBool());
CPPUNIT_ASSERT(f.tag()->contains("cpil"));
CPPUNIT_ASSERT_EQUAL(false, f.tag()->item("cpil").toBool());
CPPUNIT_ASSERT_EQUAL(StringList("0"), tags["COMPILATION"]);
}