mirror of
https://github.com/strawberrymusicplayer/strawberry
synced 2024-12-28 01:01:21 +01:00
More Tidal fixes
This commit is contained in:
parent
c77cb002f3
commit
8a57356f64
@ -9,6 +9,10 @@ Unreleased:
|
||||
* Fixed bug in pipeline not setting url
|
||||
* Fixed bug setting wrong temporary metadata
|
||||
* Removed device module from windows, since it's not implemented for windows
|
||||
* Added support for both ALSA hw and plughw
|
||||
* Added option to change url stream scheme for Tidal
|
||||
* Added encoding of Tidal token in the source code
|
||||
* Added encoding of Tidal password in the configuration
|
||||
|
||||
Version 0.3.1:
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -690,21 +691,6 @@ bool IsLaptop() {
|
||||
|
||||
}
|
||||
|
||||
QString SystemLanguageName() {
|
||||
|
||||
#if QT_VERSION >= 0x040800
|
||||
QString system_language = QLocale::system().uiLanguages().empty() ? QLocale::system().name() : QLocale::system().uiLanguages().first();
|
||||
// uiLanguages returns strings with "-" as separators for language/region;
|
||||
// however QTranslator needs "_" separators
|
||||
system_language.replace("-", "_");
|
||||
#else
|
||||
QString system_language = QLocale::system().name();
|
||||
#endif
|
||||
|
||||
return system_language;
|
||||
|
||||
}
|
||||
|
||||
bool UrlOnSameDriveAsStrawberry(const QUrl &url) {
|
||||
|
||||
if (url.scheme() != "file") return false;
|
||||
@ -723,18 +709,13 @@ bool UrlOnSameDriveAsStrawberry(const QUrl &url) {
|
||||
}
|
||||
|
||||
QUrl GetRelativePathToStrawberryBin(const QUrl &url) {
|
||||
|
||||
QDir appPath(QCoreApplication::applicationDirPath());
|
||||
return QUrl::fromLocalFile(appPath.relativeFilePath(url.toLocalFile()));
|
||||
|
||||
}
|
||||
|
||||
QString PathWithoutFilenameExtension(const QString &filename) {
|
||||
|
||||
if (filename.section('/', -1, -1).contains('.'))
|
||||
return filename.section('.', 0, -2);
|
||||
if (filename.section('/', -1, -1).contains('.')) return filename.section('.', 0, -2);
|
||||
return filename;
|
||||
|
||||
}
|
||||
|
||||
QString FiddleFileExtension(const QString &filename, const QString &new_extension) {
|
||||
@ -786,6 +767,28 @@ void CheckPortable() {
|
||||
|
||||
}
|
||||
|
||||
QString GetRandomStringWithChars(const int len) {
|
||||
const QString UseCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
||||
return GetRandomString(len, UseCharacters);
|
||||
}
|
||||
|
||||
QString GetRandomStringWithCharsAndNumbers(const int len) {
|
||||
const QString UseCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
||||
return GetRandomString(len, UseCharacters);
|
||||
}
|
||||
|
||||
QString GetRandomString(const int len, const QString &UseCharacters) {
|
||||
|
||||
QString randstr;
|
||||
for(int i=0 ; i < len ; ++i) {
|
||||
int index = qrand() % UseCharacters.length();
|
||||
QChar nextchar = UseCharacters.at(index);
|
||||
randstr.append(nextchar);
|
||||
}
|
||||
return randstr;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Utilities
|
||||
|
||||
ScopedWCharArray::ScopedWCharArray(const QString &str)
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -149,7 +150,10 @@ int GetThreadId();
|
||||
// Returns true if this machine has a battery.
|
||||
bool IsLaptop();
|
||||
|
||||
QString SystemLanguageName();
|
||||
QString GetRandomStringWithChars(const int len);
|
||||
QString GetRandomStringWithCharsAndNumbers(const int len);
|
||||
QString GetRandomString(const int len, const QString &UseCharacters);
|
||||
|
||||
}
|
||||
|
||||
class ScopedWCharArray {
|
||||
|
@ -75,7 +75,9 @@ void TidalSettingsPage::Load() {
|
||||
|
||||
s.beginGroup(kSettingsGroup);
|
||||
ui_->username->setText(s.value("username").toString());
|
||||
ui_->password->setText(s.value("password").toString());
|
||||
QByteArray password = s.value("password").toByteArray();
|
||||
if (password.isEmpty()) ui_->password->setText("");
|
||||
else ui_->password->setText(QByteArray::fromBase64(password));
|
||||
dialog()->ComboBoxLoadFromSettings(s, ui_->combobox_quality, "quality", "HIGH");
|
||||
ui_->spinbox_searchdelay->setValue(s.value("searchdelay", 1500).toInt());
|
||||
ui_->spinbox_albumssearchlimit->setValue(s.value("albumssearchlimit", 100).toInt());
|
||||
@ -94,7 +96,7 @@ void TidalSettingsPage::Save() {
|
||||
QSettings s;
|
||||
s.beginGroup(kSettingsGroup);
|
||||
s.setValue("username", ui_->username->text());
|
||||
s.setValue("password", ui_->password->text());
|
||||
s.setValue("password", ui_->password->text().toUtf8().toBase64());
|
||||
s.setValue("quality", ui_->combobox_quality->itemData(ui_->combobox_quality->currentIndex()));
|
||||
s.setValue("searchdelay", ui_->spinbox_searchdelay->value());
|
||||
s.setValue("albumssearchlimit", ui_->spinbox_albumssearchlimit->value());
|
||||
|
@ -49,7 +49,7 @@ class TidalSettingsPage : public SettingsPage {
|
||||
bool eventFilter(QObject *object, QEvent *event);
|
||||
|
||||
signals:
|
||||
void Login(const QString &username, const QString &password, const int search_id = 0);
|
||||
void Login(const QString &username, const QString &password);
|
||||
|
||||
private slots:
|
||||
void LoginClicked();
|
||||
|
@ -59,7 +59,7 @@ const Song::Source TidalService::kSource = Song::Source_Tidal;
|
||||
const char *TidalService::kApiUrl = "https://listen.tidal.com/v1";
|
||||
const char *TidalService::kAuthUrl = "https://listen.tidal.com/v1/login/username";
|
||||
const char *TidalService::kResourcesUrl = "http://resources.tidal.com";
|
||||
const char *TidalService::kApiToken = "P5Xbeo5LFvESeDy6";
|
||||
const char *TidalService::kApiTokenB64 = "UDVYYmVvNUxGdkVTZUR5Ng==";
|
||||
const int TidalService::kLoginAttempts = 2;
|
||||
|
||||
typedef QPair<QString, QString> Param;
|
||||
@ -76,7 +76,11 @@ TidalService::TidalService(Application *app, InternetModel *parent)
|
||||
user_id_(0),
|
||||
pending_search_id_(0),
|
||||
next_pending_search_id_(1),
|
||||
login_sent_(false)
|
||||
search_id_(0),
|
||||
albums_requested_(0),
|
||||
albums_received_(0),
|
||||
login_sent_(false),
|
||||
login_attempts_(0)
|
||||
{
|
||||
|
||||
timer_searchdelay_->setSingleShot(true);
|
||||
@ -103,7 +107,7 @@ void TidalService::ReloadSettings() {
|
||||
QSettings s;
|
||||
s.beginGroup(TidalSettingsPage::kSettingsGroup);
|
||||
username_ = s.value("username").toString();
|
||||
password_ = s.value("password").toString();
|
||||
password_ = QByteArray::fromBase64(s.value("password").toByteArray());
|
||||
quality_ = s.value("quality").toString();
|
||||
searchdelay_ = s.value("searchdelay", 1500).toInt();
|
||||
albumssearchlimit_ = s.value("albumssearchlimit", 100).toInt();
|
||||
@ -123,6 +127,7 @@ void TidalService::LoadSessionID() {
|
||||
session_id_ = s.value("session_id").toString();
|
||||
user_id_ = s.value("user_id").toInt();
|
||||
country_code_ = s.value("country_code").toString();
|
||||
clientuniquekey_ = Utilities::GetRandomStringWithChars(12);
|
||||
s.endGroup();
|
||||
|
||||
}
|
||||
@ -144,7 +149,10 @@ void TidalService::SendLogin(const QString &username, const QString &password) {
|
||||
typedef QPair<QByteArray, QByteArray> EncodedArg;
|
||||
typedef QList<EncodedArg> EncodedArgList;
|
||||
|
||||
ArgList args = ArgList() <<Arg("token", kApiToken) << Arg("username", username) << Arg("password", password) << Arg("clientVersion", "2.2.1--7");
|
||||
ArgList args = ArgList() << Arg("token", QByteArray::fromBase64(kApiTokenB64))
|
||||
<< Arg("username", username)
|
||||
<< Arg("password", password)
|
||||
<< Arg("clientUniqueKey", clientuniquekey_);
|
||||
|
||||
QStringList query_items;
|
||||
QUrlQuery url_query;
|
||||
@ -158,6 +166,7 @@ void TidalService::SendLogin(const QString &username, const QString &password) {
|
||||
QNetworkRequest req(url);
|
||||
|
||||
req.setRawHeader("Origin", "http://listen.tidal.com");
|
||||
req.setRawHeader("X-Tidal-Token", QByteArray::fromBase64(kApiTokenB64));
|
||||
QNetworkReply *reply = network_->post(req, url_query.toString(QUrl::FullyEncoded).toUtf8());
|
||||
NewClosure(reply, SIGNAL(finished()), this, SLOT(HandleAuthReply(QNetworkReply*)), reply);
|
||||
|
||||
@ -244,6 +253,7 @@ void TidalService::HandleAuthReply(QNetworkReply *reply) {
|
||||
country_code_ = json_obj["countryCode"].toString();
|
||||
session_id_ = json_obj["sessionId"].toString();
|
||||
user_id_ = json_obj["userId"].toInt();
|
||||
clientuniquekey_ = Utilities::GetRandomStringWithChars(12);
|
||||
|
||||
QSettings s;
|
||||
s.beginGroup(TidalSettingsPage::kSettingsGroup);
|
||||
@ -307,9 +317,11 @@ QNetworkReply *TidalService::CreateRequest(const QString &ressource_name, const
|
||||
QUrl url(kApiUrl + QString("/") + ressource_name);
|
||||
url.setQuery(url_query);
|
||||
QNetworkRequest req(url);
|
||||
req.setRawHeader("Origin", "http://listen.tidal.com");
|
||||
req.setRawHeader("X-Tidal-SessionId", session_id_.toUtf8());
|
||||
QNetworkReply *reply = network_->get(req);
|
||||
|
||||
//qLog(Debug) << "Tidal: Sending request" << url;
|
||||
qLog(Debug) << "Tidal: Sending request" << url;
|
||||
|
||||
return reply;
|
||||
|
||||
@ -611,11 +623,7 @@ void TidalService::SearchFinished(QNetworkReply *reply, int id) {
|
||||
void TidalService::GetAlbum(const int album_id) {
|
||||
|
||||
QList<Param> parameters;
|
||||
parameters << Param("token", session_id_)
|
||||
<< Param("soundQuality", quality_);
|
||||
|
||||
QNetworkReply *reply = CreateRequest(QString("albums/%1/tracks").arg(album_id), parameters);
|
||||
|
||||
NewClosure(reply, SIGNAL(finished()), this, SLOT(GetAlbumFinished(QNetworkReply*, int, int)), reply, search_id_, album_id);
|
||||
|
||||
}
|
||||
@ -784,8 +792,7 @@ void TidalService::GetStreamURL(const QUrl &url) {
|
||||
requests_song_.insert(song_id, url);
|
||||
|
||||
QList<Param> parameters;
|
||||
parameters << Param("token", session_id_)
|
||||
<< Param("soundQuality", quality_);
|
||||
parameters << Param("soundQuality", quality_);
|
||||
|
||||
QNetworkReply *reply = CreateRequest(QString("tracks/%1/streamUrl").arg(song_id), parameters);
|
||||
|
||||
|
@ -103,7 +103,7 @@ class TidalService : public InternetService {
|
||||
static const char *kApiUrl;
|
||||
static const char *kAuthUrl;
|
||||
static const char *kResourcesUrl;
|
||||
static const char *kApiToken;
|
||||
static const char *kApiTokenB64;
|
||||
|
||||
NetworkAccessManager *network_;
|
||||
TidalUrlHandler *url_handler_;
|
||||
@ -121,6 +121,7 @@ class TidalService : public InternetService {
|
||||
QString session_id_;
|
||||
quint64 user_id_;
|
||||
QString country_code_;
|
||||
QString clientuniquekey_;
|
||||
|
||||
int pending_search_id_;
|
||||
int next_pending_search_id_;
|
||||
|
Loading…
Reference in New Issue
Block a user