[Database] restored id on Artist, Genre and Release tables. Added basic MusicBrainz ID support. Improved search filters a bit
This commit is contained in:
@@ -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)));
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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());
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user