Allowed custom release types + handle more MusicBrainz secondary types in UI. fixes #373

This commit is contained in:
emeric
2023-12-11 23:25:58 +01:00
parent a2cc243a08
commit 3ad990a183
33 changed files with 793 additions and 725 deletions
+3 -3
View File
@@ -226,15 +226,15 @@ namespace MetaData
{
track.recordingMBID = UUID::fromString(value);
}
else if (std::find(std::cbegin(_extraTags), std::cend(_extraTags), tag) != std::cend(_extraTags))
else if (std::find(std::cbegin(_userExtraTags), std::cend(_userExtraTags), tag) != std::cend(_userExtraTags))
{
const std::vector<std::string_view> tagValues{ StringUtils::splitString(value, "/,;") };
if (!tagValues.empty())
{
std::set<std::string> values;
std::vector<std::string> values;
std::transform(std::cbegin(tagValues), std::cend(tagValues), std::inserter(values, std::begin(values)), [](std::string_view v) { return std::string{ v }; });
track.tags[tag] = std::move(values);
track.userExtraTags[tag] = std::move(values);
}
}
}
+5 -10
View File
@@ -214,12 +214,7 @@ namespace MetaData
}
}
release->primaryType = getPropertyValueFirstMatchAs<MetaData::Release::PrimaryType>(tags, { "MUSICBRAINZ_ALBUMTYPE", "RELEASETYPE", "MUSICBRAINZ ALBUM TYPE", "MUSICBRAINZ/ALBUM TYPE" });
if (release->primaryType)
{
const auto secondaryTypes{ getPropertyValuesFirstMatchAs<MetaData::Release::SecondaryType>(tags, {"MUSICBRAINZ_ALBUMTYPE", "RELEASETYPE", "MUSICBRAINZ ALBUM TYPE", "MUSICBRAINZ/ALBUM TYPE"}) };
release->secondaryTypes.assign(std::cbegin(secondaryTypes), std::cend(secondaryTypes));
}
release->releaseTypes = getPropertyValuesFirstMatchAs<std::string>(tags, { "MUSICBRAINZ_ALBUMTYPE", "RELEASETYPE", "MUSICBRAINZ ALBUM TYPE", "MUSICBRAINZ/ALBUM TYPE" });
return release;
}
@@ -368,18 +363,18 @@ namespace MetaData
track.replayGain = StringUtils::readAs<float>(value);
else if (tag == "ARTIST")
track.artistDisplayName = value;
else if (std::find(std::cbegin(_extraTags), std::cend(_extraTags), tag) != std::cend(_extraTags))
else if (std::find(std::cbegin(_userExtraTags), std::cend(_userExtraTags), tag) != std::cend(_userExtraTags))
{
std::set<std::string> tagValues;
std::vector<std::string> tagValues;
for (std::string_view valueList : values)
{
const std::vector<std::string_view> splittedValues{ splitAndTrimString(valueList, "/,;") }; // handle possibily bad split tags
for (std::string_view value : splittedValues)
tagValues.insert(std::string{ value });
tagValues.push_back(std::string{ value });
}
if (!tagValues.empty())
track.tags[tag] = std::move(tagValues);
track.userExtraTags[tag] = std::move(tagValues);
}
}
+74 -125
View File
@@ -27,142 +27,91 @@
namespace MetaData::Utils
{
Wt::WDate
parseDate(std::string_view dateStr)
{
static constexpr const char* formats[]
{
"%Y-%m-%d",
"%Y/%m/%d",
};
Wt::WDate parseDate(std::string_view dateStr)
{
static constexpr const char* formats[]
{
"%Y-%m-%d",
"%Y/%m/%d",
};
for (const char* format : formats)
{
std::tm tm = {};
std::istringstream ss {std::string {dateStr}}; // TODO, remove extra copy here
ss >> std::get_time(&tm, format);
if (ss.fail())
continue;
for (const char* format : formats)
{
std::tm tm = {};
std::istringstream ss{ std::string {dateStr} }; // TODO, remove extra copy here
ss >> std::get_time(&tm, format);
if (ss.fail())
continue;
const Wt::WDate res
{
tm.tm_year + 1900, // years since 1900
tm.tm_mon + 1, // months since January [0, 11]
tm.tm_mday ? tm.tm_mday : 1 // day of the month [1, 31]
};
if (!res.isValid())
continue;
const Wt::WDate res
{
tm.tm_year + 1900, // years since 1900
tm.tm_mon + 1, // months since January [0, 11]
tm.tm_mday ? tm.tm_mday : 1 // day of the month [1, 31]
};
if (!res.isValid())
continue;
return res;
}
return res;
}
return {};
}
return {};
}
std::string_view
readStyleToString(ParserReadStyle readStyle)
{
switch (readStyle)
{
case ParserReadStyle::Fast: return "fast";
case ParserReadStyle::Average: return "average";
case ParserReadStyle::Accurate: return "accurate";
}
std::string_view readStyleToString(ParserReadStyle readStyle)
{
switch (readStyle)
{
case ParserReadStyle::Fast: return "fast";
case ParserReadStyle::Average: return "average";
case ParserReadStyle::Accurate: return "accurate";
}
throw LmsException {"Unknown read style"};
}
throw LmsException{ "Unknown read style" };
}
PerformerArtist
extractPerformerAndRole(std::string_view entry)
{
std::string_view artistName;
std::string_view role;
PerformerArtist extractPerformerAndRole(std::string_view entry)
{
std::string_view artistName;
std::string_view role;
std::size_t roleBegin {};
std::size_t roleEnd {};
std::size_t count {};
std::size_t roleBegin{};
std::size_t roleEnd{};
std::size_t count{};
for (std::size_t i {}; i < entry.size(); ++i)
{
std::size_t currentIndex {entry.size() - i - 1};
const char c {entry[currentIndex]};
for (std::size_t i{}; i < entry.size(); ++i)
{
std::size_t currentIndex{ entry.size() - i - 1 };
const char c{ entry[currentIndex] };
if (std::isspace(c))
continue;
if (std::isspace(c))
continue;
if (c == ')')
{
if (count++ == 0)
roleEnd = currentIndex;
}
else if (c == '(')
{
if (count == 0)
break;
if (c == ')')
{
if (count++ == 0)
roleEnd = currentIndex;
}
else if (c == '(')
{
if (count == 0)
break;
if (--count == 0)
{
roleBegin = currentIndex + 1;
role = StringUtils::stringTrim(entry.substr(roleBegin, roleEnd - roleBegin));
artistName = StringUtils::stringTrim(entry.substr(0, currentIndex));
break;
}
}
else if (count == 0)
break;
}
if (--count == 0)
{
roleBegin = currentIndex + 1;
role = StringUtils::stringTrim(entry.substr(roleBegin, roleEnd - roleBegin));
artistName = StringUtils::stringTrim(entry.substr(0, currentIndex));
break;
}
}
else if (count == 0)
break;
}
if (!roleEnd || !roleBegin)
artistName = StringUtils::stringTrim(entry);
return PerformerArtist {Artist {artistName}, std::string {role}};
}
}
namespace StringUtils
{
static bool iequals(std::string_view a, std::string_view b)
{
return std::equal(std::cbegin(a), std::cend(a),
std::cbegin(b), std::cend(b),
[](char a, char b) { return tolower(a) == tolower(b);}
);
}
template<>
std::optional<MetaData::Release::PrimaryType> readAs(std::string_view str)
{
str = stringTrim(str);
if (iequals(str, "album"))
return MetaData::Release::PrimaryType::Album;
else if (iequals(str, "single"))
return MetaData::Release::PrimaryType::Single;
else if (iequals(str, "EP"))
return MetaData::Release::PrimaryType::EP;
else if (iequals(str, "broadcast"))
return MetaData::Release::PrimaryType::Broadcast;
else if (iequals(str, "other"))
return MetaData::Release::PrimaryType::Other;
return std::nullopt;
}
template<>
std::optional<MetaData::Release::SecondaryType> readAs(std::string_view str)
{
str = stringTrim(str);
if (iequals(str, "compilation"))
return MetaData::Release::SecondaryType::Compilation;
else if (iequals(str, "soundtrack"))
return MetaData::Release::SecondaryType::Soundtrack;
else if (iequals(str, "live"))
return MetaData::Release::SecondaryType::Live;
else if (iequals(str, "demo"))
return MetaData::Release::SecondaryType::Demo;
return std::nullopt;
}
}
if (!roleEnd || !roleBegin)
artistName = StringUtils::stringTrim(entry);
return PerformerArtist{ Artist {artistName}, std::string {role} };
}
}
-10
View File
@@ -39,13 +39,3 @@ namespace MetaData::Utils
// format is "artist name (role)"
PerformerArtist extractPerformerAndRole(std::string_view entry);
}
namespace StringUtils
{
template<>
std::optional<MetaData::Release::PrimaryType> readAs(std::string_view str);
template<>
std::optional<MetaData::Release::SecondaryType> readAs(std::string_view str);
}