From 7c0370b4eacdd62c06c7324a39f092361e84a2bc Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 27 Dec 2025 16:26:02 +0100 Subject: Do not include hidden feeds when counting unread articles in categories (#8357) fix https://github.com/FreshRSS/FreshRSS/issues/8347 --- app/Models/Category.php | 46 +++++++++++++++++++++++++++++----------------- app/Models/CategoryDAO.php | 11 ++++++++--- app/Models/Context.php | 2 +- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/app/Models/Category.php b/app/Models/Category.php index 4d7740ed1..2bdad2904 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -18,11 +18,11 @@ class FreshRSS_Category extends Minz_Model { private int $kind = 0; private string $name; private int $nbFeeds = -1; + /** Number of unread articles in feeds with visibility FreshRSS_Feed::PRIORITY_FEED */ private int $nbNotRead = -1; /** @var array|null where the key is the feed ID */ private ?array $feeds = null; - /** @var bool|int */ - private $hasFeedsWithError = false; + private bool|int $hasFeedsWithError = false; private int $lastUpdate = 0; private bool $error = false; @@ -39,8 +39,10 @@ class FreshRSS_Category extends Minz_Model { foreach ($feeds as $feed) { $feed->_category($this); $this->nbFeeds++; - $this->nbNotRead += $feed->nbNotRead(); - $this->hasFeedsWithError |= ($feed->inError() && !$feed->mute()); + if ($feed->priority() > FreshRSS_Feed::PRIORITY_HIDDEN) { + $this->nbNotRead += $feed->nbNotRead(); + $this->hasFeedsWithError |= ($feed->inError() && !$feed->mute()); + } } } } @@ -90,13 +92,25 @@ class FreshRSS_Category extends Minz_Model { * @throws Minz_ConfigurationNamespaceException * @throws Minz_PDOConnectionException */ - public function nbNotRead(): int { - if ($this->nbNotRead < 0) { + public function nbNotRead(int $minPriority = FreshRSS_Feed::PRIORITY_FEED): int { + if ($this->nbNotRead > 0 && $minPriority === FreshRSS_Feed::PRIORITY_FEED) { + return $this->nbNotRead; + } + if ($this->feeds === null) { $catDAO = FreshRSS_Factory::createCategoryDao(); - $this->nbNotRead = $catDAO->countNotRead($this->id()); + $nb = $catDAO->countNotRead($this->id(), $minPriority); + if ($minPriority === FreshRSS_Feed::PRIORITY_FEED) { + $this->nbNotRead = $nb; + } + return $nb; } - - return $this->nbNotRead; + $nb = 0; + foreach ($this->feeds as $feed) { + if ($feed->priority() >= $minPriority) { + $nb += $feed->nbNotRead(); + } + } + return $nb; } /** @return array */ @@ -117,8 +131,10 @@ class FreshRSS_Category extends Minz_Model { $this->nbNotRead = 0; foreach ($this->feeds as $feed) { $this->nbFeeds++; - $this->nbNotRead += $feed->nbNotRead(); - $this->hasFeedsWithError |= ($feed->inError() && !$feed->mute()); + if ($feed->priority() > FreshRSS_Feed::PRIORITY_HIDDEN) { + $this->nbNotRead += $feed->nbNotRead(); + $this->hasFeedsWithError |= ($feed->inError() && !$feed->mute()); + } } $this->sortFeeds(); } @@ -290,14 +306,10 @@ class FreshRSS_Category extends Minz_Model { /** * @param array $categories */ - public static function countUnread(array $categories, int $minPriority = 0): int { + public static function countUnread(array $categories, int $minPriority = FreshRSS_Feed::PRIORITY_FEED): int { $n = 0; foreach ($categories as $category) { - foreach ($category->feeds() as $feed) { - if ($feed->priority() >= $minPriority) { - $n += $feed->nbNotRead(); - } - } + $n += $category->nbNotRead($minPriority); } return $n; } diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index e03f69016..d98a2ffc1 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -410,9 +410,14 @@ SQL; return isset($res[0]) ? (int)$res[0] : -1; } - public function countNotRead(int $id): int { - $sql = 'SELECT COUNT(*) AS count FROM `_entry` e INNER JOIN `_feed` f ON e.id_feed=f.id WHERE category=:id AND e.is_read=0'; - $res = $this->fetchColumn($sql, 0, [':id' => $id]); + public function countNotRead(int $id, int $minPriority = FreshRSS_Feed::PRIORITY_CATEGORY): int { + $sql = <<<'SQL' + SELECT COUNT(*) AS count FROM `_entry` e + INNER JOIN `_feed` f ON e.id_feed=f.id + WHERE f.category=:id AND e.is_read=0 + AND f.priority>=:minPriority + SQL; + $res = $this->fetchColumn($sql, 0, [':id' => $id, ':minPriority' => $minPriority]); return isset($res[0]) ? (int)$res[0] : -1; } diff --git a/app/Models/Context.php b/app/Models/Context.php index a8feb7dbd..c9d743e76 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -570,7 +570,7 @@ final class FreshRSS_Context { continue; } - if ($cat->nbNotRead() > 0) { + if ($cat->nbNotRead(minPriority: FreshRSS_Feed::PRIORITY_CATEGORY) > 0) { $another_unread_id = $cat->id(); if ($found_current_get) { // Unread articles and the current category has -- cgit v1.2.3