Adding tags in the tracks view

This commit is contained in:
emeric
2018-05-17 13:45:22 +02:00
parent 6685795b9c
commit a4788320a6
11 changed files with 184 additions and 75 deletions
+1
View File
@@ -36,6 +36,7 @@
</div>
${<if-has-release>}${release-name}${</if-has-release>}
${<if-has-artist>}${artist-name}${</if-has-artist>}
${clusters}
${play-btn}${add-btn}
</div>
</message>
+1
View File
@@ -33,6 +33,7 @@ lms_SOURCES = \
$(srcdir)/ui/explore/ArtistView.cpp \
$(srcdir)/ui/explore/ArtistsView.cpp \
$(srcdir)/ui/explore/Explore.cpp \
$(srcdir)/ui/explore/ExploreUtils.cpp \
$(srcdir)/ui/explore/Filters.cpp \
$(srcdir)/ui/explore/ReleasesView.cpp \
$(srcdir)/ui/explore/ReleaseView.cpp \
+44
View File
@@ -210,6 +210,50 @@ Track::getOriginalYear() const
return (_originalYear > 0) ? boost::make_optional<int>(_originalYear) : boost::none;
}
std::vector<std::vector<Cluster::pointer>>
Track::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::size_t size) const
{
assert(self());
assert(self()->id() != Wt::Dbo::dbo_traits<Artist>::invalidId() );
assert(session());
WhereClause where;
std::ostringstream oss;
oss << "SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN cluster_type c_type ON c.cluster_type_id = c_type.id";
where.And(WhereClause("t.id = ?")).bind(std::to_string(self()->id()));
{
WhereClause clusterClause;
for (auto clusterType : clusterTypes)
clusterClause.Or(WhereClause("c_type.id = ?")).bind(std::to_string(clusterType.id()));
where.And(clusterClause);
}
oss << " " << where.get();
oss << " GROUP BY c.id ORDER BY COUNT(c.id) DESC";
Wt::Dbo::Query<Cluster::pointer> query = session()->query<Cluster::pointer>( oss.str() );
for (const std::string& bindArg : where.getBindArgs())
query.bind(bindArg);
Wt::Dbo::collection<Cluster::pointer> queryRes = query;
std::map<IdType, std::vector<Cluster::pointer>> clusters;
for (auto cluster : queryRes)
{
if (clusters[cluster->getType().id()].size() < size)
clusters[cluster->getType().id()].push_back(cluster);
}
std::vector<std::vector<Cluster::pointer>> res;
for (auto cluster_list : clusters)
res.push_back(cluster_list.second);
return res;
}
Cluster::Cluster()
{
}
+3 -2
View File
@@ -120,8 +120,7 @@ class ClusterType : public Wt::Dbo::Dbo<ClusterType>
Wt::Dbo::collection< Wt::Dbo::ptr<Cluster> > _clusters;
};
class Track
class Track : public Wt::Dbo::Dbo<Cluster>
{
public:
@@ -197,6 +196,8 @@ class Track
Wt::Dbo::ptr<Release> getRelease(void) const { return _release; }
std::vector< Cluster::pointer > getClusters(void) const;
std::vector<std::vector<Wt::Dbo::ptr<Cluster>>> getClusterGroups(std::vector<Wt::Dbo::ptr<ClusterType>> clusterTypes, std::size_t size) const;
template<class Action>
void persist(Action& a)
{
+4 -18
View File
@@ -34,13 +34,14 @@
#include "LmsApplication.hpp"
#include "Filters.hpp"
#include "ExploreUtils.hpp"
using namespace Database;
namespace {
const std::string artistClusterTypesSetting = "artist_cluster_types";
const std::vector<std::string> defaultArtistClusterTypes =
const std::set<std::string> defaultArtistClusterTypes =
{
"GENRE",
"ALBUMGROUPING",
@@ -48,21 +49,6 @@ const std::vector<std::string> defaultArtistClusterTypes =
"COMMENT:SONGS-DB_OCCASION",
};
std::vector<ClusterType::pointer> getArtistClusterTypes(Wt::Dbo::Session& session)
{
Wt::Dbo::Transaction transaction(session);
std::vector<ClusterType::pointer> res;
for (auto clusterTypeName : splitString(Setting::getString(session, artistClusterTypesSetting), " "))
{
auto clusterType = ClusterType::getByName(session, clusterTypeName);
if (clusterType)
res.push_back(clusterType);
}
return res;
}
} // namespace
namespace UserInterface {
@@ -71,7 +57,7 @@ Artist::Artist(Filters* filters)
: _filters(filters)
{
if (!Setting::exists(LmsApp->getDboSession(), artistClusterTypesSetting))
Setting::setString(LmsApp->getDboSession(), artistClusterTypesSetting, joinStrings(defaultArtistClusterTypes, " "));
setClusterTypesToSetting(artistClusterTypesSetting, defaultArtistClusterTypes);
wApp->internalPathChanged().connect(std::bind([=]
{
@@ -112,7 +98,7 @@ Artist::refresh()
Wt::WContainerWidget* clusterContainers = t->bindNew<Wt::WContainerWidget>("clusters");
{
auto clusterTypes = getArtistClusterTypes(LmsApp->getDboSession());
auto clusterTypes = getClusterTypesFromSetting(artistClusterTypesSetting);
auto clusterGroups = artist->getClusterGroups(clusterTypes, 3);
for (auto clusters : clusterGroups)
+4 -18
View File
@@ -31,34 +31,20 @@
#include "LmsApplication.hpp"
#include "Filters.hpp"
#include "ExploreUtils.hpp"
using namespace Database;
namespace {
const std::string artistsClusterTypesSetting = "artists_cluster_types";
const std::vector<std::string> defaultArtistsClusterTypes =
const std::set<std::string> defaultArtistsClusterTypes =
{
"ALBUMGROUPING",
"GENRE",
"ALBUMMOOD",
};
std::vector<ClusterType::pointer> getArtistsClusterTypes(Wt::Dbo::Session& session)
{
Wt::Dbo::Transaction transaction(session);
std::vector<ClusterType::pointer> res;
for (auto clusterTypeName : splitString(Setting::getString(session, artistsClusterTypesSetting), " "))
{
auto clusterType = ClusterType::getByName(session, clusterTypeName);
if (clusterType)
res.push_back(clusterType);
}
return res;
}
}
namespace UserInterface {
@@ -68,7 +54,7 @@ Artists::Artists(Filters* filters)
_filters(filters)
{
if (!Setting::exists(LmsApp->getDboSession(), artistsClusterTypesSetting))
Setting::setString(LmsApp->getDboSession(), artistsClusterTypesSetting, joinStrings(defaultArtistsClusterTypes, " "));
setClusterTypesToSetting(artistsClusterTypesSetting, defaultArtistsClusterTypes);
addFunction("tr", &Wt::WTemplate::Functions::tr);
@@ -123,7 +109,7 @@ Artists::addSome()
Wt::WContainerWidget* clusterContainers = entry->bindNew<Wt::WContainerWidget>("clusters");
{
auto clusterTypes = getArtistsClusterTypes(LmsApp->getDboSession());
auto clusterTypes = getClusterTypesFromSetting(artistsClusterTypesSetting);
auto clusterGroups = artist->getClusterGroups(clusterTypes, 1);
for (auto clusters : clusterGroups)
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2018 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 "ExploreUtils.hpp"
#include "utils/Utils.hpp"
#include "database/Setting.hpp"
#include "LmsApplication.hpp"
namespace UserInterface {
std::vector<Database::ClusterType::pointer> getClusterTypesFromSetting(std::string setting)
{
std::vector<Database::ClusterType::pointer> res;
for (auto clusterTypeName : splitString(Database::Setting::getString(LmsApp->getDboSession(), setting), " "))
{
auto clusterType = Database::ClusterType::getByName(LmsApp->getDboSession(), clusterTypeName);
if (clusterType)
res.push_back(clusterType);
}
return res;
}
void setClusterTypesToSetting(std::string setting, const std::set<std::string>& clusterTypes)
{
std::vector<std::string> vec(clusterTypes.begin(), clusterTypes.end());
Database::Setting::setString(LmsApp->getDboSession(), setting, joinStrings(vec, " "));
}
} // namespace UserInterface
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2018 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 "database/Track.hpp"
namespace UserInterface {
std::vector<Database::ClusterType::pointer> getClusterTypesFromSetting(std::string setting);
void setClusterTypesToSetting(std::string setting, const std::set<std::string>& clusterTypes);
} // namespace UserInterface
+4 -17
View File
@@ -35,13 +35,14 @@
#include "LmsApplication.hpp"
#include "Filters.hpp"
#include "ExploreUtils.hpp"
using namespace Database;
namespace {
const std::string releaseClusterTypesSetting = "release_cluster_types";
const std::vector<std::string> defaultReleaseClusterTypes =
const std::set<std::string> defaultReleaseClusterTypes =
{
"GENRE",
"ALBUMGROUPING",
@@ -49,20 +50,6 @@ const std::vector<std::string> defaultReleaseClusterTypes =
"COMMENT:SONGS-DB_OCCASION",
};
std::vector<ClusterType::pointer> getReleaseClusterTypes(Wt::Dbo::Session& session)
{
Wt::Dbo::Transaction transaction(session);
std::vector<ClusterType::pointer> res;
for (auto clusterTypeName : splitString(Setting::getString(session, releaseClusterTypesSetting), " "))
{
auto clusterType = ClusterType::getByName(session, clusterTypeName);
if (clusterType)
res.push_back(clusterType);
}
return res;
}
} // namespace
namespace UserInterface {
@@ -71,7 +58,7 @@ Release::Release(Filters* filters)
: _filters(filters)
{
if (!Setting::exists(LmsApp->getDboSession(), releaseClusterTypesSetting))
Setting::setString(LmsApp->getDboSession(), releaseClusterTypesSetting, joinStrings(defaultReleaseClusterTypes, " "));
setClusterTypesToSetting(releaseClusterTypesSetting, defaultReleaseClusterTypes);
wApp->internalPathChanged().connect(std::bind([=]
{
@@ -143,7 +130,7 @@ Release::refresh()
Wt::WContainerWidget* clusterContainers = t->bindNew<Wt::WContainerWidget>("clusters");
{
auto clusterTypes = getReleaseClusterTypes(LmsApp->getDboSession());
auto clusterTypes = getClusterTypesFromSetting(releaseClusterTypesSetting);
auto clusterGroups = release->getClusterGroups(clusterTypes, 3);
for (auto clusters : clusterGroups)
+4 -18
View File
@@ -35,33 +35,19 @@
#include "LmsApplication.hpp"
#include "Filters.hpp"
#include "ExploreUtils.hpp"
using namespace Database;
namespace {
const std::string releasesClusterTypesSetting = "releases_cluster_types";
const std::vector<std::string> defaultReleasesClusterTypes =
const std::set<std::string> defaultReleasesClusterTypes =
{
"GENRE",
"ALBUMGROUPING",
};
std::vector<ClusterType::pointer> getReleasesClusterTypes(Wt::Dbo::Session& session)
{
Wt::Dbo::Transaction transaction(session);
std::vector<ClusterType::pointer> res;
for (auto clusterTypeName : splitString(Setting::getString(session, releasesClusterTypesSetting), " "))
{
auto clusterType = ClusterType::getByName(session, clusterTypeName);
if (clusterType)
res.push_back(clusterType);
}
return res;
}
} // namespace
namespace UserInterface {
@@ -71,7 +57,7 @@ Releases::Releases(Filters* filters)
_filters(filters)
{
if (!Setting::exists(LmsApp->getDboSession(), releasesClusterTypesSetting))
Setting::setString(LmsApp->getDboSession(), releasesClusterTypesSetting, joinStrings(defaultReleasesClusterTypes, " "));
setClusterTypesToSetting(releasesClusterTypesSetting, defaultReleasesClusterTypes);
addFunction("tr", &Wt::WTemplate::Functions::tr);
@@ -140,7 +126,7 @@ Releases::addSome()
Wt::WContainerWidget* clusterContainers = entry->bindNew<Wt::WContainerWidget>("clusters");
{
auto clusterTypes = getReleasesClusterTypes(LmsApp->getDboSession());
auto clusterTypes = getClusterTypesFromSetting(releasesClusterTypesSetting);
auto clusterGroups = release->getClusterGroups(clusterTypes, 1);
for (auto clusters : clusterGroups)
+39 -2
View File
@@ -27,6 +27,7 @@
#include "database/DbArtist.hpp"
#include "database/Track.hpp"
#include "database/Release.hpp"
#include "database/Setting.hpp"
#include "utils/Logger.hpp"
#include "utils/Utils.hpp"
@@ -35,15 +36,32 @@
#include "LmsApplication.hpp"
#include "Filters.hpp"
namespace UserInterface {
#include "ExploreUtils.hpp"
using namespace Database;
namespace {
const std::string trackClusterTypesSetting = "track_cluster_types";
const std::set<std::string> defaultTrackClusterTypes =
{
"GENRE",
"ALBUMGROUPING",
"ALBUMMOOD",
"COMMENT:SONGS-DB_OCCASION",
};
} // namespace
namespace UserInterface {
Tracks::Tracks(Filters* filters)
: Wt::WTemplate(Wt::WString::tr("Lms.Explore.Tracks.template")),
_filters(filters)
{
if (!Setting::exists(LmsApp->getDboSession(), trackClusterTypesSetting))
setClusterTypesToSetting(trackClusterTypesSetting, defaultTrackClusterTypes);
addFunction("tr", &Wt::WTemplate::Functions::tr);
_search = bindNew<Wt::WLineEdit>("search");
@@ -136,6 +154,25 @@ Tracks::addSome()
// Some images may not be square
cover->setWidth(64);
Wt::WContainerWidget* clusterContainers = entry->bindNew<Wt::WContainerWidget>("clusters");
{
auto clusterTypes = getClusterTypesFromSetting(trackClusterTypesSetting);
auto clusterGroups = release->getClusterGroups(clusterTypes, 1);
for (auto clusters : clusterGroups)
{
for (auto cluster : clusters)
{
auto clusterId = cluster.id();
auto entry = clusterContainers->addWidget(LmsApp->createCluster(cluster));
entry->clicked().connect([=]
{
_filters->add(clusterId);
});
}
}
}
Wt::WText* playBtn = entry->bindNew<Wt::WText>("play-btn", Wt::WString::tr("Lms.Explore.Tracks.play"), Wt::TextFormat::XHTML);
playBtn->clicked().connect(std::bind([=]
{