diff --git a/src/libs/subsonic/CMakeLists.txt b/src/libs/subsonic/CMakeLists.txt index 5d043fe8..79fa40a3 100644 --- a/src/libs/subsonic/CMakeLists.txt +++ b/src/libs/subsonic/CMakeLists.txt @@ -2,6 +2,7 @@ add_library(lmssubsonic SHARED impl/entrypoints/AlbumSongLists.cpp impl/entrypoints/Bookmarks.cpp + impl/entrypoints/MediaAnnotation.cpp impl/entrypoints/MediaLibraryScanning.cpp impl/entrypoints/MediaRetrieval.cpp impl/entrypoints/Searching.cpp diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp index 2594acd9..1088498d 100644 --- a/src/libs/subsonic/impl/SubsonicResource.cpp +++ b/src/libs/subsonic/impl/SubsonicResource.cpp @@ -48,6 +48,7 @@ #include "entrypoints/AlbumSongLists.hpp" #include "entrypoints/Bookmarks.hpp" +#include "entrypoints/MediaAnnotation.hpp" #include "entrypoints/MediaLibraryScanning.hpp" #include "entrypoints/MediaRetrieval.hpp" #include "entrypoints/Searching.hpp" @@ -785,107 +786,6 @@ handleGetPlaylistsRequest(RequestContext& context) return response; } -struct StarParameters -{ - std::vector artistIds; - std::vector releaseIds; - std::vector trackIds; -}; - -static -StarParameters -getStarParameters(const Wt::Http::ParameterMap& parameters) -{ - StarParameters res; - - // TODO handle parameters for legacy file browsing - res.trackIds = getMultiParametersAs(parameters, "id"); - res.artistIds = getMultiParametersAs(parameters, "artistId"); - res.releaseIds = getMultiParametersAs(parameters, "albumId"); - - return res; -} - -static -Response -handleStarRequest(RequestContext& context) -{ - StarParameters params {getStarParameters(context.parameters)}; - - for (const ArtistId id : params.artistIds) - Service::get()->star(context.userId, id); - - for (const ReleaseId id : params.releaseIds) - Service::get()->star(context.userId, id); - - for (const TrackId id : params.trackIds) - Service::get()->star(context.userId, id); - - return Response::createOkResponse(context.serverProtocolVersion); -} - -static -Response -handleUnstarRequest(RequestContext& context) -{ - StarParameters params {getStarParameters(context.parameters)}; - - for (const ArtistId id : params.artistIds) - Service::get()->unstar(context.userId, id); - - for (const ReleaseId id : params.releaseIds) - Service::get()->unstar(context.userId, id); - - for (const TrackId id : params.trackIds) - Service::get()->unstar(context.userId, id); - - return Response::createOkResponse(context.serverProtocolVersion); -} - -static -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)}; - - // playing now => no time to be provided - if (!submission && !times.empty()) - throw BadParameterGenericError {"time"}; - - // playing now => only one at a time - if (!submission && ids.size() > 1) - throw BadParameterGenericError {"id"}; - - // if multiple submissions, must have times - if (ids.size() > 1 && ids.size() != times.size()) - throw BadParameterGenericError {"time"}; - - if (!submission) - { - Service::get()->listenStarted({context.userId, ids.front()}); - } - else - { - if (times.empty()) - { - Service::get()->listenFinished({context.userId, ids.front()}); - } - else - { - for (std::size_t i {}; i < ids.size(); ++i) - { - const TrackId trackId {ids[i]}; - const unsigned long time {times[i]}; - Service::get()->addTimedListen({{context.userId, trackId}, Wt::WDateTime::fromTime_t(static_cast(time / 1000))}); - } - } - } - - return Response::createOkResponse(context.serverProtocolVersion); -} - static Response handleUpdatePlaylistRequest(RequestContext& context) diff --git a/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp b/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp new file mode 100644 index 00000000..96aa7c2c --- /dev/null +++ b/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2023 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 "MediaAnnotation.hpp" + +#include + +#include "services/database/ArtistId.hpp" +#include "services/database/ReleaseId.hpp" +#include "services/database/TrackId.hpp" +#include "services/scrobbling/IScrobblingService.hpp" +#include "utils/Service.hpp" +#include "ParameterParsing.hpp" +#include "SubsonicId.hpp" + +namespace API::Subsonic +{ + using namespace Database; + + namespace + { + struct StarParameters + { + std::vector artistIds; + std::vector releaseIds; + std::vector trackIds; + }; + + StarParameters getStarParameters(const Wt::Http::ParameterMap& parameters) + { + StarParameters res; + + // TODO handle parameters for legacy file browsing + res.trackIds = getMultiParametersAs(parameters, "id"); + res.artistIds = getMultiParametersAs(parameters, "artistId"); + res.releaseIds = getMultiParametersAs(parameters, "albumId"); + + return res; + } + } + + Response handleStarRequest(RequestContext& context) + { + StarParameters params{ getStarParameters(context.parameters) }; + + for (const ArtistId id : params.artistIds) + Service::get()->star(context.userId, id); + + for (const ReleaseId id : params.releaseIds) + Service::get()->star(context.userId, id); + + for (const TrackId id : params.trackIds) + Service::get()->star(context.userId, id); + + return Response::createOkResponse(context.serverProtocolVersion); + } + + Response handleUnstarRequest(RequestContext& context) + { + StarParameters params{ getStarParameters(context.parameters) }; + + for (const ArtistId id : params.artistIds) + Service::get()->unstar(context.userId, id); + + for (const ReleaseId id : params.releaseIds) + Service::get()->unstar(context.userId, id); + + for (const TrackId id : params.trackIds) + Service::get()->unstar(context.userId, id); + + return Response::createOkResponse(context.serverProtocolVersion); + } + + 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) }; + + // playing now => no time to be provided + if (!submission && !times.empty()) + throw BadParameterGenericError{ "time" }; + + // playing now => only one at a time + if (!submission && ids.size() > 1) + throw BadParameterGenericError{ "id" }; + + // if multiple submissions, must have times + if (ids.size() > 1 && ids.size() != times.size()) + throw BadParameterGenericError{ "time" }; + + if (!submission) + { + Service::get()->listenStarted({ context.userId, ids.front() }); + } + else + { + if (times.empty()) + { + Service::get()->listenFinished({ context.userId, ids.front() }); + } + else + { + for (std::size_t i{}; i < ids.size(); ++i) + { + const TrackId trackId{ ids[i] }; + const unsigned long time{ times[i] }; + Service::get()->addTimedListen({ {context.userId, trackId}, Wt::WDateTime::fromTime_t(static_cast(time / 1000)) }); + } + } + } + + return Response::createOkResponse(context.serverProtocolVersion); + } +} \ No newline at end of file diff --git a/src/libs/subsonic/impl/entrypoints/MediaAnnotation.hpp b/src/libs/subsonic/impl/entrypoints/MediaAnnotation.hpp new file mode 100644 index 00000000..593d3bd3 --- /dev/null +++ b/src/libs/subsonic/impl/entrypoints/MediaAnnotation.hpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 Emeric Poupon + * + * This file is part of LMS. + * + * LMS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LMS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LMS. If not, see . + */ + +#pragma once + +#include "RequestContext.hpp" +#include "SubsonicResponse.hpp" + +namespace API::Subsonic +{ + Response handleStarRequest(RequestContext& context); + Response handleUnstarRequest(RequestContext& context); + Response handleScrobble(RequestContext& context); +} \ No newline at end of file