# 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 = ); print "Song Title: "; chomp( my $song = ); 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->error(), ")\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 = ); 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!

]+)>!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;