lyrics 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/bin/lyrics +66 -0
- data/lib/lyrics.rb +4 -0
- data/lib/lyrics/cli/application.rb +99 -0
- data/lib/lyrics/cli/optionsparser.rb +228 -0
- data/lib/lyrics/cli/pluginadapter.rb +56 -0
- data/lib/lyrics/cli/plugins.rb +79 -0
- data/lib/lyrics/cli/wikipluginadapter.rb +139 -0
- data/lib/lyrics/i18n/README +1 -0
- data/lib/lyrics/i18n/en.rb +181 -0
- data/lib/lyrics/i18n/es.rb +181 -0
- data/lib/lyrics/i18n/i18n.rb +126 -0
- data/lib/lyrics/i18n/sk.rb +174 -0
- data/lib/lyrics/itrans/COPYRIGHT +31 -0
- data/lib/lyrics/itrans/itrans +0 -0
- data/lib/lyrics/itrans/itrans.txt +8 -0
- data/lib/lyrics/itrans/lyric.txt +23 -0
- data/lib/lyrics/itrans/udvng.ifm +206 -0
- data/lib/lyrics/lyrics.rb +567 -0
- data/lib/lyrics/lyrics_AZLyrics.rb +113 -0
- data/lib/lyrics/lyrics_DarkLyrics.rb +124 -0
- data/lib/lyrics/lyrics_Giitaayan.rb +124 -0
- data/lib/lyrics/lyrics_Jamendo.rb +166 -0
- data/lib/lyrics/lyrics_LeosLyrics.rb +142 -0
- data/lib/lyrics/lyrics_LoudSongs.rb +135 -0
- data/lib/lyrics/lyrics_LyricWiki.rb +328 -0
- data/lib/lyrics/lyrics_LyricsDownload.rb +118 -0
- data/lib/lyrics/lyrics_LyricsMania.rb +141 -0
- data/lib/lyrics/lyrics_Lyriki.rb +286 -0
- data/lib/lyrics/lyrics_SeekLyrics.rb +108 -0
- data/lib/lyrics/lyrics_Sing365.rb +103 -0
- data/lib/lyrics/lyrics_TerraLetras.rb +126 -0
- data/lib/lyrics/mediawikilyrics.rb +1417 -0
- data/lib/lyrics/utils/formdata.rb +56 -0
- data/lib/lyrics/utils/htmlentities.rb +291 -0
- data/lib/lyrics/utils/http.rb +198 -0
- data/lib/lyrics/utils/itrans.rb +160 -0
- data/lib/lyrics/utils/logger.rb +123 -0
- data/lib/lyrics/utils/strings.rb +378 -0
- data/lib/lyrics/utils/xmlhash.rb +111 -0
- data/lyrics.gemspec +98 -0
- data/spec/lyrics_spec.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- metadata +137 -0
|
@@ -0,0 +1,108 @@
|
|
|
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 "lyrics"
|
|
23
|
+
|
|
24
|
+
class SeekLyrics < Lyrics
|
|
25
|
+
|
|
26
|
+
@@white_chars = "'\"¿?¡!()[].,;:-/& "
|
|
27
|
+
|
|
28
|
+
def SeekLyrics.site_host()
|
|
29
|
+
return "www.seeklyrics.com"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def SeekLyrics.site_name()
|
|
33
|
+
return "Seek Lyrics"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def SeekLyrics.lyrics_test_data()
|
|
37
|
+
return [
|
|
38
|
+
Request.new( "Nirvana", "Smells Like Teen Spirit", "Nevermind" ),
|
|
39
|
+
Request.new( "Radiohead", "Optimistic", "Kid A" ),
|
|
40
|
+
Request.new( "Massive Attack", "Protection", "Protection" ),
|
|
41
|
+
Request.new( "Portishead", "Wandering Star", "Dummy" ),
|
|
42
|
+
]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def SeekLyrics.build_song_add_url( request )
|
|
46
|
+
return "http://#{site_host()}/submit.php"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def cleanup_token( token )
|
|
50
|
+
token = token.tr( @@white_chars, " " )
|
|
51
|
+
token.strip!()
|
|
52
|
+
token.tr!( " ", "-" )
|
|
53
|
+
return token
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def build_lyrics_fetch_data( request )
|
|
57
|
+
artist = cleanup_token( request.artist.gsub( /^the /i, "" ) )
|
|
58
|
+
title = cleanup_token( request.title )
|
|
59
|
+
return FetchPageData.new( "http://#{site_host()}/lyrics/#{artist}/#{title}.html", nil, { "Cookie"=>"pass=deleted" } )
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def parse_lyrics( response, page_body )
|
|
63
|
+
|
|
64
|
+
page_body = Strings.latin12utf8( page_body )
|
|
65
|
+
page_body.tr_s!( " \n\r\t", " " )
|
|
66
|
+
page_body.tr_s!( "", "'" )
|
|
67
|
+
|
|
68
|
+
if (md = /<b><h2>([^<-]+) - ([^<]+) Lyrics<\/h2><\/b>/i.match( page_body ))
|
|
69
|
+
response.artist, response.title = md[1].strip(), md[2].strip()
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
return if ! page_body.sub!( /^(.*)<a href="http:\/\/www\.ringtonematcher\.com.*$/i, "\\1" )
|
|
73
|
+
return if ! page_body.sub!( /^.*<img src="\/images\/phone-right\.gif" [^<]+><\/a>/i, "" )
|
|
74
|
+
|
|
75
|
+
page_body.gsub!( /\ ?<br ?\/?> ?/i, "\n" )
|
|
76
|
+
page_body.strip!()
|
|
77
|
+
|
|
78
|
+
response.lyrics = page_body
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def build_suggestions_fetch_data( request )
|
|
83
|
+
artist = cleanup_token( request.artist.gsub( /^the /i, "" ) )
|
|
84
|
+
return FetchPageData.new( "http://#{site_host()}/lyrics/#{artist}/showall.html", nil, { "Cookie"=>"pass=deleted" } )
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def parse_suggestions( request, page_body, page_url )
|
|
88
|
+
|
|
89
|
+
page_body = Strings.latin12utf8( page_body )
|
|
90
|
+
page_body.tr_s!( " \n\r\t", " " )
|
|
91
|
+
page_body.tr_s!( "", "'" )
|
|
92
|
+
|
|
93
|
+
suggestions = []
|
|
94
|
+
|
|
95
|
+
return suggestions if ! page_body.gsub!( /.*<tr><td width="50%"><\/td><td width="50%"><\/td><\/tr>/, "" )
|
|
96
|
+
return suggestions if ! page_body.gsub!( /<\/table>.*$/, "" )
|
|
97
|
+
|
|
98
|
+
page_body.split( /<td> - /i ).each() do |entry|
|
|
99
|
+
if (md = /<a href="([^"]+)"[^>]*>([^<]+)<\/a><\/td>/i.match( entry ))
|
|
100
|
+
suggestions << Suggestion.new( request.artist, md[2], "http://#{site_host()}#{md[1]}" )
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
return suggestions
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
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 "lyrics"
|
|
22
|
+
|
|
23
|
+
class Sing365 < Lyrics
|
|
24
|
+
|
|
25
|
+
def Sing365.site_host()
|
|
26
|
+
return "www.sing365.com"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def Sing365.site_name()
|
|
30
|
+
return "Sing365"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def Sing365.lyrics_test_data()
|
|
34
|
+
return [
|
|
35
|
+
Request.new( "Nirvana", "Smells Like Teen Spirit", "Nevermind" ),
|
|
36
|
+
Request.new( "The Cranberries", "Linger", "Everybody Else Is Doing It, So Why Can't We?" ),
|
|
37
|
+
Request.new( "Pearl Jam", "Porch", "Ten" ),
|
|
38
|
+
Request.new( "The Smashing Pumpkins", "Mayonaise", "Siamese Dream" ),
|
|
39
|
+
]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def Sing365.build_song_add_url( request )
|
|
43
|
+
return build_google_feeling_lucky_url( request.artist )
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def build_lyrics_fetch_data( request )
|
|
47
|
+
return FetchPageData.new( build_google_feeling_lucky_url( request.artist, request.title ) )
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def lyrics_page_valid?( request, page_body, page_url )
|
|
51
|
+
md = /<title>([^<]+) - ([^<]+) LYRICS<\/title>/i.match( page_body )
|
|
52
|
+
return md ?
|
|
53
|
+
Strings.normalize( request.artist ) == Strings.normalize( md[1] ) &&
|
|
54
|
+
Strings.normalize( request.title ) == Strings.normalize( md[2] ) :
|
|
55
|
+
false
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def parse_lyrics( response, page_body )
|
|
59
|
+
|
|
60
|
+
page_body.tr_s!( " \n\r\t", " " )
|
|
61
|
+
|
|
62
|
+
if (md = /<meta name="Description" content="([^"]+) lyrics performed by ([^"]+)">/i.match( page_body ))
|
|
63
|
+
response.artist, response.title = md[1], md[2]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
return if ! (md = /<img src="?http:\/\/#{site_host()}\/images\/phone2\.gif"? border="?0"?><br><br><\/div>(.*)<div align="?center"?><br><br><img src="?http:\/\/#{site_host()}\/images\/phone\.gif"?/i.match( page_body ))
|
|
67
|
+
|
|
68
|
+
page_body = md[1]
|
|
69
|
+
page_body.gsub!( /\ ?<br ?\/?> ?/i, "\n" )
|
|
70
|
+
page_body.gsub!( /\n{3,}/, "\n\n" )
|
|
71
|
+
|
|
72
|
+
response.lyrics = page_body
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def build_suggestions_fetch_data( request )
|
|
77
|
+
return FetchPageData.new( build_google_feeling_lucky_url( request.artist ) )
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def suggestions_page_valid?( request, page_body, page_url )
|
|
81
|
+
md = /<title>([^<]+) LYRICS<\/title>/i.match( page_body )
|
|
82
|
+
return md ? Strings.normalize( request.artist ) == Strings.normalize( md[1] ) : false
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def parse_suggestions( request, page_body, page_url )
|
|
86
|
+
|
|
87
|
+
page_body.tr_s!( " \n\r\t", " " )
|
|
88
|
+
|
|
89
|
+
suggestions = []
|
|
90
|
+
|
|
91
|
+
return suggestions if ! (md = /<img src="?http:\/\/#{site_host()}\/images\/phone2\.gif"? border="?0"?><br><br><\/div>(.*)<\/lu><br><div align="?center"?><br><img src="?http:\/\/#{site_host()}\/images\/phone\.gif"?/i.match( page_body ))
|
|
92
|
+
|
|
93
|
+
md[1].split( "<li>" ).each() do |entry|
|
|
94
|
+
if (md = /<a href="([^"]+)"[^>]*>([^<]+) Lyrics<\/a>/i.match( entry ))
|
|
95
|
+
suggestions << Suggestion.new( request.artist, md[2], "http://#{site_host()}#{md[1]}" )
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
return suggestions
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
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/htmlentities"
|
|
23
|
+
require "lyrics"
|
|
24
|
+
|
|
25
|
+
require "cgi"
|
|
26
|
+
|
|
27
|
+
class TerraLetras < Lyrics
|
|
28
|
+
|
|
29
|
+
def TerraLetras.site_host()
|
|
30
|
+
return "letras.terra.com.br"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def TerraLetras.site_name()
|
|
34
|
+
return "Terra Letras"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def TerraLetras.known_url?( url )
|
|
38
|
+
return url.index( "http://#{site_host}" ) == 0 || /^http:\/\/.*\.letras\.terra\.com\.br\/letras\/[0-9]+/.match( url )
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def TerraLetras.lyrics_test_data()
|
|
42
|
+
return [
|
|
43
|
+
Request.new( "The Cranberries", "Linger", "Everybody Else Is Doing It, So Why Can't We?" ),
|
|
44
|
+
Request.new( "Radiohead", "Optimistic", "Kid A" ),
|
|
45
|
+
Request.new( "Mark Lanegan", "One Way Street", "Field Songs" ),
|
|
46
|
+
Request.new( "U2", "One", "Achtung Baby" ),
|
|
47
|
+
]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def TerraLetras.build_song_add_url( request )
|
|
51
|
+
return "http://#{site_host()}/envie_artista.php"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def TerraLetras.build_google_feeling_lucky_url( artist, title=nil )
|
|
55
|
+
if title
|
|
56
|
+
query = Strings.google_search_quote( "#{title} letra" )
|
|
57
|
+
query << " "
|
|
58
|
+
query << Strings.google_search_quote( artist )
|
|
59
|
+
else
|
|
60
|
+
query = Strings.google_search_quote( "letras de #{artist}" )
|
|
61
|
+
query << " "
|
|
62
|
+
query << Strings.google_search_quote( "#{artist} letras" )
|
|
63
|
+
end
|
|
64
|
+
return Strings.build_google_feeling_lucky_url( query, site_host() )
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def build_lyrics_fetch_data( request )
|
|
68
|
+
artist = Strings.utf82latin1( request.artist )
|
|
69
|
+
title = Strings.utf82latin1( request.title )
|
|
70
|
+
return FetchPageData.new( "http://#{site_host()}/winamp.php?musica=#{CGI.escape(title)}&artista=#{CGI.escape(artist)}" )
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def parse_lyrics( response, page_body )
|
|
74
|
+
|
|
75
|
+
page_body = Strings.latin12utf8( page_body )
|
|
76
|
+
page_body.tr_s!( " \n\r\t", " " )
|
|
77
|
+
|
|
78
|
+
if response.url.index( "http://#{site_host}/winamp.php?" ) == 0 # direct fetch
|
|
79
|
+
if (md = /<h1><a href='[^']+' target='_blank'>([^<]+)<\/a><\/h1>/.match( page_body ))
|
|
80
|
+
response.title = md[1]
|
|
81
|
+
end
|
|
82
|
+
if (md = /<h2><a href='[^']+' target='_blank'>([^<]+)<\/a><\/h2>/.match( page_body ))
|
|
83
|
+
response.artist = md[1]
|
|
84
|
+
end
|
|
85
|
+
return if ! page_body.gsub!( /^.*corrigir letra<\/a><\/p><p>/, "" )
|
|
86
|
+
return if ! page_body.gsub!( /<\/p>.*$/, "" )
|
|
87
|
+
else # fetched from suggestions/url
|
|
88
|
+
if (md = /<h2>([^<]+)<\/h2> <h2 id='sz'>([^<]+)<\/h2>/.match( page_body ))
|
|
89
|
+
response.title, response.artist = md[1], md[2]
|
|
90
|
+
end
|
|
91
|
+
return if ! page_body.sub!( /^.*<p id='cmp'>[^<]*<\/p> <p>/, "" )
|
|
92
|
+
return if ! page_body.sub!( /<\/p>.*/, "" )
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
page_body.gsub!( /\ ?<br ?\/?> ?/i, "\n" )
|
|
96
|
+
page_body.gsub!( /\n{3,}/, "\n\n" )
|
|
97
|
+
response.lyrics = page_body
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def build_suggestions_fetch_data( request )
|
|
102
|
+
return FetchPageData.new( build_google_feeling_lucky_url( request.artist ) )
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def parse_suggestions( request, page_body, page_url )
|
|
106
|
+
|
|
107
|
+
page_body = Strings.latin12utf8( page_body )
|
|
108
|
+
page_body.tr_s!( " \n\r\t", " " )
|
|
109
|
+
HTMLEntities.decode!( page_body )
|
|
110
|
+
|
|
111
|
+
suggestions = []
|
|
112
|
+
|
|
113
|
+
return suggestions if ! page_body.gsub!( /^.*<ul class='top' id='bgn'>/, "" )
|
|
114
|
+
return suggestions if ! page_body.gsub!( /<\/ul>.*$/, "" )
|
|
115
|
+
|
|
116
|
+
page_body.split( /<\/li> ?<li>/ ).each do |entry|
|
|
117
|
+
if (md = /<a href="([^"]+)">([^<]+) - ([^<]+)<\/a>/.match( entry ))
|
|
118
|
+
suggestions << Suggestion.new( md[2], md[3], "http://#{site_host()}#{md[1]}" )
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
return suggestions
|
|
123
|
+
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
@@ -0,0 +1,1417 @@
|
|
|
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
|
+
require "utils/http"
|
|
21
|
+
require "utils/xmlhash"
|
|
22
|
+
require "utils/formdata"
|
|
23
|
+
require "utils/strings"
|
|
24
|
+
require "utils/htmlentities"
|
|
25
|
+
require "i18n/i18n"
|
|
26
|
+
require "lyrics"
|
|
27
|
+
|
|
28
|
+
require "md5"
|
|
29
|
+
require "cgi"
|
|
30
|
+
|
|
31
|
+
class MediaWikiLyrics < Lyrics
|
|
32
|
+
|
|
33
|
+
class TrackData
|
|
34
|
+
|
|
35
|
+
attr_reader :artist, :title, :year, :length, :genre
|
|
36
|
+
|
|
37
|
+
def initialize( artist, title, length=nil, genre=nil )
|
|
38
|
+
@artist = artist.strip().freeze()
|
|
39
|
+
@title = title.strip().freeze()
|
|
40
|
+
@length = 0
|
|
41
|
+
if length
|
|
42
|
+
tokens = length.to_s().split( ":" ).reverse()
|
|
43
|
+
tokens.size.times() { |idx| @length += (60**idx) * tokens[idx].strip().to_i() }
|
|
44
|
+
end
|
|
45
|
+
@genre = genre ? genre.strip().freeze() : nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class AlbumData
|
|
51
|
+
|
|
52
|
+
attr_reader :tracks, :artist, :title, :year, :month, :day, :length, :genres
|
|
53
|
+
|
|
54
|
+
# NOTE: the artist is obtained from the tracks data. If it's not
|
|
55
|
+
# the same for all tracks it would be varios_artists_name.
|
|
56
|
+
def initialize( tracks, title, year, month=0, day=0, various_artists_name="(Various Artists)" )
|
|
57
|
+
|
|
58
|
+
raise "tracks, title and year values can't be nil" if ! title || ! year || ! tracks
|
|
59
|
+
raise "tracks value can't be empty" if tracks.empty?
|
|
60
|
+
|
|
61
|
+
@tracks = tracks.clone().freeze()
|
|
62
|
+
@title = title.strip().freeze()
|
|
63
|
+
@year = year.kind_of?( String ) ? year.strip().to_i() : year.to_i()
|
|
64
|
+
@month = month.kind_of?( String ) ? month.strip().to_i() : month.to_i()
|
|
65
|
+
@day = day.kind_of?( String ) ? day.strip().to_i() : day.to_i()
|
|
66
|
+
@various_artists_name = various_artists_name.strip().freeze()
|
|
67
|
+
|
|
68
|
+
@artist = nil
|
|
69
|
+
@genres = []
|
|
70
|
+
genre = nil
|
|
71
|
+
normalized_artist = nil
|
|
72
|
+
@length = 0
|
|
73
|
+
@tracks.each() do |track|
|
|
74
|
+
if @artist == nil
|
|
75
|
+
@artist = track.artist
|
|
76
|
+
normalized_artist = Strings.normalize( @artist )
|
|
77
|
+
elsif normalized_artist != Strings.normalize( track.artist )
|
|
78
|
+
@artist = various_artists_name
|
|
79
|
+
end
|
|
80
|
+
if track.genre && ! @genres.include?( genre = String.capitalize( track.genre, true ) )
|
|
81
|
+
@genres.insert( -1, genre )
|
|
82
|
+
end
|
|
83
|
+
@length += track.length
|
|
84
|
+
end
|
|
85
|
+
@genres.freeze()
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def various_artists?()
|
|
90
|
+
return @artist == @various_artists_name
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class SongData
|
|
96
|
+
|
|
97
|
+
attr_reader :artist, :title, :lyrics, :album, :year, :credits, :lyricists
|
|
98
|
+
|
|
99
|
+
def initialize( artist, title, lyrics, album=nil, year=nil, credits=nil, lyricists=nil )
|
|
100
|
+
|
|
101
|
+
raise "artist and title values can't be nil" if ! artist || ! title
|
|
102
|
+
|
|
103
|
+
@artist = artist.strip().freeze()
|
|
104
|
+
@title = title.strip().freeze()
|
|
105
|
+
@lyrics = lyrics ? lyrics.strip().freeze() : nil
|
|
106
|
+
@album = album ? album.strip().freeze() : nil
|
|
107
|
+
@year = year.kind_of?( String ) ? year.strip().to_i() : year.to_i()
|
|
108
|
+
|
|
109
|
+
credits = credits.split( ";" ) if credits.is_a?( String )
|
|
110
|
+
@credits = []
|
|
111
|
+
credits.each() { |value| @credits << value.strip().freeze() } if credits.is_a?( Array )
|
|
112
|
+
@credits.freeze()
|
|
113
|
+
|
|
114
|
+
lyricists = lyricists.split( ";" ) if lyricists.is_a?( String )
|
|
115
|
+
@lyricists = []
|
|
116
|
+
lyricists.each() { |value| @lyricists << value.strip().freeze() } if lyricists.is_a?( Array )
|
|
117
|
+
@lyricists.freeze()
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def instrumental?()
|
|
122
|
+
return @lyrics == nil
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@@NAME = "WL".freeze()
|
|
129
|
+
@@VERSION = "0.13.4".freeze()
|
|
130
|
+
@@AUTH_INTERVAL = 60*60 # check authorization every hour (it's only really checked if the user tries to submit something)
|
|
131
|
+
@@REDIRECT_FOLLOWUPS = 3
|
|
132
|
+
|
|
133
|
+
@@SEARCH_RESULT_TITLE = "title".freeze()
|
|
134
|
+
@@SEARCH_RESULT_URL = "url".freeze()
|
|
135
|
+
|
|
136
|
+
def MediaWikiLyrics.version()
|
|
137
|
+
return @@VERSION
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def version()
|
|
141
|
+
return self.class.version()
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
attr_reader :username, :password
|
|
145
|
+
|
|
146
|
+
def initialize( cleanup_lyrics=true, logger=nil, username=nil, password=nil )
|
|
147
|
+
super( cleanup_lyrics, logger )
|
|
148
|
+
@logged_in = false
|
|
149
|
+
@cookie = nil
|
|
150
|
+
@last_auth_check = 0 # last time we checked the control page
|
|
151
|
+
@authorized = false
|
|
152
|
+
@username = username ? username.clone().freeze() : nil
|
|
153
|
+
@password = password ? password.clone().freeze() : nil
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def control_page()
|
|
157
|
+
return self.class.control_page()
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def logged_in?()
|
|
161
|
+
return @logged_in
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def build_lyrics_fetch_data( request )
|
|
165
|
+
return FetchPageData.new( build_song_rawdata_url( request.artist, request.title ) )
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def page_error?( page_body )
|
|
169
|
+
|
|
170
|
+
# database error
|
|
171
|
+
db_error = /<!-- start content -->\s*(<p>|)A database query syntax error has occurred\.\s*This may indicate a bug in the software\.*/m.match( page_body )
|
|
172
|
+
|
|
173
|
+
return true if db_error != nil
|
|
174
|
+
|
|
175
|
+
# page title error
|
|
176
|
+
title_error = /<!-- start content -->\s*(<p>|)The requested page title was invalid, empty, or an incorrectly linked inter-language or inter-wiki title\. It may contain one( or|) more characters which cannot be used in titles\.*/m.match( page_body )
|
|
177
|
+
|
|
178
|
+
return title_error != nil
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
protected :page_error?
|
|
182
|
+
|
|
183
|
+
def MediaWikiLyrics.fetch_content_page( page_url, follow_redirects=@@REDIRECT_FOLLOWUPS )
|
|
184
|
+
|
|
185
|
+
response, page_url = HTTP.fetch_page_get( page_url )
|
|
186
|
+
page_url = page_url.sub( "&action=raw", "" )
|
|
187
|
+
|
|
188
|
+
page_body = response ? response.body() : nil
|
|
189
|
+
return nil, page_url if page_body == nil
|
|
190
|
+
|
|
191
|
+
# work around redirects pages
|
|
192
|
+
count = 0
|
|
193
|
+
articles = [ parse_url( page_url ) ]
|
|
194
|
+
while ( count < follow_redirects && (md = /#redirect ?('''|)\[\[([^\]]+)\]\]('''|)/i.match( page_body )) )
|
|
195
|
+
|
|
196
|
+
article = cleanup_article( md[2] )
|
|
197
|
+
if articles.include?( article ) # circular redirect found
|
|
198
|
+
return nil, url
|
|
199
|
+
else
|
|
200
|
+
articles << article
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
response, page_url = HTTP.fetch_page_get( build_rawdata_url( article ) )
|
|
204
|
+
page_url = page_url.sub( "&action=raw", "" )
|
|
205
|
+
|
|
206
|
+
page_body = response ? response.body() : nil
|
|
207
|
+
return nil, page_url if page_body == nil
|
|
208
|
+
|
|
209
|
+
count += 1
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
page_body = "" if page_body.strip() == "/* Empty */"
|
|
213
|
+
|
|
214
|
+
return page_body, page_url
|
|
215
|
+
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def fetch_content_page( url, follow_redirects=@@REDIRECT_FOLLOWUPS )
|
|
219
|
+
self.class.fetch_content_page( url, follow_redirects )
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def fetch_lyrics_page( fetch_data )
|
|
223
|
+
return nil, nil if fetch_data.url == nil
|
|
224
|
+
log( "Fetching lyrics page... ", 0 )
|
|
225
|
+
page_body, page_url = fetch_content_page( fetch_data.url )
|
|
226
|
+
if page_body
|
|
227
|
+
log( "OK" )
|
|
228
|
+
log( response.body(), 2 ) if verbose_log?
|
|
229
|
+
else
|
|
230
|
+
log( "ERROR" )
|
|
231
|
+
end
|
|
232
|
+
return page_body, page_url
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def lyrics_page_valid?( request, page_body, page_url )
|
|
236
|
+
return ! page_error?( page_body )
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def build_suggestions_fetch_data( request )
|
|
240
|
+
return FetchPageData.new( build_song_search_url( request.artist, request.title ) )
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def lyrics_from_url( request, url )
|
|
244
|
+
# we fetch and parse lyrics from raw content mode so we need the right url format
|
|
245
|
+
if ! url.index( "&action=raw" )
|
|
246
|
+
artist, title = parse_song_url( url )
|
|
247
|
+
url = build_song_rawdata_url( artist, title, false )
|
|
248
|
+
end
|
|
249
|
+
return super( request, url )
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def parse_suggestions( request, page_body, page_url )
|
|
253
|
+
suggestions = []
|
|
254
|
+
parse_search_results( page_body, true ).each() do |result|
|
|
255
|
+
artist, title = parse_song_url( result[@@SEARCH_RESULT_URL] )
|
|
256
|
+
if ! Strings.empty?( artist ) && ! Strings.empty?( title ) && /\ \([0-9]{4,4}\)$/.match( title ) == nil
|
|
257
|
+
suggestions << Suggestion.new( artist, title, result[@@SEARCH_RESULT_URL] )
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
return suggestions
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def login( username=@username, password=@password, force=false )
|
|
264
|
+
|
|
265
|
+
return true if ! force && @logged_in && username == @username && password == @password
|
|
266
|
+
|
|
267
|
+
@username, @password = username, password
|
|
268
|
+
notify = ! @logged_in || ! force
|
|
269
|
+
|
|
270
|
+
if ! @username || ! @password
|
|
271
|
+
notify( I18n.get( "wiki.login.error", @username ? @username : "<NONE>" ) ) if notify
|
|
272
|
+
return @logged_in = false
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
notify( I18n.get( "wiki.login.attempt", @username ) ) if notify
|
|
276
|
+
|
|
277
|
+
headers = { "Keep-Alive"=>"300", "Connection"=>"keep-alive" }
|
|
278
|
+
resp, url = HTTP.fetch_page_get( "http://#{site_host()}/index.php?title=Special:Userlogin", headers )
|
|
279
|
+
@cookie = resp.response["set-cookie"].split( "; " )[0]
|
|
280
|
+
|
|
281
|
+
params = { "wpName"=>@username, "wpPassword"=>@password, "wpLoginattempt"=>"Log In" }
|
|
282
|
+
headers.update( { "Cookie"=>@cookie } )
|
|
283
|
+
resp, url = HTTP.fetch_page_post( "http://#{site_host()}/index.php?title=Special:Userlogin&action=submitlogin", params, headers, -1 )
|
|
284
|
+
|
|
285
|
+
data = resp.body()
|
|
286
|
+
data.gsub!( /[ \t\n]+/, " " )
|
|
287
|
+
|
|
288
|
+
@logged_in = (/<h2>Login error:<\/h2>/.match( data ) == nil)
|
|
289
|
+
@logged_in = (/<h1 class="firstHeading">Login successful<\/h1>/.match( data ) != nil) if @logged_in # recheck
|
|
290
|
+
|
|
291
|
+
notify( I18n.get( "wiki.login." + (@logged_in ? "success" : "error"), @username ) ) if notify
|
|
292
|
+
|
|
293
|
+
return @logged_in
|
|
294
|
+
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def logout()
|
|
298
|
+
@cookie = false
|
|
299
|
+
if @logged_in
|
|
300
|
+
@logged_in = false
|
|
301
|
+
notify( I18n.get( "wiki.logout", @username ) )
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def authorized?()
|
|
306
|
+
|
|
307
|
+
# debug( "AUTHORIZED INITIAL VALUE: #{@authorized}" )
|
|
308
|
+
|
|
309
|
+
return @authorized if (Time.new().to_i() - @last_auth_check) < @@AUTH_INTERVAL
|
|
310
|
+
|
|
311
|
+
body, url = fetch_content_page( build_rawdata_url( control_page() ) )
|
|
312
|
+
return false if ! body
|
|
313
|
+
|
|
314
|
+
# debug( "CONTROL PAGE:\n#{body}" )
|
|
315
|
+
|
|
316
|
+
@last_auth_check = Time.new().to_i()
|
|
317
|
+
|
|
318
|
+
control_data = {}
|
|
319
|
+
body.split( "\n" ).each() do |line|
|
|
320
|
+
if (md = /^([^=]+)=(.*)$/.match( line ))
|
|
321
|
+
control_data[md[1].strip()] = md[2].strip()
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
if control_data["BlockedVersions"].to_s().strip().split( /\s*;\s*/ ).include?( version() )
|
|
326
|
+
notify( I18n.get( "wiki.control.versionblocked", version() ) )
|
|
327
|
+
@authorized = false
|
|
328
|
+
# debug( "VERSION BLOCKED" )
|
|
329
|
+
elsif control_data["BlockedUsers"].to_s().strip().downcase().split( /\s*;\s*/ ).include?( @username.to_s().downcase() )
|
|
330
|
+
notify( I18n.get( "wiki.control.userblocked", @username ) )
|
|
331
|
+
@authorized = false
|
|
332
|
+
# debug( "USER BLOCKED" )
|
|
333
|
+
else
|
|
334
|
+
|
|
335
|
+
if (last_version = control_data["LastVersion"].to_s().strip().split( "." )).size > 0
|
|
336
|
+
curr_version = self.version().split( "." )
|
|
337
|
+
curr_version.size.times() do |idx|
|
|
338
|
+
if curr_version[idx].to_i() > last_version[idx].to_i()
|
|
339
|
+
break
|
|
340
|
+
elsif curr_version[idx].to_i() < last_version[idx].to_i()
|
|
341
|
+
notify( I18n.get( "wiki.control.updated", control_data["LastVersion"] ) )
|
|
342
|
+
break
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
@authorized = true
|
|
348
|
+
# debug( "SUBMIT ALLOWED" )
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
return @authorized
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def restore_session_params( username, password, cookie, last_auth_check=0, authorized=false )
|
|
355
|
+
if ! Strings.empty?( cookie ) && ! Strings.empty?( username )
|
|
356
|
+
@username = username
|
|
357
|
+
@password = password
|
|
358
|
+
@cookie = cookie
|
|
359
|
+
@last_auth_check = last_auth_check.to_i()
|
|
360
|
+
@authorized = authorized.to_s() == 'true'
|
|
361
|
+
@logged_in = true
|
|
362
|
+
notify( I18n.get( "wiki.session.restore.success", @username ) )
|
|
363
|
+
return true
|
|
364
|
+
else
|
|
365
|
+
notify( I18n.get( "wiki.session.restore.error", @username ) )
|
|
366
|
+
return false
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def restore_session( session_file )
|
|
372
|
+
values = { "username" => nil, "password" => nil, "cookie" => nil, "last_auth_check" => nil, "authorized" => nil }
|
|
373
|
+
if XMLHash.read( session_file, values )
|
|
374
|
+
return restore_session_params(
|
|
375
|
+
Strings.descramble( values["username"] ),
|
|
376
|
+
Strings.descramble( values["password"] ),
|
|
377
|
+
values["cookie"],
|
|
378
|
+
values["last_auth_check"],
|
|
379
|
+
values["authorized"]
|
|
380
|
+
)
|
|
381
|
+
else
|
|
382
|
+
notify( I18n.get( "wiki.session.restore.notfound" ) )
|
|
383
|
+
return false
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def get_session_params()
|
|
388
|
+
return (@username ? @username.clone() : nil), (@password ? @password.clone() : nil), (@cookie ? @cookie.clone() : nil), @last_auth_check, @authorized
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def save_session( session_file )
|
|
392
|
+
if ! @logged_in
|
|
393
|
+
notify( I18n.get( "wiki.session.save.error.notloggedin" ) )
|
|
394
|
+
return false
|
|
395
|
+
end
|
|
396
|
+
values = {
|
|
397
|
+
"username" => Strings.scramble( @username ),
|
|
398
|
+
"password" => Strings.scramble( @password ),
|
|
399
|
+
"cookie" => @cookie,
|
|
400
|
+
"last_auth_check" => @last_auth_check,
|
|
401
|
+
"authorized" => @authorized
|
|
402
|
+
}
|
|
403
|
+
if XMLHash.write( session_file, values )
|
|
404
|
+
notify( I18n.get( "wiki.session.save.success", @username ) )
|
|
405
|
+
return true
|
|
406
|
+
else
|
|
407
|
+
notify( I18n.get( "wiki.session.save.error", @username ) )
|
|
408
|
+
return false
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def fetch_page_edit_params( page_url )
|
|
414
|
+
headers = { "Keep-Alive"=>"300", "Connection"=>"keep-alive", "Referer"=>"#{page_url}", "Cookie"=>@cookie }
|
|
415
|
+
response, page_url = HTTP.fetch_page_get( "#{page_url}&action=edit", headers )
|
|
416
|
+
|
|
417
|
+
edit_params = {}
|
|
418
|
+
return edit_params if ! response || response.code != "200"
|
|
419
|
+
|
|
420
|
+
page_body = response.body()
|
|
421
|
+
page_body.tr_s!( " \n\r\t", " " )
|
|
422
|
+
|
|
423
|
+
if (md = /<input type=['"]hidden['"] value=['"]([a-fA-F0-9+\\]*)['"] name=['"]wpEditToken['"] ?\/>/.match( page_body ))
|
|
424
|
+
edit_params["edit_token"] = md[1]
|
|
425
|
+
if (md = /<input type=['"]hidden['"] value=['"]([0-9]+)['"] name=['"]wpEdittime['"] ?\/>/.match( page_body ))
|
|
426
|
+
edit_params["edit_time"] = md[1]
|
|
427
|
+
end
|
|
428
|
+
if (md = /<input type=['"]hidden['"] value=['"]([0-9]+)['"] name=['"]wpStarttime['"] ?\/>/.match( page_body ))
|
|
429
|
+
edit_params["start_time"] = md[1]
|
|
430
|
+
end
|
|
431
|
+
edit_params["logged_in"] = (/<li id="pt-logout">/.match( page_body ) != nil)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
return edit_params
|
|
435
|
+
end
|
|
436
|
+
protected :fetch_page_edit_params
|
|
437
|
+
|
|
438
|
+
def submit_page( page_url, page_content, summary="", watch=true, retries=1, auto_login=true )
|
|
439
|
+
|
|
440
|
+
return false if (! logged_in? && ! auto_login) || ! authorized?
|
|
441
|
+
|
|
442
|
+
(retries+1).times do
|
|
443
|
+
|
|
444
|
+
begin
|
|
445
|
+
|
|
446
|
+
next if ! logged_in? && ! login()
|
|
447
|
+
|
|
448
|
+
# make sure we have the long url format
|
|
449
|
+
page_url = build_url( parse_url( page_url ) )
|
|
450
|
+
|
|
451
|
+
# Try to get the edit token for url, can't continue without it:
|
|
452
|
+
edit_params = fetch_page_edit_params( page_url )
|
|
453
|
+
|
|
454
|
+
if ! edit_params["logged_in"] # site says user is not logged in (session has expired), force relogin
|
|
455
|
+
next if ! login( @username, @password, true )
|
|
456
|
+
# after being successfully logged in, refetch the edit page
|
|
457
|
+
edit_params = fetch_page_edit_params( page_url )
|
|
458
|
+
next if ! edit_params["logged_in"]
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
next if ! edit_params["edit_token"]
|
|
462
|
+
|
|
463
|
+
params = [
|
|
464
|
+
MultipartFormData.text_param( "wpTextbox1", page_content ),
|
|
465
|
+
MultipartFormData.text_param( "wpSummary", summary ),
|
|
466
|
+
MultipartFormData.text_param( "wpWatchthis", watch ? "on" : "off" ),
|
|
467
|
+
MultipartFormData.text_param( "wpSave", "Save page" ),
|
|
468
|
+
MultipartFormData.text_param( "wpSection", "" ),
|
|
469
|
+
MultipartFormData.text_param( "wpStarttime", edit_params["start_time"].to_s() ), # the new revision time
|
|
470
|
+
MultipartFormData.text_param( "wpEdittime", edit_params["edit_time"].to_s() ), # the previous revision time
|
|
471
|
+
MultipartFormData.text_param( "wpEditToken", edit_params["edit_token"] ),
|
|
472
|
+
]
|
|
473
|
+
|
|
474
|
+
headers = {
|
|
475
|
+
"Keep-Alive" => "300",
|
|
476
|
+
"Connection" => "keep-alive",
|
|
477
|
+
"Referer" => "http://#{site_host()}#{page_url}&action=edit",
|
|
478
|
+
"Cookie" => @cookie,
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
response, page_url = HTTP.fetch_page_post_form_multipart( "#{page_url}&action=submit", params, headers, -1 )
|
|
482
|
+
|
|
483
|
+
return true if response.code == "302" # we should have received a redirect code
|
|
484
|
+
|
|
485
|
+
rescue TimeoutError
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
return false
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def submit_redirect_page( page_url, link, summary=nil )
|
|
493
|
+
if submit_page( page_url, "#REDIRECT #{link}", summary )
|
|
494
|
+
notify( I18n.get( "wiki.submitredirect.success", link ) )
|
|
495
|
+
return url
|
|
496
|
+
else
|
|
497
|
+
notify( I18n.get( "wiki.submitredirect.error", link ) )
|
|
498
|
+
return nil
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
def upload_file( src_file, dst_file, mime_type, description="", watch=true, auto_login=true )
|
|
503
|
+
|
|
504
|
+
if ! logged_in?
|
|
505
|
+
return false if ! auto_login || ! login()
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
begin
|
|
509
|
+
data = File.new( src_file ).read()
|
|
510
|
+
rescue Exception
|
|
511
|
+
return false
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
params = [
|
|
515
|
+
MultipartFormData.file_param( "wpUploadFile", File.basename( src_file ), mime_type, data ),
|
|
516
|
+
MultipartFormData.text_param( "wpDestFile", dst_file ),
|
|
517
|
+
MultipartFormData.text_param( "wpUploadDescription", description ),
|
|
518
|
+
MultipartFormData.text_param( "wpWatchthis", watch ? "true" : "false" ),
|
|
519
|
+
MultipartFormData.text_param( "wpUpload", "Upload file" ),
|
|
520
|
+
]
|
|
521
|
+
|
|
522
|
+
headers = {
|
|
523
|
+
"Keep-Alive" => "300",
|
|
524
|
+
"Connection" => "keep-alive",
|
|
525
|
+
"Referer" => "http://#{site_host()}/index.php?title=Special:Upload&wpDestFile=#{CGI.escape(dst_file)}",
|
|
526
|
+
"Cookie" => @cookie,
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
begin
|
|
530
|
+
|
|
531
|
+
response, page_url = HTTP.fetch_page_post_form_multipart(
|
|
532
|
+
"http://#{site_host()}/index.php?title=Special:Upload",
|
|
533
|
+
params,
|
|
534
|
+
headers,
|
|
535
|
+
-1
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
# we have to receive a redirect code
|
|
539
|
+
return true if response.code == "302"
|
|
540
|
+
|
|
541
|
+
# error, possibly an expired session: relogin and try again
|
|
542
|
+
login( @username, @password, true )
|
|
543
|
+
response, page_url = HTTP.fetch_page_post_form_multipart(
|
|
544
|
+
"http://#{site_host()}/index.php?title=Special:Upload",
|
|
545
|
+
params,
|
|
546
|
+
headers,
|
|
547
|
+
-1
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
# again, we should have received a redirect
|
|
551
|
+
return response.code == "302"
|
|
552
|
+
|
|
553
|
+
rescue TimeoutError
|
|
554
|
+
return false
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
def upload_cover_image( image_path, artist, album, year, watch=true )
|
|
560
|
+
|
|
561
|
+
album_art_name = build_album_art_name( artist, album, year )
|
|
562
|
+
album_art_desc = build_album_art_description( artist, album, year )
|
|
563
|
+
image_path, mime_type = prepare_image_file( image_path )
|
|
564
|
+
|
|
565
|
+
if Strings.empty?( image_path ) || Strings.empty?( mime_type )
|
|
566
|
+
notify( I18n.get( "wiki.uploadcover.error.convert" ) )
|
|
567
|
+
else
|
|
568
|
+
notify( I18n.get( "wiki.uploadcover.uploading", album, artist ) )
|
|
569
|
+
if upload_file( image_path, album_art_name, mime_type, album_art_desc, watch )
|
|
570
|
+
notify( I18n.get( "wiki.uploadcover.success", album, artist ) )
|
|
571
|
+
else
|
|
572
|
+
notify( I18n.get( "wiki.uploadcover.error", album, artist ) )
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def build_tracks( album_data )
|
|
580
|
+
return self.class.build_tracks( album_data )
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
def build_album_page( reviewed, artist, album, year, month, day, tracks, album_art )
|
|
584
|
+
return self.class.build_album_page( reviewed, artist, album, year, month, day, tracks, album_art )
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
def submittable_album_params?( artist, album, year )
|
|
588
|
+
if Strings.empty?( artist )
|
|
589
|
+
notify( I18n.get( "wiki.submitalbum.error.invalidartist" ) )
|
|
590
|
+
return false
|
|
591
|
+
elsif Strings.empty?( album )
|
|
592
|
+
notify( I18n.get( "wiki.submitalbum.error.invalidalbum" ) )
|
|
593
|
+
return false
|
|
594
|
+
elsif year <= 1900
|
|
595
|
+
notify( I18n.get( "wiki.submitalbum.error.invalidyear" ) )
|
|
596
|
+
return false
|
|
597
|
+
else
|
|
598
|
+
return true
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
protected :submittable_album_params?
|
|
602
|
+
|
|
603
|
+
# use skip_initial_page_search when you know the page doesn't exists (i.e. when you have already searched it)
|
|
604
|
+
def submit_album_page( album_data, image_path=nil, allow_page_overwrite=true, skip_initial_page_search=false, show_review_dialog=true, must_review=false )
|
|
605
|
+
|
|
606
|
+
show_review_dialog = true if must_review
|
|
607
|
+
|
|
608
|
+
if ! allow_page_overwrite && ! skip_initial_page_search
|
|
609
|
+
notify( I18n.get( "wiki.submitalbum.searchingpage", album_data.title, album_data.artist ) )
|
|
610
|
+
if find_album_page_url( album_data.artist, album_data.title, album_data.year )
|
|
611
|
+
notify( I18n.get( "wiki.submitalbum.pagefound", album_data.title, album_data.artist ) )
|
|
612
|
+
return nil, nil
|
|
613
|
+
else
|
|
614
|
+
notify( I18n.get( "wiki.submitalbum.nopagefound", album_data.title, album_data.artist ) )
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
page_data = {
|
|
619
|
+
"site_name" => site_name(),
|
|
620
|
+
"artist" => album_data.artist,
|
|
621
|
+
"year" => album_data.year,
|
|
622
|
+
"month" => album_data.month,
|
|
623
|
+
"day" => album_data.day,
|
|
624
|
+
"album" => cleanup_title_token( album_data.title ),
|
|
625
|
+
"tracks" => build_tracks( album_data ),
|
|
626
|
+
"reviewed" => false
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
page_data["album_art_name"] = find_album_art_name( page_data["artist"], page_data["album"], page_data["year"] )
|
|
630
|
+
if page_data["album_art_name"] == nil # album art not found, we'll attempt to upload it
|
|
631
|
+
page_data["image_path"] = image_path.to_s()
|
|
632
|
+
attempt_upload = true
|
|
633
|
+
else
|
|
634
|
+
attempt_upload = false
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
# check if the album parameters are "submitteable" content
|
|
638
|
+
return nil, nil if ! submittable_album_params?( page_data["artist"], page_data["album"], page_data["year"] )
|
|
639
|
+
|
|
640
|
+
page_url = build_album_url( page_data["artist"], page_data["album"], page_data["year"], false )
|
|
641
|
+
|
|
642
|
+
page_content = build_album_page(
|
|
643
|
+
page_data["reviewed"],
|
|
644
|
+
page_data["artist"],
|
|
645
|
+
page_data["album"],
|
|
646
|
+
page_data["year"],
|
|
647
|
+
page_data["month"],
|
|
648
|
+
page_data["day"],
|
|
649
|
+
page_data["tracks"],
|
|
650
|
+
page_data["album_art_name"] ?
|
|
651
|
+
page_data["album_art_name"] :
|
|
652
|
+
build_album_art_name( page_data["artist"], page_data["album"], page_data["year"] )
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
if attempt_upload && ! Strings.empty?( page_data["image_path"] )
|
|
656
|
+
upload_cover_image( page_data["image_path"], page_data["artist"], page_data["album"], page_data["year"] )
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
summary = "#{page_data["reviewed"] ? "" : "autogen. "}album page (#{@@NAME}v#{@@VERSION})"
|
|
660
|
+
if submit_page( page_url, page_content, summary )
|
|
661
|
+
notify( I18n.get( "wiki.submitalbum.success", page_data["album"], page_data["artist"] ) )
|
|
662
|
+
return page_url, page_data
|
|
663
|
+
else
|
|
664
|
+
notify( I18n.get( "wiki.submitalbum.error", page_url ) )
|
|
665
|
+
return nil, page_data
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
def build_song_page( reviewed, artist, title, album, year, credits, lyricist, lyrics )
|
|
671
|
+
self.class.build_song_page( reviewed, artist, title, album, year, credits, lyricist, lyrics )
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
def submittable_song_params?( artist, song, lyrics, instrumental )
|
|
676
|
+
if Strings.empty?( artist )
|
|
677
|
+
notify( I18n.get( "wiki.submitsong.error.invalidartist" ) )
|
|
678
|
+
return false
|
|
679
|
+
elsif Strings.empty?( song )
|
|
680
|
+
notify( I18n.get( "wiki.submitsong.error.invalidsong" ) )
|
|
681
|
+
return false
|
|
682
|
+
elsif Strings.empty?( lyrics ) && ! instrumental
|
|
683
|
+
notify( I18n.get( "wiki.submitsong.error.nolyrics" ) )
|
|
684
|
+
return false
|
|
685
|
+
else
|
|
686
|
+
return true
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
protected :submittable_song_params?
|
|
690
|
+
|
|
691
|
+
# if edit_url is not nil, it's assumed that we're trying to overwrite (edit) a page, otherwise
|
|
692
|
+
# it's assummed that we're trying to create a new page and so overwritting won't be allowed
|
|
693
|
+
# use skip_initial_page_search when you know the page doesn't exists (i.e. when you have already searched it)
|
|
694
|
+
def submit_song_page( song_data, edit_url=nil, skip_initial_page_search=false, show_review_dialog=true, must_review=false )
|
|
695
|
+
|
|
696
|
+
show_review_dialog = true if must_review
|
|
697
|
+
|
|
698
|
+
if ! edit_url && ! skip_initial_page_search
|
|
699
|
+
notify( I18n.get( "wiki.submitsong.searchingpage", song_data.title, song_data.artist ) )
|
|
700
|
+
if find_song_page_url( song_data.artist, song_data.title )
|
|
701
|
+
notify( I18n.get( "wiki.submitsong.pagefound", song_data.title, song_data.artist ) )
|
|
702
|
+
return nil, nil
|
|
703
|
+
else
|
|
704
|
+
notify( I18n.get( "wiki.submitsong.nopagefound", song_data.title, song_data.artist ) )
|
|
705
|
+
end
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
page_data = {
|
|
709
|
+
"site_name" => site_name(),
|
|
710
|
+
"edit_mode" => edit_url != nil,
|
|
711
|
+
"artist" => cleanup_title_token( song_data.artist ),
|
|
712
|
+
"year" => song_data.year,
|
|
713
|
+
"album" => cleanup_title_token( song_data.album.to_s() ),
|
|
714
|
+
"title" => cleanup_title_token( song_data.title ),
|
|
715
|
+
"lyrics" => Strings.cleanup_lyrics( song_data.lyrics.to_s() ),
|
|
716
|
+
"instrumental" => song_data.instrumental?,
|
|
717
|
+
"credits" => song_data.credits.join( "; " ),
|
|
718
|
+
"lyricist" => song_data.lyricists.join( "; " ),
|
|
719
|
+
"reviewed" => false
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
# check if the song parameters are "submitteable" content
|
|
723
|
+
return nil, nil if ! submittable_song_params?( page_data["artist"], page_data["title"], page_data["lyrics"], page_data["instrumental"] )
|
|
724
|
+
|
|
725
|
+
page_url = edit_url ? edit_url : build_song_url( page_data["artist"], page_data["title"], false )
|
|
726
|
+
|
|
727
|
+
page_content = build_song_page(
|
|
728
|
+
page_data["reviewed"],
|
|
729
|
+
page_data["artist"],
|
|
730
|
+
page_data["title"],
|
|
731
|
+
page_data["album"],
|
|
732
|
+
page_data["year"],
|
|
733
|
+
page_data["credits"],
|
|
734
|
+
page_data["lyricist"],
|
|
735
|
+
page_data["lyrics"]
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
summary = "#{page_data["reviewed"] ? "" : "autogen. "}song page (#{@@NAME}v#{@@VERSION})"
|
|
739
|
+
if submit_page( page_url, page_content, summary )
|
|
740
|
+
notify( I18n.get( "wiki.submitsong.success", page_data["title"], page_data["artist"] ) )
|
|
741
|
+
return page_url, page_data
|
|
742
|
+
else
|
|
743
|
+
notify( I18n.get( "wiki.submitsong.error", page_url ) )
|
|
744
|
+
return nil, page_data
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
def MediaWikiLyrics.parse_search_results( page_body, content_matches=false )
|
|
750
|
+
|
|
751
|
+
results = []
|
|
752
|
+
return results if page_body == nil
|
|
753
|
+
|
|
754
|
+
page_body.tr_s!( " \n\r\t", " " )
|
|
755
|
+
page_body.gsub!( /\ ?<\/?span[^>]*> ?/, "" )
|
|
756
|
+
|
|
757
|
+
return results if ! page_body.sub!( /^.*<a name="(Article|Page)_title_matches">/, "" ) &&
|
|
758
|
+
! page_body.sub!( /^.*<a name="No_(article|page)_title_matches">/, "" )
|
|
759
|
+
|
|
760
|
+
page_body.sub!( /<a name="No_(article|page)_text_matches">.*$/, "" ) if ! content_matches
|
|
761
|
+
|
|
762
|
+
return results if ! page_body.gsub!( /<form id="powersearch" method="get" action="[^"]+">.*$/, "" )
|
|
763
|
+
page_body.gsub!( /<\/[uo]l> ?<p( [^>]*|)>View \(previous .*$/, "" )
|
|
764
|
+
|
|
765
|
+
page_body.split( "<li>" ).each() do |entry|
|
|
766
|
+
if (md = /<a href="([^"]*index\.php\/|[^"]*index\.php\?title=|\/)([^"]*)" title="([^"]+)"/.match( entry ))
|
|
767
|
+
result = {
|
|
768
|
+
@@SEARCH_RESULT_URL => "http://#{site_host()}/index.php?title=#{md[2]}",
|
|
769
|
+
@@SEARCH_RESULT_TITLE => md[3]
|
|
770
|
+
}
|
|
771
|
+
results << result if ! content_matches || ! results.include?( result )
|
|
772
|
+
end
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
return results
|
|
776
|
+
end
|
|
777
|
+
|
|
778
|
+
def parse_search_results( page_body, content_matches=false )
|
|
779
|
+
self.class.parse_search_results( page_body, content_matches )
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
@@FIND_TEMPLATE_START = 0
|
|
783
|
+
@@FIND_TEMPLATE_NAME = 1
|
|
784
|
+
@@FIND_TEMPLATE_PARAM = 2
|
|
785
|
+
@@FIND_TEMPLATE_PARAM_VALUE = 3
|
|
786
|
+
|
|
787
|
+
# NOTE: nested templates are only supported in named parameters values
|
|
788
|
+
def MediaWikiLyrics.parse_template_rec( template_text, first_index )
|
|
789
|
+
|
|
790
|
+
template_data = { "name" => "", "params" => {} }
|
|
791
|
+
|
|
792
|
+
operation = @@FIND_TEMPLATE_START
|
|
793
|
+
|
|
794
|
+
param_number = 1
|
|
795
|
+
param_name = nil
|
|
796
|
+
aux_index = -1
|
|
797
|
+
|
|
798
|
+
link = false
|
|
799
|
+
|
|
800
|
+
chr_index = first_index - 1
|
|
801
|
+
chrs_array = template_text.is_a?( Array ) ? template_text : template_text.unpack( "U*" )
|
|
802
|
+
max_chr_index = chrs_array.size-2
|
|
803
|
+
|
|
804
|
+
while ( chr_index <= max_chr_index )
|
|
805
|
+
|
|
806
|
+
chr_index += 1
|
|
807
|
+
chr = [chrs_array[chr_index]].pack( "U" )
|
|
808
|
+
|
|
809
|
+
if operation == @@FIND_TEMPLATE_START
|
|
810
|
+
if chr == "{"
|
|
811
|
+
aux_index = chr_index + 2 # start of template name
|
|
812
|
+
operation = @@FIND_TEMPLATE_NAME
|
|
813
|
+
end
|
|
814
|
+
elsif operation == @@FIND_TEMPLATE_NAME
|
|
815
|
+
if chr == "|"
|
|
816
|
+
template_data["name"] = chrs_array[aux_index..chr_index-1].pack( "U*" ).strip()
|
|
817
|
+
aux_index = chr_index + 1 # start of first parameter (if there is one)
|
|
818
|
+
operation = @@FIND_TEMPLATE_PARAM
|
|
819
|
+
elsif chr == "}" # we may have arrived to the template end (in which case the template has no parameters)
|
|
820
|
+
next_chr = chrs_array[chr_index+1]
|
|
821
|
+
if next_chr && [next_chr].pack( "U" ) == "}" # }} indicates the template end
|
|
822
|
+
template_data["name"] = chrs_array[aux_index..chr_index-1].pack( "U*" ).strip()
|
|
823
|
+
chr_index += 1
|
|
824
|
+
break
|
|
825
|
+
end
|
|
826
|
+
end
|
|
827
|
+
elsif operation == @@FIND_TEMPLATE_PARAM
|
|
828
|
+
if chr == "="
|
|
829
|
+
param_name = chrs_array[aux_index..chr_index-1].pack( "U*" ).strip()
|
|
830
|
+
param_name = param_name.to_i() if param_name.to_i() > 0
|
|
831
|
+
template_data["params"].delete( param_name )
|
|
832
|
+
aux_index = chr_index + 1 # start of parameter value
|
|
833
|
+
operation = @@FIND_TEMPLATE_PARAM_VALUE
|
|
834
|
+
elsif link
|
|
835
|
+
if chr == "]" # we may be at the end of a link (we no longer ignore | and } characters in that case)
|
|
836
|
+
next_chr = chrs_array[chr_index+1]
|
|
837
|
+
if next_chr && [next_chr].pack( "U" ) == "]" # ]] indicates the link end
|
|
838
|
+
link = false
|
|
839
|
+
chr_index += 1
|
|
840
|
+
end
|
|
841
|
+
end
|
|
842
|
+
else
|
|
843
|
+
if chr == "[" # we may be at the start of a link (we ignore the | and } characters in that case)
|
|
844
|
+
next_chr = chrs_array[chr_index+1]
|
|
845
|
+
if next_chr && [next_chr].pack( "U" ) == "[" # [[ indicates the link start
|
|
846
|
+
link = true
|
|
847
|
+
chr_index += 1
|
|
848
|
+
end
|
|
849
|
+
elsif chr == "|" # we arrived to the parameter end (the parameter has no name)
|
|
850
|
+
template_data["params"][param_number] = chrs_array[aux_index..chr_index-1].pack( "U*" )
|
|
851
|
+
HTMLEntities.decode!( template_data["params"][param_number] )
|
|
852
|
+
param_number += 1
|
|
853
|
+
aux_index = chr_index + 1 # start of next parameter (if there is one)
|
|
854
|
+
elsif chr == "}" # we may have arrived to the template end (in which case the parameter has no name)
|
|
855
|
+
next_chr = chrs_array[chr_index+1]
|
|
856
|
+
if next_chr && [next_chr].pack( "U" ) == "}" # }} indicates the template end
|
|
857
|
+
template_data["params"][param_number] = chrs_array[aux_index..chr_index-1].pack( "U*" )
|
|
858
|
+
HTMLEntities.decode!( template_data["params"][param_number] )
|
|
859
|
+
param_number += 1
|
|
860
|
+
chr_index += 1
|
|
861
|
+
break
|
|
862
|
+
end
|
|
863
|
+
end
|
|
864
|
+
end
|
|
865
|
+
elsif operation == @@FIND_TEMPLATE_PARAM_VALUE
|
|
866
|
+
if chr == "{" # we may have arrived at a nested template case (the only one
|
|
867
|
+
# supported: template inserted in a named parameter value)
|
|
868
|
+
next_chr = chrs_array[chr_index+1]
|
|
869
|
+
if next_chr && [next_chr].pack( "U" ) == "{" # {{ indicates the template start
|
|
870
|
+
template_data["params"][param_name] = [] if ! template_data["params"][param_name]
|
|
871
|
+
param_array = template_data["params"][param_name]
|
|
872
|
+
prev_text = chrs_array[aux_index..chr_index-1].pack( "U*" )
|
|
873
|
+
HTMLEntities.decode!( prev_text )
|
|
874
|
+
prev_text.lstrip!() if param_array.empty?
|
|
875
|
+
param_array.insert( -1, prev_text ) if ! prev_text.empty?
|
|
876
|
+
chr_index, nested_template_data = parse_template_rec( chrs_array, chr_index )
|
|
877
|
+
param_array.insert( -1, nested_template_data )
|
|
878
|
+
aux_index = chr_index + 1
|
|
879
|
+
end
|
|
880
|
+
elsif link
|
|
881
|
+
if chr == "]" # we may be at the end of a link (we no longer ignore | and } characters in that case)
|
|
882
|
+
next_chr = chrs_array[chr_index+1]
|
|
883
|
+
if next_chr && [next_chr].pack( "U" ) == "]" # ]] indicates the link end
|
|
884
|
+
link = false
|
|
885
|
+
chr_index += 1
|
|
886
|
+
end
|
|
887
|
+
end
|
|
888
|
+
else
|
|
889
|
+
if chr == "[" # we may be at the start of a link (we ignore the | and } characters in that case)
|
|
890
|
+
next_chr = chrs_array[chr_index+1]
|
|
891
|
+
if next_chr && [next_chr].pack( "U" ) == "[" # [[ indicates the link start
|
|
892
|
+
link = true
|
|
893
|
+
chr_index += 1
|
|
894
|
+
end
|
|
895
|
+
elsif chr == "|" # we arrived to the parameter end
|
|
896
|
+
last_text = chrs_array[aux_index..chr_index-1].pack( "U*" )
|
|
897
|
+
HTMLEntities.decode!( last_text )
|
|
898
|
+
if template_data["params"][param_name]
|
|
899
|
+
param_array = template_data["params"][param_name]
|
|
900
|
+
last_text.rstrip!()
|
|
901
|
+
param_array.insert( -1, last_text ) if ! last_text.empty?
|
|
902
|
+
else
|
|
903
|
+
last_text.strip!()
|
|
904
|
+
template_data["params"][param_name] = last_text
|
|
905
|
+
end
|
|
906
|
+
aux_index = chr_index + 1
|
|
907
|
+
operation = @@FIND_TEMPLATE_PARAM
|
|
908
|
+
elsif chr == "}" # we may have arrived to the template end
|
|
909
|
+
next_chr = chrs_array[chr_index+1]
|
|
910
|
+
if next_chr && [next_chr].pack( "U" ) == "}" # }} indicates the template end
|
|
911
|
+
last_text = chrs_array[aux_index..chr_index-1].pack( "U*" )
|
|
912
|
+
HTMLEntities.decode!( last_text )
|
|
913
|
+
if template_data["params"][param_name]
|
|
914
|
+
param_array = template_data["params"][param_name]
|
|
915
|
+
last_text.rstrip!()
|
|
916
|
+
param_array.insert( -1, last_text ) if ! last_text.empty?
|
|
917
|
+
else
|
|
918
|
+
last_text.strip!()
|
|
919
|
+
template_data["params"][param_name] = last_text
|
|
920
|
+
end
|
|
921
|
+
chr_index += 1
|
|
922
|
+
break
|
|
923
|
+
end
|
|
924
|
+
end
|
|
925
|
+
end
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
end
|
|
929
|
+
|
|
930
|
+
return chr_index, template_data
|
|
931
|
+
|
|
932
|
+
end
|
|
933
|
+
private_class_method :parse_template_rec
|
|
934
|
+
|
|
935
|
+
def MediaWikiLyrics.parse_template( template_text )
|
|
936
|
+
index, template_data = parse_template_rec( template_text, 0 )
|
|
937
|
+
return template_data
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
def parse_template( template )
|
|
941
|
+
return self.class.parse_template( template )
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
def MediaWikiLyrics.prepare_image_file( image_path, size_limit=153600 )
|
|
945
|
+
4.times() do |trynumb|
|
|
946
|
+
system( "convert", "-quality", (100-trynumb*10).to_s(), image_path, "/tmp/AlbumArt.jpg" )
|
|
947
|
+
return nil, nil if $? != 0
|
|
948
|
+
size = FileTest.size?( "/tmp/AlbumArt.jpg" )
|
|
949
|
+
return "/tmp/AlbumArt.jpg", "image/jpeg" if (size ? size : 0) <= size_limit
|
|
950
|
+
end
|
|
951
|
+
return nil, nil
|
|
952
|
+
end
|
|
953
|
+
|
|
954
|
+
def prepare_image_file( image_path, size_limit=153600 )
|
|
955
|
+
return self.class.prepare_image_file( image_path, size_limit )
|
|
956
|
+
end
|
|
957
|
+
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
def MediaWikiLyrics.cleanup_title_token( title, downcase=false )
|
|
961
|
+
return cleanup_title_token!( String.new( title ), downcase )
|
|
962
|
+
end
|
|
963
|
+
|
|
964
|
+
def cleanup_title_token( title, downcase=false )
|
|
965
|
+
return self.class.cleanup_title_token( title, downcase )
|
|
966
|
+
end
|
|
967
|
+
|
|
968
|
+
def cleanup_title_token!( title, downcase=false )
|
|
969
|
+
return self.class.cleanup_title_token!( title, downcase )
|
|
970
|
+
end
|
|
971
|
+
|
|
972
|
+
def MediaWikiLyrics.get_sort_name( title )
|
|
973
|
+
return get_sort_name!( String.new( title ) )
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
def get_sort_name( title )
|
|
977
|
+
return self.class.get_sort_name( title )
|
|
978
|
+
end
|
|
979
|
+
|
|
980
|
+
def MediaWikiLyrics.get_sort_name!( title )
|
|
981
|
+
|
|
982
|
+
title.gsub!( /\[[^\]\[]*\]/, "" )
|
|
983
|
+
|
|
984
|
+
Strings.downcase!( title )
|
|
985
|
+
|
|
986
|
+
title.gsub!( /[·\.,;:"`´¿\?¡!\(\)\[\]{}<>#\$\+\*%\^]/, "" )
|
|
987
|
+
title.gsub!( /[\\\/_-]/, " " )
|
|
988
|
+
title.gsub!( "&", "and" )
|
|
989
|
+
title.squeeze!( " " )
|
|
990
|
+
title.strip!()
|
|
991
|
+
|
|
992
|
+
title.gsub!( /^a /, "" ) # NOTE: only valid for English
|
|
993
|
+
title.gsub!( /^an /, "" )
|
|
994
|
+
title.gsub!( /^the /, "" )
|
|
995
|
+
title.gsub!( /^el /, "" )
|
|
996
|
+
title.gsub!( /^le /, "" )
|
|
997
|
+
title.gsub!( /^la /, "" )
|
|
998
|
+
title.gsub!( /^l'([aeiou])/, "\\1" )
|
|
999
|
+
title.gsub!( /^los /, "" )
|
|
1000
|
+
title.gsub!( /^las /, "" )
|
|
1001
|
+
title.gsub!( /^les /, "" )
|
|
1002
|
+
title.gsub!( "'", "" )
|
|
1003
|
+
|
|
1004
|
+
Strings.remove_vocal_accents!( title )
|
|
1005
|
+
Strings.titlecase!( title, false, false )
|
|
1006
|
+
|
|
1007
|
+
return title
|
|
1008
|
+
end
|
|
1009
|
+
|
|
1010
|
+
def get_sort_name!( title )
|
|
1011
|
+
return self.class.get_sort_name!( title )
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
def MediaWikiLyrics.get_sort_letter( title )
|
|
1015
|
+
title = get_sort_name( title )
|
|
1016
|
+
title = title.strip()
|
|
1017
|
+
if title.index( /^[0-9]/ ) == 0
|
|
1018
|
+
return "0-9"
|
|
1019
|
+
else
|
|
1020
|
+
# return title.slice( 0, 1 )
|
|
1021
|
+
return title.unpack( "U*" ).slice( 0, 1 ).pack( "U*" )
|
|
1022
|
+
end
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
def get_sort_letter( title )
|
|
1026
|
+
return self.class.get_sort_letter( title )
|
|
1027
|
+
end
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
|
|
1031
|
+
# GENERAL FUNCTIONS
|
|
1032
|
+
|
|
1033
|
+
def MediaWikiLyrics.cleanup_article( article, capitalize=true )
|
|
1034
|
+
article = article.gsub( "_", " " )
|
|
1035
|
+
article.strip!()
|
|
1036
|
+
article.squeeze!( " " )
|
|
1037
|
+
Strings.capitalize!( article, false, true ) if capitalize
|
|
1038
|
+
return article
|
|
1039
|
+
end
|
|
1040
|
+
|
|
1041
|
+
def cleanup_article( article )
|
|
1042
|
+
return self.class.cleanup_article( article )
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1045
|
+
def MediaWikiLyrics.parse_link( link )
|
|
1046
|
+
|
|
1047
|
+
if (md = /^ *\[\[([^\|\]]+)\]\] *$/.match( link ))
|
|
1048
|
+
article = cleanup_article( md[1] )
|
|
1049
|
+
return article, article if ! article.empty?
|
|
1050
|
+
end
|
|
1051
|
+
|
|
1052
|
+
if (md = /^ *\[\[([^\|\]]+)\|([^\]]*)\]\] *$/.match( link ))
|
|
1053
|
+
article = cleanup_article( md[1] )
|
|
1054
|
+
if ! article.empty?
|
|
1055
|
+
display = cleanup_article( md[2], false )
|
|
1056
|
+
return article, display if ! display.empty?
|
|
1057
|
+
end
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
return nil, nil
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
def parse_link( link )
|
|
1064
|
+
return self.class.parse_link( link )
|
|
1065
|
+
end
|
|
1066
|
+
|
|
1067
|
+
def MediaWikiLyrics.build_link( article, display=nil )
|
|
1068
|
+
return display ? "[[#{article}|#{display}]]" : "[[#{article}]]"
|
|
1069
|
+
end
|
|
1070
|
+
|
|
1071
|
+
def build_link( article, display=nil )
|
|
1072
|
+
return self.class.build_link( article, display )
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
def MediaWikiLyrics.parse_url( url )
|
|
1076
|
+
if (md = /(https?:\/\/#{site_host()}\/|)(index.php\?title=|wiki\/|)([^&]+)(&.*|)$/.match( url ))
|
|
1077
|
+
return cleanup_article( CGI.unescape( md[3] ) ) # article title
|
|
1078
|
+
else
|
|
1079
|
+
return nil
|
|
1080
|
+
end
|
|
1081
|
+
end
|
|
1082
|
+
|
|
1083
|
+
def parse_url( url )
|
|
1084
|
+
return self.class.parse_url( url )
|
|
1085
|
+
end
|
|
1086
|
+
|
|
1087
|
+
def MediaWikiLyrics.build_url( article )
|
|
1088
|
+
# return "http://#{site_host()}/index.php?title=#{CGI.escape( article )}"
|
|
1089
|
+
return "http://#{site_host()}/index.php?title=#{CGI.escape( article.gsub( " ", "_" ) )}"
|
|
1090
|
+
end
|
|
1091
|
+
|
|
1092
|
+
def build_url( article )
|
|
1093
|
+
return self.class.build_url( article )
|
|
1094
|
+
end
|
|
1095
|
+
|
|
1096
|
+
def MediaWikiLyrics.build_rawdata_url( article )
|
|
1097
|
+
return build_url( article ) + "&action=raw"
|
|
1098
|
+
end
|
|
1099
|
+
|
|
1100
|
+
def build_rawdata_url( article )
|
|
1101
|
+
return self.class.build_rawdata_url( article )
|
|
1102
|
+
end
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
# SONG FUNCTIONS
|
|
1108
|
+
|
|
1109
|
+
def MediaWikiLyrics.parse_song_link( link )
|
|
1110
|
+
article, display = parse_link( link )
|
|
1111
|
+
return nil, nil if article == nil
|
|
1112
|
+
if (md = /^([^:]+):(.+)$/.match( article ))
|
|
1113
|
+
return md[1], md[2]
|
|
1114
|
+
else
|
|
1115
|
+
return nil, nil
|
|
1116
|
+
end
|
|
1117
|
+
end
|
|
1118
|
+
|
|
1119
|
+
def parse_song_link( link )
|
|
1120
|
+
return self.class.parse_song_link( link )
|
|
1121
|
+
end
|
|
1122
|
+
|
|
1123
|
+
def MediaWikiLyrics.build_song_link( artist, title, cleanup=true )
|
|
1124
|
+
if cleanup
|
|
1125
|
+
artist = cleanup_title_token( artist )
|
|
1126
|
+
title = cleanup_title_token( title )
|
|
1127
|
+
end
|
|
1128
|
+
return build_link( "#{artist}:#{title}" )
|
|
1129
|
+
end
|
|
1130
|
+
|
|
1131
|
+
def build_song_link( artist, title, cleanup=true )
|
|
1132
|
+
return self.class.build_song_link( artist, title, cleanup )
|
|
1133
|
+
end
|
|
1134
|
+
|
|
1135
|
+
def MediaWikiLyrics.parse_song_url( url )
|
|
1136
|
+
article = parse_url( url )
|
|
1137
|
+
return nil, nil if article == nil
|
|
1138
|
+
if (md = /^([^:]+):(.+)$/.match( article ))
|
|
1139
|
+
return md[1], md[2] # artist, song title
|
|
1140
|
+
else
|
|
1141
|
+
return nil, nil
|
|
1142
|
+
end
|
|
1143
|
+
end
|
|
1144
|
+
|
|
1145
|
+
def parse_song_url( url )
|
|
1146
|
+
return self.class.parse_song_url( url )
|
|
1147
|
+
end
|
|
1148
|
+
|
|
1149
|
+
def MediaWikiLyrics.build_song_url( artist, title, cleanup=true )
|
|
1150
|
+
if cleanup
|
|
1151
|
+
artist = cleanup_title_token( artist )
|
|
1152
|
+
title = cleanup_title_token( title )
|
|
1153
|
+
end
|
|
1154
|
+
return build_url( "#{artist}:#{title}" )
|
|
1155
|
+
end
|
|
1156
|
+
|
|
1157
|
+
def build_song_url( artist, title, cleanup=true )
|
|
1158
|
+
return self.class.build_song_url( artist, title, cleanup )
|
|
1159
|
+
end
|
|
1160
|
+
|
|
1161
|
+
def MediaWikiLyrics.build_song_rawdata_url( artist, title, cleanup=true )
|
|
1162
|
+
return build_song_url( artist, title, cleanup ) + "&action=raw"
|
|
1163
|
+
end
|
|
1164
|
+
|
|
1165
|
+
def build_song_rawdata_url( artist, title, cleanup=true )
|
|
1166
|
+
return self.class.build_song_rawdata_url( artist, title, cleanup )
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
def MediaWikiLyrics.build_song_edit_url( artist, title, cleanup=true )
|
|
1170
|
+
return build_song_url( artist, title, cleanup ) + "&action=edit"
|
|
1171
|
+
end
|
|
1172
|
+
|
|
1173
|
+
def build_song_edit_url( artist, title, cleanup=true )
|
|
1174
|
+
return self.class.build_song_edit_url( artist, title, cleanup )
|
|
1175
|
+
end
|
|
1176
|
+
|
|
1177
|
+
def MediaWikiLyrics.build_song_add_url( request, cleanup=true )
|
|
1178
|
+
return build_song_url( request.artist, request.title, cleanup ) + "&action=edit"
|
|
1179
|
+
end
|
|
1180
|
+
|
|
1181
|
+
def build_song_add_url( request, cleanup=true )
|
|
1182
|
+
return self.class.build_song_add_url( request, cleanup )
|
|
1183
|
+
end
|
|
1184
|
+
|
|
1185
|
+
def MediaWikiLyrics.build_song_search_url( artist, title )
|
|
1186
|
+
artist = cleanup_title_token( artist )
|
|
1187
|
+
title = cleanup_title_token( title )
|
|
1188
|
+
search_string = CGI.escape( "#{artist}:#{title}" )
|
|
1189
|
+
return "http://#{site_host()}/index.php?redirs=1&search=#{search_string}&fulltext=Search&limit=500"
|
|
1190
|
+
end
|
|
1191
|
+
|
|
1192
|
+
def build_song_search_url( artist, title )
|
|
1193
|
+
return self.class.build_song_search_url( artist, title )
|
|
1194
|
+
end
|
|
1195
|
+
|
|
1196
|
+
def MediaWikiLyrics.find_song_page_url( artist, title )
|
|
1197
|
+
|
|
1198
|
+
url = build_song_rawdata_url( artist, title )
|
|
1199
|
+
body, url = fetch_content_page( url )
|
|
1200
|
+
|
|
1201
|
+
if ! Strings.empty?( body ) # page exists
|
|
1202
|
+
return url
|
|
1203
|
+
else
|
|
1204
|
+
artist = Strings.normalize( cleanup_title_token( artist ) )
|
|
1205
|
+
title = Strings.normalize( cleanup_title_token( title ) )
|
|
1206
|
+
normalized_target = "#{artist}:#{title}"
|
|
1207
|
+
|
|
1208
|
+
response, url = HTTP.fetch_page_get( build_song_search_url( artist, title ) )
|
|
1209
|
+
return nil if response == nil
|
|
1210
|
+
parse_search_results( response.body(), true ).each() do |result|
|
|
1211
|
+
normalized_result = result[@@SEARCH_RESULT_TITLE].split( ":" ).each() do |token|
|
|
1212
|
+
Strings.normalize!( token )
|
|
1213
|
+
end.join( ":" )
|
|
1214
|
+
return result[@@SEARCH_RESULT_URL] if normalized_target == normalized_result
|
|
1215
|
+
end
|
|
1216
|
+
|
|
1217
|
+
return nil
|
|
1218
|
+
end
|
|
1219
|
+
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
def find_song_page_url( artist, title )
|
|
1223
|
+
return self.class.find_song_page_url( artist, title )
|
|
1224
|
+
end
|
|
1225
|
+
|
|
1226
|
+
|
|
1227
|
+
|
|
1228
|
+
# ALBUM FUNCTIONS
|
|
1229
|
+
|
|
1230
|
+
def MediaWikiLyrics.parse_album_link( link )
|
|
1231
|
+
article, display = parse_link( link )
|
|
1232
|
+
return nil, nil, nil if article == nil
|
|
1233
|
+
if (md = /^([^:]+):(.+) \(([0-9]{4,4})\)$/.match( article ))
|
|
1234
|
+
return md[1], md[2], md[3]
|
|
1235
|
+
else
|
|
1236
|
+
return nil, nil, nil
|
|
1237
|
+
end
|
|
1238
|
+
end
|
|
1239
|
+
|
|
1240
|
+
def parse_album_link( link )
|
|
1241
|
+
return self.class.parse_album_link( link )
|
|
1242
|
+
end
|
|
1243
|
+
|
|
1244
|
+
def MediaWikiLyrics.build_album_link( artist, album, year, cleanup=true )
|
|
1245
|
+
if cleanup
|
|
1246
|
+
artist = cleanup_title_token( artist )
|
|
1247
|
+
album = cleanup_title_token( album )
|
|
1248
|
+
end
|
|
1249
|
+
return build_link( "#{artist}:#{album} (#{year})" )
|
|
1250
|
+
end
|
|
1251
|
+
|
|
1252
|
+
def build_album_link( artist, album, year, cleanup=true )
|
|
1253
|
+
return self.class.build_album_link( artist, album, year, cleanup )
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
def MediaWikiLyrics.parse_album_url( url )
|
|
1257
|
+
article = parse_url( url )
|
|
1258
|
+
return nil, nil, nil if article == nil
|
|
1259
|
+
if (md = /^([^:]+):(.+) \(([0-9]{4,4})\)$/.match( article ))
|
|
1260
|
+
return md[1], md[2], md[3]
|
|
1261
|
+
else
|
|
1262
|
+
return nil, nil, nil
|
|
1263
|
+
end
|
|
1264
|
+
end
|
|
1265
|
+
|
|
1266
|
+
def parse_album_url( url )
|
|
1267
|
+
return self.class.parse_album_url( url )
|
|
1268
|
+
end
|
|
1269
|
+
|
|
1270
|
+
def MediaWikiLyrics.build_album_url( artist, album, year, cleanup=true )
|
|
1271
|
+
if cleanup
|
|
1272
|
+
artist = cleanup_title_token( artist )
|
|
1273
|
+
album = cleanup_title_token( album )
|
|
1274
|
+
end
|
|
1275
|
+
return build_url( "#{artist}:#{album} (#{year})" )
|
|
1276
|
+
end
|
|
1277
|
+
|
|
1278
|
+
def build_album_url( artist, album, year, cleanup=true )
|
|
1279
|
+
return self.class.build_album_url( artist, album, year, cleanup )
|
|
1280
|
+
end
|
|
1281
|
+
|
|
1282
|
+
def MediaWikiLyrics.build_album_rawdata_url( artist, album, year, cleanup=true )
|
|
1283
|
+
return build_album_url( artist, album, year, cleanup ) + "&action=raw"
|
|
1284
|
+
end
|
|
1285
|
+
|
|
1286
|
+
def build_album_rawdata_url( artist, album, year, cleanup=true )
|
|
1287
|
+
return self.class.build_album_rawdata_url( artist, album, year, cleanup )
|
|
1288
|
+
end
|
|
1289
|
+
|
|
1290
|
+
def MediaWikiLyrics.build_album_edit_url( artist, album, year, cleanup=true )
|
|
1291
|
+
return build_album_url( artist, album, year, cleanup ) + "&action=edit"
|
|
1292
|
+
end
|
|
1293
|
+
|
|
1294
|
+
def build_album_edit_url( artist, album, year, cleanup=true )
|
|
1295
|
+
return self.class.build_album_edit_url( artist, album, year, cleanup )
|
|
1296
|
+
end
|
|
1297
|
+
|
|
1298
|
+
def MediaWikiLyrics.build_album_search_url( artist, album, year )
|
|
1299
|
+
artist = cleanup_title_token( artist )
|
|
1300
|
+
album = cleanup_title_token( album )
|
|
1301
|
+
search_string = CGI.escape( "#{artist}:#{album} (#{year})" )
|
|
1302
|
+
return "http://#{site_host()}/index.php?redirs=1&search=#{search_string}&fulltext=Search&limit=500"
|
|
1303
|
+
end
|
|
1304
|
+
|
|
1305
|
+
def build_album_search_url( artist, album, year )
|
|
1306
|
+
return self.class.build_album_search_url( artist, album, year )
|
|
1307
|
+
end
|
|
1308
|
+
|
|
1309
|
+
def MediaWikiLyrics.find_album_page_url( artist, album, year )
|
|
1310
|
+
|
|
1311
|
+
url = build_album_rawdata_url( artist, album, year )
|
|
1312
|
+
body, url = fetch_content_page( url )
|
|
1313
|
+
|
|
1314
|
+
if ! Strings.empty?( body ) # page exists
|
|
1315
|
+
return url
|
|
1316
|
+
else
|
|
1317
|
+
artist = Strings.normalize( cleanup_title_token( artist ) )
|
|
1318
|
+
album = Strings.normalize( cleanup_title_token( album ) )
|
|
1319
|
+
normalized_target = "#{artist}:#{album} #{year}" # NOTE: normalize removes the parenthesis
|
|
1320
|
+
|
|
1321
|
+
response, url = HTTP.fetch_page_get( build_album_search_url( artist, album, year ) )
|
|
1322
|
+
return nil if response == nil || response.body() == nil
|
|
1323
|
+
parse_search_results( response.body(), true ).each() do |result|
|
|
1324
|
+
normalized_result = result[@@SEARCH_RESULT_TITLE].split( ":" ).each() do |token|
|
|
1325
|
+
Strings.normalize!( token )
|
|
1326
|
+
end.join( ":" )
|
|
1327
|
+
return result[@@SEARCH_RESULT_URL] if normalized_target == normalized_result
|
|
1328
|
+
end
|
|
1329
|
+
return nil
|
|
1330
|
+
end
|
|
1331
|
+
|
|
1332
|
+
end
|
|
1333
|
+
|
|
1334
|
+
def find_album_page_url( artist, album, year )
|
|
1335
|
+
return self.class.find_album_page_url( artist, album, year )
|
|
1336
|
+
end
|
|
1337
|
+
|
|
1338
|
+
|
|
1339
|
+
# ALBUM ART FUNCTIONS
|
|
1340
|
+
|
|
1341
|
+
def build_album_art_name( artist, album, year, extension="jpg", cleanup=true )
|
|
1342
|
+
return self.class.build_album_art_name( artist, album, year, extension, cleanup )
|
|
1343
|
+
end
|
|
1344
|
+
|
|
1345
|
+
def build_album_art_description( artist, album, year, cleanup=true )
|
|
1346
|
+
return self.class.build_album_art_description( artist, album, year, cleanup )
|
|
1347
|
+
end
|
|
1348
|
+
|
|
1349
|
+
def find_album_art_name( artist, album, year )
|
|
1350
|
+
return self.class.find_album_art_name( artist, album, year )
|
|
1351
|
+
end
|
|
1352
|
+
|
|
1353
|
+
def MediaWikiLyrics.find_album_art_url( artist, album, year )
|
|
1354
|
+
if album_art_name = find_album_art_name( artist, album, year )
|
|
1355
|
+
album_art_name.gsub!( " ", "_" )
|
|
1356
|
+
return "http://#{site_host()}/index.php?title=Image:#{CGI.escape(album_art_name)}"
|
|
1357
|
+
else
|
|
1358
|
+
return nil
|
|
1359
|
+
end
|
|
1360
|
+
end
|
|
1361
|
+
|
|
1362
|
+
def find_album_art_url( artist, album, year )
|
|
1363
|
+
return self.class.find_album_art_url( artist, album, year )
|
|
1364
|
+
end
|
|
1365
|
+
|
|
1366
|
+
|
|
1367
|
+
# DATE FUNCTIONS
|
|
1368
|
+
|
|
1369
|
+
@@months = [
|
|
1370
|
+
"JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY",
|
|
1371
|
+
"AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"
|
|
1372
|
+
]
|
|
1373
|
+
|
|
1374
|
+
def MediaWikiLyrics.parse_date( date )
|
|
1375
|
+
|
|
1376
|
+
day, month, year = nil, nil, nil
|
|
1377
|
+
|
|
1378
|
+
if (md = /^(#{@@months.join( "|" )})( \d\d?|), (\d\d\d\d)$/i.match( date ))
|
|
1379
|
+
month, day, year = @@months.index( Strings.upcase( md[1] ) ) + 1, md[2].strip().to_i(), md[3].to_i()
|
|
1380
|
+
elsif (md = /^(\d\d? |)(#{@@months.join( "|" )}) (\d\d\d\d)$/i.match( date ))
|
|
1381
|
+
day, month, year = md[1].strip().to_i(), @@months.index( Strings.upcase( md[2] ) ) + 1, md[3].to_i()
|
|
1382
|
+
elsif /^(\d\d\d\d)-(\d\d)-(\d\d)$/.match( date )
|
|
1383
|
+
year, month, day = md[1].to_i(), md[2].to_i(), md[3].to_i()
|
|
1384
|
+
elsif (md = /^(\d\d\d\d)$/.match( date ))
|
|
1385
|
+
year = md[1].to_i()
|
|
1386
|
+
end
|
|
1387
|
+
|
|
1388
|
+
year = nil if year == 0
|
|
1389
|
+
month = nil if month == 0
|
|
1390
|
+
day = nil if day == 0
|
|
1391
|
+
|
|
1392
|
+
return year, month, day
|
|
1393
|
+
|
|
1394
|
+
end
|
|
1395
|
+
|
|
1396
|
+
def MediaWikiLyrics.build_date( year, month, day )
|
|
1397
|
+
|
|
1398
|
+
year, month, day = year.to_i(), month.to_i(), day.to_i()
|
|
1399
|
+
|
|
1400
|
+
if month != 0
|
|
1401
|
+
month = @@months[month-1].to_s()
|
|
1402
|
+
month = month.slice( 0..0 ).upcase() + month.slice( 1..-1 ).downcase()
|
|
1403
|
+
end
|
|
1404
|
+
|
|
1405
|
+
if day != 0 && month != 0 && year != 0
|
|
1406
|
+
return "#{month} #{day}, #{year}"
|
|
1407
|
+
elsif month != 0 && year != 0
|
|
1408
|
+
return "#{month}, #{year}"
|
|
1409
|
+
elsif year != 0
|
|
1410
|
+
return year.to_s()
|
|
1411
|
+
else
|
|
1412
|
+
return ""
|
|
1413
|
+
end
|
|
1414
|
+
|
|
1415
|
+
end
|
|
1416
|
+
|
|
1417
|
+
end
|