[WIP] Added Artist/ReleaseInfo

This commit is contained in:
emeric
2019-01-23 13:22:43 +01:00
parent b76c60f437
commit 3e142b5507
77 changed files with 2706 additions and 716 deletions
+25 -25
View File
@@ -31,33 +31,33 @@
#include <Wt/Auth/Identity.h>
#include "config/config.h"
#include "cover/CoverArtGrabber.hpp"
#include "database/Artist.hpp"
#include "database/Cluster.hpp"
#include "database/Release.hpp"
#include "explore/Explore.hpp"
#include "main/Services.hpp"
#include "utils/Logger.hpp"
#include "utils/Utils.hpp"
#include "explore/Explore.hpp"
#include "MediaPlayer.hpp"
#include "PlayHistoryView.hpp"
#include "PlayQueueView.hpp"
#include "SettingsView.hpp"
#include "admin/InitWizardView.hpp"
#include "admin/DatabaseSettingsView.hpp"
#include "admin/UserView.hpp"
#include "admin/UsersView.hpp"
#include "resource/ImageResource.hpp"
#include "resource/AudioResource.hpp"
#include "MediaPlayer.hpp"
#include "PlayHistoryView.hpp"
#include "PlayQueueView.hpp"
#include "SettingsView.hpp"
namespace UserInterface {
std::unique_ptr<Wt::WApplication>
LmsApplication::create(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, LmsApplicationGroupContainer& appGroups, Scanner::MediaScanner& scanner)
LmsApplication::create(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, LmsApplicationGroupContainer& appGroups)
{
/*
* You could read information from the environment to decide whether
* the user has permission to start a new application
*/
return std::make_unique<LmsApplication>(env, connectionPool, appGroups, scanner);
return std::make_unique<LmsApplication>(env, connectionPool, appGroups);
}
LmsApplication*
@@ -66,19 +66,12 @@ LmsApplication::instance()
return reinterpret_cast<LmsApplication*>(Wt::WApplication::instance());
}
/*
* The env argument contains information about the new session, and
* the initial request. It must be passed to the Wt::WApplication
* constructor so it is typically also an argument for your custom
* application constructor.
*/
LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, LmsApplicationGroupContainer& appGroups, Scanner::MediaScanner& scanner)
LmsApplication::LmsApplication(const Wt::WEnvironment& env,
Wt::Dbo::SqlConnectionPool& connectionPool,
LmsApplicationGroupContainer& appGroups)
: Wt::WApplication(env),
_db(connectionPool),
_appGroups(appGroups),
_scanner(scanner),
_imageResource(nullptr),
_audioResource(nullptr)
_appGroups(appGroups)
{
auto bootstrapTheme = std::make_unique<Wt::WBootstrapTheme>();
bootstrapTheme->setVersion(Wt::BootstrapVersion::v3);
@@ -96,6 +89,8 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti
messageResourceBundle().use(appRoot() + "admin-users");
messageResourceBundle().use(appRoot() + "admin-initwizard");
messageResourceBundle().use(appRoot() + "artist");
messageResourceBundle().use(appRoot() + "artistinfo");
messageResourceBundle().use(appRoot() + "artistlink");
messageResourceBundle().use(appRoot() + "artists");
messageResourceBundle().use(appRoot() + "artistsinfo");
messageResourceBundle().use(appRoot() + "explore");
@@ -105,6 +100,8 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti
messageResourceBundle().use(appRoot() + "playqueue");
messageResourceBundle().use(appRoot() + "playhistory");
messageResourceBundle().use(appRoot() + "release");
messageResourceBundle().use(appRoot() + "releaseinfo");
messageResourceBundle().use(appRoot() + "releaselink");
messageResourceBundle().use(appRoot() + "releases");
messageResourceBundle().use(appRoot() + "releasesinfo");
messageResourceBundle().use(appRoot() + "settings");
@@ -112,6 +109,9 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti
messageResourceBundle().use(appRoot() + "tracks");
messageResourceBundle().use(appRoot() + "tracksinfo");
// hack since Server does not expose the docRoot
getServices().coverArtGrabber->setDefaultCover(Wt::WApplication::instance()->docRoot() + "/images/unknown-cover.jpg");
// Require js here to avoid async problems
requireJQuery("/js/jquery-1.10.2.min.js");
require("/js/mediaplayer.js");
@@ -462,7 +462,7 @@ LmsApplication::createHome()
// Events from MediaScanner
std::string sessionId = LmsApp->sessionId();
_scanner.scanComplete().connect([=] (Scanner::MediaScanner::Stats stats)
getServices().mediaScanner->scanComplete().connect([=] (Scanner::MediaScanner::Stats stats)
{
// Runs from media scanner context
Wt::WServer::instance()->post(sessionId, [=]
+17 -16
View File
@@ -20,25 +20,29 @@
#ifndef LMS_APPLICATION_HPP
#define LMS_APPLICATION_HPP
#include <boost/optional.hpp>
#include <Wt/WApplication.h>
#include <Wt/Dbo/SqlConnectionPool.h>
#include "database/DatabaseHandler.hpp"
#include "scanner/MediaScanner.hpp"
#include "database/Artist.hpp"
#include "database/Cluster.hpp"
#include "database/Release.hpp"
#include "LmsApplicationGroup.hpp"
#include "Auth.hpp"
namespace Database {
class Artist;
class Cluster;
class Release;
}
namespace UserInterface {
class AudioResource;
class ImageResource;
// Events that can be listen to anywhere in the application
// Events that can be listen from anywhere in the application
struct Events
{
// Events relative to group
@@ -67,10 +71,10 @@ enum class MsgType
class LmsApplication : public Wt::WApplication
{
public:
LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, LmsApplicationGroupContainer& appGroups, Scanner::MediaScanner& scanner);
LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool, LmsApplicationGroupContainer& appGroups);
static std::unique_ptr<Wt::WApplication> create(const Wt::WEnvironment& env,
Wt::Dbo::SqlConnectionPool& connectionPool, LmsApplicationGroupContainer& appGroups, Scanner::MediaScanner& scanner);
Wt::Dbo::SqlConnectionPool& connectionPool, LmsApplicationGroupContainer& appGroups);
static LmsApplication* instance();
// Session application data
@@ -83,8 +87,6 @@ class LmsApplication : public Wt::WApplication
Database::User::pointer getUser() { return _db.getCurrentUser(); }
Wt::WString getUserIdentity() { return _userIdentity; }
Scanner::MediaScanner& getMediaScanner() { return _scanner; }
Events& getEvents() { return _events; }
// Utils
@@ -94,11 +96,11 @@ class LmsApplication : public Wt::WApplication
void post(std::function<void()> func);
void notifyMsg(MsgType type, const Wt::WString& message, std::chrono::milliseconds duration = std::chrono::milliseconds(4000));
static Wt::WLink createArtistLink(Database::Artist::pointer artist);
static std::unique_ptr<Wt::WAnchor> createArtistAnchor(Database::Artist::pointer artist, bool addText = true);
static Wt::WLink createReleaseLink(Database::Release::pointer release);
static std::unique_ptr<Wt::WAnchor> createReleaseAnchor(Database::Release::pointer release, bool addText = true);
static std::unique_ptr<Wt::WTemplate> createCluster(Database::Cluster::pointer cluster, bool canDelete = false);
static Wt::WLink createArtistLink(Wt::Dbo::ptr<Database::Artist> artist);
static std::unique_ptr<Wt::WAnchor> createArtistAnchor(Wt::Dbo::ptr<Database::Artist> artist, bool addText = true);
static Wt::WLink createReleaseLink(Wt::Dbo::ptr<Database::Release> release);
static std::unique_ptr<Wt::WAnchor> createReleaseAnchor(Wt::Dbo::ptr<Database::Release> release, bool addText = true);
static std::unique_ptr<Wt::WTemplate> createCluster(Wt::Dbo::ptr<Database::Cluster> cluster, bool canDelete = false);
// Signal emitted just before the session ends (user may already be logged out)
Wt::Signal<>& preQuit() { return _preQuit; }
@@ -119,8 +121,7 @@ class LmsApplication : public Wt::WApplication
LmsApplicationGroupContainer& _appGroups;
Events _events;
Wt::WString _userIdentity;
Auth* _auth;
Scanner::MediaScanner& _scanner;
Auth* _auth = nullptr;
std::shared_ptr<ImageResource> _imageResource;
std::shared_ptr<AudioResource> _audioResource;
bool _isAdmin = false;
+2 -1
View File
@@ -22,9 +22,10 @@
#include "av/AvInfo.hpp"
#include "utils/Logger.hpp"
#include "database/Artist.hpp"
#include "database/Release.hpp"
#include "database/Track.hpp"
#include "resource/ImageResource.hpp"
#include "resource/AudioResource.hpp"
+14 -36
View File
@@ -19,15 +19,12 @@
#include "PlayQueueView.hpp"
#include <random>
#include <Wt/WAnchor.h>
#include <Wt/WText.h>
#include "utils/Logger.hpp"
#include "database/TrackList.hpp"
#include "main/Services.hpp"
#include "similarity/SimilaritySearcher.hpp"
#include "utils/Logger.hpp"
#include "LmsApplication.hpp"
namespace UserInterface {
@@ -385,45 +382,26 @@ PlayQueue::addSome()
void
PlayQueue::addRadioTrack()
{
auto now = std::chrono::system_clock::now();
std::mt19937 randGenerator(std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count());
auto tracklist = getTrackList();
std::set<Database::IdType> trackIds;
{
auto ids = tracklist->getTrackIds();
trackIds = std::set<Database::IdType>(ids.begin(), ids.end());
}
// Get all the tracks of the tracklist, get the cluster that is mostly used
// and reuse it to get the next track
auto clusters = tracklist->getClusters();
if (clusters.empty())
std::vector<Database::IdType> trackIds = getTrackList()->getTrackIds();
if (trackIds.empty())
return;
for (auto cluster : clusters)
auto res = getServices().similaritySearcher->getSimilarTracks(trackIds, 1);
for (auto trackId : res)
{
std::set<Database::IdType> clusterTrackIds = cluster->getTrackIds();
std::set<Database::IdType> candidateTrackIds;
std::set_difference(clusterTrackIds.begin(), clusterTrackIds.end(),
trackIds.begin(), trackIds.end(),
std::inserter(candidateTrackIds, candidateTrackIds.end()));
if (candidateTrackIds.empty())
continue;
std::uniform_int_distribution<int> dist(0, candidateTrackIds.size() - 1);
auto trackToAdd = Database::Track::getById(LmsApp->getDboSession(), *std::next(candidateTrackIds.begin(), dist(randGenerator)));
auto trackToAdd = Database::Track::getById(LmsApp->getDboSession(), trackId);
enqueueTrack(trackToAdd);
return;
}
LMS_LOG(UI, INFO) << "No more track to be added!";
}
void addRadioTrackFromSimilarity(std::shared_ptr<Similarity::Searcher> similaritySearcher)
{
}
} // namespace UserInterface
+8
View File
@@ -31,6 +31,11 @@
#include "database/TrackList.hpp"
#include "database/Track.hpp"
namespace Similarity
{
class Finder;
}
namespace UserInterface {
class PlayQueue : public Wt::WTemplate
@@ -69,6 +74,9 @@ class PlayQueue : public Wt::WTemplate
void load(std::size_t pos, bool play);
void stop();
void addRadioTrackFromSimilarity(std::shared_ptr<Similarity::Finder> similarityFinder);
void addRadioTrackFromClusters();
bool _repeatAll = false;
bool _radioMode = false;
boost::optional<Database::IdType> _tracklistId;
+9 -8
View File
@@ -19,19 +19,20 @@
#include "DatabaseSettingsView.hpp"
#include <Wt/WString.h>
#include <Wt/WPushButton.h>
#include <Wt/WComboBox.h>
#include <Wt/WFormModel.h>
#include <Wt/WLineEdit.h>
#include <Wt/WPushButton.h>
#include <Wt/WString.h>
#include <Wt/WStringListModel.h>
#include <Wt/WTemplateFormView.h>
#include <Wt/WFormModel.h>
#include <Wt/WStringListModel.h>
#include "common/Validators.hpp"
#include "database/Cluster.hpp"
#include "main/Services.hpp"
#include "utils/Logger.hpp"
#include "utils/Utils.hpp"
#include "common/Validators.hpp"
#include "LmsApplication.hpp"
namespace UserInterface {
@@ -287,7 +288,7 @@ DatabaseSettingsView::refreshView()
{
model->saveData();
LmsApp->getMediaScanner().reschedule();
getServices().mediaScanner->reschedule();
LmsApp->notifyMsg(MsgType::Success, Wt::WString::tr("Lms.Admin.Database.settings-saved"));
}
@@ -304,7 +305,7 @@ DatabaseSettingsView::refreshView()
immScanBtn->clicked().connect([=] ()
{
LmsApp->getMediaScanner().scheduleImmediateScan();
getServices().mediaScanner->scheduleImmediateScan();
LmsApp->notifyMsg(MsgType::Info, Wt::WString::tr("Lms.Admin.Database.scan-launched"));
});
+84
View File
@@ -0,0 +1,84 @@
/*
* 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 "ArtistInfoView.hpp"
#include "database/Artist.hpp"
#include "main/Services.hpp"
#include "similarity/SimilaritySearcher.hpp"
#include "utils/Utils.hpp"
#include "ArtistLink.hpp"
#include "LmsApplication.hpp"
using namespace Database;
namespace UserInterface {
ArtistInfo::ArtistInfo()
: Wt::WTemplate(Wt::WString::tr("Lms.Explore.ArtistInfo.template"))
{
addFunction("tr", &Wt::WTemplate::Functions::tr);
_similarArtistsContainer = bindNew<Wt::WContainerWidget>("similar-artists");
wApp->internalPathChanged().connect(std::bind([=]
{
refresh();
}));
LmsApp->getEvents().dbScanned.connect([=]
{
refresh();
});
refresh();
}
void
ArtistInfo::refresh()
{
_similarArtistsContainer->clear();
if (!wApp->internalPathMatches("/artist/"))
return;
auto artistId = readAs<Database::IdType>(wApp->internalPathNextPart("/artist/"));
if (!artistId)
return;
auto artistsIds = getServices().similaritySearcher->getSimilarArtists(LmsApp->getDboSession(), *artistId, 5);
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
std::vector<Database::Artist::pointer> artists;
for (auto artistId : artistsIds)
{
auto artist = Database::Artist::getById(LmsApp->getDboSession(), artistId);
if (artist)
artists.push_back(artist);
}
for (auto artist : artists)
_similarArtistsContainer->addNew<ArtistLink>(artist);
}
} // namespace UserInterface
+39
View File
@@ -0,0 +1,39 @@
/*
* 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/>.
*/
#pragma once
#include <Wt/WContainerWidget.h>
#include <Wt/WTemplate.h>
namespace UserInterface {
class ArtistInfo : public Wt::WTemplate
{
public:
ArtistInfo();
private:
void refresh();
Wt::WContainerWidget* _similarArtistsContainer;
};
} // namespace UserInterface
+35
View File
@@ -0,0 +1,35 @@
/*
* 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 "ArtistLink.hpp"
#include <Wt/WAnchor.h>
#include "database/Artist.hpp"
#include "LmsApplication.hpp"
namespace UserInterface {
ArtistLink::ArtistLink(Database::Artist::pointer artist)
: Wt::WTemplate(Wt::WString::tr("Lms.Explore.ArtistLink.template"))
{
bindWidget("name", LmsApplication::createArtistAnchor(artist));
}
} // namespace UserInterface
+37
View File
@@ -0,0 +1,37 @@
/*
* 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/>.
*/
#pragma once
#include <Wt/WTemplate.h>
namespace Database{
class Artist;
}
namespace UserInterface {
class ArtistLink : public Wt::WTemplate
{
public:
ArtistLink(Wt::Dbo::ptr<Database::Artist> artist);
};
}
+1
View File
@@ -25,6 +25,7 @@
#include <Wt/WText.h>
#include "database/Artist.hpp"
#include "database/Release.hpp"
#include "utils/Logger.hpp"
#include "utils/Utils.hpp"
+5 -21
View File
@@ -19,34 +19,16 @@
#include "ArtistsInfoView.hpp"
#include <Wt/WAnchor.h>
#include <Wt/WLocalDateTime.h>
#include "database/Artist.hpp"
#include "database/TrackList.hpp"
#include "utils/Utils.hpp"
#include "ArtistLink.hpp"
#include "LmsApplication.hpp"
using namespace Database;
namespace {
using namespace UserInterface;
void addEntries(Wt::WContainerWidget *container, const std::vector<Artist::pointer>& artists)
{
for (auto artist : artists)
{
Wt::WTemplate* entry = container->addNew<Wt::WTemplate>(Wt::WString::tr("Lms.Explore.ArtistsInfo.template.entry"));
entry->bindWidget("name", LmsApplication::createArtistAnchor(artist));
}
}
}
namespace UserInterface {
ArtistsInfo::ArtistsInfo()
@@ -80,7 +62,8 @@ ArtistsInfo::refreshRecentlyAdded()
auto artists = Artist::getLastAdded(LmsApp->getDboSession(), after, 5);
_recentlyAddedContainer->clear();
addEntries(_recentlyAddedContainer, artists);
for (auto artist : artists)
_recentlyAddedContainer->addNew<ArtistLink>(artist);
}
void
@@ -90,7 +73,8 @@ ArtistsInfo::refreshMostPlayed()
auto artists = LmsApp->getUser()->getPlayedTrackList()->getTopArtists(5);
_mostPlayedContainer->clear();
addEntries(_mostPlayedContainer, artists);
for (auto artist : artists)
_mostPlayedContainer->addNew<ArtistLink>(artist);
}
} // namespace UserInterface
+15 -3
View File
@@ -23,14 +23,18 @@
#include <Wt/WTemplate.h>
#include <Wt/WText.h>
#include "database/Artist.hpp"
#include "database/Release.hpp"
#include "utils/Logger.hpp"
#include "LmsApplication.hpp"
#include "ArtistInfoView.hpp"
#include "ArtistsInfoView.hpp"
#include "ArtistsView.hpp"
#include "ArtistView.hpp"
#include "Filters.hpp"
#include "ReleaseInfoView.hpp"
#include "ReleasesInfoView.hpp"
#include "ReleasesView.hpp"
#include "ReleaseView.hpp"
@@ -79,7 +83,9 @@ handleInfoPathChange(Wt::WStackedWidget* stack)
{
enum Idx
{
IdxArtists = 0,
IdxArtist = 0,
IdxArtists,
IdxRelease,
IdxReleases,
IdxTracks,
};
@@ -87,9 +93,9 @@ handleInfoPathChange(Wt::WStackedWidget* stack)
static const std::map<std::string, int> indexes =
{
{ "/artists", IdxArtists },
{ "/artist", IdxArtists },
{ "/artist", IdxArtist },
{ "/releases", IdxReleases },
{ "/release", IdxReleases },
{ "/release", IdxRelease },
{ "/tracks", IdxTracks },
};
@@ -151,9 +157,15 @@ Explore::Explore()
// Info
Wt::WStackedWidget* infoStack = bindNew<Wt::WStackedWidget>("info");
auto artistInfo = std::make_unique<ArtistInfo>();
infoStack->addWidget(std::move(artistInfo));
auto artistsInfo = std::make_unique<ArtistsInfo>();
infoStack->addWidget(std::move(artistsInfo));
auto releaseInfo = std::make_unique<ReleaseInfo>();
infoStack->addWidget(std::move(releaseInfo));
auto releasesInfo = std::make_unique<ReleasesInfo>();
infoStack->addWidget(std::move(releasesInfo));
+2
View File
@@ -24,6 +24,8 @@
#include <Wt/WPushButton.h>
#include <Wt/WTemplate.h>
#include "database/Cluster.hpp"
#include "LmsApplication.hpp"
namespace UserInterface {
+84
View File
@@ -0,0 +1,84 @@
/*
* 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 "ReleaseInfoView.hpp"
#include "database/Release.hpp"
#include "main/Services.hpp"
#include "similarity/SimilaritySearcher.hpp"
#include "utils/Utils.hpp"
#include "ReleaseLink.hpp"
#include "LmsApplication.hpp"
using namespace Database;
namespace UserInterface {
ReleaseInfo::ReleaseInfo()
: Wt::WTemplate(Wt::WString::tr("Lms.Explore.ReleaseInfo.template"))
{
addFunction("tr", &Wt::WTemplate::Functions::tr);
_similarReleasesContainer = bindNew<Wt::WContainerWidget>("similar-releases");
wApp->internalPathChanged().connect(std::bind([=]
{
refresh();
}));
LmsApp->getEvents().dbScanned.connect([=]
{
refresh();
});
refresh();
}
void
ReleaseInfo::refresh()
{
_similarReleasesContainer->clear();
if (!wApp->internalPathMatches("/release/"))
return;
auto releaseId = readAs<Database::IdType>(wApp->internalPathNextPart("/release/"));
if (!releaseId)
return;
auto releasesIds = getServices().similaritySearcher->getSimilarReleases(LmsApp->getDboSession(), *releaseId, 5);
Wt::Dbo::Transaction transaction(LmsApp->getDboSession());
std::vector<Database::Release::pointer> releases;
for (auto releaseId : releasesIds)
{
auto release = Database::Release::getById(LmsApp->getDboSession(), releaseId);
if (release)
releases.push_back(release);
}
for (auto release : releases)
_similarReleasesContainer->addNew<ReleaseLink>(release);
}
} // namespace UserInterface
+39
View File
@@ -0,0 +1,39 @@
/*
* 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/>.
*/
#pragma once
#include <Wt/WContainerWidget.h>
#include <Wt/WTemplate.h>
namespace UserInterface {
class ReleaseInfo : public Wt::WTemplate
{
public:
ReleaseInfo();
private:
void refresh();
Wt::WContainerWidget* _similarReleasesContainer;
};
} // namespace UserInterface
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2019 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 "ReleaseLink.hpp"
#include <Wt/WAnchor.h>
#include <Wt/WImage.h>
#include "database/Release.hpp"
#include "resource/ImageResource.hpp"
#include "utils/Utils.hpp"
#include "LmsApplication.hpp"
using namespace Database;
namespace UserInterface {
ReleaseLink::ReleaseLink(Database::Release::pointer release)
: Wt::WTemplate(Wt::WString::tr("Lms.Explore.ReleaseLink.template"))
{
bindWidget("release-name", LmsApplication::createReleaseAnchor(release));
Wt::WAnchor* anchor = bindWidget("cover", LmsApplication::createReleaseAnchor(release, false));
auto cover = std::make_unique<Wt::WImage>();
cover->setImageLink(LmsApp->getImageResource()->getReleaseUrl(release.id(), 48));
cover->setWidth(48);
anchor->setImage(std::move(cover));
auto artists = release->getArtists();
if (artists.size() > 1)
{
setCondition("if-has-artist", true);
bindString("artist-name", Wt::WString::tr("Lms.Explore.various-artists"));
}
else if (artists.size() == 1)
{
setCondition("if-has-artist", true);
bindWidget("artist-name", LmsApplication::createArtistAnchor(artists.front()));
}
}
} // namespace UserInterface
+37
View File
@@ -0,0 +1,37 @@
/*
* 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/>.
*/
#pragma once
#include <Wt/WTemplate.h>
namespace Database {
class Release;
}
namespace UserInterface {
class ReleaseLink : public Wt::WTemplate
{
public:
ReleaseLink(Wt::Dbo::ptr<Database::Release>);
};
} // namespace UserInterface
+5 -41
View File
@@ -19,54 +19,16 @@
#include "ReleasesInfoView.hpp"
#include <Wt/WAnchor.h>
#include <Wt/WImage.h>
#include <Wt/WLocalDateTime.h>
#include <Wt/WTemplate.h>
#include "database/Release.hpp"
#include "database/TrackList.hpp"
#include "resource/ImageResource.hpp"
#include "ReleaseLink.hpp"
#include "LmsApplication.hpp"
using namespace Database;
namespace {
using namespace UserInterface;
void addEntries(Wt::WContainerWidget* container, const std::vector<Release::pointer>& releases)
{
for (auto release : releases)
{
Wt::WTemplate* entry = container->addNew<Wt::WTemplate>(Wt::WString::tr("Lms.Explore.ReleasesInfo.template.entry"));
entry->bindWidget("release-name", LmsApplication::createReleaseAnchor(release));
Wt::WAnchor* anchor = entry->bindWidget("cover", LmsApplication::createReleaseAnchor(release, false));
auto cover = std::make_unique<Wt::WImage>();
cover->setImageLink(LmsApp->getImageResource()->getReleaseUrl(release.id(), 48));
cover->setWidth(48);
anchor->setImage(std::move(cover));
auto artists = release->getArtists();
if (artists.size() > 1)
{
entry->setCondition("if-has-artist", true);
entry->bindString("artist-name", Wt::WString::tr("Lms.Explore.various-artists"));
}
else if (artists.size() == 1)
{
entry->setCondition("if-has-artist", true);
entry->bindWidget("artist-name", LmsApplication::createArtistAnchor(artists.front()));
}
}
}
} // namespace
namespace UserInterface {
ReleasesInfo::ReleasesInfo()
@@ -101,7 +63,8 @@ ReleasesInfo::refreshRecentlyAdded()
auto releases = Release::getLastAdded(LmsApp->getDboSession(), after, 5);
_recentlyAddedContainer->clear();
addEntries(_recentlyAddedContainer, releases);
for (auto release : releases)
_recentlyAddedContainer->addNew<ReleaseLink>(release);
}
void
@@ -112,7 +75,8 @@ ReleasesInfo::refreshMostPlayed()
auto releases = LmsApp->getUser()->getPlayedTrackList()->getTopReleases(5);
_mostPlayedContainer->clear();
addEntries(_mostPlayedContainer, releases);
for (auto release : releases)
_mostPlayedContainer->addNew<ReleaseLink>(release);
}
} // namespace UserInterface
+5 -6
View File
@@ -22,16 +22,15 @@
#include <Wt/WApplication.h>
#include <Wt/Http/Response.h>
#include "cover/CoverArtGrabber.hpp"
#include "database/Track.hpp"
#include "main/Services.hpp"
#include "utils/Exception.hpp"
#include "utils/Logger.hpp"
#include "utils/Utils.hpp"
#include "database/Track.hpp"
#include "LmsApplication.hpp"
#include "cover/CoverArtGrabber.hpp"
namespace UserInterface {
static const std::string unknownCoverPath = "/images/unknown-cover.jpg";
@@ -81,7 +80,7 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons
// transactions are not thread safe
{
Wt::WApplication::UpdateLock lock(LmsApp);
cover = CoverArt::Grabber::instance().getFromTrack(LmsApp->getDboSession(), *trackId, Image::Format::JPEG, *size);
cover = getServices().coverArtGrabber->getFromTrack(LmsApp->getDboSession(), *trackId, Image::Format::JPEG, *size);
}
}
else if (releaseIdStr)
@@ -93,7 +92,7 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons
// transactions are not thread safe
{
Wt::WApplication::UpdateLock lock(LmsApp);
cover = CoverArt::Grabber::instance().getFromRelease(LmsApp->getDboSession(), *releaseId, Image::Format::JPEG, *size);
cover = getServices().coverArtGrabber->getFromRelease(LmsApp->getDboSession(), *releaseId, Image::Format::JPEG, *size);
}
}
else