Daal, micro-éditeur de fils RSS en PerlTk

Afin de faciliter l'édition de fils RSS, j'ai écrit ce petit programe en perl avec une interface graphique Tk donc compatible Windows, Linux, Unix et autres Mac-OS X. C'est vraiment rudimentaire mais cela peut servir de base pour développer des choses plus complexes si besoin. C'est un canevas, une preuve de concept.

Daal Snapshot

#! /usr/bin/perl-w
# PerlTk RSS Feed Editor
# Creative commons, habett, 2005

J'ai maximisé l'usage des modules avec beaucoup d'explicité mais seul XML::RSS devrait manquer d'une distribution classique comme ActivePerl.

use Tk;
use Tk::widgets qw(TextUndo Scrollbar LabEntry NoteBook);
use XML::RSS;
use strict;
use Carp;
use diagnostics;
use locale;

On commence par créer un objet fil RSS dont on va forcer l'encodage en ISO 8859-1 pour simplifier les choses. On lit un fil vide puis on le charge et parse avec le sub qui convient.

# lecture d'un fil blanc
my $rss = new XML::RSS(encoding=>"ISO-8859-1");
my $file="blank.xml";
readfeed($file);

On passe maintenant aux artifices d'interface graphique avec Tk. Notez le lien dynamique que permet textvariable sur certains widgets.

# création de la fenêtre
my $mainwindow = MainWindow->new();
$mainwindow->configure(-title => "Daal, EdRSS");
$mainwindow->optionAdd('*TextUndo.Background' => '#fff5e1');
my $z="#";

$mainwindow->Button(-text => 'Ouvrir un feed',-width=>80,
  -command => \&loadfeed)->pack(-side=>"top",-anchor=>"n",-fill=>'x',-padx=>10,-pady=>10);

# Infos générales
my $title = $mainwindow->LabEntry(-label=>"Titre",-labelPack=>[-anchor=>"n"],-width=>80,
  -textvariable=>$rss->channel("title"))->pack(-side=>"top",-anchor=>"nw",-padx =>10,-pady=>10);
my $description = $mainwindow->LabEntry(-label=>"Description",-labelPack =>[-anchor=>"n"],-width=>80,
  -textvariable=>$rss->channel("description"))->pack(-side=>"top",-anchor=>"nw",-padx=>10,-pady=>10);
my $link = $mainwindow->LabEntry(-label=>"URL",-labelPack=>[-anchor=>"n"],-width=>80,
  -textvariable=>$rss->channel("link"))->pack(-side=>"top",-anchor=>"nw",-padx=>10,-pady=>10);

# création d'un nouvel item
$mainwindow->Button(-text=>'Nouvel item',-width=>80,-foreground=>'blue',
  -command => \&nouvelle)->pack(-side=>"top",-anchor=>"n",-fill=>'x',-padx=>10,-pady=>10);

Il est fait appel au widget NoteBook pour symboliser les différents élément du fil. Comme on le vera plus tard, nous avons restreint à 15 le nombre d'items lors de l'édition, conformément aux usages actuels.

#NoteBook des items du feed
my $w_book = $mainwindow->NoteBook()->pack(-padx=>10,-pady=>10);
my (@text,@w_page);
&book;

# quitter et/ou enregistrer
$mainwindow->Button(-text=>'Quitter sans enregistrer',-width=>80,-relief=>'sunken',-foreground=>'red',
  -command=> \&quit)->pack(-anchor=>"s",-fill=>'x',-padx=>10,-pady=>10);

$mainwindow->Button(-text=>'Enregistrer et quitter',-width=>80,-foreground=>'darkgreen',
  -command=>\&saveclose)->pack(-anchor=>"s",-fill=>'x',-padx=>10,-pady=>10);

Une fois l'interface construite, reste à lancer les opérations et à les terminer.

MainLoop();
exit(0);

Passons aux procédures, la première est celle d'ajout d'un élément au fil. Comme convenu, on limite le nombre d'items à 15. Une fois le traitement fair sur le fil, on fait appel à la procédure &book; pour mettre à jour l'affichage.

sub nouvelle {
  # nouvel élément au feed
  $rss->channel(title=>$title->get,link=>$link->get,description=>$description->get,lastBuildDate=>&tome);
  my $i = 0;
  foreach my $item (@{$rss->{'items'}}) {
    $i++;
    $item->{'title'}=$item->{'title'}->get;
    $item->{'link'}=$item->{'link'}->get;
    $item->{'description'}=$text[$i]->Contents;
  }
  pop(@{$rss->{'items'}}) if (@{$rss->{'items'}} == 15);
  $rss->add_item(title=>'Nouveau',link=>"http://",pubDate=>&tome,mode=>'insert');
  $rss->save($file);
  &book;
}

Création d'un masque d'ouverture de fichier adapté.

sub loadfeed {
  # Wiget adapté aux fils avec extension xml ou rss
  my @types = (["Feeds", ['.xml','.rss']],["All Files", "*"] );
  $file = $mainwindow->getOpenFile(-filetypes => \@types);
  &readfeed;
  &book;
}

Procédure d'affichage avec nettoyage préalable par le vide.

sub book {
  # netoyage du notebook
  my @totej = $w_book->pages;
  foreach(@totej) {
    $w_book->delete($_);
  }
  # recréation du notebook
  my $i = 0;
  &readfeed ($file);
  foreach my $item (@{$rss-gt;{'items'}}) {
    $i++;
    $w_page[$i] = $w_book->add("$i",-label=>"$z$i");
    $item->{'title'} = $w_page[$i]->Entry(-relief=>'sunken',-width=>80,-textvariable=>$item->{'title'})->pack;
    $item->{'link'} = $w_page[$i]->Entry(-relief=>'sunken',-width=>80,-textvariable=>$item->{'link'})->pack;
    $text[$i] = $w_page[$i]->TextUndo(-relief=>'sunken',-width=>69,-height=>4,-wrap=>'word')->pack;
    $text[$i]->Insert($item->{'description'});
    $text[$i]->focus;
    $w_page[$i]->pack;
  }
  $title->delete(0,"end");
  $title->insert("end",$rss->channel('title'));
  $link->delete(0,"end");
  $link->insert("end",$rss->channel('link'));
  $description->delete(0,"end");
  $description->insert("end",$rss->channel('description'));
}

Maintenant, très classiquement, lire, enregistrer, quitter.

sub readfeed {
  #lecture puis parse du feed
  my $file = shift;
  return unless $file;
  return unless -e $file;
  my $textfile;
  open (IN, $file);
  $textfile .= $_ while ();
  close (IN);
  $rss->parse($textfile);
}

sub saveclose {
  # enregistrement du feed
  $rss->channel(title=>$title->get,link=>$link->get,description=>$description->get);
  my $i=0;
  foreach my$item (@{$rss->{'items'}}) {
    $i++;
    $item->{'title'}=$item->{'title'}->get;
    $item->{'link'}=$item->{'link'}->get;
    my $temp=$text[$i]->Contents;
    chomp($temp);
    $item->{'description'}=$temp;
  }
  $rss->save($file);
  exit;
}

sub quit {
  exit(0);
}

Pour avoir une date conforme aux standards du genre, notez la petite manipulation sur gmtime.

sub tome {
  my ($wday,$month,$dayn,$time,$year) = split(/ /,scalar gmtime);
  return "$wday, $dayn $month $year $time GMT";
}

C'est tout. Le code aurait pû être plus modularisé mais il est fonctionnel. Grâce à XML::RSS, il a la vertu d'être agnostique en matière de version/format de fil.

daal.zip

menu principal