Disable automatic conversions from 8-bit strings
This commit is contained in:
@@ -55,31 +55,31 @@ SubsonicBaseRequest::SubsonicBaseRequest(SubsonicService *service, QObject *pare
|
||||
QUrl SubsonicBaseRequest::CreateUrl(const QUrl &server_url, const SubsonicSettingsPage::AuthMethod auth_method, const QString &username, const QString &password, const QString &ressource_name, const ParamList ¶ms_provided) {
|
||||
|
||||
ParamList params = ParamList() << params_provided
|
||||
<< Param("c", SubsonicService::kClientName)
|
||||
<< Param("v", SubsonicService::kApiVersion)
|
||||
<< Param("f", "json")
|
||||
<< Param("u", username);
|
||||
<< Param(QStringLiteral("c"), QLatin1String(SubsonicService::kClientName))
|
||||
<< Param(QStringLiteral("v"), QLatin1String(SubsonicService::kApiVersion))
|
||||
<< Param(QStringLiteral("f"), QStringLiteral("json"))
|
||||
<< Param(QStringLiteral("u"), username);
|
||||
|
||||
if (auth_method == SubsonicSettingsPage::AuthMethod::Hex) {
|
||||
params << Param("p", QString("enc:" + password.toUtf8().toHex()));
|
||||
params << Param(QStringLiteral("p"), QStringLiteral("enc:") + QString::fromUtf8(password.toUtf8().toHex()));
|
||||
}
|
||||
else {
|
||||
const QString salt = Utilities::CryptographicRandomString(20);
|
||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||
md5.addData(password.toUtf8());
|
||||
md5.addData(salt.toUtf8());
|
||||
params << Param("s", salt);
|
||||
params << Param("t", md5.result().toHex());
|
||||
params << Param(QStringLiteral("s"), salt);
|
||||
params << Param(QStringLiteral("t"), QString::fromUtf8(md5.result().toHex()));
|
||||
}
|
||||
|
||||
QUrlQuery url_query;
|
||||
for (const Param ¶m : params) {
|
||||
url_query.addQueryItem(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second));
|
||||
url_query.addQueryItem(QString::fromLatin1(QUrl::toPercentEncoding(param.first)), QString::fromLatin1(QUrl::toPercentEncoding(param.second)));
|
||||
}
|
||||
|
||||
QUrl url(server_url);
|
||||
|
||||
if (!url.path().isEmpty() && url.path().right(1) == "/") {
|
||||
if (!url.path().isEmpty() && url.path().right(1) == QStringLiteral("/")) {
|
||||
url.setPath(url.path() + QStringLiteral("rest/") + ressource_name + QStringLiteral(".view"));
|
||||
}
|
||||
else {
|
||||
@@ -97,13 +97,13 @@ QNetworkReply *SubsonicBaseRequest::CreateGetRequest(const QString &ressource_na
|
||||
QUrl url = CreateUrl(server_url(), auth_method(), username(), password(), ressource_name, params_provided);
|
||||
QNetworkRequest req(url);
|
||||
|
||||
if (url.scheme() == "https" && !verify_certificate()) {
|
||||
if (url.scheme() == QStringLiteral("https") && !verify_certificate()) {
|
||||
QSslConfiguration sslconfig = QSslConfiguration::defaultConfiguration();
|
||||
sslconfig.setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||
req.setSslConfiguration(sslconfig);
|
||||
}
|
||||
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/x-www-form-urlencoded"));
|
||||
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
@@ -222,7 +222,7 @@ QString SubsonicBaseRequest::ErrorsToHTML(const QStringList &errors) {
|
||||
|
||||
QString error_html;
|
||||
for (const QString &error : errors) {
|
||||
error_html += error + "<br />";
|
||||
error_html += error + QStringLiteral("<br />");
|
||||
}
|
||||
return error_html;
|
||||
|
||||
|
||||
@@ -50,9 +50,11 @@
|
||||
#include "subsonicbaserequest.h"
|
||||
#include "subsonicrequest.h"
|
||||
|
||||
const int SubsonicRequest::kMaxConcurrentAlbumsRequests = 3;
|
||||
const int SubsonicRequest::kMaxConcurrentAlbumSongsRequests = 3;
|
||||
const int SubsonicRequest::kMaxConcurrentAlbumCoverRequests = 1;
|
||||
namespace {
|
||||
constexpr int kMaxConcurrentAlbumsRequests = 3;
|
||||
constexpr int kMaxConcurrentAlbumSongsRequests = 3;
|
||||
constexpr int kMaxConcurrentAlbumCoverRequests = 1;
|
||||
} // namespace
|
||||
|
||||
SubsonicRequest::SubsonicRequest(SubsonicService *service, SubsonicUrlHandler *url_handler, Application *app, QObject *parent)
|
||||
: SubsonicBaseRequest(service, parent),
|
||||
@@ -145,9 +147,9 @@ void SubsonicRequest::FlushAlbumsRequests() {
|
||||
Request request = albums_requests_queue_.dequeue();
|
||||
++albums_requests_active_;
|
||||
|
||||
ParamList params = ParamList() << Param("type", "alphabeticalByName");
|
||||
if (request.size > 0) params << Param("size", QString::number(request.size));
|
||||
if (request.offset > 0) params << Param("offset", QString::number(request.offset));
|
||||
ParamList params = ParamList() << Param(QStringLiteral("type"), QStringLiteral("alphabeticalByName"));
|
||||
if (request.size > 0) params << Param(QStringLiteral("size"), QString::number(request.size));
|
||||
if (request.offset > 0) params << Param(QStringLiteral("offset"), QString::number(request.offset));
|
||||
|
||||
QNetworkReply *reply = CreateGetRequest(QStringLiteral("getAlbumList2"), params);
|
||||
replies_ << reply;
|
||||
@@ -341,7 +343,7 @@ void SubsonicRequest::FlushAlbumSongsRequests() {
|
||||
|
||||
Request request = album_songs_requests_queue_.dequeue();
|
||||
++album_songs_requests_active_;
|
||||
QNetworkReply *reply = CreateGetRequest(QStringLiteral("getAlbum"), ParamList() << Param("id", request.album_id));
|
||||
QNetworkReply *reply = CreateGetRequest(QStringLiteral("getAlbum"), ParamList() << Param(QStringLiteral("id"), request.album_id));
|
||||
replies_ << reply;
|
||||
QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, request]() { AlbumSongsReplyReceived(reply, request.artist_id, request.album_id, request.album_artist); });
|
||||
timeouts_->AddReply(reply);
|
||||
@@ -631,7 +633,7 @@ QString SubsonicRequest::ParseSong(Song &song, const QJsonObject &json_obj, cons
|
||||
cover_url = cover_urls_[cover_id];
|
||||
}
|
||||
else {
|
||||
cover_url = CreateUrl(server_url(), auth_method(), username(), password(), QStringLiteral("getCoverArt"), ParamList() << Param("id", cover_id));
|
||||
cover_url = CreateUrl(server_url(), auth_method(), username(), password(), QStringLiteral("getCoverArt"), ParamList() << Param(QStringLiteral("id"), cover_id));
|
||||
cover_urls_.insert(cover_id, cover_url);
|
||||
}
|
||||
}
|
||||
@@ -639,7 +641,7 @@ QString SubsonicRequest::ParseSong(Song &song, const QJsonObject &json_obj, cons
|
||||
Song::FileType filetype(Song::FileType::Stream);
|
||||
if (!mimetype.isEmpty()) {
|
||||
QMimeDatabase mimedb;
|
||||
QStringList suffixes = mimedb.mimeTypeForName(mimetype.toUtf8()).suffixes();
|
||||
QStringList suffixes = mimedb.mimeTypeForName(mimetype).suffixes();
|
||||
for (const QString &suffix : suffixes) {
|
||||
filetype = Song::FiletypeByExtension(suffix);
|
||||
if (filetype != Song::FileType::Unknown) break;
|
||||
@@ -721,7 +723,7 @@ void SubsonicRequest::AddAlbumCoverRequest(const Song &song) {
|
||||
request.album_id = song.album_id();
|
||||
request.cover_id = cover_id;
|
||||
request.url = cover_url;
|
||||
request.filename = cover_path + "/" + cover_id + ".jpg";
|
||||
request.filename = cover_path + QLatin1Char('/') + cover_id + QStringLiteral(".jpg");
|
||||
if (request.filename.isEmpty()) return;
|
||||
|
||||
album_covers_requests_sent_.insert(cover_id, song.song_id());
|
||||
@@ -799,8 +801,8 @@ void SubsonicRequest::AlbumCoverReceived(QNetworkReply *reply, const AlbumCoverR
|
||||
}
|
||||
|
||||
QString mimetype = reply->header(QNetworkRequest::ContentTypeHeader).toString();
|
||||
if (mimetype.contains(';')) {
|
||||
mimetype = mimetype.left(mimetype.indexOf(';'));
|
||||
if (mimetype.contains(QLatin1Char(';'))) {
|
||||
mimetype = mimetype.left(mimetype.indexOf(QLatin1Char(';')));
|
||||
}
|
||||
if (!ImageUtils::SupportedImageMimeTypes().contains(mimetype, Qt::CaseInsensitive) && !ImageUtils::SupportedImageFormats().contains(mimetype, Qt::CaseInsensitive)) {
|
||||
Error(QStringLiteral("Unsupported mimetype for image reader %1 for %2").arg(mimetype, request.url.toString()));
|
||||
|
||||
@@ -110,11 +110,6 @@ class SubsonicRequest : public SubsonicBaseRequest {
|
||||
static void Warn(const QString &error, const QVariant &debug = QVariant());
|
||||
void Error(const QString &error, const QVariant &debug = QVariant()) override;
|
||||
|
||||
static const int kMaxConcurrentAlbumsRequests;
|
||||
static const int kMaxConcurrentArtistAlbumsRequests;
|
||||
static const int kMaxConcurrentAlbumSongsRequests;
|
||||
static const int kMaxConcurrentAlbumCoverRequests;
|
||||
|
||||
SubsonicService *service_;
|
||||
SubsonicUrlHandler *url_handler_;
|
||||
Application *app_;
|
||||
|
||||
@@ -35,7 +35,9 @@
|
||||
#include "subsonicbaserequest.h"
|
||||
#include "subsonicscrobblerequest.h"
|
||||
|
||||
const int SubsonicScrobbleRequest::kMaxConcurrentScrobbleRequests = 3;
|
||||
namespace {
|
||||
constexpr int kMaxConcurrentScrobbleRequests = 3;
|
||||
}
|
||||
|
||||
SubsonicScrobbleRequest::SubsonicScrobbleRequest(SubsonicService *service, SubsonicUrlHandler *url_handler, Application *app, QObject *parent)
|
||||
: SubsonicBaseRequest(service, parent),
|
||||
@@ -73,9 +75,9 @@ void SubsonicScrobbleRequest::FlushScrobbleRequests() {
|
||||
Request request = scrobble_requests_queue_.dequeue();
|
||||
++scrobble_requests_active_;
|
||||
|
||||
ParamList params = ParamList() << Param("id", request.song_id)
|
||||
<< Param("submission", QVariant(request.submission).toString())
|
||||
<< Param("time", QVariant(request.time_ms).toString());
|
||||
ParamList params = ParamList() << Param(QStringLiteral("id"), request.song_id)
|
||||
<< Param(QStringLiteral("submission"), QVariant(request.submission).toString())
|
||||
<< Param(QStringLiteral("time"), QVariant(request.time_ms).toString());
|
||||
|
||||
QNetworkReply *reply = CreateGetRequest(QStringLiteral("scrobble"), params);
|
||||
replies_ << reply;
|
||||
|
||||
@@ -69,8 +69,6 @@ class SubsonicScrobbleRequest : public SubsonicBaseRequest {
|
||||
|
||||
void Error(const QString &error, const QVariant &debug = QVariant()) override;
|
||||
|
||||
static const int kMaxConcurrentScrobbleRequests;
|
||||
|
||||
SubsonicService *service_;
|
||||
SubsonicUrlHandler *url_handler_;
|
||||
Application *app_;
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "core/player.h"
|
||||
#include "core/database.h"
|
||||
#include "core/song.h"
|
||||
#include "core/settings.h"
|
||||
#include "utilities/randutils.h"
|
||||
#include "collection/collectionbackend.h"
|
||||
#include "collection/collectionmodel.h"
|
||||
@@ -64,12 +65,15 @@ using std::make_shared;
|
||||
const Song::Source SubsonicService::kSource = Song::Source::Subsonic;
|
||||
const char *SubsonicService::kClientName = "Strawberry";
|
||||
const char *SubsonicService::kApiVersion = "1.11.0";
|
||||
const char *SubsonicService::kSongsTable = "subsonic_songs";
|
||||
const char *SubsonicService::kSongsFtsTable = "subsonic_songs_fts";
|
||||
const int SubsonicService::kMaxRedirects = 3;
|
||||
|
||||
namespace {
|
||||
constexpr char kSongsTable[] = "subsonic_songs";
|
||||
constexpr char kSongsFtsTable[] = "subsonic_songs_fts";
|
||||
constexpr int kMaxRedirects = 3;
|
||||
} // namespace
|
||||
|
||||
SubsonicService::SubsonicService(Application *app, QObject *parent)
|
||||
: InternetService(Song::Source::Subsonic, QStringLiteral("Subsonic"), QStringLiteral("subsonic"), SubsonicSettingsPage::kSettingsGroup, SettingsDialog::Page::Subsonic, app, parent),
|
||||
: InternetService(Song::Source::Subsonic, QStringLiteral("Subsonic"), QStringLiteral("subsonic"), QLatin1String(SubsonicSettingsPage::kSettingsGroup), SettingsDialog::Page::Subsonic, app, parent),
|
||||
app_(app),
|
||||
url_handler_(new SubsonicUrlHandler(app, this)),
|
||||
collection_backend_(nullptr),
|
||||
@@ -85,9 +89,10 @@ SubsonicService::SubsonicService(Application *app, QObject *parent)
|
||||
|
||||
// Backend
|
||||
|
||||
|
||||
collection_backend_ = make_shared<CollectionBackend>();
|
||||
collection_backend_->moveToThread(app_->database()->thread());
|
||||
collection_backend_->Init(app_->database(), app->task_manager(), Song::Source::Subsonic, kSongsTable, kSongsFtsTable);
|
||||
collection_backend_->Init(app_->database(), app->task_manager(), Song::Source::Subsonic, QLatin1String(kSongsTable), QLatin1String(kSongsFtsTable));
|
||||
|
||||
// Model
|
||||
|
||||
@@ -126,7 +131,7 @@ void SubsonicService::ShowConfig() {
|
||||
|
||||
void SubsonicService::ReloadSettings() {
|
||||
|
||||
QSettings s;
|
||||
Settings s;
|
||||
s.beginGroup(SubsonicSettingsPage::kSettingsGroup);
|
||||
|
||||
server_url_ = s.value("url").toUrl();
|
||||
@@ -159,30 +164,30 @@ void SubsonicService::SendPingWithCredentials(QUrl url, const QString &username,
|
||||
using Param = QPair<QString, QString>;
|
||||
using ParamList = QList<Param>;
|
||||
|
||||
ParamList params = ParamList() << Param("c", kClientName)
|
||||
<< Param("v", kApiVersion)
|
||||
<< Param("f", "json")
|
||||
<< Param("u", username);
|
||||
ParamList params = ParamList() << Param(QStringLiteral("c"), QLatin1String(kClientName))
|
||||
<< Param(QStringLiteral("v"), QLatin1String(kApiVersion))
|
||||
<< Param(QStringLiteral("f"), QStringLiteral("json"))
|
||||
<< Param(QStringLiteral("u"), username);
|
||||
|
||||
if (auth_method == SubsonicSettingsPage::AuthMethod::Hex) {
|
||||
params << Param("p", QString("enc:" + password.toUtf8().toHex()));
|
||||
params << Param(QStringLiteral("p"), QStringLiteral("enc:") + QString::fromLatin1(password.toUtf8().toHex()));
|
||||
}
|
||||
else {
|
||||
const QString salt = Utilities::CryptographicRandomString(20);
|
||||
QCryptographicHash md5(QCryptographicHash::Md5);
|
||||
md5.addData(password.toUtf8());
|
||||
md5.addData(salt.toUtf8());
|
||||
params << Param("s", salt);
|
||||
params << Param("t", md5.result().toHex());
|
||||
params << Param(QStringLiteral("s"), salt);
|
||||
params << Param(QStringLiteral("t"), QString::fromLatin1(md5.result().toHex()));
|
||||
}
|
||||
|
||||
QUrlQuery url_query(url.query());
|
||||
for (const Param ¶m : params) {
|
||||
url_query.addQueryItem(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second));
|
||||
url_query.addQueryItem(QString::fromLatin1(QUrl::toPercentEncoding(param.first)), QString::fromLatin1(QUrl::toPercentEncoding(param.second)));
|
||||
}
|
||||
|
||||
if (!redirect) {
|
||||
if (!url.path().isEmpty() && url.path().right(1) == "/") {
|
||||
if (!url.path().isEmpty() && url.path().right(1) == QStringLiteral("/")) {
|
||||
url.setPath(url.path() + QStringLiteral("rest/ping.view"));
|
||||
}
|
||||
else {
|
||||
@@ -194,14 +199,14 @@ void SubsonicService::SendPingWithCredentials(QUrl url, const QString &username,
|
||||
|
||||
QNetworkRequest req(url);
|
||||
|
||||
if (url.scheme() == "https" && !verify_certificate_) {
|
||||
if (url.scheme() == QStringLiteral("https") && !verify_certificate_) {
|
||||
QSslConfiguration sslconfig = QSslConfiguration::defaultConfiguration();
|
||||
sslconfig.setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||
req.setSslConfiguration(sslconfig);
|
||||
}
|
||||
|
||||
req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/x-www-form-urlencoded"));
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
req.setAttribute(QNetworkRequest::Http2AllowedAttribute, http2_);
|
||||
@@ -263,7 +268,7 @@ void SubsonicService::HandlePingReply(QNetworkReply *reply, const QUrl &url, con
|
||||
}
|
||||
|
||||
// See if there is Json data containing "error" - then use that instead.
|
||||
QByteArray data = reply->readAll();
|
||||
const QByteArray data = reply->readAll();
|
||||
QJsonParseError parse_error;
|
||||
QJsonDocument json_doc = QJsonDocument::fromJson(data, &parse_error);
|
||||
if (parse_error.error == QJsonParseError::NoError && !json_doc.isEmpty() && json_doc.isObject()) {
|
||||
@@ -358,12 +363,12 @@ void SubsonicService::HandlePingReply(QNetworkReply *reply, const QUrl &url, con
|
||||
QString status = obj_response[QStringLiteral("status")].toString().toLower();
|
||||
QString message = obj_response[QStringLiteral("message")].toString();
|
||||
|
||||
if (status == "failed") {
|
||||
if (status == QStringLiteral("failed")) {
|
||||
emit TestComplete(false, message);
|
||||
emit TestFailure(message);
|
||||
return;
|
||||
}
|
||||
else if (status == "ok") {
|
||||
else if (status == QStringLiteral("ok")) {
|
||||
emit TestComplete(true);
|
||||
emit TestSuccess();
|
||||
return;
|
||||
@@ -461,7 +466,7 @@ void SubsonicService::PingError(const QString &error, const QVariant &debug) {
|
||||
QString error_html;
|
||||
for (const QString &e : errors_) {
|
||||
qLog(Error) << "Subsonic:" << e;
|
||||
error_html += e + "<br />";
|
||||
error_html += e + QStringLiteral("<br />");
|
||||
}
|
||||
if (debug.isValid()) qLog(Debug) << debug;
|
||||
|
||||
|
||||
@@ -103,10 +103,6 @@ class SubsonicService : public InternetService {
|
||||
private:
|
||||
void PingError(const QString &error = QString(), const QVariant &debug = QVariant());
|
||||
|
||||
static const char *kSongsTable;
|
||||
static const char *kSongsFtsTable;
|
||||
static const int kMaxRedirects;
|
||||
|
||||
Application *app_;
|
||||
ScopedPtr<QNetworkAccessManager> network_;
|
||||
SubsonicUrlHandler *url_handler_;
|
||||
|
||||
@@ -45,7 +45,7 @@ UrlHandler::LoadResult SubsonicUrlHandler::StartLoading(const QUrl &url) {
|
||||
|
||||
using Param = QPair<QString, QString>;
|
||||
using ParamList = QList<Param>;
|
||||
const QUrl stream_url = SubsonicBaseRequest::CreateUrl(server_url(), auth_method(), username(), password(), QStringLiteral("stream"), ParamList() << Param("id", url.path()));
|
||||
const QUrl stream_url = SubsonicBaseRequest::CreateUrl(server_url(), auth_method(), username(), password(), QStringLiteral("stream"), ParamList() << Param(QStringLiteral("id"), url.path()));
|
||||
|
||||
return LoadResult(url, LoadResult::Type::TrackAvailable, stream_url);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user