| Category: | Audio Related Programs |
| Author/Contact Info | /msg saskaqueer |
| Description: |
Locates and downloads lyrics to (hopefully) any song. Simple object interface so you can roll your own. I threw this together because the Lyrics::Fetcher:: modules on CPAN are horrible. There is no guarantee that the first match returned will be the correct song. That is why I use multiple sites, it gives you a fighting chance. Chances are you will receive some lyrics with additional info at the top (songwriter, etc) that I can't filter out easily. So you get stuck with some extras once in a while. |
# sample program - all available methods are used
#!c:/perl/bin/perl -w
$| = 1;
use strict;
use LyricFinder;
# 'more' is used because of both win32 and *nix support.
# you can change this to 'less', /vim?/, 'notepad', etc etc.
my $viewer = 'more';
my $lf = LyricFinder->new();
find_lyrics() while 1;
sub find_lyrics {
print "Artist: ";
chomp( my $artist = <STDIN> );
print "Song Title: ";
chomp( my $song = <STDIN> );
my $search = $lf->search(50, $artist, $song);
print "\nFound ", $search->count(), " possible results!\n";
while ( my $page = $search->fetch() ) {
if ( $page->error() ) {
print "Fetch for ", $page->source(), " failed (", $page->e
+rror(), ")\n";
next;
}
print "Fetch from ", $page->source(), " successfull (200).\n\n
+";
sleep 2;
open( my $fh, '>', '.lyrics' ) or die "open failed: $!";
print $fh $page->lyrics();
close($fh) or die "close failed: $!";
system "$viewer .lyrics";
unlink '.lyrics';
PROMPT:
print "\n\n>> ";
chomp( my $cmd = <STDIN> );
if ($cmd =~ /^[qQ]/) {
exit(0);
}
elsif ($cmd =~ /^[rR]/) {
print "\n"; last;
}
elsif ($cmd =~ /^[nN]/) {
next;
}
else {
goto PROMPT;
}
}
print "\nNo more lyrics found for given artist and song.\n\n";
}
# LyricFinder.pm - all code below here goes in same file!
package LyricFinder;
use URI::Escape;
use LWP::UserAgent;
my @sites = qw(
sing365.com
musicsonglyrics.com
lyricsdepot.com
123lyrics.net
lyricsfreak.com
azlyrics.com
elyrics.net
);
sub new {
my ($class) = @_;
my $self = {
_ua => LWP::UserAgent->new(
timeout => 30,
agent => 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT
+5.1) ' .
'Opera 7.23 [en]'
)
};
return( bless($self, $class) );
}
sub search {
my ($self, $count, @terms) = @_;
my $res = $self->{_ua}->get(
'http://www.google.com/search?q=lyrics%20' .
uri_escape( join(' ', @terms) ) . '&num=' . $count .
'&ie=UTF-8&oe=UTF-8&hl=en&btnG=Google%20Search',
Referer => 'http://www.google.com/'
);
die("Unable to retrieve search results: ${\$res->status_line()}\n"
+)
unless ( $res->is_success() );
my @links = grep {
my $link = $_;
grep { $link =~ m!^http://(?:www.)?$_! } @sites
} $res->content() =~ m!<p class=g><a href=([^>]+)>!g;
return( LyricsFinder::Search->new($self->{_ua}, \@links) );
}
package LyricsFinder::Search;
sub new {
my ($class, $ua, $links) = @_;
my $self = {
_ua => $ua,
_links => $links
};
return( bless($self, $class) );
}
sub count { scalar @{shift->{_links}} }
sub fetch {
my ($self) = @_;
if ( defined( my $page = shift(@{$self->{_links}}) ) ) {
return( LyricsFinder::Page->new($self->{_ua}, $page) );
}
else {
return( undef );
}
}
package LyricsFinder::Page;
use HTML::Entities;
sub new {
my ($class, $ua, $uri) = @_;
my $source = ($uri =~ m!^http://(?:www.)?([^/]+)/!)[0];
my $self = {
_ua => $ua,
_uri => $uri,
_source => $source
};
my $res = $self->{_ua}->get($uri);
my ($lyrics);
unless ( $res->is_error() ) {
$lyrics = $res->content();
$lyrics =~ y!\r!!d;
$lyrics =~ s!(?:\342\200\231|\306|\221|\222)!'!g;
$lyrics =~ s!\n?<\s*br\s*(?:/\s*)?>\n?!\n!ig;
$lyrics =~ s!<\!\-\-.*?\-\->!!gs;
$lyrics =~ s!<([^>]+)>!\001!gs;
($lyrics) = sort { length($b) <=> length($a) } split(/\001/, $
+lyrics);
$lyrics =~ s!\A\s*(?:\]\s*)?!!;
$lyrics =~ s!(?:\s*\[)?\s*\z!!;
$lyrics = decode_entities($lyrics);
}
if ( $res->is_error() or not defined($lyrics) or
$lyrics =~ /hotlog_js/ or $lyrics =~ /td {/ or
$lyrics =~ /All lyrics are property/
) {
$self->{_error} = $res->is_error() ? $res->code() : 'no lyrics
+ found';
}
else {
$self->{_lyrics} = $lyrics;
}
return( bless($self, $class) );
}
sub uri { shift->{_uri} }
sub error { shift->{_error} }
sub source { shift->{_source} }
sub lyrics { shift->{_lyrics} }
1;
|
|
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Lyrics Fetcher
by Jaap (Curate) on Apr 16, 2004 at 08:18 UTC | |
by saskaqueer (Friar) on Apr 16, 2004 at 09:41 UTC | |
by saskaqueer (Friar) on Apr 16, 2004 at 09:17 UTC |