Blog Shivato Web Developpement web

21avr/13

Personnalisation Selfoss (Agrégateur de flux RSS)

Edit du 27/04/2014 :
Bien qu'à l'époque de ma recherche, Selfoss était le meilleur que j'ai pu tester dans le monde du libre, après 1 an d'utilisation, je n'ai toujours pas réussi à être convaincu à 100 % que ce soit un bon remplaçant de Google Reader.
J'ai donc fait une nouvelle recherche dernièrement et je suis tombé sur FreshRSS (https://github.com/marienfressinaud/FreshRSS/), Bien qu'il ne soit toujours pas en version 1, celui-ci est très fonctionnel, installation simple, fluide et il n'y a rien à retouché pour son plaisir, tout est déjà implémenté.
Après 1 semaine de test et vérifier qu'il ne manque pas de flux par rapport à ce que j'avais déjà, il a remplacé selfoss sur mon serveur.
Le seul petit problème que j'ai eu est sur le lancement du cron de mise à jour des flux sur un hébergement mutualisé OVH, le fait de le lancer en PHP 5.3 utilise les magic_quotes et register_globals, cela empêche le bon fonctionnement du script. Pour remédier à cela, il suffit juste de le lancer en PHP 5.4 et tout fonctionne.

Comme tout le monde le sait, Google Reader s'arrête le 1 juillet 2013.
A l'annonce de cette nouvelle ce fut la fin du monde pour tout le monde comme pour moi.
Il me faut maintenant trouver un remplaçant pour continuer à suivre les centaines de flux que je suis tous les jours.
Après avoir essayé différents lecteurs RSS sur le web qui ne m'ont pas vraiment convaincu (ils travaillent tous dessus donc il faut peut être encore attendre pour trouver le remplaçant de Google), j'ai été voir du côté des agrégateurs libre et là pareil, il n'y a pas grand-chose de vraiment bien, ils ont tous leurs défauts.
Ma recherche se fait sur un outil simple et rapide, au final j'en ai retenu un qui est Selfoss (http://selfoss.aditu.de/).

Nous allons voir dans cet article comment corriger quelques défauts (cet article concerne la version 2.4 de Selfoss) :
1. Installation basique
2. Pré-fixage des tables
3. Ajout en favoris dans la barre de titre
4. Correction sur les dates françaises
5. Paramétrage de la purge
6. Lancement du cron sur un serveur OVH mutualisé

1. Installation basique

Commençons par l'installation par défaut, téléchargez les sources sur le site http://selfoss.aditu.de/.
Copiez le fichier defaults.ini en config.ini puis éditez le fichier.
Remplissez les informations de databases puis aller sur un navigateur pour pointer vers le dossier de Selfoss.
L'installation se fait tout seul, votre application est prête.
Si on regarde en BDD 4 tables ont été créés (items, sources, tags et version), c'est beaucoup mieux que d'autres agrégateurs qui vous crée 20 à 30 tables pour lire des flux.

2. Pré-fixage des tables

Le premier problème se présente ici, en prod je vais l'installer sur une database qui contient déjà d'autres applications et le nom des tables ne sont pas préfixées ce qui peut poser des conflits, nous allons donc ajouter dans le fichier de conf le pré-fixage que l'on souhaite.
Pour ce faire on va ajouter dans config.ini une variable afin d'obtenir des noms de tables comme rss_items, rss_sources, rss_tags, rss_version.

db_prefix=rss_

