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,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ITRANS software
|
|
3
|
+
*==========================================================================
|
|
4
|
+
* Copyright 1991--2001 Avinash Chopde, All Rights Reserved.
|
|
5
|
+
*
|
|
6
|
+
* Permission to use, copy, modify and distribute this software and its
|
|
7
|
+
* documentation for any purpose is hereby granted without fee, provided that
|
|
8
|
+
* the above copyright notice appear in all copies and that both that
|
|
9
|
+
* copyright notice and this permission notice appear in supporting
|
|
10
|
+
* documentation, and that the name of Avinash Chopde not be used in
|
|
11
|
+
* advertising or publicity pertaining to distribution of the software
|
|
12
|
+
* without specific, written prior permission.
|
|
13
|
+
* Avinash Chopde makes no representations about the suitability of this
|
|
14
|
+
* software for any purpose.
|
|
15
|
+
* It is provided "as is" without express or implied warranty.
|
|
16
|
+
*
|
|
17
|
+
* AVINASH CHOPDE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
18
|
+
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
|
|
19
|
+
* IN NO EVENT SHALL AVINASH CHOPDE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
20
|
+
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
21
|
+
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
22
|
+
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
23
|
+
* OF THIS SOFTWARE.
|
|
24
|
+
*
|
|
25
|
+
* Author: Avinash Chopde
|
|
26
|
+
* e-mail: avinash@acm.org
|
|
27
|
+
* home page: http://www.aczone.com/itrans/
|
|
28
|
+
*
|
|
29
|
+
If this package contains any other copyrighted material, the appropriate
|
|
30
|
+
notice has been included in such units.
|
|
31
|
+
*/
|
|
Binary file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#indianifm=udvng.ifm
|
|
2
|
+
#indian
|
|
3
|
+
%
|
|
4
|
+
##baby baby baby baby baby baby##
|
|
5
|
+
shaa naa naa
|
|
6
|
+
sun baabaa sun baabaa dil kaa kyaa kahanaa
|
|
7
|
+
shaa naa naa \threedots
|
|
8
|
+
|
|
9
|
+
##reason## hai kuchh gul khilaa naa
|
|
10
|
+
##season## bhii hai aashiqaanaa
|
|
11
|
+
haay aise me.n dil diivaanaa bas me.n kahaa.N
|
|
12
|
+
##take it easy, baby##
|
|
13
|
+
aavaaraa cha.nchal havaa_o.n pe chhaa_ii hai.n madahoshiyaa.N
|
|
14
|
+
aise me.n ko_ii jo kho jaa_e ho jaa_e.n dil kii choriyaa.n
|
|
15
|
+
shaa naa naa \threedots
|
|
16
|
+
|
|
17
|
+
milatii hai.n nazaro.n se jab nazare.n
|
|
18
|
+
hotaa hai dil pe asar
|
|
19
|
+
haa.n mil jaa_e dil se agar dil
|
|
20
|
+
to milate hai.n do hamasafar
|
|
21
|
+
shaa naa naa \threedots
|
|
22
|
+
%
|
|
23
|
+
#endindian
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
Comment * ITRANS IFM file for Unicode Output
|
|
2
|
+
Comment *===================================================================
|
|
3
|
+
Comment * Copyright 2001 Avinash Chopde, All Rights Reserved.
|
|
4
|
+
Comment *
|
|
5
|
+
Comment * Author: Avinash Chopde <avinash@acm.org> http://www.aczone.com/
|
|
6
|
+
Comment ===================================================================
|
|
7
|
+
% ------------- Instructions for Creating ITRANS IFM files for Unicode
|
|
8
|
+
% The following page has Unicode ranges for all languages, and
|
|
9
|
+
% includes both Decimal and Hexadecimal values:
|
|
10
|
+
% http://www.hclrss.demon.co.uk/unicode/devanagari.html
|
|
11
|
+
% For ITRANS tables, visit the online documents at:
|
|
12
|
+
% http://www.aczone.com/itrans/#onlinedocs
|
|
13
|
+
%
|
|
14
|
+
% The PCC <charcode> ... statements below accept either Decimal or
|
|
15
|
+
% Hexadecimal, so both of these are identical:
|
|
16
|
+
% PCC 2309 0 0 ;
|
|
17
|
+
% is same as:
|
|
18
|
+
% PCC 0x0905 0 0 ;
|
|
19
|
+
% [note: hex numbers must be preceed with "0x", decimal numbers must not
|
|
20
|
+
% have leading 0's - leading 0's imply that the number is octal]
|
|
21
|
+
% -------------
|
|
22
|
+
Comment ===================================================================
|
|
23
|
+
|
|
24
|
+
itrans: StartINDIAN
|
|
25
|
+
itrans: TEXT_UNICODE sanskrit
|
|
26
|
+
itrans: DEFAULTVOWEL a ;
|
|
27
|
+
|
|
28
|
+
% These are in Unicode, but not used by ITRANS:
|
|
29
|
+
% 2317 090D DEVANAGARI LETTER CANDRA E
|
|
30
|
+
% 2318 090E DEVANAGARI LETTER SHORT E
|
|
31
|
+
% 2321 0911 DEVANAGARI LETTER CANDRA O
|
|
32
|
+
% 2322 0912 DEVANAGARI LETTER SHORT O
|
|
33
|
+
% 2356 0934 DEVANAGARI LETTER LLLA (lda-dot)
|
|
34
|
+
% danda, double danda, nukta, udatta, anudatta, abbreviation sign
|
|
35
|
+
|
|
36
|
+
itrans: Comment The Vowels - Independent Vowels in Unicode
|
|
37
|
+
|
|
38
|
+
itrans: CC a 1 ; PCC 2309 0 0 ;
|
|
39
|
+
itrans: CC aa 1 ; PCC 2310 0 0 ;
|
|
40
|
+
itrans: CC i 1 ; PCC 2311 0 0 ;
|
|
41
|
+
itrans: CC ii 1 ; PCC 2312 0 0 ;
|
|
42
|
+
itrans: CC u 1 ; PCC 2313 0 0 ;
|
|
43
|
+
itrans: CC uu 1 ; PCC 2314 0 0 ;
|
|
44
|
+
itrans: CC ri 1 ; PCC 2315 0 0 ;
|
|
45
|
+
itrans: CC rii 1 ; PCC 2400 0 0 ;
|
|
46
|
+
itrans: CC li 1 ; PCC 2316 0 0 ;
|
|
47
|
+
itrans: CC lii 1 ; PCC 2401 0 0 ;
|
|
48
|
+
itrans: CC ay 1 ; PCC 2319 0 0 ;
|
|
49
|
+
% itrans: CC aay 1 ; % Telugu, etc only ( E ) ?
|
|
50
|
+
itrans: CC aay 1 ; PCC 2319 0 0 ;
|
|
51
|
+
itrans: CC ai 1 ; PCC 2320 0 0 ;
|
|
52
|
+
itrans: CC o 1 ; PCC 2323 0 0 ;
|
|
53
|
+
% itrans: CC oo 1 ; % Telugu, etc only ( O ) ?
|
|
54
|
+
itrans: CC oo 1 ; PCC 2323 0 0 ;
|
|
55
|
+
itrans: CC au 1 ; PCC 2324 0 0 ;
|
|
56
|
+
itrans: CC am 2 ; PCC 2309 0 0 ; PCC 2306 0 0 ;
|
|
57
|
+
itrans: CC aha 1 ; PCC 2307 0 0 ; % just visarga
|
|
58
|
+
|
|
59
|
+
itrans: Comment The Template - use Dependent Vowels as defined in Unicode
|
|
60
|
+
|
|
61
|
+
itrans: CCADD tmplA ;
|
|
62
|
+
itrans: CC tmplA-half 2 ; PCC implicit 0 0 ; PCC 2381 0 0 ;
|
|
63
|
+
itrans: CC tmplA-conjunct 2 ; PCC implicit 0 0 ; PCC 2381 0 0 ;
|
|
64
|
+
itrans: CC tmplA-a 1 ; PCC implicit 0 0 ;
|
|
65
|
+
itrans: CC tmplA-aa 2 ; PCC implicit 0 0 ; PCC 2366 0 0 ;
|
|
66
|
+
itrans: CC tmplA-i 2 ; PCC implicit 0 0 ; PCC 2367 0 0 ;
|
|
67
|
+
itrans: CC tmplA-ii 2 ; PCC implicit 0 0 ; PCC 2368 0 0 ;
|
|
68
|
+
itrans: CC tmplA-u 2 ; PCC implicit 0 0 ; PCC 2369 0 0 ;
|
|
69
|
+
itrans: CC tmplA-uu 2 ; PCC implicit 0 0 ; PCC 2370 0 0 ;
|
|
70
|
+
itrans: CC tmplA-ri 2 ; PCC implicit 0 0 ; PCC 2371 0 0 ;
|
|
71
|
+
itrans: CC tmplA-rii 2 ; PCC implicit 0 0 ; PCC 2372 0 0 ;
|
|
72
|
+
itrans: CC tmplA-li 2 ; PCC implicit 0 0 ; PCC 2402 0 0 ;
|
|
73
|
+
itrans: CC tmplA-lii 2 ; PCC implicit 0 0 ; PCC 2403 0 0 ;
|
|
74
|
+
itrans: CC tmplA-ay 2 ; PCC implicit 0 0 ; PCC 2375 0 0 ;
|
|
75
|
+
itrans: CC tmplA-aay 2 ; PCC implicit 0 0 ; PCC 2375 0 0 ;
|
|
76
|
+
itrans: CC tmplA-ai 2 ; PCC implicit 0 0 ; PCC 2376 0 0 ;
|
|
77
|
+
itrans: CC tmplA-o 2 ; PCC implicit 0 0 ; PCC 2379 0 0 ;
|
|
78
|
+
itrans: CC tmplA-oo 2 ; PCC implicit 0 0 ; PCC 2379 0 0 ;
|
|
79
|
+
itrans: CC tmplA-au 2 ; PCC implicit 0 0 ; PCC 2380 0 0 ;
|
|
80
|
+
itrans: CC tmplA-am 2 ; PCC implicit 0 0 ; PCC 2306 0 0 ;
|
|
81
|
+
itrans: CC tmplA-aha 2 ; PCC implicit 0 0 ; PCC 2307 0 0 ;
|
|
82
|
+
|
|
83
|
+
itrans: Comment The Consonants - in Unicode, all are full consonants
|
|
84
|
+
|
|
85
|
+
itrans: CCS ka tmplA ;
|
|
86
|
+
itrans: CC ka-implicit 1 ; PCC 2325 0 0 ;
|
|
87
|
+
itrans: CCS kadot ka ;
|
|
88
|
+
itrans: CC kadot-implicit 1 ; PCC 2392 0 0 ;
|
|
89
|
+
itrans: CCS kha tmplA ;
|
|
90
|
+
itrans: CC kha-implicit 1 ; PCC 2326 0 0 ;
|
|
91
|
+
itrans: CCS khadot kha ;
|
|
92
|
+
itrans: CC khadot-implicit 1 ; PCC 2393 0 0 ;
|
|
93
|
+
itrans: CCS ga tmplA ;
|
|
94
|
+
itrans: CC ga-implicit 1 ; PCC 2327 0 0 ;
|
|
95
|
+
itrans: CCS gadot ga ;
|
|
96
|
+
itrans: CC gadot-implicit 1 ; PCC 2394 0 0 ;
|
|
97
|
+
itrans: CCS gha tmplA ;
|
|
98
|
+
itrans: CC gha-implicit 1 ; PCC 2328 0 0 ;
|
|
99
|
+
itrans: CCS nga tmplA ;
|
|
100
|
+
itrans: CC nga-implicit 1 ; PCC 2329 0 0 ;
|
|
101
|
+
itrans: CCS cha tmplA ;
|
|
102
|
+
itrans: CC cha-implicit 1 ; PCC 2330 0 0 ;
|
|
103
|
+
itrans: CCS chha tmplA ;
|
|
104
|
+
itrans: CC chha-implicit 1 ; PCC 2331 0 0 ;
|
|
105
|
+
itrans: CCS ja tmplA ;
|
|
106
|
+
itrans: CC ja-implicit 1 ; PCC 2332 0 0 ;
|
|
107
|
+
itrans: CCS jadot ja ;
|
|
108
|
+
itrans: CC jadot-implicit 1 ; PCC 2395 0 0 ;
|
|
109
|
+
itrans: CCS jha tmplA ;
|
|
110
|
+
itrans: CC jha-implicit 1 ; PCC 2333 0 0 ;
|
|
111
|
+
itrans: CCS jnh tmplA ;
|
|
112
|
+
itrans: CC jnh-implicit 1 ; PCC 2334 0 0 ;
|
|
113
|
+
itrans: CCS tta tmplA ;
|
|
114
|
+
itrans: CC tta-implicit 1 ; PCC 2335 0 0 ;
|
|
115
|
+
itrans: CCS ttha tmplA ;
|
|
116
|
+
itrans: CC ttha-implicit 1 ; PCC 2336 0 0 ;
|
|
117
|
+
itrans: CCS dda tmplA ;
|
|
118
|
+
itrans: CC dda-implicit 1 ; PCC 2337 0 0 ;
|
|
119
|
+
itrans: CCS ddadot tmplA ;
|
|
120
|
+
itrans: CC ddadot-implicit 1 ; PCC 2396 0 0 ;
|
|
121
|
+
itrans: CCS ddha tmplA ;
|
|
122
|
+
itrans: CC ddha-implicit 1 ; PCC 2338 0 0 ;
|
|
123
|
+
itrans: CCS ddhadot ddadot ;
|
|
124
|
+
itrans: CC ddhadot-implicit 1 ; PCC 2397 0 0 ;
|
|
125
|
+
itrans: CCS nna tmplA ;
|
|
126
|
+
itrans: CC nna-implicit 1 ; PCC 2339 0 0 ;
|
|
127
|
+
itrans: CCS ta tmplA ;
|
|
128
|
+
itrans: CC ta-implicit 1 ; PCC 2340 0 0 ;
|
|
129
|
+
itrans: CCS tha tmplA ;
|
|
130
|
+
itrans: CC tha-implicit 1 ; PCC 2341 0 0 ;
|
|
131
|
+
itrans: CCS da tmplA;
|
|
132
|
+
itrans: CC da-implicit 1 ; PCC 2342 0 0 ;
|
|
133
|
+
itrans: CCS dha tmplA ;
|
|
134
|
+
itrans: CC dha-implicit 1 ; PCC 2343 0 0 ;
|
|
135
|
+
itrans: CCS na tmplA ;
|
|
136
|
+
itrans: CC na-implicit 1 ; PCC 2344 0 0 ;
|
|
137
|
+
itrans: CCS nnx tmplA ; % Tamil, etc only? ( ^n )
|
|
138
|
+
itrans: CC nnx-implicit 1 ; PCC 2345 0 0 ; % Devanagari: used as na-dot NNNA
|
|
139
|
+
itrans: CCS pa tmplA ;
|
|
140
|
+
itrans: CC pa-implicit 1 ; PCC 2346 0 0 ;
|
|
141
|
+
itrans: CCS pha tmplA ;
|
|
142
|
+
itrans: CC pha-implicit 1 ; PCC 2347 0 0 ;
|
|
143
|
+
itrans: CCS phadot pha ;
|
|
144
|
+
itrans: CC phadot-implicit 1 ; PCC 2398 0 0 ;
|
|
145
|
+
itrans: CCS ba tmplA ;
|
|
146
|
+
itrans: CC ba-implicit 1 ; PCC 2348 0 0 ;
|
|
147
|
+
itrans: CCS bha tmplA ;
|
|
148
|
+
itrans: CC bha-implicit 1 ; PCC 2349 0 0 ;
|
|
149
|
+
itrans: CCS ma tmplA ;
|
|
150
|
+
itrans: CC ma-implicit 1 ; PCC 2350 0 0 ;
|
|
151
|
+
itrans: CCS ya tmplA ;
|
|
152
|
+
itrans: CC ya-implicit 1 ; PCC 2351 0 0 ;
|
|
153
|
+
itrans: CCS yya tmplA ; % Devanagari: used as ya-dot
|
|
154
|
+
itrans: CC yya-implicit 1 ; PCC 2399 0 0 ;
|
|
155
|
+
itrans: CCS ra tmplA ;
|
|
156
|
+
itrans: CC ra-implicit 1 ; PCC 2352 0 0 ;
|
|
157
|
+
itrans: CCS rra tmplA ;
|
|
158
|
+
itrans: CC rra-implicit 1 ; PCC 2353 0 0 ; % RRA ra-dot
|
|
159
|
+
itrans: CCS la tmplA ;
|
|
160
|
+
itrans: CC la-implicit 1 ; PCC 2354 0 0 ;
|
|
161
|
+
itrans: CCS va tmplA ;
|
|
162
|
+
itrans: CC va-implicit 1 ; PCC 2357 0 0 ;
|
|
163
|
+
itrans: CCS sha tmplA ;
|
|
164
|
+
itrans: CC sha-implicit 1 ; PCC 2358 0 0 ;
|
|
165
|
+
itrans: CCS shha tmplA ;
|
|
166
|
+
itrans: CC shha-implicit 1 ; PCC 2359 0 0 ;
|
|
167
|
+
itrans: CCS sa tmplA ;
|
|
168
|
+
itrans: CC sa-implicit 1 ; PCC 2360 0 0 ;
|
|
169
|
+
itrans: CCS ha tmplA ;
|
|
170
|
+
itrans: CC ha-implicit 1 ; PCC 2361 0 0 ;
|
|
171
|
+
itrans: CCS lda tmplA ;
|
|
172
|
+
itrans: CC lda-implicit 1 ; PCC 2355 0 0 ;
|
|
173
|
+
itrans: CCS ksha tmplA ; % ka-shha
|
|
174
|
+
itrans: CC ksha-implicit 3 ; PCC 2325 0 0 ; PCC 2381 0 0 ; PCC 2359 0 0 ;
|
|
175
|
+
itrans: CCS gya tmplA ; % ja-jnh Unicode JA-NYA
|
|
176
|
+
itrans: CC gya-implicit 3 ; PCC 2332 0 0 ; PCC 2381 0 0 ; PCC 2334 0 0 ;
|
|
177
|
+
|
|
178
|
+
itrans: Comment The Specials (Incomplete support in ITRANS)
|
|
179
|
+
|
|
180
|
+
itrans: CC anusvara-implicit 1 ; PCC 2306 0 0 ;
|
|
181
|
+
itrans: CC chandra-implicit 1 ; PCC 2373 0 0 ; % 2373=CANDRA E, 2374=SHORT E
|
|
182
|
+
itrans: CC chandrabindu-implicit 1 ; PCC 2305 0 0 ;
|
|
183
|
+
itrans: CC aum-implicit 1 ; PCC 2384 0 0 ;
|
|
184
|
+
itrans: CC viraam-implicit 1 ; PCC 2381 0 0 ;
|
|
185
|
+
itrans: CC avagraha-implicit 1 ; PCC 2365 0 0 ;
|
|
186
|
+
% itrans: CC sri-implicit 1 ; PCC 244 0 0 ; % Tamil only?
|
|
187
|
+
|
|
188
|
+
% rahalf ( ^r or .r ) is a hack that was used in ITRANS, for the
|
|
189
|
+
% half-chandra-ra superscript, it would be very tricky to have it supported
|
|
190
|
+
% here, the best option is to avoid rahalf in the input. Use normal ra instead,
|
|
191
|
+
% i.e, instead of ga.r use rga in the input.
|
|
192
|
+
itrans: CC rahalf-implicit 2 ; PCC 2352 0 0 ; PCC 2381 0 0 ; % Devanagari only?
|
|
193
|
+
|
|
194
|
+
itrans: Comment ----------- Digits
|
|
195
|
+
itrans: CC zero 1 ; PCC 2406 0 0 ;
|
|
196
|
+
itrans: CC one 1 ; PCC 2407 0 0 ;
|
|
197
|
+
itrans: CC two 1 ; PCC 2408 0 0 ;
|
|
198
|
+
itrans: CC three 1 ; PCC 2409 0 0 ;
|
|
199
|
+
itrans: CC four 1 ; PCC 2410 0 0 ;
|
|
200
|
+
itrans: CC five 1 ; PCC 2411 0 0 ;
|
|
201
|
+
itrans: CC six 1 ; PCC 2412 0 0 ;
|
|
202
|
+
itrans: CC seven 1 ; PCC 2413 0 0 ;
|
|
203
|
+
itrans: CC eight 1 ; PCC 2414 0 0 ;
|
|
204
|
+
itrans: CC nine 1 ; PCC 2415 0 0 ;
|
|
205
|
+
|
|
206
|
+
itrans: EndINDIAN
|
|
@@ -0,0 +1,567 @@
|
|
|
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/logger"
|
|
22
|
+
require "utils/strings"
|
|
23
|
+
require "utils/http"
|
|
24
|
+
|
|
25
|
+
$VERBOSE_LOG = false
|
|
26
|
+
|
|
27
|
+
def debug( message )
|
|
28
|
+
system( "kdialog", "--msgbox", "<qt>" + message.to_s().gsub( "\n", "<br />" ) + "</qt>" )
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Lyrics
|
|
32
|
+
|
|
33
|
+
class Request
|
|
34
|
+
|
|
35
|
+
attr_reader :artist, :title, :album, :year, :fetch_data
|
|
36
|
+
attr_writer :fetch_data
|
|
37
|
+
|
|
38
|
+
def initialize( artist, title, album=nil, year=nil )
|
|
39
|
+
raise "target artist and title values can't be nil" if ! artist || ! title
|
|
40
|
+
@artist = artist.clone().freeze()
|
|
41
|
+
@title = title.clone().freeze()
|
|
42
|
+
@album = album ? album.clone().freeze() : nil
|
|
43
|
+
@year = year ? year.to_s().strip().to_i() : nil
|
|
44
|
+
@fetch_data = nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def to_s()
|
|
48
|
+
ret = " - request artist: #{@artist}\n - request title: #{@title}"
|
|
49
|
+
ret << "\n - request album: #{@album}" if @album
|
|
50
|
+
ret << "\n - request year: #{@year}" if @year
|
|
51
|
+
return ret
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class Response
|
|
57
|
+
|
|
58
|
+
attr_reader :request, :artist, :title, :album, :year, :lyrics, :url, :custom_data #, :suggestions
|
|
59
|
+
attr_writer :url
|
|
60
|
+
|
|
61
|
+
def initialize( request )
|
|
62
|
+
raise "request can't be nil" if ! request
|
|
63
|
+
@request = request
|
|
64
|
+
@artist = nil
|
|
65
|
+
@title = nil
|
|
66
|
+
@album = nil
|
|
67
|
+
@year = nil
|
|
68
|
+
@lyrics = nil
|
|
69
|
+
@custom_data = {}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def to_s()
|
|
73
|
+
ret = ""
|
|
74
|
+
ret << "\n - response artist: #{@artist}" if @artist
|
|
75
|
+
ret << "\n - response title: #{@title}" if @title
|
|
76
|
+
ret << "\n - response album: #{@album}" if @album
|
|
77
|
+
ret << "\n - response year: #{@year}" if @year
|
|
78
|
+
if @custom_data.size > 0
|
|
79
|
+
ret << "\n - response custom data:"
|
|
80
|
+
@custom_data.each { |key, val| ret << "\n - #{key}: #{val}" }
|
|
81
|
+
end
|
|
82
|
+
return ret.size > 0 ? ret.slice( 1..-1 ) : ret
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def each_modified!()
|
|
86
|
+
yield "artist", @artist if artist_modified?()
|
|
87
|
+
yield "title", @title if title_modified?()
|
|
88
|
+
yield "album", @album if album_modified?()
|
|
89
|
+
yield "year", @year if year_modified?()
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def each_modified()
|
|
93
|
+
each_modified!() { |k, v| yield k, v.clone() }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def artist_modified?()
|
|
97
|
+
return @artist && @artist != request.artist
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def artist=( artist )
|
|
101
|
+
@artist = artist ? artist.to_s().strip().freeze() : nil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def title_modified?()
|
|
105
|
+
return @title && @title != request.title
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def title=( title )
|
|
109
|
+
@title = title ? title.to_s().strip().freeze() : nil
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def album_modified?()
|
|
113
|
+
return @album && @album != request.album
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def album=( album )
|
|
117
|
+
@album = album ? album.to_s().strip().freeze() : nil
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def year_modified?()
|
|
121
|
+
return @year && @year != request.year
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def year=( year )
|
|
125
|
+
if year
|
|
126
|
+
year = year.to_s().strip().to_i()
|
|
127
|
+
if year > 1900
|
|
128
|
+
@year = year
|
|
129
|
+
else
|
|
130
|
+
@year = nil
|
|
131
|
+
end
|
|
132
|
+
else
|
|
133
|
+
@year = nil
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def lyrics=( lyrics )
|
|
138
|
+
@lyrics = Strings.decode_htmlentities!( lyrics.to_s() ).strip().freeze()
|
|
139
|
+
@lyrics = nil if @lyrics.empty?
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def custom_data=( custom_data )
|
|
143
|
+
raise "custom_data value must be a hash" if ! custom_data.is_a?( Hash )
|
|
144
|
+
@custom_data = {}
|
|
145
|
+
custom_data.each() { |k, v| @custom_data[k] = v.is_a?( String ) ? v.clone().freeze() : v }
|
|
146
|
+
@custom_data.freeze()
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
class Suggestion
|
|
152
|
+
|
|
153
|
+
attr_reader :url, :artist, :title
|
|
154
|
+
|
|
155
|
+
def initialize( artist, title, url )
|
|
156
|
+
@artist = artist.clone().freeze()
|
|
157
|
+
@title = title.clone().freeze()
|
|
158
|
+
@url = url.clone.freeze()
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def to_s()
|
|
162
|
+
return "art: #{artist} | tit: #{title} | url: #{url}"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
class FetchPageData
|
|
168
|
+
|
|
169
|
+
attr_reader :url, :post_data, :headers_data
|
|
170
|
+
|
|
171
|
+
def initialize( url, post_data=nil, headers_data=nil )
|
|
172
|
+
@url = url.freeze()
|
|
173
|
+
if post_data && post_data.size > 0
|
|
174
|
+
@post_data = post_data.clone().freeze()
|
|
175
|
+
@post_data.each() do |key|
|
|
176
|
+
@post_data[key] = @post_data[key].clone().freeze() if @post_data[key]
|
|
177
|
+
end
|
|
178
|
+
else
|
|
179
|
+
@post_data = nil
|
|
180
|
+
end
|
|
181
|
+
if headers_data && headers_data.size > 0
|
|
182
|
+
@headers_data = headers_data.clone().freeze()
|
|
183
|
+
@headers_data.each() do |key|
|
|
184
|
+
@headers_data[key] = @headers_data[key].clone().freeze() if @headers_data[key]
|
|
185
|
+
end
|
|
186
|
+
else
|
|
187
|
+
@headers_data = nil
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def to_s()
|
|
192
|
+
ret = " - fetch url: #{@url}"
|
|
193
|
+
if @post_data
|
|
194
|
+
ret << "\n - fetch post data:"
|
|
195
|
+
@post_data.each { |key, val| ret << "\n - #{key}: #{val}" }
|
|
196
|
+
end
|
|
197
|
+
if @headers_data
|
|
198
|
+
ret << "\n - fetch headers data:"
|
|
199
|
+
@headers_data.each { |key, val| ret << "\n - #{key}: #{val}" }
|
|
200
|
+
end
|
|
201
|
+
return ret
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
attr_reader :cleanup_lyrics
|
|
207
|
+
attr_writer :cleanup_lyrics
|
|
208
|
+
|
|
209
|
+
def initialize( cleanup_lyrics=true, logger=nil )
|
|
210
|
+
super()
|
|
211
|
+
@cleanup_lyrics = cleanup_lyrics
|
|
212
|
+
@logger = logger
|
|
213
|
+
@tabulation = nil
|
|
214
|
+
@skip_tabulation = false
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def log?()
|
|
218
|
+
return @logger != nil
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def verbose_log?()
|
|
222
|
+
return log? && $VERBOSE_LOG
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def logger=( logger )
|
|
226
|
+
@logger = logger
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def log( message, new_lines=1 )
|
|
230
|
+
@logger.log( message, new_lines ) if @logger
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def increase_tabulation_level()
|
|
234
|
+
@logger.increase_tabulation_level() if @logger
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def decrease_tabulation_level()
|
|
238
|
+
@logger.decrease_tabulation_level() if @logger
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def site_host()
|
|
242
|
+
return self.class.site_host()
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def site_name()
|
|
246
|
+
return self.class.site_name()
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def Lyrics.build_song_add_url( request )
|
|
250
|
+
return nil
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def build_song_add_url( request )
|
|
254
|
+
return self.class.build_song_add_url( request )
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def Lyrics.known_url?( url )
|
|
258
|
+
return url.index( "http://#{site_host}" ) == 0
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def known_url?( url )
|
|
262
|
+
return self.class.known_url?( url )
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def notify( message )
|
|
266
|
+
puts "#{site_name()}: #{message}"
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Returns a FetchPageData instance
|
|
270
|
+
def build_lyrics_fetch_data( request )
|
|
271
|
+
return FetchPageData.new( nil )
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Returns the lyrics page body (or nil if it couldn't be retrieved) and the corresponding url (or nil)
|
|
275
|
+
def fetch_lyrics_page( fetch_data )
|
|
276
|
+
|
|
277
|
+
return nil, nil if ! fetch_data.url
|
|
278
|
+
|
|
279
|
+
log( "Fetching lyrics page... ", 0 )
|
|
280
|
+
if fetch_data.post_data
|
|
281
|
+
response, url = HTTP.fetch_page_post( fetch_data.url, fetch_data.post_data, fetch_data.headers_data )
|
|
282
|
+
else
|
|
283
|
+
response, url = HTTP.fetch_page_get( fetch_data.url, fetch_data.headers_data )
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
if response && response.body()
|
|
287
|
+
log( "OK" )
|
|
288
|
+
log( response.body(), 2 ) if verbose_log?
|
|
289
|
+
return response.body(), url
|
|
290
|
+
else
|
|
291
|
+
log( "ERROR" )
|
|
292
|
+
return nil, url
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# NOTE: override for example if your using google feeling lucky to verify that
|
|
298
|
+
# the resulting page is not just some random (trashy) result.
|
|
299
|
+
# Returns false is page_body does not correspond to the requested lyrics
|
|
300
|
+
def lyrics_page_valid?( request, page_body, page_url )
|
|
301
|
+
return true
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# NOTE: implement in subclasses
|
|
305
|
+
# Must fill the relevante response properties (lyrics, [artist, title, album, year, custom_data])
|
|
306
|
+
# def parse_lyrics( response, page_body )
|
|
307
|
+
# end
|
|
308
|
+
|
|
309
|
+
# Returns a Lyrics::Response object
|
|
310
|
+
def lyrics_direct_search( request )
|
|
311
|
+
|
|
312
|
+
fetch_data = build_lyrics_fetch_data( request )
|
|
313
|
+
|
|
314
|
+
log(
|
|
315
|
+
site_name().upcase() + "\n" +
|
|
316
|
+
"Attempting LYRICS DIRECT SEARCH...\n" +
|
|
317
|
+
request.to_s() + "\n" +
|
|
318
|
+
fetch_data.to_s()
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
page_body, page_url = fetch_lyrics_page( fetch_data )
|
|
322
|
+
|
|
323
|
+
response = Response.new( request )
|
|
324
|
+
|
|
325
|
+
if page_body
|
|
326
|
+
if lyrics_page_valid?( request, page_body, page_url )
|
|
327
|
+
log( "Parsing lyrics... ", 0 )
|
|
328
|
+
response.url = page_url
|
|
329
|
+
parse_lyrics( response, page_body )
|
|
330
|
+
log( response.lyrics ? "LYRICS FOUND" : "LYRICS NOT FOUND" )
|
|
331
|
+
log( response.to_s() )
|
|
332
|
+
log( " - parsed lyrics:\n[#{lyrics_data.lyrics}" ) if verbose_log?
|
|
333
|
+
response.lyrics = Strings.cleanup_lyrics( response.lyrics ) if response.lyrics && @cleanup_lyrics
|
|
334
|
+
else
|
|
335
|
+
log( "LYRICS PAGE IS INVALID" )
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
return response
|
|
340
|
+
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# Returns a Lyrics::Response object
|
|
344
|
+
def lyrics_from_url( request, url )
|
|
345
|
+
|
|
346
|
+
response = Response.new( request )
|
|
347
|
+
|
|
348
|
+
if ! known_url?( url )
|
|
349
|
+
log( site_name().upcase() + "\nCan't handle received URL: " + url )
|
|
350
|
+
return response
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
fetch_data = build_lyrics_fetch_data( request )
|
|
354
|
+
fetch_data = FetchPageData.new( url, fetch_data.post_data, fetch_data.headers_data )
|
|
355
|
+
|
|
356
|
+
log(
|
|
357
|
+
site_name().upcase() + "\n" +
|
|
358
|
+
"Retrieving LYRICS FROM URL...\n" +
|
|
359
|
+
request.to_s() + "\n" +
|
|
360
|
+
fetch_data.to_s()
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
page_body, url = fetch_lyrics_page( fetch_data )
|
|
364
|
+
|
|
365
|
+
if page_body
|
|
366
|
+
log( "Parsing lyrics... ", 0 )
|
|
367
|
+
response.url = url
|
|
368
|
+
parse_lyrics( response, page_body )
|
|
369
|
+
log( response.lyrics ? "LYRICS FOUND" : "LYRICS NOT FOUND" )
|
|
370
|
+
log( response.to_s() )
|
|
371
|
+
log( " - parsed lyrics:\n[#{lyrics_data.lyrics}]" ) if verbose_log?
|
|
372
|
+
response.lyrics = Strings.cleanup_lyrics( response.lyrics ) if response.lyrics && @cleanup_lyrics
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
return response
|
|
376
|
+
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# Returns a FetchPageData instance
|
|
380
|
+
def build_suggestions_fetch_data( request )
|
|
381
|
+
return FetchPageData.new( nil )
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# Returns the lyrics page body (nil if it couldn't be retrieved) and the response url
|
|
385
|
+
def fetch_suggestions_page( fetch_data )
|
|
386
|
+
|
|
387
|
+
return nil, nil if ! fetch_data.url
|
|
388
|
+
|
|
389
|
+
log( fetch_data.to_s() + "\nFetching suggestions page... ", 0 )
|
|
390
|
+
|
|
391
|
+
if fetch_data.post_data
|
|
392
|
+
response, url = HTTP.fetch_page_post( fetch_data.url, fetch_data.post_data, fetch_data.headers_data )
|
|
393
|
+
else
|
|
394
|
+
response, url = HTTP.fetch_page_get( fetch_data.url, fetch_data.headers_data )
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
if response && response.body()
|
|
398
|
+
log( "OK" )
|
|
399
|
+
log( response.body(), 2 ) if verbose_log?
|
|
400
|
+
return response.body(), url
|
|
401
|
+
else
|
|
402
|
+
log( "ERROR" )
|
|
403
|
+
return nil, url
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
# NOTE: override for example if your using google feeling lucky to verify that
|
|
409
|
+
# the resulting page is not just some random (trashy) result.
|
|
410
|
+
# Returns false is body does not correspond to the required suggestions page
|
|
411
|
+
def suggestions_page_valid?( request, page_body, page_url )
|
|
412
|
+
return true
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# NOTE: implement in subclasses
|
|
416
|
+
# Returns an array of Suggestion objects
|
|
417
|
+
# def parse_suggestions( request, page_body, page_url )
|
|
418
|
+
# return []
|
|
419
|
+
# end
|
|
420
|
+
|
|
421
|
+
# Returns an array of maps { url, artist, title }
|
|
422
|
+
def suggestions( request )
|
|
423
|
+
|
|
424
|
+
log( site_name().upcase() + "\nRetrieving SUGGESTIONS...\n" + request.to_s() )
|
|
425
|
+
|
|
426
|
+
fetch_data = build_suggestions_fetch_data( request )
|
|
427
|
+
suggestions = []
|
|
428
|
+
|
|
429
|
+
suggestions_rec( request, fetch_data, suggestions, 0 )
|
|
430
|
+
|
|
431
|
+
return suggestions
|
|
432
|
+
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def suggestions_rec( request, fetch_data, cumulative_suggestions, recursion_level )
|
|
436
|
+
|
|
437
|
+
page_body, page_url = fetch_suggestions_page( fetch_data )
|
|
438
|
+
return if page_body == nil
|
|
439
|
+
|
|
440
|
+
if suggestions_page_valid?( request, page_body, page_url )
|
|
441
|
+
|
|
442
|
+
log( "Parsing suggestions...", 0 )
|
|
443
|
+
suggestions = parse_suggestions( request, page_body, page_url )
|
|
444
|
+
|
|
445
|
+
if ! suggestions.is_a?( Array )
|
|
446
|
+
log( " INVALID RESPONSE FROM PARSE_SUGGESTIONS" )
|
|
447
|
+
return
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
if suggestions.empty?
|
|
451
|
+
log( " NO SUGGESTIONS FOUND" )
|
|
452
|
+
return
|
|
453
|
+
else
|
|
454
|
+
log( "" )
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
suggestions.each() do |suggestion|
|
|
458
|
+
if suggestion.is_a?( FetchPageData )
|
|
459
|
+
log( " - url: #{suggestion.url}" )
|
|
460
|
+
increase_tabulation_level()
|
|
461
|
+
log( "Retrieving SUGGESTIONS LEVEL#{recursion_level+2}..." )
|
|
462
|
+
suggestions_rec( request, suggestion, cumulative_suggestions, recursion_level + 1 )
|
|
463
|
+
decrease_tabulation_level()
|
|
464
|
+
else
|
|
465
|
+
log( " - #{suggestion.to_s()}" )
|
|
466
|
+
cumulative_suggestions << suggestion
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
else
|
|
471
|
+
log( "SUGGESTIONS PAGE IS INVALID" )
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
end
|
|
475
|
+
protected :suggestions_rec
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def lyrics_from_suggestions( request, suggestions=nil )
|
|
479
|
+
|
|
480
|
+
log( site_name().upcase() + "\nSearching LYRICS FROM SUGGESTIONS..." )
|
|
481
|
+
|
|
482
|
+
suggestions = suggestions( request ) if suggestions == nil
|
|
483
|
+
|
|
484
|
+
normalized_artist, normalized_title = Strings.normalize( request.artist ), Strings.normalize( request.title )
|
|
485
|
+
|
|
486
|
+
log( "Scanning suggestions... ", 0 )
|
|
487
|
+
suggestions.each() do |suggestion|
|
|
488
|
+
next if ! suggestion.is_a?( Suggestion )
|
|
489
|
+
if Strings.normalize( suggestion.artist ) == normalized_artist &&
|
|
490
|
+
Strings.normalize( suggestion.title ) == normalized_title
|
|
491
|
+
log( "MATCH FOUND\n" + suggestion.to_s() )
|
|
492
|
+
# TODO should we use request.album and request.year here?
|
|
493
|
+
response = lyrics_from_url(
|
|
494
|
+
Request.new( suggestion.artist, suggestion.title, request.album, request.year ),
|
|
495
|
+
suggestion.url
|
|
496
|
+
)
|
|
497
|
+
return response, suggestions if response.lyrics
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
log( "NO VALID MATCH FOUND" )
|
|
502
|
+
|
|
503
|
+
return Response.new( request ), suggestions
|
|
504
|
+
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
# Returns a Lyrics::Response object
|
|
508
|
+
def lyrics_full_search( request )
|
|
509
|
+
|
|
510
|
+
# LYRICS DIRECT SEARCH:
|
|
511
|
+
response = lyrics_direct_search( request )
|
|
512
|
+
return response if response.lyrics
|
|
513
|
+
|
|
514
|
+
# NOT FOUND, SEARCH IN SUGGESTIONS:
|
|
515
|
+
response, suggs = lyrics_from_suggestions( request, suggestions( request ) )
|
|
516
|
+
return response
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
# default implementation, overide if there is a more accurate expression for a specific site
|
|
520
|
+
def Lyrics.build_google_feeling_lucky_url( artist, title=nil )
|
|
521
|
+
query = Strings.google_search_quote( artist )
|
|
522
|
+
query << " " << Strings.google_search_quote( title ) if title
|
|
523
|
+
query << " lyrics"
|
|
524
|
+
return Strings.build_google_feeling_lucky_url( query, self.site_host() )
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
def build_google_feeling_lucky_url( artist, title=nil )
|
|
528
|
+
return self.class.build_google_feeling_lucky_url( artist, title )
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
# NOTE: if possible use popular song that are likely to be indexed by google.
|
|
532
|
+
# We are not testing here how good or complete a site is but if the site plugin
|
|
533
|
+
# is behaving as expected. We part from the assumption that every plugin should
|
|
534
|
+
# be able to get lyrics and suggestions for the values returned here.
|
|
535
|
+
def Lyrics.lyrics_test_data()
|
|
536
|
+
return [
|
|
537
|
+
Request.new( "Nirvana", "Smells Like Teen Spirit", "Nevermind" ),
|
|
538
|
+
Request.new( "Radiohead", "Optimistic", "Kid A" ),
|
|
539
|
+
Request.new( "Massive Attack", "Protection", "Protection" ),
|
|
540
|
+
Request.new( "Pearl Jam", "Porch", "Ten" ),
|
|
541
|
+
# Request.new( "The Cranberries", "Linger", "Everybody Else Is Doing It, So Why Can't We?" ),
|
|
542
|
+
# Request.new( "Radiohead", "Idioteque", "Kid A" ),
|
|
543
|
+
# Request.new( "Radiohead", "How To Disappear Completely","stitle"=>"How To Dissapear", "Kid A" ),
|
|
544
|
+
# Request.new( "Pearl Jam", "Love Boat Captain", "Riot Act" ),
|
|
545
|
+
# Request.new( "Blur", "No Distance Left To Run", "13" ),
|
|
546
|
+
# Request.new( "Opeth", "Hope Leaves", "Damnation" ),
|
|
547
|
+
# Request.new( "Megadeth", "À tout le monde", "Youthanasia" ),
|
|
548
|
+
# Request.new( "Metallica", "Master of Puppets", "Master of Puppets" ),
|
|
549
|
+
# Request.new( "Lacuna Coil", "Heaven's a Lie", "Comalies" ),
|
|
550
|
+
# Request.new( "Pearl Jam", "Porch", "Ten" ),
|
|
551
|
+
# Request.new( "Portishead", "Wandering Star", "Dummy" ),
|
|
552
|
+
]
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
def lyrics_test_data()
|
|
556
|
+
return self.class.lyrics_test_data()
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
def Lyrics.suggestions_test_data()
|
|
560
|
+
return lyrics_test_data()
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
def suggestions_test_data()
|
|
564
|
+
return self.class.suggestions_test_data()
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
end
|