Category autoread by guid (#8673)

* Add configuration to mark same GUID as read in category.

Implement suggestion mentioned in #8641

Changes proposed in this pull request:

- Add a configuration to the categories to automatically mark entries as read if the same GUID is present in recent entries.  

How to test the feature manually:

1. Create a category. Check the option "Mark an article as read… if an identical GUID already exists [...]"  
2. Enable debug logs, or add an extension which registers to the hook `Minz_HookType::EntryAutoRead`.  
3. Add feeds which might have the same GUID.  
  For example: https://www.reddit.com/r/technology/hot.rss, https://www.reddit.com/r/technology/rising.rss, https://www.reddit.com/r/technology/best.rss, and https://www.reddit.com/r/technology/new.rss
4. See the logs "Mark GUID as read[...]", or the effect of the extension.  

* Implement behavior to mark same GUID as read in category.

* Update documentation

* Update i18n

* Fix PHP CS report

* Fix missing argument

* Fixes

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
This commit is contained in:
pe1uca
2026-04-05 13:41:37 -04:00
committed by GitHub
parent d5f3126d6c
commit c44cd2b08f
34 changed files with 88 additions and 5 deletions

View File

@@ -109,6 +109,11 @@ class FreshRSS_category_Controller extends FreshRSS_ActionController {
} else {
$category->_attribute('read_when_same_title_in_category', null);
}
if (Minz_Request::paramBoolean('enable_read_when_same_guid_in_category')) {
$category->_attribute('read_when_same_guid_in_category', Minz_Request::paramInt('read_when_same_guid_in_category'));
} else {
$category->_attribute('read_when_same_guid_in_category', null);
}
$category->_filtersAction('read', Minz_Request::paramTextToArray('filteractions_read', plaintext: true));

View File

@@ -468,6 +468,8 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
$feedsCacheToRefresh = [];
/** @var array<int,array<string,true>> */
$categoriesEntriesTitle = [];
/** @var array<int,array<string,true>> */
$categoriesEntriesGuid = [];
$feeds = Minz_ExtensionManager::callHook(Minz_HookType::FeedsListBeforeActualize, $feeds);
if (is_array($feeds)) {
@@ -601,6 +603,12 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
true
);
}
if (!isset($categoriesEntriesGuid[$feed->categoryId()]) && $category !== null && $category->hasAttribute('read_when_same_guid_in_category')) {
$categoriesEntriesGuid[$feed->categoryId()] = array_fill_keys(
$catDAO->listGuids($feed->categoryId(), $category->attributeInt('read_when_same_guid_in_category') ?? 0),
true
);
}
$mark_updated_article_unread = $feed->attributeBoolean('mark_updated_article_unread') ?? FreshRSS_Context::userConf()->mark_updated_article_unread;
@@ -646,6 +654,9 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
if (isset($categoriesEntriesTitle[$feed->categoryId()])) {
$categoriesEntriesTitle[$feed->categoryId()][$entry->title()] = true;
}
if (isset($categoriesEntriesGuid[$feed->categoryId()])) {
$categoriesEntriesGuid[$feed->categoryId()][$entry->guid()] = true;
}
if (!$entry->isRead()) {
$needFeedCacheRefresh = true; //Maybe
@@ -674,13 +685,17 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
continue;
}
$entry->applyFilterActions(array_merge($titlesAsRead, $categoriesEntriesTitle[$feed->categoryId()] ?? []));
$entry->applyFilterActions(array_merge($titlesAsRead, $categoriesEntriesTitle[$feed->categoryId()] ?? []),
$categoriesEntriesGuid[$feed->categoryId()] ?? []);
if ($readWhenSameTitleInFeed > 0) {
$titlesAsRead[$entry->title()] = true;
}
if (isset($categoriesEntriesTitle[$feed->categoryId()])) {
$categoriesEntriesTitle[$feed->categoryId()][$entry->title()] = true;
}
if (isset($categoriesEntriesGuid[$feed->categoryId()])) {
$categoriesEntriesGuid[$feed->categoryId()][$entry->guid()] = true;
}
$needFeedCacheRefresh = true;

