This commit is contained in:
emeric
2020-02-13 13:00:22 +01:00
parent e274c0ca89
commit 876fb12fe4
192 changed files with 1046 additions and 676 deletions
+18
View File
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.10)
project(lms)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
find_package(PkgConfig)
pkg_check_modules(IMAGEMAGICKXX REQUIRED ImageMagick++)
SUBDIRS(src)
install(DIRECTORY approot DESTINATION share/lms)
install(DIRECTORY docroot DESTINATION share/lms)
install(FILES systemd/default.service DESTINATION share/lms)
install(FILES conf/lms.conf DESTINATION share/lms)
+4
View File
@@ -0,0 +1,4 @@
add_compile_options(-Wall -Wextra -pedantic -Werror)
SUBDIRS(liblms lms)
-165
View File
@@ -1,171 +1,6 @@
bin_PROGRAMS = lms bin_PROGRAMS = lms
lms_SOURCES = \ lms_SOURCES = \
$(srcdir)/api/subsonic/SubsonicId.cpp \
$(srcdir)/api/subsonic/SubsonicId.hpp \
$(srcdir)/api/subsonic/SubsonicResource.cpp \
$(srcdir)/api/subsonic/SubsonicResource.hpp \
$(srcdir)/api/subsonic/SubsonicResponse.cpp \
$(srcdir)/api/subsonic/SubsonicResponse.hpp \
$(srcdir)/auth/AuthTokenService.cpp \
$(srcdir)/auth/AuthTokenService.hpp \
$(srcdir)/auth/PasswordService.cpp \
$(srcdir)/auth/PasswordService.hpp \
$(srcdir)/auth/LoginThrottler.cpp \
$(srcdir)/auth/LoginThrottler.hpp \
$(srcdir)/av/AvInfo.cpp \
$(srcdir)/av/AvInfo.hpp \
$(srcdir)/av/AvTranscoder.cpp \
$(srcdir)/av/AvTranscoder.hpp \
$(srcdir)/av/AvTypes.cpp \
$(srcdir)/av/AvTypes.hpp \
$(srcdir)/cover/CoverArtGrabber.cpp \
$(srcdir)/cover/CoverArtGrabber.hpp \
$(srcdir)/database/Artist.cpp \
$(srcdir)/database/Artist.hpp \
$(srcdir)/database/Cluster.cpp \
$(srcdir)/database/Cluster.hpp \
$(srcdir)/database/Db.cpp \
$(srcdir)/database/Db.hpp \
$(srcdir)/database/TrackArtistLink.cpp \
$(srcdir)/database/TrackArtistLink.hpp \
$(srcdir)/database/TrackFeatures.cpp \
$(srcdir)/database/TrackFeatures.hpp \
$(srcdir)/database/TrackList.cpp \
$(srcdir)/database/TrackList.hpp \
$(srcdir)/database/Types.hpp \
$(srcdir)/database/Release.cpp \
$(srcdir)/database/Release.hpp \
$(srcdir)/database/ScanSettings.cpp \
$(srcdir)/database/ScanSettings.hpp \
$(srcdir)/database/Session.cpp \
$(srcdir)/database/Session.hpp \
$(srcdir)/database/SessionPool.cpp \
$(srcdir)/database/SessionPool.hpp \
$(srcdir)/database/SqlQuery.cpp \
$(srcdir)/database/SqlQuery.hpp \
$(srcdir)/database/Track.cpp \
$(srcdir)/database/Track.hpp \
$(srcdir)/database/TrackBookmark.cpp \
$(srcdir)/database/TrackBookmark.hpp \
$(srcdir)/database/User.cpp \
$(srcdir)/database/User.hpp \
$(srcdir)/image/Image.cpp \
$(srcdir)/image/Image.hpp \
$(srcdir)/main/main.cpp \
$(srcdir)/metadata/AvFormat.cpp \
$(srcdir)/metadata/AvFormat.hpp \
$(srcdir)/metadata/MetaData.hpp \
$(srcdir)/metadata/TagLibParser.cpp \
$(srcdir)/metadata/TagLibParser.hpp \
$(srcdir)/scanner/MediaScanner.cpp \
$(srcdir)/scanner/MediaScanner.hpp \
$(srcdir)/scanner/MediaScannerStats.cpp \
$(srcdir)/scanner/MediaScannerStats.hpp \
$(srcdir)/scanner/MediaScannerAddon.hpp \
$(srcdir)/similarity/SimilaritySearcher.cpp \
$(srcdir)/similarity/SimilaritySearcher.hpp \
$(srcdir)/similarity/cluster/SimilarityClusterSearcher.cpp \
$(srcdir)/similarity/cluster/SimilarityClusterSearcher.hpp \
$(srcdir)/similarity/features/AcousticBrainzUtils.cpp \
$(srcdir)/similarity/features/AcousticBrainzUtils.hpp \
$(srcdir)/similarity/features/SimilarityFeaturesCache.cpp \
$(srcdir)/similarity/features/SimilarityFeaturesCache.hpp \
$(srcdir)/similarity/features/SimilarityFeaturesDefs.cpp \
$(srcdir)/similarity/features/SimilarityFeaturesDefs.hpp \
$(srcdir)/similarity/features/SimilarityFeaturesScannerAddon.cpp \
$(srcdir)/similarity/features/SimilarityFeaturesScannerAddon.hpp \
$(srcdir)/similarity/features/SimilarityFeaturesSearcher.cpp \
$(srcdir)/similarity/features/SimilarityFeaturesSearcher.hpp \
$(srcdir)/similarity/features/som/DataNormalizer.cpp \
$(srcdir)/similarity/features/som/DataNormalizer.hpp \
$(srcdir)/similarity/features/som/InputVector.hpp \
$(srcdir)/similarity/features/som/Matrix.hpp \
$(srcdir)/similarity/features/som/Network.cpp \
$(srcdir)/similarity/features/som/Network.hpp \
$(srcdir)/ui/Auth.cpp \
$(srcdir)/ui/Auth.hpp \
$(srcdir)/ui/LmsApplication.cpp \
$(srcdir)/ui/LmsApplication.hpp \
$(srcdir)/ui/LmsApplicationException.hpp \
$(srcdir)/ui/LmsApplicationGroup.cpp \
$(srcdir)/ui/LmsApplicationGroup.hpp \
$(srcdir)/ui/MediaPlayer.cpp \
$(srcdir)/ui/MediaPlayer.hpp \
$(srcdir)/ui/PlayQueueView.cpp \
$(srcdir)/ui/PlayQueueView.hpp \
$(srcdir)/ui/PlayHistoryView.cpp \
$(srcdir)/ui/PlayHistoryView.hpp \
$(srcdir)/ui/SettingsView.cpp \
$(srcdir)/ui/SettingsView.hpp \
$(srcdir)/ui/TrackStringUtils.cpp \
$(srcdir)/ui/TrackStringUtils.hpp \
$(srcdir)/ui/admin/DatabaseSettingsView.cpp \
$(srcdir)/ui/admin/DatabaseSettingsView.hpp \
$(srcdir)/ui/admin/DatabaseStatus.cpp \
$(srcdir)/ui/admin/DatabaseStatus.hpp \
$(srcdir)/ui/admin/InitWizardView.cpp \
$(srcdir)/ui/admin/InitWizardView.hpp \
$(srcdir)/ui/admin/UserView.cpp \
$(srcdir)/ui/admin/UserView.hpp \
$(srcdir)/ui/admin/UsersView.cpp \
$(srcdir)/ui/admin/UsersView.hpp \
$(srcdir)/ui/common/Validators.cpp \
$(srcdir)/ui/common/Validators.hpp \
$(srcdir)/ui/common/ValueStringModel.hpp \
$(srcdir)/ui/explore/ArtistInfoView.cpp \
$(srcdir)/ui/explore/ArtistInfoView.hpp \
$(srcdir)/ui/explore/ArtistLink.cpp \
$(srcdir)/ui/explore/ArtistLink.hpp \
$(srcdir)/ui/explore/ArtistsInfoView.cpp \
$(srcdir)/ui/explore/ArtistsInfoView.hpp \
$(srcdir)/ui/explore/ArtistView.cpp \
$(srcdir)/ui/explore/ArtistView.hpp \
$(srcdir)/ui/explore/ArtistsView.cpp \
$(srcdir)/ui/explore/ArtistsView.hpp \
$(srcdir)/ui/explore/Explore.cpp \
$(srcdir)/ui/explore/Explore.hpp \
$(srcdir)/ui/explore/Filters.cpp \
$(srcdir)/ui/explore/Filters.hpp \
$(srcdir)/ui/explore/ReleaseInfoView.cpp \
$(srcdir)/ui/explore/ReleaseInfoView.hpp \
$(srcdir)/ui/explore/ReleaseLink.cpp \
$(srcdir)/ui/explore/ReleaseLink.hpp \
$(srcdir)/ui/explore/ReleasesInfoView.cpp \
$(srcdir)/ui/explore/ReleasesInfoView.hpp \
$(srcdir)/ui/explore/ReleasesView.cpp \
$(srcdir)/ui/explore/ReleasesView.hpp \
$(srcdir)/ui/explore/ReleaseView.cpp \
$(srcdir)/ui/explore/ReleaseView.hpp \
$(srcdir)/ui/explore/TracksInfoView.cpp \
$(srcdir)/ui/explore/TracksInfoView.hpp \
$(srcdir)/ui/explore/TracksView.cpp \
$(srcdir)/ui/explore/TracksView.hpp \
$(srcdir)/ui/resource/ImageResource.cpp \
$(srcdir)/ui/resource/ImageResource.hpp \
$(srcdir)/ui/resource/AudioResource.cpp \
$(srcdir)/ui/resource/AudioResource.hpp \
$(srcdir)/utils/Config.cpp \
$(srcdir)/utils/Config.hpp \
$(srcdir)/utils/Exception.hpp \
$(srcdir)/utils/Logger.cpp \
$(srcdir)/utils/Logger.hpp \
$(srcdir)/utils/NetAddress.cpp \
$(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/String.cpp \
$(srcdir)/utils/String.hpp \
$(srcdir)/utils/Utils.hpp \
$(srcdir)/utils/UUID.cpp \
$(srcdir)/utils/UUID.hpp \
$(srcdir)/utils/WtLogger.cpp \
$(srcdir)/utils/WtLogger.hpp
lms_CXXFLAGS=-std=c++17 -I$(srcdir)/ui $(MAGICKXX_CFLAGS) -D_REENTRANT lms_CXXFLAGS=-std=c++17 -I$(srcdir)/ui $(MAGICKXX_CFLAGS) -D_REENTRANT
lms_LDADD=$(MAGICKXX_LIBS) lms_LDADD=$(MAGICKXX_LIBS)
View File
-76
View File
@@ -1,76 +0,0 @@
/*
* Copyright (C) 2015 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 <filesystem>
#include <map>
#include <mutex>
#include <optional>
#include <vector>
#include "database/Types.hpp"
#include "image/Image.hpp"
namespace Database {
class Session;
}
namespace CoverArt {
class Grabber
{
public:
Grabber();
Grabber(const Grabber&) = delete;
Grabber& operator=(const Grabber&) = delete;
Grabber(Grabber&&) = delete;
Grabber& operator=(Grabber&&) = delete;
void setDefaultCover(const std::filesystem::path& defaultCoverPath);
std::vector<uint8_t> getFromTrack(Database::Session& dbSession, Database::IdType trackId, Image::Format format, std::size_t size);
std::vector<uint8_t> getFromRelease(Database::Session& dbSession, Database::IdType releaseId, Image::Format format, std::size_t size);
private:
Image::Image getFromTrack(Database::Session& dbSession, Database::IdType trackId, std::size_t size);
Image::Image getFromRelease(Database::Session& dbSession, Database::IdType releaseId, std::size_t size);
std::optional<Image::Image> getFromTrack(const std::filesystem::path& path) const;
std::vector<std::filesystem::path> getCoverPaths(const std::filesystem::path& directoryPath) const;
std::optional<Image::Image> getFromDirectory(const std::filesystem::path& path) const;
Image::Image getDefaultCover(std::size_t size);
Image::Image _defaultCover;
std::mutex _mutex;
std::map<std::size_t /* size */, Image::Image> _defaultCovers;
static inline const std::vector<std::filesystem::path> _fileExtensions {".jpg", ".jpeg", ".png", ".bmp"}; // TODO parametrize
static inline const std::size_t _maxFileSize {10000000};
static inline const std::vector<std::filesystem::path> _preferredFileNames {"cover", "front"}; // TODO parametrize
};
} // namespace CoverArt
+73
View File
@@ -0,0 +1,73 @@
add_library(liblms SHARED
impl/api/subsonic/SubsonicId.cpp
impl/api/subsonic/SubsonicResource.cpp
impl/api/subsonic/SubsonicResponse.cpp
impl/auth/AuthTokenService.cpp
impl/auth/PasswordService.cpp
impl/auth/LoginThrottler.cpp
impl/av/AvInfo.cpp
impl/av/AvTranscoder.cpp
impl/av/AvTypes.cpp
impl/cover/CoverArtGrabber.cpp
impl/database/Artist.cpp
impl/database/Cluster.cpp
impl/database/Db.cpp
impl/database/TrackArtistLink.cpp
impl/database/TrackFeatures.cpp
impl/database/TrackList.cpp
impl/database/Release.cpp
impl/database/ScanSettings.cpp
impl/database/Session.cpp
impl/database/SessionPool.cpp
impl/database/SqlQuery.cpp
impl/database/Track.cpp
impl/database/TrackBookmark.cpp
impl/database/User.cpp
impl/metadata/AvFormat.cpp
impl/metadata/TagLibParser.cpp
impl/scanner/MediaScanner.cpp
impl/scanner/MediaScannerStats.cpp
impl/recommendation/Engine.cpp
impl/recommendation/ProviderCreator.cpp
impl/recommendation/features/som/DataNormalizer.cpp
impl/recommendation/features/som/Network.cpp
impl/utils/Config.cpp
impl/utils/Logger.cpp
impl/utils/NetAddress.cpp
impl/utils/Path.cpp
impl/utils/Random.cpp
impl/utils/StreamLogger.cpp
impl/utils/String.cpp
impl/utils/UUID.cpp
impl/utils/WtLogger.cpp
)
include_directories(liblms include/)
target_include_directories(liblms INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# TODO make this private
target_include_directories(liblms PUBLIC ${IMAGEMAGICKXX_INCLUDE_DIRS})
target_link_libraries(liblms PUBLIC ${IMAGEMAGICKXX_LIBRARIES})
target_compile_options(liblms PUBLIC ${IMAGEMAGICKXX_CFLAGS_OTHER})
target_link_libraries(liblms PRIVATE
avformat
avutil
config++
tag
stdc++fs
wtdbosqlite3
)
target_link_libraries(liblms PUBLIC
pthread
boost_system
wtdbo
)
install(TARGETS liblms DESTINATION lib)
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "SubsonicResource.hpp" #include "api/subsonic/SubsonicResource.hpp"
#include <atomic> #include <atomic>
#include <mutex> #include <mutex>
@@ -26,9 +26,9 @@
#include <Wt/WLocalDateTime.h> #include <Wt/WLocalDateTime.h>
#include "auth/PasswordService.hpp" #include "auth/IPasswordService.hpp"
#include "av/AvTranscoder.hpp" #include "av/AvTranscoder.hpp"
#include "cover/CoverArtGrabber.hpp" #include "cover/ICoverArtGrabber.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Db.hpp" #include "database/Db.hpp"
@@ -38,7 +38,7 @@
#include "database/TrackBookmark.hpp" #include "database/TrackBookmark.hpp"
#include "database/TrackList.hpp" #include "database/TrackList.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "similarity/SimilaritySearcher.hpp" #include "recommendation/IEngine.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "utils/Service.hpp" #include "utils/Service.hpp"
#include "utils/String.hpp" #include "utils/String.hpp"
@@ -578,10 +578,10 @@ handleChangePassword(RequestContext& context)
std::string username {getMandatoryParameterAs<std::string>(context.parameters, "username")}; std::string username {getMandatoryParameterAs<std::string>(context.parameters, "username")};
std::string password {decodePasswordIfNeeded(getMandatoryParameterAs<std::string>(context.parameters, "password"))}; std::string password {decodePasswordIfNeeded(getMandatoryParameterAs<std::string>(context.parameters, "password"))};
if (!ServiceProvider<Auth::PasswordService>::get()->evaluatePasswordStrength(username, password)) if (!ServiceProvider<Auth::IPasswordService>::get()->evaluatePasswordStrength(username, password))
throw PasswordTooWeakGenericError {}; throw PasswordTooWeakGenericError {};
const User::PasswordHash hash {ServiceProvider<Auth::PasswordService>::get()->hashPassword(password)}; const User::PasswordHash hash {ServiceProvider<Auth::IPasswordService>::get()->hashPassword(password)};
auto transaction {context.dbSession.createUniqueTransaction()}; auto transaction {context.dbSession.createUniqueTransaction()};
@@ -660,10 +660,10 @@ handleCreateUserRequest(RequestContext& context)
std::string password {decodePasswordIfNeeded(getMandatoryParameterAs<std::string>(context.parameters, "password"))}; std::string password {decodePasswordIfNeeded(getMandatoryParameterAs<std::string>(context.parameters, "password"))};
// Just ignore all the other fields as we don't handle them // Just ignore all the other fields as we don't handle them
if (!ServiceProvider<Auth::PasswordService>::get()->evaluatePasswordStrength(username, password)) if (!ServiceProvider<Auth::IPasswordService>::get()->evaluatePasswordStrength(username, password))
throw PasswordTooWeakGenericError {}; throw PasswordTooWeakGenericError {};
const User::PasswordHash hash {ServiceProvider<Auth::PasswordService>::get()->hashPassword(password)}; const User::PasswordHash hash {ServiceProvider<Auth::IPasswordService>::get()->hashPassword(password)};
auto transaction {context.dbSession.createUniqueTransaction()}; auto transaction {context.dbSession.createUniqueTransaction()};
@@ -944,7 +944,7 @@ handleGetArtistInfoRequestCommon(RequestContext& context, bool id3)
artistInfoNode.createChild("musicBrainzId").setValue(artistMBID->getAsString()); artistInfoNode.createChild("musicBrainzId").setValue(artistMBID->getAsString());
} }
auto similarArtistsId {ServiceProvider<Similarity::Searcher>::get()->getSimilarArtists(context.dbSession, id.value, count)}; auto similarArtistsId {ServiceProvider<Recommendation::IEngine>::get()->getSimilarArtists(context.dbSession, id.value, count)};
{ {
auto transaction {context.dbSession.createSharedTransaction()}; auto transaction {context.dbSession.createSharedTransaction()};
@@ -1140,7 +1140,7 @@ handleGetSimilarSongsRequestCommon(RequestContext& context, bool id3)
// Optional params // Optional params
std::size_t count {getParameterAs<std::size_t>(context.parameters, "count").value_or(50)}; std::size_t count {getParameterAs<std::size_t>(context.parameters, "count").value_or(50)};
auto similarArtistsId {ServiceProvider<Similarity::Searcher>::get()->getSimilarArtists(context.dbSession, id.value, 5)}; auto similarArtistsId {ServiceProvider<Recommendation::IEngine>::get()->getSimilarArtists(context.dbSession, id.value, 5)};
auto transaction {context.dbSession.createSharedTransaction()}; auto transaction {context.dbSession.createSharedTransaction()};
@@ -1588,10 +1588,10 @@ handleUpdateUserRequest(RequestContext& context)
if (password) if (password)
{ {
*password = decodePasswordIfNeeded(*password); *password = decodePasswordIfNeeded(*password);
if (!ServiceProvider<Auth::PasswordService>::get()->evaluatePasswordStrength(username, *password)) if (!ServiceProvider<Auth::IPasswordService>::get()->evaluatePasswordStrength(username, *password))
throw PasswordTooWeakGenericError {}; throw PasswordTooWeakGenericError {};
hash = ServiceProvider<Auth::PasswordService>::get()->hashPassword(*password); hash = ServiceProvider<Auth::IPasswordService>::get()->hashPassword(*password);
} }
auto transaction {context.dbSession.createUniqueTransaction()}; auto transaction {context.dbSession.createUniqueTransaction()};
@@ -1895,16 +1895,16 @@ handleGetCoverArt(RequestContext& context, Wt::Http::ResponseContinuation*)
switch (id.type) switch (id.type)
{ {
case Id::Type::Track: case Id::Type::Track:
res.data = ServiceProvider<CoverArt::Grabber>::get()->getFromTrack(context.dbSession, id.value, Image::Format::JPEG, size); res.data = ServiceProvider<CoverArt::IGrabber>::get()->getFromTrack(context.dbSession, id.value, CoverArt::Format::JPEG, {size, size});
break; break;
case Id::Type::Release: case Id::Type::Release:
res.data = ServiceProvider<CoverArt::Grabber>::get()->getFromRelease(context.dbSession, id.value, Image::Format::JPEG, size); res.data = ServiceProvider<CoverArt::IGrabber>::get()->getFromRelease(context.dbSession, id.value, CoverArt::Format::JPEG, {size, size});
break; break;
default: default:
throw BadParameterGenericError {"id"}; throw BadParameterGenericError {"id"};
} }
res.mimeType = Image::format_to_mimeType(Image::Format::JPEG); res.mimeType = CoverArt::formatToMimeType(CoverArt::Format::JPEG);
return res; return res;
} }
@@ -2056,19 +2056,19 @@ SubsonicResource::handleRequest(const Wt::Http::Request &request, Wt::Http::Resp
SessionPool::ScopedSession dbSession {_sessionPool}; SessionPool::ScopedSession dbSession {_sessionPool};
switch (ServiceProvider<Auth::PasswordService>::get()->checkUserPassword(dbSession.get(), switch (ServiceProvider<Auth::IPasswordService>::get()->checkUserPassword(dbSession.get(),
boost::asio::ip::address::from_string(request.clientAddress()), boost::asio::ip::address::from_string(request.clientAddress()),
clientInfo.user, clientInfo.password)) clientInfo.user, clientInfo.password))
{ {
case Auth::PasswordService::PasswordCheckResult::Match: case Auth::IPasswordService::PasswordCheckResult::Match:
break; break;
case Auth::PasswordService::PasswordCheckResult::Mismatch: case Auth::IPasswordService::PasswordCheckResult::Mismatch:
throw WrongUsernameOrPasswordError {}; throw WrongUsernameOrPasswordError {};
case Auth::PasswordService::PasswordCheckResult::Throttled: case Auth::IPasswordService::PasswordCheckResult::Throttled:
throw LoginThrottledGenericError {}; throw LoginThrottledGenericError {};
} }
RequestContext requestContext {.parameters = parameters, .dbSession = dbSession.get(), .userName = clientInfo.user}; RequestContext requestContext {parameters, dbSession.get(), clientInfo.user};
auto itEntryPoint {requestEntryPoints.find(requestPath)}; auto itEntryPoint {requestEntryPoints.find(requestPath)};
if (itEntryPoint != requestEntryPoints.end()) if (itEntryPoint != requestEntryPoints.end())
@@ -26,11 +26,17 @@
#include <Wt/WRandom.h> #include <Wt/WRandom.h>
#include "database/Session.hpp" #include "database/Session.hpp"
#include "database/User.hpp"
#include "utils/Exception.hpp" #include "utils/Exception.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
namespace Auth { namespace Auth {
std::unique_ptr<IAuthTokenService> createAuthTokenService(std::size_t maxThrottlerEntries)
{
return std::make_unique<AuthTokenService>(maxThrottlerEntries);
}
static const Wt::Auth::SHA1HashFunction sha1Function; static const Wt::Auth::SHA1HashFunction sha1Function;
AuthTokenService::AuthTokenService(std::size_t maxThrottlerEntries) AuthTokenService::AuthTokenService(std::size_t maxThrottlerEntries)
@@ -21,14 +21,9 @@
#pragma once #pragma once
#include <optional> #include "auth/IAuthTokenService.hpp"
#include <string>
#include <boost/asio/ip/address.hpp>
#include "LoginThrottler.hpp" #include "LoginThrottler.hpp"
#include "database/User.hpp"
#include "database/Types.hpp"
namespace Database namespace Database
{ {
@@ -38,7 +33,7 @@ namespace Database
namespace Auth { namespace Auth {
class AuthTokenService class AuthTokenService : public IAuthTokenService
{ {
public: public:
@@ -52,30 +47,8 @@ namespace Auth {
AuthTokenService(AuthTokenService&&) = delete; AuthTokenService(AuthTokenService&&) = delete;
AuthTokenService& operator=(AuthTokenService&&) = delete; AuthTokenService& operator=(AuthTokenService&&) = delete;
AuthTokenProcessResult processAuthToken(Database::Session& session, const boost::asio::ip::address& clientAddress, const std::string& tokenValue) override;
// Auth Token services std::string createAuthToken(Database::Session& session, Database::IdType userid, const Wt::WDateTime& expiry) override;
struct AuthTokenProcessResult
{
enum class State
{
Found,
Throttled,
NotFound,
};
struct AuthTokenInfo
{
Database::IdType userId;
Wt::WDateTime expiry;
};
State state {State::NotFound};
std::optional<AuthTokenInfo> authTokenInfo {};
};
// Removed if found
AuthTokenProcessResult processAuthToken(Database::Session& session, const boost::asio::ip::address& clientAddress, const std::string& tokenValue);
std::string createAuthToken(Database::Session& session, Database::IdType userid, const Wt::WDateTime& expiry);
private: private:
@@ -31,6 +31,11 @@
namespace Auth { namespace Auth {
std::unique_ptr<IPasswordService> createPasswordService(std::size_t maxThrottlerEntries)
{
return std::make_unique<PasswordService>(maxThrottlerEntries);
}
PasswordService::PasswordService(std::size_t maxThrottlerEntries) PasswordService::PasswordService(std::size_t maxThrottlerEntries)
: _loginThrottler{maxThrottlerEntries} : _loginThrottler{maxThrottlerEntries}
{ {
@@ -17,17 +17,12 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* This file contains some classes in order to get info from file using the libavconv */
#pragma once #pragma once
#include <string> #include <shared_mutex>
#include "auth/IPasswordService.hpp"
#include <boost/asio/ip/address.hpp>
#include "LoginThrottler.hpp" #include "LoginThrottler.hpp"
#include "database/User.hpp"
#include "database/Types.hpp"
namespace Database namespace Database
{ {
@@ -37,7 +32,7 @@ namespace Database
namespace Auth { namespace Auth {
class PasswordService class PasswordService : public IPasswordService
{ {
public: public:
@@ -53,39 +48,9 @@ namespace Auth {
// Password services // Password services
enum class PasswordCheckResult PasswordCheckResult checkUserPassword(Database::Session& session, const boost::asio::ip::address& clientAddress, const std::string& loginName, const std::string& password) override;
{ Database::User::PasswordHash hashPassword(const std::string& password) const override;
Match, bool evaluatePasswordStrength(const std::string& loginName, const std::string& password) const override;
Mismatch,
Throttled,
};
PasswordCheckResult checkUserPassword(Database::Session& session, const boost::asio::ip::address& clientAddress, const std::string& loginName, const std::string& password);
Database::User::PasswordHash hashPassword(const std::string& password) const;
bool evaluatePasswordStrength(const std::string& loginName, const std::string& password) const;
// Auth Token services
struct AuthTokenProcessResult
{
enum class State
{
Found,
Throttled,
NotFound,
};
struct AuthTokenInfo
{
Database::IdType userId;
Wt::WDateTime expiry;
};
State state;
std::optional<AuthTokenInfo> authTokenInfo;
};
// Removed if found
AuthTokenProcessResult processAuthToken(Database::Session& session, const boost::asio::ip::address& clientAddress, const std::string& tokenValue);
std::string createAuthToken(Database::Session& session, Database::IdType userid, const Wt::WDateTime& expiry);
private: private:
@@ -17,9 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "AvInfo.hpp" #include "av/AvInfo.hpp"
#include <boost/algorithm/string.hpp>
#include <array> #include <array>
@@ -92,7 +90,7 @@ getMetaDataFromDictionnary(AVDictionary* dictionnary, std::map<std::string, std:
AVDictionaryEntry *tag = NULL; AVDictionaryEntry *tag = NULL;
while ((tag = av_dict_get(dictionnary, "", tag, AV_DICT_IGNORE_SUFFIX))) while ((tag = av_dict_get(dictionnary, "", tag, AV_DICT_IGNORE_SUFFIX)))
{ {
res[boost::to_upper_copy<std::string>(tag->key)] = tag->value; res[StringUtils::stringToUpper(tag->key)] = tag->value;
} }
} }
@@ -141,7 +139,7 @@ MediaFile::getStreamInfo() const
if (avstream->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) if (avstream->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
continue; continue;
res.push_back( {.id = i, .bitrate = static_cast<std::size_t>(avstream->codecpar->bit_rate)} ); res.push_back( {i, static_cast<std::size_t>(avstream->codecpar->bit_rate)} );
} }
return res; return res;
@@ -17,13 +17,13 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "AvTranscoder.hpp" #include "av/AvTranscoder.hpp"
#include <atomic> #include <atomic>
#include <mutex> #include <mutex>
#include "AvInfo.hpp" #include "av/AvInfo.hpp"
#include "utils/Config.hpp" #include "utils/IConfig.hpp"
#include "utils/Path.hpp" #include "utils/Path.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "utils/Service.hpp" #include "utils/Service.hpp"
@@ -38,7 +38,7 @@ static std::filesystem::path ffmpegPath;
void void
Transcoder::init() Transcoder::init()
{ {
ffmpegPath = ServiceProvider<Config>::get()->getPath("ffmpeg-file", "/usr/bin/ffmpeg"); ffmpegPath = ServiceProvider<IConfig>::get()->getPath("ffmpeg-file", "/usr/bin/ffmpeg");
if (!std::filesystem::exists(ffmpegPath)) if (!std::filesystem::exists(ffmpegPath))
throw LmsException {"File '" + ffmpegPath.string() + "' does not exist!"}; throw LmsException {"File '" + ffmpegPath.string() + "' does not exist!"};
} }
@@ -17,9 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "AvTypes.hpp" #include "av/AvTypes.hpp"
#include <map>
namespace Av { namespace Av {
@@ -34,7 +32,7 @@ const char* encodingToMimetype(Encoding encoding)
case Encoding::WEBM_VORBIS: return "audio/webm"; case Encoding::WEBM_VORBIS: return "audio/webm";
} }
throw AvException("Invalid encoding"); throw AvException {"Invalid encoding"};
} }
} }
@@ -236,7 +236,7 @@ Grabber::getFromRelease(Database::Session& session, Database::IdType releaseId,
} }
std::vector<uint8_t> std::vector<uint8_t>
Grabber::getFromTrack(Database::Session& session, Database::IdType trackId, Image::Format format, std::size_t size) Grabber::getFromTrack(Database::Session& session, Database::IdType trackId, Format format, std::size_t size)
{ {
const Image::Image cover {getFromTrack(session, trackId, size)}; const Image::Image cover {getFromTrack(session, trackId, size)};
@@ -245,7 +245,7 @@ Grabber::getFromTrack(Database::Session& session, Database::IdType trackId, Imag
} }
std::vector<uint8_t> std::vector<uint8_t>
Grabber::getFromRelease(Database::Session& session, Database::IdType releaseId, Image::Format format, std::size_t size) Grabber::getFromRelease(Database::Session& session, Database::IdType releaseId, Format format, std::size_t size)
{ {
const Image::Image cover {getFromRelease(session, releaseId, size)}; const Image::Image cover {getFromRelease(session, releaseId, size)};
+78
View File
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2015 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 <filesystem>
#include <map>
#include <mutex>
#include <optional>
#include <vector>
#include "cover/ICoverArtGrabber.hpp"
#include "database/Types.hpp"
#include "Image.hpp"
namespace Database
{
class Session;
}
namespace CoverArt
{
class Grabber : public IGrabber
{
public:
Grabber();
Grabber(const Grabber&) = delete;
Grabber& operator=(const Grabber&) = delete;
Grabber(Grabber&&) = delete;
Grabber& operator=(Grabber&&) = delete;
void setDefaultCover(const std::filesystem::path& defaultCoverPath) override;
std::vector<uint8_t> getFromTrack(Database::Session& dbSession, Database::IdType trackId, Format format, std::size_t width) override;
std::vector<uint8_t> getFromRelease(Database::Session& dbSession, Database::IdType releaseId, Format format, std::size_t width) override;
private:
Image::Image getFromTrack(Database::Session& dbSession, Database::IdType trackId, std::size_t size);
Image::Image getFromRelease(Database::Session& dbSession, Database::IdType releaseId, std::size_t size);
std::optional<Image::Image> getFromTrack(const std::filesystem::path& path) const;
std::vector<std::filesystem::path> getCoverPaths(const std::filesystem::path& directoryPath) const;
std::optional<Image::Image> getFromDirectory(const std::filesystem::path& path) const;
Image::Image getDefaultCover(std::size_t size);
Image::Image _defaultCover;
std::mutex _mutex;
std::map<std::size_t /* size */, Image::Image> _defaultCovers;
static inline const std::vector<std::filesystem::path> _fileExtensions {".jpg", ".jpeg", ".png", ".bmp"}; // TODO parametrize
static inline const std::size_t _maxFileSize {10000000};
static inline const std::vector<std::filesystem::path> _preferredFileNames {"cover", "front"}; // TODO parametrize
};
} // namespace CoverArt
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Image.hpp" #include "image/Image.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
@@ -16,18 +16,18 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Artist.hpp" #include "database/Artist.hpp"
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
#include "database/Cluster.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "Cluster.hpp"
#include "Release.hpp"
#include "SqlQuery.hpp" #include "SqlQuery.hpp"
#include "Session.hpp"
#include "Track.hpp"
#include "User.hpp"
namespace Database namespace Database
{ {
@@ -17,14 +17,14 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Cluster.hpp" #include "database/Cluster.hpp"
#include "Artist.hpp" #include "database/Artist.hpp"
#include "Release.hpp" #include "database/Release.hpp"
#include "ScanSettings.hpp" #include "database/ScanSettings.hpp"
#include "Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp"
#include "SqlQuery.hpp" #include "SqlQuery.hpp"
#include "Track.hpp"
namespace Database { namespace Database {
@@ -17,13 +17,13 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Db.hpp" #include "database/Db.hpp"
#include <Wt/Dbo/FixedSqlConnectionPool.h> #include <Wt/Dbo/FixedSqlConnectionPool.h>
#include <Wt/Dbo/backend/Sqlite3.h> #include <Wt/Dbo/backend/Sqlite3.h>
#include "database/User.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "User.hpp"
namespace Database { namespace Database {
@@ -17,16 +17,16 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Release.hpp" #include "database/Release.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "Artist.hpp" #include "database/Artist.hpp"
#include "Cluster.hpp" #include "database/Cluster.hpp"
#include "Session.hpp" #include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "SqlQuery.hpp" #include "SqlQuery.hpp"
#include "Track.hpp"
#include "User.hpp"
namespace Database namespace Database
{ {
@@ -17,15 +17,15 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "ScanSettings.hpp" #include "database/ScanSettings.hpp"
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "utils/String.hpp" #include "utils/String.hpp"
#include "Cluster.hpp" #include "database/Cluster.hpp"
#include "Session.hpp" #include "database/Session.hpp"
namespace { namespace {
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Session.hpp" #include "database/Session.hpp"
#include <map> #include <map>
#include <mutex> #include <mutex>
@@ -26,17 +26,17 @@
#include "utils/Exception.hpp" #include "utils/Exception.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "Artist.hpp" #include "database/Artist.hpp"
#include "Cluster.hpp" #include "database/Cluster.hpp"
#include "Db.hpp" #include "database/Db.hpp"
#include "Release.hpp" #include "database/Release.hpp"
#include "ScanSettings.hpp" #include "database/ScanSettings.hpp"
#include "Track.hpp" #include "database/Track.hpp"
#include "TrackBookmark.hpp" #include "database/TrackBookmark.hpp"
#include "TrackArtistLink.hpp" #include "database/TrackArtistLink.hpp"
#include "TrackList.hpp" #include "database/TrackList.hpp"
#include "TrackFeatures.hpp" #include "database/TrackFeatures.hpp"
#include "User.hpp" #include "database/User.hpp"
namespace Database { namespace Database {
@@ -17,13 +17,13 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "SessionPool.hpp" #include "database/SessionPool.hpp"
#include "database/Session.hpp"
#include "utils/Exception.hpp" #include "utils/Exception.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "Session.hpp"
namespace Database { namespace Database {
SessionPool::SessionPool(Db& database, std::size_t maxSessionCount) SessionPool::SessionPool(Db& database, std::size_t maxSessionCount)
@@ -17,17 +17,17 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Track.hpp" #include "database/Track.hpp"
#include <Wt/Dbo/WtSqlTraits.h> #include <Wt/Dbo/WtSqlTraits.h>
#include "database/Artist.hpp"
#include "database/Cluster.hpp"
#include "database/Release.hpp"
#include "database/TrackFeatures.hpp"
#include "database/Session.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "Artist.hpp"
#include "Cluster.hpp"
#include "Release.hpp"
#include "TrackFeatures.hpp"
#include "Session.hpp"
#include "SqlQuery.hpp" #include "SqlQuery.hpp"
namespace Database { namespace Database {
@@ -17,11 +17,11 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "TrackArtistLink.hpp" #include "database/TrackArtistLink.hpp"
#include "Artist.hpp" #include "database/Artist.hpp"
#include "Session.hpp" #include "database/Session.hpp"
#include "Track.hpp" #include "database/Track.hpp"
namespace Database { namespace Database {
@@ -17,11 +17,11 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "TrackBookmark.hpp" #include "database/TrackBookmark.hpp"
#include "Session.hpp" #include "database/Session.hpp"
#include "Track.hpp" #include "database/Track.hpp"
#include "User.hpp" #include "database/User.hpp"
namespace Database { namespace Database {
@@ -17,14 +17,14 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "TrackFeatures.hpp" #include "database/TrackFeatures.hpp"
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "Session.hpp"
#include "Track.hpp"
namespace Database { namespace Database {
@@ -16,19 +16,18 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "TrackList.hpp" #include "database/TrackList.hpp"
#include <cassert> #include <cassert>
#include <random>
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "Artist.hpp" #include "database/Artist.hpp"
#include "Cluster.hpp" #include "database/Cluster.hpp"
#include "Release.hpp" #include "database/Release.hpp"
#include "Session.hpp" #include "database/Session.hpp"
#include "User.hpp" #include "database/User.hpp"
#include "Track.hpp" #include "database/Track.hpp"
namespace Database { namespace Database {
@@ -17,14 +17,14 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "User.hpp" #include "database/User.hpp"
#include "database/Artist.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/TrackList.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "Artist.hpp"
#include "Release.hpp"
#include "Session.hpp"
#include "Track.hpp"
#include "TrackList.hpp"
namespace Database { namespace Database {
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "AvFormat.hpp" #include "metadata/AvFormat.hpp"
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
@@ -142,7 +142,7 @@ AvFormat::parse(const std::filesystem::path& p, bool debug)
for (auto stream : mediaFile.getStreamInfo()) for (auto stream : mediaFile.getStreamInfo())
{ {
MetaData::AudioStream audioStream {.bitRate = static_cast<unsigned>(stream.bitrate)}; MetaData::AudioStream audioStream {static_cast<unsigned>(stream.bitrate)};
track.audioStreams.emplace_back(audioStream); track.audioStreams.emplace_back(audioStream);
} }
} }
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "TagLibParser.hpp" #include "metadata/TagLibParser.hpp"
#include <taglib/asffile.h> #include <taglib/asffile.h>
#include <taglib/id3v2tag.h> #include <taglib/id3v2tag.h>
@@ -180,7 +180,7 @@ TagLibParser::parse(const std::filesystem::path& p, bool debug)
track.duration = std::chrono::milliseconds {properties->length() * 1000}; track.duration = std::chrono::milliseconds {properties->length() * 1000};
MetaData::AudioStream audioStream {.bitRate = static_cast<unsigned>(properties->bitrate() * 1000)}; MetaData::AudioStream audioStream {static_cast<unsigned>(properties->bitrate() * 1000)};
track.audioStreams = {std::move(audioStream)}; track.audioStreams = {std::move(audioStream)};
} }
@@ -17,31 +17,38 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "SimilaritySearcher.hpp" #include "Engine.hpp"
#include "features/SimilarityFeaturesScannerAddon.hpp" //#include "features/SimilarityFeaturesScannerAddon.hpp"
#include "cluster/SimilarityClusterSearcher.hpp" //#include "cluster/SimilarityClusterSearcher.hpp"
#include "database/ScanSettings.hpp" #include "database/ScanSettings.hpp"
#include "database/TrackList.hpp" #include "database/TrackList.hpp"
namespace Similarity { namespace Recommendation {
Searcher::Searcher(FeaturesScannerAddon& somAddon) std::unique_ptr<IEngine>
: _somAddon(somAddon) createEngine()
{}
static
Database::ScanSettings::SimilarityEngineType
getEngineType(Database::Session& dbSession)
{ {
auto transaction {dbSession.createSharedTransaction()}; return std::make_unique<Engine>();
return Database::ScanSettings::get(dbSession)->getSimilarityEngineType(); }
void
Engine::clearProviders()
{
_providers.clear();
}
void
Engine::addProvider(std::unique_ptr<Provider> provider, unsigned priority)
{
_providers.emplace(priority, std::move(provider));
} }
std::vector<Database::IdType> std::vector<Database::IdType>
Searcher::getSimilarTracksFromTrackList(Database::Session& session, Database::IdType trackListId, std::size_t maxCount) Engine::getSimilarTracksFromTrackList(Database::Session& /*session*/, Database::IdType /*trackListId*/, std::size_t /*maxCount*/)
{ {
#if 0
auto engineType {getEngineType(session)}; auto engineType {getEngineType(session)};
auto somSearcher {_somAddon.getSearcher()}; auto somSearcher {_somAddon.getSearcher()};
@@ -66,12 +73,15 @@ Searcher::getSimilarTracksFromTrackList(Database::Session& session, Database::Id
return somSearcher->getSimilarTracks(trackIds, maxCount); return somSearcher->getSimilarTracks(trackIds, maxCount);
} }
else else
return ClusterSearcher::getSimilarTracksFromTrackList(session, trackListId, maxCount); return ClusterEngine::getSimilarTracksFromTrackList(session, trackListId, maxCount);
#endif
return {};
} }
std::vector<Database::IdType> std::vector<Database::IdType>
Searcher::getSimilarTracks(Database::Session& dbSession, const std::set<Database::IdType>& trackIds, std::size_t maxCount) Engine::getSimilarTracks(Database::Session& /*dbSession*/, const std::unordered_set<Database::IdType>& /*trackIds*/, std::size_t /*maxCount*/)
{ {
#if 0
auto engineType {getEngineType(dbSession)}; auto engineType {getEngineType(dbSession)};
auto somSearcher {_somAddon.getSearcher()}; auto somSearcher {_somAddon.getSearcher()};
@@ -82,12 +92,15 @@ Searcher::getSimilarTracks(Database::Session& dbSession, const std::set<Database
return somSearcher->getSimilarTracks(trackIds, maxCount); return somSearcher->getSimilarTracks(trackIds, maxCount);
} }
else else
return ClusterSearcher::getSimilarTracks(dbSession, trackIds, maxCount); return ClusterEngine::getSimilarTracks(dbSession, trackIds, maxCount);
#endif
return {};
} }
std::vector<Database::IdType> std::vector<Database::IdType>
Searcher::getSimilarReleases(Database::Session& dbSession, Database::IdType releaseId, std::size_t maxCount) Engine::getSimilarReleases(Database::Session& /*dbSession*/, Database::IdType /*releaseId*/, std::size_t /*maxCount*/)
{ {
#if 0
auto engineType {getEngineType(dbSession)}; auto engineType {getEngineType(dbSession)};
auto somSearcher {_somAddon.getSearcher()}; auto somSearcher {_somAddon.getSearcher()};
@@ -98,12 +111,15 @@ Searcher::getSimilarReleases(Database::Session& dbSession, Database::IdType rele
return somSearcher->getSimilarReleases(releaseId, maxCount); return somSearcher->getSimilarReleases(releaseId, maxCount);
} }
else else
return ClusterSearcher::getSimilarReleases(dbSession, releaseId, maxCount); return ClusterEngine::getSimilarReleases(dbSession, releaseId, maxCount);
#endif
return {};
} }
std::vector<Database::IdType> std::vector<Database::IdType>
Searcher::getSimilarArtists(Database::Session& dbSession, Database::IdType artistId, std::size_t maxCount) Engine::getSimilarArtists(Database::Session& /*dbSession*/, Database::IdType /*artistId*/, std::size_t /*maxCount*/)
{ {
#if 0
auto engineType {getEngineType(dbSession)}; auto engineType {getEngineType(dbSession)};
auto somSearcher {_somAddon.getSearcher()}; auto somSearcher {_somAddon.getSearcher()};
@@ -114,7 +130,9 @@ Searcher::getSimilarArtists(Database::Session& dbSession, Database::IdType artis
return somSearcher->getSimilarArtists(artistId, maxCount); return somSearcher->getSimilarArtists(artistId, maxCount);
} }
else else
return ClusterSearcher::getSimilarArtists(dbSession, artistId, maxCount); return ClusterEngine::getSimilarArtists(dbSession, artistId, maxCount);
#endif
return {};
} }
} // ns Similarity } // ns Similarity
+52
View File
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2019 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 <map>
#include "recommendation/IEngine.hpp"
#include "recommendation/Provider.hpp"
namespace Database
{
class Session;
}
namespace Recommendation
{
class Engine : public IEngine
{
public:
void clearProviders() override;
void addProvider(std::unique_ptr<Provider> provider, unsigned priority) override;
// Closest results first
std::vector<Database::IdType> getSimilarTracksFromTrackList(Database::Session& session, Database::IdType tracklistId, std::size_t maxCount) override;
std::vector<Database::IdType> getSimilarTracks(Database::Session& session, const std::unordered_set<Database::IdType>& tracksId, std::size_t maxCount) override;
std::vector<Database::IdType> getSimilarReleases(Database::Session& session, Database::IdType releaseId, std::size_t maxCount) override;
std::vector<Database::IdType> getSimilarArtists(Database::Session& session, Database::IdType artistId, std::size_t maxCount) override;
private:
std::map<unsigned, std::unique_ptr<Provider>> _providers;
};
} // ns Recommendation
@@ -0,0 +1,38 @@
/*
* 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/>.
*/
#include "recommendation/ClustersRecommendationProviderCreator.hpp"
#include "recommendation/FeaturesRecommendationProviderCreator.hpp"
#include "recommendation/Provider.hpp"
namespace Recommendation
{
std::unique_ptr<Provider> createClustersRecommendationProvider()
{
return {};
}
std::unique_ptr<Provider> createFeaturesRecommendationProvider(Scanner::MediaScanner&)
{
return {};
}
}
@@ -19,9 +19,6 @@
#include "SimilarityClusterSearcher.hpp" #include "SimilarityClusterSearcher.hpp"
#include <random>
#include <chrono>
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
@@ -25,7 +25,7 @@
#include <Wt/WIOService.h> #include <Wt/WIOService.h>
#include <Wt/Http/Client.h> #include <Wt/Http/Client.h>
#include "utils/Config.hpp" #include "utils/IConfig.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "utils/Service.hpp" #include "utils/Service.hpp"
@@ -39,7 +39,7 @@ getJsonData(const UUID& mbid)
{ {
static const std::string defaultAPIURL = "https://acousticbrainz.org/api/v1/"; static const std::string defaultAPIURL = "https://acousticbrainz.org/api/v1/";
const std::string url {ServiceProvider<Config>::get()->getString("acousticbrainz-api-url", defaultAPIURL) + std::string {mbid.getAsString()} + "/low-level"}; const std::string url {ServiceProvider<IConfig>::get()->getString("acousticbrainz-api-url", defaultAPIURL) + std::string {mbid.getAsString()} + "/low-level"};
boost::asio::io_service ioService; boost::asio::io_service ioService;
@@ -22,7 +22,7 @@
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp> #include <boost/property_tree/xml_parser.hpp>
#include "utils/Config.hpp" #include "utils/IConfig.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "utils/Service.hpp" #include "utils/Service.hpp"
@@ -32,7 +32,7 @@ namespace Similarity {
static static
std::filesystem::path getCacheDirectory() std::filesystem::path getCacheDirectory()
{ {
return ServiceProvider<Config>::get()->getPath("working-dir") / "cache" / "features"; return ServiceProvider<IConfig>::get()->getPath("working-dir") / "cache" / "features";
} }
static std::filesystem::path getCacheNetworkFilePath() static std::filesystem::path getCacheNetworkFilePath()
@@ -242,7 +242,7 @@ FeaturesCache::read()
void void
FeaturesCache::write() FeaturesCache::write()
{ {
std::filesystem::create_directories(ServiceProvider<Config>::get()->getPath("working-dir") / "cache" / "features"); std::filesystem::create_directories(ServiceProvider<IConfig>::get()->getPath("working-dir") / "cache" / "features");
if (!networkToCacheFile(_network, getCacheNetworkFilePath()) if (!networkToCacheFile(_network, getCacheNetworkFilePath())
|| !objectPositionToCacheFile(_trackPositions, getCacheTrackPositionsFilePath())) || !objectPositionToCacheFile(_trackPositions, getCacheTrackPositionsFilePath()))
@@ -17,16 +17,16 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "SimilarityFeaturesScannerAddon.hpp" #include "similarity/features/SimilarityFeaturesScannerAddon.hpp"
#include "AcousticBrainzUtils.hpp" #include "AcousticBrainzUtils.hpp"
#include "database/ScanSettings.hpp" #include "database/ScanSettings.hpp"
#include "database/Track.hpp" #include "database/Track.hpp"
#include "database/TrackFeatures.hpp" #include "database/TrackFeatures.hpp"
#include "similarity/features/SimilarityFeaturesCache.hpp"
#include "utils/Config.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "SimilarityFeaturesCache.hpp"
namespace Similarity { namespace Similarity {
static static
@@ -17,13 +17,12 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "MediaScanner.hpp" #include "scanner/MediaScanner.hpp"
#include <boost/asio/placeholders.hpp> #include <boost/asio/placeholders.hpp>
#include <Wt/WLocalDateTime.h> #include <Wt/WLocalDateTime.h>
#include "cover/CoverArtGrabber.hpp"
#include "database/Artist.hpp" #include "database/Artist.hpp"
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "database/Release.hpp" #include "database/Release.hpp"
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "MediaScannerStats.hpp" #include "scanner/MediaScannerStats.hpp"
namespace Scanner { namespace Scanner {
@@ -19,16 +19,36 @@
#include "Config.hpp" #include "Config.hpp"
#include "utils/Exception.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
std::unique_ptr<IConfig> createConfig(const std::filesystem::path& p)
{
return std::make_unique<Config>(p);
}
Config::Config(const std::filesystem::path& p) Config::Config(const std::filesystem::path& p)
{ {
_config.readFile(p.string().c_str()); try
{
_config.readFile(p.string().c_str());
}
catch( libconfig::FileIOException& e)
{
throw LmsException {"Cannot open config file '" + p.string() + "'"};
}
catch( libconfig::ParseException& e)
{
throw LmsException {"Cannot parse config file '" + p.string() + "', line = " + std::to_string(e.getLine()) + ", error = '" + e.getError() + "'"};
}
catch (libconfig::ConfigException& e)
{
throw LmsException {"Cannot open config file '" + p.string() + "': " + e.what()};
}
} }
std::string std::string
Config::getString(const std::string& setting, const std::string& def, const std::set<std::string>& allowedValues) Config::getString(const std::string& setting, const std::string& def, const std::unordered_set<std::string>& allowedValues)
{ {
try { try {
std::string res {(const char*)_config.lookup(setting)}; std::string res {(const char*)_config.lookup(setting)};
@@ -18,13 +18,12 @@
*/ */
#pragma once #pragma once
#include <filesystem> #include "utils/IConfig.hpp"
#include <set>
#include <libconfig.h++> #include <libconfig.h++>
// Used to get config values from configuration files // Used to get config values from configuration files
class Config final class Config final : public IConfig
{ {
public: public:
Config(const std::filesystem::path& p); Config(const std::filesystem::path& p);
@@ -36,11 +35,11 @@ class Config final
Config& operator=(Config&&) = delete; Config& operator=(Config&&) = delete;
// Default values are returned in case of setting not found // Default values are returned in case of setting not found
std::string getString(const std::string& setting, const std::string& def = "", const std::set<std::string>& allowedValues = {}); std::string getString(const std::string& setting, const std::string& def = "", const std::unordered_set<std::string>& allowedValues = {}) override;
std::filesystem::path getPath(const std::string& setting, const std::filesystem::path& def = std::filesystem::path()); std::filesystem::path getPath(const std::string& setting, const std::filesystem::path& def = std::filesystem::path()) override;
unsigned long getULong(const std::string& setting, unsigned long def = 0); unsigned long getULong(const std::string& setting, unsigned long def = 0) override;
long getLong(const std::string& setting, long def = 0); long getLong(const std::string& setting, long def = 0) override;
bool getBool(const std::string& setting, bool def = false); bool getBool(const std::string& setting, bool def = false) override;
private: private:
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Logger.hpp" #include "utils/Logger.hpp"
const char* getModuleName(Module mod) const char* getModuleName(Module mod)
{ {
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "NetAddress.hpp" #include "utils/NetAddress.hpp"
namespace std namespace std
{ {
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Path.hpp" #include "utils/Path.hpp"
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Random.hpp" #include "utils/Random.hpp"
namespace Random { namespace Random {
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "StreamLogger.hpp" #include "utils/StreamLogger.hpp"
StreamLogger::StreamLogger(std::ostream& os) StreamLogger::StreamLogger(std::ostream& os)
: _os {os} : _os {os}
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "String.hpp" #include "utils/String.hpp"
#include <iomanip> #include <iomanip>
@@ -103,6 +103,12 @@ stringToLower(const std::string& str)
return boost::algorithm::to_lower_copy(str); return boost::algorithm::to_lower_copy(str);
} }
std::string
stringToUpper(const std::string& str)
{
return boost::to_upper_copy<std::string>(str);
}
std::string std::string
bufferToString(const std::vector<unsigned char>& data) bufferToString(const std::vector<unsigned char>& data)
{ {
@@ -17,7 +17,7 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "UUID.hpp" #include "utils/UUID.hpp"
#include <regex> #include <regex>
@@ -17,12 +17,12 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>. * along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "WtLogger.hpp" #include "utils/WtLogger.hpp"
#include <Wt/WApplication.h> #include <Wt/WApplication.h>
#include <Wt/WLogger.h> #include <Wt/WLogger.h>
#include "Logger.hpp" #include "utils/Logger.hpp"
void void
WtLogger::processLog(const Log& log) WtLogger::processLog(const Log& log)
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2019 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/>.
*/
/* This file contains some classes in order to get info from file using the libavconv */
#pragma once
#include <optional>
#include <string>
#include <boost/asio/ip/address.hpp>
#include <Wt/WDateTime.h>
#include "database/Types.hpp"
namespace Database
{
class Session;
}
namespace Auth {
class IAuthTokenService
{
public:
// Auth Token services
struct AuthTokenProcessResult
{
enum class State
{
Found,
Throttled,
NotFound,
};
struct AuthTokenInfo
{
Database::IdType userId;
Wt::WDateTime expiry;
};
State state {State::NotFound};
std::optional<AuthTokenInfo> authTokenInfo {};
};
// Removed if found
virtual AuthTokenProcessResult processAuthToken(Database::Session& session, const boost::asio::ip::address& clientAddress, const std::string& tokenValue) = 0;
virtual std::string createAuthToken(Database::Session& session, Database::IdType userid, const Wt::WDateTime& expiry) = 0;
};
std::unique_ptr<IAuthTokenService> createAuthTokenService(std::size_t maxThrottlerEntryCount);
}
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2019 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 <boost/asio/ip/address.hpp>
#include "database/User.hpp"
#include "database/Types.hpp"
namespace Database
{
class Session;
}
namespace Auth {
class IPasswordService
{
public:
virtual ~IPasswordService() = default;
// Password services
enum class PasswordCheckResult
{
Match,
Mismatch,
Throttled,
};
virtual PasswordCheckResult checkUserPassword(Database::Session& session, const boost::asio::ip::address& clientAddress, const std::string& loginName, const std::string& password) = 0;
virtual Database::User::PasswordHash hashPassword(const std::string& password) const = 0;
virtual bool evaluatePasswordStrength(const std::string& loginName, const std::string& password) const = 0;
};
std::unique_ptr<IPasswordService> createPasswordService(std::size_t maxThrottlerEntryCount);
}
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2015 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 <string>
namespace CoverArt
{
enum class Format
{
JPEG,
};
std::string formatToMimeType(Format format);
struct Geometry
{
std::size_t width;
std::size_t height;
};
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2015 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 <filesystem>
#include <vector>
#include "database/Types.hpp"
#include "cover/CoverArt.hpp"
namespace Database {
class Session;
}
namespace CoverArt {
class IGrabber
{
public:
virtual ~IGrabber() = default;
virtual void setDefaultCover(const std::filesystem::path& defaultCoverPath) = 0;
virtual std::vector<uint8_t> getFromTrack(Database::Session& dbSession, Database::IdType trackId, Format format, std::size_t width) = 0;
virtual std::vector<uint8_t> getFromRelease(Database::Session& dbSession, Database::IdType releaseId, Format format, std::size_t width) = 0;
};
} // namespace CoverArt
@@ -67,8 +67,8 @@ class Session
Session& operator=(const Session&) = delete; Session& operator=(const Session&) = delete;
Session& operator=(Session&&) = delete; Session& operator=(Session&&) = delete;
UniqueTransaction createUniqueTransaction(); [[nodiscard]] UniqueTransaction createUniqueTransaction();
SharedTransaction createSharedTransaction(); [[nodiscard]] SharedTransaction createSharedTransaction();
void checkUniqueLocked(); void checkUniqueLocked();
void checkSharedLocked(); void checkSharedLocked();
@@ -0,0 +1,35 @@
/*
* 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 <memory>
namespace Database
{
class Session;
}
namespace Recommendation
{
class Provider;
std::unique_ptr<Provider> createClustersRecommendationProvider();
}
@@ -0,0 +1,40 @@
/*
* 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 <memory>
namespace Database
{
class Session;
}
namespace Scanner
{
class MediaScanner;
}
namespace Recommendation
{
class Provider;
std::unique_ptr<Provider> createFeaturesRecommendationProvider(Scanner::MediaScanner& scanner);
}

Some files were not shown because too many files have changed in this diff Show More