Delete remaining network replies and local redirct server in destructor
This commit is contained in:
parent
4bfad9dad8
commit
e35501ff0a
@ -211,7 +211,7 @@ void AlbumCoverFetcherSearch::FetchMoreImages() {
|
||||
|
||||
void AlbumCoverFetcherSearch::ProviderCoverFetchFinished(QNetworkReply *reply) {
|
||||
|
||||
disconnect(reply, &QNetworkReply::finished, this, nullptr);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
if (!pending_image_loads_.contains(reply)) return;
|
||||
|
@ -53,6 +53,17 @@ const int DeezerCoverProvider::kLimit = 10;
|
||||
|
||||
DeezerCoverProvider::DeezerCoverProvider(Application *app, QObject *parent): JsonCoverProvider("Deezer", true, false, 2.0, true, true, app, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
DeezerCoverProvider::~DeezerCoverProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool DeezerCoverProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const int id) {
|
||||
|
||||
typedef QPair<QString, QString> Param;
|
||||
@ -83,6 +94,7 @@ bool DeezerCoverProvider::StartSearch(const QString &artist, const QString &albu
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id); });
|
||||
|
||||
return true;
|
||||
@ -174,6 +186,9 @@ QJsonValue DeezerCoverProvider::ExtractData(const QByteArray &data) {
|
||||
|
||||
void DeezerCoverProvider::HandleSearchReply(QNetworkReply *reply, const int id) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
CoverSearchResults results;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
@ -40,6 +41,8 @@ class DeezerCoverProvider : public JsonCoverProvider {
|
||||
|
||||
public:
|
||||
explicit DeezerCoverProvider(Application *app, QObject *parent = nullptr);
|
||||
~DeezerCoverProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const int id);
|
||||
void CancelSearch(const int id);
|
||||
|
||||
@ -56,6 +59,7 @@ class DeezerCoverProvider : public JsonCoverProvider {
|
||||
static const int kLimit;
|
||||
|
||||
QNetworkAccessManager *network_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -61,7 +61,16 @@ const char *DiscogsCoverProvider::kSecretKeyB64 = "ZkFIcmlaSER4aHhRSlF2U3d0bm5ZV
|
||||
DiscogsCoverProvider::DiscogsCoverProvider(Application *app, QObject *parent) : JsonCoverProvider("Discogs", false, false, 0.0, false, false, app, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
DiscogsCoverProvider::~DiscogsCoverProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
requests_search_.clear();
|
||||
|
||||
}
|
||||
|
||||
bool DiscogsCoverProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const int id) {
|
||||
@ -124,6 +133,7 @@ QNetworkReply *DiscogsCoverProvider::CreateRequest(QUrl url, const ParamList &pa
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
|
||||
return reply;
|
||||
|
||||
@ -173,6 +183,9 @@ QByteArray DiscogsCoverProvider::GetReplyData(QNetworkReply *reply) {
|
||||
|
||||
void DiscogsCoverProvider::HandleSearchReply(QNetworkReply *reply, const int id) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
if (!requests_search_.contains(id)) {
|
||||
@ -258,6 +271,9 @@ void DiscogsCoverProvider::StartRelease(std::shared_ptr<DiscogsCoverSearchContex
|
||||
|
||||
void DiscogsCoverProvider::HandleReleaseReply(QNetworkReply *reply, const int search_id, const quint64 release_id) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
if (!requests_search_.contains(search_id)) {
|
||||
|
@ -28,6 +28,8 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QMetaType>
|
||||
#include <QPair>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <QByteArray>
|
||||
@ -88,6 +90,7 @@ class DiscogsCoverProvider : public JsonCoverProvider {
|
||||
|
||||
QNetworkAccessManager *network_;
|
||||
QMap<int, std::shared_ptr<DiscogsCoverSearchContext>> requests_search_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -55,6 +55,17 @@ const char *LastFmCoverProvider::kSecret = "80fd738f49596e9709b1bf9319c444a8";
|
||||
|
||||
LastFmCoverProvider::LastFmCoverProvider(Application *app, QObject *parent) : JsonCoverProvider("Last.fm", true, false, 1.0, true, false, app, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
LastFmCoverProvider::~LastFmCoverProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool LastFmCoverProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const int id) {
|
||||
|
||||
typedef QPair<QString, QString> Param;
|
||||
@ -100,6 +111,7 @@ bool LastFmCoverProvider::StartSearch(const QString &artist, const QString &albu
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
QNetworkReply *reply = network_->post(req, url_query.toString(QUrl::FullyEncoded).toUtf8());
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { QueryFinished(reply, id, type); });
|
||||
|
||||
return true;
|
||||
@ -108,6 +120,9 @@ bool LastFmCoverProvider::StartSearch(const QString &artist, const QString &albu
|
||||
|
||||
void LastFmCoverProvider::QueryFinished(QNetworkReply *reply, const int id, const QString &type) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
CoverSearchResults results;
|
||||
@ -305,7 +320,7 @@ QByteArray LastFmCoverProvider::GetReplyData(QNetworkReply *reply) {
|
||||
|
||||
void LastFmCoverProvider::Error(const QString &error, const QVariant &debug) {
|
||||
|
||||
qLog(Error) << "LastFm:" << error;
|
||||
qLog(Error) << "Last.fm:" << error;
|
||||
if (debug.isValid()) qLog(Debug) << debug;
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
@ -39,6 +40,8 @@ class LastFmCoverProvider : public JsonCoverProvider {
|
||||
|
||||
public:
|
||||
explicit LastFmCoverProvider(Application *app, QObject *parent = nullptr);
|
||||
~LastFmCoverProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const int id);
|
||||
|
||||
private slots:
|
||||
@ -63,6 +66,7 @@ class LastFmCoverProvider : public JsonCoverProvider {
|
||||
static const char *kSecret;
|
||||
|
||||
QNetworkAccessManager *network_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -50,6 +50,17 @@ const int MusicbrainzCoverProvider::kLimit = 8;
|
||||
|
||||
MusicbrainzCoverProvider::MusicbrainzCoverProvider(Application *app, QObject *parent): JsonCoverProvider("MusicBrainz", true, false, 1.5, true, false, app, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
MusicbrainzCoverProvider::~MusicbrainzCoverProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool MusicbrainzCoverProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const int id) {
|
||||
|
||||
Q_UNUSED(title);
|
||||
@ -66,6 +77,7 @@ bool MusicbrainzCoverProvider::StartSearch(const QString &artist, const QString
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id); });
|
||||
|
||||
return true;
|
||||
@ -74,6 +86,9 @@ bool MusicbrainzCoverProvider::StartSearch(const QString &artist, const QString
|
||||
|
||||
void MusicbrainzCoverProvider::HandleSearchReply(QNetworkReply *reply, const int search_id) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
CoverSearchResults results;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QByteArray>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
@ -38,6 +39,7 @@ class MusicbrainzCoverProvider : public JsonCoverProvider {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MusicbrainzCoverProvider(Application *app, QObject *parent = nullptr);
|
||||
~MusicbrainzCoverProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const int id);
|
||||
|
||||
@ -54,6 +56,7 @@ class MusicbrainzCoverProvider : public JsonCoverProvider {
|
||||
static const int kLimit;
|
||||
|
||||
QNetworkAccessManager *network_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -42,6 +42,17 @@
|
||||
|
||||
MusixmatchCoverProvider::MusixmatchCoverProvider(Application *app, QObject *parent): JsonCoverProvider("Musixmatch", true, false, 1.0, true, false, app, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
MusixmatchCoverProvider::~MusixmatchCoverProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool MusixmatchCoverProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const int id) {
|
||||
|
||||
Q_UNUSED(title);
|
||||
@ -69,6 +80,7 @@ bool MusixmatchCoverProvider::StartSearch(const QString &artist, const QString &
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id, artist, album); });
|
||||
|
||||
//qLog(Debug) << "Musixmatch: Sending request for" << artist_stripped << album_stripped << url;
|
||||
@ -81,6 +93,9 @@ void MusixmatchCoverProvider::CancelSearch(const int id) { Q_UNUSED(id); }
|
||||
|
||||
void MusixmatchCoverProvider::HandleSearchReply(QNetworkReply *reply, const int id, const QString &artist, const QString &album) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
CoverSearchResults results;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
|
||||
@ -37,6 +38,7 @@ class MusixmatchCoverProvider : public JsonCoverProvider {
|
||||
|
||||
public:
|
||||
explicit MusixmatchCoverProvider(Application *app, QObject *parent = nullptr);
|
||||
~MusixmatchCoverProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const int id);
|
||||
void CancelSearch(const int id);
|
||||
@ -49,6 +51,7 @@ class MusixmatchCoverProvider : public JsonCoverProvider {
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *network_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -53,6 +53,17 @@ const int QobuzCoverProvider::kLimit = 10;
|
||||
|
||||
QobuzCoverProvider::QobuzCoverProvider(Application *app, QObject *parent) : JsonCoverProvider("Qobuz", true, false, 2.0, true, true, app, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
QobuzCoverProvider::~QobuzCoverProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool QobuzCoverProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const int id) {
|
||||
|
||||
typedef QPair<QString, QString> Param;
|
||||
@ -88,6 +99,7 @@ bool QobuzCoverProvider::StartSearch(const QString &artist, const QString &album
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
req.setRawHeader("X-App-Id", kAppID);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id); });
|
||||
|
||||
return true;
|
||||
@ -142,6 +154,9 @@ QByteArray QobuzCoverProvider::GetReplyData(QNetworkReply *reply) {
|
||||
|
||||
void QobuzCoverProvider::HandleSearchReply(QNetworkReply *reply, const int id) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
CoverSearchResults results;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
@ -39,6 +40,8 @@ class QobuzCoverProvider : public JsonCoverProvider {
|
||||
|
||||
public:
|
||||
explicit QobuzCoverProvider(Application *app, QObject *parent = nullptr);
|
||||
~QobuzCoverProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const int id);
|
||||
void CancelSearch(const int id);
|
||||
|
||||
@ -55,6 +58,7 @@ class QobuzCoverProvider : public JsonCoverProvider {
|
||||
static const int kLimit;
|
||||
|
||||
QNetworkAccessManager *network_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -85,6 +85,17 @@ SpotifyCoverProvider::SpotifyCoverProvider(Application *app, QObject *parent) :
|
||||
|
||||
}
|
||||
|
||||
SpotifyCoverProvider::~SpotifyCoverProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SpotifyCoverProvider::Authenticate() {
|
||||
|
||||
QUrl redirect_url(kOAuthRedirectUrl);
|
||||
@ -230,6 +241,7 @@ void SpotifyCoverProvider::RequestAccessToken(const QString code, const QUrl red
|
||||
QByteArray query = url_query.toString(QUrl::FullyEncoded).toUtf8();
|
||||
|
||||
QNetworkReply *reply = network_->post(req, query);
|
||||
replies_ << reply;
|
||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(HandleLoginSSLErrors(QList<QSslError>)));
|
||||
connect(reply, &QNetworkReply::finished, [=] { AccessTokenRequestFinished(reply); });
|
||||
|
||||
@ -245,6 +257,9 @@ void SpotifyCoverProvider::HandleLoginSSLErrors(QList<QSslError> ssl_errors) {
|
||||
|
||||
void SpotifyCoverProvider::AccessTokenRequestFinished(QNetworkReply *reply) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError || reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
|
||||
@ -372,6 +387,7 @@ bool SpotifyCoverProvider::StartSearch(const QString &artist, const QString &alb
|
||||
req.setRawHeader("Authorization", "Bearer " + access_token_.toUtf8());
|
||||
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id, extract); });
|
||||
|
||||
return true;
|
||||
@ -429,6 +445,9 @@ QByteArray SpotifyCoverProvider::GetReplyData(QNetworkReply *reply) {
|
||||
|
||||
void SpotifyCoverProvider::HandleSearchReply(QNetworkReply *reply, const int id, const QString &extract) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = GetReplyData(reply);
|
||||
|
@ -46,6 +46,8 @@ class SpotifyCoverProvider : public JsonCoverProvider {
|
||||
|
||||
public:
|
||||
explicit SpotifyCoverProvider(Application *app, QObject *parent = nullptr);
|
||||
~SpotifyCoverProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const int id);
|
||||
void CancelSearch(const int id);
|
||||
|
||||
@ -88,6 +90,7 @@ class SpotifyCoverProvider : public JsonCoverProvider {
|
||||
quint64 expires_in_;
|
||||
quint64 login_time_;
|
||||
QTimer refresh_login_timer_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -59,6 +59,17 @@ TidalCoverProvider::TidalCoverProvider(Application *app, QObject *parent) :
|
||||
|
||||
}
|
||||
|
||||
TidalCoverProvider::~TidalCoverProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool TidalCoverProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const int id) {
|
||||
|
||||
typedef QPair<QString, QString> Param;
|
||||
@ -95,6 +106,7 @@ bool TidalCoverProvider::StartSearch(const QString &artist, const QString &album
|
||||
if (!service_->session_id().isEmpty()) req.setRawHeader("X-Tidal-SessionId", service_->session_id().toUtf8());
|
||||
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id); });
|
||||
|
||||
return true;
|
||||
@ -154,6 +166,9 @@ QByteArray TidalCoverProvider::GetReplyData(QNetworkReply *reply) {
|
||||
|
||||
void TidalCoverProvider::HandleSearchReply(QNetworkReply *reply, const int id) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
CoverSearchResults results;
|
||||
|
@ -44,6 +44,8 @@ class TidalCoverProvider : public JsonCoverProvider {
|
||||
|
||||
public:
|
||||
explicit TidalCoverProvider(Application *app, QObject *parent = nullptr);
|
||||
~TidalCoverProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const int id);
|
||||
void CancelSearch(const int id);
|
||||
|
||||
@ -64,6 +66,7 @@ class TidalCoverProvider : public JsonCoverProvider {
|
||||
|
||||
TidalService *service_;
|
||||
QNetworkAccessManager *network_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -48,6 +48,17 @@ const int AuddLyricsProvider::kMaxLength = 6000;
|
||||
|
||||
AuddLyricsProvider::AuddLyricsProvider(QObject *parent) : JsonLyricsProvider("AudD", true, false, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
AuddLyricsProvider::~AuddLyricsProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool AuddLyricsProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const quint64 id) {
|
||||
|
||||
Q_UNUSED(album);
|
||||
@ -65,6 +76,7 @@ bool AuddLyricsProvider::StartSearch(const QString &artist, const QString &album
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id, artist, title); });
|
||||
|
||||
//qLog(Debug) << "AudDLyrics: Sending request for" << url;
|
||||
@ -77,6 +89,9 @@ void AuddLyricsProvider::CancelSearch(const quint64 id) { Q_UNUSED(id); }
|
||||
|
||||
void AuddLyricsProvider::HandleSearchReply(QNetworkReply *reply, const quint64 id, const QString &artist, const QString &title) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QJsonArray json_result = ExtractResult(reply, artist, title);
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QJsonArray>
|
||||
@ -39,10 +40,15 @@ class AuddLyricsProvider : public JsonLyricsProvider {
|
||||
|
||||
public:
|
||||
explicit AuddLyricsProvider(QObject *parent = nullptr);
|
||||
~AuddLyricsProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, quint64 id);
|
||||
void CancelSearch(const quint64 id);
|
||||
|
||||
private:
|
||||
void Error(const QString &error, const QVariant &debug = QVariant());
|
||||
QJsonArray ExtractResult(QNetworkReply *reply, const QString &artist, const QString &title);
|
||||
|
||||
private slots:
|
||||
void HandleSearchReply(QNetworkReply *reply, const quint64 id, const QString &artist, const QString &title);
|
||||
|
||||
@ -51,9 +57,7 @@ class AuddLyricsProvider : public JsonLyricsProvider {
|
||||
static const char *kAPITokenB64;
|
||||
static const int kMaxLength;
|
||||
QNetworkAccessManager *network_;
|
||||
void Error(const QString &error, const QVariant &debug = QVariant());
|
||||
|
||||
QJsonArray ExtractResult(QNetworkReply *reply, const QString &artist, const QString &title);
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/network.h"
|
||||
#include "core/utilities.h"
|
||||
@ -44,6 +43,17 @@ const char *ChartLyricsProvider::kUrlSearch = "http://api.chartlyrics.com/apiv1.
|
||||
|
||||
ChartLyricsProvider::ChartLyricsProvider(QObject *parent) : LyricsProvider("ChartLyrics", false, false, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
ChartLyricsProvider::~ChartLyricsProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ChartLyricsProvider::StartSearch(const QString &artist, const QString&, const QString &title, const quint64 id) {
|
||||
|
||||
const ParamList params = ParamList() << Param("artist", artist)
|
||||
@ -57,7 +67,8 @@ bool ChartLyricsProvider::StartSearch(const QString &artist, const QString&, con
|
||||
QUrl url(kUrlSearch);
|
||||
url.setQuery(url_query);
|
||||
QNetworkReply *reply = network_->get(QNetworkRequest(url));
|
||||
NewClosure(reply, SIGNAL(finished()), this, SLOT(HandleSearchReply(QNetworkReply*, const quint64, const QString&, const QString&)), reply, id, artist, title);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id, artist, title); });
|
||||
|
||||
//qLog(Debug) << "ChartLyrics: Sending request for" << url;
|
||||
|
||||
@ -69,6 +80,9 @@ void ChartLyricsProvider::CancelSearch(const quint64) {}
|
||||
|
||||
void ChartLyricsProvider::HandleSearchReply(QNetworkReply *reply, const quint64 id, const QString &artist, const QString &title) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
|
@ -23,19 +23,22 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include "lyricsprovider.h"
|
||||
#include "lyricsfetcher.h"
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
|
||||
class ChartLyricsProvider : public LyricsProvider {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ChartLyricsProvider(QObject *parent = nullptr);
|
||||
~ChartLyricsProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const quint64 id);
|
||||
void CancelSearch(quint64 id);
|
||||
@ -50,6 +53,7 @@ class ChartLyricsProvider : public LyricsProvider {
|
||||
static const char *kUrlSearch;
|
||||
|
||||
QNetworkAccessManager *network_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -73,6 +73,17 @@ GeniusLyricsProvider::GeniusLyricsProvider(QObject *parent) : JsonLyricsProvider
|
||||
|
||||
}
|
||||
|
||||
GeniusLyricsProvider::~GeniusLyricsProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GeniusLyricsProvider::Authenticate() {
|
||||
|
||||
QUrl redirect_url(kOAuthRedirectUrl);
|
||||
@ -182,6 +193,7 @@ void GeniusLyricsProvider::RequestAccessToken(const QUrl &url, const QUrl &redir
|
||||
QByteArray query = new_url_query.toString(QUrl::FullyEncoded).toUtf8();
|
||||
|
||||
QNetworkReply *reply = network_->post(req, query);
|
||||
replies_ << reply;
|
||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(HandleLoginSSLErrors(QList<QSslError>)));
|
||||
connect(reply, &QNetworkReply::finished, [=] { AccessTokenRequestFinished(reply); });
|
||||
|
||||
@ -204,6 +216,9 @@ void GeniusLyricsProvider::HandleLoginSSLErrors(QList<QSslError> ssl_errors) {
|
||||
|
||||
void GeniusLyricsProvider::AccessTokenRequestFinished(QNetworkReply *reply) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError || reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
|
||||
@ -309,6 +324,7 @@ bool GeniusLyricsProvider::StartSearch(const QString &artist, const QString &alb
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
req.setRawHeader("Authorization", "Bearer " + access_token_.toUtf8());
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id); });
|
||||
|
||||
//qLog(Debug) << "GeniusLyrics: Sending request for" << url;
|
||||
@ -321,6 +337,9 @@ void GeniusLyricsProvider::CancelSearch(const quint64 id) { Q_UNUSED(id); }
|
||||
|
||||
void GeniusLyricsProvider::HandleSearchReply(QNetworkReply *reply, const quint64 id) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
if (!requests_search_.contains(id)) return;
|
||||
@ -422,6 +441,7 @@ void GeniusLyricsProvider::HandleSearchReply(QNetworkReply *reply, const quint64
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply *new_reply = network_->get(req);
|
||||
replies_ << new_reply;
|
||||
connect(new_reply, &QNetworkReply::finished, [=] { HandleLyricReply(new_reply, search->id, url); });
|
||||
|
||||
}
|
||||
@ -432,6 +452,9 @@ void GeniusLyricsProvider::HandleSearchReply(QNetworkReply *reply, const quint64
|
||||
|
||||
void GeniusLyricsProvider::HandleLyricReply(QNetworkReply *reply, const int search_id, const QUrl &url) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
if (!requests_search_.contains(search_id)) return;
|
||||
|
@ -48,6 +48,7 @@ class GeniusLyricsProvider : public JsonLyricsProvider {
|
||||
|
||||
public:
|
||||
explicit GeniusLyricsProvider(QObject *parent = nullptr);
|
||||
~GeniusLyricsProvider();
|
||||
|
||||
bool IsAuthenticated() { return !access_token_.isEmpty(); }
|
||||
void Authenticate();
|
||||
@ -102,6 +103,7 @@ class GeniusLyricsProvider : public JsonLyricsProvider {
|
||||
QString access_token_;
|
||||
QStringList login_errors_;
|
||||
QMap<int, std::shared_ptr<GeniusLyricsSearchContext>> requests_search_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
@ -43,6 +43,17 @@ const char *LoloLyricsProvider::kUrlSearch = "http://api.lololyrics.com/0.5/getL
|
||||
|
||||
LoloLyricsProvider::LoloLyricsProvider(QObject *parent) : LyricsProvider("LoloLyrics", true, false, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
LoloLyricsProvider::~LoloLyricsProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool LoloLyricsProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const quint64 id) {
|
||||
|
||||
Q_UNUSED(album);
|
||||
@ -60,6 +71,7 @@ bool LoloLyricsProvider::StartSearch(const QString &artist, const QString &album
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id, artist, title); });
|
||||
|
||||
//qLog(Debug) << "LoloLyrics: Sending request for" << url;
|
||||
@ -72,6 +84,9 @@ void LoloLyricsProvider::CancelSearch(const quint64 id) { Q_UNUSED(id); }
|
||||
|
||||
void LoloLyricsProvider::HandleSearchReply(QNetworkReply *reply, const quint64 id, const QString &artist, const QString &title) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QString failure_reason;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
|
||||
@ -37,17 +38,21 @@ class LoloLyricsProvider : public LyricsProvider {
|
||||
|
||||
public:
|
||||
explicit LoloLyricsProvider(QObject *parent = nullptr);
|
||||
~LoloLyricsProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const quint64 id);
|
||||
void CancelSearch(const quint64 id);
|
||||
|
||||
private:
|
||||
void Error(const QString &error, const QVariant &debug = QVariant());
|
||||
|
||||
private slots:
|
||||
void HandleSearchReply(QNetworkReply *reply, const quint64 id, const QString &artist, const QString &title);
|
||||
|
||||
private:
|
||||
static const char *kUrlSearch;
|
||||
QNetworkAccessManager *network_;
|
||||
void Error(const QString &error, const QVariant &debug = QVariant());
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -41,6 +41,17 @@
|
||||
|
||||
MusixmatchLyricsProvider::MusixmatchLyricsProvider(QObject *parent) : JsonLyricsProvider("Musixmatch", true, false, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
MusixmatchLyricsProvider::~MusixmatchLyricsProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool MusixmatchLyricsProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const quint64 id) {
|
||||
|
||||
QString artist_stripped = artist;
|
||||
@ -66,6 +77,7 @@ bool MusixmatchLyricsProvider::StartSearch(const QString &artist, const QString
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id, artist, album, title); });
|
||||
|
||||
qLog(Debug) << "MusixmatchLyrics: Sending request for" << artist_stripped << title_stripped << url;
|
||||
@ -80,6 +92,9 @@ void MusixmatchLyricsProvider::HandleSearchReply(QNetworkReply *reply, const qui
|
||||
|
||||
Q_UNUSED(album);
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
LyricsSearchResults results;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
|
||||
@ -38,6 +39,7 @@ class MusixmatchLyricsProvider : public JsonLyricsProvider {
|
||||
|
||||
public:
|
||||
explicit MusixmatchLyricsProvider(QObject *parent = nullptr);
|
||||
~MusixmatchLyricsProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const quint64 id);
|
||||
void CancelSearch(const quint64 id);
|
||||
@ -50,6 +52,7 @@ class MusixmatchLyricsProvider : public JsonLyricsProvider {
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *network_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -40,6 +40,17 @@ const char *OVHLyricsProvider::kUrlSearch = "https://api.lyrics.ovh/v1/";
|
||||
|
||||
OVHLyricsProvider::OVHLyricsProvider(QObject *parent) : JsonLyricsProvider("Lyrics.ovh", true, false, parent), network_(new NetworkAccessManager(this)) {}
|
||||
|
||||
OVHLyricsProvider::~OVHLyricsProvider() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool OVHLyricsProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const quint64 id) {
|
||||
|
||||
Q_UNUSED(album);
|
||||
@ -48,6 +59,7 @@ bool OVHLyricsProvider::StartSearch(const QString &artist, const QString &album,
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleSearchReply(reply, id, artist, title); });
|
||||
|
||||
//qLog(Debug) << "OVHLyrics: Sending request for" << url;
|
||||
@ -60,6 +72,9 @@ void OVHLyricsProvider::CancelSearch(const quint64 id) { Q_UNUSED(id); }
|
||||
|
||||
void OVHLyricsProvider::HandleSearchReply(QNetworkReply *reply, const quint64 id, const QString &artist, const QString &title) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QJsonObject json_obj = ExtractJsonObj(reply);
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
|
||||
@ -37,17 +38,21 @@ class OVHLyricsProvider : public JsonLyricsProvider {
|
||||
|
||||
public:
|
||||
explicit OVHLyricsProvider(QObject *parent = nullptr);
|
||||
~OVHLyricsProvider();
|
||||
|
||||
bool StartSearch(const QString &artist, const QString &album, const QString &title, const quint64 id);
|
||||
void CancelSearch(const quint64 id);
|
||||
|
||||
private:
|
||||
void Error(const QString &error, const QVariant &debug = QVariant());
|
||||
|
||||
private slots:
|
||||
void HandleSearchReply(QNetworkReply *reply, const quint64 id, const QString &artist, const QString &title);
|
||||
|
||||
private:
|
||||
static const char *kUrlSearch;
|
||||
QNetworkAccessManager *network_;
|
||||
void Error(const QString &error, const QVariant &debug = QVariant());
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -57,6 +57,12 @@ AcoustidClient::AcoustidClient(QObject *parent)
|
||||
network_(new NetworkAccessManager(this)),
|
||||
timeouts_(new NetworkTimeouts(kDefaultTimeout, this)) {}
|
||||
|
||||
AcoustidClient::~AcoustidClient() {
|
||||
|
||||
CancelAll();
|
||||
|
||||
}
|
||||
|
||||
void AcoustidClient::SetTimeout(const int msec) { timeouts_->SetTimeout(msec); }
|
||||
|
||||
void AcoustidClient::Start(const int id, const QString &fingerprint, int duration_msec) {
|
||||
@ -82,10 +88,13 @@ void AcoustidClient::Start(const int id, const QString &fingerprint, int duratio
|
||||
requests_[id] = reply;
|
||||
|
||||
timeouts_->AddReply(reply);
|
||||
|
||||
}
|
||||
|
||||
void AcoustidClient::Cancel(const int id) {
|
||||
|
||||
if (requests_.contains(id)) delete requests_.take(id);
|
||||
|
||||
}
|
||||
|
||||
void AcoustidClient::CancelAll() {
|
||||
@ -113,6 +122,7 @@ struct IdSource {
|
||||
|
||||
void AcoustidClient::RequestFinished(QNetworkReply *reply, const int request_id) {
|
||||
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
requests_.remove(request_id);
|
||||
|
||||
|
@ -43,6 +43,7 @@ class AcoustidClient : public QObject {
|
||||
|
||||
public:
|
||||
explicit AcoustidClient(QObject *parent = nullptr);
|
||||
~AcoustidClient();
|
||||
|
||||
// Network requests will be aborted after this interval.
|
||||
void SetTimeout(const int msec);
|
||||
@ -70,6 +71,7 @@ class AcoustidClient : public QObject {
|
||||
QNetworkAccessManager *network_;
|
||||
NetworkTimeouts *timeouts_;
|
||||
QMap<int, QNetworkReply*> requests_;
|
||||
|
||||
};
|
||||
|
||||
#endif // ACOUSTIDCLIENT_H
|
||||
|
@ -69,6 +69,12 @@ MusicBrainzClient::MusicBrainzClient(QObject *parent, QNetworkAccessManager *net
|
||||
|
||||
}
|
||||
|
||||
MusicBrainzClient::~MusicBrainzClient() {
|
||||
|
||||
CancelAll();
|
||||
|
||||
}
|
||||
|
||||
QByteArray MusicBrainzClient::GetReplyData(QNetworkReply *reply, QString &error) {
|
||||
|
||||
QByteArray data;
|
||||
@ -114,7 +120,7 @@ void MusicBrainzClient::Cancel(int id) {
|
||||
|
||||
while (!requests_.isEmpty() && requests_.contains(id)) {
|
||||
QNetworkReply *reply = requests_.take(id);
|
||||
disconnect(reply, 0, this, 0);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
if (reply->isRunning()) reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
@ -187,6 +193,7 @@ void MusicBrainzClient::FlushRequests() {
|
||||
|
||||
void MusicBrainzClient::RequestFinished(QNetworkReply *reply, const int id, const int request_number) {
|
||||
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
const int nb_removed = requests_.remove(id, reply);
|
||||
@ -232,6 +239,7 @@ void MusicBrainzClient::RequestFinished(QNetworkReply *reply, const int id, cons
|
||||
|
||||
void MusicBrainzClient::DiscIdRequestFinished(const QString &discid, QNetworkReply *reply) {
|
||||
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
ResultList ret;
|
||||
|
@ -51,6 +51,7 @@ class MusicBrainzClient : public QObject {
|
||||
// The second argument allows for specifying a custom network access manager.
|
||||
// It is used in tests. The ownership of network is not transferred.
|
||||
explicit MusicBrainzClient(QObject *parent = nullptr, QNetworkAccessManager *network = nullptr);
|
||||
~MusicBrainzClient();
|
||||
|
||||
struct Result {
|
||||
Result() : duration_msec_(0), track_(0), year_(-1) {}
|
||||
|
@ -83,7 +83,22 @@ ListenBrainzScrobbler::ListenBrainzScrobbler(Application *app, QObject *parent)
|
||||
|
||||
}
|
||||
|
||||
ListenBrainzScrobbler::~ListenBrainzScrobbler() {}
|
||||
ListenBrainzScrobbler::~ListenBrainzScrobbler() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
if (server_) {
|
||||
disconnect(server_, nullptr, this, nullptr);
|
||||
if (server_->isListening()) server_->close();
|
||||
server_->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ListenBrainzScrobbler::ReloadSettings() {
|
||||
|
||||
@ -231,12 +246,16 @@ void ListenBrainzScrobbler::RequestAccessToken(const QUrl &redirect_url, const Q
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
QByteArray query = url_query.toString(QUrl::FullyEncoded).toUtf8();
|
||||
QNetworkReply *reply = network_->post(req, query);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { AuthenticateReplyFinished(reply); });
|
||||
|
||||
}
|
||||
|
||||
void ListenBrainzScrobbler::AuthenticateReplyFinished(QNetworkReply *reply) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data;
|
||||
@ -330,6 +349,7 @@ QNetworkReply *ListenBrainzScrobbler::CreateRequest(const QUrl &url, const QJson
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
req.setRawHeader("Authorization", QString("Token %1").arg(user_token_).toUtf8());
|
||||
QNetworkReply *reply = network_->post(req, json_doc.toJson());
|
||||
replies_ << reply;
|
||||
|
||||
//qLog(Debug) << "ListenBrainz: Sending request" << json_doc.toJson();
|
||||
|
||||
@ -433,6 +453,9 @@ void ListenBrainzScrobbler::UpdateNowPlaying(const Song &song) {
|
||||
|
||||
void ListenBrainzScrobbler::UpdateNowPlayingRequestFinished(QNetworkReply *reply) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = GetReplyData(reply);
|
||||
@ -555,6 +578,9 @@ void ListenBrainzScrobbler::Submit() {
|
||||
|
||||
void ListenBrainzScrobbler::ScrobbleRequestFinished(QNetworkReply *reply, QList<quint64> list) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = GetReplyData(reply);
|
||||
|
@ -117,6 +117,8 @@ class ListenBrainzScrobbler : public ScrobblerService {
|
||||
quint64 timestamp_;
|
||||
QTimer refresh_login_timer_;
|
||||
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
#endif // LISTENBRAINZSCROBBLER_H
|
||||
|
@ -80,7 +80,22 @@ ScrobblingAPI20::ScrobblingAPI20(const QString &name, const QString &settings_gr
|
||||
scrobbled_(false),
|
||||
timestamp_(0) {}
|
||||
|
||||
ScrobblingAPI20::~ScrobblingAPI20() {}
|
||||
ScrobblingAPI20::~ScrobblingAPI20() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
if (server_) {
|
||||
disconnect(server_, nullptr, this, nullptr);
|
||||
if (server_->isListening()) server_->close();
|
||||
server_->deleteLater();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ScrobblingAPI20::ReloadSettings() {
|
||||
|
||||
@ -232,12 +247,16 @@ void ScrobblingAPI20::RequestSession(const QString &token) {
|
||||
QNetworkRequest req(session_url);
|
||||
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
QNetworkReply *reply = network()->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, &QNetworkReply::finished, [=] { AuthenticateReplyFinished(reply); });
|
||||
|
||||
}
|
||||
|
||||
void ScrobblingAPI20::AuthenticateReplyFinished(QNetworkReply *reply) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data;
|
||||
@ -362,6 +381,7 @@ QNetworkReply *ScrobblingAPI20::CreateRequest(const ParamList &request_params) {
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
QByteArray query = url_query.toString(QUrl::FullyEncoded).toUtf8();
|
||||
QNetworkReply *reply = network()->post(req, query);
|
||||
replies_ << reply;
|
||||
|
||||
//qLog(Debug) << name_ << "Sending request" << query;
|
||||
|
||||
@ -454,6 +474,9 @@ void ScrobblingAPI20::UpdateNowPlaying(const Song &song) {
|
||||
|
||||
void ScrobblingAPI20::UpdateNowPlayingRequestFinished(QNetworkReply *reply) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = GetReplyData(reply);
|
||||
@ -573,6 +596,9 @@ void ScrobblingAPI20::Submit() {
|
||||
|
||||
void ScrobblingAPI20::ScrobbleRequestFinished(QNetworkReply *reply, QList<quint64> list) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = GetReplyData(reply);
|
||||
@ -750,6 +776,9 @@ void ScrobblingAPI20::SendSingleScrobble(ScrobblerCacheItemPtr item) {
|
||||
|
||||
void ScrobblingAPI20::SingleScrobbleRequestFinished(QNetworkReply *reply, quint64 timestamp) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
ScrobblerCacheItemPtr item = cache()->Get(timestamp);
|
||||
@ -898,6 +927,9 @@ void ScrobblingAPI20::Love() {
|
||||
|
||||
void ScrobblingAPI20::LoveRequestFinished(QNetworkReply *reply) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = GetReplyData(reply);
|
||||
|
@ -157,6 +157,8 @@ class ScrobblingAPI20 : public ScrobblerService {
|
||||
bool scrobbled_;
|
||||
quint64 timestamp_;
|
||||
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
#endif // SCROBBLINGAPI20_H
|
||||
|
@ -164,6 +164,7 @@ void SubsonicRequest::AlbumsReplyReceived(QNetworkReply *reply, const int offset
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
--albums_requests_active_;
|
||||
|
@ -98,7 +98,16 @@ SubsonicService::SubsonicService(Application *app, QObject *parent)
|
||||
}
|
||||
|
||||
SubsonicService::~SubsonicService() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
if (reply->isRunning()) reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
collection_backend_->deleteLater();
|
||||
|
||||
}
|
||||
|
||||
void SubsonicService::Exit() {
|
||||
@ -177,6 +186,7 @@ void SubsonicService::SendPing(QUrl url, const QString &username, const QString
|
||||
|
||||
errors_.clear();
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(HandlePingSSLErrors(QList<QSslError>)));
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandlePingReply(reply, url, username, password); });
|
||||
|
||||
@ -196,6 +206,9 @@ void SubsonicService::HandlePingReply(QNetworkReply *reply, const QUrl &url, con
|
||||
|
||||
Q_UNUSED(url);
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError || reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
|
||||
@ -359,8 +372,8 @@ void SubsonicService::CheckConfiguration() {
|
||||
void SubsonicService::ResetSongsRequest() {
|
||||
|
||||
if (songs_request_.get()) {
|
||||
disconnect(songs_request_.get(), 0, this, 0);
|
||||
disconnect(this, 0, songs_request_.get(), 0);
|
||||
disconnect(songs_request_.get(), nullptr, this, nullptr);
|
||||
disconnect(this, nullptr, songs_request_.get(), nullptr);
|
||||
songs_request_.reset();
|
||||
}
|
||||
|
||||
|
@ -126,6 +126,8 @@ class SubsonicService : public InternetService {
|
||||
QStringList errors_;
|
||||
int ping_redirects_;
|
||||
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
#endif // SUBSONICSERVICE_H
|
||||
|
@ -51,7 +51,7 @@ TidalFavoriteRequest::~TidalFavoriteRequest() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, 0, this, 0);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
@ -152,6 +152,7 @@ void TidalFavoriteRequest::AddFavoritesReply(QNetworkReply *reply, const Favorit
|
||||
|
||||
if (replies_.contains(reply)) {
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
}
|
||||
else {
|
||||
@ -254,6 +255,7 @@ void TidalFavoriteRequest::RemoveFavoritesReply(QNetworkReply *reply, const Favo
|
||||
|
||||
if (replies_.contains(reply)) {
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
}
|
||||
else {
|
||||
|
@ -84,14 +84,14 @@ TidalRequest::~TidalRequest() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, 0, this, 0);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
if (reply->isRunning()) reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
while (!album_cover_replies_.isEmpty()) {
|
||||
QNetworkReply *reply = album_cover_replies_.takeFirst();
|
||||
disconnect(reply, 0, this, 0);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
if (reply->isRunning()) reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
@ -330,6 +330,7 @@ void TidalRequest::ArtistsReplyReceived(QNetworkReply *reply, const int limit_re
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = GetReplyData(reply, (offset_requested == 0));
|
||||
@ -521,6 +522,7 @@ void TidalRequest::AlbumsReceived(QNetworkReply *reply, const QString &artist_id
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = GetReplyData(reply, auto_login);
|
||||
@ -787,6 +789,7 @@ void TidalRequest::SongsReceived(QNetworkReply *reply, const QString &artist_id,
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = GetReplyData(reply, auto_login);
|
||||
@ -1127,6 +1130,7 @@ void TidalRequest::AlbumCoverReceived(QNetworkReply *reply, const QString &album
|
||||
|
||||
if (album_cover_replies_.contains(reply)) {
|
||||
album_cover_replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
}
|
||||
else {
|
||||
|
@ -179,9 +179,16 @@ TidalService::TidalService(Application *app, QObject *parent)
|
||||
|
||||
TidalService::~TidalService() {
|
||||
|
||||
while (!replies_.isEmpty()) {
|
||||
QNetworkReply *reply = replies_.takeFirst();
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->abort();
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
while (!stream_url_requests_.isEmpty()) {
|
||||
TidalStreamURLRequest *stream_url_req = stream_url_requests_.takeFirst();
|
||||
disconnect(stream_url_req, 0, this, 0);
|
||||
disconnect(stream_url_req, nullptr, this, nullptr);
|
||||
stream_url_req->deleteLater();
|
||||
}
|
||||
|
||||
@ -208,7 +215,7 @@ void TidalService::Exit() {
|
||||
void TidalService::ExitReceived() {
|
||||
|
||||
QObject *obj = static_cast<QObject*>(sender());
|
||||
disconnect(obj, 0, this, 0);
|
||||
disconnect(obj, nullptr, this, nullptr);
|
||||
qLog(Debug) << obj << "successfully exited.";
|
||||
wait_for_exit_.removeAll(obj);
|
||||
if (wait_for_exit_.isEmpty()) emit ExitFinished();
|
||||
@ -338,6 +345,7 @@ void TidalService::AuthorisationUrlReceived(const QUrl &url) {
|
||||
|
||||
login_errors_.clear();
|
||||
QNetworkReply *reply = network_->post(request, query);
|
||||
replies_ << reply;
|
||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(HandleLoginSSLErrors(QList<QSslError>)));
|
||||
connect(reply, &QNetworkReply::finished, [=] { AccessTokenRequestFinished(reply); });
|
||||
|
||||
@ -360,6 +368,9 @@ void TidalService::HandleLoginSSLErrors(QList<QSslError> ssl_errors) {
|
||||
|
||||
void TidalService::AccessTokenRequestFinished(QNetworkReply *reply) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
login_sent_ = false;
|
||||
@ -503,6 +514,7 @@ void TidalService::SendLogin(const QString &api_token, const QString &username,
|
||||
QNetworkReply *reply = network_->post(req, query);
|
||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(HandleLoginSSLErrors(QList<QSslError>)));
|
||||
connect(reply, &QNetworkReply::finished, [=] { HandleAuthReply(reply); });
|
||||
replies_ << reply;
|
||||
|
||||
//qLog(Debug) << "Tidal: Sending request" << url << query;
|
||||
|
||||
@ -510,6 +522,9 @@ void TidalService::SendLogin(const QString &api_token, const QString &username,
|
||||
|
||||
void TidalService::HandleAuthReply(QNetworkReply *reply) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
login_sent_ = false;
|
||||
@ -657,8 +672,8 @@ void TidalService::TryLogin() {
|
||||
void TidalService::ResetArtistsRequest() {
|
||||
|
||||
if (artists_request_.get()) {
|
||||
disconnect(artists_request_.get(), 0, this, 0);
|
||||
disconnect(this, 0, artists_request_.get(), 0);
|
||||
disconnect(artists_request_.get(), nullptr, this, nullptr);
|
||||
disconnect(this, nullptr, artists_request_.get(), nullptr);
|
||||
artists_request_.reset();
|
||||
}
|
||||
|
||||
@ -716,8 +731,8 @@ void TidalService::ArtistsUpdateProgressReceived(const int id, const int progres
|
||||
void TidalService::ResetAlbumsRequest() {
|
||||
|
||||
if (albums_request_.get()) {
|
||||
disconnect(albums_request_.get(), 0, this, 0);
|
||||
disconnect(this, 0, albums_request_.get(), 0);
|
||||
disconnect(albums_request_.get(), nullptr, this, nullptr);
|
||||
disconnect(this, nullptr, albums_request_.get(), nullptr);
|
||||
albums_request_.reset();
|
||||
}
|
||||
|
||||
@ -773,8 +788,8 @@ void TidalService::AlbumsUpdateProgressReceived(const int id, const int progress
|
||||
void TidalService::ResetSongsRequest() {
|
||||
|
||||
if (songs_request_.get()) {
|
||||
disconnect(songs_request_.get(), 0, this, 0);
|
||||
disconnect(this, 0, songs_request_.get(), 0);
|
||||
disconnect(songs_request_.get(), nullptr, this, nullptr);
|
||||
disconnect(this, nullptr, songs_request_.get(), nullptr);
|
||||
songs_request_.reset();
|
||||
}
|
||||
|
||||
|
@ -247,6 +247,7 @@ class TidalService : public InternetService {
|
||||
QStringList login_errors_;
|
||||
|
||||
QList<QObject*> wait_for_exit_;
|
||||
QList<QNetworkReply*> replies_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -57,7 +57,7 @@ TidalStreamURLRequest::TidalStreamURLRequest(TidalService *service, NetworkAcces
|
||||
TidalStreamURLRequest::~TidalStreamURLRequest() {
|
||||
|
||||
if (reply_) {
|
||||
disconnect(reply_, 0, this, 0);
|
||||
disconnect(reply_, nullptr, this, nullptr);
|
||||
if (reply_->isRunning()) reply_->abort();
|
||||
reply_->deleteLater();
|
||||
}
|
||||
@ -114,7 +114,7 @@ void TidalStreamURLRequest::GetStreamURL() {
|
||||
++tries_;
|
||||
|
||||
if (reply_) {
|
||||
disconnect(reply_, 0, this, 0);
|
||||
disconnect(reply_, nullptr, this, nullptr);
|
||||
if (reply_->isRunning()) reply_->abort();
|
||||
reply_->deleteLater();
|
||||
}
|
||||
@ -149,7 +149,7 @@ void TidalStreamURLRequest::GetStreamURL() {
|
||||
void TidalStreamURLRequest::StreamURLReceived() {
|
||||
|
||||
if (!reply_) return;
|
||||
disconnect(reply_, 0, this, 0);
|
||||
disconnect(reply_, nullptr, this, nullptr);
|
||||
reply_->deleteLater();
|
||||
|
||||
QByteArray data = GetReplyData(reply_, true);
|
||||
|
Loading…
x
Reference in New Issue
Block a user