View File

@@ -465,6 +465,20 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
return $res;
}
/** @return list<string> */
public function listGuids(int $id, int $limit = 0): array {
$sql = <<<'SQL'
SELECT e.guid FROM `_entry` e
INNER JOIN `_feed` f ON e.id_feed=f.id
WHERE f.category=:id_category
ORDER BY e.id DESC
SQL;
$sql .= ($limit < 1 ? '' : ' LIMIT ' . intval($limit));
$res = $this->fetchColumn($sql, 0, [':id_category' => $id]) ?? [];
/** @var list<string> $res */
return $res;
}
/**
* @param array<array{c_name:string,c_id:int,c_kind:int,c_last_update:int,c_error:int|bool,c_attributes?:string,
* id?:int,name?:string,url?:string,kind?:int,website?:string,priority?:int,

View File

@@ -887,8 +887,11 @@ class FreshRSS_Entry extends Minz_Model {
return (bool)$ok;
}
/** @param array<string,bool|int> $titlesAsRead */
public function applyFilterActions(array $titlesAsRead = []): void {
/**
* @param array<string,bool|int> $titlesAsRead
* @param array<string,bool|int> $guidsAsRead
*/
public function applyFilterActions(array $titlesAsRead = [], array $guidsAsRead = []): void {
$feed = $this->feed;
if ($feed === null) {
return;
@@ -903,6 +906,11 @@ class FreshRSS_Entry extends Minz_Model {
$this->_isRead(true);
Minz_ExtensionManager::callHook(Minz_HookType::EntryAutoRead, $this, 'same_title_in_feed');
}
if (!empty($guidsAsRead[$this->guid()])) {
Minz_Log::debug('Mark GUID as read: ' . $this->guid());
$this->_isRead(true);
Minz_ExtensionManager::callHook(Minz_HookType::EntryAutoRead, $this, 'same_guid_in_category');
}
}
FreshRSS_Context::userConf()->applyFilterActions($this);
$feed->category()?->applyFilterActions($this);

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'když se již nenachází v upstreamu zpráv.',
'upon_reception' => 'po obdržení článku',
'when' => 'Označit článek jako přečtený…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_feed' => 'když shodný název již existuje v top <i>n</i> nejnovějších článcích (of the feed)', // DIRTY
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'wenn der Artikel nicht mehr im Feed enthalten ist',
'upon_reception' => 'beim Empfang des Artikels',
'when' => 'Artikel als gelesen markieren…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'falls der identische Titel bereits in den <i>n</i> neusten Artikel in der Kategorie vorhanden ist.',
'when_same_title_in_feed' => 'falls der identische Titel bereits in den <i>n</i> neusten Artikel (im Feed) vorhanden ist.',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'when it is no longer in the upstream news feed', // TODO
'upon_reception' => 'upon receiving the article', // TODO
'when' => 'Mark an article as read…', // TODO
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_feed' => 'if an identical title already exists in the top <i>n</i> newest articles of the feed', // TODO
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'when it is no longer in the upstream news feed', // IGNORE
'upon_reception' => 'upon receiving the article', // IGNORE
'when' => 'Mark an article as read…', // IGNORE
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // IGNORE
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category', // IGNORE
'when_same_title_in_feed' => 'if an identical title already exists in the top <i>n</i> newest articles of the feed', // IGNORE
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'when it is no longer in the upstream news feed',
'upon_reception' => 'upon receiving the article',
'when' => 'Mark an article as read…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category',
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category',
'when_same_title_in_feed' => 'if an identical title already exists in the top <i>n</i> newest articles of the feed',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'cuando ya no está disponible en la fuente de noticias previa',
'upon_reception' => 'al recibir el artículo',
'when' => 'Marcar el artículo como leído…',
'when_same_guid_in_category' => 'si ya existe un GUID idéntico en los <i>n</i> artículos más recientes de la categoría', // DIRTY
'when_same_title_in_category' => 'si ya existe un título idéntico en los <i>n</i> artículos más recientes de la categoría',
'when_same_title_in_feed' => 'Si ya existe un título idéntico en la parte superior <i>n</i> artículos más recientes (de la fuente)',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => ' زمانی که دیگر در فید اخبار بالادستی نیست',
'upon_reception' => ' پس از دریافت مقاله',
'when' => ' علامت گذاری یک مقاله به عنوان خوانده شده…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'اگر عنوان مشابهی در بخش بالا وجود دارد <i>n</i> تازه‌ترین مقالات این دسته',
'when_same_title_in_feed' => ' اگر عنوان یکسانی از قبل در <i>n</i> جدیدترین مقالات بالا وجود داشته باشد (از فید)',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'kun artikkeli ei ole enää alkuperäisessä uutissyötteessä',
'upon_reception' => 'kun artikkeli on vastaanotettu',
'when' => 'Merkitse artikkeli luetuksi…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'jos jollakin luokan <i>n</i> uusimmalla artikkelilla on sama otsikko',
'when_same_title_in_feed' => 'jos jollakin syötteen <i>n</i> uusimmalla artikkelilla on sama otsikko',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'lorsquil nest plus dans le flux dactualités en amont',
'upon_reception' => 'dès la réception du nouvel article',
'when' => 'Marquer un article comme lu…',
'when_same_guid_in_category' => 'si un même GUID existe déjà dans les <i>n</i> articles plus récents de la catégorie',
'when_same_title_in_category' => 'si un même titre existe déjà dans les <i>n</i> articles plus récents de la catégorie',
'when_same_title_in_feed' => 'si un même titre existe déjà dans les <i>n</i> articles plus récents du flux',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'when it is no longer in the upstream news feed', // TODO
'upon_reception' => 'כאשר המאמר מתקבל',
'when' => 'סימון מאמרים כנקראו…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_feed' => 'if an identical title already exists in the top <i>n</i> newest articles of the feed', // TODO
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'ha már nincs benne a hírforrásban',
'upon_reception' => 'a cikk beérkezésekor',
'when' => 'Jelöljön meg egy cikket olvasottként…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'ha már létezik azonos cím a <i>n</i> kategória legfrissebb cikkeiben',
'when_same_title_in_feed' => 'ha egy azonos című cikk már létezik a legújabb <i>n</i> számú cikk között (a hírforrásban)',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'saat artikel hilang dari umpan situs aslinya',
'upon_reception' => 'saat menerima artikel',
'when' => 'Tandai artikel sebagai sudah dibaca…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'jika judul yang identik sudah ada di <i>n</i> artikel terbaru dalam kategori',
'when_same_title_in_feed' => 'jika judul yang identik sudah ada di <i>n</i> artikel terbaru dari umpan',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'quando non si trova più nel feed di notizie in alto',
'upon_reception' => 'Alla ricezione del contenuto',
'when' => 'Segna articoli come letti…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'se un titolo identico esiste già nei primi <i>n</i> articoli più recenti della categoria',
'when_same_title_in_feed' => 'se un titolo identico esiste già tra i <i>n</i> articoli più recenti (del feed)',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'ニュースフィードの提供元がなくなったとき',
'upon_reception' => '記事を受け取ったとき',
'when' => '記事を既読にする…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'すでに同一タイトルがカテゴリ内上位<i>n</i>件の最新記事に存在するとき',
'when_same_title_in_feed' => 'すでに同一タイトルがフィード内上位<i>n</i>件の最新記事に存在するとき',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => '원본 뉴스 피드에서 글 삭제 되었을 때',
'upon_reception' => '글을 가져오자마자',
'when' => '읽음으로 표시…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_feed' => '상위 <i>n</i>개의 최신 글에 동일한 제목이 이미 있는 경우 (of the feed)', // DIRTY
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'kad tas vairs nav augšupējā ziņu barotnē',
'upon_reception' => 'pēc raksta saņemšanas',
'when' => 'Atzīmēt rakstu kā izlasītu…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_feed' => 'ja identisks virsraksts jau ir jaunākajos <i>n</i> rakstos (of the feed)', // DIRTY
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'als het niet langer in de nieuwsfeed staat',
'upon_reception' => 'bij ontvangst van het artikel',
'when' => 'Markeer artikel als gelezen…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'als een identieke titel al voorkomt in de top <i>n</i> nieuwste artikelen van de categorie',
'when_same_title_in_feed' => 'als een zelfde titel al voorkomt in de top <i>n</i> nieuwste artikelen (of the feed)', // DIRTY
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'quand es pas mai dins lo flux de novèla font',
'upon_reception' => 'en recebre un article novèl',
'when' => 'Marcar un article coma legit…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_feed' => 'se un títol identic existís ja demest lo <i>n</i> articles mai recents (of the feed)', // DIRTY
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'gdy nie jest już wyświetlana w źródle kanału',
'upon_reception' => 'po otrzymaniu wiadomości',
'when' => 'Oznacz wiadomość jako przeczytaną…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'gdy identyczny tytuł już istnieje w <i>n</i> najnowszych wiadomościach kategorii',
'when_same_title_in_feed' => 'gdy identyczny tytuł już istnieje w <i>n</i> najnowszych wiadomościach (kanału RSS)',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'Quando não estiver mais no feed de notícias principais',
'upon_reception' => 'ao receber um artigo',
'when' => 'Marcar artigo como lido…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'se um título idêntico já existir entre os <i>n</i> artigos mais recentes da categoria',
'when_same_title_in_feed' => 'Se um título idêntico já existir nos últimos <i>n</i> artigos mais novos (do feed)',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'Quando não estiver mais no feed de notícias principais',
'upon_reception' => 'ao receber um artigo',
'when' => 'Marcar artigo como lido…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_feed' => 'Se um título idêntico já existir nos últimos <i>n</i> artigos mais novos (no feed)',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'когда это больше не в новостной ленте',
'upon_reception' => 'по получении статьи',
'when' => 'Отмечать статью прочитанной…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'если идентичный заголовок уже существует среди <i>n</i> новейших статей категории',
'when_same_title_in_feed' => 'если идентичный заголовок уже существует среди <i>n</i> новейших статей ленты',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'keď už nie je v hlavnom kanály noviniek',
'upon_reception' => 'po načítaní článku',
'when' => 'Označiť článok ako prečítaný…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_feed' => 'ak rovnaký nadpis už existuje v TOP <i>n</i> najnovších článkoch (of the feed)', // DIRTY
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'artık上游 haber akışında olmadığında',
'upon_reception' => 'makale alındığında',
'when' => 'Bir makaleyi okundu olarak işaretle…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'eğer aynı başlık kategorideki en yeni <i>n</i> makalede zaten varsa',
'when_same_title_in_feed' => 'eğer aynı başlık beslemedeki en yeni <i>n</i> makalede zaten varsa',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => 'коли статті більше нема в оригінальній стрічці новин',
'upon_reception' => 'при отриманні статті',
'when' => 'Позначити статтю прочитаною…',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'якщо котрась зі стількох найновіших статей категорії має такий самий заголовок',
'when_same_title_in_feed' => 'якщо котрась зі стількох найновіших статей стрічки має такий самий заголовок',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => '在被原订阅源被移除后',
'upon_reception' => '在接收文章后',
'when' => '何时将文章标记为已读',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => '如果分类中已经存在相同标题的最新 <i>n</i> 篇文章',
'when_same_title_in_feed' => '如果订阅源中已经存在相同标题的最新 <i>n</i> 篇文章',
),

View File

@@ -280,6 +280,7 @@ return array(
'upon_gone' => '在被原訂閱源移除後',
'upon_reception' => '在接收文章後',
'when' => '何時將文章標記為已讀',
'when_same_guid_in_category' => 'if an identical GUID already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_category' => 'if an identical title already exists in the top <i>n</i> newest articles of the category', // TODO
'when_same_title_in_feed' => '已存在 n 條相同標題文章 (of the feed)', // DIRTY
),

View File

@@ -134,6 +134,20 @@
</div>
</div>
<div class="form-group">
<label class="group-name" for="enable_read_when_same_guid_in_category"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<label class="checkbox" for="enable_read_when_same_guid_in_category">
<input type="checkbox" name="enable_read_when_same_guid_in_category" id="enable_read_when_same_guid_in_category" value="1"<?=
$this->category->hasAttribute('read_when_same_guid_in_category') ? ' checked="checked"' : '' ?> />
<?= _t('conf.reading.read.when_same_guid_in_category') ?>
<?php $read_when_same_guid_in_category = $this->category->hasAttribute('read_when_same_guid_in_category') ? $this->category->attributeInt('read_when_same_guid_in_category') : 25; ?>
<input type="number" id="read_when_same_guid_in_category" name="read_when_same_guid_in_category" min="0"
value="<?= $read_when_same_guid_in_category ?>" />
</label>
</div>
</div>
<div class="form-group">
<label class="group-name" for="filteractions_read"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">

View File

@@ -181,7 +181,7 @@ Example response for a `query_icon_info` request:
* `Minz_HookType::CustomFaviconHash` (`function(FreshRSS_Feed $feed): string | null`): Enables the modification of custom favicon hashes by returning params from the hook function. The hook should check if the `customFaviconExt` attribute of `$feed` is set to the extension's name before returning a custom value. Otherwise, the return value should be null.
* `Minz_HookType::EntriesFavorite` (`function(array $ids, bool $is_favorite): void`):
will be executed when some entries are marked or unmarked as favorites (starred)
* `Minz_HookType::EntryAutoRead` (`function(FreshRSS_Entry $entry, string $why): void`): Triggered when an entry is automatically marked as read. The *why* parameter supports the rules {`filter`, `upon_reception`, `same_title_in_feed`}.
* `Minz_HookType::EntryAutoRead` (`function(FreshRSS_Entry $entry, string $why): void`): Triggered when an entry is automatically marked as read. The *why* parameter supports the rules {`filter`, `upon_reception`, `same_title_in_feed`, `same_guid_in_category`}.
* `Minz_HookType::EntryAutoUnread` (`function(FreshRSS_Entry $entry, string $why): void`): Triggered when an entry is automatically marked as unread. The *why* parameter supports the rules {`updated_article`}.
* `Minz_HookType::EntryBeforeDisplay` (`function($entry) -> Entry | null`): will be executed every time an entry is rendered. The entry itself (instance of FreshRSS\_Entry) will be passed as parameter.
* `Minz_HookType::EntryBeforeInsert` (`function($entry) -> Entry | null`): will be executed when a feed is refreshed and new entries will be imported into the database. The new entry (instance of FreshRSS\_Entry) will be passed as parameter.

View File

@@ -228,7 +228,7 @@ The following events are available:
parameter. This way a website known to have feeds which doesnt advertise
it in the header can still be automatically supported.
* `entry_auto_read` (`function(FreshRSS_Entry $entry, string $why): void`):
Appelé lorsquune entrée est automatiquement marquée comme lue. Le paramètre *why* supporte les règles {`filter`, `upon_reception`, `same_title_in_feed`}.
Appelé lorsquune entrée est automatiquement marquée comme lue. Le paramètre *why* supporte les règles {`filter`, `upon_reception`, `same_title_in_feed`, `same_guid_in_category`}.
* `entry_auto_unread` (`function(FreshRSS_Entry $entry, string $why): void`):
Appelé lorsquune entrée est automatiquement marquée comme non-lue. Le paramètre *why* supporte les règles {`updated_article`}.
* `entry_before_display` (`function($entry) -> Entry | null`): will be