2016-10-09 19:44:06 +02:00
|
|
|
#include "./lyricswikia.h"
|
|
|
|
|
|
|
|
#include "../application/settings.h"
|
2018-03-07 01:18:01 +01:00
|
|
|
#include "../misc/networkaccessmanager.h"
|
2016-10-09 19:44:06 +02:00
|
|
|
|
|
|
|
#include <QNetworkAccessManager>
|
|
|
|
#include <QNetworkRequest>
|
2017-07-30 20:30:50 +02:00
|
|
|
#include <QStringBuilder>
|
2018-03-07 01:18:01 +01:00
|
|
|
#include <QTextDocument>
|
|
|
|
#include <QUrlQuery>
|
|
|
|
#include <QXmlStreamReader>
|
2016-10-09 22:41:34 +02:00
|
|
|
|
|
|
|
#include <functional>
|
2016-10-09 19:44:06 +02:00
|
|
|
|
|
|
|
using namespace std;
|
2016-10-09 22:41:34 +02:00
|
|
|
using namespace std::placeholders;
|
2016-10-09 19:44:06 +02:00
|
|
|
using namespace Utility;
|
|
|
|
|
|
|
|
namespace QtGui {
|
|
|
|
|
2019-04-16 22:34:47 +02:00
|
|
|
static const QString defaultLyricsWikiaUrl(QStringLiteral("https://lyrics.fandom.com"));
|
2016-10-09 22:41:34 +02:00
|
|
|
|
2019-09-25 18:17:08 +02:00
|
|
|
static QUrl lyricsWikiaApiUrl()
|
2016-10-24 20:15:10 +02:00
|
|
|
{
|
2018-08-19 15:11:46 +02:00
|
|
|
const auto &lyricsWikiaUrl = Settings::values().dbQuery.lyricsWikiaUrl;
|
2016-10-24 20:15:10 +02:00
|
|
|
return QUrl((lyricsWikiaUrl.isEmpty() ? defaultLyricsWikiaUrl : lyricsWikiaUrl) + QStringLiteral("/api.php"));
|
|
|
|
}
|
|
|
|
|
2019-09-25 18:16:20 +02:00
|
|
|
static void lazyInitializeLyricsWikiaSongId(SongDescription &desc)
|
|
|
|
{
|
|
|
|
if (!desc.songId.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
desc.songId = desc.artist % QChar(':') % desc.title;
|
|
|
|
desc.songId.replace(QChar(' '), QChar('_'));
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:18:01 +01:00
|
|
|
LyricsWikiaResultsModel::LyricsWikiaResultsModel(SongDescription &&initialSongDescription, QNetworkReply *reply)
|
|
|
|
: HttpResultsModel(move(initialSongDescription), reply)
|
|
|
|
{
|
|
|
|
}
|
2016-10-09 19:44:06 +02:00
|
|
|
|
2017-07-30 20:30:50 +02:00
|
|
|
bool LyricsWikiaResultsModel::fetchCover(const QModelIndex &index)
|
|
|
|
{
|
2019-04-21 17:08:24 +02:00
|
|
|
// FIXME: avoid code duplication with musicbrainz.cpp
|
|
|
|
|
|
|
|
// find song description
|
2018-08-19 15:11:46 +02:00
|
|
|
if (index.parent().isValid() || index.row() >= m_results.size()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
SongDescription &desc = m_results[index.row()];
|
2019-04-21 17:08:24 +02:00
|
|
|
|
|
|
|
// skip if cover is already available
|
2018-08-19 15:11:46 +02:00
|
|
|
if (!desc.cover.isEmpty()) {
|
|
|
|
return true;
|
|
|
|
}
|
2019-04-21 17:08:24 +02:00
|
|
|
|
|
|
|
// fail if album ID is unknown
|
2018-08-19 15:11:46 +02:00
|
|
|
if (desc.albumId.isEmpty()) {
|
|
|
|
m_errorList << tr("Unable to fetch cover: Album ID unknown");
|
|
|
|
emit resultsAvailable();
|
|
|
|
return true;
|
|
|
|
}
|
2019-04-21 17:08:24 +02:00
|
|
|
|
|
|
|
// skip if the item belongs to an album which cover has already been fetched
|
2019-06-14 18:08:05 +02:00
|
|
|
const auto coverData = s_coverData.find(desc.albumId);
|
|
|
|
if (coverData != s_coverData.end()) {
|
2019-04-21 17:08:24 +02:00
|
|
|
desc.cover = coverData->second;
|
|
|
|
return true;
|
2017-07-30 20:30:50 +02:00
|
|
|
}
|
2019-04-21 17:08:24 +02:00
|
|
|
|
|
|
|
// start http request
|
|
|
|
if (desc.coverUrl.isEmpty()) {
|
|
|
|
// request the cover URL
|
|
|
|
auto *const reply = requestAlbumDetails(desc);
|
|
|
|
addReply(reply, bind(&LyricsWikiaResultsModel::handleAlbumDetailsReplyFinished, this, reply, index.row()));
|
|
|
|
setFetchingCover(true);
|
|
|
|
} else {
|
|
|
|
// request the cover art
|
|
|
|
auto *const reply = networkAccessManager().get(QNetworkRequest(QUrl(desc.coverUrl)));
|
|
|
|
addReply(reply, bind(&LyricsWikiaResultsModel::handleCoverReplyFinished, this, reply, desc.albumId, index.row()));
|
|
|
|
setFetchingCover(true);
|
|
|
|
}
|
|
|
|
return false;
|
2017-07-30 20:30:50 +02:00
|
|
|
}
|
|
|
|
|
2016-10-09 22:41:34 +02:00
|
|
|
bool LyricsWikiaResultsModel::fetchLyrics(const QModelIndex &index)
|
2016-10-09 19:44:06 +02:00
|
|
|
{
|
2019-04-21 17:08:24 +02:00
|
|
|
// find song description
|
|
|
|
if (index.parent().isValid() || index.row() >= m_results.size()) {
|
|
|
|
return true;
|
2016-10-09 22:41:34 +02:00
|
|
|
}
|
2019-04-21 17:08:24 +02:00
|
|
|
SongDescription &desc = m_results[index.row()];
|
|
|
|
|
|
|
|
// skip if lyrics already present
|
|
|
|
if (!desc.lyrics.isEmpty()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fail if artist or title unknown
|
|
|
|
if (desc.artist.isEmpty() || desc.title.isEmpty()) {
|
|
|
|
m_errorList << tr("Unable to fetch lyrics: Artist or title is unknown.");
|
|
|
|
emit resultsAvailable();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// request lyrics
|
|
|
|
auto *reply = requestSongDetails(desc);
|
|
|
|
addReply(reply, bind(&LyricsWikiaResultsModel::handleSongDetailsFinished, this, reply, index.row()));
|
|
|
|
return false;
|
2016-10-09 22:41:34 +02:00
|
|
|
}
|
2016-10-09 19:44:06 +02:00
|
|
|
|
2016-10-09 22:41:34 +02:00
|
|
|
void LyricsWikiaResultsModel::parseInitialResults(const QByteArray &data)
|
|
|
|
{
|
2017-07-30 20:30:50 +02:00
|
|
|
// prepare parsing LyricsWikia meta data
|
2016-10-09 19:44:06 +02:00
|
|
|
beginResetModel();
|
|
|
|
m_results.clear();
|
2016-10-09 22:41:34 +02:00
|
|
|
QXmlStreamReader xmlReader(data);
|
2016-10-09 19:44:06 +02:00
|
|
|
|
|
|
|
// parse XML tree
|
2018-08-19 15:11:46 +02:00
|
|
|
// clang-format off
|
2016-10-09 19:44:06 +02:00
|
|
|
#include <qtutilities/misc/xmlparsermacros.h>
|
2018-08-19 15:11:46 +02:00
|
|
|
children {
|
|
|
|
iftag("getArtistResponse") {
|
2016-10-09 19:44:06 +02:00
|
|
|
QString artist;
|
2018-08-19 15:11:46 +02:00
|
|
|
children {
|
|
|
|
iftag("artist") {
|
2016-10-09 19:44:06 +02:00
|
|
|
artist = text;
|
2018-08-19 15:11:46 +02:00
|
|
|
} eliftag("albums") {
|
|
|
|
children {
|
|
|
|
iftag("albumResult") {
|
2016-10-09 19:44:06 +02:00
|
|
|
QString album, year;
|
|
|
|
QList<SongDescription> songs;
|
2018-08-19 15:11:46 +02:00
|
|
|
children {
|
|
|
|
iftag("album") {
|
2016-10-09 19:44:06 +02:00
|
|
|
album = text;
|
2018-08-19 15:11:46 +02:00
|
|
|
} eliftag("year") {
|
2016-10-09 19:44:06 +02:00
|
|
|
year = text;
|
2018-08-19 15:11:46 +02:00
|
|
|
} eliftag("songs") {
|
|
|
|
children {
|
|
|
|
iftag("item") {
|
2016-10-09 19:44:06 +02:00
|
|
|
songs << SongDescription();
|
|
|
|
songs.back().title = text;
|
2017-03-29 00:55:30 +02:00
|
|
|
songs.back().track = songs.size();
|
2018-03-07 01:18:01 +01:00
|
|
|
}
|
|
|
|
else_skip
|
2016-10-09 19:44:06 +02:00
|
|
|
}
|
2018-03-07 01:18:01 +01:00
|
|
|
}
|
|
|
|
else_skip
|
2016-10-09 22:41:34 +02:00
|
|
|
}
|
|
|
|
// need to filter results manually because the filtering provided by Lyrica Wiki API doesn't work
|
2018-03-07 01:18:01 +01:00
|
|
|
if ((m_initialDescription.album.isEmpty() || m_initialDescription.album == album)
|
|
|
|
&& (m_initialDescription.year.isEmpty() || m_initialDescription.year == year)
|
|
|
|
&& (!m_initialDescription.totalTracks || m_initialDescription.totalTracks == songs.size())) {
|
2018-08-19 15:11:46 +02:00
|
|
|
for (auto &song : songs) {
|
2018-03-07 01:18:01 +01:00
|
|
|
if ((m_initialDescription.title.isEmpty() || m_initialDescription.title == song.title)
|
|
|
|
&& (!m_initialDescription.track || m_initialDescription.track == song.track)) {
|
2016-10-09 22:41:34 +02:00
|
|
|
song.album = album;
|
|
|
|
song.year = year;
|
2017-03-29 00:55:30 +02:00
|
|
|
song.totalTracks = songs.size();
|
2016-10-09 22:41:34 +02:00
|
|
|
m_results << move(song);
|
2016-10-09 19:44:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-07 01:18:01 +01:00
|
|
|
}
|
|
|
|
else_skip
|
2016-10-09 19:44:06 +02:00
|
|
|
}
|
2018-03-07 01:18:01 +01:00
|
|
|
}
|
|
|
|
else_skip
|
2016-10-09 19:44:06 +02:00
|
|
|
}
|
2018-03-07 01:18:01 +01:00
|
|
|
for (SongDescription &song : m_results) {
|
2017-07-30 20:30:50 +02:00
|
|
|
// set the arist which is the same for all results
|
2016-10-09 19:44:06 +02:00
|
|
|
song.artist = artist;
|
2017-07-30 20:30:50 +02:00
|
|
|
// set the album ID (album is identified by its artist, year and name)
|
|
|
|
song.albumId = artist % QChar(':') % song.album % QChar('_') % QChar('(') % song.year % QChar(')');
|
|
|
|
song.albumId.replace(QChar(' '), QChar('_'));
|
2016-10-09 19:44:06 +02:00
|
|
|
}
|
2018-03-07 01:18:01 +01:00
|
|
|
}
|
|
|
|
else_skip
|
2016-10-09 19:44:06 +02:00
|
|
|
}
|
|
|
|
#include <qtutilities/misc/undefxmlparsermacros.h>
|
2018-08-19 15:11:46 +02:00
|
|
|
// clang-format on
|
2016-10-09 19:44:06 +02:00
|
|
|
|
|
|
|
// check for parsing errors
|
2018-03-07 01:18:01 +01:00
|
|
|
switch (xmlReader.error()) {
|
2016-10-09 19:44:06 +02:00
|
|
|
case QXmlStreamReader::NoError:
|
|
|
|
case QXmlStreamReader::PrematureEndOfDocumentError:
|
|
|
|
break;
|
|
|
|
default:
|
2016-10-09 22:41:34 +02:00
|
|
|
m_errorList << xmlReader.errorString();
|
2016-10-09 19:44:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// promote changes
|
|
|
|
endResetModel();
|
|
|
|
}
|
|
|
|
|
2016-10-09 22:41:34 +02:00
|
|
|
QNetworkReply *LyricsWikiaResultsModel::requestSongDetails(const SongDescription &songDescription)
|
|
|
|
{
|
|
|
|
// compose URL
|
|
|
|
QUrlQuery query;
|
|
|
|
query.addQueryItem(QStringLiteral("func"), QStringLiteral("getSong"));
|
|
|
|
query.addQueryItem(QStringLiteral("action"), QStringLiteral("lyrics"));
|
|
|
|
query.addQueryItem(QStringLiteral("fmt"), QStringLiteral("xml"));
|
|
|
|
query.addQueryItem(QStringLiteral("fixXML"), QString());
|
|
|
|
query.addQueryItem(QStringLiteral("artist"), songDescription.artist);
|
|
|
|
query.addQueryItem(QStringLiteral("title"), songDescription.title);
|
2018-03-07 01:18:01 +01:00
|
|
|
if (!songDescription.album.isEmpty()) {
|
2017-07-30 20:30:50 +02:00
|
|
|
// specifying album seems to have no effect but also doesn't hurt
|
2016-10-09 22:41:34 +02:00
|
|
|
query.addQueryItem(QStringLiteral("album"), songDescription.album);
|
|
|
|
}
|
2016-10-24 20:15:10 +02:00
|
|
|
QUrl url(lyricsWikiaApiUrl());
|
2016-10-09 22:41:34 +02:00
|
|
|
url.setQuery(query);
|
|
|
|
|
|
|
|
return Utility::networkAccessManager().get(QNetworkRequest(url));
|
|
|
|
}
|
|
|
|
|
2017-07-30 20:30:50 +02:00
|
|
|
QNetworkReply *LyricsWikiaResultsModel::requestAlbumDetails(const SongDescription &songDescription)
|
|
|
|
{
|
|
|
|
QUrl url(lyricsWikiaApiUrl());
|
|
|
|
url.setPath(QStringLiteral("/wiki/") + songDescription.albumId);
|
|
|
|
return Utility::networkAccessManager().get(QNetworkRequest(url));
|
|
|
|
}
|
|
|
|
|
2016-10-09 22:41:34 +02:00
|
|
|
void LyricsWikiaResultsModel::handleSongDetailsFinished(QNetworkReply *reply, int row)
|
|
|
|
{
|
|
|
|
QByteArray data;
|
2018-03-07 01:18:01 +01:00
|
|
|
if (auto *newReply = evaluateReplyResults(reply, data, true)) {
|
2016-10-09 22:41:34 +02:00
|
|
|
addReply(newReply, bind(&LyricsWikiaResultsModel::handleSongDetailsFinished, this, newReply, row));
|
2018-03-07 01:18:01 +01:00
|
|
|
} else if (!data.isEmpty()) {
|
2016-10-09 22:41:34 +02:00
|
|
|
parseSongDetails(row, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LyricsWikiaResultsModel::parseSongDetails(int row, const QByteArray &data)
|
|
|
|
{
|
|
|
|
// find associated result/desc
|
2018-03-07 01:18:01 +01:00
|
|
|
if (row >= m_results.size()) {
|
2016-10-09 22:41:34 +02:00
|
|
|
m_errorList << tr("Internal error: context for song details reply invalid");
|
|
|
|
setResultsAvailable(true);
|
|
|
|
return;
|
|
|
|
}
|
2019-09-25 18:16:20 +02:00
|
|
|
SongDescription &assocDesc = m_results[row];
|
2016-10-09 22:41:34 +02:00
|
|
|
|
|
|
|
QUrl parsedUrl;
|
|
|
|
|
|
|
|
// parse XML tree
|
2018-08-19 15:11:46 +02:00
|
|
|
// clang-format off
|
2016-10-09 22:41:34 +02:00
|
|
|
QXmlStreamReader xmlReader(data);
|
|
|
|
#include <qtutilities/misc/xmlparsermacros.h>
|
2018-08-19 15:11:46 +02:00
|
|
|
children {
|
|
|
|
iftag("LyricsResult") {
|
2016-10-09 22:41:34 +02:00
|
|
|
SongDescription parsedDesc;
|
2018-08-19 15:11:46 +02:00
|
|
|
children {
|
|
|
|
iftag("artist") {
|
2016-10-09 22:41:34 +02:00
|
|
|
parsedDesc.artist = text;
|
2018-08-19 15:11:46 +02:00
|
|
|
} eliftag("song") {
|
2016-10-09 22:41:34 +02:00
|
|
|
parsedDesc.title = text;
|
2018-08-19 15:11:46 +02:00
|
|
|
} eliftag("url") {
|
2016-10-09 22:41:34 +02:00
|
|
|
parsedUrl = text;
|
2018-03-07 01:18:01 +01:00
|
|
|
}
|
|
|
|
else_skip
|
2016-10-09 22:41:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// verify whether parsed results match what was requested
|
2018-03-07 01:18:01 +01:00
|
|
|
if (!parsedUrl.isEmpty() && assocDesc.title == parsedDesc.title && assocDesc.artist == parsedDesc.artist) {
|
2016-10-09 22:41:34 +02:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
parsedUrl.clear();
|
|
|
|
}
|
2018-03-07 01:18:01 +01:00
|
|
|
}
|
|
|
|
else_skip
|
2016-10-09 22:41:34 +02:00
|
|
|
}
|
|
|
|
#include <qtutilities/misc/undefxmlparsermacros.h>
|
2018-08-19 15:11:46 +02:00
|
|
|
// clang-format on
|
2016-10-09 22:41:34 +02:00
|
|
|
|
|
|
|
// check for parsing errors
|
2018-03-07 01:18:01 +01:00
|
|
|
switch (xmlReader.error()) {
|
2016-10-09 22:41:34 +02:00
|
|
|
case QXmlStreamReader::NoError:
|
|
|
|
case QXmlStreamReader::PrematureEndOfDocumentError:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
m_errorList << tr("Unable to parse song details: ") + xmlReader.errorString();
|
|
|
|
setResultsAvailable(true);
|
2018-03-07 01:18:01 +01:00
|
|
|
if (parsedUrl.isEmpty()) {
|
2016-10-09 22:41:34 +02:00
|
|
|
return; // don't complain about missing URL when the XML isn't even valid
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-03 19:38:27 +02:00
|
|
|
// requets lyrics (lyrics are truncated in XML response so just get them via the regular Wiki page)
|
2019-09-25 18:16:20 +02:00
|
|
|
// -> fall back to self-crafted URL if it was not possible to parse it from XML
|
2018-03-07 01:18:01 +01:00
|
|
|
if (parsedUrl.isEmpty()) {
|
2019-09-25 18:16:20 +02:00
|
|
|
lazyInitializeLyricsWikiaSongId(assocDesc);
|
|
|
|
parsedUrl.setPath(QStringLiteral("/wiki/") + assocDesc.songId);
|
|
|
|
m_errorList << tr(
|
|
|
|
"Song details requested for %1/%2 do not contain URL for Wiki page or do not match requested song; using self-crafted link instead")
|
|
|
|
.arg(assocDesc.artist, assocDesc.title);
|
2016-10-09 22:41:34 +02:00
|
|
|
}
|
2019-09-25 18:16:20 +02:00
|
|
|
// -> do not use parsed URL "as-is" in any case to avoid unintended requests
|
2016-10-24 20:15:10 +02:00
|
|
|
QUrl requestUrl(lyricsWikiaApiUrl());
|
2016-10-09 22:41:34 +02:00
|
|
|
requestUrl.setPath(parsedUrl.path());
|
2019-09-25 18:16:20 +02:00
|
|
|
// -> initialize the actual request
|
|
|
|
auto *const reply = Utility::networkAccessManager().get(QNetworkRequest(requestUrl));
|
2016-10-09 22:41:34 +02:00
|
|
|
addReply(reply, bind(&LyricsWikiaResultsModel::handleLyricsReplyFinished, this, reply, row));
|
|
|
|
}
|
|
|
|
|
|
|
|
void LyricsWikiaResultsModel::handleLyricsReplyFinished(QNetworkReply *reply, int row)
|
2016-10-09 19:44:06 +02:00
|
|
|
{
|
2016-10-09 22:41:34 +02:00
|
|
|
QByteArray data;
|
2018-03-07 01:18:01 +01:00
|
|
|
if (auto *newReply = evaluateReplyResults(reply, data, true)) {
|
2016-10-09 22:41:34 +02:00
|
|
|
addReply(newReply, bind(&LyricsWikiaResultsModel::handleLyricsReplyFinished, this, newReply, row));
|
2018-08-19 15:11:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!data.isEmpty()) {
|
|
|
|
parseLyricsResults(row, data);
|
2016-10-09 22:41:34 +02:00
|
|
|
}
|
2019-09-25 18:18:06 +02:00
|
|
|
if (!m_resultsAvailable) {
|
|
|
|
setResultsAvailable(true);
|
|
|
|
}
|
2016-10-09 22:41:34 +02:00
|
|
|
}
|
2016-10-09 19:44:06 +02:00
|
|
|
|
2016-10-09 22:41:34 +02:00
|
|
|
void LyricsWikiaResultsModel::parseLyricsResults(int row, const QByteArray &data)
|
|
|
|
{
|
|
|
|
// find associated result/desc
|
2018-03-07 01:18:01 +01:00
|
|
|
if (row >= m_results.size()) {
|
2016-10-09 22:41:34 +02:00
|
|
|
m_errorList << tr("Internal error: context for LyricsWikia page reply invalid");
|
|
|
|
setResultsAvailable(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SongDescription &assocDesc = m_results[row];
|
|
|
|
|
2017-07-30 20:30:50 +02:00
|
|
|
// convert data to QString
|
|
|
|
const QString html(data);
|
|
|
|
|
2016-10-09 22:41:34 +02:00
|
|
|
// parse lyrics from HTML
|
2018-08-19 15:11:46 +02:00
|
|
|
const auto lyricsStart = html.indexOf(QLatin1String("<div class='lyricbox'>"));
|
2018-03-07 01:18:01 +01:00
|
|
|
if (lyricsStart < 0) {
|
2016-10-09 22:41:34 +02:00
|
|
|
m_errorList << tr("Song details requested for %1/%2 do not contain lyrics").arg(assocDesc.artist, assocDesc.title);
|
|
|
|
setResultsAvailable(true);
|
|
|
|
return;
|
|
|
|
}
|
2018-08-19 15:11:46 +02:00
|
|
|
const auto lyricsEnd = html.indexOf(QLatin1String("<div class='lyricsbreak'></div>"), lyricsStart);
|
2016-10-09 22:41:34 +02:00
|
|
|
QTextDocument textDoc;
|
|
|
|
textDoc.setHtml(html.mid(lyricsStart, (lyricsEnd > lyricsStart) ? (lyricsEnd - lyricsStart) : -1));
|
|
|
|
assocDesc.lyrics = textDoc.toPlainText();
|
2017-07-30 20:30:50 +02:00
|
|
|
|
2019-09-25 18:18:06 +02:00
|
|
|
setResultsAvailable(true);
|
2016-10-09 22:41:34 +02:00
|
|
|
emit lyricsAvailable(index(row, 0));
|
|
|
|
}
|
|
|
|
|
2017-07-30 20:30:50 +02:00
|
|
|
void LyricsWikiaResultsModel::handleAlbumDetailsReplyFinished(QNetworkReply *reply, int row)
|
|
|
|
{
|
|
|
|
QByteArray data;
|
2018-03-07 01:18:01 +01:00
|
|
|
if (auto *newReply = evaluateReplyResults(reply, data, true)) {
|
2017-07-30 20:30:50 +02:00
|
|
|
addReply(newReply, bind(&LyricsWikiaResultsModel::handleAlbumDetailsReplyFinished, this, newReply, row));
|
|
|
|
} else {
|
|
|
|
parseAlbumDetailsAndFetchCover(row, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LyricsWikiaResultsModel::parseAlbumDetailsAndFetchCover(int row, const QByteArray &data)
|
|
|
|
{
|
|
|
|
// check whether the request failed (sufficient error message already emitted in this case)
|
2018-03-07 01:18:01 +01:00
|
|
|
if (data.isEmpty()) {
|
2017-07-30 20:30:50 +02:00
|
|
|
setFetchingCover(false);
|
|
|
|
setResultsAvailable(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find associated result/desc
|
2018-03-07 01:18:01 +01:00
|
|
|
if (row >= m_results.size()) {
|
2017-07-30 20:30:50 +02:00
|
|
|
m_errorList << tr("Internal error: context for LyricsWikia page reply invalid");
|
|
|
|
setFetchingCover(false);
|
|
|
|
setResultsAvailable(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SongDescription &assocDesc = m_results[row];
|
|
|
|
|
|
|
|
// convert data to QString
|
|
|
|
const QString html(data);
|
|
|
|
|
|
|
|
// parse cover URL from HTML
|
|
|
|
const int coverDivStart = html.indexOf(QLatin1String("<div class=\"plainlinks\" style=\"clear:right; float:right;")) + 56;
|
2018-03-07 01:18:01 +01:00
|
|
|
if (coverDivStart > 56) {
|
2017-07-30 20:30:50 +02:00
|
|
|
const int coverHrefStart = html.indexOf(QLatin1String("href=\""), coverDivStart) + 6;
|
2018-03-07 01:18:01 +01:00
|
|
|
if (coverHrefStart > coverDivStart + 6) {
|
2017-07-30 20:30:50 +02:00
|
|
|
const int coverHrefEnd = html.indexOf(QLatin1String("\""), coverHrefStart);
|
2018-03-07 01:18:01 +01:00
|
|
|
if (coverHrefEnd > 0) {
|
2017-07-30 20:30:50 +02:00
|
|
|
assocDesc.coverUrl = html.mid(coverHrefStart, coverHrefEnd - coverHrefStart);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// handle error case (cover URL not found)
|
2018-03-07 01:18:01 +01:00
|
|
|
if (assocDesc.coverUrl.isEmpty()) {
|
2017-07-30 20:30:50 +02:00
|
|
|
m_errorList << tr("Album details requested for %1/%2 do not contain cover").arg(assocDesc.artist, assocDesc.album);
|
|
|
|
setFetchingCover(false);
|
|
|
|
setResultsAvailable(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// request the cover art
|
2018-08-19 15:11:46 +02:00
|
|
|
auto *const reply = networkAccessManager().get(QNetworkRequest(QUrl(assocDesc.coverUrl)));
|
2017-07-30 20:30:50 +02:00
|
|
|
addReply(reply, bind(&LyricsWikiaResultsModel::handleCoverReplyFinished, this, reply, assocDesc.albumId, row));
|
|
|
|
}
|
|
|
|
|
2017-08-08 20:22:37 +02:00
|
|
|
QUrl LyricsWikiaResultsModel::webUrl(const QModelIndex &index)
|
|
|
|
{
|
2018-03-07 01:18:01 +01:00
|
|
|
if (index.parent().isValid() || index.row() >= results().size()) {
|
2017-08-08 20:22:37 +02:00
|
|
|
return QUrl();
|
|
|
|
}
|
|
|
|
|
|
|
|
SongDescription &desc = m_results[index.row()];
|
2019-09-25 18:16:20 +02:00
|
|
|
lazyInitializeLyricsWikiaSongId(desc);
|
2017-08-08 20:22:37 +02:00
|
|
|
|
|
|
|
// return URL
|
|
|
|
QUrl url(lyricsWikiaApiUrl());
|
|
|
|
url.setPath(QStringLiteral("/wiki/") + desc.songId);
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
2016-10-09 22:41:34 +02:00
|
|
|
QueryResultsModel *queryLyricsWikia(SongDescription &&songDescription)
|
|
|
|
{
|
2016-10-09 19:44:06 +02:00
|
|
|
// compose URL
|
|
|
|
QUrlQuery query;
|
|
|
|
query.addQueryItem(QStringLiteral("func"), QStringLiteral("getArtist"));
|
|
|
|
query.addQueryItem(QStringLiteral("fmt"), QStringLiteral("xml"));
|
|
|
|
query.addQueryItem(QStringLiteral("fixXML"), QString());
|
|
|
|
query.addQueryItem(QStringLiteral("artist"), songDescription.artist);
|
2016-10-24 20:15:10 +02:00
|
|
|
QUrl url(lyricsWikiaApiUrl());
|
2016-10-09 19:44:06 +02:00
|
|
|
url.setQuery(query);
|
|
|
|
|
|
|
|
// NOTE: Only getArtist seems to work, so artist must be specified and filtering must
|
|
|
|
// be done manually when parsing results.
|
|
|
|
|
|
|
|
// make request
|
|
|
|
return new LyricsWikiaResultsModel(move(songDescription), Utility::networkAccessManager().get(QNetworkRequest(url)));
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace QtGui
|