Écriture d’extensions pour FreshRSS

Présentation de FreshRSS

FreshRSS est un agrégateur de flux RSS / Atom écrit en PHP depuis octobre

  1. Le site officiel est situé à l’adresse
    freshrss.org et son dépot Git est hébergé par GitHub
    github.com/FreshRSS/FreshRSS.

Problème à résoudre

FreshRSS est limité dans ses possibilités techniques par différents facteurs :

Si la première limitation peut, en théorie, être levée par la participation de nouveaux contributeurs au projet, elle est en réalité conditionnée par la volonté des contributeurs à s’intéresser au code source du projet en entier. Afin de lever les deux autres limitations quant à elles, il faudra la plupart du temps passer par un « à-coté » souvent synonyme de « fork ».

Une autre solution consiste à passer par un système d’extensions. En permettant à des utilisateurs d’écrire leur propre extension sans avoir à s’intéresser au cœur même du logiciel de base, on permet :

  1. De réduire la quantité de code source à assimiler pour un nouveau contributeur ;
  2. De permettre d’intégrer des nouveautés de façon non-officielles ;
  3. De se passer des développeurs principaux pour d’éventuelles améliorations sans passer par la case « fork ».

Note : il est tout à fait imaginable que les fonctionnalités d’une extension puissent par la suite être intégrées dans le code initial de FreshRSS de façon officielle. Cela permet de proposer un « proof of concept » assez facilement.

Minz Framework

see Minz documentation

Écrire une extension pour FreshRSS

Nous y voilà ! Nous avons abordé les fonctionnalités les plus utiles de Minz et qui permettent de faire tourner FreshRSS correctement et il est plus que temps d’aborder les extensions en elles-même.

Une extension permet donc d’ajouter des fonctionnalités facilement à FreshRSS sans avoir à toucher au cœur du projet directement.

Travailler dans Docker

Quand on travaille sur une extension, c’est toujours plus facile de la travailler directement dans son environnement. Avec Docker, on peut exploiter l’option volume quand on démarre le conteneur. Heureusement, on peut l’utiliser sans avoir de connaissances particulières de Docker en utilisant la règle du Makefile :

make start extensions="/chemin/complet/de/l/extension/1 /chemin/complet/de/l/extension/2"

Les fichiers et répertoires de base

La première chose à noter est que toutes les extensions doivent se situer dans le répertoire extensions, à la base de l’arborescence de FreshRSS. Une extension est un répertoire contenant un ensemble de fichiers et sous-répertoires obligatoires ou facultatifs. La convention veut que l’on précède le nom du répertoire principal par un « x » pour indiquer qu’il ne s’agit pas d’une extension incluse par défaut dans FreshRSS.

Le répertoire principal d’une extension doit comporter au moins deux fichiers obligatoire :

Please note that there is a not a required link between the directory name of the extension and the name of the class inside extension.php, but you should follow our best practice: If you want to write a HelloWorld extension, the directory name should be xExtension-HelloWorld and the base class name HelloWorldExtension.

In the file freshrss/extensions/xExtension-HelloWorld/extension.php you need the structure:

final class HelloWorldExtension extends Minz_Extension {
	#[\Override]
	public function init() {
		parent::init();

		// your code here
	}
}

There is an example HelloWorld extension that you can download from our GitHub repo.

You may also need additional files or subdirectories depending on your needs:

In addition, it is good to have a LICENSE file indicating the license under which your extension is distributed and a README file giving a detailed description of it.

The metadata.json file

The metadata.json file defines your extension through a number of important elements. It must contain a valid JSON array containing the following entries:

Seuls les champs name et entrypoint sont requis.

Choisir entre extension « system » ou « user »

A user extension can be enabled by some users and not by others (typically for user preferences).

A system extension in comparison is enabled for every account.

Writing your own extension.php

This file is the entry point of your extension. It must contain a specific class to function. As mentioned above, the name of the class must be your entrypoint suffixed by Extension (HelloWorldExtension for example). In addition, this class must be inherited from the Minz_Extension class to benefit from extensions-specific methods.

Your class will benefit from four methods to redefine:

À FAIRE

Le système « hooks »

You can register at the FreshRSS event system in an extensions init() method, to manipulate data when some of the core functions are executed.

final class HelloWorldExtension extends Minz_Extension
{
	#[\Override]
	public function init(): void {
		parent::init();

		$this->registerHook('entry_before_display', [$this, 'renderEntry']);
		$this->registerHook('check_url_before_add', [self::class, 'checkUrl']);
	}

	public function renderEntry(FreshRSS_Entry $entry): FreshRSS_Entry {
		$message = $this->getUserConfigurationValue('message');
		$entry->_content("<h1>{$message}</h1>" . $entry->content());
		return $entry;
	}

	public static function checkUrlBeforeAdd(string $url): string {
		if (str_starts_with($url, 'https://')) {
			return $url;
		}
		return null;
	}
}

The following events are available:

ℹ️ Note: the simplepie_* hooks are only fired for feeds using SimplePie via pull, i.e. normal RSS/Atom feeds. This excludes WebSub (push), and the various HTML or JSON Web scraping methods.

Writing your own configure.phtml

When you want to support user configurations for your extension or simply display some information, you have to create the configure.phtml file.

À FAIRE