From ffc32a7bba6782ab4f341aa0f4bd46596475f5b9 Mon Sep 17 00:00:00 2001 From: Black Hat Date: Fri, 21 Sep 2018 19:21:02 +0800 Subject: Add avatar caching. --- lib/avatar.cpp | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/avatar.cpp b/lib/avatar.cpp index 438268b6..8495df31 100644 --- a/lib/avatar.cpp +++ b/lib/avatar.cpp @@ -26,6 +26,7 @@ #include #include +#include using namespace QMatrixClient; using std::move; @@ -33,7 +34,9 @@ using std::move; class Avatar::Private { public: - explicit Private(QUrl url = {}) : _url(move(url)) { } + explicit Private(QUrl url = {}) : _url(move(url)) { + _localFile = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + url.authority() + "_" + url.fileName() + ".png"); + } QImage get(Connection* connection, QSize size, get_callback_t callback) const; @@ -42,6 +45,7 @@ class Avatar::Private bool checkUrl(QUrl url) const; QUrl _url; + QUrl _localFile; // The below are related to image caching, hence mutable mutable QImage _originalImage; @@ -109,31 +113,40 @@ QImage Avatar::Private::get(Connection* connection, QSize size, qCCritical(MAIN) << "Null callbacks are not allowed in Avatar::get"; Q_ASSERT(false); } + // FIXME: Alternating between longer-width and longer-height requests // is a sure way to trick the below code into constantly getting another // image from the server because the existing one is alleged unsatisfactory. // This is plain abuse by the client, though; so not critical for now. - if( ( !(_fetched || _thumbnailRequest) - || size.width() > _requestedSize.width() - || size.height() > _requestedSize.height() ) && checkUrl(_url) ) - { - qCDebug(MAIN) << "Getting avatar from" << _url.toString(); - _requestedSize = size; - if (isJobRunning(_thumbnailRequest)) - _thumbnailRequest->abandon(); - if (callback) - callbacks.emplace_back(move(callback)); - _thumbnailRequest = connection->getThumbnail(_url, size); - QObject::connect( _thumbnailRequest, &MediaThumbnailJob::success, - _thumbnailRequest, [this] { + if (!(_fetched || _thumbnailRequest)) { + if (_localFile.isValid() && _originalImage.load(_localFile.toLocalFile())) { + if (!(_originalImage.size().isEmpty() || size.width() > _originalImage.width() || size.height() > _originalImage.height())) { _fetched = true; - _originalImage = - _thumbnailRequest->scaledThumbnail(_requestedSize); _scaledImages.clear(); for (const auto& n: callbacks) n(); callbacks.clear(); - }); + } + } else if (checkUrl(_url)) { + qCDebug(MAIN) << "Getting avatar from" << _url.toString(); + _requestedSize = size; + if (isJobRunning(_thumbnailRequest)) + _thumbnailRequest->abandon(); + if (callback) + callbacks.emplace_back(move(callback)); + _thumbnailRequest = connection->getThumbnail(_url, size); + QObject::connect( _thumbnailRequest, &MediaThumbnailJob::success, + _thumbnailRequest, [this] { + _fetched = true; + _originalImage = + _thumbnailRequest->scaledThumbnail(_requestedSize); + _originalImage.save(_localFile.toLocalFile()); + _scaledImages.clear(); + for (const auto& n: callbacks) + n(); + callbacks.clear(); + }); + } } for (const auto& p: _scaledImages) @@ -178,6 +191,7 @@ bool Avatar::updateUrl(const QUrl& newUrl) return false; d->_url = newUrl; + d->_localFile = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + newUrl.authority() + "_" + newUrl.fileName() + ".png"); d->_fetched = false; if (isJobRunning(d->_thumbnailRequest)) d->_thumbnailRequest->abandon(); -- cgit v1.2.3 From 70a56b2f525442bf5b8ad20953ab43c12ad00b7f Mon Sep 17 00:00:00 2001 From: Black Hat Date: Sun, 23 Sep 2018 12:56:12 +0800 Subject: Coding improvements. Change _localFile initializer. Move avatar into /avatar. Remove redundant codes. Change _localFile to QString. Code deduplication. --- lib/avatar.cpp | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/avatar.cpp b/lib/avatar.cpp index 8495df31..35e736c4 100644 --- a/lib/avatar.cpp +++ b/lib/avatar.cpp @@ -26,6 +26,7 @@ #include #include +#include #include using namespace QMatrixClient; @@ -34,8 +35,7 @@ using std::move; class Avatar::Private { public: - explicit Private(QUrl url = {}) : _url(move(url)) { - _localFile = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + url.authority() + "_" + url.fileName() + ".png"); + explicit Private(QUrl url = {}) : _url(move(url)), _localFile(urlToLocalFile(_url)) { } QImage get(Connection* connection, QSize size, @@ -44,8 +44,11 @@ class Avatar::Private bool checkUrl(QUrl url) const; + static QString urlToLocalFile(QUrl url); + static void checkCacheLocation(); + QUrl _url; - QUrl _localFile; + QString _localFile; // The below are related to image caching, hence mutable mutable QImage _originalImage; @@ -118,16 +121,14 @@ QImage Avatar::Private::get(Connection* connection, QSize size, // is a sure way to trick the below code into constantly getting another // image from the server because the existing one is alleged unsatisfactory. // This is plain abuse by the client, though; so not critical for now. - if (!(_fetched || _thumbnailRequest)) { - if (_localFile.isValid() && _originalImage.load(_localFile.toLocalFile())) { - if (!(_originalImage.size().isEmpty() || size.width() > _originalImage.width() || size.height() > _originalImage.height())) { - _fetched = true; - _scaledImages.clear(); - for (const auto& n: callbacks) - n(); - callbacks.clear(); - } - } else if (checkUrl(_url)) { + if (checkUrl(_url) && !(_fetched || _thumbnailRequest)) { + if (_originalImage.load(_localFile) && !_originalImage.isNull() && size.width() <= _originalImage.width() && size.height() <= _originalImage.height()) { + _fetched = true; + _scaledImages.clear(); + for (const auto& n: callbacks) + n(); + callbacks.clear(); + } else { qCDebug(MAIN) << "Getting avatar from" << _url.toString(); _requestedSize = size; if (isJobRunning(_thumbnailRequest)) @@ -140,7 +141,8 @@ QImage Avatar::Private::get(Connection* connection, QSize size, _fetched = true; _originalImage = _thumbnailRequest->scaledThumbnail(_requestedSize); - _originalImage.save(_localFile.toLocalFile()); + checkCacheLocation(); + _originalImage.save(_localFile); _scaledImages.clear(); for (const auto& n: callbacks) n(); @@ -183,6 +185,17 @@ bool Avatar::Private::checkUrl(QUrl url) const return !_bannedUrl; } +QString Avatar::Private::urlToLocalFile(QUrl url) { + return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/avatar/" + url.authority() + "_" + url.fileName() + ".png"; +} + +void Avatar::Private::checkCacheLocation() { + const QString cachePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/avatar/"; + QDir dir; + if (!dir.exists(cachePath)) + dir.mkpath(cachePath); +} + QUrl Avatar::url() const { return d->_url; } bool Avatar::updateUrl(const QUrl& newUrl) @@ -191,10 +204,9 @@ bool Avatar::updateUrl(const QUrl& newUrl) return false; d->_url = newUrl; - d->_localFile = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + newUrl.authority() + "_" + newUrl.fileName() + ".png"); + d->_localFile = d->urlToLocalFile(newUrl); d->_fetched = false; if (isJobRunning(d->_thumbnailRequest)) d->_thumbnailRequest->abandon(); return true; } - -- cgit v1.2.3