lyrics 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +17 -0
  5. data/Rakefile +45 -0
  6. data/VERSION +1 -0
  7. data/bin/lyrics +66 -0
  8. data/lib/lyrics.rb +4 -0
  9. data/lib/lyrics/cli/application.rb +99 -0
  10. data/lib/lyrics/cli/optionsparser.rb +228 -0
  11. data/lib/lyrics/cli/pluginadapter.rb +56 -0
  12. data/lib/lyrics/cli/plugins.rb +79 -0
  13. data/lib/lyrics/cli/wikipluginadapter.rb +139 -0
  14. data/lib/lyrics/i18n/README +1 -0
  15. data/lib/lyrics/i18n/en.rb +181 -0
  16. data/lib/lyrics/i18n/es.rb +181 -0
  17. data/lib/lyrics/i18n/i18n.rb +126 -0
  18. data/lib/lyrics/i18n/sk.rb +174 -0
  19. data/lib/lyrics/itrans/COPYRIGHT +31 -0
  20. data/lib/lyrics/itrans/itrans +0 -0
  21. data/lib/lyrics/itrans/itrans.txt +8 -0
  22. data/lib/lyrics/itrans/lyric.txt +23 -0
  23. data/lib/lyrics/itrans/udvng.ifm +206 -0
  24. data/lib/lyrics/lyrics.rb +567 -0
  25. data/lib/lyrics/lyrics_AZLyrics.rb +113 -0
  26. data/lib/lyrics/lyrics_DarkLyrics.rb +124 -0
  27. data/lib/lyrics/lyrics_Giitaayan.rb +124 -0
  28. data/lib/lyrics/lyrics_Jamendo.rb +166 -0
  29. data/lib/lyrics/lyrics_LeosLyrics.rb +142 -0
  30. data/lib/lyrics/lyrics_LoudSongs.rb +135 -0
  31. data/lib/lyrics/lyrics_LyricWiki.rb +328 -0
  32. data/lib/lyrics/lyrics_LyricsDownload.rb +118 -0
  33. data/lib/lyrics/lyrics_LyricsMania.rb +141 -0
  34. data/lib/lyrics/lyrics_Lyriki.rb +286 -0
  35. data/lib/lyrics/lyrics_SeekLyrics.rb +108 -0
  36. data/lib/lyrics/lyrics_Sing365.rb +103 -0
  37. data/lib/lyrics/lyrics_TerraLetras.rb +126 -0
  38. data/lib/lyrics/mediawikilyrics.rb +1417 -0
  39. data/lib/lyrics/utils/formdata.rb +56 -0
  40. data/lib/lyrics/utils/htmlentities.rb +291 -0
  41. data/lib/lyrics/utils/http.rb +198 -0
  42. data/lib/lyrics/utils/itrans.rb +160 -0
  43. data/lib/lyrics/utils/logger.rb +123 -0
  44. data/lib/lyrics/utils/strings.rb +378 -0
  45. data/lib/lyrics/utils/xmlhash.rb +111 -0
  46. data/lyrics.gemspec +98 -0
  47. data/spec/lyrics_spec.rb +7 -0
  48. data/spec/spec.opts +1 -0
  49. data/spec/spec_helper.rb +9 -0
  50. metadata +137 -0
