From d5a02c098f6fde9864acb5814c353ff93527e82c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 3 Dec 2022 09:28:26 +0100 Subject: [PATCH 1/9] work on #745 --- resources/sql.qrc | 2 + resources/sql/db_init_sqlite.sql | 1 + resources/sql/db_update_mysql_3_4.sql | 8 ++ resources/sql/db_update_sqlite_3_4.sql | 29 +++++ src/librssguard/database/databasequeries.cpp | 4 +- src/librssguard/database/databasequeries.h | 123 +++++++++++------- src/librssguard/definitions/definitions.h | 11 +- src/librssguard/services/abstract/feed.cpp | 13 +- src/librssguard/services/abstract/feed.h | 5 +- .../services/abstract/gui/formfeeddetails.cpp | 2 + .../services/abstract/gui/formfeeddetails.ui | 17 ++- .../services/abstract/serviceroot.cpp | 2 + 12 files changed, 161 insertions(+), 56 deletions(-) create mode 100644 resources/sql/db_update_mysql_3_4.sql create mode 100644 resources/sql/db_update_sqlite_3_4.sql diff --git a/resources/sql.qrc b/resources/sql.qrc index b2b3b136b..f0d0402b9 100644 --- a/resources/sql.qrc +++ b/resources/sql.qrc @@ -3,9 +3,11 @@ sql/db_init_mysql.sql sql/db_update_mysql_1_2.sql sql/db_update_mysql_2_3.sql + sql/db_update_mysql_3_4.sql sql/db_init_sqlite.sql sql/db_update_sqlite_1_2.sql sql/db_update_sqlite_2_3.sql + sql/db_update_sqlite_3_4.sql \ No newline at end of file diff --git a/resources/sql/db_init_sqlite.sql b/resources/sql/db_init_sqlite.sql index c6d1b4590..13ccdad12 100644 --- a/resources/sql/db_init_sqlite.sql +++ b/resources/sql/db_init_sqlite.sql @@ -42,6 +42,7 @@ CREATE TABLE Feeds ( update_type INTEGER NOT NULL CHECK (update_type >= 0), update_interval INTEGER NOT NULL DEFAULT 900 CHECK (update_interval >= 1), is_off INTEGER NOT NULL DEFAULT 0 CHECK (is_off >= 0 AND is_off <= 1), + is_quiet INTEGER NOT NULL DEFAULT 0 CHECK (is_quiet >= 0 AND is_quiet <= 1), open_articles INTEGER NOT NULL DEFAULT 0 CHECK (open_articles >= 0 AND open_articles <= 1), account_id INTEGER NOT NULL, custom_id TEXT NOT NULL CHECK (custom_id != ''), /* Custom ID cannot be empty, it must contain either service-specific ID, or Feeds/id. */ diff --git a/resources/sql/db_update_mysql_3_4.sql b/resources/sql/db_update_mysql_3_4.sql new file mode 100644 index 000000000..d59935efe --- /dev/null +++ b/resources/sql/db_update_mysql_3_4.sql @@ -0,0 +1,8 @@ +USE ##; +-- ! +SET FOREIGN_KEY_CHECKS = 0; +-- ! +!! db_update_sqlite_3_4.sql +-- ! +SET FOREIGN_KEY_CHECKS = 1; +-- ! \ No newline at end of file diff --git a/resources/sql/db_update_sqlite_3_4.sql b/resources/sql/db_update_sqlite_3_4.sql new file mode 100644 index 000000000..c06a9035c --- /dev/null +++ b/resources/sql/db_update_sqlite_3_4.sql @@ -0,0 +1,29 @@ +ALTER TABLE Feeds RENAME TO backup_Feeds; +-- ! +CREATE TABLE Feeds ( + id $$, + ordr INTEGER NOT NULL CHECK (ordr >= 0), + title TEXT NOT NULL CHECK (title != ''), + description TEXT, + date_created BIGINT, + icon ^^, + category INTEGER NOT NULL CHECK (category >= -1), /* Physical category ID, also root feeds contain -1 here. */ + source TEXT, + update_type INTEGER NOT NULL CHECK (update_type >= 0), + update_interval INTEGER NOT NULL DEFAULT 900 CHECK (update_interval >= 1), + is_off INTEGER NOT NULL DEFAULT 0 CHECK (is_off >= 0 AND is_off <= 1), + is_quiet INTEGER NOT NULL DEFAULT 0 CHECK (is_quiet >= 0 AND is_quiet <= 1), + open_articles INTEGER NOT NULL DEFAULT 0 CHECK (open_articles >= 0 AND open_articles <= 1), + account_id INTEGER NOT NULL, + custom_id TEXT NOT NULL CHECK (custom_id != ''), /* Custom ID cannot be empty, it must contain either service-specific ID, or Feeds/id. */ + /* Custom column for (serialized) custom account-specific data. */ + custom_data TEXT, + + FOREIGN KEY (account_id) REFERENCES Accounts (id) ON DELETE CASCADE +); +-- ! +INSERT INTO Feeds (id, ordr, title, description, date_created, icon, category, source, update_type, update_interval, is_off, open_articles, account_id, custom_id, custom_data) +SELECT id, ordr, title, description, date_created, icon, category, source, update_type, update_interval, is_off, open_articles, account_id, custom_id, custom_data +FROM backup_Feeds; +-- ! +DROP TABLE backup_Feeds; \ No newline at end of file diff --git a/src/librssguard/database/databasequeries.cpp b/src/librssguard/database/databasequeries.cpp index 402c82916..5de60aa49 100644 --- a/src/librssguard/database/databasequeries.cpp +++ b/src/librssguard/database/databasequeries.cpp @@ -2072,7 +2072,8 @@ void DatabaseQueries::createOverwriteFeed(const QSqlDatabase& db, Feed* feed, in q.prepare("UPDATE Feeds " "SET title = :title, ordr = :ordr, description = :description, date_created = :date_created, " " icon = :icon, category = :category, source = :source, update_type = :update_type, " - " update_interval = :update_interval, is_off = :is_off, open_articles = :open_articles, " + " update_interval = :update_interval, is_off = :is_off, is_quiet = :is_quiet, open_articles = " + ":open_articles, " " account_id = :account_id, custom_id = :custom_id, custom_data = :custom_data " "WHERE id = :id;"); q.bindValue(QSL(":title"), feed->title()); @@ -2088,6 +2089,7 @@ void DatabaseQueries::createOverwriteFeed(const QSqlDatabase& db, Feed* feed, in q.bindValue(QSL(":id"), feed->id()); q.bindValue(QSL(":ordr"), feed->sortOrder()); q.bindValue(QSL(":is_off"), feed->isSwitchedOff()); + q.bindValue(QSL(":is_quiet"), feed->isQuiet()); q.bindValue(QSL(":open_articles"), feed->openArticlesDirectly()); auto custom_data = feed->customDatabaseData(); diff --git a/src/librssguard/database/databasequeries.h b/src/librssguard/database/databasequeries.h index 014aba460..37913768d 100644 --- a/src/librssguard/database/databasequeries.h +++ b/src/librssguard/database/databasequeries.h @@ -34,7 +34,9 @@ class DatabaseQueries { static bool assignLabelToMessage(const QSqlDatabase& db, Label* label, const Message& msg); static bool setLabelsForMessage(const QSqlDatabase& db, const QList& labels, const Message& msg); static QList getLabelsForAccount(const QSqlDatabase& db, int account_id); - static QList getLabelsForMessage(const QSqlDatabase& db, const Message& msg, const QList installed_labels); + static QList getLabelsForMessage(const QSqlDatabase& db, + const Message& msg, + const QList installed_labels); static bool updateLabel(const QSqlDatabase& db, Label* label); static bool deleteLabel(const QSqlDatabase& db, Label* label); static bool createLabel(const QSqlDatabase& db, Label* label, int account_id); @@ -45,7 +47,10 @@ class DatabaseQueries { static bool markUnreadMessagesRead(const QSqlDatabase& db, int account_id); static bool markMessagesReadUnread(const QSqlDatabase& db, const QStringList& ids, RootItem::ReadStatus read); static bool markMessageImportant(const QSqlDatabase& db, int id, RootItem::Importance importance); - static bool markFeedsReadUnread(const QSqlDatabase& db, const QStringList& ids, int account_id, RootItem::ReadStatus read); + static bool markFeedsReadUnread(const QSqlDatabase& db, + const QStringList& ids, + int account_id, + RootItem::ReadStatus read); static bool markBinReadUnread(const QSqlDatabase& db, int account_id, RootItem::ReadStatus read); static bool markAccountReadUnread(const QSqlDatabase& db, int account_id, RootItem::ReadStatus read); static bool switchMessagesImportance(const QSqlDatabase& db, const QStringList& ids); @@ -68,27 +73,44 @@ class DatabaseQueries { static bool purgeLabelsAndLabelAssignments(const QSqlDatabase& db, int account_id); // Counts of unread/all messages. - static QMap> getMessageCountsForCategory(const QSqlDatabase& db, const QString& custom_id, - int account_id, bool only_total_counts, + static QMap> getMessageCountsForCategory(const QSqlDatabase& db, + const QString& custom_id, + int account_id, + bool only_total_counts, bool* ok = nullptr); - static QMap> getMessageCountsForAccount(const QSqlDatabase& db, int account_id, - bool only_total_counts, bool* ok = nullptr); - static int getMessageCountsForFeed(const QSqlDatabase& db, const QString& feed_custom_id, int account_id, - bool only_total_counts, bool* ok = nullptr); - static int getMessageCountsForLabel(const QSqlDatabase& db, Label* label, int account_id, - bool only_total_counts, bool* ok = nullptr); - static int getImportantMessageCounts(const QSqlDatabase& db, int account_id, - bool only_total_counts, bool* ok = nullptr); + static QMap> getMessageCountsForAccount(const QSqlDatabase& db, + int account_id, + bool only_total_counts, + bool* ok = nullptr); + static int getMessageCountsForFeed(const QSqlDatabase& db, + const QString& feed_custom_id, + int account_id, + bool only_total_counts, + bool* ok = nullptr); + static int getMessageCountsForLabel(const QSqlDatabase& db, + Label* label, + int account_id, + bool only_total_counts, + bool* ok = nullptr); + static int getImportantMessageCounts(const QSqlDatabase& db, + int account_id, + bool only_total_counts, + bool* ok = nullptr); static int getUnreadMessageCounts(const QSqlDatabase& db, int account_id, bool* ok = nullptr); - static int getMessageCountsForBin(const QSqlDatabase& db, int account_id, bool including_total_counts, bool* ok = nullptr); + static int getMessageCountsForBin(const QSqlDatabase& db, + int account_id, + bool including_total_counts, + bool* ok = nullptr); // Get messages (for newspaper view for example). static QList getUndeletedMessagesWithLabel(const QSqlDatabase& db, const Label* label, bool* ok = nullptr); static QList getUndeletedLabelledMessages(const QSqlDatabase& db, int account_id, bool* ok = nullptr); static QList getUndeletedImportantMessages(const QSqlDatabase& db, int account_id, bool* ok = nullptr); static QList getUndeletedUnreadMessages(const QSqlDatabase& db, int account_id, bool* ok = nullptr); - static QList getUndeletedMessagesForFeed(const QSqlDatabase& db, const QString& feed_custom_id, - int account_id, bool* ok = nullptr); + static QList getUndeletedMessagesForFeed(const QSqlDatabase& db, + const QString& feed_custom_id, + int account_id, + bool* ok = nullptr); static QList getUndeletedMessagesForBin(const QSqlDatabase& db, int account_id, bool* ok = nullptr); static QList getUndeletedMessagesForAccount(const QSqlDatabase& db, int account_id, bool* ok = nullptr); @@ -100,23 +122,30 @@ class DatabaseQueries { static QStringList customIdsOfUnreadMessages(const QSqlDatabase& db, int account_id, bool* ok = nullptr); static QStringList customIdsOfMessagesFromAccount(const QSqlDatabase& db, int account_id, bool* ok = nullptr); static QStringList customIdsOfMessagesFromBin(const QSqlDatabase& db, int account_id, bool* ok = nullptr); - static QStringList customIdsOfMessagesFromFeed(const QSqlDatabase& db, const QString& feed_custom_id, int account_id, + static QStringList customIdsOfMessagesFromFeed(const QSqlDatabase& db, + const QString& feed_custom_id, + int account_id, bool* ok = nullptr); // Common account methods. - template + template static QList getAccounts(const QSqlDatabase& db, const QString& code, bool* ok = nullptr); - template - static void loadRootFromDatabase(ServiceRoot* root); + template static void loadRootFromDatabase(ServiceRoot* root); static bool storeNewOauthTokens(const QSqlDatabase& db, const QString& refresh_token, int account_id); static void createOverwriteAccount(const QSqlDatabase& db, ServiceRoot* account); // Returns counts of updated messages . - static QPair updateMessages(QSqlDatabase db, QList& messages, - Feed* feed, bool force_update, bool* ok = nullptr); + static QPair updateMessages(QSqlDatabase db, + QList& messages, + Feed* feed, + bool force_update, + bool* ok = nullptr); static bool deleteAccount(const QSqlDatabase& db, ServiceRoot* account); - static bool deleteAccountData(const QSqlDatabase& db, int account_id, bool delete_messages_too, bool delete_labels_too); + static bool deleteAccountData(const QSqlDatabase& db, + int account_id, + bool delete_messages_too, + bool delete_labels_too); static bool cleanLabelledMessages(const QSqlDatabase& db, bool clean_read_only, Label* label); static bool cleanImportantMessages(const QSqlDatabase& db, bool clean_read_only, int account_id); static bool cleanUnreadMessages(const QSqlDatabase& db, int account_id); @@ -127,12 +156,13 @@ class DatabaseQueries { static bool deleteFeed(const QSqlDatabase& db, Feed* feed, int account_id); static bool deleteCategory(const QSqlDatabase& db, Category* category); - template - static Assignment getCategories(const QSqlDatabase& db, int account_id, bool* ok = nullptr); + template static Assignment getCategories(const QSqlDatabase& db, int account_id, bool* ok = nullptr); - template - static Assignment getFeeds(const QSqlDatabase& db, const QList& global_filters, - int account_id, bool* ok = nullptr); + template + static Assignment getFeeds(const QSqlDatabase& db, + const QList& global_filters, + int account_id, + bool* ok = nullptr); // Item order methods. static void moveItem(RootItem* item, bool move_top, bool move_bottom, int move_index, const QSqlDatabase& db); @@ -144,11 +174,17 @@ class DatabaseQueries { static void removeMessageFilterAssignments(const QSqlDatabase& db, int filter_id, bool* ok = nullptr); static QList getMessageFilters(const QSqlDatabase& db, bool* ok = nullptr); static QMultiMap messageFiltersInFeeds(const QSqlDatabase& db, int account_id, bool* ok = nullptr); - static void assignMessageFilterToFeed(const QSqlDatabase& db, const QString& feed_custom_id, int filter_id, - int account_id, bool* ok = nullptr); + static void assignMessageFilterToFeed(const QSqlDatabase& db, + const QString& feed_custom_id, + int filter_id, + int account_id, + bool* ok = nullptr); static void updateMessageFilter(const QSqlDatabase& db, MessageFilter* filter, bool* ok = nullptr); - static void removeMessageFilterFromFeed(const QSqlDatabase& db, const QString& feed_custom_id, int filter_id, - int account_id, bool* ok = nullptr); + static void removeMessageFilterFromFeed(const QSqlDatabase& db, + const QString& feed_custom_id, + int filter_id, + int account_id, + bool* ok = nullptr); // Gmail account. static QStringList getAllGmailRecipients(const QSqlDatabase& db, int account_id); @@ -159,7 +195,7 @@ class DatabaseQueries { explicit DatabaseQueries() = default; }; -template +template QList DatabaseQueries::getAccounts(const QSqlDatabase& db, const QString& code, bool* ok) { QSqlQuery query(db); QList roots; @@ -189,11 +225,8 @@ QList DatabaseQueries::getAccounts(const QSqlDatabase& db, const Q } } else { - qWarningNN << LOGSEC_DB - << "Loading of accounts with code" - << QUOTE_W_SPACE(code) - << "failed with error:" - << QUOTE_W_SPACE_DOT(query.lastError().text()); + qWarningNN << LOGSEC_DB << "Loading of accounts with code" << QUOTE_W_SPACE(code) + << "failed with error:" << QUOTE_W_SPACE_DOT(query.lastError().text()); if (ok != nullptr) { *ok = false; @@ -203,8 +236,7 @@ QList DatabaseQueries::getAccounts(const QSqlDatabase& db, const Q return roots; } -template -Assignment DatabaseQueries::getCategories(const QSqlDatabase& db, int account_id, bool* ok) { +template Assignment DatabaseQueries::getCategories(const QSqlDatabase& db, int account_id, bool* ok) { Assignment categories; // Obtain data for categories from the database. @@ -215,7 +247,8 @@ Assignment DatabaseQueries::getCategories(const QSqlDatabase& db, int account_id query_categories.bindValue(QSL(":account_id"), account_id); if (!query_categories.exec()) { - qFatal("Query for obtaining categories failed. Error message: '%s'.", qPrintable(query_categories.lastError().text())); + qFatal("Query for obtaining categories failed. Error message: '%s'.", + qPrintable(query_categories.lastError().text())); if (ok != nullptr) { *ok = false; @@ -254,7 +287,7 @@ Assignment DatabaseQueries::getCategories(const QSqlDatabase& db, int account_id return categories; } -template +template Assignment DatabaseQueries::getFeeds(const QSqlDatabase& db, const QList& global_filters, int account_id, @@ -306,11 +339,10 @@ Assignment DatabaseQueries::getFeeds(const QSqlDatabase& db, feed->setAutoUpdateType(static_cast(query.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); feed->setAutoUpdateInterval(query.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); feed->setIsSwitchedOff(query.value(FDS_DB_IS_OFF_INDEX).toBool()); + feed->setIsQuiet(query.value(FDS_DB_IS_QUIET_INDEX).toBool()); feed->setOpenArticlesDirectly(query.value(FDS_DB_OPEN_ARTICLES_INDEX).toBool()); - qDebugNN << LOGSEC_CORE - << "Custom ID of feed when loading from DB is" - << QUOTE_W_SPACE_DOT(feed->customId()); + qDebugNN << LOGSEC_CORE << "Custom ID of feed when loading from DB is" << QUOTE_W_SPACE_DOT(feed->customId()); // Load custom data. feed->setCustomDatabaseData(deserializeCustomData(query.value(FDS_DB_CUSTOM_DATA_INDEX).toString())); @@ -333,8 +365,7 @@ Assignment DatabaseQueries::getFeeds(const QSqlDatabase& db, return feeds; } -template -void DatabaseQueries::loadRootFromDatabase(ServiceRoot* root) { +template void DatabaseQueries::loadRootFromDatabase(ServiceRoot* root) { QSqlDatabase database = qApp->database()->driver()->connection(root->metaObject()->className()); Assignment categories = DatabaseQueries::getCategories(database, root->accountId()); Assignment feeds = DatabaseQueries::getFeeds(database, qApp->feedReader()->messageFilters(), root->accountId()); diff --git a/src/librssguard/definitions/definitions.h b/src/librssguard/definitions/definitions.h index e7ba14adc..3287a81ae 100644 --- a/src/librssguard/definitions/definitions.h +++ b/src/librssguard/definitions/definitions.h @@ -205,7 +205,7 @@ #define APP_DB_SQLITE_FILE "database.db" // Keep this in sync with schema versions declared in SQL initialization code. -#define APP_DB_SCHEMA_VERSION "3" +#define APP_DB_SCHEMA_VERSION "4" #define APP_DB_UPDATE_FILE_PATTERN "db_update_%1_%2_%3.sql" #define APP_DB_COMMENT_SPLIT "-- !\n" #define APP_DB_INCLUDE_PLACEHOLDER "!!" @@ -284,10 +284,11 @@ #define FDS_DB_UPDATE_TYPE_INDEX 8 #define FDS_DB_UPDATE_INTERVAL_INDEX 9 #define FDS_DB_IS_OFF_INDEX 10 -#define FDS_DB_OPEN_ARTICLES_INDEX 11 -#define FDS_DB_ACCOUNT_ID_INDEX 12 -#define FDS_DB_CUSTOM_ID_INDEX 13 -#define FDS_DB_CUSTOM_DATA_INDEX 14 +#define FDS_DB_IS_QUIET_INDEX 11 +#define FDS_DB_OPEN_ARTICLES_INDEX 12 +#define FDS_DB_ACCOUNT_ID_INDEX 13 +#define FDS_DB_CUSTOM_ID_INDEX 14 +#define FDS_DB_CUSTOM_DATA_INDEX 15 // Indexes of columns for feed models. #define FDS_MODEL_TITLE_INDEX 0 diff --git a/src/librssguard/services/abstract/feed.cpp b/src/librssguard/services/abstract/feed.cpp index a705ce259..882d74df7 100644 --- a/src/librssguard/services/abstract/feed.cpp +++ b/src/librssguard/services/abstract/feed.cpp @@ -22,8 +22,8 @@ Feed::Feed(RootItem* parent) : RootItem(parent), m_source(QString()), m_status(Status::Normal), m_statusString(QString()), m_autoUpdateType(AutoUpdateType::DefaultAutoUpdate), m_autoUpdateInterval(DEFAULT_AUTO_UPDATE_INTERVAL), - m_lastUpdated(QDateTime::currentDateTimeUtc()), m_isSwitchedOff(false), m_openArticlesDirectly(false), - m_messageFilters(QList>()) { + m_lastUpdated(QDateTime::currentDateTimeUtc()), m_isSwitchedOff(false), m_isQuiet(false), + m_openArticlesDirectly(false), m_messageFilters(QList>()) { setKind(RootItem::Kind::Feed); } @@ -46,6 +46,7 @@ Feed::Feed(const Feed& other) : RootItem(other) { setMessageFilters(other.messageFilters()); setOpenArticlesDirectly(other.openArticlesDirectly()); setIsSwitchedOff(other.isSwitchedOff()); + setIsQuiet(other.isQuiet()); } QList Feed::undeletedMessages() const { @@ -283,6 +284,14 @@ QString Feed::getStatusDescription() const { } } +bool Feed::isQuiet() const { + return m_isQuiet; +} + +void Feed::setIsQuiet(bool quiet) { + m_isQuiet = quiet; +} + QDateTime Feed::lastUpdated() const { return m_lastUpdated; } diff --git a/src/librssguard/services/abstract/feed.h b/src/librssguard/services/abstract/feed.h index cc2195a57..7522f2ac0 100644 --- a/src/librssguard/services/abstract/feed.h +++ b/src/librssguard/services/abstract/feed.h @@ -72,6 +72,9 @@ class Feed : public RootItem { bool isSwitchedOff() const; void setIsSwitchedOff(bool switched_off); + bool isQuiet() const; + void setIsQuiet(bool quiet); + void appendMessageFilter(MessageFilter* filter); QList> messageFilters() const; void setMessageFilters(const QList>& messageFilters); @@ -79,7 +82,6 @@ class Feed : public RootItem { QDateTime lastUpdated() const; void setLastUpdated(const QDateTime& last_updated); - public slots: virtual void updateCounts(bool including_total_count); @@ -95,6 +97,7 @@ class Feed : public RootItem { int m_autoUpdateInterval{}; // In seconds. QDateTime m_lastUpdated; bool m_isSwitchedOff; + bool m_isQuiet; bool m_openArticlesDirectly; int m_totalCount{}; int m_unreadCount{}; diff --git a/src/librssguard/services/abstract/gui/formfeeddetails.cpp b/src/librssguard/services/abstract/gui/formfeeddetails.cpp index 76f86a0f9..4adb9b1f5 100644 --- a/src/librssguard/services/abstract/gui/formfeeddetails.cpp +++ b/src/librssguard/services/abstract/gui/formfeeddetails.cpp @@ -50,6 +50,7 @@ void FormFeedDetails::apply() { m_feed->setAutoUpdateInterval(int(m_ui->m_spinAutoUpdateInterval->value())); m_feed->setOpenArticlesDirectly(m_ui->m_cbOpenArticlesAutomatically->isChecked()); m_feed->setIsSwitchedOff(m_ui->m_cbDisableFeed->isChecked()); + m_feed->setIsQuiet(m_ui->m_cbSuppressFeed->isChecked()); if (!m_creatingNew) { // We need to make sure that common data are saved. @@ -97,6 +98,7 @@ void FormFeedDetails::loadFeedData() { m_ui->m_spinAutoUpdateInterval->setValue(m_feed->autoUpdateInterval()); m_ui->m_cbOpenArticlesAutomatically->setChecked(m_feed->openArticlesDirectly()); m_ui->m_cbDisableFeed->setChecked(m_feed->isSwitchedOff()); + m_ui->m_cbSuppressFeed->setChecked(m_feed->isQuiet()); } void FormFeedDetails::acceptIfPossible() { diff --git a/src/librssguard/services/abstract/gui/formfeeddetails.ui b/src/librssguard/services/abstract/gui/formfeeddetails.ui index 30899ae4a..92a388c56 100644 --- a/src/librssguard/services/abstract/gui/formfeeddetails.ui +++ b/src/librssguard/services/abstract/gui/formfeeddetails.ui @@ -66,13 +66,20 @@ Miscellaneous - + Disable this feed + + + + Suppress this feed + + + @@ -99,6 +106,14 @@
timespinbox.h
+ + m_tabWidget + m_cmbAutoUpdateType + m_spinAutoUpdateInterval + m_cbOpenArticlesAutomatically + m_cbSuppressFeed + m_cbDisableFeed + diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp index 6b67ec8db..e9ab1d0bf 100644 --- a/src/librssguard/services/abstract/serviceroot.cpp +++ b/src/librssguard/services/abstract/serviceroot.cpp @@ -374,6 +374,7 @@ QMap ServiceRoot::storeCustomFeedsData() { feed_custom_data.insert(QSL("auto_update_type"), int(feed->autoUpdateType())); feed_custom_data.insert(QSL("msg_filters"), QVariant::fromValue(feed->messageFilters())); feed_custom_data.insert(QSL("is_off"), feed->isSwitchedOff()); + feed_custom_data.insert(QSL("is_quiet"), feed->isQuiet()); feed_custom_data.insert(QSL("open_articles_directly"), feed->openArticlesDirectly()); // NOTE: These are here specifically to be able to restore custom sort order. @@ -406,6 +407,7 @@ void ServiceRoot::restoreCustomFeedsData(const QMap& data, feed->setMessageFilters(feed_custom_data.value(QSL("msg_filters")).value>>()); feed->setIsSwitchedOff(feed_custom_data.value(QSL("is_off")).toBool()); + feed->setIsQuiet(feed_custom_data.value(QSL("is_quiet")).toBool()); feed->setOpenArticlesDirectly(feed_custom_data.value(QSL("open_articles_directly")).toBool()); } } From f77ed37c89a4fe8192c9155cbc19295e6470db60 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 3 Dec 2022 09:28:52 +0100 Subject: [PATCH 2/9] work on #745 --- src/librssguard/services/abstract/gui/formfeeddetails.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librssguard/services/abstract/gui/formfeeddetails.ui b/src/librssguard/services/abstract/gui/formfeeddetails.ui index 92a388c56..f874c739a 100644 --- a/src/librssguard/services/abstract/gui/formfeeddetails.ui +++ b/src/librssguard/services/abstract/gui/formfeeddetails.ui @@ -76,7 +76,7 @@ - Suppress this feed + Ignore notifications for this feed From 6877044a57f942ecd8b67b62450b086806aeaba9 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 3 Dec 2022 09:42:26 +0100 Subject: [PATCH 3/9] implemented #745 --- src/librssguard/core/feeddownloader.cpp | 10 +++++----- src/librssguard/core/feeddownloader.h | 6 +++--- src/librssguard/miscellaneous/application.cpp | 7 ++++++- src/librssguard/miscellaneous/feedreader.cpp | 14 +++++++++----- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/librssguard/core/feeddownloader.cpp b/src/librssguard/core/feeddownloader.cpp index 234b01b36..0e1913fa4 100644 --- a/src/librssguard/core/feeddownloader.cpp +++ b/src/librssguard/core/feeddownloader.cpp @@ -391,7 +391,7 @@ void FeedDownloader::updateOneFeed(ServiceRoot* acc, << " stored in DB."; if (updated_messages.first > 0) { - m_results.appendUpdatedFeed({feed->title(), updated_messages.first}); + m_results.appendUpdatedFeed({feed, updated_messages.first}); } } catch (const FeedFetchException& feed_ex) { @@ -500,7 +500,7 @@ QString FeedDownloadResults::overview(int how_many_feeds) const { QStringList result; for (int i = 0, number_items_output = qMin(how_many_feeds, m_updatedFeeds.size()); i < number_items_output; i++) { - result.append(m_updatedFeeds.at(i).first + QSL(": ") + QString::number(m_updatedFeeds.at(i).second)); + result.append(m_updatedFeeds.at(i).first->title() + QSL(": ") + QString::number(m_updatedFeeds.at(i).second)); } QString res_str = result.join(QSL("\n")); @@ -512,14 +512,14 @@ QString FeedDownloadResults::overview(int how_many_feeds) const { return res_str; } -void FeedDownloadResults::appendUpdatedFeed(const QPair& feed) { +void FeedDownloadResults::appendUpdatedFeed(const QPair& feed) { m_updatedFeeds.append(feed); } void FeedDownloadResults::sort() { std::sort(m_updatedFeeds.begin(), m_updatedFeeds.end(), - [](const QPair& lhs, const QPair& rhs) { + [](const QPair& lhs, const QPair& rhs) { return lhs.second > rhs.second; }); } @@ -528,6 +528,6 @@ void FeedDownloadResults::clear() { m_updatedFeeds.clear(); } -QList> FeedDownloadResults::updatedFeeds() const { +QList> FeedDownloadResults::updatedFeeds() const { return m_updatedFeeds; } diff --git a/src/librssguard/core/feeddownloader.h b/src/librssguard/core/feeddownloader.h index 8041864eb..600e8291e 100644 --- a/src/librssguard/core/feeddownloader.h +++ b/src/librssguard/core/feeddownloader.h @@ -18,16 +18,16 @@ class QMutex; // Represents results of batch feed updates. class FeedDownloadResults { public: - QList> updatedFeeds() const; + QList> updatedFeeds() const; QString overview(int how_many_feeds) const; - void appendUpdatedFeed(const QPair& feed); + void appendUpdatedFeed(const QPair& feed); void sort(); void clear(); private: // QString represents title if the feed, int represents count of newly downloaded messages. - QList> m_updatedFeeds; + QList> m_updatedFeeds; }; // This class offers means to "update" feeds and "special" categories. diff --git a/src/librssguard/miscellaneous/application.cpp b/src/librssguard/miscellaneous/application.cpp index 962b33095..a779e7db5 100644 --- a/src/librssguard/miscellaneous/application.cpp +++ b/src/librssguard/miscellaneous/application.cpp @@ -890,7 +890,12 @@ void Application::onFeedUpdatesProgress(const Feed* feed, int current, int total } void Application::onFeedUpdatesFinished(const FeedDownloadResults& results) { - if (!results.updatedFeeds().isEmpty()) { + auto fds = results.updatedFeeds(); + bool some_unquiet_feed = boolinq::from(fds).any([](const QPair& fd) { + return !fd.first->isQuiet(); + }); + + if (some_unquiet_feed) { // Now, inform about results via GUI message/notification. qApp->showGuiMessage(Notification::Event::NewUnreadArticlesFetched, {tr("Unread articles fetched"), results.overview(10), QSystemTrayIcon::MessageIcon::NoIcon}); diff --git a/src/librssguard/miscellaneous/feedreader.cpp b/src/librssguard/miscellaneous/feedreader.cpp index 73f4c04ff..0e7727ab4 100644 --- a/src/librssguard/miscellaneous/feedreader.cpp +++ b/src/librssguard/miscellaneous/feedreader.cpp @@ -336,11 +336,15 @@ void FeedReader::executeNextAutoUpdate() { // Request update for given feeds. updateFeeds(feeds_for_update); - // NOTE: OSD/bubble informing about performing of scheduled update can be shown now. - qApp->showGuiMessage(Notification::Event::ArticlesFetchingStarted, - {tr("Starting auto-download of some feeds' articles"), - tr("I will auto-download new articles for %n feed(s).", nullptr, feeds_for_update.size()), - QSystemTrayIcon::MessageIcon::Information}); + if (boolinq::from(feeds_for_update).any([](const Feed* fd) { + return !fd->isQuiet(); + })) { + // NOTE: OSD/bubble informing about performing of scheduled update can be shown now. + qApp->showGuiMessage(Notification::Event::ArticlesFetchingStarted, + {tr("Starting auto-download of some feeds' articles"), + tr("I will auto-download new articles for %n feed(s).", nullptr, feeds_for_update.size()), + QSystemTrayIcon::MessageIcon::Information}); + } } } From ad31cec373c7502ff8d3db0bfdeea9adef80e42c Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 3 Dec 2022 18:43:31 +0100 Subject: [PATCH 4/9] fix appimage, revert to qt5, polish build script --- .../scripts/github-actions/build-linux-mac.sh | 87 ++++++++++--------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/resources/scripts/github-actions/build-linux-mac.sh b/resources/scripts/github-actions/build-linux-mac.sh index 3a2c093c1..d799fd6a7 100755 --- a/resources/scripts/github-actions/build-linux-mac.sh +++ b/resources/scripts/github-actions/build-linux-mac.sh @@ -18,40 +18,42 @@ echo "OS: $os; WebEngine: $webengine" # Install needed dependencies. if [ $is_linux = true ]; then - sudo apt update - - sudo apt -qy install libgl1-mesa-dev gstreamer1.0-alsa gstreamer1.0-plugins-good gstreamer1.0-plugins-base gstreamer1.0-plugins-bad gstreamer1.0-qt5 gstreamer1.0-pulseaudio libodbc1 postgresql python3-pip - + # Qt 5. QTTARGET="linux" QTOS="gcc_64" - QTARCH="gcc_64" -else + QTARCH="gcc_64" + USE_QT6="OFF" + sudo add-apt-repository ppa:beineri/opt-qt-5.15.2-bionic -y + sudo apt-get update + + sudo apt-get -qy install qt515tools qt515base qt515webengine qt515svg qt515multimedia + sudo apt-get -qy install cmake ninja-build openssl libssl-dev libgl1-mesa-dev gstreamer1.0-alsa gstreamer1.0-plugins-good gstreamer1.0-plugins-base gstreamer1.0-plugins-bad gstreamer1.0-qt5 gstreamer1.0-pulseaudio + + source /opt/qt515/bin/qt515-env.sh +else + # Qt 6. QTTARGET="mac" QTOS="macos" - QTARCH="clang_64" -fi + QTARCH="clang_64" + USE_QT6="ON" -pip3 install aqtinstall + QTPATH="$(pwd)/Qt" + QTVERSION="6.4.1" + QTBIN="$QTPATH/$QTVERSION/$QTOS/bin" -# Setup Qt information. -QTPATH="$(pwd)/Qt" -QTVERSION="6.3.1" -QTBIN="$QTPATH/$QTVERSION/$QTOS/bin" + pip3 install aqtinstall -export QT_PLUGIN_PATH="$QTPATH/$QTVERSION/$QTOS/plugins" -export PATH="$QTBIN:$QTPATH/Tools/CMake/bin:$QTPATH/Tools/Ninja:$PATH" + echo "Qt bin directory is: $QTBIN" + echo "Qt will be installed to: $QTPATH" -echo "Qt bin directory is: $QTBIN" -echo "Qt will be installed to: $QTPATH" + # Install Qt. + aqt install-qt -O "$QTPATH" "$QTTARGET" "desktop" "$QTVERSION" "$QTARCH" -m "qtwebengine" "qtwebchannel" "qtmultimedia" "qt5compat" "qtpositioning" "qtserialport" + aqt install-tool -O "$QTPATH" "$QTTARGET" "desktop" "tools_cmake" + aqt install-tool -O "$QTPATH" "$QTTARGET" "desktop" "tools_ninja" -# Install Qt. -aqt install-qt -O "$QTPATH" "$QTTARGET" "desktop" "$QTVERSION" "$QTARCH" -m "qtwebengine" "qtwebchannel" "qtmultimedia" "qt5compat" "qtpositioning" "qtserialport" -aqt install-tool -O "$QTPATH" "$QTTARGET" "desktop" "tools_cmake" -aqt install-tool -O "$QTPATH" "$QTTARGET" "desktop" "tools_ninja" - -if [ $is_linux = true ]; then - aqt install-tool -O "$QTPATH" "$QTTARGET" "desktop" "tools_openssl_x64" + export QT_PLUGIN_PATH="$QTPATH/$QTVERSION/$QTOS/plugins" + export PATH="$QTBIN:$QTPATH/Tools/CMake/bin:$QTPATH/Tools/Ninja:$PATH" fi cmake --version @@ -61,40 +63,39 @@ git_tag=$(git describe --tags $(git rev-list --tags --max-count=1)) git_revision=$(git rev-parse --short HEAD) mkdir rssguard-build && cd rssguard-build -cmake .. -G Ninja -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DFORCE_BUNDLE_ICONS="ON" -DCMAKE_BUILD_TYPE="MinSizeRel" -DCMAKE_INSTALL_PREFIX="$prefix" -DREVISION_FROM_GIT="ON" -DBUILD_WITH_QT6="ON" -DUSE_WEBENGINE="$webengine" -DFEEDLY_CLIENT_ID="$FEEDLY_CLIENT_ID" -DFEEDLY_CLIENT_SECRET="$FEEDLY_CLIENT_SECRET" -DGMAIL_CLIENT_ID="$GMAIL_CLIENT_ID" -DGMAIL_CLIENT_SECRET="$GMAIL_CLIENT_SECRET" + +cmake .. -G Ninja -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DFORCE_BUNDLE_ICONS="ON" -DCMAKE_BUILD_TYPE="MinSizeRel" -DCMAKE_INSTALL_PREFIX="$prefix" -DREVISION_FROM_GIT="ON" -DBUILD_WITH_QT6="$USE_QT6" -DUSE_WEBENGINE="$webengine" -DFEEDLY_CLIENT_ID="$FEEDLY_CLIENT_ID" -DFEEDLY_CLIENT_SECRET="$FEEDLY_CLIENT_SECRET" -DGMAIL_CLIENT_ID="$GMAIL_CLIENT_ID" -DGMAIL_CLIENT_SECRET="$GMAIL_CLIENT_SECRET" cmake --build . cmake --install . --prefix "$prefix" if [ $is_linux = true ]; then - # Obtain linuxdeploy. - wget -qc https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage - wget -qc https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage - wget -qc https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gstreamer/master/linuxdeploy-plugin-gstreamer.sh - - chmod a+x linuxdeploy*.AppImage linuxdeploy*.sh + # Obtain linuxdeployqt. + wget -qc https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage + chmod a+x linuxdeployqt-continuous-x86_64.AppImage # Copy Gstreamer libs. install -v -Dm755 "/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner" "AppDir/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner" + gst_executables="-executable=AppDir/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner" - for plugin in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/*; do + for plugin in /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgst*.so; do basen=$(basename "$plugin") - install -v -Dm755 "$plugin" "./AppDir/usr/lib/gstreamer-1.0/$basen" + install -v -Dm755 "$plugin" "AppDir/usr/lib/gstreamer-1.0/$basen" + gst_executables="${gst_executables} -executable=AppDir/usr/lib/gstreamer-1.0/$basen" done + echo "Gstream command line for AppImage is: $gst_executables" + + # Create AppImage. + unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH + ./linuxdeployqt-continuous-x86_64.AppImage "./AppDir/usr/share/applications/com.github.rssguard.desktop" -bundle-non-qt-libs -no-translations $gst_executables + ./linuxdeployqt-continuous-x86_64.AppImage "./AppDir/usr/share/applications/com.github.rssguard.desktop" -bundle-non-qt-libs -no-translations $gst_executables + if [[ "$webengine" == "ON" ]]; then # Copy some NSS3 files to prevent WebEngine crashes. cp /usr/lib/x86_64-linux-gnu/nss/* ./AppDir/usr/lib/ -v fi - # Fix some missing Qt folders. - mkdir "$QTPATH/$QTVERSION/$QTOS/plugins/audio" - mkdir "$QTPATH/$QTVERSION/$QTOS/plugins/mediaservice" - - # Adjust library search paths. - export LD_LIBRARY_PATH="$QTPATH/$QTVERSION/$QTOS/lib:$(pwd)/AppDir/usr/lib" - - # Create AppImage. - ./linuxdeploy-x86_64.AppImage --output "appimage" --plugin "qt" --appdir "AppDir" + ./linuxdeployqt-continuous-x86_64.AppImage "./AppDir/usr/share/applications/com.github.rssguard.desktop" -appimage -no-translations $gst_executables # Rename AppImaage. set -- R*.AppImage @@ -128,4 +129,4 @@ else fi mv "$imagename" "$imagenewname" -ls +ls \ No newline at end of file From 39bb467a3fc402289215c2fb7499e08f55b63180 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 3 Dec 2022 18:47:54 +0100 Subject: [PATCH 5/9] fix workflox --- .github/workflows/rssguard.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rssguard.yml b/.github/workflows/rssguard.yml index e3552a302..dac90a188 100644 --- a/.github/workflows/rssguard.yml +++ b/.github/workflows/rssguard.yml @@ -12,19 +12,19 @@ jobs: runs-on: "${{ matrix.os }}" strategy: matrix: - os: [windows-2019, ubuntu-20.04, macos-10.15] + os: [windows-2019, ubuntu-18.04, macos-10.15] use_webengine: ["ON", "OFF"] use_qt5: ["ON", "OFF"] include: - os: windows-2019 script_name: .\resources\scripts\github-actions\build-windows.ps1 - - os: ubuntu-20.04 + - os: ubuntu-18.04 script_name: ./resources/scripts/github-actions/build-linux-mac.sh - os: macos-10.15 script_name: ./resources/scripts/github-actions/build-linux-mac.sh exclude: - - os: ubuntu-20.04 - use_qt5: "ON" + - os: ubuntu-18.04 + use_qt5: "OFF" - os: macos-10.15 use_qt5: "ON" steps: From 3169d753fb0ac8cb7e916fe4804df23b5c737997 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sat, 3 Dec 2022 18:58:32 +0100 Subject: [PATCH 6/9] fix build --- resources/scripts/github-actions/build-linux-mac.sh | 6 +++--- resources/scripts/github-actions/build-windows.ps1 | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/scripts/github-actions/build-linux-mac.sh b/resources/scripts/github-actions/build-linux-mac.sh index d799fd6a7..de772f10a 100755 --- a/resources/scripts/github-actions/build-linux-mac.sh +++ b/resources/scripts/github-actions/build-linux-mac.sh @@ -87,15 +87,15 @@ if [ $is_linux = true ]; then # Create AppImage. unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH - ./linuxdeployqt-continuous-x86_64.AppImage "./AppDir/usr/share/applications/com.github.rssguard.desktop" -bundle-non-qt-libs -no-translations $gst_executables - ./linuxdeployqt-continuous-x86_64.AppImage "./AppDir/usr/share/applications/com.github.rssguard.desktop" -bundle-non-qt-libs -no-translations $gst_executables + ./linuxdeployqt-continuous-x86_64.AppImage "./AppDir/usr/share/applications/io.github.martinrotter.rssguard.desktop" -bundle-non-qt-libs -no-translations $gst_executables + ./linuxdeployqt-continuous-x86_64.AppImage "./AppDir/usr/share/applications/io.github.martinrotter.rssguard.desktop" -bundle-non-qt-libs -no-translations $gst_executables if [[ "$webengine" == "ON" ]]; then # Copy some NSS3 files to prevent WebEngine crashes. cp /usr/lib/x86_64-linux-gnu/nss/* ./AppDir/usr/lib/ -v fi - ./linuxdeployqt-continuous-x86_64.AppImage "./AppDir/usr/share/applications/com.github.rssguard.desktop" -appimage -no-translations $gst_executables + ./linuxdeployqt-continuous-x86_64.AppImage "./AppDir/usr/share/applications/io.github.martinrotter.rssguard.desktop" -appimage -no-translations $gst_executables # Rename AppImaage. set -- R*.AppImage diff --git a/resources/scripts/github-actions/build-windows.ps1 b/resources/scripts/github-actions/build-windows.ps1 index ee3b35086..f1c900ef9 100755 --- a/resources/scripts/github-actions/build-windows.ps1 +++ b/resources/scripts/github-actions/build-windows.ps1 @@ -25,7 +25,7 @@ if ($use_qt5 -eq "ON") { $qt_version = "5.15.2" } else { - $qt_version = "6.3.2" + $qt_version = "6.4.1" } $maria_version = "10.6.11" From a3eeb4419e5f0c05cb45527e2d0402309b8950e5 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Sun, 4 Dec 2022 10:03:22 +0100 Subject: [PATCH 7/9] fixed #835 --- src/librssguard/definitions/definitions.h | 3 +++ src/librssguard/miscellaneous/application.cpp | 25 ++++++++++++++++--- src/librssguard/miscellaneous/application.h | 2 +- .../network-web/basenetworkaccessmanager.cpp | 10 +++++++- src/librssguard/network-web/webfactory.cpp | 10 +++++++- src/librssguard/network-web/webfactory.h | 4 +++ 6 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/librssguard/definitions/definitions.h b/src/librssguard/definitions/definitions.h index 3287a81ae..65be2e0ab 100644 --- a/src/librssguard/definitions/definitions.h +++ b/src/librssguard/definitions/definitions.h @@ -118,6 +118,9 @@ #define CLI_SIN_SHORT "s" #define CLI_SIN_LONG "no-single-instance" +#define CLI_USERAGENT_SHORT "u" +#define CLI_USERAGENT_LONG "user-agent" + #define CLI_ADBLOCKPORT_SHORT "p" #define CLI_ADBLOCKPORT_LONG "adblock-port" diff --git a/src/librssguard/miscellaneous/application.cpp b/src/librssguard/miscellaneous/application.cpp index a779e7db5..6c087c595 100644 --- a/src/librssguard/miscellaneous/application.cpp +++ b/src/librssguard/miscellaneous/application.cpp @@ -63,7 +63,10 @@ Application::Application(const QString& id, int& argc, char** argv, const QStringList& raw_cli_args) : SingleApplication(id, argc, argv), m_rawCliArgs(raw_cli_args), m_updateFeedsLock(new Mutex()) { - parseCmdArgumentsFromMyInstance(raw_cli_args); + QString custom_ua; + + parseCmdArgumentsFromMyInstance(raw_cli_args, custom_ua); + qInstallMessageHandler(performLogging); m_feedReader = nullptr; @@ -156,6 +159,8 @@ Application::Application(const QString& id, int& argc, char** argv, const QStrin } #endif + m_webFactory->setCustomUserAgent(custom_ua); + #if defined(USE_WEBENGINE) m_webFactory->urlIinterceptor()->load(); @@ -164,7 +169,13 @@ Application::Application(const QString& id, int& argc, char** argv, const QStrin m_webFactory->engineProfile()->setCachePath(web_data_root + QDir::separator() + QSL("cache")); m_webFactory->engineProfile()->setHttpCacheType(QWebEngineProfile::HttpCacheType::DiskHttpCache); m_webFactory->engineProfile()->setPersistentStoragePath(web_data_root + QDir::separator() + QSL("storage")); - m_webFactory->engineProfile()->setHttpUserAgent(QString(HTTP_COMPLETE_USERAGENT)); + + if (custom_ua.isEmpty()) { + m_webFactory->engineProfile()->setHttpUserAgent(QString(HTTP_COMPLETE_USERAGENT)); + } + else { + m_webFactory->engineProfile()->setHttpUserAgent(custom_ua); + } qDebugNN << LOGSEC_NETWORK << "Persistent web data storage path:" << QUOTE_W_SPACE_DOT(m_webFactory->engineProfile()->persistentStoragePath()); @@ -1004,7 +1015,7 @@ void Application::parseCmdArgumentsFromOtherInstance(const QString& message) { } } -void Application::parseCmdArgumentsFromMyInstance(const QStringList& raw_cli_args) { +void Application::parseCmdArgumentsFromMyInstance(const QStringList& raw_cli_args, QString& custom_ua) { fillCmdArgumentsParser(m_cmdParser); m_cmdParser.setApplicationDescription(QSL(APP_NAME)); @@ -1073,6 +1084,8 @@ void Application::parseCmdArgumentsFromMyInstance(const QStringList& raw_cli_arg else { m_customAdblockPort = 0; } + + custom_ua = m_cmdParser.value(QSL(CLI_USERAGENT_SHORT)); } void Application::displayLog() { @@ -1115,6 +1128,10 @@ void Application::fillCmdArgumentsParser(QCommandLineParser& parser) { QCommandLineOption forced_style({QSL(CLI_STYLE_SHORT), QSL(CLI_STYLE_LONG)}, QSL("Force some application style."), QSL("style-name")); + + QCommandLineOption custom_ua({QSL(CLI_USERAGENT_SHORT), QSL(CLI_USERAGENT_LONG)}, + QSL("User custom User-Agent HTTP header for all network requests."), + QSL("user-agent")); QCommandLineOption adblock_port({QSL(CLI_ADBLOCKPORT_SHORT), QSL(CLI_ADBLOCKPORT_LONG)}, QSL("Use custom port for AdBlock server. It is highly recommended to use values higher than 1024."), @@ -1125,7 +1142,7 @@ void Application::fillCmdArgumentsParser(QCommandLineParser& parser) { #if defined(USE_WEBENGINE) force_nowebengine, #endif - forced_style, adblock_port + forced_style, adblock_port, custom_ua }); parser.addPositionalArgument(QSL("urls"), QSL("List of URL addresses pointing to individual online feeds which should be added."), diff --git a/src/librssguard/miscellaneous/application.h b/src/librssguard/miscellaneous/application.h index 0025cbf87..f15ac86d8 100644 --- a/src/librssguard/miscellaneous/application.h +++ b/src/librssguard/miscellaneous/application.h @@ -187,7 +187,7 @@ class RSSGUARD_DLLSPEC Application : public SingleApplication { // Processes incoming message from another RSS Guard instance. void parseCmdArgumentsFromOtherInstance(const QString& message); - void parseCmdArgumentsFromMyInstance(const QStringList& raw_cli_args); + void parseCmdArgumentsFromMyInstance(const QStringList& raw_cli_args, QString &custom_ua); void displayLog(); diff --git a/src/librssguard/network-web/basenetworkaccessmanager.cpp b/src/librssguard/network-web/basenetworkaccessmanager.cpp index a7b2615b1..ef51ab3a5 100644 --- a/src/librssguard/network-web/basenetworkaccessmanager.cpp +++ b/src/librssguard/network-web/basenetworkaccessmanager.cpp @@ -62,7 +62,15 @@ QNetworkReply* BaseNetworkAccessManager::createRequest(QNetworkAccessManager::Op #endif new_request.setRawHeader(HTTP_HEADERS_COOKIE, QSL("JSESSIONID= ").toLocal8Bit()); - new_request.setRawHeader(HTTP_HEADERS_USER_AGENT, HTTP_COMPLETE_USERAGENT); + + auto custom_ua = qApp->web()->customUserAgent(); + + if (custom_ua.isEmpty()) { + new_request.setRawHeader(HTTP_HEADERS_USER_AGENT, HTTP_COMPLETE_USERAGENT); + } + else { + new_request.setRawHeader(HTTP_HEADERS_USER_AGENT, custom_ua.toLocal8Bit()); + } auto reply = QNetworkAccessManager::createRequest(op, new_request, outgoingData); return reply; diff --git a/src/librssguard/network-web/webfactory.cpp b/src/librssguard/network-web/webfactory.cpp index 5d859afd5..4a6a0ecc0 100644 --- a/src/librssguard/network-web/webfactory.cpp +++ b/src/librssguard/network-web/webfactory.cpp @@ -28,7 +28,7 @@ #include #endif -WebFactory::WebFactory(QObject* parent) : QObject(parent) { +WebFactory::WebFactory(QObject* parent) : QObject(parent), m_customUserAgent(QString()) { m_adBlock = new AdBlockManager(this); #if defined(USE_WEBENGINE) @@ -657,3 +657,11 @@ void WebFactory::generateUnescapes() { m_htmlNamedEntities[QSL("zwj")] = 0x200d; m_htmlNamedEntities[QSL("zwnj")] = 0x200c; } + +QString WebFactory::customUserAgent() const { + return m_customUserAgent; +} + +void WebFactory::setCustomUserAgent(const QString& user_agent) { + m_customUserAgent = user_agent; +} diff --git a/src/librssguard/network-web/webfactory.h b/src/librssguard/network-web/webfactory.h index a90ac7eb4..f7ab9b540 100644 --- a/src/librssguard/network-web/webfactory.h +++ b/src/librssguard/network-web/webfactory.h @@ -56,6 +56,9 @@ class WebFactory : public QObject { bool sendMessageViaEmail(const Message& message); #if defined(USE_WEBENGINE) + QString customUserAgent() const; + void setCustomUserAgent(const QString& user_agent); + private slots: void createMenu(QMenu* menu = nullptr); void webEngineSettingChanged(bool enabled); @@ -79,6 +82,7 @@ class WebFactory : public QObject { CookieJar* m_cookieJar; Readability* m_readability; QMap m_htmlNamedEntities; + QString m_customUserAgent; }; #endif // WEBFACTORY_H From 4c4e64c9142442aa1b9a0704c85d7ec7066f0157 Mon Sep 17 00:00:00 2001 From: akinokonomi <91767492+akinokonomi@users.noreply.github.com> Date: Sun, 4 Dec 2022 09:04:19 +0000 Subject: [PATCH 8/9] Update Documentation and README. (#852) Co-authored-by: akinokonomi --- README.md | 16 +- resources/docs/Documentation.md | 325 +++++++++++++++++--------------- 2 files changed, 182 insertions(+), 159 deletions(-) diff --git a/README.md b/README.md index 7f39057d1..da869b8f8 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,15 @@ RSS Guard ### [Discord server](https://discord.gg/7xbVMPPNqH) | [Downloads](https://github.com/martinrotter/rssguard/releases) | [Development builds](https://github.com/martinrotter/rssguard/releases/tag/devbuild) | [Documentation](https://github.com/martinrotter/rssguard/blob/master/resources/docs/Documentation.md) -RSS Guard is simple RSS/ATOM feed reader for Windows, Linux, BSD, OS/2 or macOS which can work with RSS/ATOM/JSON feeds and also supports many online feed services: -* [Feedly](https://feedly.com), -* [Gmail](https://developers.google.com/gmail/api), -* Google Reader API ([Bazqux](https://bazqux.com), [FreshRSS](https://freshrss.org), [Inoreader](https://www.inoreader.com), [Miniflux](https://miniflux.app), [Reedah](http://reedah.com), [The Old Reader](https://theoldreader.com) and others), -* [Nextcloud News](https://apps.nextcloud.com/apps/news), -* [Tiny Tiny RSS](https://tt-rss.org). +RSS Guard is a simple RSS/ATOM feed reader for Windows, Linux, BSD, OS/2 or macOS which can work with RSS/ATOM/JSON feeds as well as many online feed services: +* [Feedly](https://feedly.com) +* [Gmail](https://developers.google.com/gmail/api) +* Google Reader API ([Bazqux](https://bazqux.com), [FreshRSS](https://freshrss.org), [Inoreader](https://www.inoreader.com), [Miniflux](https://miniflux.app), [Reedah](http://reedah.com), [The Old Reader](https://theoldreader.com) and more) +* [Nextcloud News](https://apps.nextcloud.com/apps/news) +* [Tiny Tiny RSS](https://tt-rss.org) ![RSS Guard](resources/docs/videos/rssguard.gif) Contributed graphics: -* RSS Guard logo - [Siddharth Yadav](mailto:illustrationdesignsid@gmail.com), [@Siddharth_yd](https://www.instagram.com/siddharth_yd/). -* Flag icons - [IconDrawer](http://www.icondrawer.com). +* RSS Guard logo - [Siddharth Yadav](mailto:illustrationdesignsid@gmail.com), [@Siddharth_yd](https://www.instagram.com/siddharth_yd/) +* Flag icons - [IconDrawer](http://www.icondrawer.com) diff --git a/resources/docs/Documentation.md b/resources/docs/Documentation.md index a954acaab..79247f836 100644 --- a/resources/docs/Documentation.md +++ b/resources/docs/Documentation.md @@ -37,11 +37,11 @@ There is a [Discord server](https://discord.gg/7xbVMPPNqH) for user communicatio RSS Guard is an [open-source](https://en.wikipedia.org/wiki/Open_source) [cross-platform](#sos) [multi-protocol](#sfr) desktop feed reader. It is able to fetch feeds in RSS/RDF/ATOM/JSON formats. RSS Guard is developed on top of the [Qt library](http://qt-project.org). ## Downloads -Official place to download RSS Guard is at [Github Releases](https://github.com/martinrotter/rssguard/releases). You can also download the [development (beta) build](https://github.com/martinrotter/rssguard/releases/tag/devbuild), which is updated automatically every time the source code is updated. +Official place to download RSS Guard is at [Github Releases page](https://github.com/martinrotter/rssguard/releases). You can also download the [development (beta) build](https://github.com/martinrotter/rssguard/releases/tag/devbuild), which is updated automatically every time the source code is updated. -RSS Guard is also available for [many Linux distributions](https://repology.org/project/rssguard/versions), and even via [Flathub](https://flathub.org/apps/details/com.github.rssguard). +RSS Guard is also available in [repositories of many Linux distributions](https://repology.org/project/rssguard/versions), and via [Flathub](https://flathub.org/apps/details/com.github.rssguard). -I highly recommend to download RSS Guard only from reputable sources. +I highly recommend to download RSS Guard only from trusted sources. ## Supported Operating Systems RSS Guard is a cross-platform application, and at this point it is known to work on: @@ -54,7 +54,7 @@ RSS Guard is a cross-platform application, and at this point it is known to work ## Major Features ### Supported Feed Readers -RSS Guard is multi-account application and supports many web-based feed readers via [built-in plugins](#papi). One of the plugins, of course, provides the support for standard **RSS/ATOM/JSON** feeds with the set of features everyone would expect from classic feed reader, like OPML support, etc. +RSS Guard is multi-account application and supports many web-based feed readers via [built-in plugins](#papi). One of the plugins, of course, provides the support for standard list of **RSS/ATOM/JSON** feeds with the set of features everyone would expect from classic feed reader, like OPML support, etc. I organized the supported web-based feed readers into an elegant table: @@ -70,7 +70,7 @@ I organized the supported web-based feed readers into an elegant table: alt-img -With ISA, RSS Guard only downloads articles which are new or were updated. While the old algorithm usually always fetch all available articles, even if they are not needed, which leads to unnecessary overload of your network connection and RSS Guard. +With ISA, RSS Guard only downloads articles which are new or were updated. The old algorithm usually always fetches all available articles, even if they are not needed, which leads to unnecessary overload of your network connection and the RSS Guard. 2 Note that [labels](#lbls) are supported for all plugins, but for some plugins they are local-only, and are not synchronized with the service. Usually because service itself does not support the feature. @@ -82,15 +82,15 @@ With ISA, RSS Guard only downloads articles which are new or were updated. While * TheOldReader * FreshRSS -4 [OAuth](https://en.wikipedia.org/wiki/OAuth) is secure way of authenticating users in online applications. +4 [OAuth](https://en.wikipedia.org/wiki/OAuth) is a secure way of authenticating users in online applications. ### Article Filtering -Sometimes you need to automatically tweak incoming article - mark it starred, remove ads from its contents or simply ignore it. That's where filtering feature comes in. +Sometimes you need to automatically tweak the incoming article - mark it starred, remove ads from its contents, or simply ignore it. That's where filtering feature comes in. alt-img #### Writing article filter -Article filters are small scripts which are executed automatically when articles/feeds are downloaded. Article filters are `JavaScript` pieces of code which must provide function with prototype: +Article filters are small scripts which are executed automatically when articles/feeds are downloaded. Article filters are JavaScript pieces of code which must provide function with prototype: ```js function filterMessage() { } @@ -100,23 +100,26 @@ The function should be fast and must return values which belong to enumeration [ Each article is accessible in your script via global variable named `msg` of type `MessageObject`, see [this file](https://github.com/martinrotter/rssguard/blob/master/src/librssguard/core/messageobject.h) for the declaration. Some properties are writeable, allowing you to change contents of the article before it is written to RSS Guard's DB. You can mark article important, change its description, perhaps change author name or even assign some label to it!!! -Almost any changes you make are synchronized back to feed service if the particular RSS Guard plugin supports it. +Almost all changes you make are synchronized back to feed service, if corresponding RSS Guard plugin supports it. -You can use [special placeholders](#userd-plac) within article filter. +A [special placeholders](#userd-plac) can be used in article filters. -Also, there is a special variable named `utils`. This variable is of type `FilterUtils` and offers some useful [utility functions](#utils-object) for you to use in your filters. +There is also a special variable named `utils`. This variable is of `FilterUtils` type. It offers some useful [utility functions](#utils-object) for your filters. -RSS Guard allows to use the list of labels assigned to each article. You can, therefore, execute actions in your filtering script, based on which labels are assigned to the article. The property is called `assignedLabels` and is array of [`Label`](#Label-class) objects. +Labels assigned to articles are visible to your filters. You can, therefore, execute actions in your filtering script, based on which labels are assigned to the article. The property is called `assignedLabels` and is an array of the [`Label`](#Label-class) objects. -Passed article also offers special function: +Passed article also offers a special function: ```js Boolean MessageObject.isAlreadyInDatabase(DuplicateCheck) ``` -which allows you to perform runtime check for existence of the article in RSS Guard's database. The parameter is value from enumeration [`DuplicateCheck`](#dupl-check) and specifies how exactly you want to match your article. +which allows you to perform runtime check for existence of the article in RSS Guard's database. Parameter is the value from enumeration [`DuplicateCheck`](#dupl-check). It specifies how exactly the article should match. -For example, if you want to check if there is already another article with same author in database, you should call `msg.isAlreadyInDatabase(MessageObject.SameAuthor)`. Values of the enumeration can be combined via bitwise OR (`|`) operator in single call, like this: +For example, if you want to check if there is already another article by the same author in a database, you should call `msg.isAlreadyInDatabase(MessageObject.SameAuthor)`. +The values of enumeration can be combined in a single call with the **[bitwise OR] (`|`)** operator, like this: + + [bitwise OR]: ```js msg.isAlreadyInDatabase(MessageObject.SameAuthor | MessageObject.SameUrl) @@ -125,46 +128,46 @@ msg.isAlreadyInDatabase(MessageObject.SameAuthor | MessageObject.SameUrl) Here is the reference of methods and properties of types available in your filtering scripts. #### `MessageObject` class -| Type | Name(Parameters) | Return value | Read-only | Synchronized | Description -| :--- | :--- | :--- | :---: | :---: | --- +| Type | Name(Parameters) | Return value | Read-only | Synchronized | Description +| :--- | :--- | :--- | :---: | :---: | --- | Property | `assignedLabels` | `Array