Medium now part of a release
This commit is contained in:
@@ -64,24 +64,6 @@ findFirstValueOfAs(const Av::IAudioFile::MetadataMap& metadataMap, std::initiali
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
|
||||||
std::optional<Release>
|
|
||||||
getRelease(const Av::IAudioFile::MetadataMap& metadataMap)
|
|
||||||
{
|
|
||||||
std::optional<Release> res;
|
|
||||||
|
|
||||||
std::optional<std::string> releaseName {findFirstValueOfAs<std::string>(metadataMap, {"ALBUM"})};
|
|
||||||
if (!releaseName)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
res.emplace();
|
|
||||||
res->name = *releaseName;
|
|
||||||
res->mbid = findFirstValueOfAs<UUID>(metadataMap, {"MUSICBRAINZ ALBUM ID", "MUSICBRAINZ_ALBUMID", "MUSICBRAINZ/ALBUM ID"});
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
std::vector<Artist>
|
std::vector<Artist>
|
||||||
getReleaseArtists(const Av::IAudioFile::MetadataMap& metadataMap)
|
getReleaseArtists(const Av::IAudioFile::MetadataMap& metadataMap)
|
||||||
@@ -126,6 +108,75 @@ getArtists(const Av::IAudioFile::MetadataMap& metadataMap)
|
|||||||
return artists;
|
return artists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::optional<Release>
|
||||||
|
getRelease(const Av::IAudioFile::MetadataMap& metadataMap)
|
||||||
|
{
|
||||||
|
std::optional<Release> res;
|
||||||
|
|
||||||
|
std::optional<std::string> releaseName {findFirstValueOfAs<std::string>(metadataMap, {"ALBUM", "TALB", "WM/ALBUMTITLE"})};
|
||||||
|
if (!releaseName)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
res.emplace();
|
||||||
|
res->name = std::move(*releaseName);
|
||||||
|
res->mbid = findFirstValueOfAs<UUID>(metadataMap, {"MUSICBRAINZ ALBUM ID", "MUSICBRAINZ_ALBUMID", "MUSICBRAINZ/ALBUM ID"});
|
||||||
|
res->artists = getReleaseArtists(metadataMap);
|
||||||
|
res->mediumCount = findFirstValueOfAs<std::size_t>(metadataMap, {"TOTALDISCS", "DISCTOTAL"});
|
||||||
|
if (!res->mediumCount)
|
||||||
|
{
|
||||||
|
// mediumCount may be encoded as position/count
|
||||||
|
if (const auto value {findFirstValueOfAs<std::string>(metadataMap, {"TPOS", "DISC", "DISK", "DISCNUMBER", "WM/PARTOFSET"})})
|
||||||
|
{
|
||||||
|
// Expecting 'Number/Total'
|
||||||
|
const std::vector<std::string_view> strings {StringUtils::splitString(*value, "/") };
|
||||||
|
if (strings.size() == 2)
|
||||||
|
res->mediumCount = StringUtils::readAs<std::size_t>(strings[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::optional<Medium>
|
||||||
|
getMedium(const Av::IAudioFile::MetadataMap& metadataMap)
|
||||||
|
{
|
||||||
|
std::optional<Medium> res;
|
||||||
|
res.emplace();
|
||||||
|
|
||||||
|
res->type = findFirstValueOfAs<std::string>(metadataMap, {"TMED", "MEDIA", "WM/MEDIA"}).value_or("");
|
||||||
|
res->name = findFirstValueOfAs<std::string>(metadataMap, {"TSST", "DISCSUBTITLE", "SETSUBTITLE"}).value_or("");
|
||||||
|
res->trackCount = findFirstValueOfAs<std::size_t>(metadataMap, {"TOTALTRACKS", "TRACKTOTAL"});
|
||||||
|
if (!res->trackCount)
|
||||||
|
{
|
||||||
|
// totalTracks may be encoded as "position/count"
|
||||||
|
if (const auto value {findFirstValueOfAs<std::string>(metadataMap, {"TRCK", "TRACK", "TRACKNUMBER", "TRKN", "WM/TRACKNUMBER"})})
|
||||||
|
{
|
||||||
|
// Expecting 'Number/Total'
|
||||||
|
const std::vector<std::string_view> strings {StringUtils::splitString(*value, "/") };
|
||||||
|
if (strings.size() == 2)
|
||||||
|
res->trackCount = StringUtils::readAs<std::size_t>(strings[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// position may be encoded in TPOS/DISC/DISK as "position/count". Expecting 'Number[/Total]'
|
||||||
|
res->position = findFirstValueOfAs<std::size_t>(metadataMap, {"TPOS", "DISC", "DISK", "DISCNUMBER", "WM/PARTOFSET"});
|
||||||
|
res->release = getRelease(metadataMap);
|
||||||
|
|
||||||
|
if (res->type.empty()
|
||||||
|
&& res->name.empty()
|
||||||
|
&& !res->trackCount
|
||||||
|
&& !res->position
|
||||||
|
&& !res->release
|
||||||
|
&& !res->replayGain)
|
||||||
|
{
|
||||||
|
res.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<Track>
|
std::optional<Track>
|
||||||
AvFormatParser::parse(const std::filesystem::path& p, bool debug)
|
AvFormatParser::parse(const std::filesystem::path& p, bool debug)
|
||||||
{
|
{
|
||||||
@@ -154,16 +205,7 @@ AvFormatParser::parse(const std::filesystem::path& p, bool debug)
|
|||||||
const Av::IAudioFile::MetadataMap metadataMap {mediaFile->getMetaData()};
|
const Av::IAudioFile::MetadataMap metadataMap {mediaFile->getMetaData()};
|
||||||
|
|
||||||
track.artists = getArtists(metadataMap);
|
track.artists = getArtists(metadataMap);
|
||||||
track.release = getRelease(metadataMap);
|
track.medium = getMedium(metadataMap);
|
||||||
if (track.release)
|
|
||||||
track.release->artists = getReleaseArtists(metadataMap);
|
|
||||||
|
|
||||||
auto getOrCreateMedium = [&]() -> Medium&
|
|
||||||
{
|
|
||||||
if (!track.medium)
|
|
||||||
track.medium.emplace();
|
|
||||||
return *track.medium;
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const auto& [tag, value] : metadataMap)
|
for (const auto& [tag, value] : metadataMap)
|
||||||
{
|
{
|
||||||
@@ -175,30 +217,11 @@ AvFormatParser::parse(const std::filesystem::path& p, bool debug)
|
|||||||
else if (tag == "TRACK")
|
else if (tag == "TRACK")
|
||||||
{
|
{
|
||||||
// Expecting 'Number/Total'
|
// Expecting 'Number/Total'
|
||||||
const std::vector<std::string_view> strings {StringUtils::splitString(value, "/") };
|
track.position = StringUtils::readAs<std::size_t>(value);
|
||||||
if (strings.size() > 0)
|
|
||||||
{
|
|
||||||
track.position = StringUtils::readAs<std::size_t>(strings[0]);
|
|
||||||
|
|
||||||
if (strings.size() > 1)
|
|
||||||
getOrCreateMedium().trackCount = StringUtils::readAs<std::size_t>(strings[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (tag == "DISC")
|
|
||||||
{
|
|
||||||
// Expecting 'Number/Total'
|
|
||||||
const std::vector<std::string_view> strings {StringUtils::splitString(value, "/")};
|
|
||||||
if (strings.size() > 0)
|
|
||||||
{
|
|
||||||
getOrCreateMedium().position = StringUtils::readAs<std::size_t>(strings[0]);
|
|
||||||
|
|
||||||
if (strings.size() > 1 && track.release)
|
|
||||||
track.release->mediumCount = StringUtils::readAs<std::size_t>(strings[1]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (tag == "DATE"
|
else if (tag == "DATE"
|
||||||
|| tag == "YEAR"
|
|| tag == "YEAR"
|
||||||
|| tag == "WM/Year")
|
|| tag == "WM/YEAR")
|
||||||
{
|
{
|
||||||
track.date = Utils::parseDate(value);
|
track.date = Utils::parseDate(value);
|
||||||
}
|
}
|
||||||
@@ -221,16 +244,6 @@ AvFormatParser::parse(const std::filesystem::path& p, bool debug)
|
|||||||
{
|
{
|
||||||
track.recordingMBID = UUID::fromString(value);
|
track.recordingMBID = UUID::fromString(value);
|
||||||
}
|
}
|
||||||
else if (tag == "MEDIA")
|
|
||||||
{
|
|
||||||
getOrCreateMedium().type = value;
|
|
||||||
}
|
|
||||||
else if (tag == "TSST"
|
|
||||||
|| tag == "DISCSUBTITLE"
|
|
||||||
|| tag == "SETSUBTITLE")
|
|
||||||
{
|
|
||||||
getOrCreateMedium().name = value;
|
|
||||||
}
|
|
||||||
else if (_clusterTypeNames.find(tag) != _clusterTypeNames.end())
|
else if (_clusterTypeNames.find(tag) != _clusterTypeNames.end())
|
||||||
{
|
{
|
||||||
const std::vector<std::string_view> clusterNames {StringUtils::splitString(value, "/,;")};
|
const std::vector<std::string_view> clusterNames {StringUtils::splitString(value, "/,;")};
|
||||||
|
|||||||
@@ -81,6 +81,18 @@ getPropertyValuesFirstMatchAs(const TagMap& tags, const std::vector<std::string_
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::optional<T>
|
||||||
|
getPropertyValueFirstMatchAs(const TagMap& tags, const std::vector<std::string_view>& keys)
|
||||||
|
{
|
||||||
|
std::optional<T> res;
|
||||||
|
std::vector<T> values {getPropertyValuesFirstMatchAs<T>(tags, keys)};
|
||||||
|
if (!values.empty())
|
||||||
|
res = std::move(values.front());
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::vector<T>
|
std::vector<T>
|
||||||
getPropertyValuesAs(const TagMap& tags, const std::string& key)
|
getPropertyValuesAs(const TagMap& tags, const std::string& key)
|
||||||
@@ -88,6 +100,13 @@ getPropertyValuesAs(const TagMap& tags, const std::string& key)
|
|||||||
return getPropertyValuesFirstMatchAs<T>(tags, {key});
|
return getPropertyValuesFirstMatchAs<T>(tags, {key});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::optional<T>
|
||||||
|
getPropertyValueAs(const TagMap& tags, const std::string& key)
|
||||||
|
{
|
||||||
|
return getPropertyValueFirstMatchAs<T>(tags, {key});
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
std::vector<std::string_view>
|
std::vector<std::string_view>
|
||||||
splitAndTrimString(std::string_view str, std::string_view delimiters)
|
splitAndTrimString(std::string_view str, std::string_view delimiters)
|
||||||
@@ -185,20 +204,70 @@ getRelease(const TagMap& tags)
|
|||||||
{
|
{
|
||||||
std::optional<Release> release;
|
std::optional<Release> release;
|
||||||
|
|
||||||
std::vector<std::string> releaseName {getPropertyValuesAs<std::string>(tags, "ALBUM")};
|
auto releaseName {getPropertyValueAs<std::string>(tags, "ALBUM")};
|
||||||
if (releaseName.empty())
|
if (!releaseName)
|
||||||
return release;
|
return release;
|
||||||
|
|
||||||
const std::vector<UUID> releaseMBID {getPropertyValuesFirstMatchAs<UUID>(tags, {"MUSICBRAINZ_ALBUMID", "MUSICBRAINZ ALBUM ID", "MUSICBRAINZ/ALBUM ID"})};
|
|
||||||
|
|
||||||
release.emplace();
|
release.emplace();
|
||||||
release->name = std::move(releaseName.front());
|
release->name = std::move(*releaseName);
|
||||||
if (!releaseMBID.empty())
|
release->mbid = getPropertyValueFirstMatchAs<UUID>(tags, {"MUSICBRAINZ_ALBUMID", "MUSICBRAINZ ALBUM ID", "MUSICBRAINZ/ALBUM ID"});
|
||||||
release->mbid = releaseMBID.front();
|
release->artists = getArtists(tags, {"ALBUMARTISTS", "ALBUMARTIST"}, {"ALBUMARTISTSSORT", "ALBUMARTISTSORT"}, {"MUSICBRAINZ_ALBUMARTISTID", "MUSICBRAINZ ALBUM ARTIST ID", "MUSICBRAINZ/ALBUM ARTIST ID"});
|
||||||
|
release->mediumCount = getPropertyValueAs<std::size_t>(tags, "DISCTOTAL");
|
||||||
|
if (!release->mediumCount)
|
||||||
|
{
|
||||||
|
// mediumCount may be encoded as "position/count"
|
||||||
|
if (const auto value {getPropertyValueAs<std::string>(tags, "DISCNUMBER")})
|
||||||
|
{
|
||||||
|
// Expecting 'Number/Total'
|
||||||
|
const std::vector<std::string_view> strings {StringUtils::splitString(*value, "/") };
|
||||||
|
if (strings.size() == 2)
|
||||||
|
release->mediumCount = StringUtils::readAs<std::size_t>(strings[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return release;
|
return release;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
std::optional<Medium>
|
||||||
|
getMedium(const TagMap& tags)
|
||||||
|
{
|
||||||
|
std::optional<Medium> medium;
|
||||||
|
medium.emplace();
|
||||||
|
|
||||||
|
medium->type = getPropertyValueAs<std::string>(tags, "MEDIA").value_or("");
|
||||||
|
medium->name = getPropertyValueFirstMatchAs<std::string>(tags, {"DISCSUBTITLE", "SETSUBTITLE"}).value_or("");
|
||||||
|
medium->trackCount = getPropertyValueAs<std::size_t>(tags, "TRACKTOTAL");
|
||||||
|
if (!medium->trackCount)
|
||||||
|
{
|
||||||
|
// totalTracks may be encoded as "position/count"
|
||||||
|
if (const auto value {getPropertyValueAs<std::string>(tags, "TRACKNUMBER")})
|
||||||
|
{
|
||||||
|
// Expecting 'Number/Total'
|
||||||
|
const std::vector<std::string_view> strings {StringUtils::splitString(*value, "/") };
|
||||||
|
if (strings.size() == 2)
|
||||||
|
medium->trackCount = StringUtils::readAs<std::size_t>(strings[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// Expecting 'Number[/Total]'
|
||||||
|
medium->position = getPropertyValueAs<std::size_t>(tags, "DISCNUMBER");
|
||||||
|
medium->release = getRelease(tags);
|
||||||
|
medium->replayGain = getPropertyValueAs<float>(tags, "REPLAYGAIN_ALBUM_GAIN");
|
||||||
|
|
||||||
|
if (medium->type.empty()
|
||||||
|
&& medium->name.empty()
|
||||||
|
&& !medium->trackCount
|
||||||
|
&& !medium->position
|
||||||
|
&& !medium->release
|
||||||
|
&& !medium->replayGain)
|
||||||
|
{
|
||||||
|
medium.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return medium;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TagLib::AudioProperties::ReadStyle
|
TagLib::AudioProperties::ReadStyle
|
||||||
readStyleToTagLibReadStyle(ParserReadStyle readStyle)
|
readStyleToTagLibReadStyle(ParserReadStyle readStyle)
|
||||||
@@ -227,13 +296,6 @@ TagLibParser::processTag(Track& track, const std::string& tag, const std::vector
|
|||||||
if (tag.empty() || values.empty())
|
if (tag.empty() || values.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto getOrCreateMedium = [&]() -> Medium&
|
|
||||||
{
|
|
||||||
if (!track.medium)
|
|
||||||
track.medium.emplace();
|
|
||||||
return *track.medium;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string_view value {values.front()};
|
std::string_view value {values.front()};
|
||||||
|
|
||||||
if (tag == "TITLE")
|
if (tag == "TITLE")
|
||||||
@@ -250,41 +312,10 @@ TagLibParser::processTag(Track& track, const std::string& tag, const std::vector
|
|||||||
track.recordingMBID = UUID::fromString(value);
|
track.recordingMBID = UUID::fromString(value);
|
||||||
else if (tag == "ACOUSTID_ID")
|
else if (tag == "ACOUSTID_ID")
|
||||||
track.acoustID = UUID::fromString(value);
|
track.acoustID = UUID::fromString(value);
|
||||||
else if (tag == "TRACKTOTAL")
|
|
||||||
{
|
|
||||||
getOrCreateMedium().trackCount = StringUtils::readAs<std::size_t>(value);
|
|
||||||
}
|
|
||||||
else if (tag == "TRACKNUMBER")
|
else if (tag == "TRACKNUMBER")
|
||||||
{
|
{
|
||||||
// Expecting 'Number/Total'
|
// Expecting 'Number/Total'
|
||||||
std::vector<std::string_view> strings {splitAndTrimString(value, "/")};
|
track.position = StringUtils::readAs<std::size_t>(value);
|
||||||
|
|
||||||
if (!strings.empty())
|
|
||||||
{
|
|
||||||
track.position = StringUtils::readAs<std::size_t>(strings[0]);
|
|
||||||
|
|
||||||
// Lower priority than TRACKTOTAL
|
|
||||||
if (strings.size() > 1 && !getOrCreateMedium().trackCount)
|
|
||||||
getOrCreateMedium().trackCount = StringUtils::readAs<std::size_t>(strings[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (tag == "DISCTOTAL")
|
|
||||||
{
|
|
||||||
if (track.release)
|
|
||||||
track.release->mediumCount = StringUtils::readAs<std::size_t>(value);
|
|
||||||
}
|
|
||||||
else if (tag == "DISCNUMBER")
|
|
||||||
{
|
|
||||||
// Expecting 'Number/Total'
|
|
||||||
std::vector<std::string_view> strings {StringUtils::splitString(value, "/")};
|
|
||||||
if (!strings.empty())
|
|
||||||
{
|
|
||||||
getOrCreateMedium().position = StringUtils::readAs<std::size_t>(strings[0]);
|
|
||||||
|
|
||||||
// Lower priority than DISCTOTAL
|
|
||||||
if (strings.size() > 1 && track.release && !track.release->mediumCount)
|
|
||||||
track.release->mediumCount = StringUtils::readAs<std::size_t>(strings[1]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (tag == "DATE")
|
else if (tag == "DATE")
|
||||||
{
|
{
|
||||||
@@ -314,14 +345,8 @@ TagLibParser::processTag(Track& track, const std::string& tag, const std::vector
|
|||||||
track.copyright = value;
|
track.copyright = value;
|
||||||
else if (tag == "COPYRIGHTURL")
|
else if (tag == "COPYRIGHTURL")
|
||||||
track.copyrightURL = value;
|
track.copyrightURL = value;
|
||||||
else if (tag == "REPLAYGAIN_ALBUM_GAIN")
|
|
||||||
getOrCreateMedium().replayGain = StringUtils::readAs<float>(value);
|
|
||||||
else if (tag == "REPLAYGAIN_TRACK_GAIN")
|
else if (tag == "REPLAYGAIN_TRACK_GAIN")
|
||||||
track.replayGain = StringUtils::readAs<float>(value);
|
track.replayGain = StringUtils::readAs<float>(value);
|
||||||
else if (tag == "DISCSUBTITLE" || tag == "SETSUBTITLE")
|
|
||||||
getOrCreateMedium().name = value;
|
|
||||||
else if (tag == "MEDIA")
|
|
||||||
getOrCreateMedium().type = value;
|
|
||||||
else if (_clusterTypeNames.find(tag) != _clusterTypeNames.end())
|
else if (_clusterTypeNames.find(tag) != _clusterTypeNames.end())
|
||||||
{
|
{
|
||||||
std::set<std::string> clusterNames;
|
std::set<std::string> clusterNames;
|
||||||
@@ -395,7 +420,7 @@ TagLibParser::parse(const std::filesystem::path& p, bool debug)
|
|||||||
track.duration = std::chrono::milliseconds {properties->lengthInMilliseconds()};
|
track.duration = std::chrono::milliseconds {properties->lengthInMilliseconds()};
|
||||||
|
|
||||||
MetaData::AudioStream audioStream {static_cast<unsigned>(properties->bitrate() * 1000)};
|
MetaData::AudioStream audioStream {static_cast<unsigned>(properties->bitrate() * 1000)};
|
||||||
track.audioStreams = {std::move(audioStream)};
|
track.audioStreams = {audioStream};
|
||||||
}
|
}
|
||||||
|
|
||||||
TagMap tags {constructTagMap(f.file()->properties())};
|
TagMap tags {constructTagMap(f.file()->properties())};
|
||||||
@@ -492,9 +517,7 @@ TagLibParser::parse(const std::filesystem::path& p, bool debug)
|
|||||||
track.hasCover = true;
|
track.hasCover = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
track.release = getRelease(tags);
|
track.medium = getMedium(tags);
|
||||||
if (track.release)
|
|
||||||
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.artists = getArtists(tags, {"ARTISTS", "ARTIST"}, {"ARTISTSORT"}, {"MUSICBRAINZ_ARTISTID", "MUSICBRAINZ ARTIST ID", "MUSICBRAINZ/ARTIST ID"});
|
||||||
track.conductorArtists = getArtists(tags, {"CONDUCTORS", "CONDUCTOR"}, {"CONDUCTORSSORT", "CONDUCTORSORT"}, {});
|
track.conductorArtists = getArtists(tags, {"CONDUCTORS", "CONDUCTOR"}, {"CONDUCTORSSORT", "CONDUCTORSORT"}, {});
|
||||||
track.composerArtists = getArtists(tags, {"COMPOSERS", "COMPOSER"}, {"COMPOSERSSORT", "COMPOSERSORT"}, {});
|
track.composerArtists = getArtists(tags, {"COMPOSERS", "COMPOSER"}, {"COMPOSERSSORT", "COMPOSERSORT"}, {});
|
||||||
|
|||||||
@@ -38,5 +38,6 @@ namespace MetaData::Utils
|
|||||||
|
|
||||||
// format is "artist name (role)"
|
// format is "artist name (role)"
|
||||||
PerformerArtist extractPerformerAndRole(std::string_view entry);
|
PerformerArtist extractPerformerAndRole(std::string_view entry);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ namespace MetaData
|
|||||||
{
|
{
|
||||||
using Tags = std::map<std::string /* type */, std::set<std::string> /* names */>;
|
using Tags = std::map<std::string /* type */, std::set<std::string> /* names */>;
|
||||||
|
|
||||||
|
// Very simplified version of https://musicbrainz.org/doc/MusicBrainz_Database/Schema
|
||||||
|
|
||||||
struct Artist
|
struct Artist
|
||||||
{
|
{
|
||||||
std::optional<UUID> mbid;
|
std::optional<UUID> mbid;
|
||||||
@@ -59,6 +61,7 @@ namespace MetaData
|
|||||||
{
|
{
|
||||||
std::string type;
|
std::string type;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
std::optional<Release> release;
|
||||||
std::optional<std::size_t> position; // in release
|
std::optional<std::size_t> position; // in release
|
||||||
std::optional<std::size_t> trackCount;
|
std::optional<std::size_t> trackCount;
|
||||||
std::optional<float> replayGain;
|
std::optional<float> replayGain;
|
||||||
@@ -76,7 +79,6 @@ namespace MetaData
|
|||||||
std::string title;
|
std::string title;
|
||||||
std::optional<Medium> medium;
|
std::optional<Medium> medium;
|
||||||
std::optional<std::size_t> position; // in medium
|
std::optional<std::size_t> position; // in medium
|
||||||
std::optional<Release> release;
|
|
||||||
Tags tags;
|
Tags tags;
|
||||||
std::chrono::milliseconds duration;
|
std::chrono::milliseconds duration;
|
||||||
Wt::WDate date;
|
Wt::WDate date;
|
||||||
|
|||||||
@@ -393,9 +393,9 @@ namespace Scanner
|
|||||||
for (const Artist::pointer& artist : getOrCreateArtists(dbSession, trackInfo->artists, false))
|
for (const Artist::pointer& artist : getOrCreateArtists(dbSession, trackInfo->artists, false))
|
||||||
track.modify()->addArtistLink(TrackArtistLink::create(dbSession, track, artist, TrackArtistLinkType::Artist));
|
track.modify()->addArtistLink(TrackArtistLink::create(dbSession, track, artist, TrackArtistLinkType::Artist));
|
||||||
|
|
||||||
if (trackInfo->release)
|
if (trackInfo->medium && trackInfo->medium->release)
|
||||||
{
|
{
|
||||||
for (const Artist::pointer& releaseArtist : getOrCreateArtists(dbSession, trackInfo->release->artists, false))
|
for (const Artist::pointer& releaseArtist : getOrCreateArtists(dbSession, trackInfo->medium->release->artists, false))
|
||||||
track.modify()->addArtistLink(TrackArtistLink::create(dbSession, track, releaseArtist, TrackArtistLinkType::ReleaseArtist));
|
track.modify()->addArtistLink(TrackArtistLink::create(dbSession, track, releaseArtist, TrackArtistLinkType::ReleaseArtist));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,8 +426,8 @@ namespace Scanner
|
|||||||
track.modify()->addArtistLink(TrackArtistLink::create(dbSession, track, remixer, TrackArtistLinkType::Remixer));
|
track.modify()->addArtistLink(TrackArtistLink::create(dbSession, track, remixer, TrackArtistLinkType::Remixer));
|
||||||
|
|
||||||
track.modify()->setScanVersion(_settings.scanVersion);
|
track.modify()->setScanVersion(_settings.scanVersion);
|
||||||
if (trackInfo->release)
|
if (trackInfo->medium && trackInfo->medium->release)
|
||||||
track.modify()->setRelease(getOrCreateRelease(dbSession, *trackInfo->release));
|
track.modify()->setRelease(getOrCreateRelease(dbSession, *trackInfo->medium->release));
|
||||||
else
|
else
|
||||||
track.modify()->setRelease({});
|
track.modify()->setRelease({});
|
||||||
track.modify()->setTotalTrack(trackInfo->medium ? trackInfo->medium->trackCount : std::nullopt);
|
track.modify()->setTotalTrack(trackInfo->medium ? trackInfo->medium->trackCount : std::nullopt);
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ std::ostream&
|
|||||||
operator<<(std::ostream& os, const MetaData::Medium& medium)
|
operator<<(std::ostream& os, const MetaData::Medium& medium)
|
||||||
{
|
{
|
||||||
if (!medium.name.empty())
|
if (!medium.name.empty())
|
||||||
os << medium.name << std::endl;
|
os << medium.name;
|
||||||
|
os << std::endl;
|
||||||
|
|
||||||
if (medium.position)
|
if (medium.position)
|
||||||
os << "\tPosition: " << *medium.position << std::endl;
|
os << "\tPosition: " << *medium.position << std::endl;
|
||||||
@@ -81,6 +82,9 @@ operator<<(std::ostream& os, const MetaData::Medium& medium)
|
|||||||
if (medium.replayGain)
|
if (medium.replayGain)
|
||||||
std::cout << "\tReplay gain: " << *medium.replayGain << std::endl;
|
std::cout << "\tReplay gain: " << *medium.replayGain << std::endl;
|
||||||
|
|
||||||
|
if (medium.release)
|
||||||
|
std::cout << "Release: " << *medium.release << std::endl;
|
||||||
|
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +105,7 @@ void parse(MetaData::IParser& parser, const std::filesystem::path& file)
|
|||||||
|
|
||||||
std::cout << "Parsing time: " << std::fixed << std::setprecision(2) << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() / 1000. << "ms" << std::endl;
|
std::cout << "Parsing time: " << std::fixed << std::setprecision(2) << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() / 1000. << "ms" << std::endl;
|
||||||
|
|
||||||
std::cout << "Track metadata:" << std::endl;
|
std::cout << "Parsed metadata:" << std::endl;
|
||||||
|
|
||||||
for (const Artist& artist : track->artists)
|
for (const Artist& artist : track->artists)
|
||||||
std::cout << "Artist: " << artist << std::endl;
|
std::cout << "Artist: " << artist << std::endl;
|
||||||
@@ -134,9 +138,6 @@ void parse(MetaData::IParser& parser, const std::filesystem::path& file)
|
|||||||
for (const Artist& artist : track->remixerArtists)
|
for (const Artist& artist : track->remixerArtists)
|
||||||
std::cout << "Remixer: " << artist << std::endl;
|
std::cout << "Remixer: " << artist << std::endl;
|
||||||
|
|
||||||
if (track->release)
|
|
||||||
std::cout << "Release: " << *track->release;
|
|
||||||
|
|
||||||
if (track->medium)
|
if (track->medium)
|
||||||
std::cout << "Medium: " << *track->medium;
|
std::cout << "Medium: " << *track->medium;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user