Split the utils file

This commit is contained in:
emeric
2020-02-08 17:44:12 +01:00
parent 52a0f62491
commit e274c0ca89
47 changed files with 343 additions and 318 deletions
+4 -2
View File
@@ -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 \
+3 -3
View File
@@ -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;
+62 -57
View File
@@ -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()};
-1
View File
@@ -27,7 +27,6 @@
#include "database/Session.hpp"
#include "utils/Exception.hpp"
#include "utils/Utils.hpp"
#include "utils/Logger.hpp"
namespace Auth {
+2 -2
View File
@@ -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);
-1
View File
@@ -27,7 +27,6 @@
#include "database/Session.hpp"
#include "utils/Exception.hpp"
#include "utils/Utils.hpp"
#include "utils/Logger.hpp"
namespace Auth {
+5 -4
View File
@@ -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!";
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+3 -3
View File
@@ -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>
+1 -1
View File
@@ -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
View File
@@ -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()};
+1 -1
View File
@@ -26,7 +26,7 @@
#include <set>
#include <vector>
#include "utils/Utils.hpp"
//#include "utils/Utils.hpp"
#include "utils/UUID.hpp"
namespace MetaData
+20 -19
View File
@@ -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;
}
-1
View File
@@ -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 {
+2 -2
View File
@@ -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'},"
+4 -4
View File
@@ -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 << "\" },"
+4 -2
View File
@@ -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)
+3 -3
View File
@@ -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()));
}
+2 -2
View File
@@ -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();
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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;
-1
View File
@@ -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"
+2 -2
View File
@@ -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());
+2 -2
View File
@@ -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;
-1
View File
@@ -25,7 +25,6 @@
#include "database/Release.hpp"
#include "resource/ImageResource.hpp"
#include "utils/Utils.hpp"
#include "LmsApplication.hpp"
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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()};
-2
View File
@@ -26,8 +26,6 @@
#include "database/TrackList.hpp"
#include "database/User.hpp"
#include "utils/Utils.hpp"
#include "LmsApplication.hpp"
using namespace Database;
+2 -2
View File
@@ -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()};
+4 -4
View File
@@ -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
+64
View File
@@ -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)));
}
}
+5 -13
View File
@@ -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
+73
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)));
}