@@ -0,0 +1,118 @@
1
+ # Copyright (C) 2007 by Sergio Pistone
2
+ # sergio_pistone@yahoo.com.ar
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the
16
+ # Free Software Foundation, Inc.,
17
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
+
19
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__))
20
+
21
+ require "utils/strings"
22
+ require "utils/htmlentities"
23
+ require "lyrics"
24
+
25
+ class LyricsDownload < Lyrics
26
+
27
+ @@white_chars = "'\"¿?¡!()[].,;:-/& "
28
+
29
+ def LyricsDownload.site_host()
30
+ return "www.lyricsdownload.com"
31
+ end
32
+
33
+ def LyricsDownload.site_name()
34
+ return "Lyrics Download"
35
+ end
36
+
37
+ def LyricsDownload.lyrics_test_data()
38
+ return [
39
+ Request.new( "Nirvana", "Smells Like Teen Spirit", "Nevermind" ),
40
+ Request.new( "Radiohead", "Optimistic", "Kid A" ),
41
+ Request.new( "Massive Attack", "Protection", "Protection" ),
42
+ Request.new( "Portishead", "Wandering Star", "Dummy" ),
43
+ ]
44
+ end
45
+
46
+ def cleanup_artist( artist )
47
+ artist = artist.gsub( /^the /i, "" )
48
+ Strings.remove_vocal_accents!( artist )
49
+ artist.gsub!( "&", "and" )
50
+ artist.tr!( @@white_chars, " " )
51
+ artist.strip!()
52
+ artist.tr!( " ", "-" )
53
+ return artist
54
+ end
55
+
56
+ def cleanup_title( title )
57
+ title = Strings.remove_vocal_accents( title )
58
+ title.gsub!( "&", "and" )
59
+ title.tr!( @@white_chars, " " )
60
+ title.strip!()
61
+ title.tr!( " ", "-" )
62
+ return title
63
+ end
64
+
65
+ def build_lyrics_fetch_data( request )
66
+ artist = cleanup_title( request.artist )
67
+ title = cleanup_title( request.title )
68
+ return FetchPageData.new( "http://#{site_host()}/#{artist}-#{title}-lyrics.html" )
69
+ end
70
+
71
+ def parse_lyrics( response, page_body )
72
+
73
+ page_body = Strings.latin12utf8( page_body )
74
+ page_body.tr_s!( " \n\r\t", " " )
75
+ page_body.tr_s!( "’", "'" )
76
+ # page_body.tr_s!( "‘", "'" )
77
+
78
+ if (md = /<title>([^<]+) - ([^<]+) LYRICS ?<\/title>/i.match( page_body ))
79
+ response.artist, response.title = md[1].strip(), md[2].strip()
80
+ end
81
+
82
+ return if ! page_body.gsub!( /^.*<div class="KonaBody" ><div id="div_customCSS">/, "" )
83
+ return if ! page_body.gsub!( /<\/div> ?<\/div>.*$/, "" )
84
+
85
+ page_body.gsub!( /\ ?<br ?\/?> ?/i, "\n" )
86
+ page_body.strip!()
87
+
88
+ response.lyrics = page_body
89
+
90
+ end
91
+
92
+ def build_suggestions_fetch_data( request )
93
+ artist = cleanup_artist( request.artist )
94
+ return FetchPageData.new( "http://#{site_host()}/#{artist}-lyrics.html" )
95
+ end
96
+
97
+ def parse_suggestions( request, page_body, page_url )
98
+
99
+ page_body = Strings.latin12utf8( page_body )
100
+ page_body.tr_s!( " \n\r\t", " " )
101
+ page_body.tr_s!( "’", "'" )
102
+
103
+ suggestions = []
104
+
105
+ return suggestions if ! page_body.sub!( /^.*Lyrics list aplhabetically:<\/font><\/td>/, "" )
106
+ return suggestions if ! page_body.sub!( /<\/ul> ?<\/td> ?<\/tr> ?<\/table> ?<center><div>.*$/, "" )
107
+
108
+ page_body.split( "</li>" ).each() do |entry|
109
+ if (md = /<a class="txt_1" href="([^"]+)"><font size=2>([^<]+) Lyrics<\/font><\/a>/.match( entry ))
110
+ suggestions << Suggestion.new( request.artist, md[2], "http://#{site_host()}/#{md[1]}" )
111
+ end
112
+ end
113
+
114
+ return suggestions
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,141 @@
1
+ # Copyright (C) 2007-2008 by
2
+ # Davide Lo Re <boyska@gmail.com>
3
+ # Sergio Pistone <sergio_pistone@yahoo.com.ar>
4
+ #
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 2 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program; if not, write to the
17
+ # Free Software Foundation, Inc.,
18
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
+
20
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__))
21
+
22
+ require "utils/strings"
23
+ require "lyrics"
24
+
25
+ require "cgi"
26
+
27
+ class LyricsMania < Lyrics
28
+
29
+ def LyricsMania.site_host()
30
+ return "www.lyricsmania.com"
31
+ end
32
+
33
+ def LyricsMania.site_name()
34
+ return "LyricsMania"
35
+ end
36
+
37
+ def LyricsMania.lyrics_test_data()
38
+ return [
39
+ Request.new( "Nirvana", "Lounge Act", "Nevermind" ),
40
+ Request.new( "Radiohead", "Idioteque", "Kid A" ),
41
+ Request.new( "Pearl Jam", "Porch", "Ten" ),
42
+ Request.new( "The Smashing Pumpkins", "Mayonaise", "Siamese Dream" ),
43
+ ]
44
+ end
45
+
46
+ def LyricsMania.build_song_add_url( request )
47
+ return "http://#{site_host()}/add.html"
48
+ end
49
+
50
+ def LyricsMania.build_google_feeling_lucky_url( artist, title=nil )
51
+ query = Strings.google_search_quote( artist )
52
+ query << " " << Strings.google_search_quote( title + " lyrics" ) if title
53
+ return Strings.build_google_feeling_lucky_url( query, site_host() )
54
+ end
55
+
56
+ def build_lyrics_fetch_data( request )
57
+ return FetchPageData.new( build_google_feeling_lucky_url( request.artist, request.title ) )
58
+ end
59
+
60
+ def lyrics_page_valid?( request, page_body, page_url )
61
+ md = /<title>([^<]+) Lyrics<\/title>/i.match( page_body )
62
+ return false if ! md
63
+ page_title = Strings.normalize( md[1] )
64
+ return page_title.index( Strings.normalize( request.artist ) ) &&
65
+ page_title.index( Strings.normalize( request.title ) )
66
+ end
67
+
68
+ def parse_lyrics( response, page_body )
69
+
70
+ page_body = Strings.latin12utf8( page_body )
71
+ page_body.tr_s!( " \n\r\t", " " )
72
+
73
+ return if ! page_body.sub!( /^.* lyrics<\/h3>/, "" ) # metadata
74
+
75
+ metadata = {}
76
+ ["artist", "album"].each() do |key|
77
+ if (md =/#{key}: <b><a href=[^>]+>([^<]+)<\/a><\/b>/i.match( page_body ))
78
+ metadata[key.downcase()] = md[1].strip().sub( /\ *lyrics$/, "" )
79
+ end
80
+ end
81
+ ["year", "title"].each() do |key|
82
+ if (md =/#{key}: ([^<]+)<(br|\/td)>/i.match( page_body ))
83
+ metadata[key.downcase()] = md[1].strip()
84
+ end
85
+ end
86
+
87
+ response.artist = metadata["artist"] if metadata.include?( "artist" )
88
+ response.title = metadata["title"] if metadata.include?( "title" )
89
+ response.album = metadata["album"] if metadata.include?( "album" )
90
+ response.year = metadata["year"] if metadata.include?( "year" )
91
+
92
+ md = /<\/span> ?<\/center>(.*)<center> ?<span style/.match( page_body )
93
+ return if ! md
94
+
95
+ page_body = md[1]
96
+ page_body.sub!( /&#91;.+ Lyrics on http:\/\/#{site_host()}\/ &#93;/, "" )
97
+ page_body.sub!( /^.*<\/a>/, "" ) # additional (optional) crap at the beginning
98
+ page_body.gsub!( /<u>&lt;a[^<]+&lt;\/a&gt;<\/u>/, "" ) # yet more crap
99
+ page_body.gsub!( /\ ?<br ?\/?> ?/i, "\n" )
100
+ page_body.sub!( /^\ ?<strong>Lyrics to [^<]+<\/strong> :<\/?br> */i, "" )
101
+
102
+ page_body.strip!()
103
+
104
+ response.lyrics = page_body
105
+
106
+ end
107
+
108
+ def build_suggestions_fetch_data( request )
109
+ return FetchPageData.new( build_google_feeling_lucky_url( request.artist ) )
110
+ end
111
+
112
+ def suggestions_page_valid?( request, page_body, page_url )
113
+ md = /<title>([^<]+) Lyrics<\/title>/i.match( page_body )
114
+ return md ? Strings.normalize( md[1] ).index( Strings.normalize( request.artist ) ) : nil
115
+ end
116
+
117
+ # returns an array of maps with following keys: url, artist, title
118
+ def parse_suggestions( request, page_body, page_url )
119
+
120
+ page_body = Strings.latin12utf8( page_body )
121
+ page_body.tr_s!( " \n\r\t", " " )
122
+
123
+ suggestions = []
124
+
125
+ # remove table with other artists at the bottom
126
+ return suggestions if ! page_body.sub!( /(.*)<table.*/, "\\1" )
127
+
128
+ md = /<table width=100%>(.*)<\/table>/.match( page_body )
129
+ return suggestions if ! md
130
+
131
+ md[1].split( /<a href=/ ).each() do |entry|
132
+ if (md = /"(\/lyrics\/[^"]+)" title="[^"]+"> ?([^>]+) lyrics<\/a><br>/.match( entry ))
133
+ suggestions << Suggestion.new( request.artist, md[2], "http://#{site_host()}#{md[1]}" )
134
+ end
135
+ end
136
+
137
+ return suggestions
138
+
139
+ end
140
+
141
+ end
@@ -0,0 +1,286 @@
1
+ # Copyright (C) 2006-2008 by Sergio Pistone
2
+ # sergio_pistone@yahoo.com.ar
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the
16
+ # Free Software Foundation, Inc.,
17
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
+
19
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__))
20
+
21
+ require "utils/strings"
22
+ require "utils/http"
23
+ require "mediawikilyrics"
24
+
25
+ require "uri"
26
+ require "cgi"
27
+
28
+ class Lyriki < MediaWikiLyrics
29
+
30
+ def Lyriki.site_host()
31
+ return "www.lyriki.com"
32
+ end
33
+
34
+ def Lyriki.site_name()
35
+ return "Lyriki"
36
+ end
37
+
38
+ def Lyriki.control_page()
39
+ return "Lyriki:Wiki-Lyrics"
40
+ end
41
+
42
+ def parse_lyrics( response, page_body )
43
+
44
+ custom_data = {}
45
+
46
+ if (md = /\{\{\s*[Ss]ong\s*\|.*$/m.match( page_body ))
47
+
48
+ template_data = parse_template( md[0] )
49
+ template_data["params"].each() do |key, value|
50
+ custom_data[key.to_s()] = value
51
+ if value.is_a?( String )
52
+ value.gsub!( /<br ?\/?>/i, "; " ) if key != "song"
53
+ value.gsub!( /<\/?[^>]+\/?>/, " " )
54
+ value.tr_s!( " \n\r\t", " " )
55
+ value.strip!()
56
+ end
57
+ end
58
+
59
+ response.title = custom_data["song"] if custom_data.include?( "song" )
60
+
61
+ if custom_data["artist"].is_a?( String )
62
+ response.artist = custom_data["artist"]
63
+ elsif custom_data["artists"].is_a?( Array )
64
+ artist = ""
65
+ custom_data["artists"].each() do |token|
66
+ if token.is_a?( String )
67
+ artist << token.gsub( /\[\[|\]\]/, "" )
68
+ elsif token.is_a?( Hash ) && token["name"].downcase() == "song artist" && token["params"][1]
69
+ artist << token["params"][1]
70
+ end
71
+ end
72
+ artist.gsub!( /\s*<br *\/?>\s*/i, " " )
73
+ response.artist = artist
74
+ elsif custom_data["artists"].is_a?( String ) # this case is DEPRECATED by Lyriki guides
75
+ response.artist = custom_data["artists"].gsub( /\[\[|\]\]/, "" )
76
+ end
77
+
78
+ if custom_data["album"].is_a?( String )
79
+ response.album, response.year = custom_data["album"], custom_data["year"]
80
+ elsif custom_data["albums"].is_a?( Array )
81
+ custom_data["albums"].each() do |token|
82
+ if token.is_a?( String )
83
+ if (md = /([^:]+):(.+) \(([0-9]{4,4})\)/.match( token ))
84
+ response.album, response.year = md[2], md[3]
85
+ break
86
+ end
87
+ elsif token.is_a?( Hash )
88
+ if token["name"].downcase() == "song album" && token["params"][2] && token["params"][3]
89
+ response.album, response.year = token["params"][2], token["params"][3]
90
+ break
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ custom_data["reviewed"] = (/\{\{[Aa]utoGenerated\}\}/.match( page_body ) == nil)
99
+
100
+ if (md = /<lyrics>(.*)<\/lyrics>/im.match( page_body ))
101
+ page_body = md[1]
102
+ page_body.gsub!( /[ \t]*[\r\n][ \t]*/m, "\n" )
103
+ else
104
+ page_body.gsub!( /\{\{.*\}\}\n?/, "" )
105
+ page_body.gsub!( /\[\[Category:.*\]\]\n?/, "" )
106
+ page_body.gsub!( /\ *== *(External *Links|Links) *==.*$/im, "" )
107
+ page_body = page_body.split( "\n" ).collect() do |line|
108
+ if line.index( /\s/ ) == 0
109
+ "\n" + line
110
+ else
111
+ line
112
+ end
113
+ end.join( "" )
114
+ page_body.gsub!( /\s*<br ?\/?>\s*/i, "\n" )
115
+ end
116
+
117
+ response.lyrics = page_body if ! Strings.empty?( page_body )
118
+ response.custom_data = custom_data
119
+
120
+ end
121
+
122
+ def Lyriki.build_tracks( album_data )
123
+ ret = ""
124
+ album_data.tracks.each() do |track|
125
+ track_length = track.length > 0 ?
126
+ "|#{track.length / 60}:#{track.length % 60 < 10 ? "0#{track.length % 60}" : track.length % 60}" :
127
+ ""
128
+ track_artist = cleanup_title_token( track.artist )
129
+ track_title = cleanup_title_token( track.title )
130
+ if album_data.various_artists?
131
+ ret += "# {{song link va|#{track_artist}|#{track_title}#{track_length}}}\n"
132
+ else
133
+ ret += "# {{song link|#{track_artist}|#{track_title}#{track_length}}}\n"
134
+ end
135
+ end
136
+ return ret
137
+ end
138
+
139
+ def Lyriki.build_album_page( reviewed, artist, album, year, month, day, tracks, album_art )
140
+
141
+ raise ArgumentError if Strings.empty?( artist ) || Strings.empty?( album ) || Strings.empty?( tracks )
142
+
143
+ s_name = get_sort_name( album )
144
+ s_letter = get_sort_letter( album )
145
+
146
+ album_art = nil if ! year || album_art == build_album_art_name( artist, album, year, "jpg", false )
147
+
148
+ contents = \
149
+ "#{reviewed ? "" : "{{autoGenerated}}\n"}" \
150
+ "{{Album\n" \
151
+ "| album = #{album}\n" \
152
+ "| artist = #{artist}\n" \
153
+ "| released = #{build_date( year, month, day )}\n" \
154
+ "#{album_art ? "| image = #{album_art}\n" : ""}" \
155
+ "| tracks =\n"
156
+
157
+ return \
158
+ "#{contents}" \
159
+ "#{tracks.strip()}\n" \
160
+ "}}\n" \
161
+ "\n" \
162
+ "{{C:Album|#{s_letter}|#{s_name}}}"
163
+ end
164
+
165
+ def Lyriki.build_song_page( reviewed, artist, title, album, year, credits, lyricist, lyrics )
166
+
167
+ raise ArgumentError if artist == nil || title == nil
168
+
169
+ s_name = get_sort_name( title )
170
+ s_letter = get_sort_letter( title )
171
+ year = year.to_i() <= 1900 ? "" : year.to_s()
172
+
173
+ song_page = reviewed ? "": "{{autoGenerated}}\n"
174
+
175
+ if (md = /^([^\s].*)\s+feat\.\s+([^\s].*)$/i.match( artist.strip() ))
176
+ artist, fartist = md[1].strip(), md[2]
177
+ song_page <<
178
+ "{{Song\n" \
179
+ "| song = #{title}\n" \
180
+ "| artists = {{song artist|#{artist}}}<br />feat. {{song artist|#{fartist}}}\n" \
181
+ "| albums = {{song album|#{artist}|#{album}|#{year}}}\n" \
182
+ "| credits = #{credits.to_s().split( "; " ).join( "<br />" )}\n" \
183
+ "| lyricist = #{lyricist.to_s().split( "; " ).join( "<br />" )}\n" \
184
+ "}}\n" \
185
+ else
186
+ song_page <<
187
+ "{{Song\n" \
188
+ "| song = #{title}\n" \
189
+ "| artist = #{artist}\n" \
190
+ "| album = #{album}\n" \
191
+ "| year = #{year}\n" \
192
+ "| credits = #{credits.to_s().split( "; " ).join( "<br />" )}\n" \
193
+ "| lyricist = #{lyricist.to_s().split( "; " ).join( "<br />" )}\n" \
194
+ "}}\n" \
195
+ end
196
+
197
+ return song_page <<
198
+ "\n" \
199
+ "<lyrics>#{Strings.empty?( lyrics ) ? "<tt>(Instrumental)</tt>" : lyrics}</lyrics>\n" \
200
+ "\n" \
201
+ "{{C:Song|#{s_letter}|#{s_name}}}"
202
+ end
203
+
204
+ def Lyriki.build_album_art_name( artist, album, year, extension="jpg", cleanup=true )
205
+ if cleanup
206
+ artist = cleanup_title_token( artist )
207
+ album = cleanup_title_token( album )
208
+ end
209
+ album_art_name = "AlbumArt-#{artist}-#{album}_(#{year})#{Strings.empty?( extension ) ? "" : ".#{extension.strip()}"}".gsub( " ", "_" )
210
+ return Strings.remove_invalid_filename_chars( album_art_name )
211
+ end
212
+
213
+ def Lyriki.build_album_art_description( artist, album, year, cleanup=true )
214
+ if cleanup
215
+ artist = cleanup_title_token( artist )
216
+ album = cleanup_title_token( album )
217
+ end
218
+ return "#{artist}:#{album} (#{year})"
219
+ end
220
+
221
+ def Lyriki.find_album_art_name( artist, album, year )
222
+
223
+ normalized_artist = cleanup_title_token( artist )
224
+ Strings.remove_invalid_filename_chars!( normalized_artist )
225
+ Strings.normalize!( normalized_artist )
226
+ normalized_artist.gsub!( " ", "" )
227
+
228
+ normalized_album = cleanup_title_token( album )
229
+ Strings.remove_invalid_filename_chars!( normalized_album )
230
+ Strings.normalize!( normalized_album )
231
+ normalized_album.gsub!( " ", "" )
232
+
233
+ year = year.to_s().strip()
234
+
235
+ artist = cleanup_title_token( artist )
236
+ Strings.remove_invalid_filename_chars!( artist )
237
+ search_url = "http://#{site_host()}/index.php?ns6=1&search=#{CGI.escape( artist )}&searchx=Search&limit=500"
238
+ response, search_url = HTTP.fetch_page_get( search_url )
239
+
240
+ return nil if response == nil || response.body() == nil
241
+
242
+ candidates = []
243
+ parse_search_results( response.body(), true ).each() do |result|
244
+
245
+ next if result[@@SEARCH_RESULT_TITLE].index( "Image:" ) != 0
246
+
247
+ normalized_title = Strings.normalize( result[@@SEARCH_RESULT_TITLE] )
248
+ normalized_title.gsub!( " ", "" )
249
+
250
+ matches = 0
251
+ idx1 = normalized_title.index( "albumart" )
252
+ matches += 1 if idx1
253
+ idx1 = idx1 ? idx1 + "albumart".size : 0
254
+ idx2 = normalized_title.index( normalized_artist, idx1 )
255
+ matches += 4 if idx2
256
+ idx2 = idx2 ? idx2 + normalized_artist.size : idx1
257
+ idx3 = normalized_title.index( normalized_album, idx2 )
258
+ next if idx3 == nil
259
+ idx3 = idx3 ? idx3 + normalized_album.size : idx2
260
+ idx3 = normalized_title.index( year, idx3 )
261
+ matches += 2 if idx3
262
+
263
+ candidates.insert( -1, [ matches, result[@@SEARCH_RESULT_TITLE] ] )
264
+ end
265
+
266
+ if candidates.size > 0
267
+ candidates.sort!() { |x,y| y[0] <=> x[0] }
268
+ return URI.decode( candidates[0][1].slice( "Image:".size..-1 ).gsub( " ", "_" ) )
269
+ else
270
+ return nil
271
+ end
272
+ end
273
+
274
+ def Lyriki.cleanup_title_token!( title, downcase=false )
275
+ title.gsub!( /\[[^\]\[]*\]/, "" )
276
+ title.gsub!( /[\[|\]].*$/, "" )
277
+ title.gsub!( /`|´|’/, "'" )
278
+ title.gsub!( /''|«|»/, "\"" )
279
+ title.squeeze!( " " )
280
+ title.strip!()
281
+ title.gsub!( "+", "and" )
282
+ Strings.titlecase!( title, true, downcase )
283
+ return title
284
+ end
285
+
286
+ end