extracted bookmark handling

This commit is contained in:
emeric
2023-10-01 16:48:33 +02:00
parent 63bffa7631
commit abcf9e5b49
9 changed files with 224 additions and 98 deletions
+2
View File
@@ -2,8 +2,10 @@
add_library(lmssubsonic SHARED
impl/responses/Album.cpp
impl/responses/Artist.cpp
impl/responses/Bookmark.cpp
impl/responses/Song.cpp
impl/ProtocolVersion.cpp
impl/Bookmark.cpp
impl/Scan.cpp
impl/Stream.cpp
impl/SubsonicId.cpp
+104
View File
@@ -0,0 +1,104 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Bookmark.hpp"
#include "services/database/Session.hpp"
#include "services/database/User.hpp"
#include "services/database/Track.hpp"
#include "services/database/TrackBookmark.hpp"
#include "responses/Bookmark.hpp"
#include "responses/Song.hpp"
#include "ParameterParsing.hpp"
#include "SubsonicId.hpp"
namespace API::Subsonic
{
using namespace Database;
Response handleGetBookmarks(RequestContext& context)
{
auto transaction{ context.dbSession.createSharedTransaction() };
User::pointer user{ User::find(context.dbSession, context.userId) };
if (!user)
throw UserNotAuthorizedError{};
const auto bookmarkIds{ TrackBookmark::find(context.dbSession, user->getId(), Range {}) };
Response response{ Response::createOkResponse(context.serverProtocolVersion) };
Response::Node& bookmarksNode{ response.createNode("bookmarks") };
for (const TrackBookmarkId bookmarkId : bookmarkIds.results)
{
const TrackBookmark::pointer bookmark{ TrackBookmark::find(context.dbSession, bookmarkId) };
Response::Node bookmarkNode{ createBookmarkNode(bookmark) };
bookmarkNode.addArrayChild("entry", createSongNode(bookmark->getTrack(), context.dbSession, user));
bookmarksNode.addArrayChild("bookmark", std::move(bookmarkNode));
}
return response;
}
Response handleCreateBookmark(RequestContext& context)
{
// Mandatory params
TrackId trackId{ getMandatoryParameterAs<TrackId>(context.parameters, "id") };
unsigned long position{ getMandatoryParameterAs<unsigned long>(context.parameters, "position") };
const std::optional<std::string> comment{ getParameterAs<std::string>(context.parameters, "comment") };
auto transaction{ context.dbSession.createUniqueTransaction() };
const User::pointer user{ User::find(context.dbSession, context.userId) };
if (!user)
throw UserNotAuthorizedError{};
const Track::pointer track{ Track::find(context.dbSession, trackId) };
if (!track)
throw RequestedDataNotFoundError{};
// Replace any existing bookmark
auto bookmark{ TrackBookmark::find(context.dbSession, user->getId(), trackId) };
if (!bookmark)
bookmark = context.dbSession.create<TrackBookmark>(user, track);
bookmark.modify()->setOffset(std::chrono::milliseconds{ position });
if (comment)
bookmark.modify()->setComment(*comment);
return Response::createOkResponse(context.serverProtocolVersion);
}
Response handleDeleteBookmark(RequestContext& context)
{
// Mandatory params
TrackId trackId{ getMandatoryParameterAs<TrackId>(context.parameters, "id") };
auto transaction{ context.dbSession.createUniqueTransaction() };
auto bookmark{ TrackBookmark::find(context.dbSession, context.userId, trackId) };
if (!bookmark)
throw RequestedDataNotFoundError{};
bookmark.remove();
return Response::createOkResponse(context.serverProtocolVersion);
}
}
+32
View File
@@ -0,0 +1,32 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include "RequestContext.hpp"
#include "SubsonicResponse.hpp"
namespace API::Subsonic
{
Response handleGetBookmarks(RequestContext& context);
Response handleCreateBookmark(RequestContext& context);
Response handleDeleteBookmark(RequestContext& context);
}
+5 -96
View File
@@ -46,6 +46,11 @@
#include "utils/Service.hpp"
#include "utils/String.hpp"
#include "utils/Utils.hpp"
#include "responses/Artist.hpp"
#include "responses/Album.hpp"
#include "responses/Song.hpp"
#include "Bookmark.hpp"
#include "ParameterParsing.hpp"
#include "ProtocolVersion.hpp"
#include "RequestContext.hpp"
@@ -54,10 +59,6 @@
#include "SubsonicId.hpp"
#include "SubsonicResponse.hpp"
#include "responses/Artist.hpp"
#include "responses/Album.hpp"
#include "responses/Song.hpp"
using namespace Database;
static const std::string_view genreClusterName {"GENRE"};
@@ -186,22 +187,6 @@ checkUserTypeIsAllowed(RequestContext& context, EnumSet<Database::UserType> allo
throw UserNotAuthorizedError {};
}
static
Response::Node
trackBookmarkToResponseNode(const TrackBookmark::pointer& trackBookmark)
{
Response::Node trackBookmarkNode;
trackBookmarkNode.setAttribute("position", trackBookmark->getOffset().count());
if (!trackBookmark->getComment().empty())
trackBookmarkNode.setAttribute("comment", trackBookmark->getComment());
trackBookmarkNode.setAttribute("created", reportedDummyDate);
trackBookmarkNode.setAttribute("changed", reportedDummyDate);
trackBookmarkNode.setAttribute("username", trackBookmark->getUser()->getLoginName());
return trackBookmarkNode;
}
static
Response::Node
clusterToResponseNode(const Cluster::pointer& cluster)
@@ -1550,82 +1535,6 @@ handleUpdatePlaylistRequest(RequestContext& context)
return Response::createOkResponse(context.serverProtocolVersion);
}
static
Response
handleGetBookmarks(RequestContext& context)
{
auto transaction {context.dbSession.createSharedTransaction()};
User::pointer user {User::find(context.dbSession, context.userId)};
if (!user)
throw UserNotAuthorizedError {};
const auto bookmarkIds {TrackBookmark::find(context.dbSession, user->getId(), Range {})};
Response response {Response::createOkResponse(context.serverProtocolVersion)};
Response::Node& bookmarksNode {response.createNode("bookmarks")};
for (const TrackBookmarkId bookmarkId : bookmarkIds.results)
{
const TrackBookmark::pointer bookmark {TrackBookmark::find(context.dbSession, bookmarkId)};
Response::Node bookmarkNode {trackBookmarkToResponseNode(bookmark)};
bookmarkNode.addArrayChild("entry", createSongNode(bookmark->getTrack(), context.dbSession, user));
bookmarksNode.addArrayChild("bookmark", std::move(bookmarkNode));
}
return response ;
}
static
Response
handleCreateBookmark(RequestContext& context)
{
// Mandatory params
TrackId trackId {getMandatoryParameterAs<TrackId>(context.parameters, "id")};
unsigned long position {getMandatoryParameterAs<unsigned long>(context.parameters, "position")};
const std::optional<std::string> comment {getParameterAs<std::string>(context.parameters, "comment")};
auto transaction {context.dbSession.createUniqueTransaction()};
const User::pointer user {User::find(context.dbSession, context.userId)};
if (!user)
throw UserNotAuthorizedError {};
const Track::pointer track {Track::find(context.dbSession, trackId)};
if (!track)
throw RequestedDataNotFoundError {};
// Replace any existing bookmark
auto bookmark {TrackBookmark::find(context.dbSession, user->getId(), trackId)};
if (!bookmark)
bookmark = context.dbSession.create<TrackBookmark>(user, track);
bookmark.modify()->setOffset(std::chrono::milliseconds {position});
if (comment)
bookmark.modify()->setComment(*comment);
return Response::createOkResponse(context.serverProtocolVersion);
}
static
Response
handleDeleteBookmark(RequestContext& context)
{
// Mandatory params
TrackId trackId {getMandatoryParameterAs<TrackId>(context.parameters, "id")};
auto transaction {context.dbSession.createUniqueTransaction()};
auto bookmark {TrackBookmark::find(context.dbSession, context.userId, trackId)};
if (!bookmark)
throw RequestedDataNotFoundError {};
bookmark.remove();
return Response::createOkResponse(context.serverProtocolVersion);
}
static
Response
handleNotImplemented(RequestContext&)
+2 -1
View File
@@ -17,6 +17,8 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "responses/Album.hpp"
#include "services/database/Cluster.hpp"
#include "services/database/Artist.hpp"
#include "services/database/Release.hpp"
@@ -25,7 +27,6 @@
#include "utils/Service.hpp"
#include "utils/String.hpp"
#include "responses/Album.hpp"
#include "responses/Artist.hpp"
#include "SubsonicId.hpp"
@@ -18,6 +18,7 @@
*/
#include "responses/Artist.hpp"
#include "services/database/Artist.hpp"
#include "services/database/Release.hpp"
#include "services/database/User.hpp"
@@ -0,0 +1,43 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "responses/Bookmark.hpp"
#include "services/database/TrackBookmark.hpp"
#include "services/database/User.hpp"
#include "SubsonicResponse.hpp"
namespace API::Subsonic
{
static const std::string_view reportedDummyDate{ "2000-01-01T00:00:00" };
Response::Node createBookmarkNode(const Database::ObjectPtr<Database::TrackBookmark>& trackBookmark)
{
Response::Node trackBookmarkNode;
trackBookmarkNode.setAttribute("position", trackBookmark->getOffset().count());
if (!trackBookmark->getComment().empty())
trackBookmarkNode.setAttribute("comment", trackBookmark->getComment());
trackBookmarkNode.setAttribute("created", reportedDummyDate);
trackBookmarkNode.setAttribute("changed", reportedDummyDate);
trackBookmarkNode.setAttribute("username", trackBookmark->getUser()->getLoginName());
return trackBookmarkNode;
}
}
@@ -0,0 +1,33 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "services/database/Object.hpp"
#include "SubsonicResponse.hpp"
namespace Database
{
class TrackBookmark;
}
namespace API::Subsonic
{
Response::Node createBookmarkNode(const Database::ObjectPtr<Database::TrackBookmark>& bookmark);
}
+2 -1
View File
@@ -17,6 +17,8 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "responses/Song.hpp"
#include <string_view>
#include "services/database/Artist.hpp"
@@ -28,7 +30,6 @@
#include "utils/Service.hpp"
#include "utils/String.hpp"
#include "responses/Artist.hpp"
#include "responses/Song.hpp"
#include "SubsonicId.hpp"
namespace API::Subsonic