genius-api 0.3.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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
  3. data/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +23 -0
  6. data/.github/workflows/check-source-branch.yml +8 -0
  7. data/.github/workflows/ci.yml +38 -0
  8. data/.gitignore +15 -0
  9. data/.rspec +3 -0
  10. data/.rubocop.yml +20 -0
  11. data/.ruby-version +1 -0
  12. data/CHANGELOG.md +37 -0
  13. data/CODE_OF_CONDUCT.md +106 -0
  14. data/CONTRIBUTING.md +368 -0
  15. data/Gemfile +7 -0
  16. data/Gemfile.lock +174 -0
  17. data/LICENSE.txt +674 -0
  18. data/README.md +288 -0
  19. data/SECURITY.md +14 -0
  20. data/Steepfile +13 -0
  21. data/bin/console +15 -0
  22. data/bin/release +5 -0
  23. data/bin/setup +21 -0
  24. data/docscribe.yml +9 -0
  25. data/exe/genius-api +4 -0
  26. data/genius-api.gemspec +47 -0
  27. data/lib/extensions/deep_find.rb +36 -0
  28. data/lib/extensions/extensions.rb +12 -0
  29. data/lib/extensions/options_helper.rb +17 -0
  30. data/lib/extensions/token_ext.rb +12 -0
  31. data/lib/extensions/unescape.rb +13 -0
  32. data/lib/genius/api/account.rb +35 -0
  33. data/lib/genius/api/annotations.rb +90 -0
  34. data/lib/genius/api/artists.rb +82 -0
  35. data/lib/genius/api/authorization.rb +47 -0
  36. data/lib/genius/api/errors.rb +211 -0
  37. data/lib/genius/api/referents.rb +38 -0
  38. data/lib/genius/api/search.rb +26 -0
  39. data/lib/genius/api/songs.rb +84 -0
  40. data/lib/genius/api/version.rb +8 -0
  41. data/lib/genius/api/web_pages.rb +26 -0
  42. data/lib/genius/api.rb +23 -0
  43. data/rbs_collection.lock.yaml +232 -0
  44. data/rbs_collection.yaml +14 -0
  45. data/sig/lib/extensions/deep_find.rbs +30 -0
  46. data/sig/lib/extensions/options_helper.rbs +3 -0
  47. data/sig/lib/extensions/token_ext.rbs +3 -0
  48. data/sig/lib/extensions/unescape.rbs +3 -0
  49. data/sig/lib/genius/api/account.rbs +23 -0
  50. data/sig/lib/genius/api/annotations.rbs +13 -0
  51. data/sig/lib/genius/api/artists.rbs +15 -0
  52. data/sig/lib/genius/api/authorization.rbs +11 -0
  53. data/sig/lib/genius/api/errors.rbs +46 -0
  54. data/sig/lib/genius/api/referents.rbs +7 -0
  55. data/sig/lib/genius/api/search.rbs +5 -0
  56. data/sig/lib/genius/api/songs.rbs +15 -0
  57. data/sig/lib/genius/api/version.rbs +5 -0
  58. data/sig/lib/genius/api/web_pages.rbs +5 -0
  59. data/sig/lib/genius/api.rbs +9 -0
  60. metadata +313 -0
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Genius
4
+ # An artist is how Genius represents the creator of one or more songs (or other documents hosted on Genius). It's
5
+ # usually a musician or group of musicians.
6
+ module Artists
7
+ class << self
8
+ # Data for a specific artist.
9
+ #
10
+ # @param [String?] token Token to access https://api.genius.com.
11
+ # @param [Integer?] id ID of the artist.
12
+ # @raise [ArgumentError] if +id+ is nil.
13
+ # @return [Hash, nil]
14
+ def artists(token: nil, id: nil)
15
+ Auth.authorized?(method_name: "#{Module.nesting[1].name}.#{__method__}") if token.nil?
16
+ Errors.validate_token(token) unless token.nil?
17
+ raise ArgumentError, "`id` can't be nil!" if id.nil?
18
+
19
+ response = HTTParty.get("#{Api::RESOURCE}/artists/#{id}?access_token=#{token_ext(token)}").body
20
+ JSON.parse(response)
21
+ end
22
+
23
+ # Songs for the artist specified. By default 20 items per request.
24
+ #
25
+ # @param [String?] token Token to access https://api.genius.com.
26
+ # @param [Integer?] id ID of the artist.
27
+ # @param [Hash] options Optional query params: +:sort+, +:per_page+, +:page+.
28
+ # @return [Hash, nil]
29
+ def artists_songs(token: nil, id: nil, options: {})
30
+ return if token.nil? && !Auth.authorized?.nil?
31
+
32
+ Errors.validate_token(token) unless token.nil?
33
+
34
+ sort_values = %w[title popularity]
35
+ validate(sort_values, sort: options[:sort], per_page: options[:per_page], page: options[:page])
36
+
37
+ params = options_helper(options, %i[sort per_page page])
38
+ response = HTTParty.get("#{Api::RESOURCE}/artists/#{id}?access_token=#{token_ext(token)}#{params}").body
39
+ JSON.parse(response)
40
+ end
41
+
42
+ private
43
+
44
+ # Validates sort, per_page, and page options for artists endpoint.
45
+ #
46
+ # @private
47
+ # @param [Array] sort_values Allowed sort values.
48
+ # @param [Object] options Options with +:sort+, +:per_page+, +:page+.
49
+ # @return [void]
50
+ def validate(sort_values, **options)
51
+ validate_sort(options[:sort], sort_values)
52
+ validate_page_per_page(options[:per_page])
53
+ validate_page_per_page(options[:page])
54
+ end
55
+
56
+ # Validates the sort option against allowed values.
57
+ #
58
+ # @private
59
+ # @param [String?] sort Sort value to validate.
60
+ # @param [Array] sort_values Allowed sort values.
61
+ # @raise [ArgumentError] if +sort+ is not in +sort_values+.
62
+ # @return [void]
63
+ def validate_sort(sort, sort_values)
64
+ return unless sort && !sort_values.include?(sort)
65
+
66
+ raise ArgumentError, "`sort` can't be #{sort}. Possible values: #{sort_values.join(', ')}."
67
+ end
68
+
69
+ # Validates that per_page or page is not negative.
70
+ #
71
+ # @private
72
+ # @param [Integer?] page_per_page Value to validate.
73
+ # @raise [ArgumentError] if value is negative.
74
+ # @return [void]
75
+ def validate_page_per_page(page_per_page)
76
+ raise ArgumentError, "`per_page` or `page` can't be negative." if page_per_page&.negative?
77
+ end
78
+
79
+ Genius::Errors::DynamicRescue.rescue(Module.nesting[1])
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Genius
4
+ # +Genius::Auth+ module is used to authenticate users with their token. It
5
+ # provides initialization of token instance variable.
6
+ #
7
+ # @example
8
+ # Genius::Auth.login="yuiaYqbncErCVwItjQxFspNWUZLhGpXrPbkvgbgHSEKJRAlToamzMfdOeDB"
9
+ module Auth
10
+ class << self
11
+ # Sets the authentication token after validation.
12
+ #
13
+ # @param [String] token Token to access https://api.genius.com.
14
+ # @raise [Genius::Errors::TokenError] if +token+ is invalid.
15
+ # @return [String]
16
+ def token=(token)
17
+ Genius::Errors.validate_token(token)
18
+ @token = token
19
+ end
20
+
21
+ # Checks if the current token is authorized. Returns +false+ on validation failure.
22
+ #
23
+ # @param [String] token Token to validate.
24
+ # @param [String] method_name Method name for error messages.
25
+ # @raise [Genius::Errors::TokenError]
26
+ # @return [Boolean]
27
+ def authorized?(token = @token, method_name: "#{Module.nesting[1].name}.#{__method__}")
28
+ Errors.validate_token(token, method_name: method_name)
29
+ rescue Genius::Errors::TokenError
30
+ false
31
+ else
32
+ true
33
+ end
34
+
35
+ # Revokes the current session by setting the token to +nil+.
36
+ #
37
+ # @return [nil]
38
+ def logout!
39
+ @token = nil unless @token.nil?
40
+ end
41
+
42
+ alias login= token=
43
+
44
+ Genius::Errors::DynamicRescue.rescue(Module.nesting[1])
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Genius
4
+ # +Genius::Errors+ module includes custom exception classes and methods to
5
+ # handle all errors during requests to https://api.genius.com or during
6
+ # the work with library methods.
7
+ #
8
+ # @example
9
+ # module Genius
10
+ # module Foo
11
+ # include Genius::Errors
12
+ # class << self
13
+ # def bar(params)
14
+ # # body
15
+ # rescue TokenError => e
16
+ # puts "Error description: #{e.msg}" #=> Invalid token!....
17
+ # puts "Error description: #{e.exception_type}" #=> token_error
18
+ # end
19
+ # end
20
+ # end
21
+ # end
22
+ #
23
+ # Exception classes fields provide custom message and error types
24
+ # (+connection_error+, +token_error+, +auth_required+, etc.)
25
+ #
26
+ # @example
27
+ # begin
28
+ # raise TokenError.new(msg: "Message", error_type: "error_type")
29
+ # rescue TokenError => e
30
+ # puts e.message #=> Message
31
+ # puts e.exception_type #=> error_type
32
+ # end
33
+ #
34
+ # There will be a standard output of each exception if there will be no
35
+ # params provided.
36
+ #
37
+ # @example
38
+ # begin
39
+ # raise TokenError
40
+ # rescue TokenError => e
41
+ # puts e.message #=> Invalid token!....
42
+ # puts e.exception_type #=> token_error
43
+ # end
44
+ module Errors
45
+ # Endpoint for resource.
46
+ ENDPOINT = "#{Api::RESOURCE}/account/?access_token".freeze
47
+
48
+ # Abstract class to store all exception classes in a single object.
49
+ class GeniusExceptionSuperClass < StandardError
50
+ end
51
+
52
+ # A +TokenError+ object provides handling error during token validation.
53
+ # It throws error when +token+ is invalid - expired, revoked or something
54
+ # else. To generate new token you should go to
55
+ # https://genius.com/signup_or_login and login, then you need to create
56
+ # new client via the link below: https://genius.com/api-clients and
57
+ # generate new access token. Fields to create new api client can
58
+ # be filled in as you like - there is no restrictions and standards.
59
+ class TokenError < GeniusExceptionSuperClass
60
+ attr_reader :msg, :exception_type, :method_name
61
+
62
+ # Initializes a token validation error with optional method name hint.
63
+ #
64
+ # @param [String] msg Error message.
65
+ # @param [String] exception_type Error type identifier.
66
+ # @param [String?] method_name Optional method name for user hint.
67
+ # @return [void]
68
+ def initialize(msg: 'Invalid token. The access token provided is expired, revoked, malformed or invalid for ' \
69
+ 'other reasons.', exception_type: 'token_error', method_name: nil)
70
+ @msg = if method_name.nil?
71
+ msg
72
+ else
73
+ "#{msg} or type #{method_name}(token: \"YOUR_TOKEN\")"
74
+ end
75
+ @exception_type = exception_type
76
+ super(msg)
77
+ end
78
+ end
79
+
80
+ # A +LyricsNotFoundError+ object handles an exception where JSON with
81
+ # lyrics is not found.
82
+ class LyricsNotFoundError < GeniusExceptionSuperClass
83
+ attr_reader :msg, :exception_type
84
+
85
+ # Initializes a lyrics-not-found error.
86
+ #
87
+ # @param [String] msg Error message.
88
+ # @param [String] exception_type Error type identifier.
89
+ # @return [void]
90
+ def initialize(msg: 'Lyrics not found in current session. Retrying...', exception_type: 'invalid_lyrics')
91
+ @msg = msg
92
+ @exception_type = exception_type
93
+ super(msg)
94
+ end
95
+ end
96
+
97
+ # A +PageNotFound+ object handles an exception where response payload is
98
+ # invalid and Genius itself or its related service returns not found.
99
+ class PageNotFound < GeniusExceptionSuperClass
100
+ attr_reader :msg, :exception_type
101
+
102
+ # Initializes a page-not-found error.
103
+ #
104
+ # @param [String] msg Error message.
105
+ # @param [String] exception_type Error type identifier.
106
+ # @return [void]
107
+ def initialize(msg: 'Page not found. Try again with another response', exception_type: 'page_not_found')
108
+ @msg = msg
109
+ @exception_type = exception_type
110
+ super(msg)
111
+ end
112
+
113
+ # Checks if the HTML response indicates a page-not-found error.
114
+ #
115
+ # @param [Object] html Parsed HTML document.
116
+ # @return [Boolean]
117
+ def self.page_not_found?(html)
118
+ html.text.include?('Page not found')
119
+ end
120
+ end
121
+
122
+ # +Genius::Errors::DynamicRescue+ module is used to call dynamically
123
+ # exceptions to each method in module or class, defined in
124
+ # +Genius::Errors+ scope.
125
+ module DynamicRescue
126
+ class << self
127
+ # Wraps singleton methods of +klass+ with exception handling via {DynamicRescue.rescue_from}.
128
+ #
129
+ # @param [Module] klass Module whose singleton methods to wrap.
130
+ # @return [Array]
131
+ def rescue(klass)
132
+ DynamicRescue.rescue_from klass.singleton_methods, klass, GeniusExceptionSuperClass do |e|
133
+ puts "Error description: #{e.msg}\nException type: #{e.exception_type}"
134
+ # @todo make raise ExceptionKlass
135
+ end
136
+ end
137
+
138
+ # Redefines each method in +meths+ on +klass+ to rescue +exception+ and yield to the block.
139
+ #
140
+ # @param [Array] meths Method names to wrap.
141
+ # @param [Module] klass Module to redefine methods on.
142
+ # @param [Module] exception Exception class to rescue.
143
+ # @raise [StandardError]
144
+ # @return [Array]
145
+ def rescue_from(meths, klass, exception, &)
146
+ meths.each do |meth|
147
+ old = klass.singleton_method(meth)
148
+ klass.define_singleton_method(meth) do |*args, **kwargs|
149
+ old.unbind.bind(klass).call(*args, **kwargs) # steep:ignore
150
+ rescue exception => e
151
+ yield(e)
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ class << self
159
+ # Validates the access token by checking length and making a test request to the API.
160
+ #
161
+ # @param [String?] token Token to validate.
162
+ # @param [String?] method_name Optional method name for error hints.
163
+ # @raise [StandardError] if +token+ is nil, wrong length, or invalid.
164
+ # @return [void]
165
+ def validate_token(token, method_name: nil)
166
+ raise TokenError.new(method_name: method_name) if token.nil? || token.size != 64
167
+
168
+ response = HTTParty.get("#{ENDPOINT}=#{token}").body
169
+ status = JSON.parse(response).dig('meta', 'status')
170
+ raise TokenError.new(method_name: method_name) unless status == 200
171
+ end
172
+
173
+ # Validates token and raises on failure. Returns +true+ if valid.
174
+ #
175
+ # @deprecated Use {.validate_token} instead.
176
+ # @param [String?] token Token to validate.
177
+ # @param [String?] method_name Optional method name for error hints.
178
+ # @raise [StandardError] if token is invalid.
179
+ # @return [Boolean]
180
+ def error_handle?(token, method_name: nil)
181
+ if token.nil?
182
+ raise TokenError.new(msg: 'Token is required for this method. Please, add token via ' \
183
+ "`Genius::Auth.login=``token''` method and continue",
184
+ method_name: method_name)
185
+ elsif token.size != 64 || check_status?(token) == false
186
+ raise TokenError.new(method_name: method_name)
187
+ end
188
+ true
189
+ end
190
+
191
+ private
192
+
193
+ # Checks if the token returns a 200 status from the API.
194
+ #
195
+ # @deprecated Use {.validate_token} instead.
196
+ # @private
197
+ # @param [String] token Token to check.
198
+ # @raise [TokenError] if the response status is not 200.
199
+ # @return [Boolean]
200
+ def check_status?(token)
201
+ return false if token.size != 64 || token.nil?
202
+
203
+ response = HTTParty.get("#{ENDPOINT}=#{token}").body
204
+ raise TokenError unless JSON.parse(response).dig('meta', 'status')
205
+
206
+ status = JSON.parse(response).dig('meta', 'status')
207
+ status == 200
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Genius
4
+ # Referents are the sections of a piece of content to which annotations are
5
+ # attached. Each referent is associated with a web page or a song and may
6
+ # have one or more annotations. Referents can be searched by the document
7
+ # they are attached to or by the user that created them. When a new
8
+ # annotation is created either a referent is created with it or that
9
+ # annotation is attached to an existing referent.
10
+ module Referents
11
+ class << self
12
+ # Endpoint of the resource
13
+ ENDPOINT = "#{Api::RESOURCE}/referents".freeze
14
+ # Referents by content item or user. Pass only one of +:song_id+ and +:web_page+.
15
+ #
16
+ # @param [String?] token Token to access https://api.genius.com.
17
+ # @param [Hash] options Options: +:created_by_id+, +:text_format+, +:web_page_id+,
18
+ # +:song_id+, +:per_page+, +:page+.
19
+ # @raise [ArgumentError] if both +:song_id+ and +:web_page+ are present.
20
+ # @return [Hash, nil]
21
+ def referents(token: nil, options: {})
22
+ return if token.nil? && !Auth.authorized?.nil?
23
+
24
+ Errors.validate_token(token) unless token.nil?
25
+ if options.key?(:web_page) && options.key?(:song_id)
26
+ raise ArgumentError, 'You may pass only one of song_id and web_page_id, not both!'
27
+ end
28
+
29
+ params = options_helper(options, %i[created_by_id text_format per_page page])
30
+
31
+ response = HTTParty.get("#{ENDPOINT}?access_token=#{token_ext(token)}#{params}").body
32
+ JSON.parse(response)
33
+ end
34
+
35
+ Genius::Errors::DynamicRescue.rescue(Module.nesting[1])
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Genius
4
+ # +Genius::Search+ module provides methods to work with Genius search database
5
+ module Search
6
+ class << self
7
+ # Searches Genius for songs, artists, and other content. Optionally filters results by key using +deep_find+.
8
+ #
9
+ # @param [String?] token Token to access https://api.genius.com.
10
+ # @param [String?] query Search query.
11
+ # @param [String?] search_by Key to filter results with {Hash#deep_find}.
12
+ # @return [Hash, String, nil]
13
+ def search(token: nil, query: nil, search_by: nil)
14
+ return if token.nil? && !Auth.authorized?.nil?
15
+
16
+ Errors.validate_token(token) unless token.nil?
17
+
18
+ response = HTTParty.get("#{Api::RESOURCE}/search?q=#{query}&access_token=#{token_ext(token)}").body
19
+ search = JSON.parse(response)
20
+ search_by ? search.deep_find(search_by) : search
21
+ end
22
+
23
+ Genius::Errors::DynamicRescue.rescue(Module.nesting[1])
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Genius
4
+ # +Genius::Songs+ module provides methods to work with songs (lyrics/descriptions/etc.)
5
+ module Songs
6
+ class << self
7
+ include Genius::Errors
8
+
9
+ # Returns song data by ID. Optionally merges lyrics from the Genius page when +combine+ is +true+.
10
+ #
11
+ # @param [String?] token Token to access https://api.genius.com.
12
+ # @param [Integer?] song_id ID of the song.
13
+ # @param [Boolean] combine If +true+, fetches and merges lyrics into the response.
14
+ # @return [Hash, String, nil]
15
+ def songs(token: nil, song_id: nil, combine: false)
16
+ return if token.nil? && !Auth.authorized?.nil?
17
+
18
+ Errors.validate_token(token) unless token.nil?
19
+
20
+ response = HTTParty.get("#{Api::RESOURCE}/songs/#{song_id}?access_token=#{token_ext(token)}").body
21
+ response = JSON.parse response
22
+ combine && song_id ? merge_lyrics(song_id, response) : response
23
+ end
24
+
25
+ private
26
+
27
+ # Fetches the Genius HTML page for a song and merges lyrics into the API response.
28
+ #
29
+ # @private
30
+ # @param [Integer] song_id ID of the song.
31
+ # @param [Hash] response Original API response hash.
32
+ # @raise [Errors::PageNotFound] if the song page is not found.
33
+ # @raise [Errors::LyricsNotFoundError] if lyrics cannot be parsed.
34
+ # @return [Hash, String]
35
+ def merge_lyrics(song_id, response)
36
+ output_html = Nokogiri::HTML(HTTParty.get("https://genius.com/songs/#{song_id}"))
37
+ raise Errors::PageNotFound if Errors::PageNotFound.page_not_found?(output_html)
38
+
39
+ response['lyrics'] = parse_preloaded_state(output_html)
40
+ response
41
+ rescue Errors::LyricsNotFoundError
42
+ retry
43
+ rescue Errors::PageNotFound => e
44
+ "Error description: #{e.msg}\nException type: #{e.exception_type}"
45
+ end
46
+
47
+ # Extracts the preloaded state JSON from the Genius page HTML.
48
+ #
49
+ # @private
50
+ # @param [Object] output_html Parsed Nokogiri HTML document.
51
+ # @raise [Errors::LyricsNotFoundError] if the preloaded state script is not found.
52
+ # @return [Hash]
53
+ def parse_preloaded_state(output_html)
54
+ unformed_json = output_html.css('script')[17]
55
+ .text.match(/window\.__PRELOADED_STATE__\s=\sJSON.parse\('(?<json>(?:.+?))'\);/)
56
+ raise Errors::LyricsNotFoundError if unformed_json.nil?
57
+
58
+ JSON.parse(unformed_json[:json].unescape)
59
+ end
60
+
61
+ public
62
+
63
+ # Extracts lyrics as plain text from the Genius song page.
64
+ #
65
+ # @param [Integer] song_id ID of the song.
66
+ # @raise [ArgumentError] if +song_id+ is nil.
67
+ # @raise [NoMethodError]
68
+ # @return [String]
69
+ def get_lyrics(song_id)
70
+ raise ArgumentError, '`song_id` should be not blank!' if song_id.nil?
71
+
72
+ response = HTTParty.get("https://genius.com/songs/#{song_id}")
73
+ document = Nokogiri::HTML(response)
74
+ # @todo: something wrong with lyrics attribute value
75
+ lyrics_path = document.xpath("//*[@class='Lyrics__Container-sc-1ynbvzw-6 YYrds']")
76
+ lyrics_path.at_css('p').content
77
+ rescue NoMethodError
78
+ retry
79
+ end
80
+
81
+ Genius::Errors::DynamicRescue.rescue(Module.nesting[1])
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Genius
4
+ module Api
5
+ # Version of the gem.
6
+ VERSION = '0.3.0'
7
+ end
8
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Genius
4
+ # A web page is a single, publicly accessible page to which annotations may
5
+ # be attached. Web pages map 1-to-1 with unique, canonical URLs.
6
+ module WebPages
7
+ class << self
8
+ # Looks up a web page by URL variants and returns Genius metadata.
9
+ #
10
+ # @param [String?] token Token to access https://api.genius.com.
11
+ # @param [Hash] options URL variants: +:raw_annotatable_url+, +:canonical_url+, +:og_url+.
12
+ # @return [Hash, nil]
13
+ def lookup(token: nil, options: {})
14
+ return if token.nil? && !Auth.authorized?.nil?
15
+
16
+ Errors.validate_token(token) unless token.nil?
17
+
18
+ params = options_helper(options, %i[raw_annotatable_url canonical_url og_url])
19
+ response = HTTParty.get("#{Api::RESOURCE}/?access_token=#{token_ext(token)}#{params}").body
20
+ JSON.parse(response)
21
+ end
22
+
23
+ Genius::Errors::DynamicRescue.rescue(Module.nesting[1])
24
+ end
25
+ end
26
+ end
data/lib/genius/api.rb ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Base module which contains all of other methods/classes/etc.
4
+ module Genius
5
+ # +Genius::Api+ is a base module with different constants.
6
+ module Api
7
+ # +Genius::Api::RESOURCE+ constant contains reference to
8
+ # {Genius API}[https://api.genius.com] resource.
9
+ RESOURCE = 'https://api.genius.com'
10
+ end
11
+ end
12
+
13
+ require 'extensions/extensions'
14
+ require_relative 'api/errors'
15
+ require_relative 'api/version'
16
+ require_relative 'api/authorization'
17
+ require_relative 'api/account'
18
+ require_relative 'api/search'
19
+ require_relative 'api/songs'
20
+ require_relative 'api/annotations'
21
+ require_relative 'api/referents'
22
+ require_relative 'api/artists'
23
+ require_relative 'api/web_pages'