Make Musicbrainz cover provider respect rate limiting

This commit is contained in:
Jonas Kvinge 2020-05-15 22:53:21 +02:00
parent e9e0829cdc
commit f4429e8c4a
2 changed files with 50 additions and 4 deletions

View File

@ -23,11 +23,13 @@
#include <QtGlobal>
#include <QObject>
#include <QQueue>
#include <QVariant>
#include <QByteArray>
#include <QString>
#include <QUrl>
#include <QUrlQuery>
#include <QTimer>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
@ -47,8 +49,15 @@
const char *MusicbrainzCoverProvider::kReleaseSearchUrl = "https://musicbrainz.org/ws/2/release/";
const char *MusicbrainzCoverProvider::kAlbumCoverUrl = "https://coverartarchive.org/release/%1/front";
const int MusicbrainzCoverProvider::kLimit = 8;
const int MusicbrainzCoverProvider::kRequestsDelay = 1000;
MusicbrainzCoverProvider::MusicbrainzCoverProvider(Application *app, QObject *parent): JsonCoverProvider("MusicBrainz", true, false, 1.5, true, false, app, parent), network_(new NetworkAccessManager(this)) {}
MusicbrainzCoverProvider::MusicbrainzCoverProvider(Application *app, QObject *parent): JsonCoverProvider("MusicBrainz", true, false, 1.5, true, false, app, parent), network_(new NetworkAccessManager(this)), timer_flush_requests_(new QTimer(this)) {
timer_flush_requests_->setInterval(kRequestsDelay);
timer_flush_requests_->setSingleShot(false);
connect(timer_flush_requests_, SIGNAL(timeout()), this, SLOT(FlushRequests()));
}
MusicbrainzCoverProvider::~MusicbrainzCoverProvider() {
@ -65,7 +74,20 @@ bool MusicbrainzCoverProvider::StartSearch(const QString &artist, const QString
Q_UNUSED(title);
QString query = QString("release:\"%1\" AND artist:\"%2\"").arg(album.trimmed().replace('"', "\\\"")).arg(artist.trimmed().replace('"', "\\\""));
SearchRequest request(id, artist, album);
queue_search_requests_ << request;
if (!timer_flush_requests_->isActive()) {
timer_flush_requests_->start();
}
return true;
}
void MusicbrainzCoverProvider::SendSearchRequest(const SearchRequest &request) {
QString query = QString("release:\"%1\" AND artist:\"%2\"").arg(request.album.trimmed().replace('"', "\\\"")).arg(request.artist.trimmed().replace('"', "\\\""));
QUrlQuery url_query;
url_query.addQueryItem("query", query);
@ -78,9 +100,18 @@ bool MusicbrainzCoverProvider::StartSearch(const QString &artist, const QString
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
QNetworkReply *reply = network_->get(req);
replies_ << reply;
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id); });
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, request.id); });
return true;
}
void MusicbrainzCoverProvider::FlushRequests() {
if (!queue_search_requests_.isEmpty()) {
SendSearchRequest(queue_search_requests_.dequeue());
return;
}
timer_flush_requests_->stop();
}

View File

@ -24,6 +24,7 @@
#include <QObject>
#include <QList>
#include <QQueue>
#include <QByteArray>
#include <QVariant>
#include <QString>
@ -33,10 +34,12 @@
class QNetworkAccessManager;
class QNetworkReply;
class QTimer;
class Application;
class MusicbrainzCoverProvider : public JsonCoverProvider {
Q_OBJECT
public:
explicit MusicbrainzCoverProvider(Application *app, QObject *parent = nullptr);
~MusicbrainzCoverProvider();
@ -44,9 +47,18 @@ class MusicbrainzCoverProvider : public JsonCoverProvider {
bool StartSearch(const QString &artist, const QString &album, const QString &title, const int id);
private slots:
void FlushRequests();
void HandleSearchReply(QNetworkReply *reply, const int search_id);
private:
struct SearchRequest {
explicit SearchRequest(const int _id, const QString &_artist, const QString &_album) : id(_id), artist(_artist), album(_album) {}
int id;
QString artist;
QString album;
};
void SendSearchRequest(const SearchRequest &request);
QByteArray GetReplyData(QNetworkReply *reply);
void Error(const QString &error, const QVariant &debug = QVariant());
@ -54,8 +66,11 @@ class MusicbrainzCoverProvider : public JsonCoverProvider {
static const char *kReleaseSearchUrl;
static const char *kAlbumCoverUrl;
static const int kLimit;
static const int kRequestsDelay;
QNetworkAccessManager *network_;
QTimer *timer_flush_requests_;
QQueue<SearchRequest> queue_search_requests_;
QList<QNetworkReply*> replies_;
};