Fixed bad json musicBrainzId field in getArtistInfo2, fixes #497

This commit is contained in:
emeric
2024-07-28 14:42:16 +02:00
parent 2a02c6ede6
commit 9a91a2e080
16 changed files with 110 additions and 72 deletions
@@ -27,6 +27,7 @@
#include "ClientInfo.hpp" #include "ClientInfo.hpp"
#include "ProtocolVersion.hpp" #include "ProtocolVersion.hpp"
#include "SubsonicResponse.hpp"
namespace lms::db namespace lms::db
{ {
@@ -43,6 +44,7 @@ namespace lms::api::subsonic
const db::ObjectPtr<db::User> user; const db::ObjectPtr<db::User> user;
ClientInfo clientInfo; ClientInfo clientInfo;
ProtocolVersion serverProtocolVersion; ProtocolVersion serverProtocolVersion;
ResponseFormat responseFormat;
bool enableOpenSubsonic{ true }; bool enableOpenSubsonic{ true };
bool enableDefaultCover{}; bool enableDefaultCover{};
}; };
+11 -1
View File
@@ -411,6 +411,7 @@ namespace lms::api::subsonic
const db::UserId userId{ authenticateUser(request, clientInfo) }; const db::UserId userId{ authenticateUser(request, clientInfo) };
bool enableOpenSubsonic{ _openSubsonicDisabledClients.find(clientInfo.name) == std::cend(_openSubsonicDisabledClients) }; bool enableOpenSubsonic{ _openSubsonicDisabledClients.find(clientInfo.name) == std::cend(_openSubsonicDisabledClients) };
bool enableDefaultCover{ _defaultCoverClients.find(clientInfo.name) != std::cend(_openSubsonicDisabledClients) }; bool enableDefaultCover{ _defaultCoverClients.find(clientInfo.name) != std::cend(_openSubsonicDisabledClients) };
const ResponseFormat format{ getParameterAs<std::string>(request.getParameterMap(), "f").value_or("xml") == "json" ? ResponseFormat::json : ResponseFormat::xml };
db::User::pointer user; db::User::pointer user;
{ {
@@ -422,7 +423,16 @@ namespace lms::api::subsonic
throw UserNotAuthorizedError{}; throw UserNotAuthorizedError{};
} }
return { parameters, _db.getTLSSession(), user, clientInfo, getServerProtocolVersion(clientInfo.name), enableOpenSubsonic, enableDefaultCover }; return RequestContext{
.parameters = parameters,
.dbSession = _db.getTLSSession(),
.user = user,
.clientInfo = clientInfo,
.serverProtocolVersion = getServerProtocolVersion(clientInfo.name),
.responseFormat = format,
.enableOpenSubsonic = enableOpenSubsonic,
.enableDefaultCover = enableDefaultCover
};
} }
db::UserId SubsonicResource::authenticateUser(const Wt::Http::Request& request, const ClientInfo& clientInfo) db::UserId SubsonicResource::authenticateUser(const Wt::Http::Request& request, const ClientInfo& clientInfo)
+41 -51
View File
@@ -266,74 +266,64 @@ namespace lms::api::subsonic
first = false; first = false;
} }
if (node._value) // Values are handled manually (using attributes) in json format
assert(!node._value);
for (const auto& [key, childNode] : node._children)
{ {
if (!first) if (!first)
os << ','; os << ',';
os << "\"value\":"; serializeEscapedString(os, key.str());
serializeValue(os, *node._value); os << ':';
serializeNode(os, childNode);
first = false; first = false;
} }
else
for (const auto& [key, childArrayNodes] : node._childrenArrays)
{ {
for (const auto& [key, childNode] : node._children) if (!first)
{ os << ',';
if (!first)
os << ','; serializeEscapedString(os, key.str());
os << ":[";
bool firstChild{ true };
for (const Response::Node& childNode : childArrayNodes)
{
if (!firstChild)
os << ",";
serializeEscapedString(os, key.str());
os << ':';
serializeNode(os, childNode); serializeNode(os, childNode);
firstChild = false;
first = false;
} }
os << ']';
for (const auto& [key, childArrayNodes] : node._childrenArrays) first = false;
}
for (const auto& [key, childValues] : node._childrenValues)
{
if (!first)
os << ',';
serializeEscapedString(os, key.str());
os << ":[";
bool firstChild{ true };
for (const Node::ValueType& childValue : childValues)
{ {
if (!first) if (!firstChild)
os << ','; os << ",";
serializeEscapedString(os, key.str()); serializeValue(os, childValue);
os << ":[";
bool firstChild{ true }; firstChild = false;
for (const Response::Node& childNode : childArrayNodes)
{
if (!firstChild)
os << ",";
serializeNode(os, childNode);
firstChild = false;
}
os << ']';
first = false;
} }
os << ']';
for (const auto& [key, childValues] : node._childrenValues) first = false;
{
if (!first)
os << ',';
serializeEscapedString(os, key.str());
os << ":[";
bool firstChild{ true };
for (const Node::ValueType& childValue : childValues)
{
if (!firstChild)
os << ",";
serializeValue(os, childValue);
firstChild = false;
}
os << ']';
first = false;
}
} }
os << '}'; os << '}';
+1 -1
View File
@@ -27,7 +27,7 @@
#include "core/LiteralString.hpp" #include "core/LiteralString.hpp"
#include "RequestContext.hpp" #include "ProtocolVersion.hpp"
#include "SubsonicResponseAllocator.hpp" #include "SubsonicResponseAllocator.hpp"
namespace lms::api::subsonic namespace lms::api::subsonic
@@ -362,7 +362,7 @@ namespace lms::api::subsonic
const auto clusters{ clusterType->getClusters() }; const auto clusters{ clusterType->getClusters() };
for (const Cluster::pointer& cluster : clusters) for (const Cluster::pointer& cluster : clusters)
genresNode.addArrayChild("genre", createGenreNode(cluster)); genresNode.addArrayChild("genre", createGenreNode(context, cluster));
} }
return response; return response;
@@ -531,7 +531,17 @@ namespace lms::api::subsonic
std::optional<core::UUID> artistMBID{ artist->getMBID() }; std::optional<core::UUID> artistMBID{ artist->getMBID() };
if (artistMBID) if (artistMBID)
artistInfoNode.createChild("musicBrainzId").setValue(artistMBID->getAsString()); {
switch (context.responseFormat)
{
case ResponseFormat::json:
artistInfoNode.setAttribute("musicBrainzId", artistMBID->getAsString());
break;
case ResponseFormat::xml:
artistInfoNode.createChild("musicBrainzId").setValue(artistMBID->getAsString());
break;
}
}
} }
auto similarArtistsId{ core::Service<recommendation::IRecommendationService>::get()->getSimilarArtists(id, { TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist }, count) }; auto similarArtistsId{ core::Service<recommendation::IRecommendationService>::get()->getSimilarArtists(id, { TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist }, count) };
@@ -35,7 +35,7 @@ namespace lms::api::subsonic
throw RequestedDataNotFoundError{}; throw RequestedDataNotFoundError{};
Response response{ Response::createOkResponse(context.serverProtocolVersion) }; Response response{ Response::createOkResponse(context.serverProtocolVersion) };
response.addNode("user", createUserNode(user)); response.addNode("user", createUserNode(context, user));
return response; return response;
} }
@@ -47,7 +47,7 @@ namespace lms::api::subsonic
auto transaction{ context.dbSession.createReadTransaction() }; auto transaction{ context.dbSession.createReadTransaction() };
User::find(context.dbSession, User::FindParameters{}, [&](const User::pointer& user) { User::find(context.dbSession, User::FindParameters{}, [&](const User::pointer& user) {
usersNode.addArrayChild("user", createUserNode(user)); usersNode.addArrayChild("user", createUserNode(context, user));
}); });
return response; return response;
@@ -30,6 +30,7 @@
#include "services/feedback/IFeedbackService.hpp" #include "services/feedback/IFeedbackService.hpp"
#include "services/scrobbling/IScrobblingService.hpp" #include "services/scrobbling/IScrobblingService.hpp"
#include "RequestContext.hpp"
#include "SubsonicId.hpp" #include "SubsonicId.hpp"
#include "responses/Artist.hpp" #include "responses/Artist.hpp"
#include "responses/DiscTitle.hpp" #include "responses/DiscTitle.hpp"
@@ -33,5 +33,7 @@ namespace lms::db
namespace lms::api::subsonic namespace lms::api::subsonic
{ {
class RequestContext;
Response::Node createAlbumNode(RequestContext& context, const db::ObjectPtr<db::Release>& release, bool id3, const db::ObjectPtr<db::Directory>& directory = {}); Response::Node createAlbumNode(RequestContext& context, const db::ObjectPtr<db::Release>& release, bool id3, const db::ObjectPtr<db::Directory>& directory = {});
} }
@@ -29,6 +29,7 @@
#include "database/User.hpp" #include "database/User.hpp"
#include "services/feedback/IFeedbackService.hpp" #include "services/feedback/IFeedbackService.hpp"
#include "RequestContext.hpp"
#include "SubsonicId.hpp" #include "SubsonicId.hpp"
namespace lms::api::subsonic namespace lms::api::subsonic
@@ -36,6 +36,8 @@ namespace lms::db
namespace lms::api::subsonic namespace lms::api::subsonic
{ {
class RequestContext;
namespace utils namespace utils
{ {
std::string joinArtistNames(const std::vector<db::ObjectPtr<db::Artist>>& artists); std::string joinArtistNames(const std::vector<db::ObjectPtr<db::Artist>>& artists);
+12 -2
View File
@@ -21,13 +21,23 @@
#include "database/Cluster.hpp" #include "database/Cluster.hpp"
#include "RequestContext.hpp"
namespace lms::api::subsonic namespace lms::api::subsonic
{ {
Response::Node createGenreNode(const db::Cluster::pointer& cluster) Response::Node createGenreNode(RequestContext& context, const db::Cluster::pointer& cluster)
{ {
Response::Node clusterNode; Response::Node clusterNode;
clusterNode.setValue(cluster->getName()); switch (context.responseFormat)
{
case ResponseFormat::json:
clusterNode.setAttribute("value", cluster->getName());
break;
case ResponseFormat::xml:
clusterNode.setValue(cluster->getName());
break;
}
clusterNode.setAttribute("songCount", cluster->getTrackCount()); clusterNode.setAttribute("songCount", cluster->getTrackCount());
clusterNode.setAttribute("albumCount", cluster->getReleasesCount()); clusterNode.setAttribute("albumCount", cluster->getReleasesCount());
+4 -2
View File
@@ -30,5 +30,7 @@ namespace lms::db
namespace lms::api::subsonic namespace lms::api::subsonic
{ {
Response::Node createGenreNode(const db::ObjectPtr<db::Cluster>& cluster); class RequestContext;
}
Response::Node createGenreNode(RequestContext& context, const db::ObjectPtr<db::Cluster>& cluster);
} // namespace lms::api::subsonic
@@ -35,6 +35,7 @@
#include "services/feedback/IFeedbackService.hpp" #include "services/feedback/IFeedbackService.hpp"
#include "services/scrobbling/IScrobblingService.hpp" #include "services/scrobbling/IScrobblingService.hpp"
#include "RequestContext.hpp"
#include "SubsonicId.hpp" #include "SubsonicId.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "responses/Artist.hpp" #include "responses/Artist.hpp"
+3 -1
View File
@@ -32,5 +32,7 @@ namespace lms::db
namespace lms::api::subsonic namespace lms::api::subsonic
{ {
class RequestContext;
Response::Node createSongNode(RequestContext& context, const db::ObjectPtr<db::Track>& track, bool id3); Response::Node createSongNode(RequestContext& context, const db::ObjectPtr<db::Track>& track, bool id3);
} } // namespace lms::api::subsonic
+12 -9
View File
@@ -19,13 +19,15 @@
#include "responses/User.hpp" #include "responses/User.hpp"
#include "database/MediaLibrary.hpp"
#include "database/User.hpp" #include "database/User.hpp"
#include "RequestContext.hpp"
#include "SubsonicId.hpp"
namespace lms::api::subsonic namespace lms::api::subsonic
{ {
using namespace db; Response::Node createUserNode(RequestContext& context, const db::User::pointer& user)
Response::Node createUserNode(const User::pointer& user)
{ {
Response::Node userNode; Response::Node userNode;
@@ -38,14 +40,15 @@ namespace lms::api::subsonic
userNode.setAttribute("playlistRole", true); userNode.setAttribute("playlistRole", true);
userNode.setAttribute("coverArtRole", false); userNode.setAttribute("coverArtRole", false);
userNode.setAttribute("commentRole", false); userNode.setAttribute("commentRole", false);
userNode.setAttribute("podcastRole", false); userNode.setAttribute("podcastRole", false); // not supported
userNode.setAttribute("streamRole", true); userNode.setAttribute("streamRole", true);
userNode.setAttribute("jukeboxRole", false); userNode.setAttribute("jukeboxRole", false); // not supported
userNode.setAttribute("shareRole", false); userNode.setAttribute("shareRole", false); // not supported
Response::Node folder; // users can access all libraries
folder.setValue("0"); db::MediaLibrary::find(context.dbSession, [&](const db::MediaLibrary::pointer& library) {
userNode.addArrayChild("folder", std::move(folder)); userNode.addArrayValue("folder", idToString(library->getId()));
});
return userNode; return userNode;
} }
+3 -1
View File
@@ -30,5 +30,7 @@ namespace lms::db
namespace lms::api::subsonic namespace lms::api::subsonic
{ {
Response::Node createUserNode(const db::ObjectPtr<db::User>& user); class RequestContext;
Response::Node createUserNode(RequestContext& context, const db::ObjectPtr<db::User>& user);
} }