Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
tsshadow committed Jun 22, 2024
1 parent 7c2bc97 commit 73b62fa
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 9 deletions.
2 changes: 1 addition & 1 deletion docroot/css/bootstrap.solar.min.css

Large diffs are not rendered by default.

51 changes: 51 additions & 0 deletions src/libs/database/impl/Track.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,48 @@ namespace lms::db
return query;
}

template <typename ResultType>
Wt::Dbo::Query<ResultType> createCountQuery(Session& session, const Track::FindParameters& params)
{
session.checkReadTransaction();

auto query{ session.getDboSession()->query<ResultType>("SELECT COUNT(*) FROM track t") };

assert(params.keywords.empty() || params.name.empty());
for (std::string_view keyword : params.keywords)
query.where("t.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + utils::escapeLikeKeyword(keyword) + "%");

if (!params.name.empty())
query.where("t.name = ?").bind(params.name);

if (params.clusters.size() == 1)
{
// optim
query.join("track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(params.clusters.front());
}
else if (params.clusters.size() > 1)
{
std::ostringstream oss;
oss << "t.id IN (SELECT DISTINCT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";

WhereClause clusterClause;
for (const ClusterId clusterId : params.clusters)
{
clusterClause.Or(WhereClause("t_c.cluster_id = ?"));
query.bind(clusterId);
}

oss << " " << clusterClause.get();
oss << " GROUP BY t.id HAVING COUNT(*) = " << params.clusters.size() << ")";

query.where(oss.str());
}

return query;
}

template <typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, const Track::FindParameters& params)
{
Expand Down Expand Up @@ -314,6 +356,15 @@ namespace lms::db
return utils::execRangeQuery<TrackId>(query, parameters.range);
}

int Track::count(Session& session, const FindParameters& parameters)
{
session.checkReadTransaction();

auto query{ createCountQuery<int>(session, parameters) };
return utils::fetchQuerySingleResult(query);
}


RangeResults<Track::pointer> Track::find(Session& session, const FindParameters& parameters)
{
session.checkReadTransaction();
Expand Down
3 changes: 3 additions & 0 deletions src/libs/database/include/database/Track.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ namespace lms::db
Wt::Dbo::hasMany(a, _clusters, Wt::Dbo::ManyToMany, "track_cluster", "", Wt::Dbo::OnDeleteCascade);
}

static int count(Session &session, const FindParameters &parameters);

private:
friend class Session;
static pointer create(Session& session);
Expand Down Expand Up @@ -286,6 +288,7 @@ namespace lms::db
Wt::Dbo::ptr<MediaLibrary> _mediaLibrary;
Wt::Dbo::collection<Wt::Dbo::ptr<TrackArtistLink>> _trackArtistLinks;
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;

};

namespace Debug
Expand Down
63 changes: 56 additions & 7 deletions src/libs/subsonic/impl/entrypoints/Browsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "ParameterParsing.hpp"
#include "SubsonicId.hpp"
#include "Utils.hpp"
#include "../../../ts/RequestCacher.h"

namespace lms::api::subsonic
{
Expand Down Expand Up @@ -351,9 +352,22 @@ namespace lms::api::subsonic
return response;
}

ClusterId BGetCluster(std::string value, std::string name, RequestContext& context)
{
auto clusterType{ ClusterType::find(context.dbSession, name) };
if (!clusterType)
throw RequestedDataNotFoundError{};
auto cluster{clusterType->getCluster(value)};
if (!cluster)
throw RequestedDataNotFoundError{};
return cluster->getId();
}

Response handleGetGenresRequest(RequestContext& context)
{
Response response{ Response::createOkResponse(context.serverProtocolVersion) };
std::optional<std::string> year {getParameterAs<std::string>(context.parameters, "year")};
std::optional<std::string> length {getParameterAs<std::string>(context.parameters, "length")};

Response::Node& genresNode{ response.createNode("genres") };

Expand All @@ -363,18 +377,37 @@ namespace lms::api::subsonic
if (clusterType)
{
const auto clusters{ clusterType->getClusters() };

for (const Cluster::pointer& cluster : clusters)
genresNode.addArrayChild("genre", createGenreNode(cluster));
for (const Cluster::pointer& cluster : clusters) {
Track::FindParameters params;
std::vector<ClusterId> searchClusters = {cluster->getId()};
if ((year.has_value() && year.value() != "-1") || (length.has_value() && !length.value().empty())) {
if (year.has_value()){
searchClusters.push_back(BGetCluster(year.value(), "YEAR", context));
}
if (length.has_value()) {
searchClusters.push_back(BGetCluster(length.value(), "LENGTH", context));
}
params.setClusters(searchClusters);
auto results = Track::count(context.dbSession, params);
if (results)
genresNode.addArrayChild("genre", createGenreNode(cluster, results));
}
else
{
genresNode.addArrayChild("genre", createGenreNode(cluster));
}
}
}

return response;
}

