From ef1b32bb52f29288a96f86d5c324631bb529c75b Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Tue, 11 May 2021 08:08:00 +0200 Subject: [PATCH] preliminary implementation of #410 --- .../desktop/com.github.rssguard.appdata.xml | 2 +- resources/docs/Documentation.md | 34 ++++--- resources/docs/images/adblock.png | Bin 0 -> 10951 bytes resources/scripts/7za | 2 +- .../network-web/adblock/adblockdialog.cpp | 33 +++++- .../network-web/adblock/adblockdialog.ui | 10 +- .../network-web/adblock/adblockmanager.cpp | 95 ++++++++++-------- .../network-web/adblock/adblockmanager.h | 5 +- 8 files changed, 112 insertions(+), 69 deletions(-) create mode 100755 resources/docs/images/adblock.png diff --git a/resources/desktop/com.github.rssguard.appdata.xml b/resources/desktop/com.github.rssguard.appdata.xml index 8b53c050e..6eeb133e6 100644 --- a/resources/desktop/com.github.rssguard.appdata.xml +++ b/resources/desktop/com.github.rssguard.appdata.xml @@ -30,7 +30,7 @@ https://martinrotter.github.io/donate/ - + none diff --git a/resources/docs/Documentation.md b/resources/docs/Documentation.md index c967d2c24..abc6ca3d1 100644 --- a/resources/docs/Documentation.md +++ b/resources/docs/Documentation.md @@ -7,8 +7,8 @@ * [Supported feed formats and online feed services](Feed-formats.md) * [Message filtering](Message-filters.md) * [Database backends](#database-backends) - * [Google Reader API](#google-reader-api) * [Websites scraping](#websites-scraping) + * [Google Reader API](#google-reader-api) * [Gmail](#gmail) * [Feedly](#feedly) * [Labels](Labels.md) @@ -109,19 +109,6 @@ MariaDB (MySQL) backend is there for users, who want to store their data in a ce For database-related configuration see `Settings -> Data storage` dialog. -## Google Reader API -There is a plugin which offers synchronization with services using Google Reader API. Plugin was so far tested with FreshRSS, Reedah, The Old Reader and Bazqux. All Google Reader API enabled services should work. - -Note that Inoreader has its own separate plugin, because it uses OAuth as authentication method. - -Google Reader API integration in RSS Guard offers a way to set custom service endpoint even if you select service which is not self-hosted such as Bazqux, providing all users with greater flexibility and freedom. - - - -Note that even when all Google Reader API enabled services should follow the API, there are still some minor differences, primarily because Google Reader API has no strict documentation to follow and some services do not offer some features. - -For example The Old Reader does not seem to offer tags/labels functionality, therefore tags/labels in RSS Guard are not synchronized, but you can still use offline labels. - ## Websites scraping > **Only proceed if you consider yourself to be a power user and you know what you are doing!** @@ -169,6 +156,19 @@ Typical post-processing filter might do things like advanced CSS formatting, loc It's completely up to you if you decide to only use script as `Source` of the script or separate your custom functionality between `Source` script and `Post-process` script. Sometimes you might need different `Source` scripts for different online sources and the same `Post-process` script and vice versa. +## Google Reader API +There is a plugin which offers synchronization with services using Google Reader API. Plugin was so far tested with FreshRSS, Reedah, The Old Reader and Bazqux. All Google Reader API enabled services should work. + +Note that Inoreader has its own separate plugin, because it uses OAuth as authentication method. + +Google Reader API integration in RSS Guard offers a way to set custom service endpoint even if you select service which is not self-hosted such as Bazqux, providing all users with greater flexibility and freedom. + + + +Note that even when all Google Reader API enabled services should follow the API, there are still some minor differences, primarily because Google Reader API has no strict documentation to follow and some services do not offer some features. + +For example The Old Reader does not seem to offer tags/labels functionality, therefore tags/labels in RSS Guard are not synchronized, but you can still use offline labels. + ## Gmail RSS Guard includes Gmail plugin, which allows users to receive and send e-mail messages in a very simple fashion. Plugin uses [Gmail API](https://developers.google.com/gmail/api) and offers some e-mail client-like features: * Sending e-mail messages. @@ -213,6 +213,12 @@ RSS Guard allows you to define a set of custom tools which you can subsequently You need to have have [Node.js](https://nodejs.org) with [NPM](https://www.npmjs.com) (which is usually included in Node.js installer) installed to have ad-blocking in RSS Guard working. Also, the implementation requires additional [npm](https://www.npmjs.com) modules to be installed. You see that list of needed modules near the top of [this](https://github.com/martinrotter/rssguard/blob/master/resources/scripts/adblock/adblock-server.js) file. +I understand that the above installation of needed dependencies is not trivial, but it is necessary evil to have up-to-date and modern implementation of AdBlock in RSS Guard. Previous `C++`-based implementation was buggy, quite slow and hard to maintain. + +You can find elaborated lists of AdBlock rules [here](https://easylist.to). You can just copy direct hyperlinks to those lists and paste them into "Filter lists" textbox as seen below. Remember to always separate individual links with newlines. Same applies to "Custom filters" where you can insert individual filters, for example [filter](https://adblockplus.org/filter-cheatsheet) "idnes" to block all URLs with "idnes" in them. + + + The way ad-blocking internally works is that RSS Guard starts local HTTP browser which provides ad-blocking API, which is subsequently called by RSS Guard. There is some caching done in between, which speeds up some ad-blocking decisions. ## GUI tweaking diff --git a/resources/docs/images/adblock.png b/resources/docs/images/adblock.png new file mode 100755 index 0000000000000000000000000000000000000000..68400e23c27dac347bbff3a5695c92ef0112b1c6 GIT binary patch literal 10951 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 literal 0 HcmV?d00001 diff --git a/resources/scripts/7za b/resources/scripts/7za index 9c10723bf..47f412575 160000 --- a/resources/scripts/7za +++ b/resources/scripts/7za @@ -1 +1 @@ -Subproject commit 9c10723bfbaf6cb85107d6ee16e0324e9e487749 +Subproject commit 47f4125753452eff8800dbd6600c5a05540b15d9 diff --git a/src/librssguard/network-web/adblock/adblockdialog.cpp b/src/librssguard/network-web/adblock/adblockdialog.cpp index c8e9ac94d..e1696b4e0 100644 --- a/src/librssguard/network-web/adblock/adblockdialog.cpp +++ b/src/librssguard/network-web/adblock/adblockdialog.cpp @@ -7,6 +7,7 @@ #include "definitions/definitions.h" #include "exceptions/applicationexception.h" #include "gui/guiutilities.h" +#include "gui/messagebox.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" #include "network-web/webfactory.h" @@ -32,6 +33,13 @@ AdBlockDialog::AdBlockDialog(QWidget* parent) connect(m_ui.m_cbEnable, &QCheckBox::toggled, this, &AdBlockDialog::enableAdBlock); connect(m_ui.m_buttonBox, &QDialogButtonBox::rejected, this, &AdBlockDialog::saveAndClose); + m_ui.m_lblTestResult->label()->setWordWrap(true); + m_ui.m_btnHelp->setIcon(qApp->icons()->fromTheme(QSL("help-about"))); + m_ui.m_btnTest->setIcon(qApp->icons()->fromTheme(QSL("media-playback-start"))); + m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information, + tr("No test executed yet."), + tr("No test executed yet.")); + load(); m_ui.m_buttonBox->setFocus(); } @@ -39,7 +47,23 @@ AdBlockDialog::AdBlockDialog(QWidget* parent) void AdBlockDialog::saveAndClose() { m_manager->setFilterLists(m_ui.m_txtPredefined->toPlainText().split(QSL("\n"))); m_manager->setCustomFilters(m_ui.m_txtCustom->toPlainText().split(QSL("\n"))); - m_manager->updateUnifiedFiltersFile(); + + try { + m_manager->updateUnifiedFiltersFile(); + } + catch (const ApplicationException& ex) { + qCriticalNN << LOGSEC_ADBLOCK + << "Failed to write unified filters to file or re-start server, error:" + << QUOTE_W_SPACE_DOT(ex.message()); + + MessageBox::show(this, + QMessageBox::Icon::Critical, + tr("Cannot enable AdBlock"), + tr("There is some error in AdBlock component and it cannot be enabled. " + "Check error message below (or application debug log) for more information."), + {}, + ex.message()); + } close(); } @@ -54,7 +78,9 @@ void AdBlockDialog::enableAdBlock(bool enable) { void AdBlockDialog::testConfiguration() { try { - m_manager->testConfiguration(); + m_manager->setFilterLists(m_ui.m_txtPredefined->toPlainText().split(QSL("\n"))); + m_manager->setCustomFilters(m_ui.m_txtCustom->toPlainText().split(QSL("\n"))); + m_manager->updateUnifiedFiltersFile(); m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok, tr("You are good to go."), tr("OK!")); } catch (const ApplicationException& ex) { @@ -63,7 +89,8 @@ void AdBlockDialog::testConfiguration() { << QUOTE_W_SPACE_DOT(ex.message()); m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error, tr("There is error, check application log for more details and " - "head to online documentation."), tr("ERROR!")); + "head to online documentation.\n\nError: %1").arg(ex.message()), + tr("ERROR!")); } } diff --git a/src/librssguard/network-web/adblock/adblockdialog.ui b/src/librssguard/network-web/adblock/adblockdialog.ui index 394e49c86..c6e08e9f3 100644 --- a/src/librssguard/network-web/adblock/adblockdialog.ui +++ b/src/librssguard/network-web/adblock/adblockdialog.ui @@ -58,11 +58,11 @@ - 1 + 0 - Filter lists (list per line) + Filter lists @@ -113,7 +113,11 @@ - + + + Qt::RightToLeft + + diff --git a/src/librssguard/network-web/adblock/adblockmanager.cpp b/src/librssguard/network-web/adblock/adblockmanager.cpp index 4575974ff..0d2438c2d 100644 --- a/src/librssguard/network-web/adblock/adblockmanager.cpp +++ b/src/librssguard/network-web/adblock/adblockmanager.cpp @@ -25,15 +25,15 @@ #include AdBlockManager::AdBlockManager(QObject* parent) - : QObject(parent), m_loaded(false), m_enabled(false), m_interceptor(new AdBlockUrlInterceptor(this)) { + : QObject(parent), m_loaded(false), m_enabled(false), m_interceptor(new AdBlockUrlInterceptor(this)), + m_serverProcess(nullptr) { m_adblockIcon = new AdBlockIcon(this); m_adblockIcon->setObjectName(QSL("m_adblockIconAction")); m_unifiedFiltersFile = qApp->userDataFolder() + QDir::separator() + QSL("adblock-unified-filters.txt"); - m_serverProcess = new QProcess(this); } AdBlockManager::~AdBlockManager() { - if (m_serverProcess->state() == QProcess::ProcessState::Running) { + if (m_serverProcess != nullptr && m_serverProcess->state() == QProcess::ProcessState::Running) { m_serverProcess->kill(); } } @@ -50,7 +50,7 @@ BlockingResult AdBlockManager::block(const AdblockRequestInfo& request) const { return { false }; } else { - if (m_serverProcess->state() == QProcess::ProcessState::Running) { + if (m_serverProcess != nullptr && m_serverProcess->state() == QProcess::ProcessState::Running) { try { auto result = askServerIfBlocked(url_string); @@ -93,7 +93,23 @@ void AdBlockManager::load(bool initial_load) { } if (m_enabled) { - updateUnifiedFiltersFile(); + try { + updateUnifiedFiltersFile(); + } + catch (const ApplicationException& ex) { + qCriticalNN << LOGSEC_ADBLOCK + << "Failed to write unified filters to file or re-start server, error:" + << QUOTE_W_SPACE_DOT(ex.message()); + + qApp->showGuiMessage(tr("AdBlock needs to be configured"), + tr("AdBlock component is not configured properly."), + QSystemTrayIcon::MessageIcon::Warning, + nullptr, + true, + [=]() { + showDialog(); + }); + } } } @@ -105,12 +121,8 @@ bool AdBlockManager::canRunOnScheme(const QString& scheme) const { return !(scheme == QSL("file") || scheme == QSL("qrc") || scheme == QSL("data") || scheme == QSL("abp")); } -void AdBlockManager::testConfiguration() { - // Just try to run testing JS program to see if all dependecies are installed. -} - QString AdBlockManager::elementHidingRulesForDomain(const QUrl& url) const { - if (m_serverProcess->state() == QProcess::ProcessState::Running) { + if (m_serverProcess != nullptr && m_serverProcess->state() == QProcess::ProcessState::Running) { try { auto result = askServerForCosmeticRules(url.toString()); @@ -241,16 +253,7 @@ QString AdBlockManager::askServerForCosmeticRules(const QString& url) const { } } -void AdBlockManager::restartServer(int port) { - if (m_serverProcess->state() == QProcess::ProcessState::Running) { - m_serverProcess->kill(); - - if (!m_serverProcess->waitForFinished(1000)) { - m_serverProcess->deleteLater(); - m_serverProcess = new QProcess(this); - } - } - +QProcess* AdBlockManager::restartServer(int port) { QString temp_server = QDir::toNativeSeparators(IOFactory::getSystemFolder(QStandardPaths::StandardLocation::TempLocation)) + QDir::separator() + QSL("adblock-server.js"); @@ -259,21 +262,23 @@ void AdBlockManager::restartServer(int port) { qWarningNN << LOGSEC_ADBLOCK << "Failed to copy server file to TEMP."; } + QProcess* proc = new QProcess(this); + #if defined(Q_OS_WIN) - m_serverProcess->setProgram(QSL("node.exe")); + proc->setProgram(QSL("node.exe")); #else - m_serverProcess->setProgram(QSL("node")); + proc->setProgram(QSL("node")); #endif - m_serverProcess->setArguments({ + proc->setArguments({ QDir::toNativeSeparators(temp_server), QString::number(port), QDir::toNativeSeparators(m_unifiedFiltersFile) }); - m_serverProcess->setProcessEnvironment(QProcessEnvironment::systemEnvironment()); + proc->setProcessEnvironment(QProcessEnvironment::systemEnvironment()); - auto pe = m_serverProcess->processEnvironment(); + auto pe = proc->processEnvironment(); QString node_path = #if defined(Q_OS_WIN) pe.value(QSL("APPDATA")) + @@ -291,14 +296,18 @@ void AdBlockManager::restartServer(int port) { pe.insert(QSL("NODE_PATH"), node_path); } - m_serverProcess->setProcessEnvironment(pe); - m_serverProcess->setProcessChannelMode(QProcess::ProcessChannelMode::ForwardedErrorChannel); + proc->setProcessEnvironment(pe); + proc->setProcessChannelMode(QProcess::ProcessChannelMode::ForwardedErrorChannel); - if (!m_serverProcess->open()) { - qWarningNN << LOGSEC_ADBLOCK << "Failed to start server."; + if (!proc->open()) { + auto ers = proc->errorString(); + proc->deleteLater(); + + throw ApplicationException(ers); } else { qDebugNN << LOGSEC_ADBLOCK << "Started server."; + return proc; } } @@ -312,6 +321,10 @@ void AdBlockManager::updateUnifiedFiltersFile() { // Download filters one by one and append. for (const QString& filter_list_url : qAsConst(filter_lists)) { + if (filter_list_url.simplified().isEmpty()) { + continue; + } + QByteArray out; auto res = NetworkFactory::performNetworkOperation(filter_list_url, 2000, @@ -328,11 +341,7 @@ void AdBlockManager::updateUnifiedFiltersFile() { << QUOTE_W_SPACE_DOT(filter_list_url); } else { - qWarningNN << LOGSEC_ADBLOCK - << "Failed to download list of filters" - << QUOTE_W_SPACE(filter_list_url) - << "with error" - << QUOTE_W_SPACE_DOT(res.first); + throw NetworkException(res.first, tr("failed to download filter list '%1'").arg(filter_list_url)); } } @@ -343,16 +352,16 @@ void AdBlockManager::updateUnifiedFiltersFile() { QDir::separator() + QSL("adblock.filters"); - try { - IOFactory::writeFile(m_unifiedFiltersFile, unified_contents.toUtf8()); + IOFactory::writeFile(m_unifiedFiltersFile, unified_contents.toUtf8()); - if (m_enabled) { - restartServer(ADBLOCK_SERVER_PORT); + if (m_enabled) { + if (m_serverProcess != nullptr && m_serverProcess->state() == QProcess::ProcessState::Running) { + m_serverProcess->kill(); + m_serverProcess->waitForFinished(1000); + m_serverProcess->deleteLater(); + m_serverProcess = nullptr; } - } - catch (const ApplicationException& ex) { - qCriticalNN << LOGSEC_ADBLOCK - << "Failed to write unified filters to file, error:" - << QUOTE_W_SPACE_DOT(ex.message()); + + m_serverProcess = restartServer(ADBLOCK_SERVER_PORT); } } diff --git a/src/librssguard/network-web/adblock/adblockmanager.h b/src/librssguard/network-web/adblock/adblockmanager.h index f9f9fbd71..c77173274 100644 --- a/src/librssguard/network-web/adblock/adblockmanager.h +++ b/src/librssguard/network-web/adblock/adblockmanager.h @@ -37,8 +37,6 @@ class AdBlockManager : public QObject { bool canRunOnScheme(const QString& scheme) const; AdBlockIcon* adBlockIcon() const; - void testConfiguration(); - // General methods for adblocking. BlockingResult block(const AdblockRequestInfo& request) const; QString elementHidingRulesForDomain(const QUrl& url) const; @@ -62,8 +60,7 @@ class AdBlockManager : public QObject { private: BlockingResult askServerIfBlocked(const QString& url) const; QString askServerForCosmeticRules(const QString& url) const; - - void restartServer(int port); + QProcess* restartServer(int port); private: bool m_loaded;