Improve URL handler, return error for encrypted Tidal streams
This commit is contained in:
@@ -130,7 +130,8 @@ class InternetService : public QObject {
|
|||||||
void RemoveSongs(SongList songs);
|
void RemoveSongs(SongList songs);
|
||||||
void RemoveSongs(SongMap songs);
|
void RemoveSongs(SongMap songs);
|
||||||
|
|
||||||
void StreamURLFinished(QUrl original_url, QUrl stream_url, Song::FileType filetype, int samplerate, int bit_depth, qint64 duration, QString error = QString());
|
void StreamURLFailure(uint id, QUrl original_url, QString error);
|
||||||
|
void StreamURLSuccess(uint id, QUrl original_url, QUrl stream_url, Song::FileType filetype, int samplerate, int bit_depth, qint64 duration);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Application *app_;
|
Application *app_;
|
||||||
|
|||||||
@@ -178,10 +178,16 @@ QobuzService::QobuzService(Application *app, QObject *parent)
|
|||||||
|
|
||||||
QobuzService::~QobuzService() {
|
QobuzService::~QobuzService() {
|
||||||
|
|
||||||
|
while (!replies_.isEmpty()) {
|
||||||
|
QNetworkReply *reply = replies_.takeFirst();
|
||||||
|
QObject::disconnect(reply, nullptr, this, nullptr);
|
||||||
|
reply->abort();
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
while (!stream_url_requests_.isEmpty()) {
|
while (!stream_url_requests_.isEmpty()) {
|
||||||
std::shared_ptr<QobuzStreamURLRequest> stream_url_req = stream_url_requests_.take(stream_url_requests_.firstKey());
|
std::shared_ptr<QobuzStreamURLRequest> stream_url_req = stream_url_requests_.take(stream_url_requests_.firstKey());
|
||||||
QObject::disconnect(stream_url_req.get(), nullptr, this, nullptr);
|
QObject::disconnect(stream_url_req.get(), nullptr, this, nullptr);
|
||||||
stream_url_req->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
artists_collection_backend_->deleteLater();
|
artists_collection_backend_->deleteLater();
|
||||||
@@ -714,31 +720,44 @@ void QobuzService::SearchResultsReceived(const int id, const SongMap &songs, con
|
|||||||
emit SearchResults(id, songs, error);
|
emit SearchResults(id, songs, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QobuzService::GetStreamURL(const QUrl &url) {
|
uint QobuzService::GetStreamURL(const QUrl &url, QString &error) {
|
||||||
|
|
||||||
if (app_id().isEmpty() || app_secret().isEmpty()) { // Don't check for login here, because we allow automatic login.
|
if (app_id().isEmpty() || app_secret().isEmpty()) { // Don't check for login here, because we allow automatic login.
|
||||||
emit StreamURLFinished(url, url, Song::FileType_Stream, -1, -1, -1, tr("Missing Qobuz app ID or secret."));
|
error = tr("Missing Qobuz app ID or secret.");
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int id = ++next_stream_url_request_id_;
|
uint id = 0;
|
||||||
|
while (id == 0) id = ++next_stream_url_request_id_;
|
||||||
std::shared_ptr<QobuzStreamURLRequest> stream_url_req = std::make_shared<QobuzStreamURLRequest>(this, network_, url, id);
|
std::shared_ptr<QobuzStreamURLRequest> stream_url_req = std::make_shared<QobuzStreamURLRequest>(this, network_, url, id);
|
||||||
stream_url_requests_.insert(id, stream_url_req);
|
stream_url_requests_.insert(id, stream_url_req);
|
||||||
|
|
||||||
QObject::connect(stream_url_req.get(), &QobuzStreamURLRequest::TryLogin, this, &QobuzService::TryLogin);
|
QObject::connect(stream_url_req.get(), &QobuzStreamURLRequest::TryLogin, this, &QobuzService::TryLogin);
|
||||||
QObject::connect(stream_url_req.get(), &QobuzStreamURLRequest::StreamURLFinished, this, &QobuzService::HandleStreamURLFinished);
|
QObject::connect(stream_url_req.get(), &QobuzStreamURLRequest::StreamURLFailure, this, &QobuzService::HandleStreamURLFailure);
|
||||||
|
QObject::connect(stream_url_req.get(), &QobuzStreamURLRequest::StreamURLSuccess, this, &QobuzService::HandleStreamURLSuccess);
|
||||||
QObject::connect(this, &QobuzService::LoginComplete, stream_url_req.get(), &QobuzStreamURLRequest::LoginComplete);
|
QObject::connect(this, &QobuzService::LoginComplete, stream_url_req.get(), &QobuzStreamURLRequest::LoginComplete);
|
||||||
|
|
||||||
stream_url_req->Process();
|
stream_url_req->Process();
|
||||||
|
|
||||||
|
return id;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QobuzService::HandleStreamURLFinished(const int id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, const QString &error) {
|
void QobuzService::HandleStreamURLFailure(const uint id, const QUrl &original_url, const QString &error) {
|
||||||
|
|
||||||
if (!stream_url_requests_.contains(id)) return;
|
if (!stream_url_requests_.contains(id)) return;
|
||||||
std::shared_ptr<QobuzStreamURLRequest> stream_url_req = stream_url_requests_.take(id);
|
std::shared_ptr<QobuzStreamURLRequest> stream_url_req = stream_url_requests_.take(id);
|
||||||
|
|
||||||
emit StreamURLFinished(original_url, stream_url, filetype, samplerate, bit_depth, duration, error);
|
emit StreamURLFailure(id, original_url, error);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void QobuzService::HandleStreamURLSuccess(const uint id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration) {
|
||||||
|
|
||||||
|
if (!stream_url_requests_.contains(id)) return;
|
||||||
|
std::shared_ptr<QobuzStreamURLRequest> stream_url_req = stream_url_requests_.take(id);
|
||||||
|
|
||||||
|
emit StreamURLSuccess(id, original_url, stream_url, filetype, samplerate, bit_depth, duration);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class QobuzService : public InternetService {
|
|||||||
bool login_sent() { return login_sent_; }
|
bool login_sent() { return login_sent_; }
|
||||||
bool login_attempts() { return login_attempts_; }
|
bool login_attempts() { return login_attempts_; }
|
||||||
|
|
||||||
void GetStreamURL(const QUrl &url);
|
uint GetStreamURL(const QUrl &url, QString &error);
|
||||||
|
|
||||||
CollectionBackend *artists_collection_backend() override { return artists_collection_backend_; }
|
CollectionBackend *artists_collection_backend() override { return artists_collection_backend_; }
|
||||||
CollectionBackend *albums_collection_backend() override { return albums_collection_backend_; }
|
CollectionBackend *albums_collection_backend() override { return albums_collection_backend_; }
|
||||||
@@ -138,7 +138,8 @@ class QobuzService : public InternetService {
|
|||||||
void ArtistsUpdateProgressReceived(const int id, const int progress);
|
void ArtistsUpdateProgressReceived(const int id, const int progress);
|
||||||
void AlbumsUpdateProgressReceived(const int id, const int progress);
|
void AlbumsUpdateProgressReceived(const int id, const int progress);
|
||||||
void SongsUpdateProgressReceived(const int id, const int progress);
|
void SongsUpdateProgressReceived(const int id, const int progress);
|
||||||
void HandleStreamURLFinished(const int id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, const QString &error);
|
void HandleStreamURLFailure(const uint id, const QUrl &original_url, const QString &error);
|
||||||
|
void HandleStreamURLSuccess(const uint id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef QPair<QString, QString> Param;
|
typedef QPair<QString, QString> Param;
|
||||||
@@ -211,8 +212,8 @@ class QobuzService : public InternetService {
|
|||||||
bool login_sent_;
|
bool login_sent_;
|
||||||
int login_attempts_;
|
int login_attempts_;
|
||||||
|
|
||||||
int next_stream_url_request_id_;
|
uint next_stream_url_request_id_;
|
||||||
QMap<int, std::shared_ptr<QobuzStreamURLRequest>> stream_url_requests_;
|
QMap<uint, std::shared_ptr<QobuzStreamURLRequest>> stream_url_requests_;
|
||||||
|
|
||||||
QStringList login_errors_;
|
QStringList login_errors_;
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
#include "qobuzbaserequest.h"
|
#include "qobuzbaserequest.h"
|
||||||
#include "qobuzstreamurlrequest.h"
|
#include "qobuzstreamurlrequest.h"
|
||||||
|
|
||||||
QobuzStreamURLRequest::QobuzStreamURLRequest(QobuzService *service, NetworkAccessManager *network, const QUrl &original_url, const int id, QObject *parent)
|
QobuzStreamURLRequest::QobuzStreamURLRequest(QobuzService *service, NetworkAccessManager *network, const QUrl &original_url, const uint id, QObject *parent)
|
||||||
: QobuzBaseRequest(service, network, parent),
|
: QobuzBaseRequest(service, network, parent),
|
||||||
service_(service),
|
service_(service),
|
||||||
reply_(nullptr),
|
reply_(nullptr),
|
||||||
@@ -71,7 +71,7 @@ void QobuzStreamURLRequest::LoginComplete(const bool success, const QString &err
|
|||||||
need_login_ = false;
|
need_login_ = false;
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, error);
|
emit StreamURLFailure(id_, original_url_, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ void QobuzStreamURLRequest::LoginComplete(const bool success, const QString &err
|
|||||||
void QobuzStreamURLRequest::Process() {
|
void QobuzStreamURLRequest::Process() {
|
||||||
|
|
||||||
if (app_id().isEmpty() || app_secret().isEmpty()) {
|
if (app_id().isEmpty() || app_secret().isEmpty()) {
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, tr("Missing Qobuz app ID or secret."));
|
emit StreamURLFailure(id_, original_url_, tr("Missing Qobuz app ID or secret."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ void QobuzStreamURLRequest::Cancel() {
|
|||||||
reply_->abort();
|
reply_->abort();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, tr("Cancelled."));
|
emit StreamURLFailure(id_, original_url_, tr("Cancelled."));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -172,32 +172,32 @@ void QobuzStreamURLRequest::StreamURLReceived() {
|
|||||||
need_login_ = true;
|
need_login_ = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject json_obj = ExtractJsonObj(data);
|
QJsonObject json_obj = ExtractJsonObj(data);
|
||||||
if (json_obj.isEmpty()) {
|
if (json_obj.isEmpty()) {
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!json_obj.contains("track_id")) {
|
if (!json_obj.contains("track_id")) {
|
||||||
Error("Invalid Json reply, stream url is missing track_id.", json_obj);
|
Error("Invalid Json reply, stream url is missing track_id.", json_obj);
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int track_id = json_obj["track_id"].toInt();
|
int track_id = json_obj["track_id"].toInt();
|
||||||
if (track_id != song_id_) {
|
if (track_id != song_id_) {
|
||||||
Error("Incorrect track ID returned.", json_obj);
|
Error("Incorrect track ID returned.", json_obj);
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!json_obj.contains("mime_type") || !json_obj.contains("url")) {
|
if (!json_obj.contains("mime_type") || !json_obj.contains("url")) {
|
||||||
Error("Invalid Json reply, stream url is missing url or mime_type.", json_obj);
|
Error("Invalid Json reply, stream url is missing url or mime_type.", json_obj);
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ void QobuzStreamURLRequest::StreamURLReceived() {
|
|||||||
|
|
||||||
if (!url.isValid()) {
|
if (!url.isValid()) {
|
||||||
Error("Returned stream url is invalid.", json_obj);
|
Error("Returned stream url is invalid.", json_obj);
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, filetype, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ void QobuzStreamURLRequest::StreamURLReceived() {
|
|||||||
bit_depth = static_cast<int>(json_obj["bit_depth"].toDouble());
|
bit_depth = static_cast<int>(json_obj["bit_depth"].toDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
emit StreamURLFinished(id_, original_url_, url, filetype, samplerate, bit_depth, duration);
|
emit StreamURLSuccess(id_, original_url_, url, filetype, samplerate, bit_depth, duration);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class QobuzStreamURLRequest : public QobuzBaseRequest {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit QobuzStreamURLRequest(QobuzService *service, NetworkAccessManager *network, const QUrl &original_url, const int id, QObject *parent = nullptr);
|
explicit QobuzStreamURLRequest(QobuzService *service, NetworkAccessManager *network, const QUrl &original_url, const uint id, QObject *parent = nullptr);
|
||||||
~QobuzStreamURLRequest();
|
~QobuzStreamURLRequest();
|
||||||
|
|
||||||
void GetStreamURL();
|
void GetStreamURL();
|
||||||
@@ -54,7 +54,8 @@ class QobuzStreamURLRequest : public QobuzBaseRequest {
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void TryLogin();
|
void TryLogin();
|
||||||
void StreamURLFinished(int id, QUrl original_url, QUrl stream_url, Song::FileType filetype, int samplerate, int bit_depth, qint64 duration, QString error = QString());
|
void StreamURLFailure(uint id, QUrl original_url, QString error);
|
||||||
|
void StreamURLSuccess(uint id, QUrl original_url, QUrl stream_url, Song::FileType filetype, int samplerate, int bit_depth, qint64 duration);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void StreamURLReceived();
|
void StreamURLReceived();
|
||||||
@@ -68,7 +69,7 @@ class QobuzStreamURLRequest : public QobuzBaseRequest {
|
|||||||
QobuzService *service_;
|
QobuzService *service_;
|
||||||
QNetworkReply *reply_;
|
QNetworkReply *reply_;
|
||||||
QUrl original_url_;
|
QUrl original_url_;
|
||||||
int id_;
|
uint id_;
|
||||||
int song_id_;
|
int song_id_;
|
||||||
int tries_;
|
int tries_;
|
||||||
bool need_login_;
|
bool need_login_;
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
@@ -30,38 +32,53 @@
|
|||||||
QobuzUrlHandler::QobuzUrlHandler(Application *app, QobuzService *service)
|
QobuzUrlHandler::QobuzUrlHandler(Application *app, QobuzService *service)
|
||||||
: UrlHandler(service),
|
: UrlHandler(service),
|
||||||
app_(app),
|
app_(app),
|
||||||
service_(service),
|
service_(service) {
|
||||||
task_id_(-1) {
|
|
||||||
|
|
||||||
QObject::connect(service, &QobuzService::StreamURLFinished, this, &QobuzUrlHandler::GetStreamURLFinished);
|
QObject::connect(service, &QobuzService::StreamURLFailure, this, &QobuzUrlHandler::GetStreamURLFailure);
|
||||||
|
QObject::connect(service, &QobuzService::StreamURLSuccess, this, &QobuzUrlHandler::GetStreamURLSuccess);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UrlHandler::LoadResult QobuzUrlHandler::StartLoading(const QUrl &url) {
|
UrlHandler::LoadResult QobuzUrlHandler::StartLoading(const QUrl &url) {
|
||||||
|
|
||||||
|
Request req;
|
||||||
|
req.task_id = app_->task_manager()->StartTask(QString("Loading %1 stream...").arg(url.scheme()));
|
||||||
|
QString error;
|
||||||
|
req.id = service_->GetStreamURL(url, error);
|
||||||
|
if (req.id == 0) {
|
||||||
|
CancelTask(req.task_id);
|
||||||
|
return LoadResult(url, LoadResult::Error, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
requests_.insert(req.id, req);
|
||||||
|
|
||||||
LoadResult ret(url);
|
LoadResult ret(url);
|
||||||
if (task_id_ != -1) return ret;
|
|
||||||
task_id_ = app_->task_manager()->StartTask(QString("Loading %1 stream...").arg(url.scheme()));
|
|
||||||
service_->GetStreamURL(url);
|
|
||||||
ret.type_ = LoadResult::WillLoadAsynchronously;
|
ret.type_ = LoadResult::WillLoadAsynchronously;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QobuzUrlHandler::GetStreamURLFinished(const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, const QString &error) {
|
void QobuzUrlHandler::GetStreamURLFailure(const uint id, const QUrl &original_url, const QString &error) {
|
||||||
|
|
||||||
if (task_id_ == -1) return;
|
if (!requests_.contains(id)) return;
|
||||||
CancelTask();
|
Request req = requests_.take(id);
|
||||||
if (error.isEmpty()) {
|
CancelTask(req.task_id);
|
||||||
emit AsyncLoadComplete(LoadResult(original_url, LoadResult::TrackAvailable, stream_url, filetype, samplerate, bit_depth, duration));
|
|
||||||
}
|
emit AsyncLoadComplete(LoadResult(original_url, LoadResult::Error, error));
|
||||||
else {
|
|
||||||
emit AsyncLoadComplete(LoadResult(original_url, LoadResult::Error, error));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QobuzUrlHandler::CancelTask() {
|
void QobuzUrlHandler::GetStreamURLSuccess(const uint id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration) {
|
||||||
app_->task_manager()->SetTaskFinished(task_id_);
|
|
||||||
task_id_ = -1;
|
if (!requests_.contains(id)) return;
|
||||||
|
Request req = requests_.take(id);
|
||||||
|
CancelTask(req.task_id);
|
||||||
|
|
||||||
|
emit AsyncLoadComplete(LoadResult(original_url, LoadResult::TrackAvailable, stream_url, filetype, samplerate, bit_depth, duration));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void QobuzUrlHandler::CancelTask(const int task_id) {
|
||||||
|
app_->task_manager()->SetTaskFinished(task_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
@@ -40,15 +41,22 @@ class QobuzUrlHandler : public UrlHandler {
|
|||||||
QString scheme() const { return service_->url_scheme(); }
|
QString scheme() const { return service_->url_scheme(); }
|
||||||
LoadResult StartLoading(const QUrl &url);
|
LoadResult StartLoading(const QUrl &url);
|
||||||
|
|
||||||
void CancelTask();
|
private:
|
||||||
|
void CancelTask(const int task_id);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void GetStreamURLFinished(const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, const QString &error = QString());
|
void GetStreamURLFailure(const uint id, const QUrl &original_url, const QString &error);
|
||||||
|
void GetStreamURLSuccess(const uint id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Request {
|
||||||
|
Request() : id(0), task_id(-1) {}
|
||||||
|
uint id;
|
||||||
|
int task_id;
|
||||||
|
};
|
||||||
Application *app_;
|
Application *app_;
|
||||||
QobuzService *service_;
|
QobuzService *service_;
|
||||||
int task_id_;
|
QMap<uint, Request> requests_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,6 @@ TidalService::~TidalService() {
|
|||||||
while (!stream_url_requests_.isEmpty()) {
|
while (!stream_url_requests_.isEmpty()) {
|
||||||
std::shared_ptr<TidalStreamURLRequest> stream_url_req = stream_url_requests_.take(stream_url_requests_.firstKey());
|
std::shared_ptr<TidalStreamURLRequest> stream_url_req = stream_url_requests_.take(stream_url_requests_.firstKey());
|
||||||
QObject::disconnect(stream_url_req.get(), nullptr, this, nullptr);
|
QObject::disconnect(stream_url_req.get(), nullptr, this, nullptr);
|
||||||
stream_url_req->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
artists_collection_backend_->deleteLater();
|
artists_collection_backend_->deleteLater();
|
||||||
@@ -987,37 +986,50 @@ void TidalService::SearchResultsReceived(const int id, const SongMap &songs, con
|
|||||||
emit SearchResults(id, songs, error);
|
emit SearchResults(id, songs, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TidalService::GetStreamURL(const QUrl &url) {
|
uint TidalService::GetStreamURL(const QUrl &url, QString &error) {
|
||||||
|
|
||||||
if (!authenticated()) {
|
if (!authenticated()) {
|
||||||
if (oauth_) {
|
if (oauth_) {
|
||||||
emit StreamURLFinished(url, url, Song::FileType_Stream, -1, -1, -1, tr("Not authenticated with Tidal."));
|
error = tr("Not authenticated with Tidal.");
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (api_token_.isEmpty() || username_.isEmpty() || password_.isEmpty()) {
|
else if (api_token_.isEmpty() || username_.isEmpty() || password_.isEmpty()) {
|
||||||
emit StreamURLFinished(url, url, Song::FileType_Stream, -1, -1, -1, tr("Missing Tidal API token, username or password."));
|
error = tr("Missing Tidal API token, username or password.");
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int id = ++next_stream_url_request_id_;
|
uint id = 0;
|
||||||
|
while (id == 0) id = ++next_stream_url_request_id_;
|
||||||
std::shared_ptr<TidalStreamURLRequest> stream_url_req = std::make_shared<TidalStreamURLRequest>(this, network_, url, id);
|
std::shared_ptr<TidalStreamURLRequest> stream_url_req = std::make_shared<TidalStreamURLRequest>(this, network_, url, id);
|
||||||
stream_url_requests_.insert(id, stream_url_req);
|
stream_url_requests_.insert(id, stream_url_req);
|
||||||
|
|
||||||
QObject::connect(stream_url_req.get(), &TidalStreamURLRequest::TryLogin, this, &TidalService::TryLogin);
|
QObject::connect(stream_url_req.get(), &TidalStreamURLRequest::TryLogin, this, &TidalService::TryLogin);
|
||||||
QObject::connect(stream_url_req.get(), &TidalStreamURLRequest::StreamURLFinished, this, &TidalService::HandleStreamURLFinished);
|
QObject::connect(stream_url_req.get(), &TidalStreamURLRequest::StreamURLFailure, this, &TidalService::HandleStreamURLFailure);
|
||||||
|
QObject::connect(stream_url_req.get(), &TidalStreamURLRequest::StreamURLSuccess, this, &TidalService::HandleStreamURLSuccess);
|
||||||
QObject::connect(this, &TidalService::LoginComplete, stream_url_req.get(), &TidalStreamURLRequest::LoginComplete);
|
QObject::connect(this, &TidalService::LoginComplete, stream_url_req.get(), &TidalStreamURLRequest::LoginComplete);
|
||||||
|
|
||||||
stream_url_req->Process();
|
stream_url_req->Process();
|
||||||
|
|
||||||
|
return id;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TidalService::HandleStreamURLFinished(const int id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, const QString &error) {
|
void TidalService::HandleStreamURLFailure(const uint id, const QUrl &original_url, const QString &error) {
|
||||||
|
|
||||||
if (!stream_url_requests_.contains(id)) return;
|
if (!stream_url_requests_.contains(id)) return;
|
||||||
std::shared_ptr<TidalStreamURLRequest> stream_url_req = stream_url_requests_.take(id);
|
std::shared_ptr<TidalStreamURLRequest> stream_url_req = stream_url_requests_.take(id);
|
||||||
|
|
||||||
emit StreamURLFinished(original_url, stream_url, filetype, samplerate, bit_depth, duration, error);
|
emit StreamURLFailure(id, original_url, error);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TidalService::HandleStreamURLSuccess(const uint id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration) {
|
||||||
|
|
||||||
|
if (!stream_url_requests_.contains(id)) return;
|
||||||
|
std::shared_ptr<TidalStreamURLRequest> stream_url_req = stream_url_requests_.take(id);
|
||||||
|
|
||||||
|
emit StreamURLSuccess(id, original_url, stream_url, filetype, samplerate, bit_depth, duration);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ class TidalService : public InternetService {
|
|||||||
bool login_sent() { return login_sent_; }
|
bool login_sent() { return login_sent_; }
|
||||||
bool login_attempts() { return login_attempts_; }
|
bool login_attempts() { return login_attempts_; }
|
||||||
|
|
||||||
void GetStreamURL(const QUrl &url);
|
uint GetStreamURL(const QUrl &url, QString &error);
|
||||||
|
|
||||||
CollectionBackend *artists_collection_backend() override { return artists_collection_backend_; }
|
CollectionBackend *artists_collection_backend() override { return artists_collection_backend_; }
|
||||||
CollectionBackend *albums_collection_backend() override { return albums_collection_backend_; }
|
CollectionBackend *albums_collection_backend() override { return albums_collection_backend_; }
|
||||||
@@ -151,7 +151,8 @@ class TidalService : public InternetService {
|
|||||||
void ArtistsUpdateProgressReceived(const int id, const int progress);
|
void ArtistsUpdateProgressReceived(const int id, const int progress);
|
||||||
void AlbumsUpdateProgressReceived(const int id, const int progress);
|
void AlbumsUpdateProgressReceived(const int id, const int progress);
|
||||||
void SongsUpdateProgressReceived(const int id, const int progress);
|
void SongsUpdateProgressReceived(const int id, const int progress);
|
||||||
void HandleStreamURLFinished(const int id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, const QString &error = QString());
|
void HandleStreamURLFailure(const uint id, const QUrl &original_url, const QString &error);
|
||||||
|
void HandleStreamURLSuccess(const uint id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef QPair<QString, QString> Param;
|
typedef QPair<QString, QString> Param;
|
||||||
@@ -241,8 +242,8 @@ class TidalService : public InternetService {
|
|||||||
QString code_verifier_;
|
QString code_verifier_;
|
||||||
QString code_challenge_;
|
QString code_challenge_;
|
||||||
|
|
||||||
int next_stream_url_request_id_;
|
uint next_stream_url_request_id_;
|
||||||
QMap<int, std::shared_ptr<TidalStreamURLRequest>> stream_url_requests_;
|
QMap<uint, std::shared_ptr<TidalStreamURLRequest>> stream_url_requests_;
|
||||||
|
|
||||||
QStringList login_errors_;
|
QStringList login_errors_;
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
#include "tidalbaserequest.h"
|
#include "tidalbaserequest.h"
|
||||||
#include "tidalstreamurlrequest.h"
|
#include "tidalstreamurlrequest.h"
|
||||||
|
|
||||||
TidalStreamURLRequest::TidalStreamURLRequest(TidalService *service, NetworkAccessManager *network, const QUrl &original_url, const int id, QObject *parent)
|
TidalStreamURLRequest::TidalStreamURLRequest(TidalService *service, NetworkAccessManager *network, const QUrl &original_url, const uint id, QObject *parent)
|
||||||
: TidalBaseRequest(service, network, parent),
|
: TidalBaseRequest(service, network, parent),
|
||||||
service_(service),
|
service_(service),
|
||||||
reply_(nullptr),
|
reply_(nullptr),
|
||||||
@@ -72,7 +72,7 @@ void TidalStreamURLRequest::LoginComplete(const bool success, const QString &err
|
|||||||
need_login_ = false;
|
need_login_ = false;
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, error);
|
emit StreamURLFailure(id_, original_url_, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,11 +84,11 @@ void TidalStreamURLRequest::Process() {
|
|||||||
|
|
||||||
if (!authenticated()) {
|
if (!authenticated()) {
|
||||||
if (oauth()) {
|
if (oauth()) {
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, tr("Not authenticated with Tidal."));
|
emit StreamURLFailure(id_, original_url_, tr("Not authenticated with Tidal."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (api_token().isEmpty() || username().isEmpty() || password().isEmpty()) {
|
else if (api_token().isEmpty() || username().isEmpty() || password().isEmpty()) {
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, tr("Missing Tidal API token, username or password."));
|
emit StreamURLFailure(id_, original_url_, tr("Missing Tidal API token, username or password."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
need_login_ = true;
|
need_login_ = true;
|
||||||
@@ -106,7 +106,7 @@ void TidalStreamURLRequest::Cancel() {
|
|||||||
reply_->abort();
|
reply_->abort();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, tr("Cancelled."));
|
emit StreamURLFailure(id_, original_url_, tr("Cancelled."));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -151,38 +151,37 @@ void TidalStreamURLRequest::GetStreamURL() {
|
|||||||
void TidalStreamURLRequest::StreamURLReceived() {
|
void TidalStreamURLRequest::StreamURLReceived() {
|
||||||
|
|
||||||
if (!reply_) return;
|
if (!reply_) return;
|
||||||
QObject::disconnect(reply_, nullptr, this, nullptr);
|
|
||||||
reply_->deleteLater();
|
|
||||||
|
|
||||||
QByteArray data = GetReplyData(reply_, true);
|
QByteArray data = GetReplyData(reply_, true);
|
||||||
|
|
||||||
|
QObject::disconnect(reply_, nullptr, this, nullptr);
|
||||||
|
reply_->deleteLater();
|
||||||
|
reply_ = nullptr;
|
||||||
|
|
||||||
if (data.isEmpty()) {
|
if (data.isEmpty()) {
|
||||||
reply_ = nullptr;
|
|
||||||
if (!authenticated() && login_sent() && tries_ <= 1) {
|
if (!authenticated() && login_sent() && tries_ <= 1) {
|
||||||
need_login_ = true;
|
need_login_ = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
reply_ = nullptr;
|
|
||||||
|
|
||||||
//qLog(Debug) << "Tidal:" << data;
|
|
||||||
|
|
||||||
QJsonObject json_obj = ExtractJsonObj(data);
|
QJsonObject json_obj = ExtractJsonObj(data);
|
||||||
if (json_obj.isEmpty()) {
|
if (json_obj.isEmpty()) {
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!json_obj.contains("trackId")) {
|
if (!json_obj.contains("trackId")) {
|
||||||
Error("Invalid Json reply, stream missing trackId.", json_obj);
|
Error("Invalid Json reply, stream missing trackId.", json_obj);
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int track_id(json_obj["trackId"].toInt());
|
int track_id(json_obj["trackId"].toInt());
|
||||||
if (track_id != song_id_) {
|
if (track_id != song_id_) {
|
||||||
Error("Incorrect track ID returned.", json_obj);
|
Error("Incorrect track ID returned.", json_obj);
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,8 +205,6 @@ void TidalStreamURLRequest::StreamURLReceived() {
|
|||||||
QString manifest(json_obj["manifest"].toString());
|
QString manifest(json_obj["manifest"].toString());
|
||||||
QByteArray data_manifest = QByteArray::fromBase64(manifest.toUtf8());
|
QByteArray data_manifest = QByteArray::fromBase64(manifest.toUtf8());
|
||||||
|
|
||||||
//qLog(Debug) << "Tidal:" << data_manifest;
|
|
||||||
|
|
||||||
QXmlStreamReader xml_reader(data_manifest);
|
QXmlStreamReader xml_reader(data_manifest);
|
||||||
if (xml_reader.readNextStartElement()) {
|
if (xml_reader.readNextStartElement()) {
|
||||||
QUrl url;
|
QUrl url;
|
||||||
@@ -220,13 +217,23 @@ void TidalStreamURLRequest::StreamURLReceived() {
|
|||||||
|
|
||||||
json_obj = ExtractJsonObj(data_manifest);
|
json_obj = ExtractJsonObj(data_manifest);
|
||||||
if (json_obj.isEmpty()) {
|
if (json_obj.isEmpty()) {
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (json_obj.contains("encryptionType") && json_obj.contains("keyId")) {
|
||||||
|
QString encryption_type = json_obj["encryptionType"].toString();
|
||||||
|
QString key_id = json_obj["encryptionType"].toString();
|
||||||
|
if (!encryption_type.isEmpty() && !key_id.isEmpty()) {
|
||||||
|
Error(tr("Received URL with %1 encrypted stream from Tidal. Strawberry does not currently support encrypted streams.").arg(encryption_type));
|
||||||
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!json_obj.contains("mimeType")) {
|
if (!json_obj.contains("mimeType")) {
|
||||||
Error("Invalid Json reply, stream url reply manifest is missing mimeType.", json_obj);
|
Error("Invalid Json reply, stream url reply manifest is missing mimeType.", json_obj);
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +256,7 @@ void TidalStreamURLRequest::StreamURLReceived() {
|
|||||||
QJsonValue json_urls = json_obj["urls"];
|
QJsonValue json_urls = json_obj["urls"];
|
||||||
if (!json_urls.isArray()) {
|
if (!json_urls.isArray()) {
|
||||||
Error("Invalid Json reply, urls is not an array.", json_urls);
|
Error("Invalid Json reply, urls is not an array.", json_urls);
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QJsonArray json_array_urls = json_urls.toArray();
|
QJsonArray json_array_urls = json_urls.toArray();
|
||||||
@@ -268,13 +275,32 @@ void TidalStreamURLRequest::StreamURLReceived() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (json_obj.contains("encryptionKey")) {
|
||||||
|
QString encryption_key = json_obj["encryptionKey"].toString();
|
||||||
|
if (!encryption_key.isEmpty()) {
|
||||||
|
Error(tr("Received URL with encrypted stream from Tidal. Strawberry does not currently support encrypted streams."));
|
||||||
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_obj.contains("securityType") && json_obj.contains("securityToken")) {
|
||||||
|
QString security_type = json_obj["securityType"].toString();
|
||||||
|
QString security_token = json_obj["securityToken"].toString();
|
||||||
|
if (!security_type.isEmpty() && !security_token.isEmpty()) {
|
||||||
|
Error(tr("Received URL with encrypted stream from Tidal. Strawberry does not currently support encrypted streams."));
|
||||||
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (urls.isEmpty()) {
|
if (urls.isEmpty()) {
|
||||||
Error("Missing stream urls.", json_obj);
|
Error("Missing stream urls.", json_obj);
|
||||||
emit StreamURLFinished(id_, original_url_, original_url_, filetype, -1, -1, -1, errors_.first());
|
emit StreamURLFailure(id_, original_url_, errors_.first());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit StreamURLFinished(id_, original_url_, urls.first(), filetype, -1, -1, -1);
|
emit StreamURLSuccess(id_, original_url_, urls.first(), filetype);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class TidalStreamURLRequest : public TidalBaseRequest {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TidalStreamURLRequest(TidalService *service, NetworkAccessManager *network, const QUrl &original_url, const int id, QObject *parent = nullptr);
|
explicit TidalStreamURLRequest(TidalService *service, NetworkAccessManager *network, const QUrl &original_url, const uint id, QObject *parent = nullptr);
|
||||||
~TidalStreamURLRequest() override;
|
~TidalStreamURLRequest() override;
|
||||||
|
|
||||||
void GetStreamURL();
|
void GetStreamURL();
|
||||||
@@ -58,7 +58,8 @@ class TidalStreamURLRequest : public TidalBaseRequest {
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void TryLogin();
|
void TryLogin();
|
||||||
void StreamURLFinished(int id, QUrl original_url, QUrl stream_url, Song::FileType filetype, int samplerate, int bit_depth, qint64 duration, QString error = QString());
|
void StreamURLFailure(uint id, QUrl original_url, QString error);
|
||||||
|
void StreamURLSuccess(uint id, QUrl original_url, QUrl stream_url, Song::FileType filetype, int samplerate = -1, int bit_depth = -1, qint64 duration = -1);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void StreamURLReceived();
|
void StreamURLReceived();
|
||||||
@@ -72,7 +73,7 @@ class TidalStreamURLRequest : public TidalBaseRequest {
|
|||||||
TidalService *service_;
|
TidalService *service_;
|
||||||
QNetworkReply *reply_;
|
QNetworkReply *reply_;
|
||||||
QUrl original_url_;
|
QUrl original_url_;
|
||||||
int id_;
|
uint id_;
|
||||||
int song_id_;
|
int song_id_;
|
||||||
int tries_;
|
int tries_;
|
||||||
bool need_login_;
|
bool need_login_;
|
||||||
|
|||||||
@@ -32,38 +32,53 @@
|
|||||||
TidalUrlHandler::TidalUrlHandler(Application *app, TidalService *service)
|
TidalUrlHandler::TidalUrlHandler(Application *app, TidalService *service)
|
||||||
: UrlHandler(service),
|
: UrlHandler(service),
|
||||||
app_(app),
|
app_(app),
|
||||||
service_(service),
|
service_(service) {
|
||||||
task_id_(-1) {
|
|
||||||
|
|
||||||
QObject::connect(service, &TidalService::StreamURLFinished, this, &TidalUrlHandler::GetStreamURLFinished);
|
QObject::connect(service, &TidalService::StreamURLFailure, this, &TidalUrlHandler::GetStreamURLFailure);
|
||||||
|
QObject::connect(service, &TidalService::StreamURLSuccess, this, &TidalUrlHandler::GetStreamURLSuccess);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UrlHandler::LoadResult TidalUrlHandler::StartLoading(const QUrl &url) {
|
UrlHandler::LoadResult TidalUrlHandler::StartLoading(const QUrl &url) {
|
||||||
|
|
||||||
|
Request req;
|
||||||
|
req.task_id = app_->task_manager()->StartTask(QString("Loading %1 stream...").arg(url.scheme()));
|
||||||
|
QString error;
|
||||||
|
req.id = service_->GetStreamURL(url, error);
|
||||||
|
if (req.id == 0) {
|
||||||
|
CancelTask(req.task_id);
|
||||||
|
return LoadResult(url, LoadResult::Error, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
requests_.insert(req.id, req);
|
||||||
|
|
||||||
LoadResult ret(url);
|
LoadResult ret(url);
|
||||||
if (task_id_ != -1) return ret;
|
|
||||||
task_id_ = app_->task_manager()->StartTask(QString("Loading %1 stream...").arg(url.scheme()));
|
|
||||||
service_->GetStreamURL(url);
|
|
||||||
ret.type_ = LoadResult::WillLoadAsynchronously;
|
ret.type_ = LoadResult::WillLoadAsynchronously;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TidalUrlHandler::GetStreamURLFinished(const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, const QString &error) {
|
void TidalUrlHandler::GetStreamURLFailure(const uint id, const QUrl &original_url, const QString &error) {
|
||||||
|
|
||||||
if (task_id_ == -1) return;
|
if (!requests_.contains(id)) return;
|
||||||
CancelTask();
|
Request req = requests_.take(id);
|
||||||
if (error.isEmpty()) {
|
CancelTask(req.task_id);
|
||||||
emit AsyncLoadComplete(LoadResult(original_url, LoadResult::TrackAvailable, stream_url, filetype, samplerate, bit_depth, duration));
|
|
||||||
}
|
emit AsyncLoadComplete(LoadResult(original_url, LoadResult::Error, error));
|
||||||
else {
|
|
||||||
emit AsyncLoadComplete(LoadResult(original_url, LoadResult::Error, error));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TidalUrlHandler::CancelTask() {
|
void TidalUrlHandler::GetStreamURLSuccess(const uint id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration) {
|
||||||
app_->task_manager()->SetTaskFinished(task_id_);
|
|
||||||
task_id_ = -1;
|
if (!requests_.contains(id)) return;
|
||||||
|
Request req = requests_.take(id);
|
||||||
|
CancelTask(req.task_id);
|
||||||
|
|
||||||
|
emit AsyncLoadComplete(LoadResult(original_url, LoadResult::TrackAvailable, stream_url, filetype, samplerate, bit_depth, duration));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TidalUrlHandler::CancelTask(const int task_id) {
|
||||||
|
app_->task_manager()->SetTaskFinished(task_id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
@@ -42,15 +43,22 @@ class TidalUrlHandler : public UrlHandler {
|
|||||||
QString scheme() const override { return service_->url_scheme(); }
|
QString scheme() const override { return service_->url_scheme(); }
|
||||||
LoadResult StartLoading(const QUrl &url) override;
|
LoadResult StartLoading(const QUrl &url) override;
|
||||||
|
|
||||||
void CancelTask();
|
private:
|
||||||
|
void CancelTask(const int task_id);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void GetStreamURLFinished(const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, const QString &error = QString());
|
void GetStreamURLFailure(const uint id, const QUrl &original_url, const QString &error);
|
||||||
|
void GetStreamURLSuccess(const uint id, const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Request {
|
||||||
|
Request() : id(0), task_id(-1) {}
|
||||||
|
uint id;
|
||||||
|
int task_id;
|
||||||
|
};
|
||||||
Application *app_;
|
Application *app_;
|
||||||
TidalService *service_;
|
TidalService *service_;
|
||||||
int task_id_;
|
QMap<uint, Request> requests_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user