diff options
| author | 2021-09-19 10:56:38 +0200 | |
|---|---|---|
| committer | 2021-09-19 10:56:38 +0200 | |
| commit | a7aca6c0abfd905669004c1e4f7c8328060df27e (patch) | |
| tree | 3edd507ce9ce0762f0faf3c24108f3b1d24988e7 | |
| parent | dfc89831d4e363f62dea9df71c6b4af21cc7d7c7 (diff) | |
Improved feed action filters (#3303)
* Re-order some feed options
* Option to auto mark as read existing titles
* Option to keep at max n unread articles per feed
29 files changed, 322 insertions, 126 deletions
diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 388c34624..79ddf8e17 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -121,9 +121,12 @@ class FreshRSS_configure_Controller extends Minz_ActionController { FreshRSS_Context::$user_conf->sort_order = Minz_Request::param('sort_order', 'DESC'); FreshRSS_Context::$user_conf->mark_when = array( 'article' => Minz_Request::param('mark_open_article', false), - 'site' => Minz_Request::param('mark_open_site', false), - 'scroll' => Minz_Request::param('mark_scroll', false), + 'max_n_unread' => Minz_Request::paramBoolean('enable_keep_max_n_unread') ? Minz_Request::param('keep_max_n_unread', false) : false, 'reception' => Minz_Request::param('mark_upon_reception', false), + 'same_title_in_feed' => Minz_Request::paramBoolean('enable_read_when_same_title_in_feed') ? + Minz_Request::param('read_when_same_title_in_feed', false) : false, + 'scroll' => Minz_Request::param('mark_scroll', false), + 'site' => Minz_Request::param('mark_open_site', false), ); FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); @@ -210,7 +213,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } elseif (!$keepMax = Minz_Request::param('keep_max')) { $keepMax = FreshRSS_Feed::ARCHIVING_RETENTION_COUNT_LIMIT; } - if ($enableRetentionPeriod = Minz_Request::paramBoolean('enable_keep_period')) { + if (Minz_Request::paramBoolean('enable_keep_period')) { $keepPeriod = FreshRSS_Feed::ARCHIVING_RETENTION_PERIOD; if (is_numeric(Minz_Request::param('keep_period_count')) && preg_match('/^PT?1[YMWDH]$/', Minz_Request::param('keep_period_unit'))) { $keepPeriod = str_replace('1', Minz_Request::param('keep_period_count'), Minz_Request::param('keep_period_unit')); diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index d43f05d4a..afb05f17e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -359,6 +359,19 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $needFeedCacheRefresh = false; if (count($newGuids) > 0) { + $titlesAsRead = []; + $readWhenSameTitleInFeed = $feed->attributes('read_when_same_title_in_feed'); + if ($readWhenSameTitleInFeed == false) { + $readWhenSameTitleInFeed = FreshRSS_Context::$user_conf->mark_when['same_title_in_feed']; + } + if ($readWhenSameTitleInFeed > 0) { + $titlesAsRead = array_flip($feedDAO->listTitles($feed->id(), $feed->attributes('read_when_same_title_in_feed'))); + } + + $mark_updated_article_unread = $feed->attributes('mark_updated_article_unread') !== null ? ( + $feed->attributes('mark_updated_article_unread') + ) : FreshRSS_Context::$user_conf->mark_updated_article_unread; + // For this feed, check existing GUIDs already in database. $existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids); $newGuids = array(); @@ -379,11 +392,11 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } else { //This entry already exists but has been updated //Minz_Log::debug('Entry with GUID `' . $entry->guid() . '` updated in feed ' . $feed->url(false) . //', old hash ' . $existingHash . ', new hash ' . $entry->hash()); - $mark_updated_article_unread = $feed->attributes('mark_updated_article_unread') !== null ? - $feed->attributes('mark_updated_article_unread') : - FreshRSS_Context::$user_conf->mark_updated_article_unread; $needFeedCacheRefresh = $mark_updated_article_unread; $entry->_isRead($mark_updated_article_unread ? false : null); //Change is_read according to policy. + if ($mark_updated_article_unread) { + $feed->incPendingUnread(); //Maybe + } $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); if ($entry === null) { @@ -403,7 +416,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $id = uTimeString(); $entry->_id($id); - $entry->applyFilterActions(); + $entry->applyFilterActions($titlesAsRead); + if ($readWhenSameTitleInFeed > 0) { + $titlesAsRead[$entry->title()] = true; + } $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); if ($entry === null) { @@ -424,6 +440,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $entryDAO->beginTransaction(); } $entryDAO->addEntry($entry->toArray()); + $feed->incPendingUnread(); $nb_new_articles++; } } @@ -445,6 +462,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($needFeedCacheRefresh) { $feedDAO->updateCachedValues($feed->id()); } + $feed->keepMaxUnread(); if ($entryDAO->inTransaction()) { $entryDAO->commit(); } diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index f47988926..4bb08f495 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -112,6 +112,20 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { $feed->_attributes('read_upon_reception', Minz_Request::paramTernary('read_upon_reception')); $feed->_attributes('clear_cache', Minz_Request::paramTernary('clear_cache')); + $keep_max_n_unread = intval(Minz_Request::param('keep_max_n_unread', 0)); + $feed->_attributes('keep_max_n_unread', $keep_max_n_unread > 0 ? $keep_max_n_unread : null); + + $read_when_same_title_in_feed = Minz_Request::param('read_when_same_title_in_feed', ''); + if ($read_when_same_title_in_feed === '') { + $read_when_same_title_in_feed = null; + } else { + $read_when_same_title_in_feed = intval($read_when_same_title_in_feed); + if ($read_when_same_title_in_feed <= 0) { + $read_when_same_title_in_feed = false; + } + } + $feed->_attributes('read_when_same_title_in_feed', $read_when_same_title_in_feed); + $cookie = Minz_Request::param('curl_params_cookie', ''); $useragent = Minz_Request::param('curl_params_useragent', ''); $proxy_address = Minz_Request::param('curl_params', ''); diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php index ee58ebe5b..535f17e2e 100644 --- a/app/Models/ConfigurationSetter.php +++ b/app/Models/ConfigurationSetter.php @@ -205,12 +205,6 @@ class FreshRSS_ConfigurationSetter { $data['lazyload'] = $this->handleBool($value); } - private function _mark_when(&$data, $values) { - foreach ($values as $key => $value) { - $data['mark_when'][$key] = $this->handleBool($value); - } - } - private function _onread_jump_next(&$data, $value) { $data['onread_jump_next'] = $this->handleBool($value); } diff --git a/app/Models/Entry.php b/app/Models/Entry.php index 66e554e22..f75c0d704 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -341,12 +341,16 @@ class FreshRSS_Entry extends Minz_Model { return false; } - public function applyFilterActions() { + public function applyFilterActions($titlesAsRead = []) { if ($this->feed != null) { if ($this->feed->attributes('read_upon_reception') || ($this->feed->attributes('read_upon_reception') === null && FreshRSS_Context::$user_conf->mark_when['reception'])) { $this->_isRead(true); } + if (isset($titlesAsRead[$this->title()])) { + Minz_Log::debug('Mark title as read: ' . $this->title()); + $this->_isRead(true); + } foreach ($this->feed->filterActions() as $filterAction) { if ($this->matches($filterAction->booleanSearch())) { foreach ($filterAction->actions() as $action) { diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 012bdced8..423b913b0 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -15,6 +15,7 @@ class FreshRSS_Feed extends Minz_Model { private $category = 1; private $nbEntries = -1; private $nbNotRead = -1; + private $nbPendingNotRead = 0; private $name = ''; private $website = ''; private $description = ''; @@ -141,13 +142,13 @@ class FreshRSS_Feed extends Minz_Model { return $this->nbEntries; } - public function nbNotRead() { + public function nbNotRead($includePending = false) { if ($this->nbNotRead < 0) { $feedDAO = FreshRSS_Factory::createFeedDao(); $this->nbNotRead = $feedDAO->countNotRead($this->id()); } - return $this->nbNotRead; + return $this->nbNotRead + ($includePending ? $this->nbPendingNotRead : 0); } public function faviconPrepare() { require_once(LIB_PATH . '/favicons.php'); @@ -475,6 +476,24 @@ class FreshRSS_Feed extends Minz_Model { } } + /** + * To keep track of some new potentially unread articles since last commit+fetch from database + */ + public function incPendingUnread($n = 1) { + $this->nbPendingNotRead += $n; + } + + public function keepMaxUnread() { + $keepMaxUnread = $this->attributes('keep_max_n_unread'); + if ($keepMaxUnread == false) { + $keepMaxUnread = FreshRSS_Context::$user_conf->mark_when['max_n_unread']; + } + if ($keepMaxUnread > 0 && $this->nbNotRead(false) + $this->nbPendingNotRead > $keepMaxUnread) { + $feedDAO = FreshRSS_Factory::createFeedDao(); + $feedDAO->keepMaxUnread($this->id(), max(0, $keepMaxUnread - $this->nbPendingNotRead)); + } + } + public function cleanOldEntries() { //Remember to call updateCachedValue($id_feed) or updateCachedValues() just after $archiving = $this->attributes('archiving'); if ($archiving == null) { diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index af599c2a6..0d65e171d 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -363,6 +363,19 @@ SQL; } } + public function listTitles($id, $limit = null) { + $sql = 'SELECT title FROM `_entry` WHERE id_feed=:id_feed ORDER BY id DESC' + . ($limit < 1 ? '' : ' LIMIT ' . intval($limit)); + + $stm = $this->pdo->prepare($sql); + $stm->bindParam(':id_feed', $id, PDO::PARAM_INT); + + if ($stm && $stm->execute()) { + return $stm->fetchAll(PDO::FETCH_COLUMN, 0); + } + return false; + } + public function listByCategory($cat) { $sql = 'SELECT * FROM `_feed` WHERE category=?'; $stm = $this->pdo->prepare($sql); @@ -418,6 +431,46 @@ SQL; } } + public function keepMaxUnread($id, $n) { + //Double SELECT for MySQL workaround ERROR 1093 (HY000) + $sql = <<<'SQL' +UPDATE `_entry` SET is_read=1 +WHERE id_feed=:id_feed1 AND is_read=0 AND id <= (SELECT e3.id FROM ( + SELECT e2.id FROM `_entry` e2 + WHERE e2.id_feed=:id_feed2 AND e2.is_read=0 + ORDER BY e2.id DESC + LIMIT 1 + OFFSET :limit) e3) +SQL; + + $stm = $this->pdo->prepare($sql); + $stm->bindParam(':id_feed1', $id, PDO::PARAM_INT); + $stm->bindParam(':id_feed2', $id, PDO::PARAM_INT); + $stm->bindParam(':limit', $n, PDO::PARAM_INT); + + if (!$stm || !$stm->execute()) { + $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo(); + Minz_Log::error('SQL error keepMaxUnread: ' . json_encode($info)); + return false; + } + $affected = $stm->rowCount(); + + if ($affected > 0) { + $sql = 'UPDATE `_feed` ' + . 'SET `cache_nbUnreads`=`cache_nbUnreads`-' . $affected + . ' WHERE id=:id'; + $stm = $this->pdo->prepare($sql); + $stm->bindParam(':id', $id_feed, PDO::PARAM_INT); + if (!($stm && $stm->execute())) { + $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo(); + Minz_Log::error('SQL error keepMaxUnread cache: ' . json_encode($info)); + return false; + } + } + + return $affected; + } + public function truncate($id) { $sql = 'DELETE FROM `_entry` WHERE id_feed=:id'; $stm = $this->pdo->prepare($sql); diff --git a/app/i18n/cz/conf.php b/app/i18n/cz/conf.php index 01175cfef..bc52106e0 100644 --- a/app/i18n/cz/conf.php +++ b/app/i18n/cz/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'když je otevřen původní web s článkem', 'article_viewed' => 'během čtení článku', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'během skrolování', 'upon_reception' => 'po načtení článku', 'when' => 'Označit článek jako přečtený…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Počet zobrazených článků', diff --git a/app/i18n/de/conf.php b/app/i18n/de/conf.php index 5ccb3e738..09194ea8c 100644 --- a/app/i18n/de/conf.php +++ b/app/i18n/de/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'wenn der Artikel auf der Original-Webseite geöffnet wird', 'article_viewed' => 'wenn der Artikel angesehen wird', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'beim Scrollen bzw. Überspringen', 'upon_reception' => 'beim Empfang des Artikels', 'when' => 'Artikel als gelesen markieren…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Artikel zum Anzeigen', diff --git a/app/i18n/en-us/conf.php b/app/i18n/en-us/conf.php index c826d1098..e7f1a2b72 100644 --- a/app/i18n/en-us/conf.php +++ b/app/i18n/en-us/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'when the article is opened on its original website', 'article_viewed' => 'when the article is viewed', + 'keep_max_n_unread' => 'Max number of articles to keep unread', 'scroll' => 'while scrolling', 'upon_reception' => 'upon receiving the article', 'when' => 'Mark an article as read…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', ), 'show' => array( '_' => 'Articles to display', diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index e6beeb6c1..03905d671 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'when the article is opened on its original website', 'article_viewed' => 'when the article is viewed', + 'keep_max_n_unread' => 'Max number of articles to keep unread', 'scroll' => 'while scrolling', 'upon_reception' => 'upon receiving the article', 'when' => 'Mark an article as read…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', ), 'show' => array( '_' => 'Articles to display', diff --git a/app/i18n/es/conf.php b/app/i18n/es/conf.php index b05844592..e3fa6e9fe 100755 --- a/app/i18n/es/conf.php +++ b/app/i18n/es/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'cuando el artículo se abra en su web original', 'article_viewed' => 'cuando se muestre el artículo', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'durante el desplazamiento', 'upon_reception' => 'al recibir el artículo', 'when' => 'Marcar el artículo como leído…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Artículos a mostrar', diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php index 78d8bff1a..ea6a54862 100644 --- a/app/i18n/fr/conf.php +++ b/app/i18n/fr/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'lorsque l’article est ouvert sur le site d’origine', 'article_viewed' => 'lorsque l’article est affiché', + 'keep_max_n_unread' => 'Nombre maximum d’articles conservés non lus', 'scroll' => 'au défilement de la page', 'upon_reception' => 'dès la réception du nouvel article', 'when' => 'Marquer un article comme lu…', + 'when_same_title' => 'si un même titre existe déjà dans les <i>n</i> articles plus récents', ), 'show' => array( '_' => 'Articles à afficher', diff --git a/app/i18n/he/conf.php b/app/i18n/he/conf.php index 4d3dfb5c1..3dbf8127a 100644 --- a/app/i18n/he/conf.php +++ b/app/i18n/he/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'כאשר מאמר נפתח באתר המקורי', 'article_viewed' => 'כאשר מאמר נצפה', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'כאשר גוללים', 'upon_reception' => 'כאשר המאמר מתקבל', 'when' => 'סימון מאמרים כנקראו…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'מאמרים להצגה', diff --git a/app/i18n/it/conf.php b/app/i18n/it/conf.php index d24dda3a1..f10132fdc 100644 --- a/app/i18n/it/conf.php +++ b/app/i18n/it/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'Quando un articolo è aperto nel suo sito di origine', 'article_viewed' => 'Quando un articolo viene letto', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'Scorrendo la pagina', 'upon_reception' => 'Alla ricezione del contenuto', 'when' => 'Segna articoli come letti…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Articoli da visualizzare', diff --git a/app/i18n/ja/conf.php b/app/i18n/ja/conf.php index 81c85d2a7..244f9b87a 100644 --- a/app/i18n/ja/conf.php +++ b/app/i18n/ja/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => '記事を元のwebサイトで開いたとき', 'article_viewed' => '記事を読んだとき', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'スクロールしているとき', 'upon_reception' => '記事を受け取ったとき', 'when' => '記事を既読にする…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => '記事を表示する', diff --git a/app/i18n/kr/conf.php b/app/i18n/kr/conf.php index 4e6623034..fb88275b5 100644 --- a/app/i18n/kr/conf.php +++ b/app/i18n/kr/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => '글이 게재된 웹사이트를 방문했을 때', 'article_viewed' => '글을 읽었을 때', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => '스크롤을 하며 지나갈 때', 'upon_reception' => '글을 가져오자마자', 'when' => '읽음으로 표시…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => '글 표시 방식', diff --git a/app/i18n/nl/conf.php b/app/i18n/nl/conf.php index 9472a0d73..31c47608b 100644 --- a/app/i18n/nl/conf.php +++ b/app/i18n/nl/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'als het artikel wordt geopend op de originele website', 'article_viewed' => 'als het artikel wordt bekeken', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'tijdens het scrollen', 'upon_reception' => 'bij ontvangst van het artikel', 'when' => 'Markeer artikel als gelezen…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Artikelen om te tonen', diff --git a/app/i18n/oc/conf.php b/app/i18n/oc/conf.php index 07a62cddb..549614ae9 100644 --- a/app/i18n/oc/conf.php +++ b/app/i18n/oc/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'quand l’article es dobèrt sul site d’origina', 'article_viewed' => 'quand l’article es mostrat', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'en davalar la pagina', 'upon_reception' => 'en recebre un article novèl', 'when' => 'Marcar un article coma legit…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Articles de mostrar', diff --git a/app/i18n/pl/conf.php b/app/i18n/pl/conf.php index c50132a17..7908b44ee 100644 --- a/app/i18n/pl/conf.php +++ b/app/i18n/pl/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'gdy wiadomość jest otworzona na pierwotnej stronie', 'article_viewed' => 'gdy wiadomość jest otworzona', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'podczas przewijania', 'upon_reception' => 'po otrzymaniu wiadomości', 'when' => 'Oznacz wiadomość jako przeczytaną…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Wiadomości do wyświetlenia', diff --git a/app/i18n/pt-br/conf.php b/app/i18n/pt-br/conf.php index e5008eb03..34eaaa745 100644 --- a/app/i18n/pt-br/conf.php +++ b/app/i18n/pt-br/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'quando o artigo é aberto no site original', 'article_viewed' => 'Quando o artigo é visualizado', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'enquanto scrolling', 'upon_reception' => 'ao receber um artigo', 'when' => 'Marcar artigo como lido…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Artigos para exibir', diff --git a/app/i18n/ru/conf.php b/app/i18n/ru/conf.php index 9772c39ed..242bf063e 100644 --- a/app/i18n/ru/conf.php +++ b/app/i18n/ru/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'когда статья открывается на её сайте', 'article_viewed' => 'когда статья просматривается', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'во время прокрутки', 'upon_reception' => 'по получении статьи', 'when' => 'Отмечать статью прочитанной…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Какие статьи отображать', diff --git a/app/i18n/sk/conf.php b/app/i18n/sk/conf.php index e6b7d5b06..bddd51b26 100644 --- a/app/i18n/sk/conf.php +++ b/app/i18n/sk/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'keď je článok otvorený na svojej webovej stránke', 'article_viewed' => 'keď je článok zobrazený', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'počas skrolovania', 'upon_reception' => 'po načítaní článku', 'when' => 'Označiť článok ako prečítaný…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Článkov na zobrazenie', diff --git a/app/i18n/tr/conf.php b/app/i18n/tr/conf.php index 3c7ca101a..3379a19e3 100644 --- a/app/i18n/tr/conf.php +++ b/app/i18n/tr/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => 'orijinal makale sitesi açıldığında', 'article_viewed' => 'makale görüntülendiğinde', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => 'kaydırma yapılırken', 'upon_reception' => 'makale üzerinde gelince', 'when' => 'Makaleyi okundu olarak işaretle…', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => 'Gösterilecek makaleler', diff --git a/app/i18n/zh-cn/conf.php b/app/i18n/zh-cn/conf.php index 6c95b1576..45d287b8d 100644 --- a/app/i18n/zh-cn/conf.php +++ b/app/i18n/zh-cn/conf.php @@ -127,9 +127,11 @@ return array( 'read' => array( 'article_open_on_website' => '在打开原文章后', 'article_viewed' => '在文章被浏览后', + 'keep_max_n_unread' => 'Max number of articles to keep unread', // TODO - Translation 'scroll' => '在滚动浏览后', 'upon_reception' => '在接收文章后', 'when' => '何时将文章标记为已读', + 'when_same_title' => 'if an identical title already exists in the top <i>n</i> newest articles', // TODO - Translation ), 'show' => array( '_' => '文章显示', diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index 68d878eb0..e19a14067 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -207,12 +207,32 @@ data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['scroll'] ?>"/> <?= _t('conf.reading.read.scroll') ?> </label> + + <label class="checkbox" for="keep_max_n_unread"> + <input type="checkbox" name="enable_keep_max_n_unread" id="enable_keep_max_n_unread" value="1"<?= + empty(FreshRSS_Context::$user_conf->mark_when['max_n_unread']) ? '' : ' checked="checked"' ?> + data-leave-validation="<?= empty(FreshRSS_Context::$user_conf->mark_when['max_n_unread']) ? 0 : 1 ?>"/> + <?= _t('conf.reading.read.keep_max_n_unread') ?> + <?php $keep_max_n_unread = empty(FreshRSS_Context::$user_conf->mark_when['max_n_unread']) ? 1000 : FreshRSS_Context::$user_conf->mark_when['max_n_unread']; ?> + <input type="number" id="keep_max_n_unread" name="keep_max_n_unread" min="0" value="<?= $keep_max_n_unread ?>" data-leave-validation="<?= $keep_max_n_unread ?>" /> + </label> + <label class="checkbox" for="check_reception"> <input type="checkbox" name="mark_upon_reception" id="check_reception" value="1"<?= FreshRSS_Context::$user_conf->mark_when['reception'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['reception'] ?>"/> <?= _t('conf.reading.read.upon_reception') ?> </label> + + <label class="checkbox" for="read_when_same_title_in_feed"> + <input type="checkbox" name="enable_read_when_same_title_in_feed" id="enable_read_when_same_title_in_feed" value="1"<?= + empty(FreshRSS_Context::$user_conf->mark_when['same_title_in_feed']) ? '' : ' checked="checked"' ?> + data-leave-validation="<?= empty(FreshRSS_Context::$user_conf->mark_when['same_title_in_feed']) ? 0 : 1 ?>"/> + <?= _t('conf.reading.read.when_same_title') ?> + <?php $read_when_same_title_in_feed = empty(FreshRSS_Context::$user_conf->mark_when['same_title_in_feed']) ? 25 : FreshRSS_Context::$user_conf->mark_when['same_title_in_feed']; ?> + <input type="number" id="read_when_same_title_in_feed" name="read_when_same_title_in_feed" min="0" + value="<?= $read_when_same_title_in_feed ?>" data-leave-validation="<?= $read_when_same_title_in_feed ?>" /> + </label> </div> </div> diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 4bc9913c1..44e3c6c92 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -79,6 +79,43 @@ </div> </div> + <div class="form-group"> + <label class="group-name" for="ttl"><?= _t('sub.feed.ttl') ?></label> + <div class="group-controls"> + <select class="number" name="ttl" id="ttl" required="required"><?php + $found = false; + foreach (array(FreshRSS_Feed::TTL_DEFAULT => _t('gen.short.by_default'), 900 => '15min', 1200 => '20min', 1500 => '25min', 1800 => '30min', 2700 => '45min', + 3600 => '1h', 5400 => '1.5h', 7200 => '2h', 10800 => '3h', 14400 => '4h', 18800 => '5h', 21600 => '6h', 25200 => '7h', 28800 => '8h', + 36000 => '10h', 43200 => '12h', 64800 => '18h', + 86400 => '1d', 129600 => '1.5d', 172800 => '2d', 259200 => '3d', 345600 => '4d', 432000 => '5d', 518400 => '6d', + 604800 => '1wk', 1209600 => '2wk', 1814400 => '3wk', 2419200 => '4wk', 2629744 => '1mo') as $v => $t) { + echo '<option value="' . $v . ($this->feed->ttl() === $v ? '" selected="selected' : '') . '">' . $t . '</option>'; + if ($this->feed->ttl() == $v) { + $found = true; + } + } + if (!$found) { + echo '<option value="' . intval($this->feed->ttl()) . '" selected="selected">' . intval($this->feed->ttl()) . 's</option>'; + } + ?></select> + <label for="mute"> + <input type="checkbox" name="mute" id="mute" value="1"<?= $this->feed->mute() ? ' checked="checked"' : '' ?> /> + <?= _t('sub.feed.mute') ?> + </label> + </div> + </div> + + <?php if ($this->feed->pubSubHubbubEnabled()) { ?> + <div class="form-group"> + <div class="group-controls"> + <label class="checkbox" for="pubsubhubbub"> + <input type="checkbox" name="pubsubhubbub" id="pubsubhubbub" disabled="disabled" value="1" checked="checked" /> + <?= _t('sub.feed.websub') ?> + </label> + </div> + </div> + <?php } ?> + <div class="form-group form-actions"> <div class="group-controls"> <button class="btn btn-important"><?= _t('gen.action.submit') ?></button> @@ -90,6 +127,101 @@ </div> </div> + <legend><?= _t('sub.feed.auth.configuration') ?></legend> + <?php $auth = $this->feed->httpAuth(false); ?> + <div class="form-group"> + <label class="group-name" for="http_user_feed<?= $this->feed->id() ?>"><?= _t('sub.feed.auth.username') ?></label> + <div class="group-controls"> + <input type="text" name="http_user_feed<?= $this->feed->id() ?>" id="http_user_feed<?= $this->feed->id() ?>" class="extend" value="<?= + empty($auth['username']) ? ' ' : $auth['username'] ?>" autocomplete="off" /> + <p class="help"><?= _i('help') ?> <?= _t('sub.feed.auth.help') ?></p> + </div> + + <label class="group-name" for="http_pass_feed<?= $this->feed->id() ?>"><?= _t('sub.feed.auth.password') ?></label> + <div class="group-controls"> + <input type="password" name="http_pass_feed<?= $this->feed->id() ?>" id="http_pass_feed<?= $this->feed->id() ?>" class="extend" value="<?= + $auth['password'] ?>" autocomplete="new-password" /> + </div> + </div> + + <div class="form-group form-actions"> + <div class="group-controls"> + <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button> + <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button> + </div> + </div> + + <legend><?= _t('sub.feed.filteractions') ?></legend> + <div class="form-group"> + <label class="group-name" for="mark_updated_article_unread"><?= _t('conf.reading.mark_updated_article_unread') ?></label> + <div class="group-controls"> + <label class="checkbox" for="mark_updated_article_unread"> + <select name="mark_updated_article_unread" id="mark_updated_article_unread"> + <option value=""<?= $this->feed->attributes('mark_updated_article_unread') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option> + <option value="0"<?= $this->feed->attributes('mark_updated_article_unread') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option> + <option value="1"<?= $this->feed->attributes('mark_updated_article_unread') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option> + </select> + </label> + </div> + </div> + + <div class="form-group"> + <label class="group-name" for="keep_max_n_unread"><?= _t('conf.reading.read.keep_max_n_unread') ?></label> + <div class="group-controls"> + <input type="number" name="keep_max_n_unread" id="keep_max_n_unread" min="1" max="10000000" value="<?= $this->feed->attributes('keep_max_n_unread') ?>" placeholder="<?= _t('gen.short.by_default') ?>" /> + </div> + </div> + + <div class="form-group"> + <label class="group-name" for="read_upon_reception"><?= _t('conf.reading.read.when') ?></label> + <div class="group-controls"> + <label class="checkbox" for="read_upon_reception"> + <select name="read_upon_reception" id="read_upon_reception"> + <option value=""<?= $this->feed->attributes('read_upon_reception') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option> + <option value="0"<?= $this->feed->attributes('read_upon_reception') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option> + <option value="1"<?= $this->feed->attributes('read_upon_reception') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option> + </select> + <?= _t('conf.reading.read.upon_reception') ?> + </label> + </div> + </div> + + <div class="form-group"> + <label class="group-name" for="read_when_same_title_in_feed"><?= _t('conf.reading.read.when') ?></label> + <div class="group-controls"> + <label class="checkbox" for="read_when_same_title_in_feed"> + <select name="read_when_same_title_in_feed" id="read_when_same_title_in_feed"> + <option value=""<?= $this->feed->attributes('read_when_same_title_in_feed') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option> + <option value="0"<?= $this->feed->attributes('read_when_same_title_in_feed') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option> + <option value="10"<?= $this->feed->attributes('read_when_same_title_in_feed') == 10 ? ' selected="selected"' : '' ?>>10</option> + <option value="25"<?= $this->feed->attributes('read_when_same_title_in_feed') == 25 ? ' selected="selected"' : '' ?>>25</option> + <option value="100"<?= $this->feed->attributes('read_when_same_title_in_feed') == 100 ? ' selected="selected"' : '' ?>>100</option> + <option value="1000"<?= $this->feed->attributes('read_when_same_title_in_feed') == 1000 ? ' selected="selected"' : '' ?>>1 000</option> + </select> + <?= _t('conf.reading.read.when_same_title') ?> + </label> + </div> + </div> + + <div class="form-group"> + <label class="group-name" for="filteractions_read"><?= _t('conf.reading.read.when') ?></label> + <div class="group-controls"> + <textarea name="filteractions_read" id="filteractions_read"><?php + foreach ($this->feed->filtersAction('read') as $filterRead) { + echo $filterRead->getRawInput(), PHP_EOL; + } + ?></textarea> + <p class="help"><?= _i('help') ?> <?= _t('sub.feed.filteractions.help') ?></p> + </div> + </div> + + <div class="form-group form-actions"> + <div class="group-controls"> + <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button> + <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button> + </div> + </div> + <legend><?= _t('sub.feed.archiving') ?></legend> <div class="form-group"> @@ -220,43 +352,6 @@ </div> </div> - <div class="form-group"> - <label class="group-name" for="ttl"><?= _t('sub.feed.ttl') ?></label> - <div class="group-controls"> - <select class="number" name="ttl" id="ttl" required="required"><?php - $found = false; - foreach (array(FreshRSS_Feed::TTL_DEFAULT => _t('gen.short.by_default'), 900 => '15min', 1200 => '20min', 1500 => '25min', 1800 => '30min', 2700 => '45min', - 3600 => '1h', 5400 => '1.5h', 7200 => '2h', 10800 => '3h', 14400 => '4h', 18800 => '5h', 21600 => '6h', 25200 => '7h', 28800 => '8h', - 36000 => '10h', 43200 => '12h', 64800 => '18h', - 86400 => '1d', 129600 => '1.5d', 172800 => '2d', 259200 => '3d', 345600 => '4d', 432000 => '5d', 518400 => '6d', - 604800 => '1wk', 1209600 => '2wk', 1814400 => '3wk', 2419200 => '4wk', 2629744 => '1mo') as $v => $t) { - echo '<option value="' . $v . ($this->feed->ttl() === $v ? '" selected="selected' : '') . '">' . $t . '</option>'; - if ($this->feed->ttl() == $v) { - $found = true; - } - } - if (!$found) { - echo '<option value="' . intval($this->feed->ttl()) . '" selected="selected">' . intval($this->feed->ttl()) . 's</option>'; - } - ?></select> - <label for="mute"> - <input type="checkbox" name="mute" id="mute" value="1"<?= $this->feed->mute() ? ' checked="checked"' : '' ?> /> - <?= _t('sub.feed.mute') ?> - </label> - </div> - </div> - - <?php if ($this->feed->pubSubHubbubEnabled()) { ?> - <div class="form-group"> - <div class="group-controls"> - <label class="checkbox" for="pubsubhubbub"> - <input type="checkbox" name="pubsubhubbub" id="pubsubhubbub" disabled="disabled" value="1" checked="checked" /> - <?= _t('sub.feed.websub') ?> - </label> - </div> - </div> - <?php } ?> - <div class="form-group form-actions"> <div class="group-controls"> <button class="btn btn-important"><?= _t('gen.action.submit') ?></button> @@ -265,30 +360,6 @@ </div> </div> - <legend><?= _t('sub.feed.auth.configuration') ?></legend> - <?php $auth = $this->feed->httpAuth(false); ?> - <div class="form-group"> - <label class="group-name" for="http_user_feed<?= $this->feed->id() ?>"><?= _t('sub.feed.auth.username') ?></label> - <div class="group-controls"> - <input type="text" name="http_user_feed<?= $this->feed->id() ?>" id="http_user_feed<?= $this->feed->id() ?>" class="extend" value="<?= - empty($auth['username']) ? ' ' : $auth['username'] ?>" autocomplete="off" /> - <p class="help"><?= _i('help') ?> <?= _t('sub.feed.auth.help') ?></p> - </div> - - <label class="group-name" for="http_pass_feed<?= $this->feed->id() ?>"><?= _t('sub.feed.auth.password') ?></label> - <div class="group-controls"> - <input type="password" name="http_pass_feed<?= $this->feed->id() ?>" id="http_pass_feed<?= $this->feed->id() ?>" class="extend" value="<?= - $auth['password'] ?>" autocomplete="new-password" /> - </div> - </div> - - <div class="form-group form-actions"> - <div class="group-controls"> - <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button> - <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button> - </div> - </div> - <legend><?= _t('sub.feed.advanced') ?></legend> <div class="form-group"> <label class="group-name" for="path_entries"><?= _t('sub.feed.css_path') ?></label> @@ -328,43 +399,7 @@ </div> <div class="form-group"> - <label class="group-name" for="mark_updated_article_unread"><?= _t('conf.reading.mark_updated_article_unread') ?></label> - <div class="group-controls"> - <label class="checkbox" for="mark_updated_article_unread"> - <select name="mark_updated_article_unread" id="mark_updated_article_unread"> - <option value=""<?= $this->feed->attributes('mark_updated_article_unread') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option> - <option value="0"<?= $this->feed->attributes('mark_updated_article_unread') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option> - <option value="1"<?= $this->feed->attributes('mark_updated_article_unread') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option> - </select> - </label> - </div> - </div> - - <div class="form-group"> - <label class="group-name" for="read_upon_reception"><?= _t('conf.reading.read.when') ?></label> - <div class="group-controls"> - <label class="checkbox" for="read_upon_reception"> - <select name="read_upon_reception" id="read_upon_reception"> - <option value=""<?= $this->feed->attributes('read_upon_reception') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option> - <option value="0"<?= $this->feed->attributes('read_upon_reception') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option> - <option value="1"<?= $this->feed->attributes('read_upon_reception') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option> - </select> - <?= _t('conf.reading.read.upon_reception') ?> - </label> - </div> - </div> - - <div class="form-group"> - <div class="group-controls"> - <label class="checkbox" for="clear_cache"> - <input type="checkbox" name="clear_cache" id="clear_cache" value="1"<?= $this->feed->attributes('clear_cache') ? ' checked="checked"' : '' ?> /> - <?= _t('sub.feed.clear_cache') ?> - </label> - </div> - </div> - - <div class="form-group"> - <label class="group-name" for="path_entries"><?= _t('sub.feed.useragent') ?></label> + <label class="group-name" for="curl_params_useragent"><?= _t('sub.feed.useragent') ?></label> <div class="group-controls"> <div class="stick"> <input type="text" name="curl_params_useragent" id="curl_params_useragent" class="extend" value="<?= @@ -377,7 +412,7 @@ </div> <div class="form-group"> - <label class="group-name" for="path_entries"><?= _t('sub.feed.proxy') ?></label> + <label class="group-name" for="proxy_type"><?= _t('sub.feed.proxy') ?></label> <div class="group-controls"> <select class="number" name="proxy_type" id="proxy_type"><?php $type = ''; @@ -419,22 +454,18 @@ </div> </div> - <legend><?= _t('sub.feed.filteractions') ?></legend> <div class="form-group"> - <label class="group-name" for="filteractions_read"><?= _t('conf.reading.read.when') ?></label> <div class="group-controls"> - <textarea name="filteractions_read" id="filteractions_read"><?php - foreach ($this->feed->filtersAction('read') as $filterRead) { - echo $filterRead->getRawInput(), PHP_EOL; - } - ?></textarea> - <p class="help"><?= _i('help') ?> <?= _t('sub.feed.filteractions.help') ?></p> + <label class="checkbox" for="clear_cache"> + <input type="checkbox" name="clear_cache" id="clear_cache" value="1"<?= $this->feed->attributes('clear_cache') ? ' checked="checked"' : '' ?> /> + <?= _t('sub.feed.clear_cache') ?> + </label> </div> </div> <div class="form-group form-actions"> <div class="group-controls"> - <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button> + <button class="btn btn-important"><?= _t('gen.action.submit') ?></button> <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button> </div> </div> diff --git a/cli/i18n/ignore/en-us.php b/cli/i18n/ignore/en-us.php index 590a33f30..c7e978585 100644 --- a/cli/i18n/ignore/en-us.php +++ b/cli/i18n/ignore/en-us.php @@ -224,9 +224,11 @@ return array( 'conf.reading.number_divided_when_reader', 'conf.reading.read.article_open_on_website', 'conf.reading.read.article_viewed', + 'conf.reading.read.keep_max_n_unread', 'conf.reading.read.scroll', 'conf.reading.read.upon_reception', 'conf.reading.read.when', + 'conf.reading.read.when_same_title', 'conf.reading.show._', 'conf.reading.show.active_category', 'conf.reading.show.adaptive', diff --git a/config-user.default.php b/config-user.default.php index d7831cee9..ef2218bab 100644 --- a/config-user.default.php +++ b/config-user.default.php @@ -49,9 +49,11 @@ return array ( 'anon_access' => false, 'mark_when' => array ( 'article' => true, - 'site' => true, - 'scroll' => true, + 'max_n_unread' => false, 'reception' => false, + 'same_title_in_feed' => false, + 'scroll' => true, + 'site' => true, ), 'theme' => 'Origine', 'content_width' => 'thin', |
