ultimate_lyrics 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a09ecd6257da805ba95b8448cd62f91dfdcf1e68227da3c8b97ad84827eb0c03
4
+ data.tar.gz: b3ae4ed332ba011bafb985cfb587a82492e2c067aa4b2a0bc732d6ed53608a04
5
+ SHA512:
6
+ metadata.gz: 349464014bc5ba69e813edcae115ef5b7b596050b325c4418d1ee02817ceb2b85525c924e95d50195765f713cb5d89bc7f60a48a0b3f0dd1caff4e661f6c6035
7
+ data.tar.gz: 8976f0c3eb6e9cb079df3c51e418b9468bd660fb8525ec50719988f09b190a37f9af1147440b04d6627f11e283de13d4e6757d062d73a58f23f48b97df36bc0a
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UltimateLyrics
4
+ class Field
5
+ DATA = {
6
+ 'artist' => %w[artist lower],
7
+ 'artist2' => %w[artist lower nospace],
8
+ 'album' => %w[album lower],
9
+ 'album2' => %w[album lower nospace],
10
+ 'title' => %w[title lower],
11
+ 'Artist' => %w[artist],
12
+ 'Album' => %w[album],
13
+ 'ARTIST' => %w[artist upper],
14
+ 'year' => %w[year pretty],
15
+ 'Title' => %w[title],
16
+ 'Title2' => %w[title titlecase],
17
+ 'a' => %w[artist firstchar],
18
+ 'track' => %w[track number]
19
+ }.freeze
20
+
21
+ BEGIN_DELIMITER = '{'
22
+ END_DELIMITER = '}'
23
+
24
+ class << self
25
+ # @return [Array<UltimateLyrics::Field>]
26
+ def all
27
+ @all ||= DATA.map do |name, modifiers|
28
+ source_attr = modifiers.shift
29
+ new(name, source_attr, modifiers)
30
+ end
31
+ end
32
+
33
+ # @return [UltimateLyrics::Field]
34
+ def by_name(name)
35
+ all.find { |field| field.name == name } ||
36
+ raise("No field with name \"#{name}\" (Available: #{all.values})")
37
+ end
38
+
39
+ # @return [Array<UltimateLyrics::Field>]
40
+ def from_string(string)
41
+ names_from_string(string).map { |name| by_name(name) }
42
+ end
43
+
44
+ # @return [Array<String>]
45
+ def names_from_string(string)
46
+ string.scan(/#{::Regexp.quote(BEGIN_DELIMITER)}[^\}]+#{::Regexp.quote(END_DELIMITER)}/)
47
+ .map { |s| s.delimited_inner(BEGIN_DELIMITER, END_DELIMITER) }
48
+ end
49
+ end
50
+
51
+ common_constructor :name, :source_attribute, :modifiers
52
+
53
+ def apply(string, value)
54
+ string.gsub(apply_pattern, value)
55
+ end
56
+
57
+ def apply_pattern
58
+ /#{::Regexp.quote(BEGIN_DELIMITER)}#{::Regexp.quote(name)}#{::Regexp.quote(END_DELIMITER)}/
59
+ end
60
+
61
+ def value(value)
62
+ modifiers.inject(value.to_s) { |a, e| send(e, a) }
63
+ end
64
+
65
+ def to_s
66
+ name
67
+ end
68
+
69
+ private
70
+
71
+ def firstchar(string)
72
+ string[0]
73
+ end
74
+
75
+ def lower(string)
76
+ string.downcase
77
+ end
78
+
79
+ def nospace(string)
80
+ string.gsub(/\s/, '')
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_ruby_utils/core_ext'
4
+
5
+ module UltimateLyrics
6
+ class Lyrics
7
+ common_constructor :song_metadata, :provider_name, :text
8
+
9
+ def found?
10
+ text.present?
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_ruby_utils/core_ext'
4
+
5
+ module UltimateLyrics
6
+ class Parser
7
+ common_constructor :provider, :original_content
8
+
9
+ def original_content_invalid?
10
+ provider.invalid_indicators.any? { |v| original_content.include?(v) }
11
+ end
12
+
13
+ def result
14
+ return nil if original_content_invalid?
15
+
16
+ sanitize_text(provider.rules.inject(original_content) { |a, e| e.apply(a) })
17
+ end
18
+
19
+ def sanitize_text(text)
20
+ r = text.to_s.gsub("\t", ' ').gsub("\r", '').gsub(/ +/, ' ').gsub(/\n{2,}/m, "\n\n").strip
21
+ r.present? ? "#{r}\n" : nil
22
+ end
23
+
24
+ def url?
25
+ provider.extract_rules.any?(&:url?)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ultimate_lyrics/provider/item'
4
+
5
+ module UltimateLyrics
6
+ class Provider
7
+ class ExcludeItem < ::UltimateLyrics::Provider::Item
8
+ def apply_from_delimiters(source)
9
+ source.delimited_without_outer(begin_with, end_with)
10
+ end
11
+
12
+ def apply_from_tag(source)
13
+ source.delimited_without_outer(tag, "</#{tag_name}>")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ultimate_lyrics/provider/item'
4
+
5
+ module UltimateLyrics
6
+ class Provider
7
+ class ExtractItem < ::UltimateLyrics::Provider::Item
8
+ def apply_from_delimiters(source)
9
+ source.delimited_inner(begin_with, end_with)
10
+ end
11
+
12
+ def apply_from_tag(source)
13
+ source.delimited_inner(tag, "</#{tag_name}>")
14
+ end
15
+
16
+ def apply_from_url(source)
17
+ url.gsub('{id}', source)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UltimateLyrics
4
+ class Provider
5
+ class Item
6
+ METHODS_ATTRIBUTES = { tag: :tag, begin_with: :begin, end_with: :end, url: :url }.freeze
7
+ TAG_NAME_PARSER = /<(\w+).*>/.to_parser { |m| m[1] }
8
+
9
+ common_constructor :rule, :node
10
+
11
+ METHODS_ATTRIBUTES.each do |method_name, attr|
12
+ define_method method_name do
13
+ ::CGI.unescapeHTML(node.attribute(attr.to_s).if_present('', &:text)).presence
14
+ end
15
+
16
+ define_method "#{method_name}?" do
17
+ send(method_name).present?
18
+ end
19
+ end
20
+
21
+ def delimiters?
22
+ begin_with? || end_with?
23
+ end
24
+
25
+ def apply(source)
26
+ %w[url tag delimiters].each do |m|
27
+ next unless send("#{m}?")
28
+
29
+ return send("apply_from_#{m}", source)
30
+ end
31
+
32
+ raise 'Invalid branch hit'
33
+ end
34
+
35
+ def tag_name
36
+ TAG_NAME_PARSER.parse(tag)
37
+ end
38
+
39
+ def to_s
40
+ self.class.name.demodulize + '[' + METHODS_ATTRIBUTES
41
+ .select { |m, _a| send(m).present? }
42
+ .map { |m, a| "#{a}: #{send(m)}" }
43
+ .join(', ') +
44
+ ']'
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UltimateLyrics
4
+ class Provider
5
+ class ReplaceFields
6
+ common_constructor :metadata, :source_string
7
+
8
+ def result
9
+ fields_found.inject(source_string) { |a, e| a.gsub("{#{e}}", metadata.send(e)) }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UltimateLyrics
4
+ class Provider
5
+ class Rule
6
+ common_constructor :node
7
+
8
+ def items
9
+ node.xpath('./item').map { |v| item_class.new(self, v) }
10
+ end
11
+
12
+ def item_class
13
+ ::UltimateLyrics::Provider.const_get(type.camelize + 'Item')
14
+ end
15
+
16
+ def apply(string)
17
+ url? ? apply_with_url(string) : apply_without_url(string)
18
+ end
19
+
20
+ def to_s
21
+ "Rule[#{type} | #{items.join(', ')}]"
22
+ end
23
+
24
+ def type
25
+ node.name
26
+ end
27
+
28
+ def url?
29
+ items.any?(&:url?)
30
+ end
31
+
32
+ private
33
+
34
+ def apply_without_url(string)
35
+ items.inject(string) { |a, e| e.apply(a) }
36
+ end
37
+
38
+ def apply_with_url(string)
39
+ url_item, id_item = url_items
40
+ id_item.apply(string).if_present { |v| url_item.apply(v) }
41
+ end
42
+
43
+ def url_items
44
+ raise "There is more than 2 items in #{rule}" if items.count != 2
45
+
46
+ url_item = items.find(&:url?) || raise("No URL item found in #{rule}")
47
+ id_item = items.find(&:delimiters?) || raise("No ID item found in #{rule}")
48
+ [url_item, id_item]
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UltimateLyrics
4
+ class Provider
5
+ class UrlFormat
6
+ common_constructor :node
7
+
8
+ def apply(value)
9
+ replace_chars.inject(value) { |a, e| a.gsub(e, with) }
10
+ end
11
+
12
+ def replace_chars
13
+ ::CGI.unescapeHTML(node.attribute('replace').text).each_char.to_a
14
+ end
15
+
16
+ def with
17
+ node.attribute('with').text
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_ruby_utils/core_ext'
4
+ require 'nokogiri'
5
+ require 'ultimate_lyrics/field'
6
+
7
+ module UltimateLyrics
8
+ class Provider
9
+ require_sub __FILE__
10
+
11
+ class << self
12
+ # @return [Array<UltimateLyrics::Provider>]
13
+ def all
14
+ @all ||= ::Nokogiri::XML(
15
+ ::File.new(::File.join(__dir__, 'providers_data.xml'))
16
+ ).xpath('/lyricproviders/provider').map { |node| new(node) }
17
+ end
18
+
19
+ # @return [UltimateLyrics::Provider]
20
+ def by_name(name)
21
+ by_attribute('name', name)
22
+ end
23
+
24
+ # @return [UltimateLyrics::Provider]
25
+ def by_identifier(identifier)
26
+ by_attribute('identifier', identifier)
27
+ end
28
+
29
+ # @return [UltimateLyrics::Provider]
30
+ def by_attribute(attribute, value)
31
+ all.find { |provider| provider.send(attribute) == value } ||
32
+ raise("No provider with name \"#{value}\" (Available: " +
33
+ all.map { |p| p.send(attrbute) }.join(', ') + ')')
34
+ end
35
+ end
36
+
37
+ common_constructor :node
38
+
39
+ def extract_rules
40
+ node.xpath('./extract').map do |v|
41
+ ::UltimateLyrics::Provider::Rule.new(v)
42
+ end
43
+ end
44
+
45
+ def exclude_rules
46
+ node.xpath('./exclude').map do |v|
47
+ ::UltimateLyrics::Provider::Rule.new(v)
48
+ end
49
+ end
50
+
51
+ def identifier
52
+ name.variableize
53
+ end
54
+
55
+ def invalid_indicators
56
+ node.xpath('/invalidIndicator/@value').map(&:text)
57
+ end
58
+
59
+ # @return [String]
60
+ def name
61
+ node.attribute('name').text
62
+ end
63
+
64
+ def rules
65
+ extract_rules + exclude_rules
66
+ end
67
+
68
+ # @return [String]
69
+ def url
70
+ node.attribute('url').text
71
+ end
72
+
73
+ # @return [Array<UltimateLyrics::Field>]
74
+ def url_fields
75
+ ::UltimateLyrics::Field.from_string(url)
76
+ end
77
+
78
+ def url_formats
79
+ node.xpath('./urlFormat').map do |v|
80
+ ::UltimateLyrics::Provider::UrlFormat.new(v)
81
+ end
82
+ end
83
+
84
+ def title
85
+ node.attribute('text').text
86
+ end
87
+
88
+ def to_s
89
+ name
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aranha/parsers/source_address'
4
+ require 'eac_ruby_utils/core_ext'
5
+ require 'ultimate_lyrics/lyrics'
6
+ require 'ultimate_lyrics/parser'
7
+
8
+ module UltimateLyrics
9
+ class ProviderSearch
10
+ common_constructor :provider, :song_metadata
11
+
12
+ # @return [String]
13
+ def url
14
+ url_fields.inject(provider.url) { |a, e| e.apply(a) }
15
+ end
16
+
17
+ # @return []
18
+ def url_fields
19
+ provider.url_fields.map { |provider_url_field| song_metadata.field(provider_url_field) }
20
+ end
21
+
22
+ # @return [UltimateLyrics::Lyrics]
23
+ def lyrics
24
+ ::UltimateLyrics::Lyrics.new(song_metadata, provider.name, parser.result)
25
+ end
26
+
27
+ # @return [UltimateLyrics::Parser]
28
+ def lyrics_original_text
29
+ ::Aranha::Parsers::SourceAddress.detect_sub(url).content
30
+ rescue ::Aranha::Parsers::SourceAddress::FetchContentError
31
+ nil
32
+ end
33
+
34
+ # @return [UltimateLyrics::Parser]
35
+ def parser
36
+ ::UltimateLyrics::Parser.new(provider, lyrics_original_text)
37
+ end
38
+
39
+ def to_s
40
+ "ProviderSearch[#{provider} | #{song_metadata}]"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,355 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ Copy of https://raw.githubusercontent.com/clementine-player/Clementine/fb93ae4b020014ae38e7ebf51f3d8e333a5b572f/data/lyrics/ultimate_providers.xml.
4
+ -->
5
+ <lyricproviders>
6
+ <provider name="azlyrics.com" title="{artist} LYRICS - {title}" charset="utf-8"
7
+ url="http://www.azlyrics.com/lyrics/{artist}/{title}.html">
8
+ <urlFormat replace="._@,;&amp;\/()'&quot;-" with="" />
9
+ <extract>
10
+ <item begin="&lt;!-- Usage of azlyrics.com content by any third-party lyrics provider is prohibited by our licensing agreement. Sorry about that. --&gt;"
11
+ end="&lt;/div&gt;" />
12
+ </extract>
13
+ <exclude>
14
+ <item tag="&lt;B&gt;" />
15
+ <item begin="&lt;i&gt;[" end="]&lt;/i&gt;" />
16
+ <item begin="[" end="]" />
17
+ </exclude>
18
+ <invalidIndicator value="&lt;h1&gt;Welcome to AZLyrics!&lt;/h1&gt;" />
19
+ </provider>
20
+ <provider name="bollywoodlyrics.com (Bollywood songs)"
21
+ title="{title} Song Lyrics - BollywoodLyrics.com" charset="utf-8"
22
+ url="http://www.bollywoodlyrics.com/lyric/{Title}">
23
+ <urlFormat replace="_@;\/&quot;'()[]" with="-" />
24
+ <urlFormat replace="?" with="" />
25
+ <extract>
26
+ <item begin="&lt;div class=&quot;entry-content&quot;&gt;" end="&lt;/div&gt;" />
27
+ </extract>
28
+ <invalidIndicator value="Couldn't find that page." />
29
+ </provider>
30
+ <provider name="darklyrics.com" title="{ARTIST} LYRICS - &quot;{title}&quot; ({year}) album"
31
+ charset="utf-8" url="http://www.darklyrics.com/lyrics/{artist2}/{album2}.html">
32
+ <extract>
33
+ <item begin="&lt;h3&gt;&lt;a name=&quot;{track}&quot;&gt;{track}. {Title2}&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;"
34
+ end="&lt;h3&gt;" />
35
+ </extract>
36
+ <extract>
37
+ <item begin="&lt;h3&gt;&lt;a name=&quot;{track}&quot;&gt;{track}. {Title2}&lt;/a&gt;&lt;/h3&gt;&lt;br /&gt;"
38
+ end="&lt;div class=&quot;thanks&quot;&gt;" />
39
+ </extract>
40
+ <invalidIndicator value="The page you requested was not found on DarkLyrics.com." />
41
+ </provider>
42
+ <provider name="directlyrics.com" title="{artist} - {title} lyrics" charset="iso-8859-1"
43
+ url="http://www.directlyrics.com/{artist}-{title}-lyrics.html">
44
+ <urlFormat replace="_@,;&amp;\/'&quot;" with="-" />
45
+ <urlFormat replace="." with="" />
46
+ <extract>
47
+ <item tag="&lt;div id=&quot;lyricsContent&quot;&gt;" />
48
+ <item tag="&lt;p&gt;" />
49
+ </extract>
50
+ <exclude>
51
+ <item begin="&lt;b&gt;" end="&lt;/b&gt;" />
52
+ </exclude>
53
+ </provider>
54
+ <provider name="elyrics.net" title="{title} Lyrics - {artist}" charset="iso-8859-1"
55
+ url="http://www.elyrics.net/read/{a}/{artist}-lyrics/{title}-lyrics.html">
56
+ <urlFormat replace="_@;&amp;\/&quot;" with="-" />
57
+ <urlFormat replace="'" with="_" />
58
+ <extract>
59
+ <item tag="&lt;div class='ly' style='font-size:12px;'&gt;" />
60
+ </extract>
61
+ <exclude>
62
+ <item tag="&lt;strong&gt;" />
63
+ <item tag="&lt;em&gt;" />
64
+ </exclude>
65
+ <invalidIndicator value="Page not Found" />
66
+ </provider>
67
+ <provider name="Encyclopaedia Metallum" title="{title Lyrics - {artist}" charset="utf-8"
68
+ url="http://www.metal-archives.com/search/ajax-advanced/searching/songs/?songTitle={title}&amp;bandName={artist}&amp;ExactBandMatch=1">
69
+
70
+ <extract>
71
+ <item url="http://www.metal-archives.com/release/ajax-view-lyrics/id/{id}" />
72
+ <item begin="id=\&quot;lyricsLink_" end="&quot;" />
73
+ </extract>
74
+ <invalidIndicator value="&quot;iTotalRecords&quot;: 0" />
75
+ <invalidIndicator value="lyrics not available" />
76
+ </provider>
77
+ <provider name="genius.com" charset="utf-8" url="https://www.genius.com/{artist}-{title}-lyrics">
78
+ <urlFormat replace=",._@!#%^*+;\/&quot;'()[]" with="" />
79
+ <urlFormat replace=":" with="-" />
80
+ <!-- When $ is used as the dollar sign it is omitted from the url
81
+ When $ is used instead of 's',
82
+ in some cases it is replaced by 's'(Too $hort -> too-short)
83
+ in other cases it is omitted ($uicideboy$ -> uicideboy)
84
+ I chose to omit it though, in some cases it's gonna be problematic -->
85
+ <urlFormat replace="$" with="" />
86
+ <urlFormat replace="ÄÂÀÁÃäâàáã" with="a" />
87
+ <urlFormat replace="ËÊÈÉëêèé" with="e" />
88
+ <urlFormat replace="ÏÌïì" with="i" />
89
+ <urlFormat replace="ÖÔÒÓÕöôòóõ" with="o" />
90
+ <urlFormat replace="ÜŪÙÚüūùú" with="u" />
91
+ <urlFormat replace="ŸÝÿý" with="y" />
92
+ <urlFormat replace="Ññ" with="n" />
93
+ <urlFormat replace="Çç" with="c" />
94
+ <urlFormat replace="ß" with="ss" />
95
+ <urlFormat replace="&amp;" with="and" />
96
+ <extract>
97
+ <item tag="&lt;div class=&quot;lyrics&quot;&gt;" />
98
+ </extract>
99
+ <exclude>
100
+ <item begin="&lt;!--" end="--&gt;" />
101
+ <item begin="&lt;a href=" end="&gt;" />
102
+ <item begin="&lt;/a" end="&gt;" />
103
+ </exclude>
104
+ </provider>
105
+ <provider name="hindilyrics.net (Bollywood songs)" title="{title} ({album})" charset="utf-8"
106
+ url="http://www.hindilyrics.net/lyrics/of-{Title}.html">
107
+ <urlFormat replace="_@;\/&quot;'()[]" with="%20" />
108
+ <urlFormat replace="?" with="" />
109
+ <extract>
110
+ <item begin="&lt;div class=nm&gt;Movie&lt;/div&gt;:" end="&lt;/pre&gt;" />
111
+ </extract>
112
+ <exclude>
113
+ <item begin="&lt;span class=" end="&quot;&gt;" />
114
+ </exclude>
115
+ <invalidIndicator value="Couldn't find that page." />
116
+ </provider>
117
+ <provider name="letras.mus.br" title="" charset="utf-8"
118
+ url="https://www.letras.mus.br/winamp.php?musica={title}&amp;artista={artist}">
119
+ <urlFormat replace="_@,;&amp;\/&quot;" with="_" />
120
+ <urlFormat replace="" with="+" />
121
+ <extract>
122
+ <item begin="&lt;/div&gt;" end="&lt;/div&gt;" />
123
+ </extract>
124
+ <invalidIndicator value="Verifique se o nome do seu arquivo e sua" />
125
+ </provider>
126
+ <provider name="lololyrics.com" title="" charset="utf-8"
127
+ url="http://api.lololyrics.com/0.5/getLyric?artist={artist}&amp;track={title}">
128
+ <urlFormat replace="_@,;&amp;\/&quot;#" with="_" />
129
+ <extract>
130
+ <item tag="&lt;response&gt;" />
131
+ </extract>
132
+ <invalidIndicator value="ERROR" />
133
+ </provider>
134
+ <provider name="loudson.gs" title="" charset="utf-8"
135
+ url="http://www.loudson.gs/{a}/{artist}/{album}/{title}">
136
+ <urlFormat replace="_@,;&amp;\/&quot;" with="-" />
137
+ <urlFormat replace="." with="" />
138
+ <extract>
139
+ <item tag="&lt;div class=&quot;middle_col_TracksLyrics &quot;&gt;" />
140
+ </extract>
141
+ </provider>
142
+ <provider name="lyrics.com" title="{artist} - {title} Lyrics" charset="utf-8"
143
+ url="http://www.lyrics.com/lyrics/{artist}/{title}.html">
144
+ <urlFormat replace="_@,;&amp;\/&quot;" with="-" />
145
+ <urlFormat replace="'." with="" />
146
+ <extract>
147
+ <item tag="&lt;div id=&quot;lyrics&quot; class=&quot;SCREENONLY&quot;&gt;" />
148
+ </extract>
149
+ <exclude>
150
+ <item begin="&lt;br&gt;&lt;br&gt;&lt;a target='_blank'" end="&gt;&lt;/a&gt;" />
151
+ </exclude>
152
+ <invalidIndicator value="Click to search for the Lyrics on Lyrics.com" />
153
+ <invalidIndicator value="we do not have the lyric for this song" />
154
+ </provider>
155
+ <provider name="lyrics.wikia.com" title="{artist}:{title} Lyrics - " charset="utf-8"
156
+ url="http://lyrics.wikia.com/{Artist}:{Title}">
157
+ <urlFormat replace="_@;\&quot;" with="_" />
158
+ <urlFormat replace="?" with="%3F" />
159
+ <extract>
160
+ <item begin="&lt;div class='lyricbox'&gt;" end="&lt;div class='lyricsbreak'" />
161
+ </extract>
162
+ <exclude>
163
+ <item tag="&lt;div class='rtMatcher'&gt;" />
164
+ <item tag="&lt;span style=&quot;padding:1em&quot;&gt;" />
165
+ </exclude>
166
+ </provider>
167
+ <provider name="lyricsbay.com" title="{title} lyrics {artist}" charset="iso-8859-1"
168
+ url="http://www.lyricsbay.com/{title}_lyrics-{artist}.html">
169
+ <urlFormat replace="_@,;&amp;\/'&quot;" with="_" />
170
+ <urlFormat replace="." with="" />
171
+ <extract>
172
+ <item tag="&lt;div id=EchoTopic&gt;" />
173
+ </extract>
174
+ <exclude>
175
+ <item tag="&lt;textarea name=&quot;songscpy&quot; id=&quot;songscpyid&quot; onclick=&quot;callselect('songscpyid','selectswf')&quot; rows=&quot;3&quot; cols=&quot;45&quot; READONLY&gt;" />
176
+ </exclude>
177
+ </provider>
178
+ <provider name="lyricsdownload.com" title="{artist} - {title} LYRICS" charset="utf-8"
179
+ url="http://www.lyricsdownload.com/{artist}-{title}-lyrics.html">
180
+ <urlFormat replace="_@,;&amp;\/&quot;" with="-" />
181
+ <urlFormat replace="." with="" />
182
+ <extract>
183
+ <item tag="&lt;div id=&quot;div_customCSS&quot;&gt;" />
184
+ </extract>
185
+ <invalidIndicator value="We haven't lyrics of this song" />
186
+ </provider>
187
+ <provider name="lyricsmania.com" title="{artist} - {title} Lyrics" charset="iso-8859-1"
188
+ url="http://www.lyricsmania.com/{title}_lyrics_{artist}.html">
189
+ <urlFormat replace="_@;&amp;\/&quot;'." with="_" />
190
+ <extract>
191
+ <item begin="&lt;span style=&quot;font-size:14px;&quot;&gt;"
192
+ end="&lt;span style=&quot;font-size:14px;&quot;&gt;" />
193
+ <item begin="&lt;/center&gt;" end="&lt;a" />
194
+ </extract>
195
+ <invalidIndicator value="The lyrics you requested is not in our archive yet," />
196
+ </provider>
197
+ <provider name="lyricsmode.com" title="{artist} - {title} lyrics" charset="iso-8859-1"
198
+ url="http://www.lyricsmode.com/lyrics/{a}/{artist}/{title}.html">
199
+ <urlFormat replace="._@,;&amp;\/&quot;" with="_" />
200
+ <extract>
201
+ <item tag="&lt;div id='songlyrics_h' class='dn'&gt;" />
202
+ </extract>
203
+ <invalidIndicator value="Sorry, we have no" />
204
+ </provider>
205
+ <provider name="lyricsplugin.com" title="{artist} - {title} Lyrics" charset="utf-8"
206
+ url="http://www.lyricsplugin.com/winamp03/plugin/?title={title}&amp;artist={artist}">
207
+ <urlFormat replace="_@;&amp;\/&quot;" with="-" />
208
+ <urlFormat replace="'" with="" />
209
+ <urlFormat replace="" with="%20" />
210
+ <extract>
211
+ <item tag="&lt;div id=&quot;lyrics&quot;&gt;" />
212
+ </extract>
213
+ </provider>
214
+ <provider name="lyricsreg.com" title="{title} lyrics {artist}" charset="iso-8859-1"
215
+ url="http://www.lyricsreg.com/lyrics/{artist}/{title}/">
216
+ <urlFormat replace="_@,;&amp;\/&quot;" with="+" />
217
+ <urlFormat replace="'." with="" />
218
+ <extract>
219
+ <item begin="Ringtone to your Cell" end="Ringtone to your Cell" />
220
+ <item begin="&lt;div style=&quot;text-align:center;&quot;&gt;" end="&lt;a" />
221
+ </extract>
222
+ <invalidIndicator value="Page not Found" />
223
+ </provider>
224
+ <provider name="lyricstime.com" title="{artist} - {title} Lyrics" charset="iso-8859-1"
225
+ url="http://www.lyricstime.com/{artist}-{title}-lyrics.html">
226
+ <urlFormat replace="_@,;&amp;\/&quot;'" with="-" />
227
+ <urlFormat replace="." with="" />
228
+ <extract>
229
+ <item tag="&lt;div id=&quot;songlyrics&quot; &gt;" />
230
+ <item tag="&lt;p&gt;" />
231
+ </extract>
232
+ </provider>
233
+ <provider name="lyriki.com" title="" charset="utf-8"
234
+ url="http://www.lyriki.com/{artist}:{title}">
235
+ <urlFormat replace="_@,;&amp;\/&quot;" with="_" />
236
+ <urlFormat replace="." with="" />
237
+ <extract>
238
+ <item begin="&lt;/table&gt;" end="&lt;div class=&quot;printfooter&quot;&gt;" />
239
+ <item tag="&lt;p&gt;" />
240
+ </extract>
241
+ </provider>
242
+ <provider name="metrolyrics.com" title="{artist} - {title} LYRICS" charset="utf-8"
243
+ url="http://www.metrolyrics.com/{title}-lyrics-{artist}.html">
244
+ <urlFormat replace="_@,;&amp;\/&quot;" with="-" />
245
+ <urlFormat replace="'." with="" />
246
+ <extract>
247
+ <item tag="&lt;span id=&quot;lyrics&quot;&gt;" />
248
+ </extract>
249
+ <extract>
250
+ <item tag="&lt;div id=&quot;lyrics&quot;&gt;" />
251
+ </extract>
252
+ <exclude>
253
+ <item tag="&lt;h5&gt;" />
254
+ </exclude>
255
+ <invalidIndicator value="These lyrics are missing" />
256
+ </provider>
257
+ <provider name="mp3lyrics.org" title="{artist} &amp;quot;{title}&amp;quot; Lyrics"
258
+ charset="utf-8" url="http://www.mp3lyrics.org/{a}/{artist}/{title}/">
259
+ <urlFormat replace="_@,;&amp;\/&quot;" with="-" />
260
+ <urlFormat replace="'." with="" />
261
+ <extract>
262
+ <item tag="&lt;span id=gn_lyricsB&gt;" />
263
+ </extract>
264
+ <extract>
265
+ <item tag="&lt;div class=&quot;KonaBody&quot; id=&quot;EchoTopic&quot;&gt;" />
266
+ </extract>
267
+ <exclude>
268
+ <item tag="&lt;font size=2&gt;" />
269
+ <item begin="&lt;b&gt;&lt;i&gt;" end="&lt;/u&gt;&lt;/b&gt;:" />
270
+ <item begin="&lt;b&gt;Lyrics" end="&lt;/b&gt;" />
271
+ </exclude>
272
+ <invalidIndicator value="Something went wrong" />
273
+ </provider>
274
+ <provider name="musixmatch.com" title="{artist} - {title} lyrics | Musixmatch" charset="utf-8"
275
+ url="https://www.musixmatch.com/lyrics/{Artist}/{Title}">
276
+ <urlFormat replace="_@;\/&quot;'()[]" with="-" />
277
+ <urlFormat replace="?" with="" />
278
+ <extract>
279
+ <item begin="&lt;span id=&quot;lyrics-html&quot;" end="&lt;/span&gt;" />
280
+ </extract>
281
+ <exclude>
282
+ <item begin="data-reactid=&quot;" end="&quot;&gt;" />
283
+ </exclude>
284
+ <invalidIndicator value="We couldn't find that page." />
285
+ </provider>
286
+ <provider name="seeklyrics.com" title="{artist} - {title} Lyrics" charset="iso-8859-1"
287
+ url="http://www.seeklyrics.com/lyrics/{Artist}/{Title}.html">
288
+ <urlFormat replace="_@,;&amp;\/'&quot;" with="-" />
289
+ <urlFormat replace="." with="" />
290
+ <extract>
291
+ <item tag="&lt;div id=&quot;songlyrics&quot;&gt;" />
292
+ </extract>
293
+ </provider>
294
+ <provider name="songlyrics.com" title="{title} LYRICS - {artist}" charset="utf-8"
295
+ url="http://www.songlyrics.com/{artist}/{title}-lyrics/">
296
+ <urlFormat replace="._@,;&amp;\/&quot;" with="-" />
297
+ <urlFormat replace="'" with="_" />
298
+ <extract>
299
+ <item tag="&lt;p id=&quot;songLyricsDiv&quot; ondragstart=&quot;return false;&quot; onselectstart=&quot;return false;&quot; oncontextmenu=&quot;return false;&quot; class=&quot;songLyricsV14&quot; style=&quot;font-size: 14px;z-index: 9999;position: absolute;left: -6000px;&quot;&gt;" />
300
+ </extract>
301
+ <exclude>
302
+ <item begin="[" end="]" />
303
+ </exclude>
304
+ <invalidIndicator value="Sorry, we have no" />
305
+ <invalidIndicator value="This is an upcoming album and we do not have the" />
306
+ </provider>
307
+ <provider name="tekstowo.pl (Original lyric language)" title="{artist} - {title} - tekst"
308
+ charset="utf-8" url="http://www.tekstowo.pl/piosenka,{artist},{title}.html">
309
+ <urlFormat replace="_@,;&amp;\/'&quot;." with="_" />
310
+ <extract>
311
+ <item begin="&lt;div class=&quot;song-text&quot;&gt;"
312
+ end="&lt;a href=&quot;javascript:;&quot;" />
313
+ </extract>
314
+ <extract>
315
+ <item tag="&lt;div class=&quot;tlumaczenie&quot;&gt;" />
316
+ </extract>
317
+ <exclude>
318
+ <item begin="&lt;h2&gt;" end="&lt;/h2&gt;&lt;br /&gt;" />
319
+ </exclude>
320
+ </provider>
321
+ <provider name="tekstowo.pl (Translated to Polish)" title="{artist} - {title} - tekst"
322
+ charset="utf-8" url="http://www.tekstowo.pl/piosenka,{artist},{title}.html">
323
+ <urlFormat replace="_@,;&amp;\/'&quot;." with="_" />
324
+ <extract>
325
+ <item begin="&lt;div id=&quot;translation&quot; class=" end="&lt;a href=" />
326
+ </extract>
327
+ <exclude>
328
+ <item begin="&quot;id-" end="&quot;&gt;" />
329
+ </exclude>
330
+ </provider>
331
+ <provider name="teksty.org" title="{artist} - {title} - tekst" charset="utf-8"
332
+ url="http://teksty.org/{artist},{title},tekst-piosenki">
333
+ <urlFormat replace="_@,;&amp;\/&quot;'" with="-" />
334
+ <urlFormat replace="." with="" />
335
+ <extract>
336
+ <item begin="&lt;div class=&quot;songText&quot; id=&quot;songContent&quot;&gt;"
337
+ end="&lt;/div&gt;" />
338
+ </extract>
339
+ </provider>
340
+ <provider name="vagalume.com.br" title="{title} de {artist} no VAGALUME" charset="iso-8859-1"
341
+ url="http://vagalume.com.br/{artist}/{title}.html">
342
+ <urlFormat replace="_@,;&amp;\/'&quot;." with="-" />
343
+ <extract>
344
+ <item tag="&lt;span class=&quot;editable_area&quot;&gt;" />
345
+ </extract>
346
+ </provider>
347
+ <provider name="vagalume.com.br (Portuguese translations)"
348
+ title="{title} de {artist} no VAGALUME" charset="iso-8859-1"
349
+ url="http://vagalume.com.br/{artist}/{title}-traducao.html">
350
+ <urlFormat replace="_@,;&amp;\/'&quot;." with="-" />
351
+ <extract>
352
+ <item tag="&lt;div class=&quot;tab_traducao sideBySide lyricArea tab_tra_pt&quot;&gt;" />
353
+ </extract>
354
+ </provider>
355
+ </lyricproviders>
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UltimateLyrics
4
+ class SongMetadata
5
+ class Field
6
+ enable_listable
7
+ lists.add_symbol :sources, :album, :artist, :title, :track, :year
8
+
9
+ common_constructor :song_metadata, :field
10
+
11
+ def apply(string)
12
+ field.apply(string, value)
13
+ end
14
+
15
+ def value
16
+ field.value(song_metadata.send(field.source_attribute))
17
+ end
18
+
19
+ def to_s
20
+ "[#{song_metadata} | #{field}]"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_ruby_utils/core_ext'
4
+
5
+ module UltimateLyrics
6
+ class SongMetadata
7
+ require_sub __FILE__
8
+ common_constructor :data do
9
+ self.data = ::UltimateLyrics::SongMetadata::Field.lists.sources.hash_keys_validate!(data)
10
+ end
11
+
12
+ ::UltimateLyrics::SongMetadata::Field.lists.sources.each_value do |field|
13
+ define_method field do
14
+ data.fetch(field)
15
+ end
16
+ end
17
+
18
+ # @param field [UltimateLyrics::Field]
19
+ # @return [UltimateLyrics::SongMetadata::Field]
20
+ def field(field)
21
+ UltimateLyrics::SongMetadata::Field.new(self, field)
22
+ end
23
+
24
+ def to_s
25
+ data.map { |k, v| "#{k}=#{v}" }.join(', ')
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UltimateLyrics
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_ruby_utils/core_ext'
4
+
5
+ module UltimateLyrics
6
+ require_sub __FILE__
7
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ultimate_lyrics
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Put here the authors
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-09-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aranha-parsers
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.8'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.8.5
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.8'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.8.5
33
+ - !ruby/object:Gem::Dependency
34
+ name: eac_ruby_utils
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.74'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.74'
47
+ - !ruby/object:Gem::Dependency
48
+ name: eac_ruby_gem_support
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.4'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.4'
61
+ description:
62
+ email:
63
+ executables: []
64
+ extensions: []
65
+ extra_rdoc_files: []
66
+ files:
67
+ - lib/ultimate_lyrics.rb
68
+ - lib/ultimate_lyrics/field.rb
69
+ - lib/ultimate_lyrics/lyrics.rb
70
+ - lib/ultimate_lyrics/parser.rb
71
+ - lib/ultimate_lyrics/provider.rb
72
+ - lib/ultimate_lyrics/provider/exclude_item.rb
73
+ - lib/ultimate_lyrics/provider/extract_item.rb
74
+ - lib/ultimate_lyrics/provider/item.rb
75
+ - lib/ultimate_lyrics/provider/replace_fields.rb
76
+ - lib/ultimate_lyrics/provider/rule.rb
77
+ - lib/ultimate_lyrics/provider/url_format.rb
78
+ - lib/ultimate_lyrics/provider_search.rb
79
+ - lib/ultimate_lyrics/providers_data.xml
80
+ - lib/ultimate_lyrics/song_metadata.rb
81
+ - lib/ultimate_lyrics/song_metadata/field.rb
82
+ - lib/ultimate_lyrics/version.rb
83
+ homepage:
84
+ licenses: []
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubygems_version: 3.1.6
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Put here de description.
105
+ test_files: []