From 0ccd095534a4d560167aea8d972d2ff9082969d8 Mon Sep 17 00:00:00 2001 From: emeric Date: Wed, 1 Oct 2025 22:11:32 +0200 Subject: [PATCH] Refactored request context handling --- src/libs/subsonic/CMakeLists.txt | 2 + src/libs/subsonic/impl/RequestContext.cpp | 107 +++++++++++ src/libs/subsonic/impl/RequestContext.hpp | 48 +++-- src/libs/subsonic/impl/SubsonicResource.cpp | 108 ++--------- src/libs/subsonic/impl/SubsonicResource.hpp | 15 +- .../subsonic/impl/SubsonicResourceConfig.cpp | 63 +++++++ ...entInfo.hpp => SubsonicResourceConfig.hpp} | 20 ++- .../impl/endpoints/AlbumSongLists.cpp | 88 ++++----- .../subsonic/impl/endpoints/Bookmarks.cpp | 60 +++---- src/libs/subsonic/impl/endpoints/Browsing.cpp | 170 +++++++++--------- .../impl/endpoints/MediaAnnotation.cpp | 56 +++--- .../impl/endpoints/MediaLibraryScanning.cpp | 4 +- .../impl/endpoints/MediaRetrieval.cpp | 56 +++--- .../subsonic/impl/endpoints/Playlists.cpp | 82 ++++----- src/libs/subsonic/impl/endpoints/Podcast.cpp | 46 ++--- .../subsonic/impl/endpoints/Searching.cpp | 58 +++--- src/libs/subsonic/impl/endpoints/System.cpp | 6 +- .../impl/endpoints/UserManagement.cpp | 16 +- src/libs/subsonic/impl/responses/Album.cpp | 18 +- .../subsonic/impl/responses/AlbumInfo.cpp | 2 +- src/libs/subsonic/impl/responses/Artist.cpp | 10 +- src/libs/subsonic/impl/responses/Genre.cpp | 2 +- src/libs/subsonic/impl/responses/Lyrics.cpp | 4 +- src/libs/subsonic/impl/responses/Playlist.cpp | 2 +- src/libs/subsonic/impl/responses/Podcast.cpp | 2 +- src/libs/subsonic/impl/responses/Song.cpp | 20 +-- src/libs/subsonic/impl/responses/User.cpp | 2 +- 27 files changed, 594 insertions(+), 473 deletions(-) create mode 100644 src/libs/subsonic/impl/RequestContext.cpp create mode 100644 src/libs/subsonic/impl/SubsonicResourceConfig.cpp rename src/libs/subsonic/impl/{ClientInfo.hpp => SubsonicResourceConfig.hpp} (61%) 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(context.parameters, "id") }; + const bool includeEpisodes{ getParameterAs(context.getParameters(), "includeEpisodes").value_or(true) }; + const std::optional podcastId{ getParameterAs(context.getParameters(), "id") }; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; + Response response{ Response::createOkResponse(context.getServerProtocolVersion()) }; Response::Node& podcastsNode{ response.createNode("podcasts") }; podcastsNode.createEmptyArrayChild("channel"); - auto transaction{ context.dbSession.createReadTransaction() }; + auto transaction{ context.getDbSession().createReadTransaction() }; auto processPodcast{ [&](const db::Podcast::pointer& podcast) { podcastsNode.addArrayChild("channel", createPodcastNode(context, podcast, includeEpisodes)); @@ -49,34 +49,34 @@ namespace lms::api::subsonic if (podcastId.has_value()) { - db::Podcast::pointer podcast{ db::Podcast::find(context.dbSession, podcastId.value()) }; + db::Podcast::pointer podcast{ db::Podcast::find(context.getDbSession(), podcastId.value()) }; if (!podcast) throw RequestedDataNotFoundError{}; processPodcast(podcast); } else - db::Podcast::find(context.dbSession, processPodcast); + db::Podcast::find(context.getDbSession(), processPodcast); return response; } Response handleGetNewestPodcasts(RequestContext& context) { - std::size_t count{ getParameterAs(context.parameters, "count").value_or(20) }; + std::size_t count{ getParameterAs(context.getParameters(), "count").value_or(20) }; count = std::min(count, 100); - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; + Response response{ Response::createOkResponse(context.getServerProtocolVersion()) }; Response::Node& newestPodcastsNode{ response.createNode("newestPodcasts") }; newestPodcastsNode.createEmptyArrayChild("episode"); { - auto transaction{ context.dbSession.createReadTransaction() }; + auto transaction{ context.getDbSession().createReadTransaction() }; db::PodcastEpisode::FindParameters findParameters; findParameters.setRange(db::Range{ .offset = 0, .size = count }); - db::PodcastEpisode::find(context.dbSession, findParameters, [&](const db::PodcastEpisode::pointer& episode) { + db::PodcastEpisode::find(context.getDbSession(), findParameters, [&](const db::PodcastEpisode::pointer& episode) { newestPodcastsNode.addArrayChild("episode", createPodcastEpisodeNode(episode)); }); } @@ -88,13 +88,13 @@ namespace lms::api::subsonic { core::Service::get()->refreshPodcasts(); - return Response::createOkResponse(context.serverProtocolVersion); + return Response::createOkResponse(context.getServerProtocolVersion()); } Response handleCreatePodcastChannel(RequestContext& context) { // Mandatory parameters - const std::string url{ getMandatoryParameterAs(context.parameters, "url") }; + const std::string url{ getMandatoryParameterAs(context.getParameters(), "url") }; if (url.empty() || !(url.starts_with("http://") || url.starts_with("https://"))) throw BadParameterGenericError{ "Invalid url" }; @@ -102,52 +102,52 @@ namespace lms::api::subsonic // no effect if podcast already exists core::Service::get()->addPodcast(url); - return Response::createOkResponse(context.serverProtocolVersion); + return Response::createOkResponse(context.getServerProtocolVersion()); } Response handleDeletePodcastChannel(RequestContext& context) { // Mandatory parameters - const db::PodcastId podcastId{ getMandatoryParameterAs(context.parameters, "id") }; + const db::PodcastId podcastId{ getMandatoryParameterAs(context.getParameters(), "id") }; if (!core::Service::get()->removePodcast(podcastId)) throw RequestedDataNotFoundError{}; - return Response::createOkResponse(context.serverProtocolVersion); + return Response::createOkResponse(context.getServerProtocolVersion()); } Response handleDeletePodcastEpisode(RequestContext& context) { // Mandatory parameters - const db::PodcastEpisodeId episodeId{ getMandatoryParameterAs(context.parameters, "id") }; + const db::PodcastEpisodeId episodeId{ getMandatoryParameterAs(context.getParameters(), "id") }; if (!core::Service::get()->deletePodcastEpisode(episodeId)) throw RequestedDataNotFoundError{}; - return Response::createOkResponse(context.serverProtocolVersion); + return Response::createOkResponse(context.getServerProtocolVersion()); } Response handleDownloadPodcastEpisode(RequestContext& context) { // Mandatory parameters - const db::PodcastEpisodeId episodeId{ getMandatoryParameterAs(context.parameters, "id") }; + const db::PodcastEpisodeId episodeId{ getMandatoryParameterAs(context.getParameters(), "id") }; if (!core::Service::get()->downloadPodcastEpisode(episodeId)) throw RequestedDataNotFoundError{}; - return Response::createOkResponse(context.serverProtocolVersion); + return Response::createOkResponse(context.getServerProtocolVersion()); } Response handleGetPodcastEpisode(RequestContext& context) { // Mandatory parameters - const db::PodcastEpisodeId episodeId{ getMandatoryParameterAs(context.parameters, "id") }; + const db::PodcastEpisodeId episodeId{ 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() }; - const db::PodcastEpisode::pointer episode{ db::PodcastEpisode::find(context.dbSession, episodeId) }; + const db::PodcastEpisode::pointer episode{ db::PodcastEpisode::find(context.getDbSession(), episodeId) }; if (!episode) throw RequestedDataNotFoundError{}; diff --git a/src/libs/subsonic/impl/endpoints/Searching.cpp b/src/libs/subsonic/impl/endpoints/Searching.cpp index f38f1519..c8119c9d 100644 --- a/src/libs/subsonic/impl/endpoints/Searching.cpp +++ b/src/libs/subsonic/impl/endpoints/Searching.cpp @@ -118,14 +118,14 @@ namespace lms::api::subsonic { // For now, no need to optimize all this // Find all the directories that match the name and that do not contain any track (considered by the legacy API as artists) - const std::size_t artistCount{ getParameterAs(context.parameters, "artistCount").value_or(20) }; + const std::size_t artistCount{ getParameterAs(context.getParameters(), "artistCount").value_or(20) }; if (artistCount == 0) return; if (artistCount > defaultMaxCountSize) throw ParameterValueTooHighGenericError{ "artistCount", defaultMaxCountSize }; - const std::size_t artistOffset{ getParameterAs(context.parameters, "artistOffset").value_or(0) }; + const std::size_t artistOffset{ getParameterAs(context.getParameters(), "artistOffset").value_or(0) }; Directory::FindParameters params; params.setKeywords(keywords); @@ -133,7 +133,7 @@ namespace lms::api::subsonic params.setWithNoTrack(true); params.setMediaLibrary(mediaLibrary); - Directory::find(context.dbSession, params, [&](const Directory::pointer& directory) { + Directory::find(context.getDbSession(), params, [&](const Directory::pointer& directory) { Response::Node childNode; childNode.setAttribute("id", idToString(directory->getId())); childNode.setAttribute("name", directory->getName()); @@ -147,14 +147,14 @@ namespace lms::api::subsonic { static ScanTracker currentScansInProgress; - const std::size_t artistCount{ getParameterAs(context.parameters, "artistCount").value_or(20) }; + const std::size_t artistCount{ getParameterAs(context.getParameters(), "artistCount").value_or(20) }; if (artistCount == 0) return; if (artistCount > defaultMaxCountSize) throw ParameterValueTooHighGenericError{ "artistCount", defaultMaxCountSize }; - const std::size_t artistOffset{ getParameterAs(context.parameters, "artistOffset").value_or(0) }; + const std::size_t artistOffset{ getParameterAs(context.getParameters(), "artistOffset").value_or(0) }; ArtistId lastRetrievedId; auto findArtists{ [&] { @@ -164,7 +164,7 @@ namespace lms::api::subsonic params.setRange(Range{ artistOffset, artistCount }); params.setSortMethod(ArtistSortMethod::Id); // must be consistent with both methods - Artist::find(context.dbSession, params, [&](const Artist::pointer& artist) { + Artist::find(context.getDbSession(), params, [&](const Artist::pointer& artist) { searchResultNode.addArrayChild("artist", createArtistNode(context, artist)); lastRetrievedId = artist->getId(); }); @@ -177,9 +177,9 @@ namespace lms::api::subsonic else { ScanTracker::ScanInfo scanInfo{ - .clientAddress = context.clientIpAddr, - .clientName = context.clientInfo.name, - .user = context.user->getId(), + .clientAddress = context.getClientIpAddr(), + .clientName = std::string{ context.getClientName() }, + .user = context.getUser()->getId(), .library = mediaLibrary, .offset = artistOffset }; @@ -187,7 +187,7 @@ namespace lms::api::subsonic if (ArtistId cachedLastRetrievedId{ currentScansInProgress.extractLastRetrievedObjectId(scanInfo) }; cachedLastRetrievedId.isValid()) { Artist::find( - context.dbSession, cachedLastRetrievedId, artistCount, [&](const Artist::pointer& artist) { + context.getDbSession(), cachedLastRetrievedId, artistCount, [&](const Artist::pointer& artist) { searchResultNode.addArrayChild("artist", createArtistNode(context, artist)); }, mediaLibrary); @@ -210,14 +210,14 @@ namespace lms::api::subsonic { static ScanTracker currentScansInProgress; - const std::size_t albumCount{ getParameterAs(context.parameters, "albumCount").value_or(20) }; + const std::size_t albumCount{ getParameterAs(context.getParameters(), "albumCount").value_or(20) }; if (albumCount == 0) return; if (albumCount > defaultMaxCountSize) throw ParameterValueTooHighGenericError{ "albumCount", defaultMaxCountSize }; - const std::size_t albumOffset{ getParameterAs(context.parameters, "albumOffset").value_or(0) }; + const std::size_t albumOffset{ getParameterAs(context.getParameters(), "albumOffset").value_or(0) }; ReleaseId lastRetrievedId; @@ -228,7 +228,7 @@ namespace lms::api::subsonic params.filters.setMediaLibrary(mediaLibrary); params.setSortMethod(ReleaseSortMethod::Id); // must be consistent with both methods - Release::find(context.dbSession, params, [&](const Release::pointer& release) { + Release::find(context.getDbSession(), params, [&](const Release::pointer& release) { searchResultNode.addArrayChild("album", createAlbumNode(context, release, id3)); lastRetrievedId = release->getId(); }); @@ -241,9 +241,9 @@ namespace lms::api::subsonic else { ScanTracker::ScanInfo scanInfo{ - .clientAddress = context.clientIpAddr, - .clientName = context.clientInfo.name, - .user = context.user->getId(), + .clientAddress = context.getClientIpAddr(), + .clientName = std::string{ context.getClientName() }, + .user = context.getUser()->getId(), .library = mediaLibrary, .offset = albumOffset }; @@ -251,7 +251,7 @@ namespace lms::api::subsonic if (ReleaseId cachedLastRetrievedId{ currentScansInProgress.extractLastRetrievedObjectId(scanInfo) }; cachedLastRetrievedId.isValid()) { Release::find( - context.dbSession, cachedLastRetrievedId, albumCount, [&](const Release::pointer& release) { + context.getDbSession(), cachedLastRetrievedId, albumCount, [&](const Release::pointer& release) { searchResultNode.addArrayChild("album", createAlbumNode(context, release, id3)); }, mediaLibrary); @@ -274,14 +274,14 @@ namespace lms::api::subsonic { static ScanTracker currentScansInProgress; - const std::size_t songCount{ getParameterAs(context.parameters, "songCount").value_or(20) }; + const std::size_t songCount{ getParameterAs(context.getParameters(), "songCount").value_or(20) }; if (songCount == 0) return; if (songCount > defaultMaxCountSize) throw ParameterValueTooHighGenericError{ "songCount", defaultMaxCountSize }; - const std::size_t songOffset{ getParameterAs(context.parameters, "songOffset").value_or(0) }; + const std::size_t songOffset{ getParameterAs(context.getParameters(), "songOffset").value_or(0) }; TrackId lastRetrievedId; @@ -292,7 +292,7 @@ namespace lms::api::subsonic params.filters.setMediaLibrary(mediaLibrary); params.setSortMethod(TrackSortMethod::Id); // must be consistent with both methods - Track::find(context.dbSession, params, [&](const Track::pointer& track) { + Track::find(context.getDbSession(), params, [&](const Track::pointer& track) { searchResultNode.addArrayChild("song", createSongNode(context, track, id3)); lastRetrievedId = track->getId(); }); @@ -305,9 +305,9 @@ namespace lms::api::subsonic else { ScanTracker::ScanInfo scanInfo{ - .clientAddress = context.clientIpAddr, - .clientName = context.clientInfo.name, - .user = context.user->getId(), + .clientAddress = context.getClientIpAddr(), + .clientName = std::string{ context.getClientName() }, + .user = context.getUser()->getId(), .library = mediaLibrary, .offset = songOffset }; @@ -315,7 +315,7 @@ namespace lms::api::subsonic if (TrackId cachedLastRetrievedId{ currentScansInProgress.extractLastRetrievedObjectId(scanInfo) }; cachedLastRetrievedId.isValid()) { Track::find( - context.dbSession, cachedLastRetrievedId, songCount, [&](const Track::pointer& track) { + context.getDbSession(), cachedLastRetrievedId, songCount, [&](const Track::pointer& track) { searchResultNode.addArrayChild("song", createSongNode(context, track, id3)); }, mediaLibrary); @@ -337,24 +337,24 @@ namespace lms::api::subsonic Response handleSearchRequestCommon(RequestContext& context, bool id3) { // Mandatory params - const std::string queryString{ getMandatoryParameterAs(context.parameters, "query") }; + const std::string queryString{ getMandatoryParameterAs(context.getParameters(), "query") }; std::string_view query{ queryString }; // Optional params - const MediaLibraryId mediaLibrary{ getParameterAs(context.parameters, "musicFolderId").value_or(MediaLibraryId{}) }; + const MediaLibraryId mediaLibrary{ getParameterAs(context.getParameters(), "musicFolderId").value_or(MediaLibraryId{}) }; // Symfonium adds extra "" - if (context.clientInfo.name == "Symfonium") + if (context.getClientName() == "Symfonium") query = core::stringUtils::stringTrim(query, "\""); std::vector keywords; if (!query.empty()) keywords = core::stringUtils::splitString(query, ' '); - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; + Response response{ Response::createOkResponse(context.getServerProtocolVersion()) }; Response::Node& searchResultNode{ response.createNode(id3 ? "searchResult3" : "searchResult2") }; - auto transaction{ context.dbSession.createReadTransaction() }; + auto transaction{ context.getDbSession().createReadTransaction() }; if (id3) findRequestedArtists(context, keywords, mediaLibrary, searchResultNode); diff --git a/src/libs/subsonic/impl/endpoints/System.cpp b/src/libs/subsonic/impl/endpoints/System.cpp index fd89ccf2..1b195949 100644 --- a/src/libs/subsonic/impl/endpoints/System.cpp +++ b/src/libs/subsonic/impl/endpoints/System.cpp @@ -4,12 +4,12 @@ namespace lms::api::subsonic { Response handlePingRequest(RequestContext& context) { - return Response::createOkResponse(context.serverProtocolVersion); + return Response::createOkResponse(context.getServerProtocolVersion()); } Response handleGetLicenseRequest(RequestContext& context) { - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; + Response response{ Response::createOkResponse(context.getServerProtocolVersion()) }; Response::Node& licenseNode{ response.createNode("license") }; licenseNode.setAttribute("licenseExpires", "2035-09-03T14:46:43"); @@ -21,7 +21,7 @@ namespace lms::api::subsonic Response handleGetOpenSubsonicExtensions(RequestContext& context) { - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; + Response response{ Response::createOkResponse(context.getServerProtocolVersion()) }; { Response::Node& transcodeOffsetNode{ response.createArrayNode("openSubsonicExtensions") }; diff --git a/src/libs/subsonic/impl/endpoints/UserManagement.cpp b/src/libs/subsonic/impl/endpoints/UserManagement.cpp index 541b2a46..2781db15 100644 --- a/src/libs/subsonic/impl/endpoints/UserManagement.cpp +++ b/src/libs/subsonic/impl/endpoints/UserManagement.cpp @@ -16,24 +16,24 @@ namespace lms::api::subsonic { void checkUserIsMySelfOrAdmin(RequestContext& context, const std::string& username) { - if (context.user->getLoginName() != username && !context.user->isAdmin()) + if (context.getUser()->getLoginName() != username && !context.getUser()->isAdmin()) throw UserNotAuthorizedError{}; } } // namespace Response handleGetUserRequest(RequestContext& context) { - std::string username{ getMandatoryParameterAs(context.parameters, "username") }; + std::string username{ getMandatoryParameterAs(context.getParameters(), "username") }; - auto transaction{ context.dbSession.createReadTransaction() }; + auto transaction{ context.getDbSession().createReadTransaction() }; checkUserIsMySelfOrAdmin(context, username); - const User::pointer user{ User::find(context.dbSession, username) }; + const User::pointer user{ User::find(context.getDbSession(), username) }; if (!user) throw RequestedDataNotFoundError{}; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; + Response response{ Response::createOkResponse(context.getServerProtocolVersion()) }; response.addNode("user", createUserNode(context, user)); return response; @@ -41,11 +41,11 @@ namespace lms::api::subsonic Response handleGetUsersRequest(RequestContext& context) { - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; + Response response{ Response::createOkResponse(context.getServerProtocolVersion()) }; Response::Node& usersNode{ response.createNode("users") }; - auto transaction{ context.dbSession.createReadTransaction() }; - User::find(context.dbSession, User::FindParameters{}, [&](const User::pointer& user) { + auto transaction{ context.getDbSession().createReadTransaction() }; + User::find(context.getDbSession(), User::FindParameters{}, [&](const User::pointer& user) { usersNode.addArrayChild("user", createUserNode(context, user)); }); diff --git a/src/libs/subsonic/impl/responses/Album.cpp b/src/libs/subsonic/impl/responses/Album.cpp index 9ac5387f..61eaa8d1 100644 --- a/src/libs/subsonic/impl/responses/Album.cpp +++ b/src/libs/subsonic/impl/responses/Album.cpp @@ -69,7 +69,7 @@ namespace lms::api::subsonic Directory::FindParameters params; params.setRelease(release->getId()); params.setRange(Range{ 0, 1 }); // only support 1 directory <-> 1 release - Directory::find(context.dbSession, params, [&](const Directory::pointer& foundDirectory) { + Directory::find(context.getDbSession(), params, [&](const Directory::pointer& foundDirectory) { directoryToReport = foundDirectory; }); } @@ -116,10 +116,10 @@ namespace lms::api::subsonic } } - albumNode.setAttribute("playCount", core::Service::get()->getCount(context.user->getId(), release->getId())); + albumNode.setAttribute("playCount", core::Service::get()->getCount(context.getUser()->getId(), release->getId())); // Report the first GENRE for this track - const ClusterType::pointer genreClusterType{ ClusterType::find(context.dbSession, "GENRE") }; + const ClusterType::pointer genreClusterType{ ClusterType::find(context.getDbSession(), "GENRE") }; if (genreClusterType) { const auto clusters{ release->getClusters(genreClusterType->getId(), 1) }; @@ -127,14 +127,14 @@ namespace lms::api::subsonic albumNode.setAttribute("genre", clusters.front()->getName()); } - if (const Wt::WDateTime dateTime{ core::Service::get()->getStarredDateTime(context.user->getId(), release->getId()) }; dateTime.isValid()) + if (const Wt::WDateTime dateTime{ core::Service::get()->getStarredDateTime(context.getUser()->getId(), release->getId()) }; dateTime.isValid()) albumNode.setAttribute("starred", core::stringUtils::toISO8601String(dateTime)); // Always report user rating, even if legacy API only specified it for directories - if (const auto rating{ core::Service::get()->getRating(context.user->getId(), release->getId()) }) + if (const auto rating{ core::Service::get()->getRating(context.getUser()->getId(), release->getId()) }) albumNode.setAttribute("userRating", *rating); - if (!context.enableOpenSubsonic) + if (!context.isOpenSubsonicEnabled()) return albumNode; // OpenSubsonic specific fields (must always be set) @@ -143,7 +143,7 @@ namespace lms::api::subsonic albumNode.setAttribute("mediaType", "album"); { - const Wt::WDateTime dateTime{ core::Service::get()->getLastListenDateTime(context.user->getId(), release->getId()) }; + const Wt::WDateTime dateTime{ core::Service::get()->getLastListenDateTime(context.getUser()->getId(), release->getId()) }; albumNode.setAttribute("played", dateTime.isValid() ? core::stringUtils::toISO8601String(dateTime) : std::string{ "" }); } @@ -159,7 +159,7 @@ namespace lms::api::subsonic params.setRelease(release->getId()); params.setClusterTypeName(clusterTypeName); - Cluster::find(context.dbSession, params, [&](const Cluster::pointer& cluster) { + Cluster::find(context.getDbSession(), params, [&](const Cluster::pointer& cluster) { albumNode.addArrayValue(field, cluster->getName()); }); } }; @@ -174,7 +174,7 @@ namespace lms::api::subsonic params.setRelease(release->getId()); params.setClusterType(genreClusterType->getId()); - Cluster::find(context.dbSession, params, [&](const Cluster::pointer& cluster) { + Cluster::find(context.getDbSession(), params, [&](const Cluster::pointer& cluster) { albumNode.addArrayChild("genres", createItemGenreNode(cluster->getName())); }); } diff --git a/src/libs/subsonic/impl/responses/AlbumInfo.cpp b/src/libs/subsonic/impl/responses/AlbumInfo.cpp index 0463609a..e58b07c7 100644 --- a/src/libs/subsonic/impl/responses/AlbumInfo.cpp +++ b/src/libs/subsonic/impl/responses/AlbumInfo.cpp @@ -31,7 +31,7 @@ namespace lms::api::subsonic if (const auto releaseMBID{ release->getMBID() }) { - switch (context.responseFormat) + switch (context.getResponseFormat()) { case ResponseFormat::json: albumInfo.setAttribute("musicBrainzId", releaseMBID->getAsString()); diff --git a/src/libs/subsonic/impl/responses/Artist.cpp b/src/libs/subsonic/impl/responses/Artist.cpp index 08ad7cf7..a54da524 100644 --- a/src/libs/subsonic/impl/responses/Artist.cpp +++ b/src/libs/subsonic/impl/responses/Artist.cpp @@ -101,17 +101,17 @@ namespace lms::api::subsonic artistNode.setAttribute("coverArt", idToString(coverArtId)); } - const std::size_t count{ Release::getCount(context.dbSession, Release::FindParameters{}.setArtist(artist->getId())) }; + const std::size_t count{ Release::getCount(context.getDbSession(), Release::FindParameters{}.setArtist(artist->getId())) }; artistNode.setAttribute("albumCount", count); - if (const Wt::WDateTime dateTime{ core::Service::get()->getStarredDateTime(context.user->getId(), artist->getId()) }; dateTime.isValid()) + if (const Wt::WDateTime dateTime{ core::Service::get()->getStarredDateTime(context.getUser()->getId(), artist->getId()) }; dateTime.isValid()) artistNode.setAttribute("starred", core::stringUtils::toISO8601String(dateTime)); - if (const auto rating{ core::Service::get()->getRating(context.user->getId(), artist->getId()) }) + if (const auto rating{ core::Service::get()->getRating(context.getUser()->getId(), artist->getId()) }) artistNode.setAttribute("userRating", *rating); // OpenSubsonic specific fields (must always be set) - if (context.enableOpenSubsonic) + if (context.isOpenSubsonicEnabled()) { artistNode.setAttribute("mediaType", "artist"); @@ -125,7 +125,7 @@ namespace lms::api::subsonic // roles Response::Node roles; artistNode.createEmptyArrayValue("roles"); - for (const TrackArtistLinkType linkType : TrackArtistLink::findUsedTypes(context.dbSession, artist->getId())) + for (const TrackArtistLinkType linkType : TrackArtistLink::findUsedTypes(context.getDbSession(), artist->getId())) artistNode.addArrayValue("roles", utils::toString(linkType)); } diff --git a/src/libs/subsonic/impl/responses/Genre.cpp b/src/libs/subsonic/impl/responses/Genre.cpp index 0b0504d4..9bc491fe 100644 --- a/src/libs/subsonic/impl/responses/Genre.cpp +++ b/src/libs/subsonic/impl/responses/Genre.cpp @@ -29,7 +29,7 @@ namespace lms::api::subsonic { Response::Node clusterNode; - switch (context.responseFormat) + switch (context.getResponseFormat()) { case ResponseFormat::json: clusterNode.setAttribute("value", cluster->getName()); diff --git a/src/libs/subsonic/impl/responses/Lyrics.cpp b/src/libs/subsonic/impl/responses/Lyrics.cpp index 2273d046..eb32438b 100644 --- a/src/libs/subsonic/impl/responses/Lyrics.cpp +++ b/src/libs/subsonic/impl/responses/Lyrics.cpp @@ -55,7 +55,7 @@ namespace lms::api::subsonic addLine(std::move(line)); } - switch (context.responseFormat) + switch (context.getResponseFormat()) { case ResponseFormat::json: lyricsNode.setAttribute("value", lyricsText); @@ -89,7 +89,7 @@ namespace lms::api::subsonic if (timestamp) lineNode.setAttribute("start", std::chrono::duration_cast(*timestamp).count()); - switch (context.responseFormat) + switch (context.getResponseFormat()) { case ResponseFormat::json: lineNode.setAttribute("value", std::move(line)); diff --git a/src/libs/subsonic/impl/responses/Playlist.cpp b/src/libs/subsonic/impl/responses/Playlist.cpp index e3a9befb..2ba03013 100644 --- a/src/libs/subsonic/impl/responses/Playlist.cpp +++ b/src/libs/subsonic/impl/responses/Playlist.cpp @@ -48,7 +48,7 @@ namespace lms::api::subsonic if (const db::ArtworkId artworkId{ core::Service::get()->findTrackListImage(tracklist->getId()) }; artworkId.isValid()) { - if (const auto artwork{ db::Artwork::find(context.dbSession, artworkId) }) + if (const auto artwork{ db::Artwork::find(context.getDbSession(), artworkId) }) { CoverArtId coverArtId{ artwork->getId(), artwork->getLastWrittenTime().toTime_t() }; playlistNode.setAttribute("coverArt", idToString(coverArtId)); diff --git a/src/libs/subsonic/impl/responses/Podcast.cpp b/src/libs/subsonic/impl/responses/Podcast.cpp index aab4be08..4f89d1f0 100644 --- a/src/libs/subsonic/impl/responses/Podcast.cpp +++ b/src/libs/subsonic/impl/responses/Podcast.cpp @@ -125,7 +125,7 @@ namespace lms::api::subsonic params.setPodcast(podcast->getId()); params.setSortMode(db::PodcastEpisodeSortMode::PubDateDesc); - db::PodcastEpisode::find(context.dbSession, params, [&](const db::PodcastEpisode::pointer& episode) { + db::PodcastEpisode::find(context.getDbSession(), params, [&](const db::PodcastEpisode::pointer& episode) { podcastNode.addArrayChild("episode", createPodcastEpisodeNode(episode)); }); } diff --git a/src/libs/subsonic/impl/responses/Song.cpp b/src/libs/subsonic/impl/responses/Song.cpp index b9ae638f..87a0d753 100644 --- a/src/libs/subsonic/impl/responses/Song.cpp +++ b/src/libs/subsonic/impl/responses/Song.cpp @@ -100,7 +100,7 @@ namespace lms::api::subsonic trackResponse.setAttribute("year", *originalYear); else if (const auto year{ track->getYear() }) trackResponse.setAttribute("year", *year); - trackResponse.setAttribute("playCount", core::Service::get()->getCount(context.user->getId(), track->getId())); + trackResponse.setAttribute("playCount", core::Service::get()->getCount(context.getUser()->getId(), track->getId())); // maybe not available if user just removed the library without rescanning if (const db::MediaLibrary::pointer library{ track->getMediaLibrary() }) @@ -119,9 +119,9 @@ namespace lms::api::subsonic trackResponse.setAttribute("suffix", extension.string().substr(1) /* skip leading .*/); } - if (context.user->getSubsonicEnableTranscodingByDefault()) + if (context.getUser()->getSubsonicEnableTranscodingByDefault()) { - const std::string fileSuffix{ formatToSuffix(context.user->getSubsonicDefaultTranscodingOutputFormat()) }; + const std::string fileSuffix{ formatToSuffix(context.getUser()->getSubsonicDefaultTranscodingOutputFormat()) }; trackResponse.setAttribute("transcodedSuffix", fileSuffix); trackResponse.setAttribute("transcodedContentType", core::getMimeType(std::filesystem::path{ "." + fileSuffix })); } @@ -160,10 +160,10 @@ namespace lms::api::subsonic trackResponse.setAttribute("type", "music"); trackResponse.setAttribute("created", core::stringUtils::toISO8601String(track->getAddedTime())); trackResponse.setAttribute("contentType", core::getMimeType(track->getAbsoluteFilePath().extension())); - if (const auto rating{ core::Service::get()->getRating(context.user->getId(), track->getId()) }) + if (const auto rating{ core::Service::get()->getRating(context.getUser()->getId(), track->getId()) }) trackResponse.setAttribute("userRating", *rating); - if (const Wt::WDateTime dateTime{ core::Service::get()->getStarredDateTime(context.user->getId(), track->getId()) }; dateTime.isValid()) + if (const Wt::WDateTime dateTime{ core::Service::get()->getStarredDateTime(context.getUser()->getId(), track->getId()) }; dateTime.isValid()) trackResponse.setAttribute("starred", core::stringUtils::toISO8601String(dateTime)); // Report the first GENRE for this track @@ -173,13 +173,13 @@ namespace lms::api::subsonic params.setTrack(track->getId()); params.setClusterTypeName("GENRE"); - genres = Cluster::find(context.dbSession, params).results; + genres = Cluster::find(context.getDbSession(), params).results; if (!genres.empty()) trackResponse.setAttribute("genre", genres.front()->getName()); } // OpenSubsonic specific fields (must always be set) - if (!context.enableOpenSubsonic) + if (!context.isOpenSubsonicEnabled()) return trackResponse; trackResponse.setAttribute("comment", track->getComment()); @@ -190,7 +190,7 @@ namespace lms::api::subsonic trackResponse.setAttribute("mediaType", "song"); { - const Wt::WDateTime dateTime{ core::Service::get()->getLastListenDateTime(context.user->getId(), track->getId()) }; + const Wt::WDateTime dateTime{ core::Service::get()->getLastListenDateTime(context.getUser()->getId(), track->getId()) }; trackResponse.setAttribute("played", dateTime.isValid() ? core::stringUtils::toISO8601String(dateTime) : ""); } @@ -204,7 +204,7 @@ namespace lms::api::subsonic trackResponse.createEmptyArrayChild("artists"); trackResponse.createEmptyArrayChild("contributors"); - TrackArtistLink::find(context.dbSession, track->getId(), [&](const TrackArtistLink::pointer& link, const Artist::pointer& artist) { + TrackArtistLink::find(context.getDbSession(), track->getId(), [&](const TrackArtistLink::pointer& link, const Artist::pointer& artist) { switch (link->getType()) { case TrackArtistLinkType::Artist: @@ -230,7 +230,7 @@ namespace lms::api::subsonic params.setTrack(track->getId()); params.setClusterTypeName(clusterTypeName); - for (const auto& cluster : Cluster::find(context.dbSession, params).results) + for (const auto& cluster : Cluster::find(context.getDbSession(), params).results) trackResponse.addArrayValue(field, cluster->getName()); } }; diff --git a/src/libs/subsonic/impl/responses/User.cpp b/src/libs/subsonic/impl/responses/User.cpp index 81d4d786..567f12eb 100644 --- a/src/libs/subsonic/impl/responses/User.cpp +++ b/src/libs/subsonic/impl/responses/User.cpp @@ -46,7 +46,7 @@ namespace lms::api::subsonic userNode.setAttribute("shareRole", false); // not supported // users can access all libraries - db::MediaLibrary::find(context.dbSession, [&](const db::MediaLibrary::pointer& library) { + db::MediaLibrary::find(context.getDbSession(), [&](const db::MediaLibrary::pointer& library) { userNode.addArrayValue("folder", library->getId().getValue()); });