Stands4LyricsProvider: Use API for search
This commit is contained in:
parent
93d1d40ea5
commit
9b06e85f94
@ -22,20 +22,26 @@
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QRegularExpression>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "core/networkaccessmanager.h"
|
||||
#include "utilities/strutils.h"
|
||||
#include "lyricsfetcher.h"
|
||||
#include "lyricsprovider.h"
|
||||
#include "stands4lyricsprovider.h"
|
||||
|
||||
const char *Stands4LyricsProvider::kUrl = "https://www.lyrics.com/lyrics/";
|
||||
const char *Stands4LyricsProvider::kApiUrl = "https://www.abbreviations.com/services/v2/lyrics.php";
|
||||
const char *Stands4LyricsProvider::kLyricsUrl = "https://www.lyrics.com/lyrics/";
|
||||
const char *Stands4LyricsProvider::kUID = "11363";
|
||||
const char *Stands4LyricsProvider::kTokenB64 = "b3FOYmxhV1ZKRGxIMnV4OA==";
|
||||
|
||||
Stands4LyricsProvider::Stands4LyricsProvider(NetworkAccessManager *network, QObject *parent) : LyricsProvider("Stands4Lyrics", true, false, network, parent) {}
|
||||
Stands4LyricsProvider::Stands4LyricsProvider(NetworkAccessManager *network, QObject *parent) : JsonLyricsProvider("Stands4Lyrics", true, false, network, parent) {}
|
||||
|
||||
Stands4LyricsProvider::~Stands4LyricsProvider() {
|
||||
|
||||
@ -50,16 +56,20 @@ Stands4LyricsProvider::~Stands4LyricsProvider() {
|
||||
|
||||
bool Stands4LyricsProvider::StartSearch(const QString &artist, const QString &album, const QString &title, const int id) {
|
||||
|
||||
Q_UNUSED(album);
|
||||
|
||||
QUrl url(kUrl + StringFixup(artist) + "/" + StringFixup(title) + ".html");
|
||||
QUrlQuery url_query;
|
||||
url_query.addQueryItem(QUrl::toPercentEncoding("uid"), QUrl::toPercentEncoding(kUID));
|
||||
url_query.addQueryItem(QUrl::toPercentEncoding("tokenid"), QUrl::toPercentEncoding(QByteArray::fromBase64(kTokenB64)));
|
||||
url_query.addQueryItem(QUrl::toPercentEncoding("format"), "json");
|
||||
url_query.addQueryItem(QUrl::toPercentEncoding("artist"), artist);
|
||||
url_query.addQueryItem(QUrl::toPercentEncoding("album"), album);
|
||||
url_query.addQueryItem(QUrl::toPercentEncoding("term"), title);
|
||||
QUrl url(kApiUrl);
|
||||
url.setQuery(url_query);
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, id, artist, title]() { HandleSearchReply(reply, id, artist, title); });
|
||||
|
||||
qLog(Debug) << "Stands4Lyrics: Sending request for" << url;
|
||||
QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, id, artist, album, title]() { HandleSearchReply(reply, id, artist, album, title); });
|
||||
|
||||
return true;
|
||||
|
||||
@ -67,7 +77,88 @@ bool Stands4LyricsProvider::StartSearch(const QString &artist, const QString &al
|
||||
|
||||
void Stands4LyricsProvider::CancelSearch(const int id) { Q_UNUSED(id); }
|
||||
|
||||
void Stands4LyricsProvider::HandleSearchReply(QNetworkReply *reply, const int id, const QString &artist, const QString &title) {
|
||||
void Stands4LyricsProvider::HandleSearchReply(QNetworkReply *reply, const int id, const QString &artist, const QString &album, const QString &title) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
QObject::disconnect(reply, nullptr, this, nullptr);
|
||||
reply->deleteLater();
|
||||
|
||||
QByteArray data = ExtractData(reply);
|
||||
if (data.isEmpty()) {
|
||||
emit SearchFinished(id);
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject json_obj = ExtractJsonObj(data);
|
||||
if (json_obj.isEmpty()) {
|
||||
qLog(Debug) << "Stands4Lyrics: No lyrics for" << artist << album << title;
|
||||
emit SearchFinished(id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json_obj.contains("result") || !json_obj["result"].isArray()) {
|
||||
Error("Json reply is missing result.", json_obj);
|
||||
emit SearchFinished(id);
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonArray json_result = json_obj["result"].toArray();
|
||||
if (json_result.isEmpty()) {
|
||||
qLog(Debug) << "Stands4Lyrics: No lyrics for" << artist << album << title;
|
||||
emit SearchFinished(id);
|
||||
return;
|
||||
}
|
||||
|
||||
LyricsSearchResults results;
|
||||
for (const QJsonValueRef value : json_result) {
|
||||
if (!value.isObject()) {
|
||||
qLog(Error) << "Stands4Lyrics: Invalid Json reply, result is not an object.";
|
||||
qLog(Debug) << value;
|
||||
continue;
|
||||
}
|
||||
QJsonObject obj = value.toObject();
|
||||
if (
|
||||
!obj.contains("song") ||
|
||||
!obj.contains("artist") ||
|
||||
!obj.contains("album")
|
||||
) {
|
||||
qLog(Error) << "Stands4Lyrics: Invalid Json reply, result is missing data.";
|
||||
qLog(Debug) << value;
|
||||
continue;
|
||||
}
|
||||
QString result_artist = obj["artist"].toString();
|
||||
QString result_album = obj["album"].toString();
|
||||
QString result_title = obj["song"].toString();
|
||||
if (result_artist.compare(artist, Qt::CaseInsensitive) != 0 &&
|
||||
result_album.compare(album, Qt::CaseInsensitive) != 0 &&
|
||||
result_title.compare(title, Qt::CaseInsensitive) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SendLyricsRequest(id, result_artist, result_album, result_title);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
qLog(Debug) << "Stands4Lyrics: No lyrics for" << artist << album << title;
|
||||
emit SearchFinished(id);
|
||||
|
||||
}
|
||||
|
||||
void Stands4LyricsProvider::SendLyricsRequest(const int id, const QString &artist, const QString &album, const QString &title) {
|
||||
|
||||
QUrl url(kLyricsUrl + StringFixup(artist) + "/" + StringFixup(title) + ".html");
|
||||
QNetworkRequest req(url);
|
||||
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
replies_ << reply;
|
||||
QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, id, artist, album, title]() { HandleLyricsReply(reply, id, artist, album, title); });
|
||||
|
||||
}
|
||||
|
||||
void Stands4LyricsProvider::HandleLyricsReply(QNetworkReply *reply, const int id, const QString &artist, const QString &album, const QString &title) {
|
||||
|
||||
if (!replies_.contains(reply)) return;
|
||||
replies_.removeAll(reply);
|
||||
@ -76,32 +167,35 @@ void Stands4LyricsProvider::HandleSearchReply(QNetworkReply *reply, const int id
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
Error(QString("%1 (%2)").arg(reply->errorString()).arg(reply->error()));
|
||||
emit SearchFinished(id, LyricsSearchResults());
|
||||
emit SearchFinished(id);
|
||||
return;
|
||||
}
|
||||
else if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
|
||||
Error(QString("Received HTTP code %1").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()));
|
||||
emit SearchFinished(id, LyricsSearchResults());
|
||||
emit SearchFinished(id);
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray data = reply->readAll();
|
||||
if (data.isEmpty()) {
|
||||
Error("Empty reply received from server.");
|
||||
emit SearchFinished(id, LyricsSearchResults());
|
||||
emit SearchFinished(id);
|
||||
return;
|
||||
}
|
||||
|
||||
const QString lyrics = ParseLyricsFromHTML(QString::fromUtf8(data), QRegularExpression("<div[^>]*>"), QRegularExpression("<\\/div>"), QRegularExpression("<div id=\"lyrics\"[^>]+>"), false);
|
||||
if (lyrics.isEmpty() || lyrics.contains("Click to search for the Lyrics on Lyrics.com", Qt::CaseInsensitive)) {
|
||||
qLog(Debug) << "Stands4Lyrics: No lyrics for" << artist << title;
|
||||
emit SearchFinished(id, LyricsSearchResults());
|
||||
qLog(Debug) << "Stands4Lyrics: No lyrics for" << artist << album << title;
|
||||
emit SearchFinished(id);
|
||||
return;
|
||||
}
|
||||
|
||||
qLog(Debug) << "Stands4Lyrics: Got lyrics for" << artist << title;
|
||||
qLog(Debug) << "Stands4Lyrics: Got lyrics for" << artist << album << title;
|
||||
|
||||
LyricsSearchResult result;
|
||||
result.artist = artist;
|
||||
result.album = album;
|
||||
result.title = title;
|
||||
result.lyrics = lyrics;
|
||||
emit SearchFinished(id, LyricsSearchResults() << result);
|
||||
|
||||
|
@ -26,13 +26,13 @@
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
|
||||
#include "lyricsprovider.h"
|
||||
#include "jsonlyricsprovider.h"
|
||||
#include "lyricsfetcher.h"
|
||||
|
||||
class QNetworkReply;
|
||||
class NetworkAccessManager;
|
||||
|
||||
class Stands4LyricsProvider : public LyricsProvider {
|
||||
class Stands4LyricsProvider : public JsonLyricsProvider {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@ -43,14 +43,19 @@ class Stands4LyricsProvider : public LyricsProvider {
|
||||
void CancelSearch(const int id) override;
|
||||
|
||||
private:
|
||||
void SendLyricsRequest(const int id, const QString &artist, const QString &album, const QString &title);
|
||||
void Error(const QString &error, const QVariant &debug = QVariant()) override;
|
||||
static QString StringFixup(QString string);
|
||||
|
||||
private slots:
|
||||
void HandleSearchReply(QNetworkReply *reply, const int id, const QString &artist, const QString &title);
|
||||
void HandleSearchReply(QNetworkReply *reply, const int id, const QString &artist, const QString &album, const QString &title);
|
||||
void HandleLyricsReply(QNetworkReply *reply, const int id, const QString &artist, const QString &album, const QString &title);
|
||||
|
||||
private:
|
||||
static const char *kUrl;
|
||||
static const char *kApiUrl;
|
||||
static const char *kLyricsUrl;
|
||||
static const char *kUID;
|
||||
static const char *kTokenB64;
|
||||
QList<QNetworkReply*> replies_;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user