diff --git a/src/libs/services/CMakeLists.txt b/src/libs/services/CMakeLists.txt index fd4d3160..70f360ed 100644 --- a/src/libs/services/CMakeLists.txt +++ b/src/libs/services/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(auth) add_subdirectory(cover) add_subdirectory(database) +add_subdirectory(feedback) add_subdirectory(recommendation) add_subdirectory(scanner) add_subdirectory(scrobbling) diff --git a/src/libs/services/database/impl/User.cpp b/src/libs/services/database/impl/User.cpp index 038c3a55..75c69adf 100644 --- a/src/libs/services/database/impl/User.cpp +++ b/src/libs/services/database/impl/User.cpp @@ -161,61 +161,61 @@ User::getQueuedTrackList(Session& session) const } void -User::starArtist(ObjectPtr artist) +User::star(ObjectPtr artist) { if (_starredArtists.count(getDboPtr(artist)) == 0) _starredArtists.insert(getDboPtr(artist)); } void -User::unstarArtist(ObjectPtr artist) +User::unstar(ObjectPtr artist) { if (_starredArtists.count(getDboPtr(artist)) != 0) _starredArtists.erase(getDboPtr(artist)); } bool -User::hasStarredArtist(ObjectPtr artist) const +User::isStarred(ObjectPtr artist) const { return _starredArtists.count(getDboPtr(artist)) != 0; } void -User::starRelease(ObjectPtr release) +User::star(ObjectPtr release) { if (_starredReleases.count(getDboPtr(release)) == 0) _starredReleases.insert(getDboPtr(release)); } void -User::unstarRelease(ObjectPtr release) +User::unstar(ObjectPtr release) { if (_starredReleases.count(getDboPtr(release)) != 0) _starredReleases.erase(getDboPtr(release)); } bool -User::hasStarredRelease(ObjectPtr release) const +User::isStarred(ObjectPtr release) const { return _starredReleases.count(getDboPtr(release)) != 0; } void -User::starTrack(ObjectPtr track) +User::star(ObjectPtr track) { if (_starredTracks.count(getDboPtr(track)) == 0) _starredTracks.insert(getDboPtr(track)); } void -User::unstarTrack(ObjectPtr track) +User::unstar(ObjectPtr track) { if (_starredTracks.count(getDboPtr(track)) != 0) _starredTracks.erase(getDboPtr(track)); } bool -User::hasStarredTrack(ObjectPtr track) const +User::isStarred(ObjectPtr track) const { return _starredTracks.count(getDboPtr(track)) != 0; } diff --git a/src/libs/services/database/include/services/database/User.hpp b/src/libs/services/database/include/services/database/User.hpp index 34748567..34bfac2c 100644 --- a/src/libs/services/database/include/services/database/User.hpp +++ b/src/libs/services/database/include/services/database/User.hpp @@ -167,18 +167,18 @@ class User : public Object ObjectPtr getQueuedTrackList(Session& session) const; - void starArtist(ObjectPtr artist); - void unstarArtist(ObjectPtr artist); - bool hasStarredArtist(ObjectPtr artist) const; + void star(ObjectPtr artist); + void unstar(ObjectPtr artist); + bool isStarred(ObjectPtr artist) const; - void starRelease(ObjectPtr release); - void unstarRelease(ObjectPtr release); - bool hasStarredRelease(ObjectPtr release) const; + void star(ObjectPtr release); + void unstar(ObjectPtr release); + bool isStarred(ObjectPtr release) const; // Stars - void starTrack(ObjectPtr track); - void unstarTrack(ObjectPtr track); - bool hasStarredTrack(ObjectPtr track) const; + void star(ObjectPtr track); + void unstar(ObjectPtr track); + bool isStarred(ObjectPtr track) const; template void persist(Action& a) diff --git a/src/libs/services/database/test/Artist.cpp b/src/libs/services/database/test/Artist.cpp index dcace44e..d94c6daf 100644 --- a/src/libs/services/database/test/Artist.cpp +++ b/src/libs/services/database/test/Artist.cpp @@ -366,3 +366,36 @@ TEST_F(DatabaseFixture, SingleArtistNonReleaseTracks) EXPECT_EQ(tracks.front()->getId(), track2.getId()); } } + +TEST_F(DatabaseFixture, SingleStarredArtist) +{ + ScopedArtist artist {session, "MyArtist"}; + ScopedTrack track {session, "MyTrack"}; + ScopedUser user {session, "MyUser"}; + + { + auto transaction {session.createUniqueTransaction()}; + + EXPECT_FALSE(user->isStarred(artist.get())); + } + + { + auto transaction {session.createUniqueTransaction()}; + + auto trackArtistLink {TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist)}; + user.get().modify()->star(artist.get()); + } + + { + auto transaction {session.createSharedTransaction()}; + + EXPECT_TRUE(user->isStarred(artist.get())); + + bool hasMore {}; + auto artists {Artist::getStarred(session, user.get(), {}, std::nullopt, Artist::SortMethod::BySortName, std::nullopt, hasMore)}; + ASSERT_EQ(artists.size(), 1); + EXPECT_EQ(artists.front()->getId(), artist.getId()); + EXPECT_FALSE(hasMore); + } +} + diff --git a/src/libs/services/database/test/DatabaseTest.cpp b/src/libs/services/database/test/DatabaseTest.cpp index 1bca6150..2e0a386a 100644 --- a/src/libs/services/database/test/DatabaseTest.cpp +++ b/src/libs/services/database/test/DatabaseTest.cpp @@ -104,100 +104,6 @@ TEST_F(DatabaseFixture, SingleUser) } } -TEST_F(DatabaseFixture, SingleStarredArtist) -{ - ScopedArtist artist {session, "MyArtist"}; - ScopedTrack track {session, "MyTrack"}; - ScopedUser user {session, "MyUser"}; - - { - auto transaction {session.createUniqueTransaction()}; - - EXPECT_FALSE(user->hasStarredArtist(artist.get())); - } - - { - auto transaction {session.createUniqueTransaction()}; - - auto trackArtistLink {TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist)}; - user.get().modify()->starArtist(artist.get()); - } - - { - auto transaction {session.createSharedTransaction()}; - - EXPECT_TRUE(user->hasStarredArtist(artist.get())); - - bool hasMore {}; - auto artists {Artist::getStarred(session, user.get(), {}, std::nullopt, Artist::SortMethod::BySortName, std::nullopt, hasMore)}; - ASSERT_EQ(artists.size(), 1); - EXPECT_EQ(artists.front()->getId(), artist.getId()); - EXPECT_FALSE(hasMore); - } -} - -TEST_F(DatabaseFixture, SingleStarredRelease) -{ - ScopedRelease release {session, "MyRelease"}; - ScopedTrack track {session, "MyTrack"}; - ScopedUser user {session, "MyUser"}; - - { - auto transaction {session.createSharedTransaction()}; - - EXPECT_FALSE(user->hasStarredRelease(release.get())); - } - - { - auto transaction {session.createUniqueTransaction()}; - - track.get().modify()->setRelease(release.get()); - user.get().modify()->starRelease(release.get()); - } - - { - auto transaction {session.createSharedTransaction()}; - - EXPECT_TRUE(user->hasStarredRelease(release.get())); - - bool hasMore {}; - auto releases {Release::getStarred(session, user.get(), {}, std::nullopt, hasMore)}; - ASSERT_EQ(releases.size(), 1); - EXPECT_EQ(releases.front()->getId(), release.getId()); - EXPECT_FALSE(hasMore); - } -} - -TEST_F(DatabaseFixture, SingleStarredTrack) -{ - ScopedTrack track {session, "MyTrack"}; - ScopedUser user {session, "MyUser"}; - - { - auto transaction {session.createUniqueTransaction()}; - - EXPECT_FALSE(user->hasStarredTrack(track.get())); - } - - { - auto transaction {session.createUniqueTransaction()}; - - user.get().modify()->starTrack(track.get()); - } - - { - auto transaction {session.createUniqueTransaction()}; - - EXPECT_TRUE(user->hasStarredTrack(track.get())); - - bool hasMore {}; - auto tracks {Track::getStarred(session, user.get(), {}, std::nullopt, hasMore)}; - ASSERT_EQ(tracks.size(), 1); - EXPECT_EQ(tracks.front()->getId(), track.getId()); - EXPECT_FALSE(hasMore); - } -} - TEST_F(DatabaseFixture, SingleTrackList) { ScopedUser user {session, "MyUser"}; diff --git a/src/libs/services/database/test/Release.cpp b/src/libs/services/database/test/Release.cpp index 801fd9bf..84f765f4 100644 --- a/src/libs/services/database/test/Release.cpp +++ b/src/libs/services/database/test/Release.cpp @@ -361,3 +361,36 @@ TEST_F(DatabaseFixture, MultiTracksSingleReleaseDate) } } +TEST_F(DatabaseFixture, SingleStarredRelease) +{ + ScopedRelease release {session, "MyRelease"}; + ScopedTrack track {session, "MyTrack"}; + ScopedUser user {session, "MyUser"}; + + { + auto transaction {session.createSharedTransaction()}; + + EXPECT_FALSE(user->isStarred(release.get())); + } + + { + auto transaction {session.createUniqueTransaction()}; + + track.get().modify()->setRelease(release.get()); + user.get().modify()->star(release.get()); + } + + { + auto transaction {session.createSharedTransaction()}; + + EXPECT_TRUE(user->isStarred(release.get())); + + bool hasMore {}; + auto releases {Release::getStarred(session, user.get(), {}, std::nullopt, hasMore)}; + ASSERT_EQ(releases.size(), 1); + EXPECT_EQ(releases.front()->getId(), release.getId()); + EXPECT_FALSE(hasMore); + } +} + + diff --git a/src/libs/services/database/test/Track.cpp b/src/libs/services/database/test/Track.cpp index bdc54855..a4b22d61 100644 --- a/src/libs/services/database/test/Track.cpp +++ b/src/libs/services/database/test/Track.cpp @@ -115,5 +115,36 @@ TEST_F(DatabaseFixture, SingleTrackDate) } } +TEST_F(DatabaseFixture, SingleStarredTrack) +{ + ScopedTrack track {session, "MyTrack"}; + ScopedUser user {session, "MyUser"}; + + { + auto transaction {session.createUniqueTransaction()}; + + EXPECT_FALSE(user->isStarred(track.get())); + } + + { + auto transaction {session.createUniqueTransaction()}; + + user.get().modify()->star(track.get()); + } + + { + auto transaction {session.createUniqueTransaction()}; + + EXPECT_TRUE(user->isStarred(track.get())); + + bool hasMore {}; + auto tracks {Track::getStarred(session, user.get(), {}, std::nullopt, hasMore)}; + ASSERT_EQ(tracks.size(), 1); + EXPECT_EQ(tracks.front()->getId(), track.getId()); + EXPECT_FALSE(hasMore); + } +} + + diff --git a/src/libs/services/feedback/CMakeLists.txt b/src/libs/services/feedback/CMakeLists.txt new file mode 100644 index 00000000..3049f60f --- /dev/null +++ b/src/libs/services/feedback/CMakeLists.txt @@ -0,0 +1,19 @@ + +add_library(lmsfeedback SHARED + impl/FeedbackService.cpp + ) + +target_include_directories(lmsfeedback INTERFACE + include + ) + +target_include_directories(lmsfeedback PRIVATE + include + ) + +target_link_libraries(lmsfeedback PRIVATE + lmsdatabase + ) + +install(TARGETS lmsfeedback DESTINATION lib) + diff --git a/src/libs/services/feedback/impl/FeedbackService.cpp b/src/libs/services/feedback/impl/FeedbackService.cpp new file mode 100644 index 00000000..d4c0a04f --- /dev/null +++ b/src/libs/services/feedback/impl/FeedbackService.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2021 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 . + */ + +#include "FeedbackService.hpp" +#include "services/database/Db.hpp" +#include "services/database/Artist.hpp" +#include "services/database/Release.hpp" +#include "services/database/Session.hpp" +#include "services/database/Track.hpp" +#include "services/database/User.hpp" + +namespace +{ + using namespace Database; + + void + exec(Db& db, UserId userId, ArtistId artistId, std::function func) + { + Session& dbSession {db.getTLSSession()}; + auto transaction {dbSession.createSharedTransaction()}; + + Database::User::pointer user {Database::User::getById(dbSession, userId)}; + if (!user) + return; + + Database::Artist::pointer artist {Database::Artist::getById(dbSession, artistId)}; + if (!artist) + return; + + func(user, artist); + } + + void + exec(Db& db, UserId userId, ReleaseId releaseId, std::function func) + { + Session& dbSession {db.getTLSSession()}; + auto transaction {dbSession.createSharedTransaction()}; + + Database::User::pointer user {Database::User::getById(dbSession, userId)}; + if (!user) + return; + + Database::Release::pointer release {Database::Release::getById(dbSession, releaseId)}; + if (!release) + return; + + func(user, release); + } + + void + exec(Db& db, UserId userId, TrackId trackId, std::function func) + { + Session& dbSession {db.getTLSSession()}; + auto transaction {dbSession.createSharedTransaction()}; + + Database::User::pointer user {Database::User::getById(dbSession, userId)}; + if (!user) + return; + + Database::Track::pointer track {Database::Track::getById(dbSession, trackId)}; + if (!track) + return; + + func(user, track); + } +} + +namespace Feedback +{ + std::unique_ptr + createFeedbackService(Database::Db& db) + { + return std::make_unique(db); + } + + FeedbackService::FeedbackService(Database::Db& db) + : _db {db} + { + } + + void + FeedbackService::star(Database::UserId userId, Database::ArtistId artistId) + { + starObject(userId, artistId); + } + + void + FeedbackService::unstar(Database::UserId userId, Database::ArtistId artistId) + { + unstarObject(userId, artistId); + } + + bool + FeedbackService::isStarred(Database::UserId userId, Database::ArtistId artistId) + { + return isObjectStarred(userId, artistId); + } + + void + FeedbackService::star(Database::UserId userId, Database::ReleaseId releaseId) + { + starObject(userId, releaseId); + } + + void + FeedbackService::unstar(Database::UserId userId, Database::ReleaseId releaseId) + { + unstarObject(userId, releaseId); + } + + bool + FeedbackService::isStarred(Database::UserId userId, Database::ReleaseId releaseId) + { + return isObjectStarred(userId, releaseId); + } + + void + FeedbackService::star(Database::UserId userId, Database::TrackId trackId) + { + starObject(userId, trackId); + } + + void + FeedbackService::unstar(Database::UserId userId, Database::TrackId trackId) + { + unstarObject(userId, trackId); + } + + bool + FeedbackService::isStarred(Database::UserId userId, Database::TrackId trackId) + { + return isObjectStarred(userId, trackId); + } + + template + void + FeedbackService::starObject(Database::UserId userId, DatabaseId objectId) + { + exec(_db, userId, objectId, [](Database::User::pointer user, auto object) + { + user.modify()->star(object); + }); + } + + template + void + FeedbackService::unstarObject(Database::UserId userId, DatabaseId objectId) + { + exec(_db, userId, objectId, [](Database::User::pointer user, auto object) + { + user.modify()->unstar(object); + }); + } + + template + bool + FeedbackService::isObjectStarred(Database::UserId userId, DatabaseId objectId) + { + bool res {}; + exec(_db, userId, objectId, [&res](Database::User::pointer user, auto object) + { + res = user->isStarred(object); + }); + return res; + } +} // ns Feedback + diff --git a/src/libs/services/feedback/impl/FeedbackService.hpp b/src/libs/services/feedback/impl/FeedbackService.hpp new file mode 100644 index 00000000..c2b37b13 --- /dev/null +++ b/src/libs/services/feedback/impl/FeedbackService.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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 . + */ + +#pragma once + +#include "services/feedback/IFeedbackService.hpp" + +namespace Database +{ + class Db; +} + +namespace Feedback +{ + class FeedbackService : public IFeedbackService + { + public: + FeedbackService(Database::Db& db); + + private: + void star(Database::UserId userId, Database::ArtistId artistId) override; + void unstar(Database::UserId userId, Database::ArtistId artistId) override; + bool isStarred(Database::UserId userId, Database::ArtistId artistId) override; + + void star(Database::UserId userId, Database::ReleaseId releaseId) override; + void unstar(Database::UserId userId, Database::ReleaseId releaseId) override; + bool isStarred(Database::UserId userId, Database::ReleaseId artistId) override; + + void star(Database::UserId userId, Database::TrackId trackId) override; + void unstar(Database::UserId userId, Database::TrackId trackId) override; + bool isStarred(Database::UserId userId, Database::TrackId trackId) override; + + template + void starObject(Database::UserId userId, DatabaseId objectId); + template + void unstarObject(Database::UserId userId, DatabaseId objectId); + template + bool isObjectStarred(Database::UserId userId, DatabaseId objectId); + + Database::Db& _db; + }; +} // ns Feedback + diff --git a/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp b/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp new file mode 100644 index 00000000..67b89d62 --- /dev/null +++ b/src/libs/services/feedback/include/services/feedback/IFeedbackService.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 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 . + */ + +#pragma once + +#include "services/database/Types.hpp" + +namespace Database +{ + class Db; +} + +namespace Feedback +{ + class IFeedbackService + { + public: + virtual ~IFeedbackService() = default; + + virtual void star(Database::UserId userId, Database::ArtistId artistId) = 0; + virtual void unstar(Database::UserId userId, Database::ArtistId artistId) = 0; + virtual bool isStarred(Database::UserId userId, Database::ArtistId artistId) = 0; + + virtual void star(Database::UserId userId, Database::ReleaseId releaseId) = 0; + virtual void unstar(Database::UserId userId, Database::ReleaseId releaseId) = 0; + virtual bool isStarred(Database::UserId userId, Database::ReleaseId artistId) = 0; + + virtual void star(Database::UserId userId, Database::TrackId trackId) = 0; + virtual void unstar(Database::UserId userId, Database::TrackId trackId) = 0; + virtual bool isStarred(Database::UserId userId, Database::TrackId artistId) = 0; + }; + + std::unique_ptr createFeedbackService(Database::Db& db); +} // ns Feedback + diff --git a/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp b/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp index af60143e..530a946e 100644 --- a/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp +++ b/src/libs/services/scanner/include/services/scanner/ScannerStats.hpp @@ -26,8 +26,8 @@ #include "services/database/Types.hpp" -namespace Scanner { - +namespace Scanner +{ enum class ScanErrorType { CannotReadFile, // cannot read file @@ -102,6 +102,5 @@ namespace Scanner { std::size_t nbFiles() const; std::size_t nbChanges() const; }; - -} +} // namespace Scanner diff --git a/src/libs/subsonic/CMakeLists.txt b/src/libs/subsonic/CMakeLists.txt index d4f4b985..c36bf1ba 100644 --- a/src/libs/subsonic/CMakeLists.txt +++ b/src/libs/subsonic/CMakeLists.txt @@ -20,6 +20,7 @@ target_link_libraries(lmssubsonic PRIVATE lmsauth lmsav lmsdatabase + lmsfeedback lmsrecommendation lmsscanner lmsscrobbling diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp index 6778f4b0..dc6440f9 100644 --- a/src/libs/subsonic/impl/SubsonicResource.cpp +++ b/src/libs/subsonic/impl/SubsonicResource.cpp @@ -37,6 +37,7 @@ #include "services/database/TrackBookmark.hpp" #include "services/database/TrackList.hpp" #include "services/database/User.hpp" +#include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "services/scrobbling/IScrobblingService.hpp" #include "services/cover/ICoverService.hpp" @@ -322,7 +323,7 @@ trackToResponseNode(const Track::pointer& track, Session& dbSession, const User: trackResponse.setAttribute("type", "music"); trackResponse.setAttribute("created", dateTimeToCreatedString(track->getLastWritten())); - if (user->hasStarredTrack(track)) + if (Service::get()->isStarred(user->getId(), track->getId())) trackResponse.setAttribute("starred", reportedStarredDate); // Report the first GENRE for this track @@ -413,7 +414,7 @@ releaseToResponseNode(const Release::pointer& release, Session& dbSession, const } } - if (user->hasStarredRelease(release)) + if (Service::get()->isStarred(user->getId(), release->getId())) albumNode.setAttribute("starred", reportedStarredDate); return albumNode; @@ -431,7 +432,7 @@ artistToResponseNode(const User::pointer& user, const Artist::pointer& artist, b if (id3) artistNode.setAttribute("albumCount", artist->getReleaseCount()); - if (user->hasStarredArtist(artist)) + if (Service::get()->isStarred(user->getId(), artist->getId())) artistNode.setAttribute("starred", reportedStarredDate); return artistNode; @@ -1471,7 +1472,7 @@ handleStarRequest(RequestContext& context) if (!artist) continue; - user.modify()->starArtist(artist); + Service::get()->star(user->getId(), artist->getId()); } for (const ReleaseId id : params.releaseIds) @@ -1480,7 +1481,7 @@ handleStarRequest(RequestContext& context) if (!release) continue; - user.modify()->starRelease(release); + Service::get()->star(user->getId(), release->getId()); } for (const TrackId id : params.trackIds) @@ -1489,7 +1490,7 @@ handleStarRequest(RequestContext& context) if (!track) continue; - user.modify()->starTrack(track); + Service::get()->star(user->getId(), track->getId()); } return Response::createOkResponse(context.serverProtocolVersion); @@ -1527,7 +1528,7 @@ handleUnstarRequest(RequestContext& context) if (!artist) continue; - user.modify()->unstarArtist(artist); + Service::get()->unstar(user->getId(), artist->getId()); } for (const ReleaseId id : params.releaseIds) @@ -1536,7 +1537,7 @@ handleUnstarRequest(RequestContext& context) if (!release) continue; - user.modify()->unstarRelease(release); + Service::get()->unstar(user->getId(), release->getId()); } for (const TrackId id : params.trackIds) @@ -1545,7 +1546,7 @@ handleUnstarRequest(RequestContext& context) if (!track) continue; - user.modify()->unstarTrack(track); + Service::get()->unstar(user->getId(), track->getId()); } diff --git a/src/lms/CMakeLists.txt b/src/lms/CMakeLists.txt index 33dad4b1..83bead84 100644 --- a/src/lms/CMakeLists.txt +++ b/src/lms/CMakeLists.txt @@ -52,6 +52,7 @@ target_link_libraries(lms PRIVATE lmsav lmsauth lmsdatabase + lmsfeedback lmsrecommendation lmsscanner lmsscrobbling diff --git a/src/lms/main.cpp b/src/lms/main.cpp index e82bc6a3..8329f6d6 100644 --- a/src/lms/main.cpp +++ b/src/lms/main.cpp @@ -31,6 +31,7 @@ #include "services/cover/ICoverService.hpp" #include "services/database/Db.hpp" #include "services/database/Session.hpp" +#include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "services/scanner/IScannerService.hpp" #include "services/scrobbling/IScrobblingService.hpp" @@ -238,7 +239,7 @@ int main(int argc, char* argv[]) // Service initialization order is important (reverse-order for deinit) Service childProcessManagerService {createChildProcessManager(ioContext)}; - + Service feedbackService {Feedback::createFeedbackService(database)}; Service authTokenService; Service authPasswordService; Service authEnvService; diff --git a/src/lms/ui/PlayQueue.cpp b/src/lms/ui/PlayQueue.cpp index 32ab87e7..fd4f42b2 100644 --- a/src/lms/ui/PlayQueue.cpp +++ b/src/lms/ui/PlayQueue.cpp @@ -28,6 +28,7 @@ #include "services/database/Track.hpp" #include "services/database/TrackList.hpp" #include "services/database/User.hpp" +#include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "utils/Logger.hpp" #include "utils/Random.hpp" @@ -488,27 +489,14 @@ PlayQueue::addEntry(const Database::TrackListEntry::pointer& tracklistEntry) { Wt::WPopupMenu* popup {LmsApp->createPopupMenu()}; - bool isStarred {}; - { - auto transaction {LmsApp->getDbSession().createSharedTransaction()}; - - if (auto track {Database::Track::getById(LmsApp->getDbSession(), trackId)}) - isStarred = LmsApp->getUser()->hasStarredTrack(track); - } - + const bool isStarred {Service::get()->isStarred(LmsApp->getUserId(), trackId)}; popup->addItem(Wt::WString::tr(isStarred ? "Lms.Explore.unstar" : "Lms.Explore.star")) ->triggered().connect(moreBtn, [=] { - auto transaction {LmsApp->getDbSession().createUniqueTransaction()}; - - auto track {Database::Track::getById(LmsApp->getDbSession(), trackId)}; - if (!track) - return; - if (isStarred) - LmsApp->getUser().modify()->unstarTrack(track); + Service::get()->unstar(LmsApp->getUserId(), trackId); else - LmsApp->getUser().modify()->starTrack(track); + Service::get()->star(LmsApp->getUserId(), trackId); }); popup->addItem(Wt::WString::tr("Lms.Explore.download")) ->setLink(Wt::WLink {std::make_unique(trackId)}); diff --git a/src/lms/ui/explore/ArtistView.cpp b/src/lms/ui/explore/ArtistView.cpp index f66337ba..e4c65a01 100644 --- a/src/lms/ui/explore/ArtistView.cpp +++ b/src/lms/ui/explore/ArtistView.cpp @@ -32,6 +32,7 @@ #include "services/database/Session.hpp" #include "services/database/Track.hpp" #include "services/database/User.hpp" +#include "services/feedback/IFeedbackService.hpp" #include "services/recommendation/IRecommendationService.hpp" #include "utils/Logger.hpp" #include "utils/String.hpp" @@ -165,26 +166,14 @@ Artist::refreshView() artistsAction.emit(PlayQueueAction::PlayLast, {_artistId}); }); - bool isStarred {}; - { - auto transaction {LmsApp->getDbSession().createSharedTransaction()}; - - if (auto artist {Database::Artist::getById(LmsApp->getDbSession(), *artistId)}) - isStarred = LmsApp->getUser()->hasStarredArtist(artist); - } + const bool isStarred {Service::get()->isStarred(LmsApp->getUserId(), _artistId)}; popup->addItem(Wt::WString::tr(isStarred ? "Lms.Explore.unstar" : "Lms.Explore.star")) ->triggered().connect(this, [=] { - auto transaction {LmsApp->getDbSession().createUniqueTransaction()}; - - auto artist {Database::Artist::getById(LmsApp->getDbSession(), *artistId)}; - if (!artist) - return; - if (isStarred) - LmsApp->getUser().modify()->unstarArtist(artist); + Service::get()->unstar(LmsApp->getUserId(), _artistId); else - LmsApp->getUser().modify()->starArtist(artist); + Service::get()->star(LmsApp->getUserId(), _artistId); }); popup->addItem(Wt::WString::tr("Lms.Explore.download")) ->setLink(Wt::WLink {std::make_unique(*artistId)}); diff --git a/src/lms/ui/explore/ReleasePopup.cpp b/src/lms/ui/explore/ReleasePopup.cpp index 6d924c43..cc970b0f 100644 --- a/src/lms/ui/explore/ReleasePopup.cpp +++ b/src/lms/ui/explore/ReleasePopup.cpp @@ -24,7 +24,9 @@ #include "services/database/Release.hpp" #include "services/database/Session.hpp" #include "services/database/User.hpp" +#include "services/feedback/IFeedbackService.hpp" #include "resource/DownloadResource.hpp" +#include "utils/Service.hpp" #include "LmsApplication.hpp" namespace UserInterface @@ -47,27 +49,14 @@ namespace UserInterface releasesAction.emit(PlayQueueAction::PlayLast, {releaseId}); }); - bool isStarred {}; - { - auto transaction {LmsApp->getDbSession().createSharedTransaction()}; - - if (auto release {Database::Release::getById(LmsApp->getDbSession(), releaseId)}) - isStarred = LmsApp->getUser()->hasStarredRelease(release); - } - + const bool isStarred {Service::get()->isStarred(LmsApp->getUserId(), releaseId)}; popup->addItem(Wt::WString::tr(isStarred ? "Lms.Explore.unstar" : "Lms.Explore.star")) ->triggered().connect(&target, [=] { - auto transaction {LmsApp->getDbSession().createUniqueTransaction()}; - - auto release {Database::Release::getById(LmsApp->getDbSession(), releaseId)}; - if (!release) - return; - if (isStarred) - LmsApp->getUser().modify()->unstarRelease(release); + Service::get()->unstar(LmsApp->getUserId(), releaseId); else - LmsApp->getUser().modify()->starRelease(release); + Service::get()->star(LmsApp->getUserId(), releaseId); }); popup->addItem(Wt::WString::tr("Lms.Explore.download")) ->setLink(Wt::WLink {std::make_unique(releaseId)}); diff --git a/src/lms/ui/explore/TrackPopup.cpp b/src/lms/ui/explore/TrackPopup.cpp index d1b1bdea..f95e5825 100644 --- a/src/lms/ui/explore/TrackPopup.cpp +++ b/src/lms/ui/explore/TrackPopup.cpp @@ -24,6 +24,8 @@ #include "services/database/Session.hpp" #include "services/database/Track.hpp" #include "services/database/User.hpp" +#include "services/feedback/IFeedbackService.hpp" +#include "utils/Service.hpp" #include "resource/DownloadResource.hpp" #include "LmsApplication.hpp" @@ -42,13 +44,7 @@ namespace UserInterface tracksAction.emit(PlayQueueAction::PlayLast, {trackId}); }); - bool isStarred {}; - { - auto transaction {LmsApp->getDbSession().createSharedTransaction()}; - - if (auto track {Database::Track::getById(LmsApp->getDbSession(), trackId)}) - isStarred = LmsApp->getUser()->hasStarredTrack(track); - } + bool isStarred {Service::get()->isStarred(LmsApp->getUserId(), trackId)}; popup->addItem(Wt::WString::tr(isStarred ? "Lms.Explore.unstar" : "Lms.Explore.star")) ->triggered().connect(&target, [=] { @@ -59,9 +55,9 @@ namespace UserInterface return; if (isStarred) - LmsApp->getUser().modify()->unstarTrack(track); + Service::get()->unstar(LmsApp->getUserId(), trackId); else - LmsApp->getUser().modify()->starTrack(track); + Service::get()->star(LmsApp->getUserId(), trackId); }); popup->addItem(Wt::WString::tr("Lms.Explore.download")) ->setLink(Wt::WLink {std::make_unique(trackId)});