Allow the artist and album to be specified separately when searching for album covers
This commit is contained in:
parent
2e9ec3e9d4
commit
bac414a630
@ -39,8 +39,9 @@ class AmazonCoverProvider(clementine.CoverProvider):
|
|||||||
|
|
||||||
self.network = clementine.NetworkAccessManager()
|
self.network = clementine.NetworkAccessManager()
|
||||||
|
|
||||||
def StartSearch(self, query, id):
|
def StartSearch(self, artist, album, id):
|
||||||
url = QUrl.fromEncoded(self.API_URL.format(self.PrepareAmazonRESTUrl(query)))
|
query = self.PrepareAmazonRESTUrl(artist + " " + album)
|
||||||
|
url = QUrl.fromEncoded(self.API_URL.format(query))
|
||||||
LOGGER.debug("ID %d: Sending request to '%s'" % (id, url))
|
LOGGER.debug("ID %d: Sending request to '%s'" % (id, url))
|
||||||
|
|
||||||
reply = self.network.get(QNetworkRequest(url))
|
reply = self.network.get(QNetworkRequest(url))
|
||||||
|
@ -25,8 +25,8 @@ class GoogleImagesCoverProvider(clementine.CoverProvider):
|
|||||||
}
|
}
|
||||||
self.network = clementine.NetworkAccessManager()
|
self.network = clementine.NetworkAccessManager()
|
||||||
|
|
||||||
def StartSearch(self, query, id):
|
def StartSearch(self, artist, album, id):
|
||||||
url = self.GetQueryURL(query)
|
url = self.GetQueryURL(artist + " " + album)
|
||||||
LOGGER.info("Id %d - sending request to '%s'" % (id, url))
|
LOGGER.info("Id %d - sending request to '%s'" % (id, url))
|
||||||
|
|
||||||
reply = self.network.get(QNetworkRequest(url))
|
reply = self.network.get(QNetworkRequest(url))
|
||||||
@ -34,12 +34,12 @@ class GoogleImagesCoverProvider(clementine.CoverProvider):
|
|||||||
def QueryFinished():
|
def QueryFinished():
|
||||||
LOGGER.debug("Id %d - finished" % id)
|
LOGGER.debug("Id %d - finished" % id)
|
||||||
|
|
||||||
self.SearchFinished(id, self.ParseReply(query, reply))
|
self.SearchFinished(id, self.ParseReply(artist, album, reply))
|
||||||
|
|
||||||
reply.connect("finished()", QueryFinished)
|
reply.connect("finished()", QueryFinished)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def ParseReply(self, query, reply):
|
def ParseReply(self, artist, album, reply):
|
||||||
results = json.loads(str(reply.readAll()))
|
results = json.loads(str(reply.readAll()))
|
||||||
|
|
||||||
parsed = []
|
parsed = []
|
||||||
@ -48,7 +48,9 @@ class GoogleImagesCoverProvider(clementine.CoverProvider):
|
|||||||
LOGGER.warning("Error parsing reply: %s", results["responseDetails"])
|
LOGGER.warning("Error parsing reply: %s", results["responseDetails"])
|
||||||
return parsed
|
return parsed
|
||||||
|
|
||||||
LOGGER.info("Parsing reply for query '%s'", query)
|
query = "%s - %s" % (artist, album)
|
||||||
|
|
||||||
|
LOGGER.info("Parsing reply for query '%s'" % query)
|
||||||
for result in results['responseData']['results']:
|
for result in results['responseData']['results']:
|
||||||
current = clementine.CoverSearchResult()
|
current = clementine.CoverSearchResult()
|
||||||
|
|
||||||
|
@ -33,10 +33,11 @@ AlbumCoverFetcher::AlbumCoverFetcher(QObject* parent, QNetworkAccessManager* net
|
|||||||
connect(request_starter_, SIGNAL(timeout()), SLOT(StartRequests()));
|
connect(request_starter_, SIGNAL(timeout()), SLOT(StartRequests()));
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 AlbumCoverFetcher::FetchAlbumCover(
|
quint64 AlbumCoverFetcher::FetchAlbumCover(const QString& artist,
|
||||||
const QString& artist_name, const QString& album_name) {
|
const QString& album) {
|
||||||
CoverSearchRequest request;
|
CoverSearchRequest request;
|
||||||
request.query = artist_name + " " + album_name;
|
request.artist = artist;
|
||||||
|
request.album = album;
|
||||||
request.search = false;
|
request.search = false;
|
||||||
request.id = next_id_ ++;
|
request.id = next_id_ ++;
|
||||||
|
|
||||||
@ -44,9 +45,11 @@ quint64 AlbumCoverFetcher::FetchAlbumCover(
|
|||||||
return request.id;
|
return request.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 AlbumCoverFetcher::SearchForCovers(const QString &query) {
|
quint64 AlbumCoverFetcher::SearchForCovers(const QString& artist,
|
||||||
|
const QString& album) {
|
||||||
CoverSearchRequest request;
|
CoverSearchRequest request;
|
||||||
request.query = query;
|
request.artist = artist;
|
||||||
|
request.album = album;
|
||||||
request.search = true;
|
request.search = true;
|
||||||
request.id = next_id_ ++;
|
request.id = next_id_ ++;
|
||||||
|
|
||||||
@ -81,8 +84,8 @@ void AlbumCoverFetcher::StartRequests() {
|
|||||||
|
|
||||||
// search objects are this fetcher's children so worst case scenario - they get
|
// search objects are this fetcher's children so worst case scenario - they get
|
||||||
// deleted with it
|
// deleted with it
|
||||||
AlbumCoverFetcherSearch* search = new AlbumCoverFetcherSearch(request, network_,
|
AlbumCoverFetcherSearch* search = new AlbumCoverFetcherSearch(
|
||||||
this);
|
request, network_, this);
|
||||||
active_requests_.insert(request.id, search);
|
active_requests_.insert(request.id, search);
|
||||||
|
|
||||||
connect(search, SIGNAL(SearchFinished(quint64, CoverSearchResults)),
|
connect(search, SIGNAL(SearchFinished(quint64, CoverSearchResults)),
|
||||||
|
@ -38,8 +38,11 @@ class AlbumCoverFetcherSearch;
|
|||||||
struct CoverSearchRequest {
|
struct CoverSearchRequest {
|
||||||
// an unique (for one AlbumCoverFetcher) request identifier
|
// an unique (for one AlbumCoverFetcher) request identifier
|
||||||
quint64 id;
|
quint64 id;
|
||||||
|
|
||||||
// a search query
|
// a search query
|
||||||
QString query;
|
QString artist;
|
||||||
|
QString album;
|
||||||
|
|
||||||
// is this only a search request or should we also fetch the first
|
// is this only a search request or should we also fetch the first
|
||||||
// cover that's found?
|
// cover that's found?
|
||||||
bool search;
|
bool search;
|
||||||
@ -77,7 +80,7 @@ class AlbumCoverFetcher : public QObject {
|
|||||||
|
|
||||||
static const int kMaxConcurrentRequests;
|
static const int kMaxConcurrentRequests;
|
||||||
|
|
||||||
quint64 SearchForCovers(const QString& query);
|
quint64 SearchForCovers(const QString& artist, const QString& album);
|
||||||
quint64 FetchAlbumCover(const QString& artist, const QString& album);
|
quint64 FetchAlbumCover(const QString& artist, const QString& album);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
@ -60,18 +60,19 @@ void AlbumCoverFetcherSearch::TerminateSearch() {
|
|||||||
void AlbumCoverFetcherSearch::Start() {
|
void AlbumCoverFetcherSearch::Start() {
|
||||||
CoverProviders* providers = &CoverProviders::instance();
|
CoverProviders* providers = &CoverProviders::instance();
|
||||||
|
|
||||||
// end this search before it even began if there are no providers...
|
|
||||||
foreach(CoverProvider* provider, providers->List()) {
|
foreach(CoverProvider* provider, providers->List()) {
|
||||||
connect(provider, SIGNAL(SearchFinished(int,QList<CoverSearchResult>)),
|
connect(provider, SIGNAL(SearchFinished(int,QList<CoverSearchResult>)),
|
||||||
SLOT(ProviderSearchFinished(int,QList<CoverSearchResult>)));
|
SLOT(ProviderSearchFinished(int,QList<CoverSearchResult>)));
|
||||||
const int id = providers->NextId();
|
const int id = providers->NextId();
|
||||||
const bool success = provider->StartSearch(request_.query, id);
|
const bool success = provider->StartSearch(
|
||||||
|
request_.artist, request_.album, id);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
pending_requests_[id] = provider;
|
pending_requests_[id] = provider;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// end this search before it even began if there are no providers...
|
||||||
if(pending_requests_.isEmpty()) {
|
if(pending_requests_.isEmpty()) {
|
||||||
TerminateSearch();
|
TerminateSearch();
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
// Starts searching for covers matching the given query text. Returns true
|
// Starts searching for covers matching the given query text. Returns true
|
||||||
// if the query has been started, or false if an error occurred. The provider
|
// if the query has been started, or false if an error occurred. The provider
|
||||||
// should remember the ID and emit it along with the result when it finishes.
|
// should remember the ID and emit it along with the result when it finishes.
|
||||||
virtual bool StartSearch(const QString& query, int id) = 0;
|
virtual bool StartSearch(const QString& artist, const QString& album, int id) = 0;
|
||||||
|
|
||||||
virtual void CancelSearch(int id) {}
|
virtual void CancelSearch(int id) {}
|
||||||
|
|
||||||
|
@ -30,10 +30,10 @@ LastFmCoverProvider::LastFmCoverProvider(QObject* parent)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LastFmCoverProvider::StartSearch(const QString& query, int id) {
|
bool LastFmCoverProvider::StartSearch(const QString& artist, const QString& album, int id) {
|
||||||
QMap<QString, QString> params;
|
QMap<QString, QString> params;
|
||||||
params["method"] = "album.search";
|
params["method"] = "album.search";
|
||||||
params["album"] = query;
|
params["album"] = album + " " + artist;
|
||||||
|
|
||||||
QNetworkReply* reply = lastfm::ws::post(params);
|
QNetworkReply* reply = lastfm::ws::post(params);
|
||||||
connect(reply, SIGNAL(finished()), SLOT(QueryFinished()));
|
connect(reply, SIGNAL(finished()), SLOT(QueryFinished()));
|
||||||
|
@ -33,7 +33,7 @@ class LastFmCoverProvider : public CoverProvider {
|
|||||||
public:
|
public:
|
||||||
LastFmCoverProvider(QObject* parent);
|
LastFmCoverProvider(QObject* parent);
|
||||||
|
|
||||||
bool StartSearch(const QString& query, int id);
|
bool StartSearch(const QString& artist, const QString& album, int id);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void QueryFinished();
|
void QueryFinished();
|
||||||
|
@ -79,16 +79,16 @@ if (_wrapper) {
|
|||||||
}
|
}
|
||||||
CoverProvider::CancelSearch(id);
|
CoverProvider::CancelSearch(id);
|
||||||
}
|
}
|
||||||
bool PythonQtShell_CoverProvider::StartSearch(const QString& query, int id)
|
bool PythonQtShell_CoverProvider::StartSearch(const QString& artist, const QString& album, int id)
|
||||||
{
|
{
|
||||||
if (_wrapper) {
|
if (_wrapper) {
|
||||||
PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "StartSearch");
|
PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, "StartSearch");
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
if (obj && !PythonQtSlotFunction_Check(obj)) {
|
if (obj && !PythonQtSlotFunction_Check(obj)) {
|
||||||
static const char* argumentList[] ={"bool" , "const QString&" , "int"};
|
static const char* argumentList[] ={"bool" , "const QString&" , "const QString&" , "int"};
|
||||||
static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(3, argumentList);
|
static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(4, argumentList);
|
||||||
bool returnValue = 0;
|
bool returnValue = 0;
|
||||||
void* args[3] = {NULL, (void*)&query, (void*)&id};
|
void* args[4] = {NULL, (void*)&artist, (void*)&album, (void*)&id};
|
||||||
PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true);
|
PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true);
|
||||||
if (result) {
|
if (result) {
|
||||||
args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue);
|
args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue);
|
||||||
|
@ -74,7 +74,7 @@ public:
|
|||||||
PythonQtShell_CoverProvider(const QString& name, QObject* parent):CoverProvider(name, parent),_wrapper(NULL) {};
|
PythonQtShell_CoverProvider(const QString& name, QObject* parent):CoverProvider(name, parent),_wrapper(NULL) {};
|
||||||
|
|
||||||
virtual void CancelSearch(int id);
|
virtual void CancelSearch(int id);
|
||||||
virtual bool StartSearch(const QString& query, int id);
|
virtual bool StartSearch(const QString& artist, const QString& album, int id);
|
||||||
virtual void childEvent(QChildEvent* arg__1);
|
virtual void childEvent(QChildEvent* arg__1);
|
||||||
virtual void customEvent(QEvent* arg__1);
|
virtual void customEvent(QEvent* arg__1);
|
||||||
virtual bool event(QEvent* arg__1);
|
virtual bool event(QEvent* arg__1);
|
||||||
|
@ -158,12 +158,7 @@ QString AlbumCoverChoiceController::LoadCoverFromURL(Song* song) {
|
|||||||
|
|
||||||
QString AlbumCoverChoiceController::SearchForCover(Song* song) {
|
QString AlbumCoverChoiceController::SearchForCover(Song* song) {
|
||||||
// Get something sensible to stick in the search box
|
// Get something sensible to stick in the search box
|
||||||
QString query = song->artist();
|
QImage image = cover_searcher_->Exec(song->artist(), song->album());
|
||||||
if (!query.isEmpty())
|
|
||||||
query += " ";
|
|
||||||
query += song->album();
|
|
||||||
|
|
||||||
QImage image = cover_searcher_->Exec(query);
|
|
||||||
|
|
||||||
if(!image.isNull()) {
|
if(!image.isNull()) {
|
||||||
QString cover = SaveCoverInCache(song->artist(), song->album(), image);
|
QString cover = SaveCoverInCache(song->artist(), song->album(), image);
|
||||||
|
@ -115,11 +115,12 @@ void AlbumCoverSearcher::Init(AlbumCoverFetcher* fetcher) {
|
|||||||
connect(fetcher_, SIGNAL(SearchFinished(quint64,CoverSearchResults)), SLOT(SearchFinished(quint64,CoverSearchResults)));
|
connect(fetcher_, SIGNAL(SearchFinished(quint64,CoverSearchResults)), SLOT(SearchFinished(quint64,CoverSearchResults)));
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage AlbumCoverSearcher::Exec(const QString &query) {
|
QImage AlbumCoverSearcher::Exec(const QString& artist, const QString& album) {
|
||||||
ui_->query->setText(query);
|
ui_->artist->setText(artist);
|
||||||
ui_->query->setFocus();
|
ui_->album->setText(album);
|
||||||
|
ui_->artist->setFocus();
|
||||||
|
|
||||||
if(!query.isEmpty()) {
|
if(!artist.isEmpty() || !album.isEmpty()) {
|
||||||
Search();
|
Search();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,13 +141,14 @@ QImage AlbumCoverSearcher::Exec(const QString &query) {
|
|||||||
void AlbumCoverSearcher::Search() {
|
void AlbumCoverSearcher::Search() {
|
||||||
ui_->busy->show();
|
ui_->busy->show();
|
||||||
ui_->search->setEnabled(false);
|
ui_->search->setEnabled(false);
|
||||||
ui_->query->setEnabled(false);
|
ui_->artist->setEnabled(false);
|
||||||
|
ui_->album->setEnabled(false);
|
||||||
ui_->covers->setEnabled(false);
|
ui_->covers->setEnabled(false);
|
||||||
|
|
||||||
model_->clear();
|
model_->clear();
|
||||||
cover_loading_tasks_.clear();
|
cover_loading_tasks_.clear();
|
||||||
|
|
||||||
id_ = fetcher_->SearchForCovers(ui_->query->text());
|
id_ = fetcher_->SearchForCovers(ui_->artist->text(), ui_->album->text());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlbumCoverSearcher::SearchFinished(quint64 id, const CoverSearchResults& results) {
|
void AlbumCoverSearcher::SearchFinished(quint64 id, const CoverSearchResults& results) {
|
||||||
@ -154,7 +156,8 @@ void AlbumCoverSearcher::SearchFinished(quint64 id, const CoverSearchResults& re
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ui_->search->setEnabled(true);
|
ui_->search->setEnabled(true);
|
||||||
ui_->query->setEnabled(true);
|
ui_->artist->setEnabled(true);
|
||||||
|
ui_->album->setEnabled(true);
|
||||||
ui_->covers->setEnabled(true);
|
ui_->covers->setEnabled(true);
|
||||||
id_ = 0;
|
id_ = 0;
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ public:
|
|||||||
|
|
||||||
void Init(AlbumCoverFetcher* fetcher);
|
void Init(AlbumCoverFetcher* fetcher);
|
||||||
|
|
||||||
QImage Exec(const QString& query);
|
QImage Exec(const QString& artist, const QString& album);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void keyPressEvent(QKeyEvent *);
|
void keyPressEvent(QKeyEvent *);
|
||||||
|
@ -17,9 +17,22 @@
|
|||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="LineEdit" name="query">
|
<widget class="LineEdit" name="artist">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Artist</string>
|
||||||
|
</property>
|
||||||
<property name="hint" stdset="0">
|
<property name="hint" stdset="0">
|
||||||
<string>Enter search terms here</string>
|
<string>Artist</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="LineEdit" name="album">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Album</string>
|
||||||
|
</property>
|
||||||
|
<property name="hint" stdset="0">
|
||||||
|
<string>Album</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -99,7 +112,8 @@
|
|||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>query</tabstop>
|
<tabstop>artist</tabstop>
|
||||||
|
<tabstop>album</tabstop>
|
||||||
<tabstop>search</tabstop>
|
<tabstop>search</tabstop>
|
||||||
<tabstop>covers</tabstop>
|
<tabstop>covers</tabstop>
|
||||||
<tabstop>buttonBox</tabstop>
|
<tabstop>buttonBox</tabstop>
|
||||||
@ -139,7 +153,7 @@
|
|||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
<connection>
|
<connection>
|
||||||
<sender>query</sender>
|
<sender>artist</sender>
|
||||||
<signal>returnPressed()</signal>
|
<signal>returnPressed()</signal>
|
||||||
<receiver>search</receiver>
|
<receiver>search</receiver>
|
||||||
<slot>click()</slot>
|
<slot>click()</slot>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user