Allowed custom release types + handle more MusicBrainz secondary types in UI. fixes #373
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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} };
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user