From 58624785931e529cf350703beab7110335ea3a70 Mon Sep 17 00:00:00 2001 From: Jeena Date: Wed, 5 Oct 2016 16:49:40 +0200 Subject: [PATCH] Downoad all images in the background and keep them in memory As one of the first steps to offline capability we download all images and put them into the JSON stirng and into the content as data-uris for -tags. This way you can go offline and keep enjoying pictures in your feeds, at least untill you restart FeedTheMonkey for now. --- src/post.cpp | 71 +++++++++++++++++++++++++++++++++++++++++---- src/post.h | 12 ++++++-- src/tinytinyrss.cpp | 2 +- 3 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/post.cpp b/src/post.cpp index 2d3179b..3a20840 100644 --- a/src/post.cpp +++ b/src/post.cpp @@ -28,6 +28,33 @@ Post::Post(QObject *parent) : QObject(parent) } Post::Post(QJsonObject post, QObject *parent) : QObject(parent) +{ + populateFromJson(post); +} + +Post::Post(QJsonObject post, QNetworkAccessManager *networkManager, QObject *parent) : QObject(parent) +{ + mNetworkManager = networkManager; + populateFromJson(post); + + QObject::connect(this, &Post::contentChanged, [this]() { + QJsonObject obj = QJsonDocument::fromJson(mJsonString.toUtf8()).object(); + obj["content"] = QJsonValue(mContent); + QJsonDocument doc(obj); + QString result(doc.toJson(QJsonDocument::Indented)); + mJsonString = result; + emit jsonStringChanged(mJsonString); + }); + + cacheImgs(); +} + +Post::~Post() +{ + +} + +void Post::populateFromJson(QJsonObject post) { mTitle = html2text(post.value("title").toString().trimmed()); mFeedTitle = html2text(post.value("feed_title").toString().trimmed()); @@ -50,11 +77,6 @@ Post::Post(QJsonObject post, QObject *parent) : QObject(parent) mJsonString = result; } -Post::~Post() -{ - -} - void Post::setRead(bool r) { if(mRead == r) return; @@ -77,3 +99,42 @@ QString Post::html2text(const QString htmlString) doc.setHtml(htmlString); return doc.toPlainText(); } + +void Post::cacheImgs() +{ + QRegExp imgTagRegex("\\]*src\\s*=\\s*\"([^\"]*)\"[^\\>]*\\>", Qt::CaseInsensitive); + imgTagRegex.setMinimal(true); + QStringList urlmatches; + int offset = 0; + while( (offset = imgTagRegex.indexIn(mContent, offset)) != -1){ + offset += imgTagRegex.matchedLength(); + urlmatches.append(imgTagRegex.cap(1)); // Should hold only src property + } + + for(QString url : urlmatches) { + + if(url.startsWith("http")) { + QNetworkRequest request(url); + QNetworkReply *reply = mNetworkManager->get(request); + + connect(reply, &QNetworkReply::finished, [url, this, reply] () { + if (reply) { + if (reply->error() == QNetworkReply::NoError) { + QVariant mimeType(reply->header(QNetworkRequest::ContentTypeHeader)); + QString imgString = QString("data:") + mimeType.toString() + QString(";base64,") + QString(reply->readAll().toBase64()); + if(mimeType == "image/jpeg" || mimeType == "image/gif" || mimeType == "image/png") + { + mContent = mContent.replace(url, imgString); + emit contentChanged(mContent); + } + } else { + int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + //do some error management + qWarning() << "HTTP error: " << httpStatus; + } + reply->deleteLater(); + } + }); + } + } +} diff --git a/src/post.h b/src/post.h index 56ab9ff..ad1649d 100644 --- a/src/post.h +++ b/src/post.h @@ -24,6 +24,7 @@ #include #include #include +#include class Post : public QObject { @@ -35,16 +36,17 @@ class Post : public QObject Q_PROPERTY(QString author READ author CONSTANT) Q_PROPERTY(QUrl link READ link CONSTANT) Q_PROPERTY(QDateTime date READ date CONSTANT) - Q_PROPERTY(QString content READ content CONSTANT) + Q_PROPERTY(QString content READ content NOTIFY contentChanged) Q_PROPERTY(QString excerpt READ excerpt CONSTANT) Q_PROPERTY(bool starred READ starred NOTIFY starredChanged) Q_PROPERTY(bool read READ read WRITE setRead NOTIFY readChanged) Q_PROPERTY(bool dontChangeRead READ dontChangeRead WRITE setDontChangeRead NOTIFY dontChangeReadChanged) - Q_PROPERTY(QString jsonString READ jsonString CONSTANT) + Q_PROPERTY(QString jsonString READ jsonString NOTIFY jsonStringChanged) public: Post(QObject *parent = 0); Post(QJsonObject post, QObject *parent = 0); + Post(QJsonObject post, QNetworkAccessManager *networkManager, QObject *parent = 0); ~Post(); QString title() const { return mTitle; } QString feedTitle() const { return mFeedTitle; } @@ -63,9 +65,11 @@ public: QString jsonString() const { return mJsonString; } signals: + void contentChanged(QString); void starredChanged(bool); void readChanged(bool); void dontChangeReadChanged(bool); + void jsonStringChanged(QString); public slots: @@ -83,7 +87,11 @@ private: bool mRead; bool mDontChangeRead; QString mJsonString; + QString html2text(const QString htmlString); + void cacheImgs(); + void populateFromJson(QJsonObject post); + QNetworkAccessManager *mNetworkManager; }; #endif // POST_H diff --git a/src/tinytinyrss.cpp b/src/tinytinyrss.cpp index 4806c04..3cc5ae0 100644 --- a/src/tinytinyrss.cpp +++ b/src/tinytinyrss.cpp @@ -62,7 +62,7 @@ void TinyTinyRSS::reload() for(int i = 0; i < posts.count(); i++) { QJsonObject postJson = posts.at(i).toObject(); - Post *post = new Post(postJson, this); + Post *post = new Post(postJson, mNetworkManager, this); connect(post, SIGNAL(readChanged(bool)), this, SLOT(onPostReadChanged(bool))); mPosts.append(post); }