Browse Source

Hook to modify the list of feeds to actualize (#8655)

* Add FeedsListBeforeActualize hook.

Closes #8650
Implement new hook to allow extensions to modify the list of feeds to actualize.  

How to test the feature manually:

1. Add several feeds from a single site (e.g. reddit and YT).  
2. Add feeds to other sites.  
3. Add and enable the extension https://github.com/pe1uca/xExtension-Declumping  
4. Call `php app/actualize_script.php` to update feeds with a different order.  

A log like this one is needed to properly see the behavior.  
```php
foreach ($feeds as $key => $value) {
    syslog(LOG_INFO, "$key: {$value->name()} ({$value->url()})");
}
```

Sort in alphabetical order.

* Implement call to hook

* Remove duplicate return

* Fix PHPStan error

* Update documentation

* Sanitize hook response

* Markdown cleaning

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
pe1uca 19 giờ trước cách đây
mục cha
commit
bca9a5586e

+ 7 - 0
app/Controllers/feedController.php

@@ -469,6 +469,13 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
 		/** @var array<int,array<string,true>> */
 		$categoriesEntriesTitle = [];
 
+		$feeds = Minz_ExtensionManager::callHook(Minz_HookType::FeedsListBeforeActualize, $feeds);
+		if (is_array($feeds)) {
+			$feeds = array_filter($feeds, static fn($feed): bool => $feed instanceof FreshRSS_Feed);
+		} else {
+			$feeds = [];
+		}
+
 		foreach ($feeds as $feed) {
 			$feed = Minz_ExtensionManager::callHook(Minz_HookType::FeedBeforeActualize, $feed);
 			if (!($feed instanceof FreshRSS_Feed)) {

+ 1 - 0
docs/en/developers/03_Backend/05_Extensions.md

@@ -189,6 +189,7 @@ Example response for a `query_icon_info` request:
 * `Minz_HookType::EntryBeforeUpdate` (`function($entry) -> Entry | null`): will be executed when a feed is refreshed and just before an entry is updated in the database. Useful for reading the final state of the entry after filter actions have been applied. The updated entry (instance of FreshRSS\_Entry) will be passed as parameter.
 * `Minz_HookType::FeedBeforeActualize` (`function($feed) -> Feed | null`): will be executed when a feed is updated. The feed (instance of FreshRSS\_Feed) will be passed as parameter.
 * `Minz_HookType::FeedBeforeInsert` (`function($feed) -> Feed | null`): will be executed when a new feed is imported into the database. The new feed (instance of FreshRSS\_Feed) will be passed as parameter.
+* `Minz_HookType::FeedsListBeforeActualize` (`function(array<FreshRSS_Feed> $feedList) -> array | null`): will be executed before FreshRSS tries to update feeds. The list of feeds (array of `FreshRSS_Feed`) to update will be passed as a parameter. Useful for modifying the order in which the feeds will be updated.
 * `Minz_HookType::FreshrssInit` (`function() -> none`): will be executed at the end of the initialization of FreshRSS, useful to initialize components or to do additional access checks.
 * `Minz_HookType::FreshrssUserMaintenance` (`function() -> none`): will be executed for each user during the `actualize_script`, useful to run some maintenance tasks on the user.
 * `Minz_HookType::JsVars` (`function($vars = array) -> array | null`): will be executed if the `jsonVars` in the header will be generated.

+ 4 - 1
docs/fr/developers/03_Backend/05_Extensions.md

@@ -249,11 +249,14 @@ The following events are available:
 * `entries_favorite` (`function(array $ids, bool $is_favorite): void`):
 	will be executed when some entries are marked or unmarked as favorites (starred)
 * `feed_before_actualize` (`function($feed) -> Feed | null`): will be
-	executed when a feed is updated. The feed (instance of FreshRSS\_Feed)
+	executed when a feed is updated. The feed (instance of `FreshRSS_Feed`)
 	will be passed as parameter.
 * `feed_before_insert` (`function($feed) -> Feed | null`): will be executed
 	when a new feed is imported into the database. The new feed (instance of
 	FreshRSS\_Feed) will be passed as parameter.
+* `feeds_list_before_actualize` (`function(array<FreshRSS_Feed> $feedList) -> array | null`) : exécuté avant que FreshRSS actualise les flux.
+	La liste des flux (tableau 	de `FreshRSS_Feed`) à actualiser sera passé comme le paramètre.
+	Utile pour modifier l’ordre dans lequel les flux seront mis à jour
 * `freshrss_init` (`function() -> none`): will be executed at the end of the
 	initialization of FreshRSS, useful to initialize components or to do
 	additional access checks

+ 5 - 3
lib/Minz/HookType.php

@@ -11,12 +11,13 @@ enum Minz_HookType: string {
 	case EntriesFavorite = 'entries_favorite';	// function(array $ids, bool $is_favorite): void
 	case EntryAutoRead = 'entry_auto_read';	// function(FreshRSS_Entry $entry, string $why): void
 	case EntryAutoUnread = 'entry_auto_unread';	// function(FreshRSS_Entry $entry, string $why): void
+	case EntryBeforeAdd = 'entry_before_add';	// function(FreshRSS_Entry $entry) -> FreshRSS_Entry | null
 	case EntryBeforeDisplay = 'entry_before_display';	// function(FreshRSS_Entry $entry) -> FreshRSS_Entry | null
 	case EntryBeforeInsert = 'entry_before_insert';	// function(FreshRSS_Entry $entry) -> FreshRSS_Entry | null
-	case EntryBeforeAdd = 'entry_before_add';	// function(FreshRSS_Entry $entry) -> FreshRSS_Entry | null
 	case EntryBeforeUpdate = 'entry_before_update';	// function(FreshRSS_Entry $entry) -> FreshRSS_Entry | null
 	case FeedBeforeActualize = 'feed_before_actualize';	// function(FreshRSS_Feed $feed) -> FreshRSS_Feed | null
 	case FeedBeforeInsert = 'feed_before_insert';	// function(FreshRSS_Feed $feed) -> FreshRSS_Feed | null
+	case FeedsListBeforeActualize = 'feeds_list_before_actualize';	// function(array $feedsList) -> array
 	case FreshrssInit = 'freshrss_init';	// function() -> none
 	case FreshrssUserMaintenance = 'freshrss_user_maintenance';	// function() -> none
 	case JsVars = 'js_vars';	// function($vars = array) -> array | null
@@ -45,16 +46,17 @@ enum Minz_HookType: string {
 			case self::NavEntries:
 			case self::NavMenu:
 				return Minz_HookSignature::NoneToString;
+			case self::ActionExecute:
 			case self::CheckUrlBeforeAdd:
+			case self::EntryBeforeAdd:
 			case self::EntryBeforeDisplay:
 			case self::EntryBeforeInsert:
-			case self::EntryBeforeAdd:
 			case self::EntryBeforeUpdate:
 			case self::FeedBeforeActualize:
 			case self::FeedBeforeInsert:
+			case self::FeedsListBeforeActualize:
 			case self::JsVars:
 			case self::NavReadingModes:
-			case self::ActionExecute:
 			case self::ViewModes:
 				return Minz_HookSignature::OneToOne;
 			case self::CustomFaviconBtnUrl: