properly handle multi tags like MP3 ID3 v2.4 tags
This commit is contained in:
+11
-13
@@ -61,24 +61,22 @@ getAlbum(const MetadataMap& metadataMap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
boost::optional<Artist>
|
std::vector<Artist>
|
||||||
getAlbumArtist(const MetadataMap& metadataMap)
|
getAlbumArtists(const MetadataMap& metadataMap)
|
||||||
{
|
{
|
||||||
boost::optional<Artist> res;
|
std::vector<Artist> res;
|
||||||
|
|
||||||
auto artist {findFirstValueOf(metadataMap, {"ALBUM_ARTIST"})};
|
auto name {findFirstValueOf(metadataMap, {"ALBUM_ARTIST"})};
|
||||||
if (!artist)
|
if (!name)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
res = Artist{*artist, ""};
|
Artist artist {*name, ""};
|
||||||
|
|
||||||
auto artistMBID {findFirstValueOf(metadataMap, {"MUSICBRAINZ ALBUM ARTIST ID"})};
|
auto mbid {findFirstValueOf(metadataMap, {"MUSICBRAINZ ALBUM ARTIST ID"})};
|
||||||
if (!artistMBID)
|
if (mbid)
|
||||||
return res;
|
artist.musicBrainzArtistID = *mbid;
|
||||||
|
|
||||||
res->musicBrainzArtistID = *artistMBID;
|
return {std::move(artist)};
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -213,7 +211,7 @@ AvFormat::parse(const boost::filesystem::path& p, bool debug)
|
|||||||
|
|
||||||
track.artists = getArtists(metadataMap);
|
track.artists = getArtists(metadataMap);
|
||||||
track.album = getAlbum(metadataMap);
|
track.album = getAlbum(metadataMap);
|
||||||
track.albumArtist = getAlbumArtist(metadataMap);
|
track.albumArtists = getAlbumArtists(metadataMap);
|
||||||
}
|
}
|
||||||
catch(Av::MediaFileException& e)
|
catch(Av::MediaFileException& e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace MetaData
|
|||||||
struct Track
|
struct Track
|
||||||
{
|
{
|
||||||
std::vector<Artist> artists;
|
std::vector<Artist> artists;
|
||||||
boost::optional<Artist> albumArtist;
|
std::vector<Artist> albumArtists;
|
||||||
std::string title;
|
std::string title;
|
||||||
std::string musicBrainzTrackID;
|
std::string musicBrainzTrackID;
|
||||||
std::string musicBrainzRecordID;
|
std::string musicBrainzRecordID;
|
||||||
|
|||||||
@@ -31,18 +31,15 @@
|
|||||||
namespace MetaData
|
namespace MetaData
|
||||||
{
|
{
|
||||||
|
|
||||||
boost::optional<std::string>
|
std::vector<std::string>
|
||||||
getPropertyValue(const TagLib::PropertyMap& properties, const std::string& key)
|
getPropertyValues(const TagLib::PropertyMap& properties, const std::string& key)
|
||||||
{
|
{
|
||||||
boost::optional<std::string> res;
|
std::vector<std::string> res;
|
||||||
|
|
||||||
const TagLib::StringList& values {properties[key]};
|
const TagLib::StringList& values {properties[key]};
|
||||||
if (values.isEmpty())
|
|
||||||
return res;
|
|
||||||
|
|
||||||
res = stringTrim(values.front().to8Bit(true));
|
res.reserve(values.size());
|
||||||
if (res->empty())
|
std::transform(std::cbegin(values), std::cend(values), std::back_inserter(res), [](const auto& value) { return stringTrim(value.to8Bit(true)); });
|
||||||
res.reset();
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -60,82 +57,77 @@ splitAndTrimString(const std::string& str, const std::string& delimiters)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
std::vector<std::string>
|
|
||||||
getMusicBrainzArtistID(const TagLib::PropertyMap& properties)
|
|
||||||
{
|
|
||||||
boost::optional<std::string> value {getPropertyValue(properties, "MUSICBRAINZ_ARTISTID")};
|
|
||||||
|
|
||||||
if (!value)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return splitAndTrimString(*value, "/"); // Picard separator is '/'
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
std::vector<Artist>
|
std::vector<Artist>
|
||||||
getArtists(const TagLib::PropertyMap& properties)
|
getArtists(const TagLib::PropertyMap& properties)
|
||||||
{
|
{
|
||||||
std::vector<Artist> res;
|
std::vector<Artist> res;
|
||||||
|
|
||||||
boost::optional<std::string> value;
|
std::vector<std::string> artistNames {getPropertyValues(properties, "ARTISTS")};
|
||||||
|
if (artistNames.empty())
|
||||||
value = getPropertyValue(properties, "ARTISTS");
|
artistNames = getPropertyValues(properties, "ARTIST");
|
||||||
if (value)
|
|
||||||
{
|
|
||||||
std::vector<std::string> artists {splitAndTrimString(*value, "/;")}; // Picard separator is '/'
|
|
||||||
std::vector<std::string> artistsMBID {getMusicBrainzArtistID(properties)};
|
|
||||||
|
|
||||||
for (std::size_t i {}; i < artists.size(); ++i)
|
|
||||||
res.emplace_back(Artist{std::move(artists[i]), artistsMBID.size() == artists.size() ? std::move(artistsMBID[i]) : ""});
|
|
||||||
|
|
||||||
|
if (artistNames.empty())
|
||||||
return res;
|
return res;
|
||||||
}
|
|
||||||
|
|
||||||
value = getPropertyValue(properties, "ARTIST");
|
const std::vector<std::string> artistsMBID {getPropertyValues(properties, "MUSICBRAINZ_ARTISTID")};
|
||||||
if (value)
|
|
||||||
res.emplace_back(Artist{std::move(*value), ""});
|
if (artistNames.size() == artistsMBID.size())
|
||||||
|
{
|
||||||
|
std::transform(std::cbegin(artistNames), std::cend(artistNames), std::cbegin(artistsMBID), std::back_inserter(res),
|
||||||
|
[&](const std::string& name, const std::string& mbid) { return Artist{name, mbid}; });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::transform(std::cbegin(artistNames), std::cend(artistNames), std::back_inserter(res),
|
||||||
|
[&](const std::string& name) { return Artist{name, ""}; });
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
boost::optional<Artist>
|
std::vector<Artist>
|
||||||
getAlbumArtist(const TagLib::PropertyMap& properties)
|
getAlbumArtists(const TagLib::PropertyMap& properties)
|
||||||
{
|
{
|
||||||
boost::optional<Artist> res;
|
std::vector<Artist> res;
|
||||||
|
|
||||||
boost::optional<std::string> value;
|
std::vector<std::string> artistNames {getPropertyValues(properties, "ALBUMARTIST")};
|
||||||
|
if (artistNames.empty())
|
||||||
value = getPropertyValue(properties, "ALBUMARTIST");
|
|
||||||
if (!value)
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
res = Artist{std::move(*value), ""};
|
const std::vector<std::string> artistsMBID {getPropertyValues(properties, "MUSICBRAINZ_ALBUMARTISTID")};
|
||||||
|
|
||||||
value = getPropertyValue(properties, "MUSICBRAINZ_ALBUMARTISTID");
|
if (artistNames.size() == artistsMBID.size())
|
||||||
if (value)
|
{
|
||||||
res->musicBrainzArtistID = std::move(*value);
|
std::transform(std::cbegin(artistNames), std::cend(artistNames), std::cbegin(artistsMBID), std::back_inserter(res),
|
||||||
|
[&](const std::string& name, const std::string& mbid) { return Artist{name, mbid}; });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::transform(std::cbegin(artistNames), std::cend(artistNames), std::back_inserter(res),
|
||||||
|
[&](const std::string& name) { return Artist{name, ""}; });
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
boost::optional<Album>
|
boost::optional<Album>
|
||||||
getAlbum(const TagLib::PropertyMap& properties)
|
getAlbum(const TagLib::PropertyMap& properties)
|
||||||
{
|
{
|
||||||
boost::optional<Album> res;
|
boost::optional<Album> res;
|
||||||
|
|
||||||
boost::optional<std::string> value {getPropertyValue(properties, "ALBUM")};
|
std::vector<std::string> albumName {getPropertyValues(properties, "ALBUM")};
|
||||||
if (!value)
|
if (albumName.empty())
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
res = Album{std::move(*value), ""};
|
std::vector<std::string> albumMBID {getPropertyValues(properties, "MUSICBRAINZ_ALBUMID")};
|
||||||
|
|
||||||
boost::optional<std::string> mbid {getPropertyValue(properties, "MUSICBRAINZ_ALBUMID")};
|
res = Album{std::move(albumName.front()), ""};
|
||||||
if (mbid)
|
|
||||||
res->musicBrainzAlbumID = std::move(*mbid);
|
if (!albumMBID.empty())
|
||||||
|
res->musicBrainzAlbumID = std::move(albumMBID.front());
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -192,7 +184,7 @@ TagLibParser::parse(const boost::filesystem::path& p, bool debug)
|
|||||||
std::vector<std::string> strs;
|
std::vector<std::string> strs;
|
||||||
std::transform(values.begin(), values.end(), std::back_inserter(strs), [](const auto& value) { return value.to8Bit(true); });
|
std::transform(values.begin(), values.end(), std::back_inserter(strs), [](const auto& value) { return value.to8Bit(true); });
|
||||||
|
|
||||||
std::cout << "[" << tag << "] = " << joinStrings(strs, ",") << std::endl;
|
std::cout << "[" << tag << "] = " << joinStrings(strs, "*SEP*") << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag.empty() || values.isEmpty() || values.front().isEmpty())
|
if (tag.empty() || values.isEmpty() || values.front().isEmpty())
|
||||||
@@ -288,7 +280,7 @@ TagLibParser::parse(const boost::filesystem::path& p, bool debug)
|
|||||||
}
|
}
|
||||||
|
|
||||||
track.artists = getArtists(properties);
|
track.artists = getArtists(properties);
|
||||||
track.albumArtist = getAlbumArtist(properties);
|
track.albumArtists = getAlbumArtists(properties);
|
||||||
track.album = getAlbum(properties);
|
track.album = getAlbum(properties);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ void parse(MetaData::Parser& parser, const boost::filesystem::path& file)
|
|||||||
for (const Artist& artist : track->artists)
|
for (const Artist& artist : track->artists)
|
||||||
std::cout << "Artist: " << artist << std::endl;
|
std::cout << "Artist: " << artist << std::endl;
|
||||||
|
|
||||||
if (track->albumArtist)
|
for (const Artist& artist: track->albumArtists)
|
||||||
std::cout << "Album artist: " << *track->albumArtist << std::endl;
|
std::cout << "Album artist: " << artist << std::endl;
|
||||||
|
|
||||||
if (track->album)
|
if (track->album)
|
||||||
std::cout << "Album: " << *track->album << std::endl;
|
std::cout << "Album: " << *track->album << std::endl;
|
||||||
|
|||||||
Reference in New Issue
Block a user