Added support for explcit tags (rtng, ITUNESADVISORY)
This commit is contained in:
@@ -32,6 +32,7 @@ namespace lms::metadata
|
||||
// Mapping to internal avformat names and/or common alternative custom names
|
||||
static const std::unordered_map<TagType, std::vector<std::string>> tagMapping{
|
||||
{ TagType::AcoustID, { "ACOUSTID_ID", "ACOUSTID ID" } },
|
||||
{ TagType::Advisory, { "ITUNESADVISORY" } },
|
||||
{ TagType::Album, { "ALBUM", "TALB", "WM/ALBUMTITLE" } },
|
||||
{ TagType::AlbumArtist, { "ALBUMARTIST", "ALBUM_ARTIST" } },
|
||||
{ TagType::AlbumArtistSortOrder, { "ALBUMARTISTSORT", "TSO2" } },
|
||||
|
||||
@@ -26,12 +26,13 @@
|
||||
|
||||
namespace lms::metadata
|
||||
{
|
||||
// using picard internal names
|
||||
// prefer using picard internal names
|
||||
// see https://picard-docs.musicbrainz.org/en/appendices/tag_mapping.html
|
||||
enum class TagType
|
||||
{
|
||||
AcoustID,
|
||||
AcoustIDFingerprint,
|
||||
Advisory, // non standard
|
||||
Album,
|
||||
AlbumArtist,
|
||||
AlbumArtists, // non standard
|
||||
|
||||
@@ -246,6 +246,25 @@ namespace lms::metadata
|
||||
|
||||
return artistDisplayName;
|
||||
}
|
||||
|
||||
std::optional<Track::Advisory> getAdvisory(const ITagReader& tagReader)
|
||||
{
|
||||
if (const auto value{ getTagValueAs<int>(tagReader, TagType::Advisory) })
|
||||
{
|
||||
switch (*value)
|
||||
{
|
||||
case 1:
|
||||
case 4:
|
||||
return Track::Advisory::Explicit;
|
||||
case 2:
|
||||
return Track::Advisory::Clean;
|
||||
case 0:
|
||||
return Track::Advisory::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<IParser> createParser(ParserBackend parserBackend, ParserReadStyle parserReadStyle)
|
||||
@@ -370,6 +389,7 @@ namespace lms::metadata
|
||||
track.originalYear = utils::parseYear(*dateStr);
|
||||
}
|
||||
|
||||
track.advisory = getAdvisory(tagReader);
|
||||
track.lyrics = getLyrics(tagReader); // no custom delimiter on lyrics
|
||||
track.comments = getTagValuesAs<std::string>(tagReader, TagType::Comment, {} /* no custom delimiter on comments */);
|
||||
track.copyright = getTagValueAs<std::string>(tagReader, TagType::Copyright).value_or("");
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace lms::metadata
|
||||
// Mapping to internal taglib names and/or common alternative custom names
|
||||
const std::unordered_map<TagType, std::vector<std::string>> tagMapping{
|
||||
{ TagType::AcoustID, { "ACOUSTID_ID", "ACOUSTID ID" } },
|
||||
{ TagType::Advisory, { "ITUNESADVISORY" } },
|
||||
{ TagType::Album, { "ALBUM" } },
|
||||
{ TagType::AlbumArtist, { "ALBUMARTIST" } },
|
||||
{ TagType::AlbumArtistSortOrder, { "ALBUMARTISTSORT" } },
|
||||
@@ -319,10 +320,18 @@ namespace lms::metadata
|
||||
// MP4
|
||||
else if (TagLib::MP4::File * mp4File{ dynamic_cast<TagLib::MP4::File*>(_file.file()) })
|
||||
{
|
||||
TagLib::MP4::Item coverItem{ mp4File->tag()->item("covr") };
|
||||
TagLib::MP4::CoverArtList coverArtList{ coverItem.toCoverArtList() };
|
||||
if (!coverArtList.isEmpty())
|
||||
_hasEmbeddedCover = true;
|
||||
if (const TagLib::MP4::Item coverItem{ mp4File->tag()->item("covr") }; coverItem.isValid())
|
||||
{
|
||||
if (coverItem.type() == TagLib::MP4::Item::Type::CoverArtList)
|
||||
_hasEmbeddedCover = true;
|
||||
}
|
||||
|
||||
// Taglib does not expose rtng in properties
|
||||
if (const TagLib::MP4::Item rtngItem{ mp4File->tag()->item("rtng") }; rtngItem.isValid())
|
||||
{
|
||||
if (rtngItem.type() == TagLib::MP4::Item::Type::Byte)
|
||||
_propertyMap["ITUNESADVISORY"] = TagLib::String{ std::to_string(rtngItem.toByte()) };
|
||||
}
|
||||
|
||||
if (!_propertyMap.contains("ORIGINALDATE"))
|
||||
{
|
||||
|
||||
@@ -102,6 +102,12 @@ namespace lms::metadata
|
||||
|
||||
struct Track
|
||||
{
|
||||
enum class Advisory
|
||||
{
|
||||
Unknown,
|
||||
Explicit,
|
||||
Clean,
|
||||
};
|
||||
AudioProperties audioProperties;
|
||||
std::optional<core::UUID> mbid;
|
||||
std::optional<core::UUID> recordingMBID;
|
||||
@@ -117,6 +123,7 @@ namespace lms::metadata
|
||||
Wt::WDate date;
|
||||
std::optional<int> originalYear{};
|
||||
Wt::WDate originalDate;
|
||||
std::optional<Advisory> advisory;
|
||||
bool hasCover{};
|
||||
std::optional<core::UUID> acoustID;
|
||||
std::string copyright;
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace lms::metadata
|
||||
TestTagReader testTags{
|
||||
{
|
||||
{ TagType::AcoustID, { "e987a441-e134-4960-8019-274eddacc418" } },
|
||||
{ TagType::Advisory, { "2" } },
|
||||
{ TagType::Album, { "MyAlbum" } },
|
||||
{ TagType::AlbumSortOrder, { "MyAlbumSortName" } },
|
||||
{ TagType::Artist, { "MyArtist1 & MyArtist2" } },
|
||||
@@ -99,6 +100,8 @@ namespace lms::metadata
|
||||
}
|
||||
|
||||
EXPECT_EQ(track->acoustID, core::UUID::fromString("e987a441-e134-4960-8019-274eddacc418"));
|
||||
ASSERT_TRUE(track->advisory.has_value());
|
||||
EXPECT_EQ(track->advisory.value(), Track::Advisory::Clean);
|
||||
EXPECT_EQ(track->artistDisplayName, "MyArtist1 & MyArtist2");
|
||||
ASSERT_EQ(track->artists.size(), 2);
|
||||
EXPECT_EQ(track->artists[0].name, "MyArtist1");
|
||||
@@ -581,4 +584,31 @@ namespace lms::metadata
|
||||
EXPECT_EQ(track->artists[1].mbid, std::nullopt);
|
||||
EXPECT_EQ(track->artistDisplayName, "Artist1, Artist2"); // reconstruct the artist display name
|
||||
}
|
||||
|
||||
TEST(Parser, advisory)
|
||||
{
|
||||
auto doTest = [](std::string_view value, std::optional<Track::Advisory> expectedValue) {
|
||||
const TestTagReader testTags{
|
||||
{
|
||||
{ TagType::Advisory, { value } },
|
||||
}
|
||||
};
|
||||
|
||||
Parser parser;
|
||||
std::unique_ptr<Track> track{ Parser{}.parse(testTags) };
|
||||
|
||||
ASSERT_EQ(track->advisory.has_value(), expectedValue.has_value()) << "Value = '" << value << "'";
|
||||
if (track->advisory.has_value())
|
||||
{
|
||||
EXPECT_EQ(track->advisory.value(), expectedValue);
|
||||
}
|
||||
};
|
||||
|
||||
doTest("0", Track::Advisory::Unknown);
|
||||
doTest("1", Track::Advisory::Explicit);
|
||||
doTest("4", Track::Advisory::Explicit);
|
||||
doTest("2", Track::Advisory::Clean);
|
||||
doTest("", std::nullopt);
|
||||
doTest("3", std::nullopt);
|
||||
}
|
||||
} // namespace lms::metadata
|
||||
|
||||
Reference in New Issue
Block a user