Extracted lists entry points

This commit is contained in:
emeric
2023-10-01 21:13:36 +02:00
parent 955320e3a8
commit c3184636ab
4 changed files with 306 additions and 245 deletions
+1 -245
View File
@@ -46,6 +46,7 @@
#include "utils/String.hpp"
#include "utils/Utils.hpp"
#include "entrypoints/AlbumSongLists.hpp"
#include "entrypoints/Bookmarks.hpp"
#include "entrypoints/MediaLibraryScanning.hpp"
#include "entrypoints/MediaRetrieval.hpp"
@@ -263,156 +264,6 @@ handleGetLicenseRequest(RequestContext& context)
return response;
}
static
Response
handleGetRandomSongsRequest(RequestContext& context)
{
// Optional params
std::size_t size {getParameterAs<std::size_t>(context.parameters, "size").value_or(50)};
size = std::min(size, std::size_t {500});
auto transaction {context.dbSession.createSharedTransaction()};
User::pointer user {User::find(context.dbSession, context.userId)};
if (!user)
throw UserNotAuthorizedError {};
const auto trackIds {Track::find(context.dbSession, Track::FindParameters {}.setSortMethod(TrackSortMethod::Random).setRange({0, size}))};
Response response {Response::createOkResponse(context.serverProtocolVersion)};
Response::Node& randomSongsNode {response.createNode("randomSongs")};
for (const TrackId trackId : trackIds.results)
{
const Track::pointer track {Track::find(context.dbSession, trackId)};
randomSongsNode.addArrayChild("song", createSongNode(track, context.dbSession, user));
}
return response;
}
static
Response
handleGetAlbumListRequestCommon(const RequestContext& context, bool id3)
{
// Mandatory params
const std::string type {getMandatoryParameterAs<std::string>(context.parameters, "type")};
// Optional params
const std::size_t size {getParameterAs<std::size_t>(context.parameters, "size").value_or(10)};
const std::size_t offset {getParameterAs<std::size_t>(context.parameters, "offset").value_or(0)};
const Range range {offset, size};
RangeResults<ReleaseId> releases;
Scrobbling::IScrobblingService& scrobbling {*Service<Scrobbling::IScrobblingService>::get()};
auto transaction {context.dbSession.createSharedTransaction()};
User::pointer user {User::find(context.dbSession, context.userId)};
if (!user)
throw UserNotAuthorizedError {};
if (type == "alphabeticalByName")
{
Release::FindParameters params;
params.setSortMethod(ReleaseSortMethod::Name);
params.setRange(range);
releases = Release::find(context.dbSession, params);
}
else if (type == "alphabeticalByArtist")
{
releases = Release::findOrderedByArtist(context.dbSession, range);
}
else if (type == "byGenre")
{
// Mandatory param
const std::string genre {getMandatoryParameterAs<std::string>(context.parameters, "genre")};
if (const ClusterType::pointer clusterType {ClusterType::find(context.dbSession, genreClusterName)})
{
if (const Cluster::pointer cluster {clusterType->getCluster(genre)})
{
Release::FindParameters params;
params.setClusters({cluster->getId()});
params.setSortMethod(ReleaseSortMethod::Name);
params.setRange(range);
releases = Release::find(context.dbSession, params);
}
}
}
else if (type == "byYear")
{
const int fromYear {getMandatoryParameterAs<int>(context.parameters, "fromYear")};
const int toYear {getMandatoryParameterAs<int>(context.parameters, "toYear")};
Release::FindParameters params;
params.setSortMethod(ReleaseSortMethod::Date);
params.setRange(range);
params.setDateRange(DateRange::fromYearRange(fromYear, toYear));
releases = Release::find(context.dbSession, params);
}
else if (type == "frequent")
{
releases = scrobbling.getTopReleases(context.userId, {}, range);
}
else if (type == "newest")
{
Release::FindParameters params;
params.setSortMethod(ReleaseSortMethod::LastWritten);
params.setRange(range);
releases = Release::find(context.dbSession, params);
}
else if (type == "random")
{
// Random results are paginated, but there is no acceptable way to handle the pagination params without repeating some albums
// (no seed provided by subsonic, ot it would require to store some kind of context for each user/client when iterating over the random albums)
Release::FindParameters params;
params.setSortMethod(ReleaseSortMethod::Random);
params.setRange({0, size});
releases = Release::find(context.dbSession, params);
}
else if (type == "recent")
{
releases = scrobbling.getRecentReleases(context.userId, {}, range);
}
else if (type == "starred")
{
releases = scrobbling.getStarredReleases(context.userId, {}, range);
}
else
throw NotImplementedGenericError {};
Response response {Response::createOkResponse(context.serverProtocolVersion)};
Response::Node& albumListNode {response.createNode(id3 ? "albumList2" : "albumList")};
for (const ReleaseId releaseId : releases.results)
{
const Release::pointer release {Release::find(context.dbSession, releaseId)};
albumListNode.addArrayChild("album", createAlbumNode(release, context.dbSession, user, id3));
}
return response;
}
static
Response
handleGetAlbumListRequest(RequestContext& context)
{
return handleGetAlbumListRequestCommon(context, false /* no id3 */);
}
static
Response
handleGetAlbumList2Request(RequestContext& context)
{
return handleGetAlbumListRequestCommon(context, true /* id3 */);
}
static
Response
@@ -865,57 +716,6 @@ handleGetSimilarSongs2Request(RequestContext& context)
return handleGetSimilarSongsRequestCommon(context, true /* id3 */);
}
static
Response
handleGetStarredRequestCommon(RequestContext& context, bool id3)
{
auto transaction {context.dbSession.createSharedTransaction()};
User::pointer user {User::find(context.dbSession, context.userId)};
if (!user)
throw UserNotAuthorizedError {};
Response response {Response::createOkResponse(context.serverProtocolVersion)};
Response::Node& starredNode {response.createNode(id3 ? "starred2" : "starred")};
Scrobbling::IScrobblingService& scrobbling {*Service<Scrobbling::IScrobblingService>::get()};
for (const ArtistId artistId : scrobbling.getStarredArtists(context.userId, {} /* clusters */, std::nullopt /* linkType */, ArtistSortMethod::BySortName, Range {}).results)
{
if (auto artist {Artist::find(context.dbSession, artistId)})
starredNode.addArrayChild("artist", createArtistNode(artist, context.dbSession, user, id3));
}
for (const ReleaseId releaseId : scrobbling.getStarredReleases(context.userId, {} /* clusters */, Range {}).results)
{
if (auto release {Release::find(context.dbSession, releaseId)})
starredNode.addArrayChild("album", createAlbumNode(release, context.dbSession, user, id3));
}
for (const TrackId trackId : scrobbling.getStarredTracks(context.userId, {} /* clusters */, Range {}).results)
{
if (auto track {Track::find(context.dbSession, trackId)})
starredNode.addArrayChild("song", createSongNode(track, context.dbSession, user));
}
return response;
}
static
Response
handleGetStarredRequest(RequestContext& context)
{
return handleGetStarredRequestCommon(context, false /* no id3 */);
}
static
Response
handleGetStarred2Request(RequestContext& context)
{
return handleGetStarredRequestCommon(context, true /* id3 */);
}
static
Response::Node
tracklistToResponseNode(const TrackList::pointer& tracklist, Session&)
@@ -985,50 +785,6 @@ handleGetPlaylistsRequest(RequestContext& context)
return response;
}
static
Response
handleGetSongsByGenreRequest(RequestContext& context)
{
// Mandatory params
std::string genre {getMandatoryParameterAs<std::string>(context.parameters, "genre")};
// Optional params
std::size_t size {getParameterAs<std::size_t>(context.parameters, "count").value_or(10)};
size = std::min(size, std::size_t {500});
std::size_t offset {getParameterAs<std::size_t>(context.parameters, "offset").value_or(0)};
auto transaction {context.dbSession.createSharedTransaction()};
auto clusterType {ClusterType::find(context.dbSession, genreClusterName)};
if (!clusterType)
throw RequestedDataNotFoundError {};
auto cluster {clusterType->getCluster(genre)};
if (!cluster)
throw RequestedDataNotFoundError {};
User::pointer user {User::find(context.dbSession, context.userId)};
if (!user)
throw UserNotAuthorizedError {};
Response response {Response::createOkResponse(context.serverProtocolVersion)};
Response::Node& songsByGenreNode {response.createNode("songsByGenre")};
Track::FindParameters params;
params.setClusters({cluster->getId()});
params.setRange({offset, size});
auto trackIds {Track::find(context.dbSession, params)};
for (const TrackId trackId : trackIds.results)
{
const Track::pointer track {Track::find(context.dbSession, trackId)};
songsByGenreNode.addArrayChild("song", createSongNode(track, context.dbSession, user));
}
return response;
}
struct StarParameters
{
std::vector<ArtistId> artistIds;