[Database] restored id on Artist, Genre and Release tables. Added basic MusicBrainz ID support. Improved search filters a bit

This commit is contained in:
emeric
2015-07-26 20:29:19 +02:00
parent b8e5113914
commit d59a04f5da
44 changed files with 1600 additions and 686 deletions
+1 -1
View File
@@ -199,7 +199,7 @@ AudioMediaPlayer::load(Database::Track::id_type trackId)
bitrate = CurrentUser()->getAudioBitrate();
trackPath = track->getPath();
_mediaTitle->setText ( Wt::WString::fromUTF8(track->getName()) );
_mediaArtistRelease->setText ( Wt::WString::fromUTF8(track->getArtistName()) + " - " + Wt::WString::fromUTF8(track->getReleaseName()) );
_mediaArtistRelease->setText ( Wt::WString::fromUTF8(track->getArtist()->getName()) + " - " + Wt::WString::fromUTF8(track->getRelease()->getName()) );
_mediaCover->setImageLink( Wt::WLink (LmsApplication::instance()->getCoverResource()->getTrackUrl(trackId, 72)));
}
+23 -16
View File
@@ -52,6 +52,8 @@ void WPopupMenuClear(Wt::WPopupMenu* menu)
namespace UserInterface {
namespace Desktop {
using namespace Database;
// Special playlist generated each time the playque gets changed
// Restored at the beginning of the session
static const std::string CurrentQueuePlaylistName = "__current__";
@@ -269,7 +271,7 @@ Audio::playlistShowSaveDialog(std::string playlistName)
Wt::Dbo::Transaction transaction(DboSession());
// Actually create the dialog only if the given list already exists
if (Database::Playlist::get(DboSession(), playlistName, CurrentUser()))
if (Playlist::get(DboSession(), playlistName, CurrentUser()))
{
Wt::WMessageBox *messageBox = new Wt::WMessageBox
("Overwrite playlist",
@@ -301,25 +303,25 @@ Audio::playlistSaveFromPlayqueue(std::string playlistName)
Wt::Dbo::Transaction transaction(DboSession());
Database::Playlist::pointer playlist = Database::Playlist::get(DboSession(), playlistName, CurrentUser());
Playlist::pointer playlist = Playlist::get(DboSession(), playlistName, CurrentUser());
if (playlist)
{
LMS_LOG(MOD_UI, SEV_INFO) << "Erasing playlist '" << playlistName << "'";
playlist.remove();
}
playlist = Database::Playlist::create(DboSession(), playlistName, false, CurrentUser());
playlist = Playlist::create(DboSession(), playlistName, false, CurrentUser());
std::vector<Database::Track::id_type> trackIds;
std::vector<Track::id_type> trackIds;
_playQueue->getTracks(trackIds);
int pos = 0;
BOOST_FOREACH(Database::Track::id_type trackId, trackIds)
for (Track::id_type trackId : trackIds)
{
Database::Track::pointer track = Database::Track::getById(DboSession(), trackId);
Track::pointer track = Track::getById(DboSession(), trackId);
if (track)
Database::PlaylistEntry::create(DboSession(), track, playlist, pos++);
PlaylistEntry::create(DboSession(), track, playlist, pos++);
}
LMS_LOG(MOD_UI, SEV_INFO) << "Saving playqueue to playlist '" << playlistName << "' done. Contains " << pos << " entries";
@@ -330,16 +332,16 @@ Audio::playlistLoadToPlayqueue(std::string playlistName)
{
LMS_LOG(MOD_UI, SEV_DEBUG) << "Loading playlist '" << playlistName << "' to playqueue";
std::vector<Database::Track::id_type> entries;
std::vector<Track::id_type> entries;
{
Wt::Dbo::Transaction transaction(DboSession());
Database::Playlist::pointer playlist = Database::Playlist::get(DboSession(), playlistName, CurrentUser());
Playlist::pointer playlist = Playlist::get(DboSession(), playlistName, CurrentUser());
if (!playlist)
return;
entries = Database::PlaylistEntry::getEntries(DboSession(), playlist);
entries = PlaylistEntry::getEntries(DboSession(), playlist);
}
_playQueue->clear();
@@ -365,7 +367,7 @@ Audio::playlistShowDeleteDialog(std::string name)
{
Wt::Dbo::Transaction transaction(DboSession());
Database::Playlist::pointer playlist = Database::Playlist::get(DboSession(), name, CurrentUser());
Playlist::pointer playlist = Playlist::get(DboSession(), name, CurrentUser());
if (playlist)
playlist.remove();
@@ -396,9 +398,9 @@ Audio::playlistRefreshMenus()
}));
_popupMenuSave->addSeparator();
std::vector<Database::Playlist::pointer> playlists = Database::Playlist::get(DboSession(), CurrentUser());
std::vector<Playlist::pointer> playlists = Playlist::get(DboSession(), CurrentUser());
BOOST_FOREACH(Database::Playlist::pointer playlist, playlists)
for (Playlist::pointer playlist : playlists)
{
if (playlist->getName() == CurrentQueuePlaylistName)
continue;
@@ -431,7 +433,7 @@ Audio::search(std::string searchText)
void
Audio::addSelectedTracks(void)
{
std::vector<Database::Track::id_type> trackIds;
std::vector<Track::id_type> trackIds;
_trackView->getSelectedTracks(trackIds);
// If nothing is selected, get the whole track list
@@ -444,7 +446,9 @@ Audio::addSelectedTracks(void)
void
Audio::playSelectedTracks(PlayQueueAddType addType)
{
std::vector<Database::Track::id_type> trackIds;
std::vector<Track::id_type> trackIds;
LMS_LOG(MOD_UI, SEV_DEBUG) << "Playing selected tracks... nb selected = " << _trackView->getNbSelectedTracks() << ", add type = " << (addType == PlayQueueAddAllTracks ? "AddAll" : "AddSelected");
_playQueue->clear();
@@ -458,6 +462,9 @@ Audio::playSelectedTracks(PlayQueueAddType addType)
break;
case PlayQueueAddSelectedTracks:
LMS_LOG(MOD_UI, SEV_DEBUG) << "Adding selected tracks...";
// If nothing selected, get all the track and play everything
if (_trackView->getNbSelectedTracks() == 0)
{
@@ -485,7 +492,7 @@ Audio::playSelectedTracks(PlayQueueAddType addType)
}
void
Audio::playTrack(Database::Track::id_type trackId, int pos)
Audio::playTrack(Track::id_type trackId, int pos)
{
{
Wt::Dbo::Transaction transaction(DboSession());
+5 -9
View File
@@ -47,16 +47,12 @@ KeywordSearchFilter::getConstraint(Database::SearchFilter& filter)
boost::algorithm::split(values, _lastEmittedText, boost::is_any_of(" "), boost::token_compress_on);
// For each part, do a global search on all searchable fields
BOOST_FOREACH(std::string value, values)
for (const std::string& value : values)
{
Database::SearchFilter::FieldValues likeMatch;
likeMatch[Database::SearchFilter::Field::Artist].push_back(value);
likeMatch[Database::SearchFilter::Field::Release].push_back(value);
likeMatch[Database::SearchFilter::Field::Genre].push_back(value);
likeMatch[Database::SearchFilter::Field::Track].push_back(value);
filter.likeMatches.push_back(likeMatch);
filter.nameLikeMatch[Database::SearchFilter::Field::Artist].push_back(value);
filter.nameLikeMatch[Database::SearchFilter::Field::Release].push_back(value);
filter.nameLikeMatch[Database::SearchFilter::Field::Genre].push_back(value);
filter.nameLikeMatch[Database::SearchFilter::Field::Track].push_back(value);
}
}
}
+22 -16
View File
@@ -366,12 +366,16 @@ PlayQueue::select(int rowId)
void
PlayQueue::addTracks(const std::vector<Database::Track::id_type>& trackIds)
{
using namespace Database;
LMS_LOG(MOD_UI, SEV_DEBUG) << "Adding " << trackIds.size() << " tracks to play queue";
// Add tracks to model
//
BOOST_FOREACH(Database::Track::id_type trackId, trackIds)
for (Track::id_type trackId : trackIds)
{
Wt::Dbo::Transaction transaction(DboSession());
Database::Track::pointer track (Database::Track::getById(DboSession(), trackId));
Track::pointer track (Track::getById(DboSession(), trackId));
if (track)
{
@@ -382,7 +386,7 @@ PlayQueue::addTracks(const std::vector<Database::Track::id_type>& trackIds)
_model->setData(dataRow, COLUMN_ID_TRACK_ID, track.id(), Wt::UserRole);
std::string coverUrl;
if (track->getCoverType() != Database::Track::CoverType::None)
if (track->getCoverType() != Track::CoverType::None)
coverUrl = LmsApplication::instance()->getCoverResource()->getTrackUrl(track.id(), 64);
else
coverUrl = LmsApplication::instance()->getCoverResource()->getUnknownTrackUrl(64);
@@ -392,8 +396,8 @@ PlayQueue::addTracks(const std::vector<Database::Track::id_type>& trackIds)
TrackInfo trackInfo;
trackInfo.track = Wt::WString::fromUTF8(track->getName());
trackInfo.artist = Wt::WString::fromUTF8(track->getArtistName());
trackInfo.release = Wt::WString::fromUTF8(track->getReleaseName());
trackInfo.artist = Wt::WString::fromUTF8(track->getArtist()->getName());
trackInfo.release = Wt::WString::fromUTF8(track->getRelease()->getName());
_model->setData(dataRow, COLUMN_ID_NAME, trackInfo, TrackInfoRole);
}
}
@@ -455,19 +459,21 @@ PlayQueue::playPrevious(void)
}
}
bool
void
PlayQueue::readTrack(int rowPos)
{
LMS_LOG(MOD_UI, SEV_DEBUG) << "Reading track at pos " << rowPos;
Database::Track::id_type trackId = boost::any_cast<Database::Track::id_type>(_model->data(rowPos, COLUMN_ID_TRACK_ID, Wt::UserRole));
LMS_LOG(MOD_UI, SEV_DEBUG) << "Reading track at pos " << rowPos << ", row count = " << _model->rowCount();
setPlayingTrackPos(rowPos);
if (rowPos < _model->rowCount())
{
Database::Track::id_type trackId = boost::any_cast<Database::Track::id_type>(_model->data(rowPos, COLUMN_ID_TRACK_ID, Wt::UserRole));
_sigTrackPlay.emit(trackId, rowPos);
setPlayingTrackPos(rowPos);
this->scrollTo( _model->index(_trackSelector->getCurrent(), 0));
_sigTrackPlay.emit(trackId, rowPos);
return true;
this->scrollTo( _model->index(_trackSelector->getCurrent(), 0));
}
}
void
@@ -485,7 +491,7 @@ PlayQueue::setPlayingTrackPos(int newRowPos)
if (newRowPos >= 0)
{
_model->setData(newRowPos, COLUMN_ID_NAME, "playqueue-playing", Wt::StyleClassRole);
_model->setData(newRowPos, COLUMN_ID_NAME, std::string("playqueue-playing"), Wt::StyleClassRole);
}
}
@@ -527,7 +533,7 @@ PlayQueue::moveSelectedUp(void)
Wt::WModelIndexSet newIndexSet;
// ordered from up to down
BOOST_FOREACH(Wt::WModelIndex index, indexSet)
for (Wt::WModelIndex index : indexSet)
{
// Do nothing if the first selected index is on the top
if (index.row() == 0)
@@ -570,7 +576,7 @@ PlayQueue::moveSelectedDown(void)
Wt::WModelIndexSet newIndexSet;
// ordered from up to down
BOOST_REVERSE_FOREACH(Wt::WModelIndex index, indexSet)
for (Wt::WModelIndex index : indexSet)
{
// Do nothing if the last selected index is the last one
if (index.row() == _model->rowCount() - 1)
+1 -1
View File
@@ -72,7 +72,7 @@ class PlayQueue : public Wt::WTableView
void layoutSizeChanged (int width, int height);
bool readTrack(int rowId);
void readTrack(int rowId);
void setPlayingTrackPos(int newRowPos);
void renumber(int firstId, int lastId);
+17 -16
View File
@@ -39,7 +39,7 @@ TableFilterGenre::TableFilterGenre(Wt::WContainerWidget* parent)
SearchFilter filter;
Genre::updateGenreQueryModel(DboSession(), _queryModel, filter, columnNames);
Genre::updateUIQueryModel(DboSession(), _queryModel, filter, columnNames);
this->setSelectionMode(Wt::ExtendedSelection);
this->setSortingEnabled(true);
@@ -82,7 +82,7 @@ TableFilterGenre::layoutSizeChanged (int width, int height)
void
TableFilterGenre::refresh(SearchFilter& filter)
{
Genre::updateGenreQueryModel(DboSession(), _queryModel, filter);
Genre::updateUIQueryModel(DboSession(), _queryModel, filter);
}
// Get constraint created by this filter
@@ -91,14 +91,15 @@ TableFilterGenre::getConstraint(SearchFilter& filter)
{
Wt::WModelIndexSet indexSet = this->selectedIndexes();
BOOST_FOREACH(Wt::WModelIndex index, indexSet) {
for (Wt::WModelIndex index : indexSet)
{
if (!index.isValid())
continue;
std::string name = _queryModel.resultRow( index.row() ).get<0>();
// TODO set invisible track id
Database::Genre::id_type id = _queryModel.resultRow( index.row() ).get<0>();
filter.exactMatch[Database::SearchFilter::Field::Genre].push_back(name);
filter.idMatch[Database::SearchFilter::Field::Genre].push_back(id);
}
}
@@ -109,7 +110,7 @@ TableFilterArtist::TableFilterArtist(Wt::WContainerWidget* parent)
SearchFilter filter;
Track::updateArtistQueryModel(DboSession(), _queryModel, filter, columnNames);
Artist::updateUIQueryModel(DboSession(), _queryModel, filter, columnNames);
this->setSelectionMode(Wt::ExtendedSelection);
this->setSortingEnabled(true);
@@ -153,7 +154,7 @@ TableFilterArtist::layoutSizeChanged (int width, int height)
void
TableFilterArtist::refresh(SearchFilter& filter)
{
Track::updateArtistQueryModel(DboSession(), _queryModel, filter);
Artist::updateUIQueryModel(DboSession(), _queryModel, filter);
}
// Get constraint created by this filter
@@ -167,9 +168,9 @@ TableFilterArtist::getConstraint(SearchFilter& filter)
if (!index.isValid())
continue;
std::string name = _queryModel.resultRow( index.row() ).get<0>();
Artist::id_type id = _queryModel.resultRow( index.row() ).get<0>();
filter.exactMatch[Database::SearchFilter::Field::Artist].push_back(name);
filter.idMatch[Database::SearchFilter::Field::Artist].push_back(id);
}
}
@@ -180,7 +181,7 @@ TableFilterRelease::TableFilterRelease(Wt::WContainerWidget* parent)
SearchFilter filter;
Track::updateReleaseQueryModel(DboSession(), _queryModel, filter, columnNames);
Release::updateUIQueryModel(DboSession(), _queryModel, filter, columnNames);
this->setSelectionMode(Wt::ExtendedSelection);
this->setSortingEnabled(true);
@@ -231,7 +232,7 @@ TableFilterRelease::layoutSizeChanged (int width, int height)
void
TableFilterRelease::refresh(SearchFilter& filter)
{
Track::updateReleaseQueryModel(DboSession(), _queryModel, filter);
Release::updateUIQueryModel(DboSession(), _queryModel, filter);
}
// Get constraint created by this filter
@@ -240,14 +241,14 @@ TableFilterRelease::getConstraint(SearchFilter& filter)
{
Wt::WModelIndexSet indexSet = this->selectedIndexes();
BOOST_FOREACH(Wt::WModelIndex index, indexSet) {
for (Wt::WModelIndex index : indexSet)
{
if (!index.isValid())
continue;
std::string name = _queryModel.resultRow( index.row() ).get<0>();
Release::id_type id = _queryModel.resultRow( index.row() ).get<0>();
filter.exactMatch[Database::SearchFilter::Field::Release].push_back(name);
filter.idMatch[Database::SearchFilter::Field::Release].push_back(id);
}
}
+3 -3
View File
@@ -52,7 +52,7 @@ class TableFilterGenre : public Wt::WTableView, public Filter
SigDoubleClicked _sigDoubleClicked;
// Name, track count
Wt::Dbo::QueryModel<Database::Genre::GenreResult> _queryModel;
Wt::Dbo::QueryModel<Database::Genre::UIQueryResult> _queryModel;
};
class TableFilterArtist : public Wt::WTableView, public Filter
@@ -77,7 +77,7 @@ class TableFilterArtist : public Wt::WTableView, public Filter
SigDoubleClicked _sigDoubleClicked;
// Name, track count
Wt::Dbo::QueryModel<Database::Track::ArtistResult> _queryModel;
Wt::Dbo::QueryModel<Database::Artist::UIQueryResult> _queryModel;
};
class TableFilterRelease : public Wt::WTableView, public Filter
@@ -102,7 +102,7 @@ class TableFilterRelease : public Wt::WTableView, public Filter
SigDoubleClicked _sigDoubleClicked;
// Name, track count
Wt::Dbo::QueryModel<Database::Track::ReleaseResult> _queryModel;
Wt::Dbo::QueryModel<Database::Release::UIQueryResult> _queryModel;
};
+15 -12
View File
@@ -50,7 +50,7 @@ TrackView::TrackView(Wt::WContainerWidget* parent)
Database::SearchFilter filter;
Database::Track::updateTracksQueryModel(DboSession(), _queryModel, filter, columnNames);
Database::Track::updateUIQueryModel(DboSession(), _queryModel, filter, columnNames);
_queryModel.setBatchSize(300);
@@ -111,7 +111,7 @@ TrackView::TrackView(Wt::WContainerWidget* parent)
void
TrackView::refresh(Database::SearchFilter& filter)
{
Database::Track::updateTracksQueryModel(DboSession(), _queryModel, filter);
Database::Track::updateUIQueryModel(DboSession(), _queryModel, filter);
}
void
@@ -121,17 +121,17 @@ TrackView::getSelectedTracks(std::vector<Database::Track::id_type>& track_ids)
Wt::WModelIndexSet indexSet = this->selectedIndexes();
BOOST_FOREACH(Wt::WModelIndex index, indexSet)
for (Wt::WModelIndex index : indexSet)
{
if (!index.isValid())
continue;
Database::Track::pointer track = _queryModel.resultRow( index.row() );
Database::Track::id_type id = _queryModel.resultRow( index.row() ).get<0>();
track_ids.push_back(track.id());
track_ids.push_back(id);
}
LMS_LOG(MOD_UI, SEV_DEBUG) << "Getting all selected tracks DONE...";
LMS_LOG(MOD_UI, SEV_DEBUG) << "Getting all selected tracks: " << track_ids.size();
}
std::size_t
@@ -144,7 +144,8 @@ int
TrackView::getFirstSelectedTrackPosition(void)
{
Wt::WModelIndexSet indexSet = this->selectedIndexes();
BOOST_FOREACH(Wt::WModelIndex index, indexSet)
for (Wt::WModelIndex index : indexSet)
{
if (!index.isValid())
continue;
@@ -160,14 +161,16 @@ TrackView::getTracks(std::vector<Database::Track::id_type>& trackIds)
{
LMS_LOG(MOD_UI, SEV_DEBUG) << "Getting all tracks...";
for (int i = 0; i < _queryModel.rowCount(); ++i)
{
Database::Track::pointer track = _queryModel.resultRow(i);
Wt::Dbo::Transaction transaction(DboSession());
Wt::Dbo::collection<Database::Track::UIQueryResult> results = _queryModel.query();
trackIds.push_back(track.id());
for (auto it = results.begin(); it != results.end(); ++it)
{
Database::Track::id_type id = it->get<0>();
trackIds.push_back(id);
}
LMS_LOG(MOD_UI, SEV_DEBUG) << "Getting all tracks done!";
LMS_LOG(MOD_UI, SEV_DEBUG) << "Getting all tracks done! " << trackIds.size() << " tracks!";
}
} // namespace Desktop
+1 -1
View File
@@ -62,7 +62,7 @@ class TrackView : public Wt::WTableView, public Filter
SigTrackDoubleClicked _sigTrackDoubleClicked;
typedef Database::Track::pointer ResultType;
typedef Database::Track::UIQueryResult ResultType;
Wt::Dbo::QueryModel< ResultType > _queryModel;
Wt::WTableView* _tableView;
+7 -11
View File
@@ -28,6 +28,8 @@
namespace UserInterface {
namespace Mobile {
using namespace Database;
ArtistSearch::ArtistSearch(Wt::WContainerWidget *parent)
: Wt::WContainerWidget(parent),
_resCount(0)
@@ -57,15 +59,9 @@ ArtistSearch::search(Database::SearchFilter filter, size_t nb)
void
ArtistSearch::addResults(Database::SearchFilter filter, std::size_t nb)
{
Wt::Dbo::Transaction transaction(DboSession());
std::vector<std::string> artists;
{
Wt::Dbo::Transaction transaction(DboSession());
// Request one more to see if more results are to be expected
artists = Database::Track::getArtists(DboSession(), filter, _resCount, nb + 1);
}
std::vector<Artist::pointer> artists = Artist::getByFilter(DboSession(), filter, _resCount, nb + 1);
bool expectMoreResults;
if (artists.size() == nb + 1)
@@ -76,16 +72,16 @@ ArtistSearch::addResults(Database::SearchFilter filter, std::size_t nb)
else
expectMoreResults = false;
BOOST_FOREACH(std::string artist, artists)
for (Artist::pointer artist : artists)
{
Wt::WTemplate* res = new Wt::WTemplate(this);
res->setTemplateText(Wt::WString::tr("mobile-artist-res"));
Wt::WText *text = new Wt::WText(Wt::WString::fromUTF8(artist), Wt::PlainText);
Wt::WText *text = new Wt::WText(Wt::WString::fromUTF8(artist->getName()), Wt::PlainText);
res->bindWidget("name", text);
res->clicked().connect(std::bind([=] {
_sigArtistSelected(artist);
_sigArtistSelected(artist.id());
}));
}
+4 -4
View File
@@ -37,13 +37,13 @@ class ArtistSearch : public Wt::WContainerWidget
void search(Database::SearchFilter filter, std::size_t nb);
// Slots
Wt::Signal<std::string>& artistSelected() { return _sigArtistSelected;}
Wt::Signal<void>& moreArtistsSelected() { return _sigMoreArtistsSelected;}
Wt::Signal<Database::Artist::id_type>& artistSelected() { return _sigArtistSelected;}
Wt::Signal<void>& moreArtistsSelected() { return _sigMoreArtistsSelected;}
private:
Wt::Signal<std::string> _sigArtistSelected;
Wt::Signal<void> _sigMoreArtistsSelected;
Wt::Signal<Database::Artist::id_type> _sigArtistSelected;
Wt::Signal<void> _sigMoreArtistsSelected;
void clear(void);
void addResults(Database::SearchFilter filter, size_t nb);
+31 -41
View File
@@ -41,6 +41,8 @@
namespace UserInterface {
namespace Mobile {
using namespace Database;
Audio::Audio(Wt::WContainerWidget *parent)
: UserInterface::Audio(parent)
{
@@ -72,13 +74,13 @@ Audio::Audio(Wt::WContainerWidget *parent)
switch (CurrentUser()->getAudioEncoding())
{
case Database::AudioEncoding::MP3: encoding = Wt::WMediaPlayer::MP3; break;
case Database::AudioEncoding::WEBMA: encoding = Wt::WMediaPlayer::WEBMA; break;
case Database::AudioEncoding::OGA: encoding = Wt::WMediaPlayer::OGA; break;
case Database::AudioEncoding::FLA: encoding = Wt::WMediaPlayer::FLA; break;
case Database::AudioEncoding::AUTO:
case AudioEncoding::MP3: encoding = Wt::WMediaPlayer::MP3; break;
case AudioEncoding::WEBMA: encoding = Wt::WMediaPlayer::WEBMA; break;
case AudioEncoding::OGA: encoding = Wt::WMediaPlayer::OGA; break;
case AudioEncoding::FLA: encoding = Wt::WMediaPlayer::FLA; break;
case AudioEncoding::AUTO:
default:
encoding = AudioMediaPlayer::getBestEncoding();
encoding = AudioMediaPlayer::getBestEncoding();
}
}
@@ -96,43 +98,28 @@ Audio::Audio(Wt::WContainerWidget *parent)
boost::algorithm::split(keywords, text, boost::is_any_of(" "), boost::token_compress_on);
{
Database::SearchFilter filter;
BOOST_FOREACH(std::string keyword, keywords)
SearchFilter filter;
for (std::string keyword : keywords)
{
Database::SearchFilter::FieldValues likeMatch;
likeMatch[Database::SearchFilter::Field::Artist].push_back(keyword);
likeMatch[Database::SearchFilter::Field::Release].push_back(keyword);
filter.likeMatches.push_back(likeMatch);
filter.nameLikeMatch[SearchFilter::Field::Artist].push_back(keyword);
filter.nameLikeMatch[SearchFilter::Field::Release].push_back(keyword);
}
releaseSearch->search(filter, 3);
}
{
Database::SearchFilter filter;
BOOST_FOREACH(std::string keyword, keywords)
{
Database::SearchFilter::FieldValues likeMatch;
likeMatch[Database::SearchFilter::Field::Artist].push_back(keyword);
filter.likeMatches.push_back(likeMatch);
}
SearchFilter filter;
for (std::string keyword : keywords)
filter.nameLikeMatch[SearchFilter::Field::Artist].push_back(keyword);
artistSearch->search(filter, 3);
}
{
Database::SearchFilter filter;
SearchFilter filter;
BOOST_FOREACH(std::string keyword, keywords)
{
Database::SearchFilter::FieldValues likeMatch;
likeMatch[Database::SearchFilter::Field::Track].push_back(keyword);
filter.likeMatches.push_back(likeMatch);
}
filter.nameLikeMatch[SearchFilter::Field::Track].push_back(keyword);
trackSearch->search(filter, 3);
}
@@ -143,38 +130,41 @@ Audio::Audio(Wt::WContainerWidget *parent)
}));
artistSearch->moreArtistsSelected().connect(std::bind([=] {
artistSearch->moreArtistsSelected().connect(std::bind([=]
{
releaseSearch->hide();
trackSearch->hide();
artistSearch->show();
}));
artistSearch->artistSelected().connect(std::bind([=] (std::string artist) {
artistSearch->artistSelected().connect(std::bind([=] (Artist::id_type artistId)
{
artistSearch->hide();
trackSearch->hide();
releaseSearch->show();
Database::SearchFilter filter;
filter.exactMatch[Database::SearchFilter::Field::Artist].push_back(artist);
SearchFilter filter;
filter.idMatch[SearchFilter::Field::Artist].push_back(artistId);
releaseSearch->search(filter, 20);
}, std::placeholders::_1));
releaseSearch->moreReleasesSelected().connect(std::bind([=] {
releaseSearch->moreReleasesSelected().connect(std::bind([=]
{
artistSearch->hide();
trackSearch->hide();
releaseSearch->show();
}));
releaseSearch->releaseSelected().connect(std::bind([=] (std::string release)
releaseSearch->releaseSelected().connect(std::bind([=] (Release::id_type releaseId)
{
artistSearch->hide();
releaseSearch->hide();
trackSearch->show();
// TODO load track search with selected release
Database::SearchFilter filter;
filter.exactMatch[Database::SearchFilter::Field::Release].push_back(release);
SearchFilter filter;
filter.idMatch[SearchFilter::Field::Release].push_back(releaseId);
trackSearch->search(filter, 20);
}, std::placeholders::_1));
@@ -185,13 +175,13 @@ Audio::Audio(Wt::WContainerWidget *parent)
releaseSearch->hide();
}));
trackSearch->trackPlay().connect(std::bind([=] (Database::Track::id_type id)
trackSearch->trackPlay().connect(std::bind([=] (Track::id_type id)
{
LMS_LOG(MOD_UI, SEV_DEBUG) << "Playing track id " << id;
// TODO reduce transaction scope here
Wt::Dbo::Transaction transaction(DboSession());
Database::Track::pointer track = Database::Track::getById(DboSession(), id);
Track::pointer track = Track::getById(DboSession(), id);
if (track)
{
@@ -217,7 +207,7 @@ Audio::Audio(Wt::WContainerWidget *parent)
// Initially, populate the widgets using an empty search
{
Database::SearchFilter filter; // empty filter
SearchFilter filter; // empty filter
artistSearch->search(filter, 3);
releaseSearch->search(filter, 3);
trackSearch->search(filter, 3);
@@ -98,7 +98,7 @@ AudioMediaPlayer::play(Database::Track::id_type trackId, const Transcode::Parame
Database::Track::pointer track = Database::Track::getById(DboSession(), trackId);
_track->setText( Wt::WString::fromUTF8(track->getName() ));
_artistRelease->setText( Wt::WString::fromUTF8(track->getArtistName()) );
_artistRelease->setText( Wt::WString::fromUTF8(track->getArtist()->getName()) );
}
}
+8 -12
View File
@@ -30,6 +30,8 @@
namespace UserInterface {
namespace Mobile {
using namespace Database;
ReleaseSearch::ReleaseSearch(Wt::WContainerWidget *parent)
: Wt::WContainerWidget(parent),
_resCount(0)
@@ -59,15 +61,9 @@ ReleaseSearch::search(Database::SearchFilter filter, size_t max)
void
ReleaseSearch::addResults(Database::SearchFilter filter, size_t nb)
{
Wt::Dbo::Transaction transaction(DboSession());
std::vector<std::string> releases;
{
Wt::Dbo::Transaction transaction(DboSession());
// Request one more to see if more results are to be expected
releases = Database::Track::getReleases(DboSession(), filter, _resCount, nb + 1);
}
std::vector<Release::pointer> releases = Release::getByFilter(DboSession(), filter, _resCount, nb + 1);
bool expectMoreResults;
if (releases.size() == nb + 1)
@@ -78,20 +74,20 @@ ReleaseSearch::addResults(Database::SearchFilter filter, size_t nb)
else
expectMoreResults = false;
BOOST_FOREACH(std::string release, releases)
for (Release::pointer release : releases)
{
Wt::WTemplate* releaseWidget = new Wt::WTemplate(this);
releaseWidget->setTemplateText(Wt::WString::tr("mobile-release-res"));
Wt::WImage *cover = new Wt::WImage();
cover->setStyleClass("center-block");
cover->setImageLink( Wt::WLink( LmsApplication::instance()->getCoverResource()->getReleaseUrl(release, 56)));
cover->setImageLink( Wt::WLink( LmsApplication::instance()->getCoverResource()->getReleaseUrl(release.id(), 56)));
releaseWidget->bindWidget("cover", cover);
releaseWidget->bindWidget("name", new Wt::WText(Wt::WString::fromUTF8(release), Wt::PlainText));
releaseWidget->bindWidget("name", new Wt::WText(Wt::WString::fromUTF8(release->getName()), Wt::PlainText));
releaseWidget->clicked().connect(std::bind([=] {
_sigReleaseSelected(release);
_sigReleaseSelected(release.id());
}));
}
+4 -4
View File
@@ -37,13 +37,13 @@ class ReleaseSearch : public Wt::WContainerWidget
void search(Database::SearchFilter filter, size_t nb);
// Slots
Wt::Signal<std::string>& releaseSelected() { return _sigReleaseSelected;}
Wt::Signal<void>& moreReleasesSelected() { return _sigMoreReleasesSelected;}
Wt::Signal<Database::Release::id_type>& releaseSelected() { return _sigReleaseSelected;}
Wt::Signal<void>& moreReleasesSelected() { return _sigMoreReleasesSelected;}
private:
Wt::Signal<std::string> _sigReleaseSelected;
Wt::Signal<void> _sigMoreReleasesSelected;
Wt::Signal<Database::Release::id_type> _sigReleaseSelected;
Wt::Signal<void> _sigMoreReleasesSelected;
void clear(void);
void addResults(Database::SearchFilter filter, size_t nb);
+7 -5
View File
@@ -30,6 +30,8 @@
namespace UserInterface {
namespace Mobile {
using namespace Database;
TrackSearch::TrackSearch(Wt::WContainerWidget *parent)
: Wt::WContainerWidget(parent),
_resCount(0)
@@ -62,7 +64,7 @@ TrackSearch::addResults(Database::SearchFilter filter, size_t nb)
{
Wt::Dbo::Transaction transaction(DboSession());
std::vector< Database::Track::pointer > tracks = Database::Track::getTracks(DboSession(), filter, _resCount, nb + 1);
std::vector<Track::pointer > tracks = Track::getByFilter(DboSession(), filter, _resCount, nb + 1);
bool expectMoreResults;
if (tracks.size() == nb + 1)
@@ -73,7 +75,7 @@ TrackSearch::addResults(Database::SearchFilter filter, size_t nb)
else
expectMoreResults = false;
BOOST_FOREACH(Database::Track::pointer track, tracks)
for (Track::pointer track : tracks)
{
Wt::WTemplate* trackWidget = new Wt::WTemplate(this);
trackWidget->setTemplateText(Wt::WString::tr("mobile-track-res"));
@@ -90,11 +92,11 @@ TrackSearch::addResults(Database::SearchFilter filter, size_t nb)
title->setStyleClass("mobile-track");
container->addWidget(title);
if (!track->getArtistName().empty()
|| !track->getReleaseName().empty())
if (!track->getArtist()->getName().empty()
|| !track->getRelease()->getName().empty())
{
title->setInline(false);
Wt::WText *artistRelease = new Wt::WText(Wt::WString::fromUTF8(track->getArtistName() + " - " + track->getReleaseName()), Wt::PlainText);
Wt::WText *artistRelease = new Wt::WText(Wt::WString::fromUTF8(track->getArtist()->getName() + " - " + track->getRelease()->getName()), Wt::PlainText);
artistRelease->setStyleClass("mobile-artist");
container->addWidget(artistRelease);
}
+62 -56
View File
@@ -17,8 +17,6 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <boost/foreach.hpp>
#include <Wt/WApplication>
#include <Wt/Http/Response>
@@ -73,9 +71,9 @@ CoverResource::getDefaultCover(std::size_t size)
}
std::string
CoverResource::getReleaseUrl(std::string releaseName, std::size_t size) const
CoverResource::getReleaseUrl(Database::Release::id_type releaseId, std::size_t size) const
{
return url() + "&release=" + releaseName + "&size=" + std::to_string(size);
return url() + "&releaseid=" + std::to_string(releaseId) + "&size=" + std::to_string(size);
}
std::string
@@ -101,76 +99,84 @@ CoverResource::putCover(Wt::Http::Response& response, const CoverArt::CoverArt&
void
CoverResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response)
{
// Get the id of the track
// Retrieve parameters
const std::string *trackIdStr = request.getParameter("trackid");
const std::string *releaseIdStr = request.getParameter("releaseid");
const std::string *sizeStr = request.getParameter("size");
const std::string *releaseStr = request.getParameter("release");
std::vector<CoverArt::CoverArt> covers;
// Mandatory parameter size
if (!sizeStr)
return;
std::size_t size = std::stol(*sizeStr);
if (size > maxSize)
return;
if (trackIdStr)
try
{
Database::Track::id_type trackId = std::stol(*trackIdStr);
boost::filesystem::path path;
Database::Track::CoverType coverType = Database::Track::CoverType::None;
std::vector<CoverArt::CoverArt> covers;
// Mandatory parameter size
if (!sizeStr)
return;
std::size_t size = std::stol(*sizeStr);
if (size > maxSize)
return;
if (trackIdStr)
{
Database::Track::id_type trackId = std::stol(*trackIdStr);
boost::filesystem::path path;
Database::Track::CoverType coverType = Database::Track::CoverType::None;
{
// transactions are not thread safe
std::unique_lock<std::mutex> lock(_mutex);
Wt::Dbo::Transaction transaction(_db.getSession());
Database::Track::pointer track = Database::Track::getById(_db.getSession(), trackId);
if (track)
{
coverType = track->getCoverType();
path = track->getPath();
}
}
switch (coverType)
{
case Database::Track::CoverType::Embedded:
covers = CoverArt::Grabber::instance().getFromTrack(path);
break;
case Database::Track::CoverType::ExternalFile:
covers = CoverArt::Grabber::instance().getFromDirectory(path.parent_path());
break;
case Database::Track::CoverType::None:
break;
}
}
else if (releaseIdStr)
{
Database::Release::id_type releaseId = std::stol(*releaseIdStr); // TODO try catch
// transactions are not thread safe
std::unique_lock<std::mutex> lock(_mutex);
Wt::Dbo::Transaction transaction(_db.getSession());
Database::Track::pointer track = Database::Track::getById(_db.getSession(), trackId);
if (track)
covers = CoverArt::Grabber::instance().getFromRelease(_db.getSession(), releaseId);
}
for (CoverArt::CoverArt& cover : covers)
{
if (cover.scale(size))
{
coverType = track->getCoverType();
path = track->getPath();
putCover(response, cover);
return;
}
}
switch (coverType)
{
case Database::Track::CoverType::Embedded:
covers = CoverArt::Grabber::instance().getFromTrack(path);
break;
// If no cover found, just send default one
putCover(response, getDefaultCover(size));
case Database::Track::CoverType::ExternalFile:
covers = CoverArt::Grabber::instance().getFromDirectory(path.parent_path());
break;
case Database::Track::CoverType::None:
break;
}
}
else if (releaseStr)
catch (std::invalid_argument& e)
{
// transactions are not thread safe
std::unique_lock<std::mutex> lock(_mutex);
Wt::Dbo::Transaction transaction(_db.getSession());
covers = CoverArt::Grabber::instance().getFromRelease(_db.getSession(), *releaseStr);
LMS_LOG(MOD_UI, SEV_ERROR) << "Invalid argument: " << e.what();
}
BOOST_FOREACH(CoverArt::CoverArt& cover, covers)
{
if (cover.scale(size))
{
putCover(response, cover);
return;
}
}
// If no cover found, just send default one
putCover(response, getDefaultCover(size));
}
} // namespace UserInterface
+1 -1
View File
@@ -39,7 +39,7 @@ class CoverResource : public Wt::WResource
CoverResource(Database::Handler& db, Wt::WObject *parent = 0);
~CoverResource();
std::string getReleaseUrl(std::string releaseName, size_t size) const;
std::string getReleaseUrl(Database::Release::id_type releaseId, size_t size) const;
std::string getTrackUrl(Database::Track::id_type trackId, size_t size) const;
std::string getUnknownTrackUrl(size_t size) const;