diff --git a/README.md b/README.md index 8f985bb4..923266e5 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ LMS is written entirely in C++. Therefore, it is suitable to run on embedded dev ### Debian ```sh -$ apt-get install g++ autoconf automake libboost-dev libboost-locale-dev libboost-iostreams-dev libavcodec-dev libwtdbosqlite-dev libwthttp-dev libwtdbo-dev libwt-dev libmagick++-dev libavcodec-dev libavformat-dev libav-tools libpstreams-dev libcurl-dev libcurlpp-dev libconfig++-dev ffmpeg +$ apt-get install g++ autoconf automake libboost-dev libboost-locale-dev libboost-iostreams-dev libavcodec-dev libavutil-dev libavformat-dev libav-tools libwtdbosqlite-dev libwthttp-dev libwtdbo-dev libwt-dev libmagick++-dev libpstreams-dev libcurlpp-dev libconfig++-dev libpstreams-dev ffmpeg libtag1-dev ``` ## Build diff --git a/src/database/Release.cpp b/src/database/Release.cpp index ca9e1fb5..a7f15dea 100644 --- a/src/database/Release.cpp +++ b/src/database/Release.cpp @@ -108,7 +108,7 @@ getQuery(Wt::Dbo::Session& session, WhereClause clusterClause; for (auto id : clusterIds) - clusterClause.And(WhereClause("c.id = ?")).bind(std::to_string(id)); + clusterClause.Or(WhereClause("c.id = ?")).bind(std::to_string(id)); where.And(clusterClause); } @@ -195,17 +195,48 @@ Release::hasVariousArtists() const } std::vector> -Release::getTracks() const +Release::getTracks(const std::vector& clusterIds) const { assert(self()); + assert(self()->id() != Wt::Dbo::dbo_traits::invalidId() ); assert(session()); - Wt::Dbo::collection> res = session()->query>( - "SELECT t FROM track t INNER JOIN release r ON t.release_id = r.id") - .where("r.id = ?") - .orderBy("t.disc_number,t.track_number") - .bind(id()); + WhereClause where; - return std::vector>(res.begin(), res.end()); + std::ostringstream oss; + oss << "SELECT t FROM track t INNER JOIN release r ON t.release_id = r.id"; + + if (!clusterIds.empty()) + { + oss << " INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id"; + + WhereClause clusterClause; + + for (auto id : clusterIds) + clusterClause.Or(WhereClause("c.id = ?")).bind(std::to_string(id)); + + where.And(clusterClause); + } + + where.And(WhereClause("r.id = ?")).bind(std::to_string(id())); + + oss << " " << where.get(); + + if (!clusterIds.empty()) + oss << " GROUP BY t.id HAVING COUNT(*) = " << clusterIds.size(); + + oss << " ORDER BY t.disc_number,t.track_number"; + + Wt::Dbo::Query query = session()->query( oss.str() ); + + for (const std::string& bindArg : where.getBindArgs()) + { + query.bind(bindArg); + } + + Wt::Dbo::collection< Wt::Dbo::ptr > res = query; + + return std::vector< Wt::Dbo::ptr > (res.begin(), res.end()); } + } // namespace Database diff --git a/src/database/Release.hpp b/src/database/Release.hpp index fc6fedcb..390d60a0 100644 --- a/src/database/Release.hpp +++ b/src/database/Release.hpp @@ -57,7 +57,7 @@ class Release : public Wt::Dbo::Dbo int size, bool& moreExpected); - std::vector> getTracks() const; + std::vector> getTracks(const std::vector& clusters = std::vector()) const; // Create static pointer create(Wt::Dbo::Session& session, const std::string& name, const std::string& MBID = ""); diff --git a/src/database/Track.cpp b/src/database/Track.cpp index ac7faa18..65e3319e 100644 --- a/src/database/Track.cpp +++ b/src/database/Track.cpp @@ -129,7 +129,7 @@ getQuery(Wt::Dbo::Session& session, WhereClause clusterClause; for (auto id : clusterIds) - clusterClause.And(WhereClause("c.id = ?")).bind(std::to_string(id)); + clusterClause.Or(WhereClause("c.id = ?")).bind(std::to_string(id)); where.And(clusterClause); } diff --git a/src/ui/ArtistView.cpp b/src/ui/ArtistView.cpp index 5327ced6..9c98dd93 100644 --- a/src/ui/ArtistView.cpp +++ b/src/ui/ArtistView.cpp @@ -84,8 +84,8 @@ Artist::refresh() entry->addFunction("tr", Wt::WTemplate::Functions::tr); { - Wt::WAnchor *coverAnchor = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/release/" + std::to_string(release.id()))); - Wt::WImage *cover = new Wt::WImage(coverAnchor); + Wt::WAnchor* coverAnchor = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/release/" + std::to_string(release.id()))); + Wt::WImage* cover = new Wt::WImage(coverAnchor); cover->setImageLink(SessionImageResource()->getReleaseUrl(release.id(), 128)); // Some images may not be square cover->setWidth(128); @@ -93,8 +93,8 @@ Artist::refresh() } { - Wt::WAnchor *releaseAnchor = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/release/" + std::to_string(release.id()))); - Wt::WText *releaseName = new Wt::WText(releaseAnchor); + Wt::WAnchor* releaseAnchor = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/release/" + std::to_string(release.id()))); + Wt::WText* releaseName = new Wt::WText(releaseAnchor); releaseName->setText(Wt::WString::fromUTF8(release->getName(), Wt::PlainText)); entry->bindWidget("name", releaseAnchor); } diff --git a/src/ui/Explore.cpp b/src/ui/Explore.cpp index 46cfc5ca..8686f0f2 100644 --- a/src/ui/Explore.cpp +++ b/src/ui/Explore.cpp @@ -83,9 +83,9 @@ Explore::Explore(Wt::WContainerWidget* parent) stack->addWidget(new Artists(filters)); stack->addWidget(new Artist(filters)); - stack->addWidget(new Releases(/*filters*/)); - stack->addWidget(new Release(/*filters*/)); - stack->addWidget(new Tracks(/*filters*/)); + stack->addWidget(new Releases(filters)); + stack->addWidget(new Release(filters)); + stack->addWidget(new Tracks(filters)); wApp->internalPathChanged().connect(std::bind([=] { diff --git a/src/ui/ReleaseView.cpp b/src/ui/ReleaseView.cpp index 098b12a5..69b5078f 100644 --- a/src/ui/ReleaseView.cpp +++ b/src/ui/ReleaseView.cpp @@ -33,8 +33,9 @@ namespace UserInterface { -Release::Release(Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent) +Release::Release(Filters* filters, Wt::WContainerWidget* parent) +: Wt::WContainerWidget(parent), + _filters(filters) { wApp->internalPathChanged().connect(std::bind([=] { @@ -109,10 +110,9 @@ Release::refresh() auto tracksContainer = new Wt::WContainerWidget(); t->bindWidget("tracks", tracksContainer); - std::vector clusterIds; // TODO fill + auto clusterIds = _filters->getClusterIds(); + auto tracks = release->getTracks(clusterIds); -// auto tracks = release->getTracks(clusterIds); - auto tracks = release->getTracks(); bool variousArtists = release->hasVariousArtists(); for (auto track : tracks) diff --git a/src/ui/ReleaseView.hpp b/src/ui/ReleaseView.hpp index 0a68a9e9..b51568cd 100644 --- a/src/ui/ReleaseView.hpp +++ b/src/ui/ReleaseView.hpp @@ -21,15 +21,19 @@ #include +#include "Filters.hpp" + namespace UserInterface { class Release : public Wt::WContainerWidget { public: - Release(Wt::WContainerWidget* parent = 0); + Release(Filters* filters, Wt::WContainerWidget* parent = 0); private: void refresh(); + + Filters* _filters; }; } // namespace UserInterface diff --git a/src/ui/ReleasesView.cpp b/src/ui/ReleasesView.cpp index 7c7da4de..414c1418 100644 --- a/src/ui/ReleasesView.cpp +++ b/src/ui/ReleasesView.cpp @@ -36,8 +36,9 @@ namespace UserInterface { using namespace Database; -Releases::Releases(Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent) +Releases::Releases(Filters* filters, Wt::WContainerWidget* parent) +: Wt::WContainerWidget(parent), + _filters(filters) { auto releases = new Wt::WTemplate(Wt::WString::tr("template-releases"), this); releases->addFunction("tr", &Wt::WTemplate::Functions::tr); @@ -63,7 +64,7 @@ Releases::refresh(std::vector searchKeywords) { _releasesContainer->clear(); - std::vector clusterIds; // TODO fill + auto clusterIds = _filters->getClusterIds(); Wt::Dbo::Transaction transaction(DboSession()); @@ -75,8 +76,8 @@ Releases::refresh(std::vector searchKeywords) Wt::WTemplate* entry = new Wt::WTemplate(Wt::WString::tr("template-releases-entry"), _releasesContainer); entry->addFunction("tr", Wt::WTemplate::Functions::tr); - Wt::WAnchor *coverAnchor = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/release/" + std::to_string(release.id()))); - Wt::WImage *cover = new Wt::WImage(coverAnchor); + Wt::WAnchor* coverAnchor = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/release/" + std::to_string(release.id()))); + Wt::WImage* cover = new Wt::WImage(coverAnchor); cover->setImageLink(SessionImageResource()->getReleaseUrl(release.id(), 128)); // Some images may not be square cover->setWidth(128); @@ -91,8 +92,8 @@ Releases::refresh(std::vector searchKeywords) } else { - Wt::WAnchor *artistAnchor = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/artist/" + std::to_string(artists.front().id()))); - Wt::WText *artist = new Wt::WText(artistAnchor); + Wt::WAnchor* artistAnchor = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/artist/" + std::to_string(artists.front().id()))); + Wt::WText* artist = new Wt::WText(artistAnchor); artist->setText(Wt::WString::fromUTF8(artists.front()->getName(), Wt::PlainText)); entry->bindWidget("artist-name", artistAnchor); } diff --git a/src/ui/ReleasesView.hpp b/src/ui/ReleasesView.hpp index 7a4325cd..bf741678 100644 --- a/src/ui/ReleasesView.hpp +++ b/src/ui/ReleasesView.hpp @@ -21,17 +21,20 @@ #include +#include "Filters.hpp" + namespace UserInterface { class Releases : public Wt::WContainerWidget { public: - Releases(Wt::WContainerWidget* parent = 0); + Releases(Filters* filters, Wt::WContainerWidget* parent = 0); private: void refresh(std::vector searchKeywords = std::vector()); - Wt::WContainerWidget *_releasesContainer; + Filters* _filters; + Wt::WContainerWidget* _releasesContainer; }; } // namespace UserInterface diff --git a/src/ui/TracksView.cpp b/src/ui/TracksView.cpp index bc834de5..c904c6ae 100644 --- a/src/ui/TracksView.cpp +++ b/src/ui/TracksView.cpp @@ -35,8 +35,9 @@ namespace UserInterface { using namespace Database; -Tracks::Tracks(Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent) +Tracks::Tracks(Filters* filters, Wt::WContainerWidget* parent) +: Wt::WContainerWidget(parent), + _filters(filters) { auto tracks = new Wt::WTemplate(Wt::WString::tr("template-tracks"), this); tracks->addFunction("tr", &Wt::WTemplate::Functions::tr); @@ -62,7 +63,7 @@ Tracks::refresh(std::vector searchKeywords) { _tracksContainer->clear(); - std::vector clusterIds; // TODO fill + auto clusterIds = _filters->getClusterIds(); Wt::Dbo::Transaction transaction(DboSession()); diff --git a/src/ui/TracksView.hpp b/src/ui/TracksView.hpp index 7ba2c61c..3210e666 100644 --- a/src/ui/TracksView.hpp +++ b/src/ui/TracksView.hpp @@ -21,17 +21,20 @@ #include +#include "Filters.hpp" + namespace UserInterface { class Tracks : public Wt::WContainerWidget { public: - Tracks(Wt::WContainerWidget* parent = 0); + Tracks(Filters* filters, Wt::WContainerWidget* parent = 0); private: void refresh(std::vector searchKeywords = std::vector()); - Wt::WContainerWidget *_tracksContainer; + Wt::WContainerWidget* _tracksContainer; + Filters* _filters; }; } // namespace UserInterface