diff --git a/resources/sql.qrc b/resources/sql.qrc
index 0187a0294..b669edc27 100644
--- a/resources/sql.qrc
+++ b/resources/sql.qrc
@@ -8,6 +8,7 @@
sql/db_update_mysql_5_6.sql
sql/db_update_mysql_6_7.sql
sql/db_update_mysql_7_8.sql
+ sql/db_update_mysql_8_9.sql
sql/db_init_sqlite.sql
sql/db_update_sqlite_1_2.sql
@@ -17,5 +18,6 @@
sql/db_update_sqlite_5_6.sql
sql/db_update_sqlite_6_7.sql
sql/db_update_sqlite_7_8.sql
+ sql/db_update_sqlite_8_9.sql
\ No newline at end of file
diff --git a/resources/sql/db_init_sqlite.sql b/resources/sql/db_init_sqlite.sql
index 928cfed4b..62af2450c 100644
--- a/resources/sql/db_init_sqlite.sql
+++ b/resources/sql/db_init_sqlite.sql
@@ -43,7 +43,7 @@ CREATE TABLE Feeds (
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),
- is_rtl INTEGER NOT NULL DEFAULT 0 CHECK (is_rtl >= 0 AND is_rtl <= 1),
+ is_rtl INTEGER NOT NULL DEFAULT 0 CHECK (is_rtl >= 0 AND is_rtl <= 1024),
add_any_datetime_articles INTEGER NOT NULL DEFAULT 0 CHECK (add_any_datetime_articles >= 0 AND add_any_datetime_articles <= 1),
datetime_to_avoid BIGINT NOT NULL DEFAULT 0 CHECK (datetime_to_avoid >= 0),
diff --git a/resources/sql/db_update_mysql_8_9.sql b/resources/sql/db_update_mysql_8_9.sql
new file mode 100644
index 000000000..b1d5f46f3
--- /dev/null
+++ b/resources/sql/db_update_mysql_8_9.sql
@@ -0,0 +1,7 @@
+USE ##;
+-- !
+SET FOREIGN_KEY_CHECKS = 0;
+-- !
+!! db_update_sqlite_8_9.sql
+-- !
+SET FOREIGN_KEY_CHECKS = 1;
\ No newline at end of file
diff --git a/resources/sql/db_update_sqlite_8_9.sql b/resources/sql/db_update_sqlite_8_9.sql
new file mode 100644
index 000000000..6edfa8e1f
--- /dev/null
+++ b/resources/sql/db_update_sqlite_8_9.sql
@@ -0,0 +1,40 @@
+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),
+ is_rtl INTEGER NOT NULL DEFAULT 0 CHECK (is_rtl >= 0 AND is_rtl <= 1024),
+
+ add_any_datetime_articles INTEGER NOT NULL DEFAULT 0 CHECK (add_any_datetime_articles >= 0 AND add_any_datetime_articles <= 1),
+ datetime_to_avoid BIGINT NOT NULL DEFAULT 0 CHECK (datetime_to_avoid >= 0),
+
+ keep_article_customize INTEGER NOT NULL DEFAULT 0 CHECK (keep_article_customize >= 0 AND keep_article_customize <= 1),
+ keep_article_count INTEGER NOT NULL DEFAULT 0 CHECK (keep_article_count >= 0),
+ keep_unread_articles INTEGER NOT NULL DEFAULT 1 CHECK (keep_unread_articles >= 0 AND keep_unread_articles <= 1),
+ keep_starred_articles INTEGER NOT NULL DEFAULT 1 CHECK (keep_starred_articles >= 0 AND keep_starred_articles <= 1),
+ recycle_articles INTEGER NOT NULL DEFAULT 0 CHECK (recycle_articles >= 0 AND recycle_articles <= 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, is_quiet, is_rtl, add_any_datetime_articles, datetime_to_avoid, keep_article_customize, keep_article_count, keep_unread_articles, keep_starred_articles, recycle_articles, open_articles, account_id, custom_id, custom_data)
+SELECT id, ordr, title, description, date_created, icon, category, source, update_type, update_interval, is_off, is_quiet, is_rtl, add_any_datetime_articles, datetime_to_avoid, keep_article_customize, keep_article_count, keep_unread_articles, keep_starred_articles, recycle_articles, 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/CMakeLists.txt b/src/librssguard/CMakeLists.txt
index 5d0e9dabe..87a3440f1 100644
--- a/src/librssguard/CMakeLists.txt
+++ b/src/librssguard/CMakeLists.txt
@@ -297,6 +297,7 @@ set(SOURCES
services/abstract/category.h
services/abstract/feed.cpp
services/abstract/feed.h
+ services/abstract/feedrtlbehavior.h
services/abstract/gui/accountdetails.cpp
services/abstract/gui/accountdetails.h
services/abstract/gui/authenticationdetails.cpp
diff --git a/src/librssguard/core/message.cpp b/src/librssguard/core/message.cpp
index a99af51eb..e42540664 100644
--- a/src/librssguard/core/message.cpp
+++ b/src/librssguard/core/message.cpp
@@ -111,7 +111,8 @@ Message::Message() {
m_categories = QList();
m_accountId = m_id = 0;
m_score = 0.0;
- m_isRead = m_isImportant = m_isDeleted = m_isRtl = false;
+ m_isRead = m_isImportant = m_isDeleted = false;
+ m_rtlBehavior = RtlBehavior::NoRtl;
m_assignedLabels = QList