diff --git a/src/libs/subsonic/CMakeLists.txt b/src/libs/subsonic/CMakeLists.txt
index 89519d64..002bdfe6 100644
--- a/src/libs/subsonic/CMakeLists.txt
+++ b/src/libs/subsonic/CMakeLists.txt
@@ -28,11 +28,13 @@ add_library(lmssubsonic STATIC
impl/responses/Song.cpp
impl/responses/User.cpp
impl/CoverArtId.cpp
+ impl/RequestContext.cpp
impl/ResponseFormat.cpp
impl/ProtocolVersion.cpp
impl/ParameterParsing.cpp
impl/SubsonicId.cpp
impl/SubsonicResource.cpp
+ impl/SubsonicResourceConfig.cpp
impl/SubsonicResponse.cpp
)
diff --git a/src/libs/subsonic/impl/RequestContext.cpp b/src/libs/subsonic/impl/RequestContext.cpp
new file mode 100644
index 00000000..8f8c5283
--- /dev/null
+++ b/src/libs/subsonic/impl/RequestContext.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2025 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 "RequestContext.hpp"
+
+#include "ParameterParsing.hpp"
+#include "SubsonicResourceConfig.hpp"
+#include "SubsonicResponse.hpp"
+
+namespace lms::api::subsonic
+{
+ namespace
+ {
+ void checkProtocolVersion(ProtocolVersion client, ProtocolVersion server)
+ {
+ if (client.major > server.major)
+ throw ServerMustUpgradeError{};
+ if (client.major < server.major)
+ throw ClientMustUpgradeError{};
+ if (client.minor > server.minor)
+ throw ServerMustUpgradeError{};
+ if (client.minor == server.minor)
+ {
+ if (client.patch > server.patch)
+ throw ServerMustUpgradeError{};
+ }
+ }
+ } // namespace
+
+ RequestContext::RequestContext(const Wt::Http::Request& request, db::Session& dbSession, db::ObjectPtr user, const SubsonicResourceConfig& config)
+ : _request{ request }
+ , _dbSession{ dbSession }
+ , _user{ user }
+ , _config{ config }
+ , _clientName{ getMandatoryParameterAs(_request.getParameterMap(), "c") }
+ , _clientProtocolVersion{ getMandatoryParameterAs(_request.getParameterMap(), "v") }
+ , _responseFormat{ getParameterAs(request.getParameterMap(), "f").value_or("xml") == "json" ? ResponseFormat::json : ResponseFormat::xml }
+ , _serverProtocolVersion{ _config.serverProtocolVersionsByClient.contains(_clientName) ? _config.serverProtocolVersionsByClient.at(_clientName) : defaultServerProtocolVersion }
+ , _isOpenSubsonicEnabled{ !_config.openSubsonicDisabledClients.contains(_clientName) }
+ {
+ checkProtocolVersion(_clientProtocolVersion, _serverProtocolVersion);
+ }
+
+ RequestContext::~RequestContext() = default;
+
+ const RequestContext::ParameterMap& RequestContext::getParameters() const
+ {
+ return _request.getParameterMap();
+ }
+
+ std::istream& RequestContext::getBody() const
+ {
+ return _request.in();
+ }
+
+ db::Session& RequestContext::getDbSession()
+ {
+ return _dbSession;
+ }
+
+ db::ObjectPtr RequestContext::getUser() const
+ {
+ return _user;
+ }
+
+ std::string RequestContext::getClientIpAddr() const
+ {
+ return _request.clientAddress();
+ }
+
+ std::string_view RequestContext::getClientName() const
+ {
+ return _clientName;
+ }
+
+ ProtocolVersion RequestContext::getServerProtocolVersion() const
+ {
+ return _serverProtocolVersion;
+ }
+
+ ResponseFormat RequestContext::getResponseFormat() const
+ {
+ return _responseFormat;
+ }
+
+ bool RequestContext::isOpenSubsonicEnabled() const
+ {
+ return _isOpenSubsonicEnabled;
+ }
+
+} // namespace lms::api::subsonic
diff --git a/src/libs/subsonic/impl/RequestContext.hpp b/src/libs/subsonic/impl/RequestContext.hpp
index 1b80bf70..7e295756 100644
--- a/src/libs/subsonic/impl/RequestContext.hpp
+++ b/src/libs/subsonic/impl/RequestContext.hpp
@@ -19,15 +19,17 @@
#pragma once
+#include
#include
+#include
#include
#include "database/Object.hpp"
-#include "ClientInfo.hpp"
#include "ProtocolVersion.hpp"
#include "ResponseFormat.hpp"
+#include "SubsonicResourceConfig.hpp"
namespace lms::db
{
@@ -37,15 +39,41 @@ namespace lms::db
namespace lms::api::subsonic
{
- struct RequestContext
+ class RequestContext
{
- const Wt::Http::ParameterMap& parameters;
- db::Session& dbSession;
- db::ObjectPtr user;
- std::string clientIpAddr;
- ClientInfo clientInfo;
- ProtocolVersion serverProtocolVersion;
- ResponseFormat responseFormat;
- bool enableOpenSubsonic{ true };
+ public:
+ RequestContext(const Wt::Http::Request& request, db::Session& dbSession, db::ObjectPtr user, const SubsonicResourceConfig& config);
+ ~RequestContext();
+ RequestContext(const RequestContext&) = delete;
+ RequestContext& operator=(const RequestContext&) = delete;
+
+ using ParameterMap = Wt::Http::ParameterMap;
+
+ const ParameterMap& getParameters() const;
+ std::istream& getBody() const;
+
+ db::Session& getDbSession();
+ db::ObjectPtr getUser() const;
+
+ std::string getClientIpAddr() const;
+ std::string_view getClientName() const;
+
+ ProtocolVersion getServerProtocolVersion() const;
+ ResponseFormat getResponseFormat() const;
+ bool isOpenSubsonicEnabled() const;
+
+ private:
+ const Wt::Http::Request& _request;
+ db::Session& _dbSession;
+ db::ObjectPtr _user;
+ const SubsonicResourceConfig& _config;
+
+ const std::string _clientName;
+ const ProtocolVersion _clientProtocolVersion;
+ const ResponseFormat _responseFormat;
+
+ const ProtocolVersion _serverProtocolVersion;
+ const bool _isOpenSubsonicEnabled;
};
+
} // namespace lms::api::subsonic
diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp
index 60731a61..5a32166d 100644
--- a/src/libs/subsonic/impl/SubsonicResource.cpp
+++ b/src/libs/subsonic/impl/SubsonicResource.cpp
@@ -60,32 +60,6 @@ namespace lms::api::subsonic
namespace
{
- std::unordered_map readConfigProtocolVersions()
- {
- std::unordered_map res;
-
- core::Service::get()->visitStrings("api-subsonic-old-server-protocol-clients",
- [&](std::string_view client) {
- res.emplace(std::string{ client }, ProtocolVersion{ .major = 1, .minor = 12, .patch = 0 });
- },
- { "DSub" });
-
- return res;
- }
-
- std::unordered_set readOpenSubsonicDisabledClients()
- {
- std::unordered_set res;
-
- core::Service::get()->visitStrings("api-open-subsonic-disabled-clients",
- [&](std::string_view client) {
- res.emplace(std::string{ client });
- },
- { "DSub" });
-
- return res;
- }
-
std::string parameterMapToDebugString(const Wt::Http::ParameterMap& parameterMap)
{
constexpr std::string_view redactedStr{ "*REDACTED*" };
@@ -292,24 +266,10 @@ namespace lms::api::subsonic
throw UserNotAuthorizedError{};
}
-
- ClientInfo getClientInfo(const Wt::Http::Request& request)
- {
- const auto& parameters{ request.getParameterMap() };
- ClientInfo res;
-
- // Mandatory parameters
- res.name = getMandatoryParameterAs(parameters, "c");
- res.version = getMandatoryParameterAs(parameters, "v");
-
- return res;
- }
} // namespace
SubsonicResource::SubsonicResource(db::IDb& db)
- : _serverProtocolVersionsByClient{ readConfigProtocolVersions() }
- , _openSubsonicDisabledClients{ readOpenSubsonicDisabledClients() }
- , _supportUserPasswordAuthentication{ core::Service::get()->getBool("api-subsonic-support-user-password-auth", true) }
+ : _config{ readSubsonicResourceConfig(*core::Service::get()) }
, _db{ db }
{
}
@@ -334,21 +294,20 @@ namespace lms::api::subsonic
try
{
- // We need to parse client a soon as possible to make sure to answer with the right protocol version
- protocolVersion = getServerProtocolVersion(getMandatoryParameterAs(request.getParameterMap(), "c"));
- RequestContext requestContext{ buildRequestContext(request) };
-
- auto itEntryPoint{ requestEntryPoints.find(requestPath) };
- if (itEntryPoint != requestEntryPoints.end())
+ if (auto itEntryPoint{ requestEntryPoints.find(requestPath) }; itEntryPoint != requestEntryPoints.end())
{
LMS_SCOPED_TRACE_OVERVIEW("Subsonic", itEntryPoint->first);
+ db::User::pointer user;
if (itEntryPoint->second.authMode == AuthenticationMode::Authenticated)
{
- requestContext.user = getUserFromUserId(_db.getTLSSession(), authenticateUser(request));
- checkUserTypeIsAllowed(requestContext.user, itEntryPoint->second.allowedUserTypes);
+ user = getUserFromUserId(_db.getTLSSession(), authenticateUser(request));
+ checkUserTypeIsAllowed(user, itEntryPoint->second.allowedUserTypes);
}
+ RequestContext requestContext{ request, _db.getTLSSession(), user, _config };
+ protocolVersion = requestContext.getServerProtocolVersion();
+
const Response resp{ [&] {
LMS_SCOPED_TRACE_DETAILED("Subsonic", "HandleRequest");
return itEntryPoint->second.func(requestContext);
@@ -372,8 +331,12 @@ namespace lms::api::subsonic
// Media retrieval endpoints are always authenticated
// Optim: no need to reauth user for each continuation
+ db::User::pointer user;
if (!request.continuation())
- requestContext.user = getUserFromUserId(_db.getTLSSession(), authenticateUser(request));
+ user = getUserFromUserId(_db.getTLSSession(), authenticateUser(request));
+
+ RequestContext requestContext{ request, _db.getTLSSession(), user, _config };
+ protocolVersion = requestContext.getServerProtocolVersion();
itStreamHandler->second(requestContext, request, response);
LMS_LOG(API_SUBSONIC, DEBUG, "Request " << requestId << " '" << requestPath << "' handled!");
@@ -397,49 +360,6 @@ namespace lms::api::subsonic
}
}
- ProtocolVersion SubsonicResource::getServerProtocolVersion(const std::string& clientName) const
- {
- auto it{ _serverProtocolVersionsByClient.find(clientName) };
- if (it == std::cend(_serverProtocolVersionsByClient))
- return defaultServerProtocolVersion;
-
- return it->second;
- }
-
- void SubsonicResource::checkProtocolVersion(ProtocolVersion client, ProtocolVersion server)
- {
- if (client.major > server.major)
- throw ServerMustUpgradeError{};
- if (client.major < server.major)
- throw ClientMustUpgradeError{};
- if (client.minor > server.minor)
- throw ServerMustUpgradeError{};
- if (client.minor == server.minor)
- {
- if (client.patch > server.patch)
- throw ServerMustUpgradeError{};
- }
- }
-
- RequestContext SubsonicResource::buildRequestContext(const Wt::Http::Request& request)
- {
- const Wt::Http::ParameterMap& parameters{ request.getParameterMap() };
- const ClientInfo clientInfo{ getClientInfo(request) };
- bool enableOpenSubsonic{ !_openSubsonicDisabledClients.contains(clientInfo.name) };
- const ResponseFormat format{ getParameterAs(request.getParameterMap(), "f").value_or("xml") == "json" ? ResponseFormat::json : ResponseFormat::xml };
-
- return RequestContext{
- .parameters = parameters,
- .dbSession = _db.getTLSSession(),
- .user = db::User::pointer{},
- .clientIpAddr = request.clientAddress(),
- .clientInfo = clientInfo,
- .serverProtocolVersion = getServerProtocolVersion(clientInfo.name),
- .responseFormat = format,
- .enableOpenSubsonic = enableOpenSubsonic,
- };
- }
-
db::UserId SubsonicResource::authenticateUser(const Wt::Http::Request& request)
{
const auto& parameters{ request.getParameterMap() };
@@ -449,7 +369,7 @@ namespace lms::api::subsonic
const auto user{ getParameterAs(parameters, "u") };
const auto password{ getParameterAs(parameters, "p") };
- if (!_supportUserPasswordAuthentication && (password || user))
+ if (!_config.supportUserPasswordAuthentication && (password || user))
throw ProvidedAuthenticationMechanismNotSupportedError{};
const auto apiKey{ getParameterAs(parameters, "apiKey") };
diff --git a/src/libs/subsonic/impl/SubsonicResource.hpp b/src/libs/subsonic/impl/SubsonicResource.hpp
index b0d89217..70c9a5de 100644
--- a/src/libs/subsonic/impl/SubsonicResource.hpp
+++ b/src/libs/subsonic/impl/SubsonicResource.hpp
@@ -18,16 +18,13 @@
*/
#pragma once
-#include
-#include
-#include
-
+#include
#include
#include
#include "database/objects/UserId.hpp"
-#include "RequestContext.hpp"
+#include "SubsonicResourceConfig.hpp"
namespace lms::db
{
@@ -43,16 +40,10 @@ namespace lms::api::subsonic
private:
void handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response) override;
- ProtocolVersion getServerProtocolVersion(const std::string& clientName) const;
- static void checkProtocolVersion(ProtocolVersion client, ProtocolVersion server);
- RequestContext buildRequestContext(const Wt::Http::Request& request);
db::UserId authenticateUser(const Wt::Http::Request& request);
- const std::unordered_map _serverProtocolVersionsByClient;
- const std::unordered_set _openSubsonicDisabledClients;
- const bool _supportUserPasswordAuthentication;
-
+ const SubsonicResourceConfig _config;
db::IDb& _db;
};
} // namespace lms::api::subsonic
diff --git a/src/libs/subsonic/impl/SubsonicResourceConfig.cpp b/src/libs/subsonic/impl/SubsonicResourceConfig.cpp
new file mode 100644
index 00000000..f33d50b5
--- /dev/null
+++ b/src/libs/subsonic/impl/SubsonicResourceConfig.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2025 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 "SubsonicResourceConfig.hpp"
+
+#include "core/IConfig.hpp"
+
+namespace lms::api::subsonic
+{
+ namespace
+ {
+ std::unordered_map readConfigProtocolVersions(core::IConfig& config)
+ {
+ std::unordered_map res;
+
+ config.visitStrings("api-subsonic-old-server-protocol-clients",
+ [&](std::string_view client) {
+ res.emplace(std::string{ client }, ProtocolVersion{ .major = 1, .minor = 12, .patch = 0 });
+ },
+ { "DSub" });
+
+ return res;
+ }
+
+ std::unordered_set readOpenSubsonicDisabledClients(core::IConfig& config)
+ {
+ std::unordered_set res;
+
+ config.visitStrings("api-open-subsonic-disabled-clients",
+ [&](std::string_view client) {
+ res.emplace(std::string{ client });
+ },
+ { "DSub" });
+
+ return res;
+ }
+ } // namespace
+
+ SubsonicResourceConfig readSubsonicResourceConfig(core::IConfig& config)
+ {
+ return SubsonicResourceConfig{
+ .serverProtocolVersionsByClient = readConfigProtocolVersions(config),
+ .openSubsonicDisabledClients = readOpenSubsonicDisabledClients(config),
+ .supportUserPasswordAuthentication = config.getBool("api-subsonic-support-user-password-auth", true)
+ };
+ }
+} // namespace lms::api::subsonic
\ No newline at end of file
diff --git a/src/libs/subsonic/impl/ClientInfo.hpp b/src/libs/subsonic/impl/SubsonicResourceConfig.hpp
similarity index 61%
rename from src/libs/subsonic/impl/ClientInfo.hpp
rename to src/libs/subsonic/impl/SubsonicResourceConfig.hpp
index bd684f47..0eef5698 100644
--- a/src/libs/subsonic/impl/ClientInfo.hpp
+++ b/src/libs/subsonic/impl/SubsonicResourceConfig.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 Emeric Poupon
+ * Copyright (C) 2025 Emeric Poupon
*
* This file is part of LMS.
*
@@ -20,14 +20,24 @@
#pragma once
#include
+#include
+#include
#include "ProtocolVersion.hpp"
+namespace lms::core
+{
+ class IConfig;
+}
+
namespace lms::api::subsonic
{
- struct ClientInfo
+ struct SubsonicResourceConfig
{
- std::string name;
- ProtocolVersion version;
+ std::unordered_map serverProtocolVersionsByClient;
+ std::unordered_set openSubsonicDisabledClients;
+ bool supportUserPasswordAuthentication;
};
-} // namespace lms::api::subsonic
+
+ SubsonicResourceConfig readSubsonicResourceConfig(core::IConfig& _config);
+} // namespace lms::api::subsonic
\ No newline at end of file
diff --git a/src/libs/subsonic/impl/endpoints/AlbumSongLists.cpp b/src/libs/subsonic/impl/endpoints/AlbumSongLists.cpp
index 2c9871d7..15e175a9 100644
--- a/src/libs/subsonic/impl/endpoints/AlbumSongLists.cpp
+++ b/src/libs/subsonic/impl/endpoints/AlbumSongLists.cpp
@@ -47,12 +47,12 @@ namespace lms::api::subsonic
Response handleGetAlbumListRequestCommon(RequestContext& context, bool id3)
{
// Mandatory params
- const std::string type{ getMandatoryParameterAs(context.parameters, "type") };
+ const std::string type{ getMandatoryParameterAs(context.getParameters(), "type") };
// Optional params
- const MediaLibraryId mediaLibraryId{ getParameterAs(context.parameters, "musicFolderId").value_or(MediaLibraryId{}) };
- const std::size_t size{ getParameterAs(context.parameters, "size").value_or(10) };
- const std::size_t offset{ getParameterAs(context.parameters, "offset").value_or(0) };
+ const MediaLibraryId mediaLibraryId{ getParameterAs(context.getParameters(), "musicFolderId").value_or(MediaLibraryId{}) };
+ const std::size_t size{ getParameterAs(context.getParameters(), "size").value_or(10) };
+ const std::size_t offset{ getParameterAs(context.getParameters(), "offset").value_or(0) };
if (size > defaultMaxCountSize)
throw ParameterValueTooHighGenericError{ "size", defaultMaxCountSize };
@@ -62,7 +62,7 @@ namespace lms::api::subsonic
scrobbling::IScrobblingService& scrobblingService{ *core::Service::get() };
feedback::IFeedbackService& feedbackService{ *core::Service::get() };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
if (type == "alphabeticalByName")
{
@@ -71,7 +71,7 @@ namespace lms::api::subsonic
params.setRange(range);
params.filters.setMediaLibrary(mediaLibraryId);
- releases = Release::findIds(context.dbSession, params);
+ releases = Release::findIds(context.getDbSession(), params);
}
else if (type == "alphabeticalByArtist")
{
@@ -80,14 +80,14 @@ namespace lms::api::subsonic
params.setRange(range);
params.filters.setMediaLibrary(mediaLibraryId);
- releases = Release::findIds(context.dbSession, params);
+ releases = Release::findIds(context.getDbSession(), params);
}
else if (type == "byGenre")
{
// Mandatory param
- const std::string genre{ getMandatoryParameterAs(context.parameters, "genre") };
+ const std::string genre{ getMandatoryParameterAs(context.getParameters(), "genre") };
- if (const ClusterType::pointer clusterType{ ClusterType::find(context.dbSession, "GENRE") })
+ if (const ClusterType::pointer clusterType{ ClusterType::find(context.getDbSession(), "GENRE") })
{
if (const Cluster::pointer cluster{ clusterType->getCluster(genre) })
{
@@ -97,14 +97,14 @@ namespace lms::api::subsonic
params.setSortMethod(ReleaseSortMethod::Name);
params.setRange(range);
- releases = Release::findIds(context.dbSession, params);
+ releases = Release::findIds(context.getDbSession(), params);
}
}
}
else if (type == "byYear")
{
- const int fromYear{ getMandatoryParameterAs(context.parameters, "fromYear") };
- const int toYear{ getMandatoryParameterAs(context.parameters, "toYear") };
+ const int fromYear{ getMandatoryParameterAs(context.getParameters(), "fromYear") };
+ const int toYear{ getMandatoryParameterAs(context.getParameters(), "toYear") };
Release::FindParameters params;
params.setSortMethod(fromYear > toYear ? ReleaseSortMethod::DateDesc : ReleaseSortMethod::DateAsc);
@@ -112,12 +112,12 @@ namespace lms::api::subsonic
params.setDateRange(YearRange{ std::min(fromYear, toYear), std::max(fromYear, toYear) });
params.filters.setMediaLibrary(mediaLibraryId);
- releases = Release::findIds(context.dbSession, params);
+ releases = Release::findIds(context.getDbSession(), params);
}
else if (type == "frequent")
{
scrobbling::IScrobblingService::FindParameters params;
- params.setUser(context.user->getId());
+ params.setUser(context.getUser()->getId());
params.setRange(range);
params.filters.setMediaLibrary(mediaLibraryId);
@@ -130,7 +130,7 @@ namespace lms::api::subsonic
params.setRange(range);
params.filters.setMediaLibrary(mediaLibraryId);
- releases = Release::findIds(context.dbSession, params);
+ releases = Release::findIds(context.getDbSession(), params);
}
else if (type == "random")
{
@@ -141,12 +141,12 @@ namespace lms::api::subsonic
params.setRange(Range{ 0, size });
params.filters.setMediaLibrary(mediaLibraryId);
- releases = Release::findIds(context.dbSession, params);
+ releases = Release::findIds(context.getDbSession(), params);
}
else if (type == "recent")
{
scrobbling::IScrobblingService::FindParameters params;
- params.setUser(context.user->getId());
+ params.setUser(context.getUser()->getId());
params.setRange(range);
params.filters.setMediaLibrary(mediaLibraryId);
@@ -155,7 +155,7 @@ namespace lms::api::subsonic
else if (type == "starred")
{
feedback::IFeedbackService::FindParameters params;
- params.setUser(context.user->getId());
+ params.setUser(context.getUser()->getId());
params.setRange(range);
params.filters.setMediaLibrary(mediaLibraryId);
@@ -166,12 +166,12 @@ namespace lms::api::subsonic
throw NotImplementedGenericError{};
}
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& albumListNode{ response.createNode(id3 ? Response::Node::Key{ "albumList2" } : Response::Node::Key{ "albumList" }) };
for (const ReleaseId releaseId : releases.results)
{
- const Release::pointer release{ Release::find(context.dbSession, releaseId) };
+ const Release::pointer release{ Release::find(context.getDbSession(), releaseId) };
albumListNode.addArrayChild("album", createAlbumNode(context, release, id3));
}
@@ -181,11 +181,11 @@ namespace lms::api::subsonic
Response handleGetStarredRequestCommon(RequestContext& context, bool id3)
{
// Optional parameters
- const MediaLibraryId mediaLibrary{ getParameterAs(context.parameters, "musicFolderId").value_or(MediaLibraryId{}) };
+ const MediaLibraryId mediaLibrary{ getParameterAs(context.getParameters(), "musicFolderId").value_or(MediaLibraryId{}) };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& starredNode{ response.createNode(id3 ? Response::Node::Key{ "starred2" } : Response::Node::Key{ "starred" }) };
feedback::IFeedbackService& feedbackService{ *core::Service::get() };
@@ -194,29 +194,29 @@ namespace lms::api::subsonic
if (id3)
{
feedback::IFeedbackService::ArtistFindParameters artistFindParams;
- artistFindParams.setUser(context.user->getId());
+ artistFindParams.setUser(context.getUser()->getId());
artistFindParams.setSortMethod(ArtistSortMethod::SortName);
for (const ArtistId artistId : feedbackService.findStarredArtists(artistFindParams).results)
{
- if (auto artist{ Artist::find(context.dbSession, artistId) })
+ if (auto artist{ Artist::find(context.getDbSession(), artistId) })
starredNode.addArrayChild("artist", createArtistNode(context, artist));
}
}
feedback::IFeedbackService::FindParameters findParameters;
- findParameters.setUser(context.user->getId());
+ findParameters.setUser(context.getUser()->getId());
findParameters.filters.setMediaLibrary(mediaLibrary);
for (const ReleaseId releaseId : feedbackService.findStarredReleases(findParameters).results)
{
- if (auto release{ Release::find(context.dbSession, releaseId) })
+ if (auto release{ Release::find(context.getDbSession(), releaseId) })
starredNode.addArrayChild("album", createAlbumNode(context, release, id3));
}
for (const TrackId trackId : feedbackService.findStarredTracks(findParameters).results)
{
- if (auto track{ Track::find(context.dbSession, trackId) })
- starredNode.addArrayChild("song", createSongNode(context, track, context.user));
+ if (auto track{ Track::find(context.getDbSession(), trackId) })
+ starredNode.addArrayChild("song", createSongNode(context, track, context.getUser()));
}
return response;
@@ -236,23 +236,23 @@ namespace lms::api::subsonic
Response handleGetRandomSongsRequest(RequestContext& context)
{
// Optional params
- const MediaLibraryId mediaLibraryId{ getParameterAs(context.parameters, "musicFolderId").value_or(MediaLibraryId{}) };
- std::size_t size{ getParameterAs(context.parameters, "size").value_or(50) };
+ const MediaLibraryId mediaLibraryId{ getParameterAs(context.getParameters(), "musicFolderId").value_or(MediaLibraryId{}) };
+ std::size_t size{ getParameterAs(context.getParameters(), "size").value_or(50) };
if (size > defaultMaxCountSize)
throw ParameterValueTooHighGenericError{ "size", defaultMaxCountSize };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& randomSongsNode{ response.createNode("randomSongs") };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
Track::FindParameters params;
params.setSortMethod(TrackSortMethod::Random);
params.setRange(Range{ 0, size });
params.filters.setMediaLibrary(mediaLibraryId);
- Track::find(context.dbSession, params, [&](const Track::pointer& track) {
- randomSongsNode.addArrayChild("song", createSongNode(context, track, context.user));
+ Track::find(context.getDbSession(), params, [&](const Track::pointer& track) {
+ randomSongsNode.addArrayChild("song", createSongNode(context, track, context.getUser()));
});
return response;
@@ -261,19 +261,19 @@ namespace lms::api::subsonic
Response handleGetSongsByGenreRequest(RequestContext& context)
{
// Mandatory params
- std::string genre{ getMandatoryParameterAs(context.parameters, "genre") };
+ std::string genre{ getMandatoryParameterAs(context.getParameters(), "genre") };
// Optional params
- const MediaLibraryId mediaLibrary{ getParameterAs(context.parameters, "musicFolderId").value_or(MediaLibraryId{}) };
- std::size_t count{ getParameterAs(context.parameters, "count").value_or(10) };
+ const MediaLibraryId mediaLibrary{ getParameterAs(context.getParameters(), "musicFolderId").value_or(MediaLibraryId{}) };
+ std::size_t count{ getParameterAs(context.getParameters(), "count").value_or(10) };
if (count > defaultMaxCountSize)
throw ParameterValueTooHighGenericError{ "count", defaultMaxCountSize };
- std::size_t offset{ getParameterAs(context.parameters, "offset").value_or(0) };
+ std::size_t offset{ getParameterAs(context.getParameters(), "offset").value_or(0) };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- auto clusterType{ ClusterType::find(context.dbSession, "GENRE") };
+ auto clusterType{ ClusterType::find(context.getDbSession(), "GENRE") };
if (!clusterType)
throw RequestedDataNotFoundError{};
@@ -281,7 +281,7 @@ namespace lms::api::subsonic
if (!cluster)
throw RequestedDataNotFoundError{};
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& songsByGenreNode{ response.createNode("songsByGenre") };
Track::FindParameters params;
@@ -289,8 +289,8 @@ namespace lms::api::subsonic
params.filters.setMediaLibrary(mediaLibrary);
params.setRange(Range{ offset, count });
- Track::find(context.dbSession, params, [&](const Track::pointer& track) {
- songsByGenreNode.addArrayChild("song", createSongNode(context, track, context.user));
+ Track::find(context.getDbSession(), params, [&](const Track::pointer& track) {
+ songsByGenreNode.addArrayChild("song", createSongNode(context, track, context.getUser()));
});
return response;
diff --git a/src/libs/subsonic/impl/endpoints/Bookmarks.cpp b/src/libs/subsonic/impl/endpoints/Bookmarks.cpp
index 7587bed7..41ea02cc 100644
--- a/src/libs/subsonic/impl/endpoints/Bookmarks.cpp
+++ b/src/libs/subsonic/impl/endpoints/Bookmarks.cpp
@@ -38,18 +38,18 @@ namespace lms::api::subsonic
Response handleGetBookmarks(RequestContext& context)
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- const auto bookmarkIds{ TrackBookmark::find(context.dbSession, context.user->getId()) };
+ const auto bookmarkIds{ TrackBookmark::find(context.getDbSession(), context.getUser()->getId()) };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& bookmarksNode{ response.createNode("bookmarks") };
for (const TrackBookmarkId bookmarkId : bookmarkIds.results)
{
- const TrackBookmark::pointer bookmark{ TrackBookmark::find(context.dbSession, bookmarkId) };
+ const TrackBookmark::pointer bookmark{ TrackBookmark::find(context.getDbSession(), bookmarkId) };
Response::Node bookmarkNode{ createBookmarkNode(bookmark) };
- bookmarkNode.addChild("entry", createSongNode(context, bookmark->getTrack(), context.user));
+ bookmarkNode.addChild("entry", createSongNode(context, bookmark->getTrack(), context.getUser()));
bookmarksNode.addArrayChild("bookmark", std::move(bookmarkNode));
}
@@ -59,51 +59,51 @@ namespace lms::api::subsonic
Response handleCreateBookmark(RequestContext& context)
{
// Mandatory params
- TrackId trackId{ getMandatoryParameterAs(context.parameters, "id") };
- unsigned long position{ getMandatoryParameterAs(context.parameters, "position") };
- const std::optional comment{ getParameterAs(context.parameters, "comment") };
+ TrackId trackId{ getMandatoryParameterAs(context.getParameters(), "id") };
+ unsigned long position{ getMandatoryParameterAs(context.getParameters(), "position") };
+ const std::optional comment{ getParameterAs(context.getParameters(), "comment") };
- auto transaction{ context.dbSession.createWriteTransaction() };
+ auto transaction{ context.getDbSession().createWriteTransaction() };
- const Track::pointer track{ Track::find(context.dbSession, trackId) };
+ const Track::pointer track{ Track::find(context.getDbSession(), trackId) };
if (!track)
throw RequestedDataNotFoundError{};
// Replace any existing bookmark
- auto bookmark{ TrackBookmark::find(context.dbSession, context.user->getId(), trackId) };
+ auto bookmark{ TrackBookmark::find(context.getDbSession(), context.getUser()->getId(), trackId) };
if (!bookmark)
- bookmark = context.dbSession.create(context.user, track);
+ bookmark = context.getDbSession().create(context.getUser(), track);
bookmark.modify()->setOffset(std::chrono::milliseconds{ position });
if (comment)
bookmark.modify()->setComment(*comment);
- return Response::createOkResponse(context.serverProtocolVersion);
+ return Response::createOkResponse(context.getServerProtocolVersion());
}
Response handleDeleteBookmark(RequestContext& context)
{
// Mandatory params
- TrackId trackId{ getMandatoryParameterAs(context.parameters, "id") };
+ TrackId trackId{ getMandatoryParameterAs(context.getParameters(), "id") };
- auto transaction{ context.dbSession.createWriteTransaction() };
+ auto transaction{ context.getDbSession().createWriteTransaction() };
- auto bookmark{ TrackBookmark::find(context.dbSession, context.user->getId(), trackId) };
+ auto bookmark{ TrackBookmark::find(context.getDbSession(), context.getUser()->getId(), trackId) };
if (!bookmark)
throw RequestedDataNotFoundError{};
bookmark.remove();
- return Response::createOkResponse(context.serverProtocolVersion);
+ return Response::createOkResponse(context.getServerProtocolVersion());
}
// Use a dedicated internal playlist
Response handleGetPlayQueue(RequestContext& context)
{
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
- auto transaction{ context.dbSession.createReadTransaction() };
- const db::PlayQueue::pointer playQueue{ db::PlayQueue::find(context.dbSession, context.user->getId(), "subsonic") };
+ auto transaction{ context.getDbSession().createReadTransaction() };
+ const db::PlayQueue::pointer playQueue{ db::PlayQueue::find(context.getDbSession(), context.getUser()->getId(), "subsonic") };
if (playQueue)
{
Response::Node& playQueueNode{ response.createNode("playQueue") };
@@ -115,7 +115,7 @@ namespace lms::api::subsonic
}
// mandatory fields
- playQueueNode.setAttribute("username", context.user->getLoginName());
+ playQueueNode.setAttribute("username", context.getUser()->getLoginName());
playQueueNode.setAttribute("changed", core::stringUtils::toISO8601String(playQueue->getLastModifiedDateTime()));
playQueueNode.setAttribute("changedBy", "unknown"); // we don't store the client name (could be several same clients on several devices...)
@@ -130,9 +130,9 @@ namespace lms::api::subsonic
Response handleSavePlayQueue(RequestContext& context)
{
// optional params
- std::vector trackIds{ getMultiParametersAs(context.parameters, "id") };
- const std::optional currentTrackId{ getParameterAs(context.parameters, "current") };
- const std::chrono::milliseconds currentPositionInTrack{ getParameterAs(context.parameters, "current").value_or(0) };
+ std::vector trackIds{ getMultiParametersAs(context.getParameters(), "id") };
+ const std::optional currentTrackId{ getParameterAs(context.getParameters(), "current") };
+ const std::chrono::milliseconds currentPositionInTrack{ getParameterAs(context.getParameters(), "current").value_or(0) };
std::vector tracks;
tracks.reserve(trackIds.size());
@@ -140,20 +140,20 @@ namespace lms::api::subsonic
// no id means we clear the play queue (see https://github.com/opensubsonic/open-subsonic-api/pull/106)
if (!trackIds.empty())
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
for (db::TrackId trackId : trackIds)
{
- if (db::Track::pointer track{ db::Track::find(context.dbSession, trackId) })
+ if (db::Track::pointer track{ db::Track::find(context.getDbSession(), trackId) })
tracks.push_back(track);
}
}
{
- auto transaction{ context.dbSession.createWriteTransaction() };
+ auto transaction{ context.getDbSession().createWriteTransaction() };
- db::PlayQueue::pointer playQueue{ db::PlayQueue::find(context.dbSession, context.user->getId(), "subsonic") };
+ db::PlayQueue::pointer playQueue{ db::PlayQueue::find(context.getDbSession(), context.getUser()->getId(), "subsonic") };
if (!playQueue)
- playQueue = context.dbSession.create(context.user, "subsonic");
+ playQueue = context.getDbSession().create(context.getUser(), "subsonic");
playQueue.modify()->clear();
std::size_t index{};
@@ -171,6 +171,6 @@ namespace lms::api::subsonic
playQueue.modify()->setLastModifiedDateTime(Wt::WDateTime::currentDateTime());
}
- return Response::createOkResponse(context.serverProtocolVersion);
+ return Response::createOkResponse(context.getServerProtocolVersion());
}
} // namespace lms::api::subsonic
\ No newline at end of file
diff --git a/src/libs/subsonic/impl/endpoints/Browsing.cpp b/src/libs/subsonic/impl/endpoints/Browsing.cpp
index 5d0d9e10..561e57c2 100644
--- a/src/libs/subsonic/impl/endpoints/Browsing.cpp
+++ b/src/libs/subsonic/impl/endpoints/Browsing.cpp
@@ -91,7 +91,7 @@ namespace lms::api::subsonic
params.setParentDirectory(parentDirectory->getId());
params.setSortMethod(DirectorySortMethod::Name);
- Directory::find(context.dbSession, params, [&](const Directory::pointer& directory) {
+ Directory::find(context.getDbSession(), params, [&](const Directory::pointer& directory) {
const std::string_view name{ directory->getName() };
assert(!name.empty());
@@ -114,7 +114,7 @@ namespace lms::api::subsonic
const std::size_t meanTrackCountPerArtist{ (count / artistIds.size()) + 1 };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
std::vector tracks;
tracks.reserve(count);
@@ -126,7 +126,7 @@ namespace lms::api::subsonic
params.setRange(Range{ 0, meanTrackCountPerArtist });
params.setSortMethod(TrackSortMethod::Random);
- const auto artistTracks{ Track::findIds(context.dbSession, params) };
+ const auto artistTracks{ Track::findIds(context.getDbSession(), params) };
tracks.insert(std::end(tracks),
std::begin(artistTracks.results),
std::end(artistTracks.results));
@@ -145,7 +145,7 @@ namespace lms::api::subsonic
const std::size_t meanTrackCountPerRelease{ (count / releaseIds.size()) + 1 };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
std::vector tracks;
tracks.reserve(count);
@@ -157,7 +157,7 @@ namespace lms::api::subsonic
params.setRange(Range{ 0, meanTrackCountPerRelease });
params.setSortMethod(TrackSortMethod::Random);
- const auto releaseTracks{ Track::findIds(context.dbSession, params) };
+ const auto releaseTracks{ Track::findIds(context.getDbSession(), params) };
tracks.insert(std::end(tracks),
std::begin(releaseTracks.results),
std::end(releaseTracks.results));
@@ -174,31 +174,31 @@ namespace lms::api::subsonic
Response handleGetSimilarSongsRequestCommon(RequestContext& context, bool id3)
{
// Optional params
- std::size_t count{ getParameterAs(context.parameters, "count").value_or(50) };
+ std::size_t count{ getParameterAs(context.getParameters(), "count").value_or(50) };
if (count > defaultMaxCountSize)
throw ParameterValueTooHighGenericError{ "count", defaultMaxCountSize };
std::vector tracks;
- if (const auto artistId{ getParameterAs(context.parameters, "id") })
+ if (const auto artistId{ getParameterAs(context.getParameters(), "id") })
tracks = findSimilarSongs(context, *artistId, count);
- else if (const auto releaseId{ getParameterAs(context.parameters, "id") })
+ else if (const auto releaseId{ getParameterAs(context.getParameters(), "id") })
tracks = findSimilarSongs(context, *releaseId, count);
- else if (const auto trackId{ getParameterAs(context.parameters, "id") })
+ else if (const auto trackId{ getParameterAs(context.getParameters(), "id") })
tracks = findSimilarSongs(context, *trackId, count);
else
throw BadParameterGenericError{ "id" };
core::random::shuffleContainer(tracks);
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& similarSongsNode{ response.createNode(id3 ? Response::Node::Key{ "similarSongs2" } : Response::Node::Key{ "similarSongs" }) };
for (const TrackId trackId : tracks)
{
- const Track::pointer track{ Track::find(context.dbSession, trackId) };
- similarSongsNode.addArrayChild("song", createSongNode(context, track, context.user));
+ const Track::pointer track{ Track::find(context.getDbSession(), trackId) };
+ similarSongsNode.addArrayChild("song", createSongNode(context, track, context.getUser()));
}
return response;
@@ -223,11 +223,11 @@ namespace lms::api::subsonic
Response handleGetMusicFoldersRequest(RequestContext& context)
{
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& musicFoldersNode{ response.createNode("musicFolders") };
- auto transaction{ context.dbSession.createReadTransaction() };
- MediaLibrary::find(context.dbSession, [&](const MediaLibrary::pointer& library) {
+ auto transaction{ context.getDbSession().createReadTransaction() };
+ MediaLibrary::find(context.getDbSession(), [&](const MediaLibrary::pointer& library) {
Response::Node& musicFolderNode{ musicFoldersNode.createArrayChild("musicFolder") };
musicFolderNode.setAttribute("id", library->getId().getValue());
@@ -240,16 +240,16 @@ namespace lms::api::subsonic
Response handleGetIndexesRequest(RequestContext& context)
{
// Optional params
- const MediaLibraryId mediaLibrary{ getParameterAs(context.parameters, "musicFolderId").value_or(MediaLibraryId{}) };
+ const MediaLibraryId mediaLibrary{ getParameterAs(context.getParameters(), "musicFolderId").value_or(MediaLibraryId{}) };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& indexesNode{ response.createNode("indexes") };
indexesNode.setAttribute("ignoredArticles", "");
indexesNode.setAttribute("lastModified", reportedDummyDateULong); // TODO report last file write?
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- const std::vector rootDirectories{ getRootDirectories(context.dbSession, mediaLibrary) };
+ const std::vector rootDirectories{ getRootDirectories(context.getDbSession(), mediaLibrary) };
IndexMap indexedDirectories;
for (const Directory::pointer& rootdirectory : rootDirectories)
@@ -257,8 +257,8 @@ namespace lms::api::subsonic
Track::FindParameters params;
params.setDirectory(rootdirectory->getId());
- Track::find(context.dbSession, params, [&](const Track::pointer& track) {
- indexesNode.addArrayChild("child", createSongNode(context, track, context.user));
+ Track::find(context.getDbSession(), params, [&](const Track::pointer& track) {
+ indexesNode.addArrayChild("child", createSongNode(context, track, context.getUser()));
});
getIndexedChildDirectories(context, rootdirectory, indexedDirectories);
@@ -287,21 +287,21 @@ namespace lms::api::subsonic
Response handleGetMusicDirectoryRequest(RequestContext& context)
{
// Mandatory params
- const auto directoryId{ getMandatoryParameterAs(context.parameters, "id") };
+ const auto directoryId{ getMandatoryParameterAs(context.getParameters(), "id") };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& directoryNode{ response.createNode("directory") };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- const Directory::pointer directory{ Directory::find(context.dbSession, directoryId) };
+ const Directory::pointer directory{ Directory::find(context.getDbSession(), directoryId) };
if (!directory)
throw RequestedDataNotFoundError{};
- if (const Release::pointer release{ getReleaseFromDirectory(context.dbSession, directoryId) })
+ if (const Release::pointer release{ getReleaseFromDirectory(context.getDbSession(), directoryId) })
{
- directoryNode.setAttribute("playCount", core::Service::get()->getCount(context.user->getId(), release->getId()));
- if (const Wt::WDateTime dateTime{ core::Service::get()->getStarredDateTime(context.user->getId(), release->getId()) }; dateTime.isValid())
+ directoryNode.setAttribute("playCount", core::Service::get()->getCount(context.getUser()->getId(), release->getId()));
+ if (const Wt::WDateTime dateTime{ core::Service::get()->getStarredDateTime(context.getUser()->getId(), release->getId()) }; dateTime.isValid())
directoryNode.setAttribute("starred", core::stringUtils::toISO8601String(dateTime));
}
@@ -317,8 +317,8 @@ namespace lms::api::subsonic
params.setParentDirectory(directory->getId());
params.setSortMethod(DirectorySortMethod::Name);
- Directory::find(context.dbSession, params, [&](const Directory::pointer& subDirectory) {
- const Release::pointer release{ getReleaseFromDirectory(context.dbSession, subDirectory->getId()) };
+ Directory::find(context.getDbSession(), params, [&](const Directory::pointer& subDirectory) {
+ const Release::pointer release{ getReleaseFromDirectory(context.getDbSession(), subDirectory->getId()) };
if (release)
{
@@ -343,8 +343,8 @@ namespace lms::api::subsonic
params.setDirectory(directory->getId());
params.setSortMethod(TrackSortMethod::AbsoluteFilePath);
- Track::find(context.dbSession, params, [&](const Track::pointer& track) {
- directoryNode.addArrayChild("child", createSongNode(context, track, context.user));
+ Track::find(context.getDbSession(), params, [&](const Track::pointer& track) {
+ directoryNode.addArrayChild("child", createSongNode(context, track, context.getUser()));
});
}
@@ -353,13 +353,13 @@ namespace lms::api::subsonic
Response handleGetGenresRequest(RequestContext& context)
{
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& genresNode{ response.createNode("genres") };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- const ClusterType::pointer clusterType{ ClusterType::find(context.dbSession, "GENRE") };
+ const ClusterType::pointer clusterType{ ClusterType::find(context.getDbSession(), "GENRE") };
if (clusterType)
{
const auto clusters{ clusterType->getClusters() };
@@ -374,9 +374,9 @@ namespace lms::api::subsonic
Response handleGetArtistsRequest(RequestContext& context)
{
// Optional params
- const MediaLibraryId mediaLibrary{ getParameterAs(context.parameters, "musicFolderId").value_or(MediaLibraryId{}) };
+ const MediaLibraryId mediaLibrary{ getParameterAs(context.getParameters(), "musicFolderId").value_or(MediaLibraryId{}) };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& artistsNode{ response.createNode("artists") };
artistsNode.setAttribute("ignoredArticles", "");
@@ -384,10 +384,10 @@ namespace lms::api::subsonic
Artist::FindParameters parameters;
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
parameters.setSortMethod(ArtistSortMethod::SortName);
- switch (context.user->getSubsonicArtistListMode())
+ switch (context.getUser()->getSubsonicArtistListMode())
{
case SubsonicArtistListMode::AllArtists:
break;
@@ -411,10 +411,10 @@ namespace lms::api::subsonic
bool hasMoreArtists{ true };
while (hasMoreArtists)
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
parameters.setRange(Range{ currentArtistOffset, batchSize });
- const auto artists{ Artist::find(context.dbSession, parameters) };
+ const auto artists{ Artist::find(context.getDbSession(), parameters) };
for (const Artist::pointer& artist : artists.results)
{
std::string_view sortName{ artist->getSortName() };
@@ -441,9 +441,9 @@ namespace lms::api::subsonic
for (const ArtistId artistId : artistIds)
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- if (const Artist::pointer artist{ Artist::find(context.dbSession, artistId) })
+ if (const Artist::pointer artist{ Artist::find(context.getDbSession(), artistId) })
indexNode.addArrayChild("artist", createArtistNode(context, artist));
}
}
@@ -454,18 +454,18 @@ namespace lms::api::subsonic
Response handleGetArtistRequest(RequestContext& context)
{
// Mandatory params
- ArtistId id{ getMandatoryParameterAs(context.parameters, "id") };
+ ArtistId id{ getMandatoryParameterAs(context.getParameters(), "id") };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- const Artist::pointer artist{ Artist::find(context.dbSession, id) };
+ const Artist::pointer artist{ Artist::find(context.getDbSession(), id) };
if (!artist)
throw RequestedDataNotFoundError{};
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node artistNode{ createArtistNode(context, artist) };
- const auto releases{ Release::find(context.dbSession, Release::FindParameters{}.setArtist(artist->getId())) };
+ const auto releases{ Release::find(context.getDbSession(), Release::FindParameters{}.setArtist(artist->getId())) };
for (const Release::pointer& release : releases.results)
artistNode.addArrayChild("album", createAlbumNode(context, release, true /* id3 */));
@@ -477,18 +477,18 @@ namespace lms::api::subsonic
Response handleGetAlbumRequest(RequestContext& context)
{
// Mandatory params
- ReleaseId id{ getMandatoryParameterAs(context.parameters, "id") };
+ ReleaseId id{ getMandatoryParameterAs(context.getParameters(), "id") };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- Release::pointer release{ Release::find(context.dbSession, id) };
+ Release::pointer release{ Release::find(context.getDbSession(), id) };
if (!release)
throw RequestedDataNotFoundError{};
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node albumNode{ createAlbumNode(context, release, true /* id3 */) };
- const auto tracks{ Track::find(context.dbSession, Track::FindParameters{}.setRelease(id).setSortMethod(TrackSortMethod::Release)) };
+ const auto tracks{ Track::find(context.getDbSession(), Track::FindParameters{}.setRelease(id).setSortMethod(TrackSortMethod::Release)) };
for (const Track::pointer& track : tracks.results)
albumNode.addArrayChild("song", createSongNode(context, track, true /* id3 */));
@@ -500,16 +500,16 @@ namespace lms::api::subsonic
Response handleGetSongRequest(RequestContext& context)
{
// Mandatory params
- TrackId id{ getMandatoryParameterAs(context.parameters, "id") };
+ TrackId id{ getMandatoryParameterAs(context.getParameters(), "id") };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- const Track::pointer track{ Track::find(context.dbSession, id) };
+ const Track::pointer track{ Track::find(context.getDbSession(), id) };
if (!track)
throw RequestedDataNotFoundError{};
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
- response.addNode("song", createSongNode(context, track, context.user));
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
+ response.addNode("song", createSongNode(context, track, context.getUser()));
return response;
}
@@ -517,24 +517,24 @@ namespace lms::api::subsonic
Response handleGetArtistInfo2Request(RequestContext& context)
{
// Mandatory params
- ArtistId id{ getMandatoryParameterAs(context.parameters, "id") };
+ ArtistId id{ getMandatoryParameterAs(context.getParameters(), "id") };
// Optional params
- std::size_t count{ getParameterAs(context.parameters, "count").value_or(20) };
+ std::size_t count{ getParameterAs(context.getParameters(), "count").value_or(20) };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& artistInfoNode{ response.createNode(Response::Node::Key{ "artistInfo2" }) };
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- const Artist::pointer artist{ Artist::find(context.dbSession, id) };
+ const Artist::pointer artist{ Artist::find(context.getDbSession(), id) };
if (!artist)
throw RequestedDataNotFoundError{};
if (const std::optional artistMBID{ artist->getMBID() })
{
- switch (context.responseFormat)
+ switch (context.getResponseFormat())
{
case ResponseFormat::json:
artistInfoNode.setAttribute("musicBrainzId", artistMBID->getAsString());
@@ -545,10 +545,10 @@ namespace lms::api::subsonic
}
}
- ArtistInfo::find(context.dbSession, id, Range{ .offset = 0, .size = 1 }, [&](const ArtistInfo::pointer& artistInfo) {
+ ArtistInfo::find(context.getDbSession(), id, Range{ .offset = 0, .size = 1 }, [&](const ArtistInfo::pointer& artistInfo) {
if (!artistInfo->getBiography().empty())
{
- switch (context.responseFormat)
+ switch (context.getResponseFormat())
{
case ResponseFormat::json:
artistInfoNode.setAttribute("biography", artistInfo->getBiography());
@@ -564,11 +564,11 @@ namespace lms::api::subsonic
auto similarArtistsId{ core::Service::get()->getSimilarArtists(id, { TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist }, count) };
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
for (const ArtistId similarArtistId : similarArtistsId)
{
- const Artist::pointer similarArtist{ Artist::find(context.dbSession, similarArtistId) };
+ const Artist::pointer similarArtist{ Artist::find(context.getDbSession(), similarArtistId) };
if (similarArtist)
artistInfoNode.addArrayChild("similarArtist", createArtistNode(context, similarArtist));
}
@@ -579,14 +579,14 @@ namespace lms::api::subsonic
Response handleGetAlbumInfo(RequestContext& context)
{
- const db::DirectoryId directoryId{ getMandatoryParameterAs(context.parameters, "id") };
+ const db::DirectoryId directoryId{ getMandatoryParameterAs(context.getParameters(), "id") };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- if (db::Release::pointer release{ getReleaseFromDirectory(context.dbSession, directoryId) })
+ if (db::Release::pointer release{ getReleaseFromDirectory(context.getDbSession(), directoryId) })
response.addNode("albumInfo", createAlbumInfoNode(context, release));
}
return response;
@@ -594,14 +594,14 @@ namespace lms::api::subsonic
Response handleGetAlbumInfo2(RequestContext& context)
{
- const db::ReleaseId releaseId{ getMandatoryParameterAs(context.parameters, "id") };
+ const db::ReleaseId releaseId{ getMandatoryParameterAs(context.getParameters(), "id") };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- if (db::Release::pointer release{ db::Release::find(context.dbSession, releaseId) })
+ if (db::Release::pointer release{ db::Release::find(context.getDbSession(), releaseId) })
response.addNode("albumInfo", createAlbumInfoNode(context, release));
}
@@ -621,29 +621,29 @@ namespace lms::api::subsonic
Response handleGetTopSongs(RequestContext& context)
{
// Mandatory params
- std::string_view artistName{ getMandatoryParameterAs(context.parameters, "artist") };
- std::size_t count{ getParameterAs(context.parameters, "count").value_or(50) };
+ std::string_view artistName{ getMandatoryParameterAs(context.getParameters(), "artist") };
+ std::size_t count{ getParameterAs(context.getParameters(), "count").value_or(50) };
if (count > defaultMaxCountSize)
throw ParameterValueTooHighGenericError{ "count", defaultMaxCountSize };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& topSongs{ response.createNode("topSongs") };
- const auto artists{ Artist::find(context.dbSession, artistName) };
+ const auto artists{ Artist::find(context.getDbSession(), artistName) };
if (artists.size() == 1)
{
scrobbling::IScrobblingService::FindParameters params;
- params.setUser(context.user->getId());
+ params.setUser(context.getUser()->getId());
params.setRange(db::Range{ 0, count });
params.setArtist(artists.front()->getId());
const auto trackIds{ core::Service::get()->getTopTracks(params) };
for (const TrackId trackId : trackIds.results)
{
- if (Track::pointer track{ Track::find(context.dbSession, trackId) })
- topSongs.addArrayChild("song", createSongNode(context, track, context.user));
+ if (Track::pointer track{ Track::find(context.getDbSession(), trackId) })
+ topSongs.addArrayChild("song", createSongNode(context, track, context.getUser()));
}
}
diff --git a/src/libs/subsonic/impl/endpoints/MediaAnnotation.cpp b/src/libs/subsonic/impl/endpoints/MediaAnnotation.cpp
index 3bd79e77..ae033bae 100644
--- a/src/libs/subsonic/impl/endpoints/MediaAnnotation.cpp
+++ b/src/libs/subsonic/impl/endpoints/MediaAnnotation.cpp
@@ -113,72 +113,72 @@ namespace lms::api::subsonic
Response handleStarRequest(RequestContext& context)
{
- StarParameters params{ getStarParameters(context.parameters) };
+ StarParameters params{ getStarParameters(context.getParameters()) };
for (const DirectoryId id : params.directoryIds)
{
- if (const ReleaseId releaseId{ getReleaseIdFromDirectory(context.dbSession, id) }; releaseId.isValid())
- core::Service::get()->star(context.user->getId(), releaseId);
+ if (const ReleaseId releaseId{ getReleaseIdFromDirectory(context.getDbSession(), id) }; releaseId.isValid())
+ core::Service::get()->star(context.getUser()->getId(), releaseId);
}
for (const ArtistId id : params.artistIds)
- core::Service::get()->star(context.user->getId(), id);
+ core::Service::get()->star(context.getUser()->getId(), id);
for (const ReleaseId id : params.releaseIds)
- core::Service::get()->star(context.user->getId(), id);
+ core::Service::get()->star(context.getUser()->getId(), id);
for (const TrackId id : params.trackIds)
- core::Service::get()->star(context.user->getId(), id);
+ core::Service::get()->star(context.getUser()->getId(), id);
- return Response::createOkResponse(context.serverProtocolVersion);
+ return Response::createOkResponse(context.getServerProtocolVersion());
}
Response handleUnstarRequest(RequestContext& context)
{
- const StarParameters params{ getStarParameters(context.parameters) };
+ const StarParameters params{ getStarParameters(context.getParameters()) };
for (const DirectoryId id : params.directoryIds)
{
- if (const ReleaseId releaseId{ getReleaseIdFromDirectory(context.dbSession, id) }; releaseId.isValid())
- core::Service::get()->unstar(context.user->getId(), releaseId);
+ if (const ReleaseId releaseId{ getReleaseIdFromDirectory(context.getDbSession(), id) }; releaseId.isValid())
+ core::Service::get()->unstar(context.getUser()->getId(), releaseId);
}
for (const ArtistId id : params.artistIds)
- core::Service::get()->unstar(context.user->getId(), id);
+ core::Service::get()->unstar(context.getUser()->getId(), id);
for (const ReleaseId id : params.releaseIds)
- core::Service::get()->unstar(context.user->getId(), id);
+ core::Service::get()->unstar(context.getUser()->getId(), id);
for (const TrackId id : params.trackIds)
- core::Service::get()->unstar(context.user->getId(), id);
+ core::Service::get()->unstar(context.getUser()->getId(), id);
- return Response::createOkResponse(context.serverProtocolVersion);
+ return Response::createOkResponse(context.getServerProtocolVersion());
}
Response handleSetRating(RequestContext& context)
{
- const RatingParameters params{ getRatingParameters(context.parameters) };
+ const RatingParameters params{ getRatingParameters(context.getParameters()) };
if (const ArtistId * artistId{ std::get_if(¶ms.id) })
- core::Service::get()->setRating(context.user->getId(), *artistId, params.rating);
+ core::Service::get()->setRating(context.getUser()->getId(), *artistId, params.rating);
else if (const DirectoryId * directoryId{ std::get_if(¶ms.id) })
{
- if (const ReleaseId releaseId{ getReleaseIdFromDirectory(context.dbSession, *directoryId) }; releaseId.isValid())
- core::Service::get()->setRating(context.user->getId(), releaseId, params.rating);
+ if (const ReleaseId releaseId{ getReleaseIdFromDirectory(context.getDbSession(), *directoryId) }; releaseId.isValid())
+ core::Service::get()->setRating(context.getUser()->getId(), releaseId, params.rating);
}
else if (const ReleaseId * releaseId{ std::get_if(¶ms.id) })
- core::Service::get()->setRating(context.user->getId(), *releaseId, params.rating);
+ core::Service::get()->setRating(context.getUser()->getId(), *releaseId, params.rating);
else if (const TrackId * trackId{ std::get_if(¶ms.id) })
- core::Service::get()->setRating(context.user->getId(), *trackId, params.rating);
+ core::Service::get()->setRating(context.getUser()->getId(), *trackId, params.rating);
- return Response::createOkResponse(context.serverProtocolVersion);
+ return Response::createOkResponse(context.getServerProtocolVersion());
}
Response handleScrobble(RequestContext& context)
{
- const std::vector ids{ getMandatoryMultiParametersAs(context.parameters, "id") };
- const std::vector times{ getMultiParametersAs(context.parameters, "time") };
- const bool submission{ getParameterAs(context.parameters, "submission").value_or(true) };
+ const std::vector ids{ getMandatoryMultiParametersAs(context.getParameters(), "id") };
+ const std::vector times{ getMultiParametersAs(context.getParameters(), "time") };
+ const bool submission{ getParameterAs(context.getParameters(), "submission").value_or(true) };
// playing now => only one at a time
if (!submission && ids.size() > 1)
@@ -190,13 +190,13 @@ namespace lms::api::subsonic
if (!submission)
{
- core::Service::get()->listenStarted({ context.user->getId(), ids.front() });
+ core::Service::get()->listenStarted({ context.getUser()->getId(), ids.front() });
}
else
{
if (times.empty())
{
- core::Service::get()->listenFinished({ context.user->getId(), ids.front() });
+ core::Service::get()->listenFinished({ context.getUser()->getId(), ids.front() });
}
else
{
@@ -204,11 +204,11 @@ namespace lms::api::subsonic
{
const TrackId trackId{ ids[i] };
const unsigned long time{ times[i] };
- core::Service::get()->addTimedListen({ { context.user->getId(), trackId }, Wt::WDateTime::fromTime_t(static_cast(time / 1000)) });
+ core::Service::get()->addTimedListen({ { context.getUser()->getId(), trackId }, Wt::WDateTime::fromTime_t(static_cast(time / 1000)) });
}
}
}
- return Response::createOkResponse(context.serverProtocolVersion);
+ return Response::createOkResponse(context.getServerProtocolVersion());
}
} // namespace lms::api::subsonic
\ No newline at end of file
diff --git a/src/libs/subsonic/impl/endpoints/MediaLibraryScanning.cpp b/src/libs/subsonic/impl/endpoints/MediaLibraryScanning.cpp
index 3a899b2b..2c09c161 100644
--- a/src/libs/subsonic/impl/endpoints/MediaLibraryScanning.cpp
+++ b/src/libs/subsonic/impl/endpoints/MediaLibraryScanning.cpp
@@ -51,7 +51,7 @@ namespace lms::api::subsonic::Scan
Response handleGetScanStatus(RequestContext& context)
{
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
response.addNode("scanStatus", createStatusResponseNode());
return response;
@@ -61,7 +61,7 @@ namespace lms::api::subsonic::Scan
{
core::Service::get()->requestImmediateScan();
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
response.addNode("scanStatus", createStatusResponseNode());
return response;
diff --git a/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp b/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp
index 1ad9d273..bffd1f09 100644
--- a/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp
+++ b/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp
@@ -176,20 +176,20 @@ namespace lms::api::subsonic
StreamParameters getStreamParameters(RequestContext& context)
{
// Mandatory params
- const auto trackId{ getParameterAs(context.parameters, "id") };
- const auto podcastEpisodeId{ getParameterAs(context.parameters, "id") };
+ const auto trackId{ getParameterAs(context.getParameters(), "id") };
+ const auto podcastEpisodeId{ getParameterAs(context.getParameters(), "id") };
if (!trackId && !podcastEpisodeId)
throw RequiredParameterMissingError{ "id" };
const AudioFileId audioId{ trackId ? AudioFileId{ *trackId } : AudioFileId{ *podcastEpisodeId } };
// Optional params
- std::size_t maxBitRate{ getParameterAs(context.parameters, "maxBitRate").value_or(0) * 1000 }; // "If set to zero, no limit is imposed", given in kpbs
- const std::string format{ getParameterAs(context.parameters, "format").value_or("") };
- std::size_t timeOffset{ getParameterAs(context.parameters, "timeOffset").value_or(0) };
- bool estimateContentLength{ getParameterAs(context.parameters, "estimateContentLength").value_or(false) };
+ std::size_t maxBitRate{ getParameterAs(context.getParameters(), "maxBitRate").value_or(0) * 1000 }; // "If set to zero, no limit is imposed", given in kpbs
+ const std::string format{ getParameterAs(context.getParameters(), "format").value_or("") };
+ std::size_t timeOffset{ getParameterAs(context.getParameters(), "timeOffset").value_or(0) };
+ bool estimateContentLength{ getParameterAs(context.getParameters(), "estimateContentLength").value_or(false) };
- const AudioFileInfo audioFileInfo{ getAudioFileInfo(context.dbSession, audioId) };
+ const AudioFileInfo audioFileInfo{ getAudioFileInfo(context.getDbSession(), audioId) };
StreamParameters parameters;
@@ -205,8 +205,8 @@ namespace lms::api::subsonic
std::optional requestedFormat{ subsonicStreamFormatToAvOutputFormat(format) };
if (!requestedFormat)
{
- if (context.user->getSubsonicEnableTranscodingByDefault())
- requestedFormat = userTranscodeFormatToAvFormat(context.user->getSubsonicDefaultTranscodingOutputFormat());
+ if (context.getUser()->getSubsonicEnableTranscodingByDefault())
+ requestedFormat = userTranscodeFormatToAvFormat(context.getUser()->getSubsonicDefaultTranscodingOutputFormat());
}
if (!requestedFormat && (maxBitRate == 0 || audioFileInfo.bitrate <= maxBitRate))
@@ -231,9 +231,9 @@ namespace lms::api::subsonic
// Need to transcode here
if (!requestedFormat)
- requestedFormat = userTranscodeFormatToAvFormat(context.user->getSubsonicDefaultTranscodingOutputFormat());
+ requestedFormat = userTranscodeFormatToAvFormat(context.getUser()->getSubsonicDefaultTranscodingOutputFormat());
if (!bitrate)
- bitrate = context.user->getSubsonicDefaultTranscodingOutputBitrate();
+ bitrate = context.getUser()->getSubsonicDefaultTranscodingOutputBitrate();
if (maxBitRate)
bitrate = std::min(bitrate, maxBitRate);
@@ -248,13 +248,13 @@ namespace lms::api::subsonic
Response handleGetLyrics(RequestContext& context)
{
- std::string artistName{ getParameterAs(context.parameters, "artist").value_or("") };
- std::string titleName{ getParameterAs(context.parameters, "title").value_or("") };
+ std::string artistName{ getParameterAs(context.getParameters(), "artist").value_or("") };
+ std::string titleName{ getParameterAs(context.getParameters(), "title").value_or("") };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
// best effort search, as this API is really limited
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
db::Track::FindParameters params;
params.setName(titleName);
@@ -262,7 +262,7 @@ namespace lms::api::subsonic
params.setRange(db::Range{ .offset = 0, .size = 2 });
// Choice: we return nothing if there are too many results
- const auto tracks{ db::Track::findIds(context.dbSession, params) };
+ const auto tracks{ db::Track::findIds(context.getDbSession(), params) };
if (tracks.results.size() == 1)
{
// Choice: we return only the first lyrics if the track has many lyrics
@@ -271,7 +271,7 @@ namespace lms::api::subsonic
lyricsParams.setSortMethod(db::TrackLyricsSortMethod::ExternalFirst);
lyricsParams.setRange(db::Range{ 0, 1 });
- db::TrackLyrics::find(context.dbSession, lyricsParams, [&](const db::TrackLyrics::pointer& lyrics) {
+ db::TrackLyrics::find(context.getDbSession(), lyricsParams, [&](const db::TrackLyrics::pointer& lyrics) {
response.addNode("lyrics", createLyricsNode(context, lyrics));
});
}
@@ -282,14 +282,14 @@ namespace lms::api::subsonic
Response handleGetLyricsBySongId(RequestContext& context)
{
// mandatory params
- db::TrackId id{ getMandatoryParameterAs(context.parameters, "id") };
+ db::TrackId id{ getMandatoryParameterAs(context.getParameters(), "id") };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& lyricsList{ response.createNode("lyricsList") };
lyricsList.createEmptyArrayChild("structuredLyrics");
- auto transaction{ context.dbSession.createReadTransaction() };
- const db::Track::pointer track{ db::Track::find(context.dbSession, id) };
+ auto transaction{ context.getDbSession().createReadTransaction() };
+ const db::Track::pointer track{ db::Track::find(context.getDbSession(), id) };
if (track)
{
db::TrackLyrics::FindParameters params;
@@ -297,7 +297,7 @@ namespace lms::api::subsonic
params.setExternal(true); // First try to only report external lyrics as they are often duplicate of embedded lyrics and support more features
bool hasExternalLyrics{};
- db::TrackLyrics::find(context.dbSession, params, [&](const db::TrackLyrics::pointer& lyrics) {
+ db::TrackLyrics::find(context.getDbSession(), params, [&](const db::TrackLyrics::pointer& lyrics) {
lyricsList.addArrayChild("structuredLyrics", createStructuredLyricsNode(context, lyrics));
hasExternalLyrics = true;
});
@@ -305,7 +305,7 @@ namespace lms::api::subsonic
if (!hasExternalLyrics)
{
params.setExternal(false);
- db::TrackLyrics::find(context.dbSession, params, [&](const db::TrackLyrics::pointer& lyrics) {
+ db::TrackLyrics::find(context.getDbSession(), params, [&](const db::TrackLyrics::pointer& lyrics) {
lyricsList.addArrayChild("structuredLyrics", createStructuredLyricsNode(context, lyrics));
});
}
@@ -322,13 +322,13 @@ namespace lms::api::subsonic
if (!continuation)
{
// Mandatory params
- db::TrackId id{ getMandatoryParameterAs(context.parameters, "id") };
+ db::TrackId id{ getMandatoryParameterAs(context.getParameters(), "id") };
std::filesystem::path trackPath;
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- auto track{ db::Track::find(context.dbSession, id) };
+ auto track{ db::Track::find(context.getDbSession(), id) };
if (!track)
throw RequestedDataNotFoundError{};
@@ -381,9 +381,9 @@ namespace lms::api::subsonic
void handleGetCoverArt(RequestContext& context, const Wt::Http::Request& /*request*/, Wt::Http::Response& response)
{
// Mandatory params
- const CoverArtId coverArtId{ getMandatoryParameterAs(context.parameters, "id") };
+ const CoverArtId coverArtId{ getMandatoryParameterAs(context.getParameters(), "id") };
- std::optional size{ getParameterAs(context.parameters, "size") };
+ std::optional size{ getParameterAs(context.getParameters(), "size") };
if (size)
*size = std::clamp(*size, std::size_t{ 32 }, std::size_t{ 2048 });
diff --git a/src/libs/subsonic/impl/endpoints/Playlists.cpp b/src/libs/subsonic/impl/endpoints/Playlists.cpp
index cfa46fff..00ae150e 100644
--- a/src/libs/subsonic/impl/endpoints/Playlists.cpp
+++ b/src/libs/subsonic/impl/endpoints/Playlists.cpp
@@ -53,9 +53,9 @@ namespace lms::api::subsonic
Response handleGetPlaylistsRequest(RequestContext& context)
{
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node& playlistsNode{ response.createNode("playlists") };
auto addTrackList{ [&](const db::TrackList::pointer& trackList) {
@@ -65,10 +65,10 @@ namespace lms::api::subsonic
// First add user's playlists
{
TrackList::FindParameters params;
- params.setUser(context.user->getId());
+ params.setUser(context.getUser()->getId());
params.setType(TrackListType::PlayList);
- db::TrackList::find(context.dbSession, params, [&](const db::TrackList::pointer& trackList) {
+ db::TrackList::find(context.getDbSession(), params, [&](const db::TrackList::pointer& trackList) {
addTrackList(trackList);
});
}
@@ -78,10 +78,10 @@ namespace lms::api::subsonic
TrackList::FindParameters params;
params.setVisibility(TrackList::Visibility::Public);
params.setType(TrackListType::PlayList);
- params.setExcludedUser(context.user->getId());
+ params.setExcludedUser(context.getUser()->getId());
- db::TrackList::find(context.dbSession, params, [&](const db::TrackList::pointer& trackList) {
- assert(trackList->getUserId() != context.user->getId());
+ db::TrackList::find(context.getDbSession(), params, [&](const db::TrackList::pointer& trackList) {
+ assert(trackList->getUserId() != context.getUser()->getId());
addTrackList(trackList);
});
}
@@ -92,23 +92,23 @@ namespace lms::api::subsonic
Response handleGetPlaylistRequest(RequestContext& context)
{
// Mandatory params
- TrackListId trackListId{ getMandatoryParameterAs(context.parameters, "id") };
+ TrackListId trackListId{ getMandatoryParameterAs(context.getParameters(), "id") };
- auto transaction{ context.dbSession.createReadTransaction() };
+ auto transaction{ context.getDbSession().createReadTransaction() };
- TrackList::pointer trackList{ TrackList::find(context.dbSession, trackListId) };
+ TrackList::pointer trackList{ TrackList::find(context.getDbSession(), trackListId) };
if (!trackList || trackList->getType() != TrackListType::PlayList)
throw RequestedDataNotFoundError{};
- if (trackList->getUserId() != context.user->getId() && trackList->getVisibility() != TrackList::Visibility::Public)
+ if (trackList->getUserId() != context.getUser()->getId() && trackList->getVisibility() != TrackList::Visibility::Public)
throw RequestedDataNotFoundError{};
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node playlistNode{ createPlaylistNode(context, trackList) };
auto entries{ trackList->getEntries() };
for (const TrackListEntry::pointer& entry : entries.results)
- playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), context.user));
+ playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), context.getUser()));
response.addNode("playlist", std::move(playlistNode));
@@ -118,21 +118,21 @@ namespace lms::api::subsonic
Response handleCreatePlaylistRequest(RequestContext& context)
{
// Optional params
- const auto id{ getParameterAs(context.parameters, "playlistId") };
- auto name{ getParameterAs(context.parameters, "name") };
+ const auto id{ getParameterAs(context.getParameters(), "playlistId") };
+ auto name{ getParameterAs(context.getParameters(), "name") };
- std::vector trackIds{ getMultiParametersAs(context.parameters, "songId") };
+ std::vector trackIds{ getMultiParametersAs(context.getParameters(), "songId") };
if (!name && !id)
throw RequiredParameterMissingError{ "name or playlistId" };
- auto transaction{ context.dbSession.createWriteTransaction() };
+ auto transaction{ context.getDbSession().createWriteTransaction() };
TrackList::pointer trackList;
if (id)
{
- trackList = TrackList::find(context.dbSession, *id);
- checkTrackListModificationAccess(trackList, context.user->getId());
+ trackList = TrackList::find(context.getDbSession(), *id);
+ checkTrackListModificationAccess(trackList, context.getUser()->getId());
if (name)
trackList.modify()->setName(*name);
@@ -142,26 +142,26 @@ namespace lms::api::subsonic
}
else
{
- trackList = context.dbSession.create(*name, TrackListType::PlayList);
- trackList.modify()->setUser(context.user);
+ trackList = context.getDbSession().create(*name, TrackListType::PlayList);
+ trackList.modify()->setUser(context.getUser());
trackList.modify()->setVisibility(TrackList::Visibility::Private);
}
for (const TrackId trackId : trackIds)
{
- Track::pointer track{ Track::find(context.dbSession, trackId) };
+ Track::pointer track{ Track::find(context.getDbSession(), trackId) };
if (!track)
continue;
- context.dbSession.create(track, trackList);
+ context.getDbSession().create(track, trackList);
}
- Response response{ Response::createOkResponse(context.serverProtocolVersion) };
+ Response response{ Response::createOkResponse(context.getServerProtocolVersion()) };
Response::Node playlistNode{ createPlaylistNode(context, trackList) };
auto entries{ trackList->getEntries() };
for (const TrackListEntry::pointer& entry : entries.results)
- playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), context.user));
+ playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), context.getUser()));
response.addNode("playlist", std::move(playlistNode));
@@ -171,19 +171,19 @@ namespace lms::api::subsonic
Response handleUpdatePlaylistRequest(RequestContext& context)
{
// Mandatory params
- TrackListId id{ getMandatoryParameterAs(context.parameters, "playlistId") };
+ TrackListId id{ getMandatoryParameterAs(context.getParameters(), "playlistId") };
// Optional parameters
- auto name{ getParameterAs(context.parameters, "name") };
- auto isPublic{ getParameterAs(context.parameters, "public") };
+ auto name{ getParameterAs(context.getParameters(), "name") };
+ auto isPublic{ getParameterAs(context.getParameters(), "public") };
- std::vector trackIdsToAdd{ getMultiParametersAs(context.parameters, "songIdToAdd") };
- std::vector trackPositionsToRemove{ getMultiParametersAs(context.parameters, "songIndexToRemove") };
+ std::vector trackIdsToAdd{ getMultiParametersAs(context.getParameters(), "songIdToAdd") };
+ std::vector trackPositionsToRemove{ getMultiParametersAs(context.getParameters(), "songIndexToRemove") };
- auto transaction{ context.dbSession.createWriteTransaction() };
+ auto transaction{ context.getDbSession().createWriteTransaction() };
- TrackList::pointer trackList{ TrackList::find(context.dbSession, id) };
- checkTrackListModificationAccess(trackList, context.user->getId());
+ TrackList::pointer trackList{ TrackList::find(context.getDbSession(), id) };
+ checkTrackListModificationAccess(trackList, context.getUser()->getId());
if (name)
trackList.modify()->setName(*name);
@@ -206,27 +206,27 @@ namespace lms::api::subsonic
// Add tracks
for (const TrackId trackIdToAdd : trackIdsToAdd)
{
- Track::pointer track{ Track::find(context.dbSession, trackIdToAdd) };
+ Track::pointer track{ Track::find(context.getDbSession(), trackIdToAdd) };
if (!track)
continue;
- context.dbSession.create(track, trackList);
+ context.getDbSession().create(track, trackList);
}
- return Response::createOkResponse(context.serverProtocolVersion);
+ return Response::createOkResponse(context.getServerProtocolVersion());
}
Response handleDeletePlaylistRequest(RequestContext& context)
{
- TrackListId id{ getMandatoryParameterAs(context.parameters, "id") };
+ TrackListId id{ getMandatoryParameterAs(context.getParameters(), "id") };
- auto transaction{ context.dbSession.createWriteTransaction() };
+ auto transaction{ context.getDbSession().createWriteTransaction() };
- TrackList::pointer trackList{ TrackList::find(context.dbSession, id) };
- checkTrackListModificationAccess(trackList, context.user->getId());
+ TrackList::pointer trackList{ TrackList::find(context.getDbSession(), id) };
+ checkTrackListModificationAccess(trackList, context.getUser()->getId());
trackList.remove();
- return Response::createOkResponse(context.serverProtocolVersion);
+ return Response::createOkResponse(context.getServerProtocolVersion());
}
} // namespace lms::api::subsonic
\ No newline at end of file
diff --git a/src/libs/subsonic/impl/endpoints/Podcast.cpp b/src/libs/subsonic/impl/endpoints/Podcast.cpp
index 3d740c0d..c4d129ff 100644
--- a/src/libs/subsonic/impl/endpoints/Podcast.cpp
+++ b/src/libs/subsonic/impl/endpoints/Podcast.cpp
@@ -34,14 +34,14 @@ namespace lms::api::subsonic
{
Response handleGetPodcasts(RequestContext& context)
{
- const bool includeEpisodes{ getParameterAs(context.parameters, "includeEpisodes").value_or(true) };
- const std::optional podcastId{ getParameterAs