Просмотр исходного кода

Add per-feed option to show or hide enclosures (#9015)

* Add per-feed option to show or hide enclosures

Some feeds attach lots of enclosures (images, audio, video, downloads)
that clutter the article view for readers who only want the text. Add
a per-feed "Show enclosures" setting (Feed configuration > Display),
defaulting to "by default" (i.e. shown, matching current behaviour),
following the same ternary-attribute pattern used by existing
per-feed overrides such as show_unread_count and read_upon_gone.

Also apply the preference to the GReader-compat API content call and
the Fever API entry serialization, so third-party clients like Reeder
and Fever apps respect it too, not just the normal web UI. Renamed the
translation key to display_enclosures to match the underlying feed
attribute name.

Fixes #4999

* i18n: fr

* Fix Fever API

* Remove accessor

* Forgotten fix

---------

Co-authored-by: Gerard Alvear <gerard.alvear@logiqd.me>
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Gerard Alvear Porras 1 день назад
Родитель
Сommit
1b8eb17858

+ 1 - 0
CHANGELOG.md

@@ -18,6 +18,7 @@ See also [the FreshRSS releases](https://github.com/FreshRSS/FreshRSS/releases).
 * Features
 	* New option to hide badges showing number of unread articles (*Phantom Obligation*) [#8844](https://github.com/FreshRSS/FreshRSS/pull/8844)
 	* New option to keep or not the custom sort order when navigating between categories and feeds [#8969](https://github.com/FreshRSS/FreshRSS/pull/8969)
+	* New per-feed option to show or hide enclosures (attachments) [#4999](https://github.com/FreshRSS/FreshRSS/issues/4999)
 * Bug fixing
 	* Fix lost elements while parsing search query [#8884](https://github.com/FreshRSS/FreshRSS/pull/8884)
 * CLI

+ 1 - 1
README.fr.md

@@ -234,7 +234,7 @@ Voir le [dépôt dédié à ces extensions](https://github.com/FreshRSS/Extensio
 | English (United States) (en-US) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen-US+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Español (es) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fes+%2F%28TODO%7CDIRTY%29%24%2F) |
 | فارسی (fa) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffa+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Suomi (fi) | ■■■■■■■■■・ 92% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
+| Suomi (fi) | ■■■■■■■■■・ 91% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Français (fr) | ■■■■■■■■■■ 100% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffr+%2F%28TODO%7CDIRTY%29%24%2F) |
 | עברית (he) | ■■■■・・・・・・ 41% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Magyar (hu) | ■■■■■■■■■・ 99% | [contribuer](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%24%2F) |

+ 1 - 1
README.md

@@ -130,7 +130,7 @@ See the [repository dedicated to those extensions](https://github.com/FreshRSS/E
 | English (United States) (en-US) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fen-US+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Español (es) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fes+%2F%28TODO%7CDIRTY%29%24%2F) |
 | فارسی (fa) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffa+%2F%28TODO%7CDIRTY%29%24%2F) |
-| Suomi (fi) | ■■■■■■■■■・ 92% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
+| Suomi (fi) | ■■■■■■■■■・ 91% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffi+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Français (fr) | ■■■■■■■■■■ 100% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Ffr+%2F%28TODO%7CDIRTY%29%24%2F) |
 | עברית (he) | ■■■■・・・・・・ 41% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhe+%2F%28TODO%7CDIRTY%29%24%2F) |
 | Magyar (hu) | ■■■■■■■■■・ 99% | [contribute](https://github.com/search?q=repo%3AFreshRSS%2FFreshRSS+path%3Aapp%2Fi18n%2Fhu+%2F%28TODO%7CDIRTY%29%24%2F) |

+ 1 - 0
app/Controllers/subscriptionController.php

@@ -153,6 +153,7 @@ class FreshRSS_subscription_Controller extends FreshRSS_ActionController {
 			if (Minz_Request::hasParam('show_unread_count')) {
 				$feed->_attribute('show_unread_count', Minz_Request::paramTernary('show_unread_count'));
 			}
+			$feed->_attribute('display_enclosures', Minz_Request::paramTernary('display_enclosures'));
 
 			$keep_max_n_unread = Minz_Request::paramTernary('keep_max_n_unread') === true ? Minz_Request::paramInt('keep_max_n_unread') : null;
 			$feed->_attribute('keep_max_n_unread', $keep_max_n_unread >= 0 ? $keep_max_n_unread : null);

+ 1 - 1
app/Models/Entry.php

@@ -1249,7 +1249,7 @@ class FreshRSS_Entry extends Minz_Model {
 			$item['title'] = escapeToUnicodeAlternative($this->title(), false);
 			unset($item['alternate'][0]['type']);
 			$item['summary'] = [
-				'content' => mb_strcut($this->content(true), 0, self::API_MAX_COMPAT_CONTENT_LENGTH, 'UTF-8'),
+				'content' => mb_strcut($this->content($feed?->attributeBoolean('display_enclosures') ?? true), 0, self::API_MAX_COMPAT_CONTENT_LENGTH, 'UTF-8'),
 			];
 		} else {
 			$item['content'] = [

+ 1 - 0
app/i18n/cs/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'For compatible themes only',	// TODO
 			'no' => 'Ne',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Spodní řádek',
 			'display_authors' => 'Autoři',

+ 1 - 0
app/i18n/de/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Nur für kompatible Themes',
 			'no' => 'Nein',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Fußzeile',
 			'display_authors' => 'Autoren',

+ 1 - 0
app/i18n/el/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Μόνο για συμβατά θέματα',
 			'no' => 'Όχι',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Κάτω γραμμή',
 			'display_authors' => 'Συντάκτες',

+ 1 - 0
app/i18n/en-US/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'For compatible themes only',	// IGNORE
 			'no' => 'No',	// IGNORE
 		),
+		'display_enclosures' => 'Show enclosures',	// IGNORE
 		'icon' => array(
 			'bottom_line' => 'Bottom line',	// IGNORE
 			'display_authors' => 'Authors',	// IGNORE

+ 1 - 0
app/i18n/en/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'For compatible themes only',
 			'no' => 'No',
 		),
+		'display_enclosures' => 'Show enclosures',
 		'icon' => array(
 			'bottom_line' => 'Bottom line',
 			'display_authors' => 'Authors',

+ 1 - 0
app/i18n/es/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Solo para temas compatibles',
 			'no' => 'No',	// IGNORE
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Línea inferior',
 			'display_authors' => 'Autores',

+ 1 - 0
app/i18n/fa/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'کمک',
 			'no' => 'خیر',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => ' خط پایین',
 			'display_authors' => ' نویسندگان',

+ 1 - 0
app/i18n/fi/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Toimii vain yhteensopivissa teemoissa',
 			'no' => 'Ei',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Alin rivi',
 			'display_authors' => 'Kirjoittajat',

+ 1 - 0
app/i18n/fr/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Seulement pour les thèmes compatibles',
 			'no' => 'Non',
 		),
+		'display_enclosures' => 'Afficher les pièces jointes',
 		'icon' => array(
 			'bottom_line' => 'Ligne du bas',
 			'display_authors' => 'Auteurs',

+ 1 - 0
app/i18n/he/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'For compatible themes only',	// TODO
 			'no' => 'No',	// TODO
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'שורה תחתונה',
 			'display_authors' => 'Authors',	// TODO

+ 1 - 0
app/i18n/hu/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Csak kompatibilis témákhoz',
 			'no' => 'Nem',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Alsó sor',
 			'display_authors' => 'Szerzők',

+ 1 - 0
app/i18n/id/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Hanya untuk tema yang kompatibel',
 			'no' => 'Tidak',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Baris bawah',
 			'display_authors' => 'Penulis',

+ 1 - 0
app/i18n/it/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Solo per i temi compatibili',
 			'no' => 'No',	// IGNORE
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Barra in fondo',
 			'display_authors' => 'Autori',

+ 1 - 0
app/i18n/ja/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => '対応テーマのみ',
 			'no' => '無効',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => '下段',
 			'display_authors' => '著者',

+ 1 - 0
app/i18n/ko/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'For compatible themes only',	// TODO
 			'no' => '끄기',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => '하단',
 			'display_authors' => '저자',

+ 1 - 0
app/i18n/lv/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Tikai saderīgām tēmām',
 			'no' => 'Nē',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Apakšējā līnija',
 			'display_authors' => 'Autori',

+ 1 - 0
app/i18n/nl/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Alleen voor compatibele thema’s',
 			'no' => 'Nee',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Onderaan',
 			'display_authors' => 'Auteurs',

+ 1 - 0
app/i18n/oc/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'For compatible themes only',	// TODO
 			'no' => 'No',	// TODO
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Linha enbàs',
 			'display_authors' => 'Autors',

+ 1 - 0
app/i18n/pl/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Wyłącznie dla kompatybilnych wyglądów',
 			'no' => 'Wyłączony',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Dolny margines',
 			'display_authors' => 'Autorzy',

+ 1 - 0
app/i18n/pt-BR/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Somente para temas compatíveis',
 			'no' => 'Não',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Linha inferior',
 			'display_authors' => 'Autores',

+ 1 - 0
app/i18n/pt-PT/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'For compatible themes only',	// TODO
 			'no' => 'Não',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Linha inferior',
 			'display_authors' => 'Autores',

+ 1 - 0
app/i18n/ru/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Только для совместимых тем',
 			'no' => 'Нет',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Нижняя линия',
 			'display_authors' => 'Авторы',

+ 1 - 0
app/i18n/sk/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'For compatible themes only',	// TODO
 			'no' => 'Nie',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Spodný riadok',
 			'display_authors' => 'Autori',

+ 1 - 0
app/i18n/tr/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Yalnızca uyumlu temalar için',
 			'no' => 'Hayır',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Alt satır',
 			'display_authors' => 'Yazarlar',

+ 1 - 0
app/i18n/uk/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => 'Лише для підтримуваних тем',
 			'no' => 'Вимкнено',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => 'Нижній рядок',
 			'display_authors' => 'Автори',

+ 1 - 0
app/i18n/zh-CN/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => '仅适用于兼容性主题',
 			'no' => '关闭',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => '底栏',
 			'display_authors' => '作者',

+ 1 - 0
app/i18n/zh-TW/conf.php

@@ -38,6 +38,7 @@ return array(
 			'help' => '僅適用於相容主題',
 			'no' => '否',
 		),
+		'display_enclosures' => 'Show enclosures',	// TODO
 		'icon' => array(
 			'bottom_line' => '底部',
 			'display_authors' => '作者',

+ 11 - 0
app/views/helpers/feed/update.phtml

@@ -173,6 +173,17 @@
 				</div>
 			</div>
 
+			<div class="form-group">
+				<label class="group-name" for="display_enclosures"><?= _t('conf.display.display_enclosures') ?></label>
+				<div class="group-controls">
+					<select name="display_enclosures" id="display_enclosures" class="w50">
+						<option value=""<?= $this->feed->attributeBoolean('display_enclosures') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
+						<option value="0"<?= $this->feed->attributeBoolean('display_enclosures') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
+						<option value="1"<?= $this->feed->attributeBoolean('display_enclosures') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
+					</select>
+				</div>
+			</div>
+
 			<?php
 				$feedDefaultSort = $this->feed->defaultSort();
 				$feedDefaultOrder = $this->feed->defaultOrder();

+ 1 - 1
app/views/helpers/index/article.phtml

@@ -99,7 +99,7 @@
 		</header>
 
 		<div class="text">
-			<?= $entry->content(true) ?>
+			<?= $entry->content($feed->attributeBoolean('display_enclosures') ?? true) ?>
 		</div>
 		<?php
 		$display_authors_date = in_array(FreshRSS_Context::userConf()->show_author_date, ['b', 'f'], true);

+ 3 - 1
app/views/index/normal.phtml

@@ -128,7 +128,9 @@ $today = @strtotime('today');
 					<?php } ?>
 				</header>
 				<div class="text"><?=
-					FreshRSS_Context::userConf()->lazyload && !FreshRSS_Context::userConf()->display_posts ? lazyimg($this->entry->content(true)) : $this->entry->content(true)
+					FreshRSS_Context::userConf()->lazyload && !FreshRSS_Context::userConf()->display_posts ?
+						lazyimg($this->entry->content($this->feed->attributeBoolean('display_enclosures') ?? true)) :
+						$this->entry->content($this->feed->attributeBoolean('display_enclosures') ?? true)
 				?></div>
 				<?php
 				$display_authors_date = FreshRSS_Context::userConf()->show_author_date === 'f' || FreshRSS_Context::userConf()->show_author_date === 'b';

+ 2 - 1
p/api/fever.php

@@ -553,7 +553,8 @@ final class FeverAPI
 				'feed_id' => $entry->feedId(),
 				'title' => escapeToUnicodeAlternative($entry->title(), false),
 				'author' => escapeToUnicodeAlternative(trim($entry->authors(true), '; '), false),
-				'html' => $entry->content(), 'url' => htmlspecialchars_decode($entry->link(), ENT_QUOTES),
+				'html' => $entry->content($entry->feed()?->attributeBoolean('display_enclosures') ?? true),
+				'url' => htmlspecialchars_decode($entry->link(), ENT_QUOTES),
 				'is_saved' => $entry->isFavorite() ? 1 : 0,
 				'is_read' => $entry->isRead() ? 1 : 0,
 				'created_on_time' => $entry->date(true),