Implemented Subsonic's user rating for tracks, albums and artists, fixes #511
This commit is contained in:
@@ -206,7 +206,7 @@ namespace lms::api::subsonic
|
||||
// Media annotation
|
||||
{ "/star", { handleStarRequest } },
|
||||
{ "/unstar", { handleUnstarRequest } },
|
||||
{ "/setRating", { handleNotImplemented } },
|
||||
{ "/setRating", { handleSetRating } },
|
||||
{ "/scrobble", { handleScrobble } },
|
||||
|
||||
// Sharing
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "MediaAnnotation.hpp"
|
||||
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "core/Service.hpp"
|
||||
@@ -77,6 +78,37 @@ namespace lms::api::subsonic
|
||||
return res ? res->getId() : ReleaseId{};
|
||||
}
|
||||
|
||||
struct RatingParameters
|
||||
{
|
||||
std::variant<ArtistId, ReleaseId, TrackId, DirectoryId> id;
|
||||
std::optional<Rating> rating;
|
||||
};
|
||||
|
||||
RatingParameters getRatingParameters(const Wt::Http::ParameterMap& parameters)
|
||||
{
|
||||
RatingParameters res;
|
||||
|
||||
if (const auto artistId{ getParameterAs<ArtistId>(parameters, "id") })
|
||||
res.id = *artistId;
|
||||
else if (const auto releaseId{ getParameterAs<ReleaseId>(parameters, "id") })
|
||||
res.id = *releaseId;
|
||||
else if (const auto trackId{ getParameterAs<TrackId>(parameters, "id") })
|
||||
res.id = *trackId;
|
||||
else if (const auto directoryId{ getParameterAs<DirectoryId>(parameters, "id") })
|
||||
res.id = *directoryId;
|
||||
else
|
||||
throw RequiredParameterMissingError{ "id" };
|
||||
|
||||
const int rating = getMandatoryParameterAs<int>(parameters, "rating"); // The rating between 1 and 5 (inclusive), or 0 to remove the rating
|
||||
if (rating < 0 || rating > 5)
|
||||
throw BadParameterGenericError{ "rating must be 0 or in range 1-5" };
|
||||
|
||||
if (rating > 0)
|
||||
res.rating = rating;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Response handleStarRequest(RequestContext& context)
|
||||
@@ -103,7 +135,7 @@ namespace lms::api::subsonic
|
||||
|
||||
Response handleUnstarRequest(RequestContext& context)
|
||||
{
|
||||
StarParameters params{ getStarParameters(context.parameters) };
|
||||
const StarParameters params{ getStarParameters(context.parameters) };
|
||||
|
||||
for (const DirectoryId id : params.directoryIds)
|
||||
{
|
||||
@@ -123,6 +155,25 @@ namespace lms::api::subsonic
|
||||
return Response::createOkResponse(context.serverProtocolVersion);
|
||||
}
|
||||
|
||||
Response handleSetRating(RequestContext& context)
|
||||
{
|
||||
const RatingParameters params{ getRatingParameters(context.parameters) };
|
||||
|
||||
if (const ArtistId * artistId{ std::get_if<ArtistId>(¶ms.id) })
|
||||
core::Service<feedback::IFeedbackService>::get()->setRating(context.user->getId(), *artistId, params.rating);
|
||||
else if (const DirectoryId * directoryId{ std::get_if<DirectoryId>(¶ms.id) })
|
||||
{
|
||||
if (const ReleaseId releaseId{ getReleaseFromDirectory(context.dbSession, *directoryId) }; releaseId.isValid())
|
||||
core::Service<feedback::IFeedbackService>::get()->setRating(context.user->getId(), releaseId, params.rating);
|
||||
}
|
||||
else if (const ReleaseId * releaseId{ std::get_if<ReleaseId>(¶ms.id) })
|
||||
core::Service<feedback::IFeedbackService>::get()->setRating(context.user->getId(), *releaseId, params.rating);
|
||||
else if (const TrackId * trackId{ std::get_if<TrackId>(¶ms.id) })
|
||||
core::Service<feedback::IFeedbackService>::get()->setRating(context.user->getId(), *trackId, params.rating);
|
||||
|
||||
return Response::createOkResponse(context.serverProtocolVersion);
|
||||
}
|
||||
|
||||
Response handleScrobble(RequestContext& context)
|
||||
{
|
||||
const std::vector<TrackId> ids{ getMandatoryMultiParametersAs<TrackId>(context.parameters, "id") };
|
||||
|
||||
@@ -26,5 +26,6 @@ namespace lms::api::subsonic
|
||||
{
|
||||
Response handleStarRequest(RequestContext& context);
|
||||
Response handleUnstarRequest(RequestContext& context);
|
||||
Response handleSetRating(RequestContext& context);
|
||||
Response handleScrobble(RequestContext& context);
|
||||
} // namespace lms::api::subsonic
|
||||
@@ -116,6 +116,10 @@ namespace lms::api::subsonic
|
||||
if (const Wt::WDateTime dateTime{ core::Service<feedback::IFeedbackService>::get()->getStarredDateTime(context.user->getId(), release->getId()) }; dateTime.isValid())
|
||||
albumNode.setAttribute("starred", core::stringUtils::toISO8601String(dateTime));
|
||||
|
||||
// Always report user rating, even if legacy API only specified it for directories
|
||||
if (const auto rating{ core::Service<feedback::IFeedbackService>::get()->getRating(context.user->getId(), release->getId()) })
|
||||
albumNode.setAttribute("userRating", *rating);
|
||||
|
||||
if (!context.enableOpenSubsonic)
|
||||
return albumNode;
|
||||
|
||||
|
||||
@@ -103,6 +103,9 @@ namespace lms::api::subsonic
|
||||
if (const Wt::WDateTime dateTime{ core::Service<feedback::IFeedbackService>::get()->getStarredDateTime(context.user->getId(), artist->getId()) }; dateTime.isValid())
|
||||
artistNode.setAttribute("starred", core::stringUtils::toISO8601String(dateTime));
|
||||
|
||||
if (const auto rating{ core::Service<feedback::IFeedbackService>::get()->getRating(context.user->getId(), artist->getId()) })
|
||||
artistNode.setAttribute("userRating", *rating);
|
||||
|
||||
// OpenSubsonic specific fields (must always be set)
|
||||
if (context.enableOpenSubsonic)
|
||||
{
|
||||
|
||||
@@ -133,6 +133,8 @@ namespace lms::api::subsonic
|
||||
trackResponse.setAttribute("type", "music");
|
||||
trackResponse.setAttribute("created", core::stringUtils::toISO8601String(track->getLastWritten()));
|
||||
trackResponse.setAttribute("contentType", av::getMimeType(track->getAbsoluteFilePath().extension()));
|
||||
if (const auto rating{ core::Service<feedback::IFeedbackService>::get()->getRating(context.user->getId(), track->getId()) })
|
||||
trackResponse.setAttribute("userRating", *rating);
|
||||
|
||||
if (const Wt::WDateTime dateTime{ core::Service<feedback::IFeedbackService>::get()->getStarredDateTime(context.user->getId(), track->getId()) }; dateTime.isValid())
|
||||
trackResponse.setAttribute("starred", core::stringUtils::toISO8601String(dateTime));
|
||||
|
||||
Reference in New Issue
Block a user