154 lines
6.5 KiB
C++
154 lines
6.5 KiB
C++
#include "./spotifydownload.h"
|
|
|
|
#include "../application/utils.h"
|
|
|
|
#include <QApplication>
|
|
#include <QClipboard>
|
|
#include <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QJsonParseError>
|
|
#include <QUrlQuery>
|
|
|
|
using namespace Application;
|
|
|
|
namespace Network {
|
|
|
|
const QUrl SpotifyDownload::m_spotifyUrl = QUrl(QStringLiteral("https://play.spotify.com/"));
|
|
bool SpotifyDownload::m_authenticationCredentialsValidated = false;
|
|
QString SpotifyDownload::m_csrftoken = QString();
|
|
QString SpotifyDownload::m_trackingId = QString();
|
|
QString SpotifyDownload::m_referrer = QString();
|
|
QString SpotifyDownload::m_creationFlow = QString();
|
|
QStringList SpotifyDownload::m_supportedUseragents = QStringList()
|
|
<< QStringLiteral("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:23.0) Gecko/20100101 Firefox/23.0");
|
|
|
|
/*!
|
|
* \class SpotifyDownload
|
|
* \brief Download implementation for Spotify songs.
|
|
* \remarks Under construction (not even rudimental finished).
|
|
*/
|
|
|
|
/*!
|
|
* \brief Constructs a new SpotifyDownload for the specified \a songid.
|
|
*/
|
|
SpotifyDownload::SpotifyDownload(const QString &songid, QObject *parent)
|
|
: HttpDownloadWithInfoRequst(QUrl(), parent)
|
|
, m_currentRequest(SpotifyRequestType::Invalid)
|
|
, m_triesToGetAuthenticationData(0)
|
|
{
|
|
setId(songid);
|
|
}
|
|
|
|
QString SpotifyDownload::typeName() const
|
|
{
|
|
return tr("Spotify");
|
|
}
|
|
|
|
void SpotifyDownload::resetSession()
|
|
{
|
|
m_authenticationCredentialsValidated = false;
|
|
m_csrftoken.clear();
|
|
m_trackingId.clear();
|
|
m_referrer.clear();
|
|
m_creationFlow.clear();
|
|
}
|
|
|
|
Download *SpotifyDownload::infoRequestDownload(bool &success, QString &reasonForFail)
|
|
{
|
|
HttpDownload *download = nullptr;
|
|
if (m_csrftoken.isEmpty() || m_trackingId.isEmpty() /* || creationFlow.isEmpty()*/) {
|
|
if (m_triesToGetAuthenticationData < 2) {
|
|
download = new HttpDownload(m_spotifyUrl);
|
|
download->setCustomUserAgent(m_supportedUseragents.at(0));
|
|
success = true;
|
|
++m_triesToGetAuthenticationData;
|
|
m_currentRequest = SpotifyRequestType::GetAuthenticationData;
|
|
} else {
|
|
reasonForFail = tr("Unable to find data required for autentication.");
|
|
success = false;
|
|
}
|
|
} else if (!m_authenticationCredentialsValidated) {
|
|
if (initialAuthenticationCredentials().isIncomplete()) {
|
|
reportAuthenticationRequired(
|
|
-1, tr("To download songs from Spotify authentication is required so you have to enter the credentials of your Spotify account."));
|
|
reasonForFail = tr("Authentication credentials not given.");
|
|
//networkError = QNetworkReply::AuthenticationRequiredError;
|
|
success = false;
|
|
} else {
|
|
QUrl url(m_spotifyUrl);
|
|
url.setPath(QStringLiteral("/xhr/json/auth.php"));
|
|
download = new HttpDownload(url);
|
|
QByteArray postData;
|
|
QUrlQuery query;
|
|
query.addQueryItem(QStringLiteral("type"), QStringLiteral("sp"));
|
|
query.addQueryItem(QStringLiteral("username"), initialAuthenticationCredentials().userName());
|
|
query.addQueryItem(QStringLiteral("password"), initialAuthenticationCredentials().password());
|
|
query.addQueryItem(QStringLiteral("secret"), m_csrftoken);
|
|
query.addQueryItem(QStringLiteral("trackingId"), m_trackingId);
|
|
query.addQueryItem(QStringLiteral("landingURL"), m_spotifyUrl.toString());
|
|
query.addQueryItem(QStringLiteral("cf"), m_creationFlow);
|
|
postData.append(query.toString(QUrl::FullyEncoded));
|
|
download->setMethod(HttpDownloadMethod::Post);
|
|
download->setPostData(postData);
|
|
download->setCustomUserAgent(m_supportedUseragents.at(0));
|
|
|
|
success = true;
|
|
m_currentRequest = SpotifyRequestType::Authenticate;
|
|
}
|
|
}
|
|
return download;
|
|
}
|
|
|
|
void SpotifyDownload::evalVideoInformation(Download *, QBuffer *videoInfoBuffer)
|
|
{
|
|
if (m_currentRequest == SpotifyRequestType::Invalid)
|
|
reportInitiated(false, tr("Interal error (current request type not set)."));
|
|
else {
|
|
switch (m_currentRequest) {
|
|
case SpotifyRequestType::GetAuthenticationData: {
|
|
QString responseData(videoInfoBuffer->readAll());
|
|
substring(responseData, m_csrftoken, 0, QStringLiteral("\"csrftoken\":\""), QStringLiteral("\""));
|
|
substring(responseData, m_trackingId, 0, QStringLiteral("\"trackingId\":\""), QStringLiteral("\""));
|
|
substring(responseData, m_creationFlow, 0, QStringLiteral("\"creationFlow\":\""), QStringLiteral("\""));
|
|
substring(responseData, m_referrer, 0, QStringLiteral("\"referrer\":\""), QStringLiteral("\""));
|
|
m_currentRequest = SpotifyRequestType::Invalid;
|
|
doInit();
|
|
break;
|
|
}
|
|
case SpotifyRequestType::Authenticate: {
|
|
QByteArray responseData(videoInfoBuffer->readAll());
|
|
QApplication::clipboard()->setText(QString(responseData));
|
|
QJsonParseError error;
|
|
QJsonDocument document = QJsonDocument::fromJson(responseData, &error);
|
|
if (error.error == QJsonParseError::NoError) {
|
|
QJsonObject obj = document.object();
|
|
QJsonValue statusVal = obj.value(QStringLiteral("status"));
|
|
if (statusVal.toString().compare(QLatin1String("ok"), Qt::CaseInsensitive) == 0) {
|
|
m_authenticationCredentialsValidated = true;
|
|
reportInitiated(true);
|
|
} else {
|
|
QString error = obj.value(QStringLiteral("error")).toString();
|
|
QString message;
|
|
if (error.isEmpty()) {
|
|
message = tr("Authentication failed. Spotify returned no error message.");
|
|
} else if (error.compare(QLatin1String("invalid_credentials"), Qt::CaseInsensitive) == 0) {
|
|
message = tr("Authentication failed because the entered credentials are invalid.");
|
|
} else {
|
|
message = tr("Authentication failed. Error message returned by Spotify: %1").arg(error);
|
|
}
|
|
reportInitiated(false, message);
|
|
}
|
|
} else {
|
|
reportInitiated(false,
|
|
tr("Authentication failed because the response by Spotify is no valid Json document (parse error: %1).")
|
|
.arg(error.errorString()));
|
|
}
|
|
break;
|
|
}
|
|
case SpotifyRequestType::Invalid:;
|
|
}
|
|
}
|
|
}
|
|
} // namespace Network
|