
La idea es hacer una búsqueda en el dispositivo en donde están nuestros MP3 y crear un indice en HTML con todas nuestras canciones; Usando un navegador pudieramos tocarlos en la computadora sin necesidad de copiarlos fuera de nuestro tocador de MP3, el cual está conectado por el puerto USB…
Pienselo, imaginese que usted tiene un servidor de archivos en su casa protegido por su firewall y desea bajarse algunas canciones desde el trabajo o un hotel a su laptop; Todas sus canciones están indexadas (y el servidor web está protegido por clave y usa protección con SSL).
Depinga, ¿no?
Idealmente pudieramos concentrarnos en escribir una rutina recursiva en la cual almacenariamos los contadores; Por otro lado si decidimos hacerlo en Perl, podemos utilizar un módulo llamado File::Find el cual viene con Perl 5.6.1 o superior (yo para este ejemplo utilizaré 5.8.0).
Si usted no esta familizarizado con Unix, quizas no conozca la herramienta find. Por ejemplo, para mostrar el tamaño de mis archivos mp3 puedo utilizar lo siguiente:
[josevnz@localhost josevnz]$ find /mnt/usb/ -type f -name ‘*.mp3′ -ls
548 12976 -rwxr-xr-x 1 josevnz josevnz 13287049 Jan 23 18:08 /mnt/usb/Anthrax/Persistence_of_Time/01\ -\ Time.mp3
549 13552 -rwxr-xr-x 1 josevnz josevnz 13869684 Jan 23 18:12 /mnt/usb/Anthrax/Persistence_of_Time/02\ -\ Blood.mp3
550 13408 -rwxr-xr-x 1 josevnz josevnz 13729250 Jan 23 18:15 /mnt/usb/Anthrax/Persistence_of_Time/03\ -\ Keep_It_in_the_Family.mp3
551 12048 -rwxr-xr-x 1 josevnz josevnz 12326579 Jan 23 18:19 /mnt/usb/Anthrax/Persistence_of_Time/04\ -\ In_My_World.mp3
552 9920 -rwxr-xr-x 1 josevnz josevnz 10148176 Jan 23 18:21 /mnt/usb/Anthrax/Persistence_of_Time/05\ -\ Gridlock.mp3
553 6384 -rwxr-xr-x 1 josevnz josevnz 6530321 Jan 23 18:22 /mnt/usb/Anthrax/Persistence_of_Time/06\ -\ Intro_to_Reality.mp3
554 9008 -rwxr-xr-x 1 josevnz josevnz 9210275 Jan 23 18:25 /mnt/usb/Anthrax/Persistence_of_Time/07\ -\ Belly_of_the_Beast.mp3
555 5152 -rwxr-xr-x 1 josevnz josevnz 5263905 Jan 23 18:26 /mnt/usb/Anthrax/Persistence_of_Time/08\ -\ Got_the_Time.mp3
556 9504 -rwxr-xr-x 1 josevnz josevnz 9731052 Jan 23 18:28 /mnt/usb/Anthrax/Persistence_of_Time/09\ -\ H8_Red.mp3
557 10576 -rwxr-xr-x 1 josevnz josevnz 10821090 Jan 23 18:30 /mnt/usb/Anthrax/Persistence_of_Time/10\ -\ One_Man_Stands.mp3
558 7904 -rwxr-xr-x 1 josevnz josevnz 8093488 Jan 23 18:32 /mnt/usb/Anthrax/Persistence_of_Time/11\ -\ Discharge.mp3
569 11984 -rwxr-xr-x 1 josevnz josevnz 12264721 Jan 23 18:43 /mnt/usb/Anthrax/State_Of_Euphoria/01\ -\ Be_All,_End_All.mp3
570 9808 -rwxr-xr-x 1 josevnz josevnz 10033655 Jan 23 18:46 /mnt/usb/Anthrax/State_Of_Euphoria/02\ -\ Out_Of_Sight,_Out_Of_Mind.mp3
571 10688 -rwxr-xr-x 1 josevnz josevnz 10933939 Jan 23 18:49 /mnt/usb/Anthrax/State_Of_Euphoria/03\ -\ Make_Me_Laugh.mp3
572 8320 -rwxr-xr-x 1 josevnz josevnz 8513955 Jan 23 18:51 /mnt/usb/Anthrax/State_Of_Euphoria/04\ -\ Antisocial.mp3
573 14256 -rwxr-xr-x 1 josevnz josevnz 14588574 Jan 23 18:55 /mnt/usb/Anthrax/State_Of_Euphoria/05\ -\ Who_Cares_Wins.mp3
574 10512 -rwxr-xr-x 1 josevnz josevnz 10752545 Jan 23 18:57 /mnt/usb/Anthrax/State_Of_Euphoria/06\ -\ Now_It_s_Dark.mp3
575 10288 -rwxr-xr-x 1 josevnz josevnz 10530190 Jan 23 19:00 /mnt/usb/Anthrax/State_Of_Euphoria/07\ -\ Schism.mp3
Entonces nos quedaría la tarea de capturar esta salida en un archivo, para procesarla luego.
¿Pero, y que tal y si quisiera hacer lo mismo en Windows, sin find? ¿Que tal si lo quiero hacer con Perl?. Bueno, no se desespere, para ello utilice el program ‘find2perl’ y listo:
[josevnz@localhost josevnz]$ find2perl /mnt/usb/ -type f -name '*.mp3' -ls
¡Que arrecho!. Resulta que ‘find2perl‘ le va a convertir a usted su expresión de find en un programa en Perl, toda una belleza.
Pero nosotros, como carajos vergachú, vamos más bien a hacer un programita un poco más sofisticado. La idea básica detrás de File::Find es llamar a una rutina que hace la búsqueda y utilizar una función de ‘callback’ (la cual será llamada cada vez que encontremos un archivo) para filtrar los resultados.
Ahh… y antes de empezar: Si usted es como yo, ni de vaina se acordará de todos los pasos anteriores, así que más bien redirija la salida de find2perl a un archivo y utilicelo como una plantilla.
Ahora vamos a concentrarnos en como obtener información de el catalogo; Una forma eficiente y segura es revizando la metadata que viene dentro de cada archivo MP3, para ello usamos otro módulo disponible en CPAN llamado MP3::Tag.
File::Find ya viene con Perl (al menos con Fedora Core 2) así que sólo les voy a mostrar como instalar el módulo que lee la metadata de los MP3:
[josevnz@localhost josevnz]$ su -
Password:
[root@localhost root]# perl -MCPAN -e'install MP3::Tag'
CPAN: Storable loaded ok
Going to read /root/.cpan/Metadata
Database was generated on Sat, 23 Oct 2004 12:07:36 GMT
CPAN: LWP::UserAgent loaded ok
Fetching with LWP:
ftp://ftp.perl.org/pub/CPAN/authors/01mailrc.txt.gz
Going to read /root/.cpan/sources/authors/01mailrc.txt.gz
Fetching with LWP:
ftp://ftp.perl.org/pub/CPAN/modules/02packages.details.txt.gz
Going to read /root/.cpan/sources/modules/02packages.details.txt.gz
Database was generated on Wed, 26 Jan 2005 07:42:35 GMT
Fetching with LWP:
ftp://ftp.perl.org/pub/CPAN/modules/03modlist.data.gz
Going to read /root/.cpan/sources/modules/03modlist.data.gz
Going to write /root/.cpan/Metadata
Running install for module MP3::Tag
Running make for I/IL/ILYAZ/modules/MP3-Tag-0.94.tar.gz
Fetching with LWP:
ftp://ftp.perl.org/pub/CPAN/authors/id/I/IL/ILYAZ/modules/MP3-Tag-0.94.tar.gz
CPAN: Digest::MD5 loaded ok
Fetching with LWP:
ftp://ftp.perl.org/pub/CPAN/authors/id/I/IL/ILYAZ/modules/CHECKSUMS
Checksum for /root/.cpan/sources/authors/id/I/IL/ILYAZ/modules/MP3-Tag-0.94.tar.gz ok
Scanning cache /root/.cpan/build for sizes
Deleting from cache: /root/.cpan/build/GD-2.16 (10.3>10.0 MB)
MP3-Tag-0.94/
MP3-Tag-0.94/cddb.tm
MP3-Tag-0.94/cddb.tmp
MP3-Tag-0.94/Changes
MP3-Tag-0.94/data_pod.PL
MP3-Tag-0.94/examples/
MP3-Tag-0.94/examples/audio_rename.pl
MP3-Tag-0.94/examples/extractID3v2.pl
MP3-Tag-0.94/examples/mod/
MP3-Tag-0.94/examples/mod/Music_Translate_Fields.pm
MP3-Tag-0.94/examples/mod/transliterate_win1251.pm
MP3-Tag-0.94/examples/mp3info.pl
MP3-Tag-0.94/examples/mp3info2.pl
MP3-Tag-0.94/examples/README.txt
MP3-Tag-0.94/examples/tagged.pl
MP3-Tag-0.94/examples/tagit.pl
MP3-Tag-0.94/examples/type_mp3_dir.pl
MP3-Tag-0.94/Makefile.PL
MP3-Tag-0.94/MANIFEST
MP3-Tag-0.94/META.yml
MP3-Tag-0.94/README.txt
MP3-Tag-0.94/t/
MP3-Tag-0.94/t/mp3tag.t
MP3-Tag-0.94/t/parser.t
MP3-Tag-0.94/t/set_v2.t
MP3-Tag-0.94/t/update_tags.t
MP3-Tag-0.94/t/v2_comments.t
MP3-Tag-0.94/Tag/
MP3-Tag-0.94/Tag/CDDB_File.pm
MP3-Tag-0.94/Tag/File.pm
MP3-Tag-0.94/Tag/ID3v1.pm
MP3-Tag-0.94/Tag/ID3v2.pm
MP3-Tag-0.94/Tag/Inf.pm
MP3-Tag-0.94/Tag/LastResort.pm
MP3-Tag-0.94/Tag/ParseData.pm
MP3-Tag-0.94/Tag.pm
MP3-Tag-0.94/test.mp3
MP3-Tag-0.94/tk-tag/
MP3-Tag-0.94/tk-tag/README
MP3-Tag-0.94/tk-tag/tk-tag.pl
MP3-Tag-0.94/TODO
CPAN.pm: Going to build I/IL/ILYAZ/modules/MP3-Tag-0.94.tar.gz
Checking if your kit is complete...
Looks good
Writing Makefile for MP3::Tag
cp Tag/CDDB_File.pm blib/lib/MP3/Tag/CDDB_File.pm
cp Tag.pm blib/lib/MP3/Tag.pm
cp Tag/ParseData.pm blib/lib/MP3/Tag/ParseData.pm
cp Tag/Inf.pm blib/lib/MP3/Tag/Inf.pm
cp Tag/ID3v2.pm blib/lib/MP3/Tag/ID3v2.pm
cp Tag/ID3v1.pm blib/lib/MP3/Tag/ID3v1.pm
cp Tag/File.pm blib/lib/MP3/Tag/File.pm
cp Tag/LastResort.pm blib/lib/MP3/Tag/LastResort.pm
/usr/bin/perl "-Iblib/arch" "-Iblib/lib" data_pod.PL ID3v2-Data.pod
Manifying blib/man3/MP3::Tag.3pm
Manifying blib/man3/MP3::Tag::ID3v1.3pm
Manifying blib/man3/MP3::Tag::File.3pm
Manifying blib/man3/MP3::Tag::CDDB_File.3pm
Manifying blib/man3/MP3::Tag::ParseData.3pm
Manifying blib/man3/MP3::Tag::Inf.3pm
Manifying blib/man3/MP3::Tag::ID3v2.3pm
Manifying blib/man3/MP3::Tag::ID3v2-Data.3pm
Manifying blib/man3/MP3::Tag::LastResort.3pm
/usr/bin/make -- OK
Running make test
PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/mp3tag.........ok
t/parser.........ok
t/set_v2.........ok
t/update_tags....ok
t/v2_comments....ok
All tests successful.
Files=5, Tests=172, 1 wallclock secs ( 1.13 cusr + 0.14 csys = 1.27 CPU)
/usr/bin/make test -- OK
Running make install
Installing /usr/lib/perl5/site_perl/5.8.3/MP3/Tag.pm
Installing /usr/lib/perl5/site_perl/5.8.3/MP3/Tag/File.pm
Installing /usr/lib/perl5/site_perl/5.8.3/MP3/Tag/Inf.pm
Installing /usr/lib/perl5/site_perl/5.8.3/MP3/Tag/ID3v2.pm
Installing /usr/lib/perl5/site_perl/5.8.3/MP3/Tag/ParseData.pm
Installing /usr/lib/perl5/site_perl/5.8.3/MP3/Tag/ID3v1.pm
Installing /usr/lib/perl5/site_perl/5.8.3/MP3/Tag/CDDB_File.pm
Installing /usr/lib/perl5/site_perl/5.8.3/MP3/Tag/LastResort.pm
Installing /usr/share/man/man3/MP3::Tag::File.3pm
Installing /usr/share/man/man3/MP3::Tag::CDDB_File.3pm
Installing /usr/share/man/man3/MP3::Tag::ParseData.3pm
Installing /usr/share/man/man3/MP3::Tag::ID3v2.3pm
Installing /usr/share/man/man3/MP3::Tag::LastResort.3pm
Installing /usr/share/man/man3/MP3::Tag.3pm
Installing /usr/share/man/man3/MP3::Tag::ID3v2-Data.3pm
Installing /usr/share/man/man3/MP3::Tag::Inf.3pm
Installing /usr/share/man/man3/MP3::Tag::ID3v1.3pm
Writing /usr/lib/perl5/site_perl/5.8.3/i386-linux-thread-multi/auto/MP3/Tag/.packlist
Appending installation info to /usr/lib/perl5/5.8.3/i386-linux-thread-multi/perllocal.pod
/usr/bin/make install -- OK
[root@localhost root]#
Este es el código que hace el truco:
1:#!/usr/bin/perl
2:
3:use strict;
4:use File::Find;
5:use MP3::Tag;
6:use Date::Format;
7:
8:# Pointers to common used names
9:use vars qw/*name *dir *prune/;
10:*name = *File::Find::name;
11:*dir = *File::Find::dir;
12:*prune = *File::Find::prune;
13:use constant MAX_SIZE => 99999999;
14:use constant DEBUG => 0;
15:use constant TIME_TEMPLATE => "%c"; # man Date::Format
16:my $color_counter = 1; # Global counter
17:
18:# Each one of these colors is used on the data rows (for even and pair columns)
19:my @table_colors = (
20: "255, 102, 0",
21: "255, 153, 0"
22:);
23:
24:sub count;
25:
26:if ( ! -d $ARGV[0] ) {
27: die "Please provide a valid directory! ('$ARGV[0]')";
28:}
29:my $date = time2str(TIME_TEMPLATE, time);
30: print <<EOF
31:<html>
32:<head>
33:<meta content="text/html; charset=ISO-8859-1"
34:http-equiv="content-type">
35:<title>My Music Collection - $date</title>
36:</head>
37:<body>
38:<table style="width: 100\%; text-align: left;" border="1" cellpadding="2"
39:cellspacing="2">
40:<tbody>
41:<tr>
42:<th style="vertical-align: top; background-color: rgb(0, 102, 0);"><span
43:style="color: rgb(255, 255, 255);">Title</span><br
44:style="color: rgb(255, 255, 255);">
45:</th>
46:<th
47:style="vertical-align: top; color: rgb(255, 255, 255); background-color: rgb(0, 102, 0);">Track<br>
48:</th>
49:<th
50:style="vertical-align: top; color: rgb(255, 255, 255); background-color: rgb(0, 102, 0);">Artist<br>
51:</th>
52:<th
53:style="vertical-align: top; color: rgb(255, 255, 255); background-color: rgb(0, 102, 0);">Album<br>
54:</th>
55:<th
56:style="vertical-align: top; color: rgb(255, 255, 255); background-color: rgb(0, 102, 0);">Comment<br>
57:</th>
58:<th
59:style="vertical-align: top; color: rgb(255, 255, 255); background-color: rgb(0, 102, 0);">Year<br>
60:</th>
61:<th style="vertical-align: top; background-color: rgb(0, 102, 0);"><span
62:style="color: rgb(255, 255, 255);">Genre</span><br>
63:</th>
64:</tr>
65:EOF
66:;
67:
68:eval {
69:
70: # Traverse desired filesystems
71: File::Find::find({wanted => \&count}, $ARGV[0]);
72:};
73:
74:if ($@) {
75: # Print the HTML end, so at least the document is well formed...
76: print <<EOF
77: </tbody>
78:</table>
79:<br>
80:</body>
81:</html>
82:EOF
83:;
84: die "$!";
85:}
86:exit;
87:
88:# Callback function that will perform the search
89:# Argument: Current file being transversed
90:# Returns: void
91:sub count {
92: my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
93: $atime,$mtime,$ctime,$blksize,$blocks) = lstat($_);
94: # Does it look like an MP3 file?
95: if ( ( -f $_ ) && ( $_ =~ /^.*\.mp3\z/s ) ) {
96: my $mp3 = MP3::Tag->new($_);
97: my ($title, $track, $artist, $album, $comment, $year, $genre) =
98: $mp3->autoinfo();
99: if (DEBUG) {
100: printf STDERR "%s\n", $date;
101: printf STDERR
102: "title: %s, track: %s, artist: %s, album: %s,
103: comment: %s,year: %s, genre: %s\n",
104: $title, $track, $artist, $album, $comment,
105: $year, $genre;
106: }
107: my $index = $color_counter % 2;
108: print <<EOF;
109: <tr>
110:<td
111:style="vertical-align: top; background-color: rgb(
112: $table_colors[$index]);"><a href="file:\/\/$name">$title</a></td>
113:<td
114:style="vertical-align: top; background-color: rgb(
115: $table_colors[$index]);">$track</td>
116:<td
117:style="vertical-align: top; background-color: rgb(
118: $table_colors[$index]);">$artist</td>
119:<td
120:style="vertical-align: top; background-color: rgb(
121: $table_colors[$index]);">$album</td>
122:<td
123:style="vertical-align: top; background-color: rgb(
124: $table_colors[$index]);">$comment</td>
125:<td
126:style="vertical-align: top; background-color: rgb(
127: $table_colors[$index]);">$year</td>
128:<td
129:style="vertical-align: top; background-color: rgb(
130: $table_colors[$index]);">$genre</td>
131:</tr>
132:EOF
133:;
134: $color_counter++;
135: $mp3->close();
136: }
137:}
138:
139:__END__
140:
141:=head1 NAME
142:
143:MP3Counter.plx - A program that creates an HTML index from your MP3 collection
144:
145:=head1 DESCRIPTION
146:
147:This program asumes that you are ordering your MP3 collection like this:
148:
149: Artist name--->
150: Album name--->
151: Song name
152:
153:Then you can use the program like this:
154:
155:MP3Counter.plx <directory> > /directory/index.html
156:
157:But that really doesn't matter as we read the metadata directly from the MP3
158:file!
159:
160:=head1 AUTHOR
161:
162:Jose Vicente Nunez Zuleta.
163:
164:=head1 BLOG
165:
166:El Angel Negro - http://elangelnegro.blogspot.com
167:
168:=head1 LICENSE
169:
170:GPL
171:
172:=head1 TODO
173:
174:Improve paging and HTML output!
175:
176:=cut
Lo corremos así:
[josevnz@localhost MP3]$ time ./MP3Counter.plx /mnt/usb/ > index.html
real 0m3.091s
user 0m2.229s
sys 0m0.789s
[josevnz@localhost MP3]$
(Corre bastante rápido).
Blogger me vuelve mierda las tablas, así que le dejo a usted la tarea de correr el programa para ver como se ve el asunto (si, que ladilla…). Si quiere ver una salida de ejemplo, haga click aqui.
Si no quiere generar un archivo estático, entonces tendrá que modificar el programa para que se comporte como un CGI; Sin embargo dado lo poco (digo yo) que cambia su colección de MP3 entonces quizas será mejor poner el script como un trabajo en Cron. Otra cosa que seguro usted deberá mejorar es la paginación, ya que todas las canciones salen en una sola pagina.
Como siempre, puede bajarse el código fuente desde aqui. Será hasta el próximo programa
Sin categoría
Comentarios recientes