L'outil du jour a probablement déjà été écrit, et réécrit par les trois-quarts des programmeurs de la planète, mais bon, cela fait partie de la petite gym hebdomadaire.
J'avais donc besoin d'un outil me permettant de télécharger les fichiers d'un podcast en ligne de commande. Rien de complexe donc, et aucun outil qui faisait déjà le travail à ma connaissance (et j'avoue ne pas avoir cherché !).
Voici le script :
#!/usr/bin/env perl
use strict;
use warnings;
package App::podcaster;
use Getopt::Long;
use LWP::UserAgent;
use XML::LibXML;
use File::Spec;
use File::Basename;
use Carp;
use Term::ANSIColor;
__PACKAGE__->run() unless caller();
sub new {
my ( $class, %args ) = @_;
my $self = {};
$self->{url} = delete $args{url};
$self->{output_dir} = delete $args{output_dir} || './';
$self->{ua} = LWP::UserAgent->new(
agent => 'Mozilla/5.0',
show_progress => 1,
cookie_jar => {},
);
bless $self, $class;
}
sub run {
my $config = {};
GetOptions( $config, 'url=s', 'output_dir=s' );
die _usage() unless _valid($config);
my $podcaster = App::podcaster->new(
url => $config->{url},
output_dir => $config->{output_dir},
);
$podcaster->download_enclosures();
}
sub get_enclosures {
my ($self) = @_;
my $res = $self->{ua}->get( $self->{url} );
if ( $res->is_success ) {
my $xml = $res->decoded_content;
my $feed = XML::LibXML->load_xml( string => $xml );
my @nodes = $feed->findnodes('//enclosure/@url');
my @encl_urls = map { $_->value } @nodes;
return @encl_urls;
}
else {
carp $self->{url}, $res->status_line, $/;
}
}
sub download_enclosures {
my ($self) = @_;
my @encl_urls = $self->get_enclosures();
for (@encl_urls) {
my $output_filename = $self->_get_filename($_);
if ( not -e $output_filename ) {
my $res =
$self->{ua}->get( $_, ':content_file' => $output_filename, );
if ( $res->is_success ) {
print colored(
['green'], basename($output_filename) . " is downloaded."
), $/;
}
else {
print colored(
['red'],
basename($output_filename)
. " can't be downloaded: "
. $res->status_line
), $/;
}
}
else {
print colored( ['green'],
basename($output_filename) . " is already downloaded." ),
$/;
}
}
}
sub _get_filename {
my ( $self, $url ) = @_;
return File::Spec->catfile( $self->{output_dir}, basename($url) );
}
sub _valid {
my $config = shift;
if ( exists $config->{url} and exists $config->{output_dir} ) {
return 1;
}
else {
return 0;
}
}
sub _usage {
return "Usage: $0 --url http://path.to/rss.xml --output_dir ./\n";
}
1;
Le script est un modulino, essentiellement car je pense que ce n'est que la première version de l'outil. J'ai déjà quelques idées de fonctionnalités à ajouter !
En ce qui concerne l'algorithme, c'est assez simple :
- le programme prend deux arguments, l'URL du podcast et le répertoire où les fichiers doivent être téléchargés ;
- nous récupérons le contenu de l'URL du podcast ;
-
nous utilisons une expression XPath,
//enclosure/@url, pour récupérer les URLs des différents fichiers ; - nous téléchargeons les différents fichiers.
Simple, efficace, et j'ai maintenant un outil en ligne de commande pour mes podcasts !



