Split the utils file
This commit is contained in:
+4
-2
@@ -55,7 +55,6 @@ lms_SOURCES = \
|
||||
$(srcdir)/main/main.cpp \
|
||||
$(srcdir)/metadata/AvFormat.cpp \
|
||||
$(srcdir)/metadata/AvFormat.hpp \
|
||||
$(srcdir)/metadata/MetaData.cpp \
|
||||
$(srcdir)/metadata/MetaData.hpp \
|
||||
$(srcdir)/metadata/TagLibParser.cpp \
|
||||
$(srcdir)/metadata/TagLibParser.hpp \
|
||||
@@ -155,10 +154,13 @@ lms_SOURCES = \
|
||||
$(srcdir)/utils/NetAddress.hpp \
|
||||
$(srcdir)/utils/Path.cpp \
|
||||
$(srcdir)/utils/Path.hpp \
|
||||
$(srcdir)/utils/Random.cpp \
|
||||
$(srcdir)/utils/Random.hpp \
|
||||
$(srcdir)/utils/Service.hpp \
|
||||
$(srcdir)/utils/StreamLogger.cpp \
|
||||
$(srcdir)/utils/StreamLogger.hpp \
|
||||
$(srcdir)/utils/Utils.cpp \
|
||||
$(srcdir)/utils/String.cpp \
|
||||
$(srcdir)/utils/String.hpp \
|
||||
$(srcdir)/utils/Utils.hpp \
|
||||
$(srcdir)/utils/UUID.cpp \
|
||||
$(srcdir)/utils/UUID.hpp \
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "SubsonicResponse.hpp"
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
namespace API::Subsonic
|
||||
{
|
||||
@@ -33,7 +33,7 @@ IdFromString(const std::string& id)
|
||||
if (id == "root")
|
||||
return Id {Id::Type::Root};
|
||||
|
||||
std::vector<std::string> values {splitString(id, "-")};
|
||||
std::vector<std::string> values {StringUtils::splitString(id, "-")};
|
||||
if (values.size() != 2)
|
||||
return std::nullopt;
|
||||
|
||||
@@ -51,7 +51,7 @@ IdFromString(const std::string& id)
|
||||
else
|
||||
return std::nullopt;
|
||||
|
||||
auto optId {readAs<Database::IdType>(values[1])};
|
||||
auto optId {StringUtils::readAs<Database::IdType>(values[1])};
|
||||
if (!optId)
|
||||
return std::nullopt;
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "similarity/SimilaritySearcher.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/String.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "SubsonicId.hpp"
|
||||
#include "SubsonicResponse.hpp"
|
||||
@@ -52,65 +53,69 @@ static const std::string reportedStarredDate {"2000-01-01T00:00:00"};
|
||||
static const std::string reportedCreatedBookmarkDate {"2000-01-01T00:00:00"};
|
||||
static const std::string reportedChangedBookmarkDate {"2000-01-01T00:00:00"};
|
||||
|
||||
template<>
|
||||
std::optional<API::Subsonic::Id>
|
||||
readAs(const std::string& str)
|
||||
{
|
||||
return API::Subsonic::IdFromString(str);
|
||||
}
|
||||
|
||||
template<>
|
||||
std::optional<bool>
|
||||
readAs(const std::string& str)
|
||||
{
|
||||
if (str == "true")
|
||||
return true;
|
||||
else if (str == "false")
|
||||
return false;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
namespace API::Subsonic
|
||||
{
|
||||
struct ClientVersion
|
||||
{
|
||||
unsigned major {};
|
||||
unsigned minor {};
|
||||
unsigned patch {};
|
||||
};
|
||||
struct ClientVersion
|
||||
{
|
||||
unsigned major {};
|
||||
unsigned minor {};
|
||||
unsigned patch {};
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
std::optional<API::Subsonic::ClientVersion>
|
||||
readAs(const std::string& str)
|
||||
namespace StringUtils
|
||||
{
|
||||
// Expects "X.Y.Z"
|
||||
const auto numbers {splitString(str, ".")};
|
||||
if (numbers.size() < 2 || numbers.size() > 3)
|
||||
return std::nullopt;
|
||||
|
||||
API::Subsonic::ClientVersion version;
|
||||
|
||||
auto number {readAs<unsigned>(numbers[0])};
|
||||
if (!number)
|
||||
return std::nullopt;
|
||||
version.major = *number;
|
||||
|
||||
number = {readAs<unsigned>(numbers[1])};
|
||||
if (!number)
|
||||
return std::nullopt;
|
||||
version.minor = *number;
|
||||
|
||||
if (numbers.size() == 3)
|
||||
template<>
|
||||
std::optional<API::Subsonic::Id>
|
||||
StringUtils::readAs(const std::string& str)
|
||||
{
|
||||
number = {readAs<unsigned>(numbers[2])};
|
||||
if (!number)
|
||||
return std::nullopt;
|
||||
version.patch = *number;
|
||||
return API::Subsonic::IdFromString(str);
|
||||
}
|
||||
|
||||
template<>
|
||||
std::optional<bool>
|
||||
StringUtils::readAs(const std::string& str)
|
||||
{
|
||||
if (str == "true")
|
||||
return true;
|
||||
else if (str == "false")
|
||||
return false;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
std::optional<API::Subsonic::ClientVersion>
|
||||
StringUtils::readAs(const std::string& str)
|
||||
{
|
||||
// Expects "X.Y.Z"
|
||||
const auto numbers {StringUtils::splitString(str, ".")};
|
||||
if (numbers.size() < 2 || numbers.size() > 3)
|
||||
return std::nullopt;
|
||||
|
||||
API::Subsonic::ClientVersion version;
|
||||
|
||||
auto number {StringUtils::readAs<unsigned>(numbers[0])};
|
||||
if (!number)
|
||||
return std::nullopt;
|
||||
version.major = *number;
|
||||
|
||||
number = {StringUtils::readAs<unsigned>(numbers[1])};
|
||||
if (!number)
|
||||
return std::nullopt;
|
||||
version.minor = *number;
|
||||
|
||||
if (numbers.size() == 3)
|
||||
{
|
||||
number = {StringUtils::readAs<unsigned>(numbers[2])};
|
||||
if (!number)
|
||||
return std::nullopt;
|
||||
version.patch = *number;
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +141,7 @@ static
|
||||
std::string
|
||||
makeNameFilesystemCompatible(const std::string& name)
|
||||
{
|
||||
return replaceInString(name, "/", "_");
|
||||
return StringUtils::replaceInString(name, "/", "_");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -151,7 +156,7 @@ getMultiParametersAs(const Wt::Http::ParameterMap& parameterMap, const std::stri
|
||||
|
||||
for (const std::string& param : it->second)
|
||||
{
|
||||
auto value {readAs<T>(param)};
|
||||
auto value {StringUtils::readAs<T>(param)};
|
||||
if (!value)
|
||||
throw BadParameterFormatGenericError {paramName};
|
||||
|
||||
@@ -201,7 +206,7 @@ decodePasswordIfNeeded(const std::string& password)
|
||||
{
|
||||
if (password.find("enc:") == 0)
|
||||
{
|
||||
auto decodedPassword {stringFromHex(password.substr(4))};
|
||||
auto decodedPassword {StringUtils::stringFromHex(password.substr(4))};
|
||||
if (!decodedPassword)
|
||||
return password; // fallback on plain password
|
||||
|
||||
@@ -310,7 +315,7 @@ getArtistNames(const std::vector<Artist::pointer>& artists)
|
||||
return artist->getName();
|
||||
});
|
||||
|
||||
return joinStrings(names, ", ");
|
||||
return StringUtils::joinStrings(names, ", ");
|
||||
}
|
||||
|
||||
static
|
||||
@@ -1386,7 +1391,7 @@ handleSearchRequestCommon(RequestContext& context, bool id3)
|
||||
// Mandatory params
|
||||
std::string query {getMandatoryParameterAs<std::string>(context.parameters, "query")};
|
||||
|
||||
std::vector<std::string> keywords {splitString(query, " ")};
|
||||
std::vector<std::string> keywords {StringUtils::splitString(query, " ")};
|
||||
|
||||
// Optional params
|
||||
std::size_t artistCount {getParameterAs<std::size_t>(context.parameters, "artistCount").value_or(20)};
|
||||
@@ -2035,7 +2040,7 @@ SubsonicResource::handleRequest(const Wt::Http::Request &request, Wt::Http::Resp
|
||||
LMS_LOG(API_SUBSONIC, DEBUG) << "Handling request " << requestId << " '" << request.pathInfo() << "', continuation = " << (request.continuation() ? "true" : "false") << ", params = " << parameterMapToDebugString(request.getParameterMap());
|
||||
|
||||
std::string requestPath {request.pathInfo()};
|
||||
if (stringEndsWith(requestPath, ".view"))
|
||||
if (StringUtils::stringEndsWith(requestPath, ".view"))
|
||||
requestPath.resize(requestPath.length() - 5);
|
||||
|
||||
const Wt::Http::ParameterMap& parameters {request.getParameterMap()};
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include "database/Session.hpp"
|
||||
#include "utils/Exception.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
|
||||
namespace Auth {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "LoginThrottler.hpp"
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/Random.hpp"
|
||||
|
||||
namespace Auth {
|
||||
|
||||
@@ -71,7 +71,7 @@ LoginThrottler::onBadClientAttempt(const boost::asio::ip::address& address)
|
||||
if (_attemptsInfo.size() >= _maxEntries)
|
||||
removeOutdatedEntries();
|
||||
if (_attemptsInfo.size() >= _maxEntries)
|
||||
_attemptsInfo.erase(pickRandom(_attemptsInfo));
|
||||
_attemptsInfo.erase(Random::pickRandom(_attemptsInfo));
|
||||
|
||||
_attemptsInfo[address] = now.addSecs(3);
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#include "database/Session.hpp"
|
||||
#include "utils/Exception.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
|
||||
namespace Auth {
|
||||
|
||||
+5
-4
@@ -24,7 +24,7 @@
|
||||
#include <array>
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
namespace Av {
|
||||
|
||||
@@ -230,19 +230,20 @@ MediaFile::getAttachedPictures(std::size_t nbMaxPictures) const
|
||||
return pictures;
|
||||
}
|
||||
|
||||
std::optional<MediaFileFormat> guessMediaFileFormat(const std::filesystem::path& file)
|
||||
std::optional<MediaFileFormat>
|
||||
guessMediaFileFormat(const std::filesystem::path& file)
|
||||
{
|
||||
AVOutputFormat* format {av_guess_format(NULL,file.string().c_str(),NULL)};
|
||||
if (!format || !format->name)
|
||||
return {};
|
||||
|
||||
auto formats {splitString(format->name, ",")};
|
||||
auto formats {StringUtils::splitString(format->name, ",")};
|
||||
if (formats.size() > 1)
|
||||
LMS_LOG(AV, INFO) << "File '" << file.string() << "' reported several formats: '" << format->name << "'";
|
||||
|
||||
std::vector<std::string> mimeTypes;
|
||||
if (format->mime_type)
|
||||
mimeTypes = splitString(format->mime_type, ",");
|
||||
mimeTypes = StringUtils::splitString(format->mime_type, ",");
|
||||
|
||||
if (mimeTypes.empty())
|
||||
LMS_LOG(AV, INFO) << "File '" << file.string() << "', no mime type found!";
|
||||
|
||||
@@ -71,7 +71,7 @@ class Artist : public Wt::Dbo::Dbo<Artist>
|
||||
|
||||
// Accessors
|
||||
const std::string& getName(void) const { return _name; }
|
||||
std::optional<UUID> getMBID(void) const { return readAs<UUID>(_MBID); }
|
||||
std::optional<UUID> getMBID(void) const { return UUID::fromString(_MBID); }
|
||||
|
||||
std::vector<Wt::Dbo::ptr<Release>> getReleases(const std::set<IdType>& clusterIds = {}) const; // if non empty, get the releases that match all these clusters
|
||||
std::size_t getReleaseCount() const;
|
||||
|
||||
@@ -89,7 +89,7 @@ class Release : public Wt::Dbo::Dbo<Release>
|
||||
|
||||
// Accessors
|
||||
std::string getName() const { return _name; }
|
||||
std::optional<UUID> getMBID() const { return readAs<UUID>(_MBID); }
|
||||
std::optional<UUID> getMBID() const { return UUID::fromString(_MBID); }
|
||||
std::optional<std::size_t> getTotalTrackNumber() const;
|
||||
std::optional<std::size_t> getTotalDiscNumber() const;
|
||||
std::chrono::milliseconds getDuration() const;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <Wt/Dbo/WtSqlTraits.h>
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "Cluster.hpp"
|
||||
#include "Session.hpp"
|
||||
@@ -65,7 +65,7 @@ ScanSettings::get(Session& session)
|
||||
std::set<std::filesystem::path>
|
||||
ScanSettings::getAudioFileExtensions() const
|
||||
{
|
||||
auto extensions = splitString(_audioFileExtensions, " ");
|
||||
auto extensions = StringUtils::splitString(_audioFileExtensions, " ");
|
||||
return std::set<std::filesystem::path>(std::cbegin(extensions), std::cend(extensions));
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ ScanSettings::getClusterTypes() const
|
||||
void
|
||||
ScanSettings::setMediaDirectory(const std::filesystem::path& p)
|
||||
{
|
||||
_mediaDirectory = stringTrimEnd(p.string(), "/\\");
|
||||
_mediaDirectory = StringUtils::stringTrimEnd(p.string(), "/\\");
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
|
||||
@@ -113,7 +113,7 @@ class Track : public Wt::Dbo::Dbo<Track>
|
||||
Wt::WDateTime getLastWriteTime() const { return _fileLastWrite; }
|
||||
Wt::WDateTime getAddedTime() const { return _fileAdded; }
|
||||
bool hasCover() const { return _hasCover; }
|
||||
std::optional<UUID> getMBID() const { return readAs<UUID>(_MBID); }
|
||||
std::optional<UUID> getMBID() const { return UUID::fromString(_MBID); }
|
||||
std::optional<std::string> getCopyright() const;
|
||||
std::optional<std::string> getCopyrightURL() const;
|
||||
std::vector<Wt::Dbo::ptr<Artist>> getArtists(TrackArtistLink::Type type = TrackArtistLink::Type::Artist) const;
|
||||
|
||||
+20
-16
@@ -19,10 +19,14 @@
|
||||
|
||||
#include "AvFormat.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include "av/AvInfo.hpp"
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
|
||||
namespace MetaData
|
||||
{
|
||||
@@ -37,7 +41,7 @@ findFirstValueOfAs(const MetadataMap& metadataMap, std::initializer_list<std::st
|
||||
if (it == std::cend(metadataMap))
|
||||
return std::nullopt;
|
||||
|
||||
return readAs<T>(stringTrim(it->second));
|
||||
return StringUtils::readAs<T>(StringUtils::stringTrim(it->second));
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -48,12 +52,12 @@ findFirstValueOfAs(const MetadataMap& metadataMap, std::initializer_list<std::st
|
||||
if (!str)
|
||||
return std::nullopt;
|
||||
|
||||
std::vector<std::string> strUuids = splitString(*str, "/");
|
||||
std::vector<std::string> strUuids = StringUtils::splitString(*str, "/");
|
||||
std::vector<UUID> res;
|
||||
|
||||
for (const std::string strUuid : strUuids)
|
||||
{
|
||||
std::optional<UUID> uuid {readAs<UUID>(strUuid)};
|
||||
std::optional<UUID> uuid {UUID::fromString(strUuid)};
|
||||
if (!uuid)
|
||||
return std::nullopt;
|
||||
|
||||
@@ -103,7 +107,7 @@ getArtists(const MetadataMap& metadataMap)
|
||||
std::vector<std::string> artistNames;
|
||||
if (metadataMap.find("ARTISTS") != metadataMap.end())
|
||||
{
|
||||
artistNames = splitString(metadataMap.find("ARTISTS")->second, "/;");
|
||||
artistNames = StringUtils::splitString(metadataMap.find("ARTISTS")->second, "/;");
|
||||
}
|
||||
else if (metadataMap.find("ARTIST") != metadataMap.end())
|
||||
{
|
||||
@@ -163,54 +167,54 @@ AvFormat::parse(const std::filesystem::path& p, bool debug)
|
||||
else if (tag == "TRACK")
|
||||
{
|
||||
// Expecting 'Number/Total'
|
||||
std::vector<std::string> strings {splitString(value, "/") };
|
||||
std::vector<std::string> strings {StringUtils::splitString(value, "/") };
|
||||
|
||||
if (strings.size() > 0)
|
||||
{
|
||||
track.trackNumber = readAs<std::size_t>(strings[0]);
|
||||
track.trackNumber = StringUtils::readAs<std::size_t>(strings[0]);
|
||||
|
||||
if (strings.size() > 1)
|
||||
track.totalTrack = readAs<std::size_t>(strings[1]);
|
||||
track.totalTrack = StringUtils::readAs<std::size_t>(strings[1]);
|
||||
}
|
||||
}
|
||||
else if (tag == "DISC")
|
||||
{
|
||||
// Expecting 'Number/Total'
|
||||
std::vector<std::string> strings {splitString(value, "/")};
|
||||
std::vector<std::string> strings {StringUtils::splitString(value, "/")};
|
||||
|
||||
if (strings.size() > 0)
|
||||
{
|
||||
track.discNumber = readAs<std::size_t>(strings[0]);
|
||||
track.discNumber = StringUtils::readAs<std::size_t>(strings[0]);
|
||||
|
||||
if (strings.size() > 1)
|
||||
track.totalDisc = readAs<std::size_t>(strings[1]);
|
||||
track.totalDisc = StringUtils::readAs<std::size_t>(strings[1]);
|
||||
}
|
||||
}
|
||||
else if (tag == "DATE"
|
||||
|| tag == "YEAR"
|
||||
|| tag == "WM/Year")
|
||||
{
|
||||
track.year = readAs<int>(value);
|
||||
track.year = StringUtils::readAs<int>(value);
|
||||
}
|
||||
else if (tag == "TDOR" // Original release time (ID3v2 2.4)
|
||||
|| tag == "TORY") // Original release year
|
||||
{
|
||||
track.originalYear = readAs<int>(value);
|
||||
track.originalYear = StringUtils::readAs<int>(value);
|
||||
}
|
||||
else if (tag == "ACOUSTID ID")
|
||||
{
|
||||
track.acoustID = readAs<UUID>(value);
|
||||
track.acoustID = UUID::fromString(value);
|
||||
}
|
||||
else if (tag == "MUSICBRAINZ RELEASE TRACK ID"
|
||||
|| tag == "MUSICBRAINZ_RELEASETRACKID"
|
||||
|| tag == "MUSICBRAINZ_TRACKID"
|
||||
|| tag == "MUSICBRAINZ/TRACK ID")
|
||||
{
|
||||
track.musicBrainzTrackID = readAs<UUID>(value);
|
||||
track.musicBrainzTrackID = UUID::fromString(value);
|
||||
}
|
||||
else if (_clusterTypeNames.find(tag) != _clusterTypeNames.end())
|
||||
{
|
||||
std::vector<std::string> clusterNames {splitString(value, "/,;")};
|
||||
std::vector<std::string> clusterNames {StringUtils::splitString(value, "/,;")};
|
||||
|
||||
if (!clusterNames.empty())
|
||||
track.clusters[tag] = std::set<std::string>{clusterNames.begin(), clusterNames.end()};
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/Utils.hpp"
|
||||
//#include "utils/Utils.hpp"
|
||||
#include "utils/UUID.hpp"
|
||||
|
||||
namespace MetaData
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
#include <taglib/tpropertymap.h>
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
|
||||
namespace MetaData
|
||||
{
|
||||
@@ -49,7 +50,7 @@ getPropertyValuesFirstMatchAs(const TagLib::PropertyMap& properties, const std::
|
||||
|
||||
for (const auto& value : values)
|
||||
{
|
||||
auto val {readAs<T>(stringTrim(value.to8Bit(true)))};
|
||||
auto val {StringUtils::readAs<T>(StringUtils::stringTrim(value.to8Bit(true)))};
|
||||
if (!val)
|
||||
continue;
|
||||
|
||||
@@ -75,9 +76,9 @@ splitAndTrimString(const std::string& str, const std::string& delimiters)
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
|
||||
std::vector<std::string> strings {splitString(str, delimiters)};
|
||||
std::vector<std::string> strings {StringUtils::splitString(str, delimiters)};
|
||||
for (const std::string& s : strings)
|
||||
res.emplace_back(stringTrim(s));
|
||||
res.emplace_back(StringUtils::stringTrim(s));
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -224,29 +225,29 @@ TagLibParser::parse(const std::filesystem::path& p, bool debug)
|
||||
std::vector<std::string> strs;
|
||||
std::transform(values.begin(), values.end(), std::back_inserter(strs), [](const auto& value) { return value.to8Bit(true); });
|
||||
|
||||
std::cout << "[" << tag << "] = " << joinStrings(strs, "*SEP*") << std::endl;
|
||||
std::cout << "[" << tag << "] = " << StringUtils::joinStrings(strs, "*SEP*") << std::endl;
|
||||
}
|
||||
|
||||
if (tag.empty() || values.isEmpty() || values.front().isEmpty())
|
||||
continue;
|
||||
|
||||
std::string value {stringTrim(values.front().to8Bit(true))};
|
||||
std::string value {StringUtils::stringTrim(values.front().to8Bit(true))};
|
||||
|
||||
if (tag == "TITLE")
|
||||
track.title = value;
|
||||
else if (tag == "MUSICBRAINZ_RELEASETRACKID"
|
||||
|| tag == "MUSICBRAINZ RELEASE TRACK ID")
|
||||
{
|
||||
track.musicBrainzTrackID = readAs<UUID>(value);
|
||||
track.musicBrainzTrackID = UUID::fromString(value);
|
||||
}
|
||||
else if (tag == "MUSICBRAINZ_TRACKID"
|
||||
|| tag == "MUSICBRAINZ TRACK ID")
|
||||
track.musicBrainzRecordID = readAs<UUID>(value);
|
||||
track.musicBrainzRecordID = UUID::fromString(value);
|
||||
else if (tag == "ACOUSTID_ID")
|
||||
track.acoustID = readAs<UUID>(value);
|
||||
track.acoustID = UUID::fromString(value);
|
||||
else if (tag == "TRACKTOTAL")
|
||||
{
|
||||
auto totalTrack = readAs<std::size_t>(value);
|
||||
auto totalTrack = StringUtils::readAs<std::size_t>(value);
|
||||
if (totalTrack)
|
||||
track.totalTrack = totalTrack;
|
||||
}
|
||||
@@ -257,44 +258,44 @@ TagLibParser::parse(const std::filesystem::path& p, bool debug)
|
||||
|
||||
if (!strings.empty())
|
||||
{
|
||||
track.trackNumber = readAs<std::size_t>(strings[0]);
|
||||
track.trackNumber = StringUtils::readAs<std::size_t>(strings[0]);
|
||||
|
||||
// Lower priority than TRACKTOTAL
|
||||
if (strings.size() > 1 && !track.totalTrack)
|
||||
track.totalTrack = readAs<std::size_t>(strings[1]);
|
||||
track.totalTrack = StringUtils::readAs<std::size_t>(strings[1]);
|
||||
}
|
||||
}
|
||||
else if (tag == "DISCTOTAL")
|
||||
{
|
||||
auto totalDisc = readAs<std::size_t>(value);
|
||||
auto totalDisc = StringUtils::readAs<std::size_t>(value);
|
||||
if (totalDisc)
|
||||
track.totalDisc = totalDisc;
|
||||
}
|
||||
else if (tag == "DISCNUMBER")
|
||||
{
|
||||
// Expecting 'Number/Total'
|
||||
std::vector<std::string> strings {splitString(value, "/")};
|
||||
std::vector<std::string> strings {StringUtils::splitString(value, "/")};
|
||||
|
||||
if (!strings.empty())
|
||||
{
|
||||
track.discNumber = readAs<std::size_t>(strings[0]);
|
||||
track.discNumber = StringUtils::readAs<std::size_t>(strings[0]);
|
||||
|
||||
// Lower priority than DISCTOTAL
|
||||
if (strings.size() > 1 && !track.totalDisc)
|
||||
track.totalDisc = readAs<std::size_t>(strings[1]);
|
||||
track.totalDisc = StringUtils::readAs<std::size_t>(strings[1]);
|
||||
}
|
||||
}
|
||||
else if (tag == "DATE")
|
||||
track.year = readAs<int>(value);
|
||||
track.year = StringUtils::readAs<int>(value);
|
||||
else if (tag == "ORIGINALDATE" && !track.originalYear)
|
||||
{
|
||||
// Lower priority than ORIGINALYEAR
|
||||
track.originalYear = readAs<int>(value);
|
||||
track.originalYear = StringUtils::readAs<int>(value);
|
||||
}
|
||||
else if (tag == "ORIGINALYEAR")
|
||||
{
|
||||
// Higher priority than ORIGINALDATE
|
||||
auto originalYear = readAs<int>(value);
|
||||
auto originalYear = StringUtils::readAs<int>(value);
|
||||
if (originalYear)
|
||||
track.originalYear = originalYear;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "utils/Exception.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Path.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "database/TrackList.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
namespace Similarity {
|
||||
namespace ClusterSearcher {
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "utils/Config.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
namespace Similarity {
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "database/TrackFeatures.hpp"
|
||||
#include "som/DataNormalizer.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
|
||||
namespace Similarity {
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include "explore/Explore.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "admin/InitWizardView.hpp"
|
||||
#include "admin/DatabaseSettingsView.hpp"
|
||||
@@ -639,7 +639,7 @@ LmsApplication::notifyMsg(MsgType type, const Wt::WString& message, std::chrono:
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << "$.notify({"
|
||||
"message: '" << jsEscape(message.toUTF8()) << "'"
|
||||
"message: '" << StringUtils::jsEscape(message.toUTF8()) << "'"
|
||||
"},{"
|
||||
"type: '" << msgTypeToString(type) << "',"
|
||||
"placement: {from: 'top', align: 'center'},"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "resource/ImageResource.hpp"
|
||||
#include "resource/AudioResource.hpp"
|
||||
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
@@ -73,9 +73,9 @@ MediaPlayer::loadTrack(Database::IdType trackId, bool play)
|
||||
<< "var params = {"
|
||||
<< " resource: \"" << resource << "\","
|
||||
<< " duration: " << std::chrono::duration_cast<std::chrono::seconds>(track->getDuration()).count() << ","
|
||||
<< " title: \"" << jsEscape(track->getName()) << "\","
|
||||
<< " artist: \"" << (!artists.empty() ? jsEscape(artists.front()->getName()) : "") << "\","
|
||||
<< " release: \"" << (track->getRelease() ? jsEscape(track->getRelease()->getName()) : "") << "\","
|
||||
<< " title: \"" << StringUtils::jsEscape(track->getName()) << "\","
|
||||
<< " artist: \"" << (!artists.empty() ? StringUtils::jsEscape(artists.front()->getName()) : "") << "\","
|
||||
<< " release: \"" << (track->getRelease() ? StringUtils::jsEscape(track->getRelease()->getName()) : "") << "\","
|
||||
<< " artwork: ["
|
||||
<< " { src: \"" << LmsApp->getImageResource()->getTrackUrl(trackId, 96) << "\", sizes: \"96x96\", type: \"" << imgResourceMimeType << "\" },"
|
||||
<< " { src: \"" << LmsApp->getImageResource()->getTrackUrl(trackId, 256) << "\", sizes: \"256x256\", type: \"" << imgResourceMimeType << "\" },"
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
#include "database/User.hpp"
|
||||
#include "similarity/SimilaritySearcher.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Random.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "TrackStringUtils.hpp"
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
@@ -72,7 +74,7 @@ PlayQueue::PlayQueue()
|
||||
|
||||
Database::TrackList::pointer trackList {getTrackList()};
|
||||
auto entries {trackList->getEntries()};
|
||||
shuffleContainer(entries);
|
||||
Random::shuffleContainer(entries);
|
||||
|
||||
getTrackList().modify()->clear();
|
||||
for (const auto& entry : entries)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "database/Cluster.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "common/Validators.hpp"
|
||||
#include "common/ValueStringModel.hpp"
|
||||
@@ -104,7 +104,7 @@ class DatabaseSettingsModel : public Wt::WFormModel
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
std::transform(clusterTypes.begin(), clusterTypes.end(), std::back_inserter(names), [](auto clusterType) { return clusterType->getName(); });
|
||||
setValue(TagsField, joinStrings(names, " "));
|
||||
setValue(TagsField, StringUtils::joinStrings(names, " "));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ class DatabaseSettingsModel : public Wt::WFormModel
|
||||
if (similarityEngineTypeRow)
|
||||
scanSettings.modify()->setSimilarityEngineType(_similarityEngineTypeModel->getValue(*similarityEngineTypeRow));
|
||||
|
||||
auto clusterTypes {splitString(valueText(TagsField).toUTF8(), " ")};
|
||||
auto clusterTypes {StringUtils::splitString(valueText(TagsField).toUTF8(), " ")};
|
||||
scanSettings.modify()->setClusterTypes(LmsApp->getDbSession(), std::set<std::string>(clusterTypes.begin(), clusterTypes.end()));
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "utils/Exception.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "common/Validators.hpp"
|
||||
#include "common/ValueStringModel.hpp"
|
||||
@@ -229,7 +229,7 @@ UserView::refreshView()
|
||||
if (!wApp->internalPathMatches("/admin/user"))
|
||||
return;
|
||||
|
||||
auto userId = readAs<Database::IdType>(wApp->internalPathNextPart("/admin/user/"));
|
||||
auto userId = StringUtils::readAs<Database::IdType>(wApp->internalPathNextPart("/admin/user/"));
|
||||
|
||||
clear();
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "database/Artist.hpp"
|
||||
#include "similarity/SimilaritySearcher.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "ArtistLink.hpp"
|
||||
#include "LmsApplication.hpp"
|
||||
@@ -59,7 +59,7 @@ ArtistInfo::refresh()
|
||||
if (!wApp->internalPathMatches("/artist/"))
|
||||
return;
|
||||
|
||||
auto artistId = readAs<Database::IdType>(wApp->internalPathNextPart("/artist/"));
|
||||
auto artistId = StringUtils::readAs<Database::IdType>(wApp->internalPathNextPart("/artist/"));
|
||||
if (!artistId)
|
||||
return;
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "database/Release.hpp"
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "resource/ImageResource.hpp"
|
||||
|
||||
@@ -63,7 +63,7 @@ Artist::refresh()
|
||||
|
||||
clear();
|
||||
|
||||
auto artistId = readAs<Database::IdType>(wApp->internalPathNextPart("/artist/"));
|
||||
const auto artistId {StringUtils::readAs<Database::IdType>(wApp->internalPathNextPart("/artist/"))};
|
||||
if (!artistId)
|
||||
return;
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "database/Artist.hpp"
|
||||
#include "database/TrackList.hpp"
|
||||
#include "database/User.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "ArtistLink.hpp"
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "common/ValueStringModel.hpp"
|
||||
#include "database/Artist.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "LmsApplication.hpp"
|
||||
#include "Filters.hpp"
|
||||
@@ -83,7 +83,7 @@ Artists::refresh()
|
||||
void
|
||||
Artists::addSome()
|
||||
{
|
||||
auto searchKeywords = splitString(_search->text().toUTF8(), " ");
|
||||
const auto searchKeywords {StringUtils::splitString(_search->text().toUTF8(), " ")};
|
||||
|
||||
auto clusterIds = _filters->getClusterIds();
|
||||
auto linkModel = static_cast<ArtistLinkModel*>(_linkType->model().get());
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "database/Release.hpp"
|
||||
#include "similarity/SimilaritySearcher.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "ReleaseLink.hpp"
|
||||
#include "LmsApplication.hpp"
|
||||
@@ -64,7 +64,7 @@ ReleaseInfo::refresh()
|
||||
if (!wApp->internalPathMatches("/release/"))
|
||||
return;
|
||||
|
||||
auto releaseId {readAs<Database::IdType>(wApp->internalPathNextPart("/release/"))};
|
||||
auto releaseId {StringUtils::readAs<Database::IdType>(wApp->internalPathNextPart("/release/"))};
|
||||
if (!releaseId)
|
||||
return;
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "database/Release.hpp"
|
||||
#include "resource/ImageResource.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "database/Track.hpp"
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "resource/ImageResource.hpp"
|
||||
|
||||
@@ -65,7 +65,7 @@ Release::refresh()
|
||||
return;
|
||||
|
||||
clear();
|
||||
auto releaseId {readAs<Database::IdType>(wApp->internalPathNextPart("/release/"))};
|
||||
auto releaseId {StringUtils::readAs<Database::IdType>(wApp->internalPathNextPart("/release/"))};
|
||||
if (!releaseId)
|
||||
return;
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "database/Release.hpp"
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "resource/ImageResource.hpp"
|
||||
|
||||
@@ -137,7 +137,7 @@ Releases::addSome()
|
||||
std::vector<Database::IdType>
|
||||
Releases::getReleases(std::optional<std::size_t> offset, std::optional<std::size_t> limit, bool& moreResults) const
|
||||
{
|
||||
const auto searchKeywords {splitString(_search->text().toUTF8(), " ")};
|
||||
const auto searchKeywords {StringUtils::splitString(_search->text().toUTF8(), " ")};
|
||||
|
||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
#include "database/TrackList.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "database/Track.hpp"
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "resource/ImageResource.hpp"
|
||||
|
||||
@@ -78,7 +78,7 @@ _filters {filters}
|
||||
std::vector<Database::IdType>
|
||||
Tracks::getTracks(std::optional<std::size_t> offset, std::optional<std::size_t> size, bool& moreResults)
|
||||
{
|
||||
const auto searchKeywords {splitString(_search->text().toUTF8(), " ")};
|
||||
const auto searchKeywords {StringUtils::splitString(_search->text().toUTF8(), " ")};
|
||||
const auto clusterIds {_filters->getClusterIds()};
|
||||
|
||||
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "utils/Exception.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
#include "LmsApplication.hpp"
|
||||
|
||||
@@ -65,7 +65,7 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons
|
||||
if (!sizeStr)
|
||||
return;
|
||||
|
||||
const auto size {readAs<std::size_t>(*sizeStr)};
|
||||
const auto size {StringUtils::readAs<std::size_t>(*sizeStr)};
|
||||
if (!size || *size > maxSize)
|
||||
return;
|
||||
|
||||
@@ -73,7 +73,7 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons
|
||||
|
||||
if (trackIdStr)
|
||||
{
|
||||
const auto trackId {readAs<Database::IdType>(*trackIdStr)};
|
||||
const auto trackId {StringUtils::readAs<Database::IdType>(*trackIdStr)};
|
||||
if (!trackId)
|
||||
return;
|
||||
|
||||
@@ -85,7 +85,7 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons
|
||||
}
|
||||
else if (releaseIdStr)
|
||||
{
|
||||
const auto releaseId {readAs<Database::IdType>(*releaseIdStr)};
|
||||
const auto releaseId {StringUtils::readAs<Database::IdType>(*releaseIdStr)};
|
||||
if (!releaseId)
|
||||
return;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Emeric Poupon
|
||||
* Copyright (C) 2020 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
@@ -17,14 +17,17 @@
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "MetaData.hpp"
|
||||
#include "Random.hpp"
|
||||
|
||||
#include "utils/Utils.hpp"
|
||||
namespace Random {
|
||||
|
||||
namespace MetaData
|
||||
RandGenerator& getRandGenerator()
|
||||
{
|
||||
static thread_local std::random_device rd;
|
||||
static thread_local std::mt19937 randGenerator(rd());
|
||||
|
||||
return randGenerator;
|
||||
}
|
||||
|
||||
|
||||
} // namespace MetaData
|
||||
} // Random
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
namespace Random {
|
||||
|
||||
using RandGenerator = std::mt19937;
|
||||
RandGenerator& getRandGenerator();
|
||||
|
||||
template <typename T>
|
||||
T
|
||||
getRandom(T min, T max)
|
||||
{
|
||||
std::uniform_int_distribution<> dist {min, max};
|
||||
return dist (getRandGenerator());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T
|
||||
getRealRandom(T min, T max)
|
||||
{
|
||||
std::uniform_real_distribution<> dist {min, max};
|
||||
return dist (getRandGenerator());
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
void
|
||||
shuffleContainer(Container& container)
|
||||
{
|
||||
std::shuffle(std::begin(container), std::end(container), getRandGenerator());
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
typename Container::const_iterator
|
||||
pickRandom(const Container& container)
|
||||
{
|
||||
if (container.empty())
|
||||
return std::end(container);
|
||||
|
||||
return std::next(std::begin(container), getRandom(0, static_cast<int>(container.size() - 1)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Emeric Poupon
|
||||
* Copyright (C) 2020 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
@@ -17,18 +17,16 @@
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "String.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace StringUtils {
|
||||
|
||||
bool
|
||||
readList(const std::string& str, const std::string& separators, std::list<std::string>& results)
|
||||
{
|
||||
@@ -200,11 +198,5 @@ stringFromHex(const std::string& str)
|
||||
return res;
|
||||
}
|
||||
|
||||
RandGenerator& getRandGenerator()
|
||||
{
|
||||
static thread_local std::random_device rd;
|
||||
static thread_local std::mt19937 randGenerator(rd());
|
||||
|
||||
return randGenerator;
|
||||
}
|
||||
} // StringUtils
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace StringUtils {
|
||||
|
||||
std::vector<std::string>
|
||||
splitString(const std::string& string, const std::string& separators);
|
||||
|
||||
std::string
|
||||
joinStrings(const std::vector<std::string>& strings, const std::string& delimiter);
|
||||
|
||||
std::string
|
||||
stringTrim(const std::string& str, const std::string& whitespaces = " \t");
|
||||
|
||||
std::string
|
||||
stringTrimEnd(const std::string& str, const std::string& whitespaces = " \t");
|
||||
|
||||
std::string
|
||||
stringToLower(const std::string& str);
|
||||
|
||||
std::string
|
||||
bufferToString(const std::vector<unsigned char>& data);
|
||||
|
||||
template<typename T>
|
||||
std::optional<T> readAs(const std::string& str)
|
||||
{
|
||||
T res;
|
||||
|
||||
std::istringstream iss ( str );
|
||||
iss >> res;
|
||||
if (iss.fail())
|
||||
return std::nullopt;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string
|
||||
replaceInString(const std::string& str, const std::string& from, const std::string& to);
|
||||
|
||||
std::string
|
||||
jsEscape(const std::string& str);
|
||||
|
||||
bool
|
||||
stringEndsWith(const std::string& str, const std::string& ending);
|
||||
|
||||
std::optional<std::string>
|
||||
stringFromHex(const std::string& str);
|
||||
|
||||
} // StringUtils
|
||||
|
||||
+12
-5
@@ -21,21 +21,28 @@
|
||||
|
||||
#include <regex>
|
||||
|
||||
#include "Utils.hpp"
|
||||
namespace StringUtils
|
||||
{
|
||||
template <>
|
||||
std::optional<UUID>
|
||||
readAs(const std::string& str)
|
||||
{
|
||||
return UUID::fromString(str);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
bool
|
||||
stringIsUUID(const std::string& str)
|
||||
stringIsUUID(std::string_view str)
|
||||
{
|
||||
static const std::regex re { R"([0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})"};
|
||||
|
||||
return std::regex_match(str, re);
|
||||
return std::regex_match(std::cbegin(str), std::cend(str), re);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
std::optional<UUID>
|
||||
readAs(const std::string& str)
|
||||
UUID::fromString(std::string_view str)
|
||||
{
|
||||
if (!stringIsUUID(str))
|
||||
return std::nullopt;
|
||||
|
||||
+10
-8
@@ -19,27 +19,29 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "utils/String.hpp"
|
||||
|
||||
class UUID
|
||||
{
|
||||
public:
|
||||
|
||||
static std::optional<UUID> fromString(std::string_view str);
|
||||
|
||||
std::string_view getAsString() const { return _value; }
|
||||
|
||||
private:
|
||||
|
||||
template <typename UUID>
|
||||
friend std::optional<UUID> readAs(const std::string& str);
|
||||
|
||||
UUID(std::string_view value) : _value {value} {}
|
||||
std::string _value;
|
||||
};
|
||||
|
||||
template<>
|
||||
std::optional<UUID>
|
||||
readAs(const std::string& str);
|
||||
namespace StringUtils
|
||||
{
|
||||
template <>
|
||||
std::optional<UUID>
|
||||
readAs(const std::string& str);
|
||||
}
|
||||
|
||||
|
||||
+1
-123
@@ -19,92 +19,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <Wt/WDate.h>
|
||||
|
||||
bool
|
||||
readList(const std::string& str, const std::string& separators, std::list<std::string>& results);
|
||||
|
||||
std::vector<std::string>
|
||||
splitString(const std::string& string, const std::string& separators);
|
||||
|
||||
std::string
|
||||
joinStrings(const std::vector<std::string>& strings, const std::string& delimiter);
|
||||
|
||||
std::string
|
||||
stringTrim(const std::string& str, const std::string& whitespaces = " \t");
|
||||
|
||||
std::string
|
||||
stringTrimEnd(const std::string& str, const std::string& whitespaces = " \t");
|
||||
|
||||
std::string
|
||||
stringToLower(const std::string& str);
|
||||
|
||||
std::string
|
||||
bufferToString(const std::vector<unsigned char>& data);
|
||||
|
||||
template<typename T>
|
||||
std::optional<T> readAs(const std::string& str)
|
||||
{
|
||||
T res;
|
||||
|
||||
std::istringstream iss ( str );
|
||||
iss >> res;
|
||||
if (iss.fail())
|
||||
return std::nullopt;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string
|
||||
replaceInString(const std::string& str, const std::string& from, const std::string& to);
|
||||
|
||||
std::string
|
||||
jsEscape(const std::string& str);
|
||||
|
||||
bool
|
||||
stringEndsWith(const std::string& str, const std::string& ending);
|
||||
|
||||
std::optional<std::string>
|
||||
stringFromHex(const std::string& str);
|
||||
|
||||
// warning: not efficient
|
||||
template<class In, class Out, class U = typename std::iterator_traits<In>::value_type>
|
||||
void uniqueAndSortedByOccurence(In first, In last, Out out)
|
||||
{
|
||||
std::map<U, std::size_t> occurencesMap;
|
||||
|
||||
for (In it = first; it != last; ++it)
|
||||
{
|
||||
if (occurencesMap.find(*it) == occurencesMap.end())
|
||||
occurencesMap[*it] = 0;
|
||||
|
||||
occurencesMap[*it]++;
|
||||
}
|
||||
|
||||
struct Item
|
||||
{
|
||||
U elem;
|
||||
std::size_t count;
|
||||
};
|
||||
|
||||
std::vector<Item> occurencesVector;
|
||||
for (const auto& occurence : occurencesMap)
|
||||
occurencesVector.emplace_back(Item{occurence.first, occurence.second});
|
||||
|
||||
std::sort(occurencesVector.begin(), occurencesVector.end(), [](const auto& a, const auto& b) { return a.count > b.count;});
|
||||
|
||||
for (const auto& occurence : occurencesVector)
|
||||
*out++ = occurence.elem;
|
||||
}
|
||||
#include <functional>
|
||||
|
||||
template<class T, class Compare = std::less<>>
|
||||
constexpr T clamp(T v, T lo, T hi, Compare comp = {})
|
||||
@@ -113,40 +28,3 @@ constexpr T clamp(T v, T lo, T hi, Compare comp = {})
|
||||
return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
|
||||
}
|
||||
|
||||
using RandGenerator = std::mt19937;
|
||||
RandGenerator& getRandGenerator();
|
||||
|
||||
template <typename T>
|
||||
T
|
||||
getRandom(T min, T max)
|
||||
{
|
||||
std::uniform_int_distribution<> dist {min, max};
|
||||
return dist (getRandGenerator());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T
|
||||
getRealRandom(T min, T max)
|
||||
{
|
||||
std::uniform_real_distribution<> dist {min, max};
|
||||
return dist (getRandGenerator());
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
void
|
||||
shuffleContainer(Container& container)
|
||||
{
|
||||
std::shuffle(std::begin(container), std::end(container), getRandGenerator());
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
typename Container::const_iterator
|
||||
pickRandom(const Container& container)
|
||||
{
|
||||
if (container.empty())
|
||||
return std::end(container);
|
||||
|
||||
return std::next(std::begin(container), getRandom(0, static_cast<int>(container.size() - 1)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user