File Coverage

blib/lib/LyricFinder/Musixmatch.pm
Criterion Covered Total %
statement 23 97 23.7
branch 0 30 0.0
condition 0 30 0.0
subroutine 8 11 72.7
pod 2 2 100.0
total 33 170 19.4


line stmt bran cond sub pod time code
1             package LyricFinder::Musixmatch;
2              
3 1     1   8 use strict;
  1         3  
  1         32  
4 1     1   6 use warnings;
  1         2  
  1         26  
5 1     1   5 use Carp;
  1         3  
  1         59  
6 1     1   6 use HTML::Strip;
  1         2  
  1         20  
7 1     1   5 use URI::Escape;
  1         2  
  1         78  
8 1     1   7 use parent 'LyricFinder::_Class';
  1         2  
  1         6  
9              
10             our $haveLyricsCache;
11             BEGIN {
12 1     1   100 $haveLyricsCache = 0;
13 1     1   70 eval "use LyricFinder::Cache; \$haveLyricsCache = 1; 1";
  1         7  
  1         2  
  1         21  
14             }
15              
16             my $Source = 'Musixmatch';
17             my $Site = 'https://www.musixmatch.com';
18             my $DEBUG = 0;
19              
20             sub new
21             {
22 0     0 1   my $class = shift;
23              
24 0           my $self = $class->SUPER::new($Source, @_);
25 0           @{$self->{'_fetchers'}} = ($Source);
  0            
26 0           unshift(@{$self->{'_fetchers'}}, 'Cache') if ($haveLyricsCache
27 0 0 0       && $self->{'-cache'} && $self->{'-cache'} !~ /^\>/);
      0        
28              
29 0           bless $self, $class; #BLESS IT!
30              
31 0           return $self;
32             }
33              
34             sub fetch {
35 0     0 1   my ($self, $artist_in, $song_in) = @_;
36              
37 0           $self->_debug("Musixmatch::fetch($artist_in, $song_in)!");
38              
39 0 0         return '' unless ($self->_check_inputs($artist_in, $song_in));
40 0 0         return '' if ($self->{'Error'} ne 'Ok');
41              
42             # first, see if we've got it cached:
43 0           $self->_debug("i:haveCache=$haveLyricsCache= -cachedir=".$self->{'-cache'}."=");
44 0 0 0       if ($haveLyricsCache && $self->{'-cache'} && $self->{'-cache'} !~ /^\>/) {
      0        
45 0           my $cache = new LyricFinder::Cache(%{$self});
  0            
46 0 0         if ($cache) {
47 0           my $lyrics = $cache->fetch($artist_in, $song_in);
48 0 0 0       if (defined($lyrics) && $lyrics =~ /\w/) {
49 0           $self->_debug("..Got lyrics from cache.");
50 0           $self->{'Source'} = 'Cache';
51 0           $self->{'Site'} = $cache->site();
52 0           $self->{'Url'} = $cache->url();
53              
54 0           return $lyrics;
55             }
56             }
57             }
58              
59 0           $self->{'Site'} = $Site;
60              
61 0           (my $artist = $artist_in) =~ s#\s*\/.*$##; #ONLY USE 1ST ARTIST, IF MORE THAN ONE!
62 0           (my $song = $song_in) =~ s#\s*\/\s*#\-#; #FIX SONGS WITH "/" IN THEM!
63 0           $artist =~ s/\&/feat/; #DON'T ASK ME WHY "&" => "feat"? BUT IT DOES!
64 0           $song =~ s/\&/feat/;
65 0           $artist =~ s/ +/\-/g;
66 0           $song =~ s/ +/\-/g;
67 0           $artist =~ tr/A-Z/a-z/;
68 0           $song =~ tr/A-Z/a-z/;
69 0           $artist = uri_escape_utf8($artist);
70 0           $song = uri_escape_utf8($song);
71 0           $artist =~ s/[^a-z0-9\-\%]//gi;
72 0           $song =~ s/[^a-z0-9\-\%]//gi;
73              
74             # Their URLs look like e.g.:
75             #https://www.musixmatch.com/lyrics/Artist-name/Title
76 0           $self->{'Url'} = $Site . '/lyrics/'
77             . join('/', $artist, $song);
78              
79 0           my $lyrics = $self->_web_fetch($artist_in, $song_in);
80 0 0 0       if ($lyrics && $haveLyricsCache && $self->{'-cache'} && $self->{'-cache'} !~ /^\
      0        
      0        
81 0           $self->_debug("=== WILL CACHE LYRICS! ===");
82             # cache the fetched lyrics, if we can:
83 0           my $cache = new LyricFinder::Cache(%{$self});
  0            
84 0 0         $cache->save($artist_in, $song_in, $lyrics) if ($cache);
85             }
86 0           return $lyrics;
87             }
88              
89             sub _parse {
90 0     0     my $self = shift;
91 0           my $html = shift;
92              
93 0           $self->_debug("Musixmatch::_parse()!");
94 0           my $goodbit = '';
95 0           my $text = '';
96 0           my $mm_status = '';
97 0           my $hs = HTML::Strip->new();
98              
99             #METHOD 1: MERGE LYRICS FROM BOTH (OR MORE?) LYRIC "SPANS" MM LIKES TO BREAK LYRICS UP INTO
100             #2 SEPARATE SPAN TAGS: A SHORT (ABBREVIATED) PART, FOLLOWED BY THE REST OF THE LYRICS:
101 0           while ($html =~ s#\(.+?)\<\/span\>##s) {
102 0           $mm_status = $1;
103 0           $goodbit = $2;
104 0           $text .= $hs->parse($goodbit) . "\r\n";
105             }
106 0 0         unless ($text =~ /[a-z]/i) { #IF METHOD 1 FAILS, THE FULL LYRICS ARE OFTEN FOUND IN THE FIRST "body":
107 0           $html =~ s#\\\"#\x02#gs; #PROTECT ESCAPED QUOTES
108 0 0         if ($html =~ m#\"body\"\:\"([^\"]+)#s) {
109 0           $mm_status = 'error!';
110 0           ($goodbit = $1) =~ s#\x02#\"#gs;
111 0           $text .= $hs->parse($goodbit);
112 0           $text =~ s#\\n#\n#gs; #line-feeds are encoded literally in the JSON block.
113             }
114             }
115 0 0         if ($text =~ /[a-z]/i) {
116             $text .= "\r\n(Musixmatch status: $mm_status)"
117 0 0 0       unless ((defined($self->{'-noextra'}) && $self->{'-noextra'}) || $mm_status !~ /\S/);
      0        
118              
119             #WHILE WE'RE AT IT, SEE IF WE HAVE A COVER IMAGE?!:
120 0 0         if ($html =~ m#\(.+?)\<\/div\>#s) {
121 0           my $imgdiv = $1;
122 0 0         if ($imgdiv =~ m#\
123 0           my $imgurl = $1;
124 0 0         $imgurl = 'https:' . $imgurl if ($imgurl =~ m#^//#);
125 0           $self->{'image_url'} = $imgurl;
126             }
127             }
128              
129 0           return $self->_normalize_lyric_text($self->_html2text($text));
130             } else {
131 0           carp($self->{'Error'} = "e:$Source - Failed to identify lyrics on result page.");
132 0           return '';
133             }
134             }
135              
136             1
137              
138             __END__