From 6bdb1446a1ad846e70c36ebfe29c3a3e459c3201 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Fri, 8 Jan 2021 11:08:37 +0100 Subject: [PATCH] Adblock now can efficiently perform unwanted element hiding. --- resources/docs/Documentation.md | 2 +- src/librssguard/definitions/definitions.h | 1 + .../network-web/adblock/adblockmanager.cpp | 17 ++++++++ .../network-web/adblock/adblockmanager.h | 2 + .../adblock/adblockurlinterceptor.cpp | 2 +- src/librssguard/network-web/webpage.cpp | 40 +++++++++++++++++-- src/librssguard/network-web/webpage.h | 7 +++- .../services/abstract/serviceroot.cpp | 2 +- 8 files changed, 66 insertions(+), 7 deletions(-) diff --git a/resources/docs/Documentation.md b/resources/docs/Documentation.md index ad3472ca4..c0575b3b9 100644 --- a/resources/docs/Documentation.md +++ b/resources/docs/Documentation.md @@ -157,7 +157,7 @@ You can right click on any item in embedded web browser and hit `Save as` button You can download up to 6 files simultaneously. ## AdBlock -[Web-based variant](#web-based-and-lite-app-variants) of RSS Guard offers ad-blocking functionality too. +[Web-based variant](#web-based-and-lite-app-variants) of RSS Guard offers ad-blocking functionality. AdBlock uses standard AdBlock-Plus-like scripts, thus allowing you to use EasyList etc. AdBlock supports element hiding rules and site-wide blocking. You can find its settings in `Web browser & tabs` section of main menu. diff --git a/src/librssguard/definitions/definitions.h b/src/librssguard/definitions/definitions.h index 3cd6400ce..8d400a58e 100755 --- a/src/librssguard/definitions/definitions.h +++ b/src/librssguard/definitions/definitions.h @@ -99,6 +99,7 @@ #define LOGSEC_FEEDMODEL "feed-model: " #define LOGSEC_FEEDDOWNLOADER "feed-downloader: " #define LOGSEC_MESSAGEMODEL "message-model: " +#define LOGSEC_JS "javascript: " #define LOGSEC_GUI "gui: " #define LOGSEC_CORE "core: " #define LOGSEC_DB "database: " diff --git a/src/librssguard/network-web/adblock/adblockmanager.cpp b/src/librssguard/network-web/adblock/adblockmanager.cpp index cdd724ef8..17a282213 100644 --- a/src/librssguard/network-web/adblock/adblockmanager.cpp +++ b/src/librssguard/network-web/adblock/adblockmanager.cpp @@ -329,6 +329,23 @@ QString AdBlockManager::elementHidingRulesForDomain(const QUrl& url) const { } } +QString AdBlockManager::generateJsForElementHiding(const QString& css) const { + QString source = QL1S("(function() {" + "var head = document.getElementsByTagName('head')[0];" + "if (!head) return;" + "var css = document.createElement('style');" + "css.setAttribute('type', 'text/css');" + "css.appendChild(document.createTextNode('%1'));" + "head.appendChild(css);" + "})()"); + QString style = css; + + style.replace(QL1S("'"), QL1S("\\'")); + style.replace(QL1S("\n"), QL1S("\\n")); + + return source.arg(style); +} + AdBlockSubscription* AdBlockManager::subscriptionByName(const QString& name) const { for (AdBlockSubscription* subscription : m_subscriptions) { if (subscription->title() == name) { diff --git a/src/librssguard/network-web/adblock/adblockmanager.h b/src/librssguard/network-web/adblock/adblockmanager.h index 8443cdc6c..9e8a7b5e8 100644 --- a/src/librssguard/network-web/adblock/adblockmanager.h +++ b/src/librssguard/network-web/adblock/adblockmanager.h @@ -58,6 +58,8 @@ class AdBlockManager : public QObject { QString elementHidingRules(const QUrl& url) const; QString elementHidingRulesForDomain(const QUrl& url) const; + QString generateJsForElementHiding(const QString& css) const; + AdBlockSubscription* subscriptionByName(const QString& name) const; QList subscriptions() const; diff --git a/src/librssguard/network-web/adblock/adblockurlinterceptor.cpp b/src/librssguard/network-web/adblock/adblockurlinterceptor.cpp index 02ba03790..c287aacd4 100644 --- a/src/librssguard/network-web/adblock/adblockurlinterceptor.cpp +++ b/src/librssguard/network-web/adblock/adblockurlinterceptor.cpp @@ -30,6 +30,6 @@ void AdBlockUrlInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) { if (m_manager->block(AdblockRequestInfo(info)) != nullptr) { info.block(true); - qWarning() << LOGSEC_ADBLOCK << "Blocked request:" << QUOTE_W_SPACE_DOT(info.requestUrl().toString()); + qWarningNN << LOGSEC_ADBLOCK << "Blocked request:" << QUOTE_W_SPACE_DOT(info.requestUrl().toString()); } } diff --git a/src/librssguard/network-web/webpage.cpp b/src/librssguard/network-web/webpage.cpp index 2f50354d7..5c73ddaf8 100644 --- a/src/librssguard/network-web/webpage.cpp +++ b/src/librssguard/network-web/webpage.cpp @@ -17,19 +17,46 @@ #include #include #include +#include WebPage::WebPage(QObject* parent) : QWebEnginePage(parent) { setBackgroundColor(Qt::transparent); + + connect(this, &QWebEnginePage::loadFinished, this, &WebPage::hideUnwantedElements); } WebViewer* WebPage::view() const { return qobject_cast(QWebEnginePage::view()); } -bool WebPage::acceptNavigationRequest(const QUrl& url, NavigationType type, bool isMainFrame) { +void WebPage::hideUnwantedElements() { + if (!qApp->web()->adBlock()->isEnabled()) { + return; + } + + auto css = qApp->web()->adBlock()->elementHidingRules(url()); + + if (!css.isEmpty()) { + auto js = qApp->web()->adBlock()->generateJsForElementHiding(css); + + runJavaScript(js); + qDebugNN << LOGSEC_JS << "Running global JS for element hiding rules."; + } + + css = qApp->web()->adBlock()->elementHidingRulesForDomain(url()); + + if (!css.isEmpty()) { + auto js = qApp->web()->adBlock()->generateJsForElementHiding(css); + + runJavaScript(js); + qDebugNN << LOGSEC_JS << "Running domain-specific JS for element hiding rules."; + } +} + +bool WebPage::acceptNavigationRequest(const QUrl& url, NavigationType type, bool is_main_frame) { const RootItem* root = view()->root(); - if (isMainFrame) { + if (is_main_frame) { auto* adblock_rule = qApp->web()->adBlock()->block(AdblockRequestInfo(url)); if (adblock_rule != nullptr) { @@ -57,6 +84,13 @@ bool WebPage::acceptNavigationRequest(const QUrl& url, NavigationType type, bool return true; } else { - return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame); + return QWebEnginePage::acceptNavigationRequest(url, type, is_main_frame); } } + +void WebPage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, + int line_number, const QString& source_id) { + Q_UNUSED(level) + + qWarningNN << LOGSEC_JS << message << QSL(" (source: %1:%2)").arg(source_id, QString::number(line_number)); +} diff --git a/src/librssguard/network-web/webpage.h b/src/librssguard/network-web/webpage.h index e794a97b8..08ecacc63 100644 --- a/src/librssguard/network-web/webpage.h +++ b/src/librssguard/network-web/webpage.h @@ -15,8 +15,13 @@ class WebPage : public QWebEnginePage { WebViewer* view() const; + private slots: + void hideUnwantedElements(); + protected: - bool acceptNavigationRequest(const QUrl& url, NavigationType type, bool isMainFrame); + virtual bool acceptNavigationRequest(const QUrl& url, NavigationType type, bool is_main_frame); + virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, + int line_number, const QString& source_id); }; #endif // WEBPAGE_H diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp index b3f126c14..90afa03f6 100644 --- a/src/librssguard/services/abstract/serviceroot.cpp +++ b/src/librssguard/services/abstract/serviceroot.cpp @@ -704,7 +704,7 @@ void ServiceRoot::assembleFeeds(Assignment feeds) { categories.value(feed.first)->appendChild(feed.second); } else { - qWarning("Feed '%s' is loose, skipping it.", qPrintable(feed.second->title())); + qWarningNN << LOGSEC_CORE << "Feed" << QUOTE_W_SPACE(feed.second->title()) << "is loose, skipping it."; } } }