Response handleGetMoodRequest(RequestContext& context)
{
auto reqCacher = RequestCacher::getInstance();
Response response{ Response::createOkResponse(context.serverProtocolVersion) };
std::optional<int> year {getParameterAs<int>(context.parameters, "year")};
std::optional<std::string> year {getParameterAs<std::string>(context.parameters, "year")};
std::optional<std::string> length {getParameterAs<std::string>(context.parameters, "length")};

Response::Node& moodNode{ response.createNode("mood") };

Expand All @@ -384,10 +417,26 @@ namespace lms::api::subsonic
if (clusterType)
{
const auto clusters{ clusterType->getClusters() };

for (const Cluster::pointer& cluster : clusters)
if (!year.has_value() || year==-1)
for (const Cluster::pointer& cluster : clusters) {
Track::FindParameters params;
std::vector<ClusterId> searchClusters = {cluster->getId()};
if ((year.has_value() && year.value() != "-1") || (length.has_value() && !length.value().empty())) {
if (year.has_value()){
searchClusters.push_back(BGetCluster(year.value(), "YEAR", context));
}
if (length.has_value()) {
searchClusters.push_back(BGetCluster(length.value(), "LENGTH", context));
}
params.setClusters(searchClusters);
auto results = Track::count(context.dbSession, params);
if (results)
moodNode.addArrayChild("mood", createGenreNode(cluster, results));
}
else
{
moodNode.addArrayChild("mood", createGenreNode(cluster));
}
}
}

return response;
Expand Down
11 changes: 11 additions & 0 deletions src/libs/subsonic/impl/responses/Genre.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,15 @@ namespace lms::api::subsonic

return clusterNode;
}

Response::Node createGenreNode(const db::Cluster::pointer& cluster, int songCount)
{
Response::Node clusterNode;

clusterNode.setValue(cluster->getName());
clusterNode.setAttribute("songCount", songCount);
clusterNode.setAttribute("albumCount", cluster->getReleasesCount());

return clusterNode;
}
}
1 change: 1 addition & 0 deletions src/libs/subsonic/impl/responses/Genre.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ namespace lms::db

namespace lms::api::subsonic
{
Response::Node createGenreNode(const db::ObjectPtr<db::Cluster>& cluster, int songCount);
Response::Node createGenreNode(const db::ObjectPtr<db::Cluster>& cluster);
}
5 changes: 5 additions & 0 deletions src/libs/ts/RequestCacher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//
// Created by teun on 6/22/24.
//

#include "RequestCacher.h"
37 changes: 37 additions & 0 deletions src/libs/ts/RequestCacher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

#pragma once

#include <map>
#include <string>
#include <vector>
#include <vector>
#include "database/ClusterId.hpp"

class RequestCacher {
public:
static RequestCacher &getInstance() {
static RequestCacher instance; // Guaranteed to be destroyed.
// Instantiated on first use.
return instance;
};


bool hasCache(const std::vector<lms::db::ClusterId> &aClusters) {
return !mLookupTable[aClusters].empty();
}

bool getCache(const std::vector<lms::db::ClusterId> &aClusters) {
return mLookupTable[aClusters];
}

void addToCache(const std::vector<lms::db::ClusterId> &aClusters, std::vector<int> aValues) {
mLookupTable.emplace(aClusters, aValues);
}

void invalidateCache()
{
mLookupTable.clear();
}

std::map<std::vector<lms::db::ClusterId>, std::vector<int>> mLookupTable;
};
4 changes: 3 additions & 1 deletion src/lms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ add_executable(lms
ui/resource/AudioTranscodingResource.cpp
ui/resource/CoverResource.cpp
ui/resource/DownloadResource.cpp
)
../libs/ts/RequestCacher.cpp
../libs/ts/RequestCacher.h
)

target_include_directories(lms PRIVATE
ui/
Expand Down

0 comments on commit 73b62fa

Please sign in to comment.