Generalized 'disc' to 'medium' in tag parser

This commit is contained in:
emeric
2023-03-07 17:11:36 +01:00
parent 3a9bde0092
commit 59eff32377
5 changed files with 113 additions and 104 deletions
+18 -14
View File
@@ -77,7 +77,7 @@ getRelease(const Av::IAudioFile::MetadataMap& metadataMap)
res.emplace();
res->name = *releaseName;
res->releaseMBID = findFirstValueOfAs<UUID>(metadataMap, {"MUSICBRAINZ ALBUM ID", "MUSICBRAINZ_ALBUMID", "MUSICBRAINZ/ALBUM ID"});
res->mbid = findFirstValueOfAs<UUID>(metadataMap, {"MUSICBRAINZ ALBUM ID", "MUSICBRAINZ_ALBUMID", "MUSICBRAINZ/ALBUM ID"});
return res;
}
@@ -149,20 +149,20 @@ AvFormatParser::parse(const std::filesystem::path& p, bool debug)
track.duration = mediaFile->getDuration();
track.hasCover = mediaFile->hasAttachedPictures();
MetaData::Clusters clusters;
MetaData::Tags tags;
const Av::IAudioFile::MetadataMap metadataMap {mediaFile->getMetaData()};
track.artists = getArtists(metadataMap);
track.release = getRelease(metadataMap);
if (track.release)
track.release->releaseArtists = getReleaseArtists(metadataMap);
track.release->artists = getReleaseArtists(metadataMap);
auto getOrCreateDisc = [&]() -> Disc&
auto getOrCreateMedium = [&]() -> Medium&
{
if (!track.disc)
track.disc.emplace();
return *track.disc;
if (!track.medium)
track.medium.emplace();
return *track.medium;
};
for (const auto& [tag, value] : metadataMap)
@@ -178,10 +178,10 @@ AvFormatParser::parse(const std::filesystem::path& p, bool debug)
const std::vector<std::string_view> strings {StringUtils::splitString(value, "/") };
if (strings.size() > 0)
{
track.trackNumber = StringUtils::readAs<std::size_t>(strings[0]);
track.position = StringUtils::readAs<std::size_t>(strings[0]);
if (strings.size() > 1)
getOrCreateDisc().totalTrack = StringUtils::readAs<std::size_t>(strings[1]);
getOrCreateMedium().trackCount = StringUtils::readAs<std::size_t>(strings[1]);
}
}
else if (tag == "DISC")
@@ -190,10 +190,10 @@ AvFormatParser::parse(const std::filesystem::path& p, bool debug)
const std::vector<std::string_view> strings {StringUtils::splitString(value, "/")};
if (strings.size() > 0)
{
track.discNumber = StringUtils::readAs<std::size_t>(strings[0]);
getOrCreateMedium().position = StringUtils::readAs<std::size_t>(strings[0]);
if (strings.size() > 1 && track.release)
track.release->totalDisc = StringUtils::readAs<std::size_t>(strings[1]);
track.release->mediumCount = StringUtils::readAs<std::size_t>(strings[1]);
}
}
else if (tag == "DATE"
@@ -214,18 +214,22 @@ AvFormatParser::parse(const std::filesystem::path& p, bool debug)
else if (tag == "MUSICBRAINZ RELEASE TRACK ID"
|| tag == "MUSICBRAINZ_RELEASETRACKID")
{
track.trackMBID = UUID::fromString(value);
track.mbid = UUID::fromString(value);
}
else if (tag == "MUSICBRAINZ_TRACKID"
|| tag == "MUSICBRAINZ/TRACK ID")
{
track.recordingMBID = UUID::fromString(value);
}
else if (tag == "MEDIA")
{
getOrCreateMedium().type = value;
}
else if (tag == "TSST"
|| tag == "DISCSUBTITLE"
|| tag == "SETSUBTITLE")
{
getOrCreateDisc().subtitle = value;
getOrCreateMedium().name = value;
}
else if (_clusterTypeNames.find(tag) != _clusterTypeNames.end())
{
@@ -237,7 +241,7 @@ AvFormatParser::parse(const std::filesystem::path& p, bool debug)
std::transform(std::cbegin(clusterNames), std::cend(clusterNames),
std::inserter(values, std::begin(values)),
[](std::string_view clusterName) { return std::string {clusterName}; });
track.clusters[tag] = std::move(values);
track.tags[tag] = std::move(values);
}
}
}
+22 -21
View File
@@ -131,7 +131,7 @@ getArtists(const TagMap& tags,
if (artistNames.size() == artistsMBID.size())
{
for (std::size_t i {}; i < artistsMBID.size(); ++i)
artists[i].artistMBID = artistsMBID[i];
artists[i].mbid = artistsMBID[i];
}
}
@@ -194,7 +194,7 @@ getRelease(const TagMap& tags)
release.emplace();
release->name = std::move(releaseName.front());
if (!releaseMBID.empty())
release->releaseMBID = releaseMBID.front();
release->mbid = releaseMBID.front();
return release;
}
@@ -227,11 +227,11 @@ TagLibParser::processTag(Track& track, const std::string& tag, const std::vector
if (tag.empty() || values.empty())
return;
auto getOrCreateDisc = [&]() -> Disc&
auto getOrCreateMedium = [&]() -> Medium&
{
if (!track.disc)
track.disc.emplace();
return *track.disc;
if (!track.medium)
track.medium.emplace();
return *track.medium;
};
std::string_view value {values.front()};
@@ -242,7 +242,7 @@ TagLibParser::processTag(Track& track, const std::string& tag, const std::vector
|| tag == "MUSICBRAINZ RELEASE TRACK ID"
|| tag == "MUSICBRAINZ/RELEASE TRACK ID")
{
track.trackMBID = UUID::fromString(value);
track.mbid = UUID::fromString(value);
}
else if (tag == "MUSICBRAINZ_TRACKID"
|| tag == "MUSICBRAINZ TRACK ID"
@@ -252,7 +252,7 @@ TagLibParser::processTag(Track& track, const std::string& tag, const std::vector
track.acoustID = UUID::fromString(value);
else if (tag == "TRACKTOTAL")
{
getOrCreateDisc().totalTrack = StringUtils::readAs<std::size_t>(value);
getOrCreateMedium().trackCount = StringUtils::readAs<std::size_t>(value);
}
else if (tag == "TRACKNUMBER")
{
@@ -261,17 +261,17 @@ TagLibParser::processTag(Track& track, const std::string& tag, const std::vector
if (!strings.empty())
{
track.trackNumber = StringUtils::readAs<std::size_t>(strings[0]);
track.position = StringUtils::readAs<std::size_t>(strings[0]);
// Lower priority than TRACKTOTAL
if (strings.size() > 1 && !getOrCreateDisc().totalTrack)
getOrCreateDisc().totalTrack = StringUtils::readAs<std::size_t>(strings[1]);
if (strings.size() > 1 && !getOrCreateMedium().trackCount)
getOrCreateMedium().trackCount = StringUtils::readAs<std::size_t>(strings[1]);
}
}
else if (tag == "DISCTOTAL")
{
if (track.release)
track.release->totalDisc = StringUtils::readAs<std::size_t>(value);
track.release->mediumCount = StringUtils::readAs<std::size_t>(value);
}
else if (tag == "DISCNUMBER")
{
@@ -279,11 +279,11 @@ TagLibParser::processTag(Track& track, const std::string& tag, const std::vector
std::vector<std::string_view> strings {StringUtils::splitString(value, "/")};
if (!strings.empty())
{
track.discNumber = StringUtils::readAs<std::size_t>(strings[0]);
getOrCreateMedium().position = StringUtils::readAs<std::size_t>(strings[0]);
// Lower priority than DISCTOTAL
if (strings.size() > 1 && track.release && !track.release->totalDisc)
track.release->totalDisc = StringUtils::readAs<std::size_t>(strings[1]);
if (strings.size() > 1 && track.release && !track.release->mediumCount)
track.release->mediumCount = StringUtils::readAs<std::size_t>(strings[1]);
}
}
else if (tag == "DATE")
@@ -315,24 +315,25 @@ TagLibParser::processTag(Track& track, const std::string& tag, const std::vector
else if (tag == "COPYRIGHTURL")
track.copyrightURL = value;
else if (tag == "REPLAYGAIN_ALBUM_GAIN")
getOrCreateDisc().replayGain = StringUtils::readAs<float>(value);
getOrCreateMedium().replayGain = StringUtils::readAs<float>(value);
else if (tag == "REPLAYGAIN_TRACK_GAIN")
track.replayGain = StringUtils::readAs<float>(value);
else if (tag == "DISCSUBTITLE" || tag == "SETSUBTITLE")
getOrCreateDisc().subtitle = value;
getOrCreateMedium().name = value;
else if (tag == "MEDIA")
getOrCreateMedium().type = value;
else if (_clusterTypeNames.find(tag) != _clusterTypeNames.end())
{
std::set<std::string> clusterNames;
for (const auto& valueList : values)
for (std::string_view valueList : values)
{
const std::vector<std::string_view> splittedValues {splitAndTrimString(valueList, "/,;")};
for (std::string_view value : splittedValues)
clusterNames.insert(std::string {value});
}
if (!clusterNames.empty())
track.clusters[tag] = clusterNames;
track.tags[tag] = std::move(clusterNames);
}
}
@@ -493,7 +494,7 @@ TagLibParser::parse(const std::filesystem::path& p, bool debug)
track.release = getRelease(tags);
if (track.release)
track.release->releaseArtists = getArtists(tags, {"ALBUMARTISTS", "ALBUMARTIST"}, {"ALBUMARTISTSSORT", "ALBUMARTISTSORT"}, {"MUSICBRAINZ_ALBUMARTISTID", "MUSICBRAINZ ALBUM ARTIST ID", "MUSICBRAINZ/ALBUM ARTIST ID"});
track.release->artists = getArtists(tags, {"ALBUMARTISTS", "ALBUMARTIST"}, {"ALBUMARTISTSSORT", "ALBUMARTISTSORT"}, {"MUSICBRAINZ_ALBUMARTISTID", "MUSICBRAINZ ALBUM ARTIST ID", "MUSICBRAINZ/ALBUM ARTIST ID"});
track.artists = getArtists(tags, {"ARTISTS", "ARTIST"}, {"ARTISTSORT"}, {"MUSICBRAINZ_ARTISTID", "MUSICBRAINZ ARTIST ID", "MUSICBRAINZ/ARTIST ID"});
track.conductorArtists = getArtists(tags, {"CONDUCTORS", "CONDUCTOR"}, {"CONDUCTORSSORT", "CONDUCTORSORT"}, {});
track.composerArtists = getArtists(tags, {"COMPOSERS", "COMPOSER"}, {"COMPOSERSSORT", "COMPOSERSORT"}, {});
+17 -16
View File
@@ -33,16 +33,16 @@
namespace MetaData
{
using Clusters = std::map<std::string /* type */, std::set<std::string> /* names */>;
using Tags = std::map<std::string /* type */, std::set<std::string> /* names */>;
struct Artist
{
std::string name;
std::optional<std::string> sortName;
std::optional<UUID> artistMBID;
std::string name;
std::optional<std::string> sortName;
std::optional<UUID> mbid;
Artist(std::string_view _name) : name {_name} {}
Artist(std::string_view _name, std::optional<std::string> _sortName, std::optional<UUID> _artistMBID) : name {_name}, sortName {std::move(_sortName)}, artistMBID {std::move(_artistMBID)} {}
Artist(std::string_view _name, std::optional<std::string> _sortName, std::optional<UUID> _mbid) : name {_name}, sortName {std::move(_sortName)}, mbid {std::move(_mbid)} {}
};
using PerformerContainer = std::map<std::string /*role*/, std::vector<Artist>>;
@@ -50,16 +50,18 @@ namespace MetaData
struct Release
{
std::string name;
std::vector<Artist> releaseArtists;
std::optional<UUID> releaseMBID;
std::optional<std::size_t> totalDisc;
std::vector<Artist> artists;
std::optional<UUID> mbid;
std::optional<std::size_t> mediumCount;
};
struct Disc
struct Medium
{
std::string subtitle;
std::optional<std::size_t> position;
std::string type;
std::string name;
std::optional<float> replayGain;
std::optional<std::size_t> totalTrack;
std::optional<std::size_t> trackCount;
};
struct AudioStream
@@ -71,14 +73,13 @@ namespace MetaData
{
std::vector<Artist> artists;
std::string title;
std::optional<UUID> trackMBID;
std::optional<UUID> mbid;
std::optional<UUID> recordingMBID;
std::optional<Release> release;
std::optional<Disc> disc;
Clusters clusters;
std::optional<Medium> medium;
Tags tags;
std::chrono::milliseconds duration;
std::optional<std::size_t> trackNumber;
std::optional<std::size_t> discNumber;
std::optional<std::size_t> position; // in medium
Wt::WDate date;
Wt::WDate originalDate;
bool hasCover {};
@@ -42,8 +42,8 @@ namespace
{
Artist::pointer artist {session.create<Artist>(artistInfo.name)};
if (artistInfo.artistMBID)
artist.modify()->setMBID(*artistInfo.artistMBID);
if (artistInfo.mbid)
artist.modify()->setMBID(*artistInfo.mbid);
if (artistInfo.sortName)
artist.modify()->setSortName(*artistInfo.sortName);
@@ -76,9 +76,9 @@ namespace
Artist::pointer artist;
// First try to get by MBID
if (artistInfo.artistMBID)
if (artistInfo.mbid)
{
artist = Artist::find(session, *artistInfo.artistMBID);
artist = Artist::find(session, *artistInfo.mbid);
if (!artist)
artist = createArtist(session, artistInfo);
else
@@ -120,8 +120,8 @@ namespace
{
if (release->getName() != releaseInfo.name)
release.modify()->setName(releaseInfo.name);
if (release->getTotalDisc() != releaseInfo.totalDisc)
release.modify()->setTotalDisc(releaseInfo.totalDisc);
if (release->getTotalDisc() != releaseInfo.mediumCount)
release.modify()->setTotalDisc(releaseInfo.mediumCount);
}
Release::pointer
@@ -130,11 +130,11 @@ namespace
Release::pointer release;
// First try to get by MBID
if (releaseInfo.releaseMBID)
if (releaseInfo.mbid)
{
release = Release::find(session, *releaseInfo.releaseMBID);
release = Release::find(session, *releaseInfo.mbid);
if (!release)
release = session.create<Release>(releaseInfo.name, releaseInfo.releaseMBID);
release = session.create<Release>(releaseInfo.name, releaseInfo.mbid);
updateReleaseIfNeeded(release, releaseInfo);
return release;
@@ -165,17 +165,17 @@ namespace
}
std::vector<Cluster::pointer>
getOrCreateClusters(Session& session, const MetaData::Clusters& clustersNames)
getOrCreateClusters(Session& session, const MetaData::Tags& tags)
{
std::vector< Cluster::pointer > clusters;
std::vector<Cluster::pointer> clusters;
for (auto clusterNames : clustersNames)
for (const auto& [tag, values] : tags)
{
auto clusterType = ClusterType::find(session, clusterNames.first);
auto clusterType = ClusterType::find(session, tag);
if (!clusterType)
continue;
for (auto clusterName : clusterNames.second)
for (auto clusterName : values)
{
auto cluster = clusterType->getCluster(clusterName);
if (!cluster)
@@ -287,9 +287,9 @@ namespace Scanner
Track::pointer track {Track::findByPath(dbSession, file) };
if (trackInfo->trackMBID && (!track || _settings.skipDuplicateMBID))
if (trackInfo->mbid && (!track || _settings.skipDuplicateMBID))
{
std::vector<Track::pointer> duplicateTracks {Track::findByMBID(dbSession, *trackInfo->trackMBID)};
std::vector<Track::pointer> duplicateTracks {Track::findByMBID(dbSession, *trackInfo->mbid)};
// find for existing MBIDs as the file may have just been moved
if (!track && duplicateTracks.size() == 1)
@@ -395,7 +395,7 @@ namespace Scanner
if (trackInfo->release)
{
for (const Artist::pointer& releaseArtist : getOrCreateArtists(dbSession, trackInfo->release->releaseArtists, false))
for (const Artist::pointer& releaseArtist : getOrCreateArtists(dbSession, trackInfo->release->artists, false))
track.modify()->addArtistLink(TrackArtistLink::create(dbSession, track, releaseArtist, TrackArtistLinkType::ReleaseArtist));
}
@@ -430,16 +430,16 @@ namespace Scanner
track.modify()->setRelease(getOrCreateRelease(dbSession, *trackInfo->release));
else
track.modify()->setRelease({});
track.modify()->setTotalTrack(trackInfo->disc ? trackInfo->disc->totalTrack : std::nullopt);
track.modify()->setReleaseReplayGain(trackInfo->disc ? trackInfo->disc->replayGain : std::nullopt);
track.modify()->setDiscSubtitle(trackInfo->disc ? trackInfo->disc->subtitle : "");
track.modify()->setClusters(getOrCreateClusters(dbSession, trackInfo->clusters));
track.modify()->setTotalTrack(trackInfo->medium ? trackInfo->medium->trackCount : std::nullopt);
track.modify()->setReleaseReplayGain(trackInfo->medium ? trackInfo->medium->replayGain : std::nullopt);
track.modify()->setDiscSubtitle(trackInfo->medium ? trackInfo->medium->name : "");
track.modify()->setClusters(getOrCreateClusters(dbSession, trackInfo->tags));
track.modify()->setLastWriteTime(lastWriteTime);
track.modify()->setName(title);
track.modify()->setDuration(trackInfo->duration);
track.modify()->setAddedTime(Wt::WDateTime::currentDateTime());
track.modify()->setTrackNumber(trackInfo->trackNumber ? *trackInfo->trackNumber : 0);
track.modify()->setDiscNumber(trackInfo->discNumber ? *trackInfo->discNumber : 0);
track.modify()->setTrackNumber(trackInfo->position);
track.modify()->setDiscNumber(trackInfo->medium ? trackInfo->medium->position : std::nullopt);
track.modify()->setDate(trackInfo->date);
track.modify()->setOriginalDate(trackInfo->originalDate);
@@ -448,7 +448,7 @@ namespace Scanner
track.modify()->setDate(trackInfo->originalDate);
track.modify()->setRecordingMBID(trackInfo->recordingMBID);
track.modify()->setTrackMBID(trackInfo->trackMBID);
track.modify()->setTrackMBID(trackInfo->mbid);
if (auto trackFeatures {TrackFeatures::find(dbSession, track->getId())})
trackFeatures.remove(); // TODO: only if MBID changed?
track.modify()->setHasCover(trackInfo->hasCover);
+32 -29
View File
@@ -35,8 +35,8 @@ operator<<(std::ostream& os, const MetaData::Artist& artist)
{
os << artist.name;
if (artist.artistMBID)
os << " (" << artist.artistMBID->getAsString() << ")";
if (artist.mbid)
os << " (" << artist.mbid->getAsString() << ")";
if (artist.sortName)
os << " '" << *artist.sortName << "'";
@@ -50,30 +50,36 @@ operator<<(std::ostream& os, const MetaData::Release& release)
{
os << release.name;
if (release.releaseMBID)
os << " (" << release.releaseMBID->getAsString() << ")" << std::endl;
if (release.mbid)
os << " (" << release.mbid->getAsString() << ")" << std::endl;
if (release.totalDisc)
std::cout << "\tTotalDisc: " << *release.totalDisc << std::endl;
if (release.mediumCount)
std::cout << "\tMediumCount: " << *release.mediumCount << std::endl;
for (const MetaData::Artist& artist : release.releaseArtists)
std::cout << "\tAlbum artist: " << artist << std::endl;
for (const MetaData::Artist& artist : release.artists)
std::cout << "\tRelease artist: " << artist << std::endl;
return os;
}
static
std::ostream&
operator<<(std::ostream& os, const MetaData::Disc& disc)
operator<<(std::ostream& os, const MetaData::Medium& medium)
{
if (!disc.subtitle.empty())
os << disc.subtitle << std::endl;
if (!medium.name.empty())
os << medium.name << std::endl;
if (disc.totalTrack)
std::cout << "\tTotalTrack: " << *disc.totalTrack << std::endl;
if (medium.position)
os << "\tPosition: " << *medium.position << std::endl;
if (disc.replayGain)
std::cout << "\tDisc replay gain: " << *disc.replayGain << std::endl;
if (!medium.type.empty())
os << "\tType: " << medium.type << std::endl;
if (medium.trackCount)
std::cout << "\tTrackCount: " << *medium.trackCount << std::endl;
if (medium.replayGain)
std::cout << "\tReplay gain: " << *medium.replayGain << std::endl;
return os;
}
@@ -131,33 +137,30 @@ void parse(MetaData::IParser& parser, const std::filesystem::path& file)
if (track->release)
std::cout << "Release: " << *track->release;
if (track->disc)
std::cout << "Disc: " << *track->disc;
if (track->medium)
std::cout << "Medium: " << *track->medium;
std::cout << "Title: " << track->title << std::endl;
if (track->trackMBID)
std::cout << "track MBID = " << track->trackMBID->getAsString() << std::endl;
if (track->mbid)
std::cout << "Track MBID = " << track->mbid->getAsString() << std::endl;
if (track->recordingMBID)
std::cout << "recording MBID = " << track->recordingMBID->getAsString() << std::endl;
std::cout << "Recording MBID = " << track->recordingMBID->getAsString() << std::endl;
for (const auto& cluster : track->clusters)
for (const auto& [tag, values] : track->tags)
{
std::cout << "Cluster: " << cluster.first << std::endl;
for (const auto& name : cluster.second)
std::cout << "Tag: " << tag << std::endl;
for (const auto& value : values)
{
std::cout << "\t" << name << std::endl;
std::cout << "\t" << value << std::endl;
}
}
std::cout << "Duration: " << std::fixed << std::setprecision(2) << track->duration.count() / 1000. << "s" << std::endl;
if (track->trackNumber)
std::cout << "Track: " << *track->trackNumber << std::endl;
if (track->discNumber)
std::cout << "Disc: " << *track->discNumber << std::endl;
if (track->position)
std::cout << "Position: " << *track->position << std::endl;
if (track->date.isValid())
std::cout << "Date: " << track->date.toString("yyyy-MM-dd") << std::endl;