Maintenant nous allons modifier les sources PHP pour prendre en compte cette nouvelle variable de conf.
Les sources à modifier se trouvent dans le dossier daos, voici la liste des fichiers impactés (rassurez vous les sources sont à la fin de l'article) :
daos/mysql/Database.php
daos/mysql/Items.php
daos/mysql/Sources.php
daos/mysql/Tags.php
daos/pgsql/Database.php
daos/pgsql/Items.php
daos/pgsql/Sources.php
daos/sqlite/Database.php
daos/sqlite/Sources.php

Le but est d'ajouter la ligne suivante avant chaque nom de table dans les requêtes et également dans les conditions qui vérifient si les tables existent pour faire l'installation.

// Code a ajouter : \F3::get('db_prefix')

// Exemple pour une requête et une condition
if(!in_array(\F3::get('db_prefix') . 'items', $tables))
    \F3::get('db')->exec('
        CREATE TABLE ' . \F3::get('db_prefix') . 'items (
            id INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
            datetime DATETIME NOT NULL ,
            title TEXT NOT NULL ,
            content LONGTEXT NOT NULL ,
            thumbnail TEXT ,
            icon TEXT ,
            unread BOOL NOT NULL ,
            starred BOOL NOT NULL ,
            source INT NOT NULL ,
            uid VARCHAR(255) NOT NULL,
            link TEXT NOT NULL,
            INDEX (source)
        ) ENGINE = MYISAM DEFAULT CHARSET=utf8;
    ');

Retournez sur votre navigateur, actualiser la page et les 4 nouvelles tables sont créées, on peut donc supprimer les anciennes sans préfixe.

3. Ajout en favoris dans la barre de titre

Maintenant il y a encore un point qui pour moi est très gênant c'est qu'il faut ouvrir la news pour la marquer comme favoris, ce qui est assez pénible.
Nous allons donc remédier à cela en éditant les fichiers suivants :

- templates/item.phtml
Ajoutez une ligne pour ajouter la petite étoile au-dessus de la ligne pour l'icone :

<!-- Ajout de l'étoile dans la barre de titre -->
<span class="title-starr entry-starr <?PHP echo $this->item['starred']==1 ? 'active' : ''; ?>">&nbsp;</span>

<!-- icon -->
...

- public/css/style.css
Nous allons ajouter le css sur notre nouvelle étoile, sous ".entry-toolbar li" ajoutez :

.entry-smartphone-share li,
.entry-toolbar li {
    float:left;
    margin-left:10px;
    padding-left:20px;
    cursor:pointer;
    background-size:16px 16px;
    background-repeat:no-repeat;
    background-position: left center;
}
/* On ajoute notre nouvelle étoile dans la barre de titre (nouvelle class CSS) */    
.title-starr {
    float:left;
    padding-left:20px;
    cursor:pointer;
    background-size:16px 16px;
    background-repeat:no-repeat;
    background-position: left center;
}
/* On l'ajoute également dans la définition de l'image non active (ajout sur ligne existante) */
.entry-toolbar .entry-starr, .title-starr.entry-starr {
    background-image:url(images/unstarred.png);
}
/* On l'ajoute également dans la définition de l'image active (ajout sur ligne existante) */
.entry-toolbar .entry-starr.active, .title-starr.entry-starr.active {
    background-image:url(images/starred.png);
}

- public/js/selfoss-base.js
Pour éviter de dupliquer la méthode qui gère la gestion des favoris nous allons créer une fonction dans ce fichier qui s'occupe de faire le traitement, c'est un copié/collé de la partie du fichier selfoss-events-entriestoolbar.js qui s'occupe de mettre en favoris avec quelques adaptations pour la gestion de l'étoile du bas et du haut.
Sous la fonction anonymise(), ajoutez une virgule après l'accolade de fin de cette fonction puis ajouter la fonction suivante :

/**
 * Mutualisation du code pour le starred
 *
 */
starrOrUnstarr: function(parentSource) {
    var parent = $(parentSource).parents('.entry');
    var id = parent.attr('id').substr(5);
    var starr = $(parentSource).hasClass('active')==false;
    var buttonTitle = $("#entry"+id+" .title-starr.entry-starr, #entrr"+id+" .title-starr.entry-starr");
    var buttonToolbar = $("#entry"+id+" .entry-toolbar .entry-starr, #entrr"+id+" .entry-toolbar .entry-starr");
    
    // update button
    var setButton = function(starr) {
        if(starr) {
        	buttonTitle.addClass('active');
        	buttonToolbar.addClass('active');
        	buttonToolbar.html($('#lang').data('unstar'));
        } else {
        	buttonTitle.removeClass('active');
        	buttonToolbar.removeClass('active');
            buttonToolbar.html($('#lang').data('star'));
        }
    };
    setButton(starr);
    
    // update statistics in main menue
    var updateStats = function(starr) {
        var starred = parseInt($('.nav-filter-starred span').html());
        if(starr) {
            starred++;
        } else {
            starred--;
        }
        $('.nav-filter-starred span').html(starred);
    };
    updateStats(starr);
    
    $.ajax({
        url: $('base').attr('href') + (starr ? 'starr/' : 'unstarr/') + id,
        type: 'POST',
        error: function(jqXHR, textStatus, errorThrown) {
            // rollback ui changes
            setButton(!starr);
            updateStats(!starr);
            alert('Can not starr/unstarr item: '+errorThrown);
        }
    });
    
    return false;
}

- public/js/selfoss-events-entries.js
Nous allons ajouter l'appel à la fonction starrOrUnstarr lors d'un clique sur l'étoile ajoutée :

// starr/unstarr
$('.title-starr').unbind('click').click(function() {
	selfoss.starrOrUnstarr(this);
});

- public/js/selfoss-events-entriestoolbar.js
Ici nous allons simplement commenter le code que nous avons repris pour créer notre fonction et l'appeler directement :

parent.find('.entry-starr').unbind('click').click(function() {
    selfoss.starrOrUnstarr(this);
    /*var parent = $(this).parents('.entry');
    var id = parent.attr('id').substr(5);
    var starr = $(this).hasClass('active')==false;
    var button = $("#entry"+id+" .entry-starr, #entrr"+id+" .entry-starr");
    
    // update button
    var setButton = function(starr) {
        if(starr) {
            button.addClass('active');
            button.html($('#lang').data('unstar'));
        } else {
            button.removeClass('active');
            button.html($('#lang').data('star'));
        }
    };
    setButton(starr);
    
    // update statistics in main menue
    var updateStats = function(starr) {
        var starred = parseInt($('.nav-filter-starred span').html());
        if(starr) {
            starred++;
        } else {
            starred--;
        }
        $('.nav-filter-starred span').html(starred);
    };
    updateStats(starr);
    
    $.ajax({
        url: $('base').attr('href') + (starr ? 'starr/' : 'unstarr/') + id,
        type: 'POST',
        error: function(jqXHR, textStatus, errorThrown) {
            // rollback ui changes
            setButton(!starr);
            updateStats(!starr);
            alert('Can not starr/unstarr item: '+errorThrown);
        }
    });
    
    return false;*/
});

Après avoir éditer un des fichiers css et/ou js, il faut supprimer les fichiers public/all.css et/ou public/all.js afin qu'il se régénère avec nos modifications.

4. Correction sur les dates françaises

Nous pouvons également mettre la date des articles au format français.
Pour ce faire on va ajouter la variable lang_time_format dans les fichiers de config de langues qui se trouvent dans public/lang.
Le ficher fr.ini suffit, mais autant le mettre sur toutes les langues.

lang_time_format=d/m/Y H:i:s

Puis pour prendre en compte cette variable nous allons éditer la méthode dateago() du fichier helpers/ViewHelper.php.
Malheureusement je n'ai pas compris le fonctionnement de la dernière ligne de cette méthode :

return \F3::get('lang_timestamp', $date->getTimestamp());

Nous allons donc faire autrement en utilisant notre variable à la place de lang_timestamp :

public function dateago($datestr) {
    $date = new \DateTime($datestr);
    $now = new \DateTime();
    $ageInSeconds = $now->getTimestamp() - $date->getTimestamp();
    $ageInMinutes = $ageInSeconds / 60;
    $ageInHours = $ageInMinutes / 60;
    $ageInDays = $ageInHours / 24;
    
    if($ageInMinutes<1)
        return \F3::get('lang_seconds',round($ageInSeconds, 0));
    if($ageInHours<1)
        return \F3::get('lang_minutes',round($ageInMinutes, 0));
    if($ageInDays<1)
        return \F3::get('lang_hours',round($ageInHours, 0));
    
    // On commente l'ancien traitement
    //return $datestr;
    //return \F3::get('lang_timestamp', $date->getTimestamp());
    // Puis on ajoute le notre
    $date->getTimestamp();
    return $date->format(\F3::get('lang_time_format'));
    
}

Nous avons désormais un format de date que nous pouvons modifier a souhait dans notre fichier de conf de langue.

Il y a aussi un bug dans le fichier de conf public/lang/fr.ini, au lieu de la variable lang_days il faut mettre lang_hours, de ce fait nous avons x hours ago au lieu de l'avoir en français :

; mauvaise ligne
lang_days=il y a {0, plural, one {1 heure}, other {# heures}}
; bonne ligne
lang_hours=il y a {0, plural, one {1 heure}, other {# heures}}

5. Paramétrage de la purge

Heureusement pour notre base de données personnelle, les items sont purgés, seulement il supprime tous ceux qui ont plus de x jours (valeur de la variable items_lifetime de config.ini) et qui n'ont pas été mis en favoris, ce qui veut dire que si vous partez en vacances plus de jours que le nombre paramétré vous n'aurez plus les articles que vous n'avez pas lus en rentrant.
Pour y remédier nous allons ajouter une variable dans le config.ini :

; 0 pour ne pas supprimer les articles non lu, 1 pour supprimer tout les articles de plus de (items_lifetime) jours lu et non lu
delete_item_unread=0

Puis nous allons éditer les fichiers suivants pour prendre en compte cette variable :
daos/mysql/Items.php
daos/pgsql/Items.php

La méthode à modifier est cleanup() sur laquelle nous rajoutons un if pour dire si oui ou non il faut supprimer les items non lu :

public function cleanup(\DateTime $date) {
	$sWhere = '';
	if (\F3::get('delete_item_unread') == 0) {
		$sWhere = ' AND unread = 0 ';
	}
    \F3::get('db')->exec('DELETE FROM ' . \F3::get('db_prefix') . 'items WHERE starred=0 AND datetime<:date ' . $sWhere,
                array(':date' => $date->format('Y-m-d').' 00:00:00'));
}

Toutes ces modifications ont été testées sous mysql, mais il n'y a pas de raison que ça ne fonctionne pas sous postgreSql ou sqlite.

6. Lancement du cron sur un serveur OVH mutualisé

Le lancement du cron sur un serveur OVH mutualisé ne fonctionne pas.
Si dans votre crontab vous lancez le script update.php vous aurez l'erreur suivante :
Undefined index: SCRIPT_NAME
PHP Fatal error: Uncaught exception 'ErrorException' with message 'Undefined index: ONERROR' in /homez.XXX/USER/www/selfoss/libs/f3/base.php:1399
Stack trace:
#0 /homez.XXX/USER/www/selfoss/libs/f3/base.php(862): {closure}(8, 'Undefined index...', '/homez.XXX/USER...', 862, Array)
#1 /homez.XXX/USER/www/selfoss/libs/f3/base.php(1393): Base-error(500, 'Undefined index...', Array)
#2 [internal function]: {closure}(Object(ErrorException))
#3 {main}
thrown in /homez.XXX/USER/www/selfoss/libs/f3/base.php on line 1399
Status: 500

Une solution existe tout de même, il suffit d'appeler en wget l'url de mise à jour des flux.
Il suffit de créer un fichier updateOvh.php contenant la ligne suivante et d'appeler dans le planificateur de tâches d'OVH ce nouveau script à la place de update.php.

<?php
var_dump(exec('wget --quiet --delete-after http://mon-domaine.com/selfoss/update'));

 

J'alimenterais cet article au fur et à mesure de mon utilisation, je pense avoir déjà trouvé 2 ou 3 autres points à corriger.
Bonne lecture de flux !

Share |
Taggé comme: , , Commentaires
Commentaires (0) Trackbacks (0)

Désolé, le formulaire de commentaire est fermé pour le moment

Trackbacks are disabled.