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.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
- data/.github/ISSUE_TEMPLATE/config.yml +5 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +23 -0
- data/.github/workflows/check-source-branch.yml +8 -0
- data/.github/workflows/ci.yml +38 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.rubocop.yml +20 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +37 -0
- data/CODE_OF_CONDUCT.md +106 -0
- data/CONTRIBUTING.md +368 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +174 -0
- data/LICENSE.txt +674 -0
- data/README.md +288 -0
- data/SECURITY.md +14 -0
- data/Steepfile +13 -0
- data/bin/console +15 -0
- data/bin/release +5 -0
- data/bin/setup +21 -0
- data/docscribe.yml +9 -0
- data/exe/genius-api +4 -0
- data/genius-api.gemspec +47 -0
- data/lib/extensions/deep_find.rb +36 -0
- data/lib/extensions/extensions.rb +12 -0
- data/lib/extensions/options_helper.rb +17 -0
- data/lib/extensions/token_ext.rb +12 -0
- data/lib/extensions/unescape.rb +13 -0
- data/lib/genius/api/account.rb +35 -0
- data/lib/genius/api/annotations.rb +90 -0
- data/lib/genius/api/artists.rb +82 -0
- data/lib/genius/api/authorization.rb +47 -0
- data/lib/genius/api/errors.rb +211 -0
- data/lib/genius/api/referents.rb +38 -0
- data/lib/genius/api/search.rb +26 -0
- data/lib/genius/api/songs.rb +84 -0
- data/lib/genius/api/version.rb +8 -0
- data/lib/genius/api/web_pages.rb +26 -0
- data/lib/genius/api.rb +23 -0
- data/rbs_collection.lock.yaml +232 -0
- data/rbs_collection.yaml +14 -0
- data/sig/lib/extensions/deep_find.rbs +30 -0
- data/sig/lib/extensions/options_helper.rbs +3 -0
- data/sig/lib/extensions/token_ext.rbs +3 -0
- data/sig/lib/extensions/unescape.rbs +3 -0
- data/sig/lib/genius/api/account.rbs +23 -0
- data/sig/lib/genius/api/annotations.rbs +13 -0
- data/sig/lib/genius/api/artists.rbs +15 -0
- data/sig/lib/genius/api/authorization.rbs +11 -0
- data/sig/lib/genius/api/errors.rbs +46 -0
- data/sig/lib/genius/api/referents.rbs +7 -0
- data/sig/lib/genius/api/search.rbs +5 -0
- data/sig/lib/genius/api/songs.rbs +15 -0
- data/sig/lib/genius/api/version.rbs +5 -0
- data/sig/lib/genius/api/web_pages.rbs +5 -0
- data/sig/lib/genius/api.rbs +9 -0
- metadata +313 -0
data/README.md
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Genius API
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Welcome to the unofficial [Genius API](https://docs.genius.com) representation. This repo reflects all of the service
|
|
6
|
+
API and much more!
|
|
7
|
+
|
|
8
|
+
## Documentation content
|
|
9
|
+
|
|
10
|
+
1. [Overview][1]
|
|
11
|
+
2. [Installation][2]
|
|
12
|
+
1. [Build from source][2.1]
|
|
13
|
+
1. [Manual installation][2.1.1]
|
|
14
|
+
2. [Automatic installation][2.1.2]
|
|
15
|
+
2. [Build via bundler][2.2]
|
|
16
|
+
3. [Usage][3]
|
|
17
|
+
4. [Requirements][4]
|
|
18
|
+
1. [Common usage][4.1]
|
|
19
|
+
2. [Development purposes][4.2]
|
|
20
|
+
5. [Development][5]
|
|
21
|
+
6. [Type checking][6]
|
|
22
|
+
1. [RBS][6.1]
|
|
23
|
+
2. [Steep][6.2]
|
|
24
|
+
7. [Documentation][7]
|
|
25
|
+
1. [YARD][7.1]
|
|
26
|
+
2. [Docscribe][7.2]
|
|
27
|
+
8. [Project style guide][8]
|
|
28
|
+
9. [Contributing][9]
|
|
29
|
+
10. [License][10]
|
|
30
|
+
11. [Code of Conduct][11]
|
|
31
|
+
|
|
32
|
+
## Overview
|
|
33
|
+
|
|
34
|
+
As noted above, this gem fully represents Genius service API. The projects source tree is pretty simple. All of the
|
|
35
|
+
resources are stored in theirs separate module, so it does code readability much cleaner.
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
Genius API gem is quite simple to use and install. There are two options to install it — for those who is going to
|
|
40
|
+
contribute into the project and for those who is going to embed gem to theirs project. See below for each step.
|
|
41
|
+
|
|
42
|
+
### Build from source
|
|
43
|
+
|
|
44
|
+
#### Manual installation
|
|
45
|
+
|
|
46
|
+
The manual installation includes installation via command line interface. it is practically no different from what
|
|
47
|
+
happens during the automatic build of the project:
|
|
48
|
+
|
|
49
|
+
```shell
|
|
50
|
+
git clone https://github.com/unurgunite/genius-api.git && \
|
|
51
|
+
cd genius-api && \
|
|
52
|
+
bundle install && \
|
|
53
|
+
gem build genius-api.gemspec && \
|
|
54
|
+
gem install genius-api-0.2.1.gem
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Now everything should work fine. Just type `irb` and `require "genius/api"` to start working with the library
|
|
58
|
+
|
|
59
|
+
#### Automatic installation
|
|
60
|
+
|
|
61
|
+
The automatic installation is simpler but it has at least same steps as manual installation:
|
|
62
|
+
|
|
63
|
+
```shell
|
|
64
|
+
git clone https://github.com/unurgunite/genius-api.git && \
|
|
65
|
+
cd genius-api && \
|
|
66
|
+
bin/setup
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
If you see `irb` interface, then everything works fine. The main goal of automatic installation is that you do not need
|
|
70
|
+
to create your own script to simplify project build and clean up the shell history. Note: you do not need to require
|
|
71
|
+
projects file after the automatic installation. See `bin/setup` file for clarity of the statement
|
|
72
|
+
|
|
73
|
+
### Build via bundler
|
|
74
|
+
|
|
75
|
+
This documentation point is close to those who need to embed the library in their project. Just place this gem to your
|
|
76
|
+
Gemfile or create it manually via `bundle init`:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
# Your Gemfile
|
|
80
|
+
gem 'genius-api'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
And then execute:
|
|
84
|
+
|
|
85
|
+
```shell
|
|
86
|
+
bundle install
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Or install it yourself for non bundled projects as:
|
|
90
|
+
|
|
91
|
+
```shell
|
|
92
|
+
gem install genius-api
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Usage
|
|
96
|
+
|
|
97
|
+
All docs are available at the separate page: https://unurgunite.github.io/genius-api_docs/
|
|
98
|
+
|
|
99
|
+
## Requirements
|
|
100
|
+
|
|
101
|
+
This section will show dependencies which are used in the project. This section splits in two other sections —
|
|
102
|
+
requirements for common use and requirements for the development purposes.
|
|
103
|
+
|
|
104
|
+
### Common use
|
|
105
|
+
|
|
106
|
+
The `genius-api` gem requires Ruby >= 3.2 and is built on top of two other gems:
|
|
107
|
+
|
|
108
|
+
| Dependencies | Description |
|
|
109
|
+
|-----------------|---------------------------------------------------------------------------------------------|
|
|
110
|
+
| [HTTParty][101] | The HTTParty gem is used to send requests to the REST client of the https://api.genius.com/ |
|
|
111
|
+
| [Nokogiri][102] | The Nokogiri gem is used to represent XML objects as Ruby structures. |
|
|
112
|
+
|
|
113
|
+
### Development purposes
|
|
114
|
+
|
|
115
|
+
For the development purposes `genius-api` gem uses:
|
|
116
|
+
|
|
117
|
+
| Dependencies | Description |
|
|
118
|
+
|------------------|------------------------------------------------------------------------------------------|
|
|
119
|
+
| [RSpec][201] | The RSpec gem is used for test which are located in a separate folder under `spec` name. |
|
|
120
|
+
| [RuboCop][202] | The RuboCop gem is used for code formatting. |
|
|
121
|
+
| [Rake][203] | The Rake gem is used for building tasks as generating documentation. |
|
|
122
|
+
| [Dotenv][204] | The Dotenv gem is used for setting variables for test environment (`token`, for e.g.). |
|
|
123
|
+
| [Coderay][205] | The Coderay gem is used for colorizing Rspec output. |
|
|
124
|
+
| [YARD][206] | The YARD gem is used for the documentation. |
|
|
125
|
+
| [RBS][207] | The RBS gem is used for Ruby type signatures. |
|
|
126
|
+
| [Steep][208] | The Steep gem is used for static type checking. |
|
|
127
|
+
| [Docscribe][209] | The Docscribe gem is used for automated YARD documentation generation. |
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests.
|
|
132
|
+
You can
|
|
133
|
+
also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
134
|
+
|
|
135
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
|
|
136
|
+
version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
|
|
137
|
+
push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
138
|
+
|
|
139
|
+
## Type checking
|
|
140
|
+
|
|
141
|
+
This project uses RBS for type signatures and Steep for static type checking.
|
|
142
|
+
|
|
143
|
+
### RBS
|
|
144
|
+
|
|
145
|
+
RBS type signatures are located in `sig/` directory. To validate them:
|
|
146
|
+
|
|
147
|
+
```shell
|
|
148
|
+
bundle exec rbs validate
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Steep
|
|
152
|
+
|
|
153
|
+
To run the Steep type checker:
|
|
154
|
+
|
|
155
|
+
```shell
|
|
156
|
+
bundle exec steep check
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Documentation
|
|
160
|
+
|
|
161
|
+
This project uses YARD for documentation with Docscribe for automated annotation generation.
|
|
162
|
+
|
|
163
|
+
### YARD
|
|
164
|
+
|
|
165
|
+
To generate YARD documentation:
|
|
166
|
+
|
|
167
|
+
```shell
|
|
168
|
+
bundle exec yard doc -o docs
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Generated docs will be placed in `docs/` (gitignored).
|
|
172
|
+
|
|
173
|
+
### Docscribe
|
|
174
|
+
|
|
175
|
+
Docscribe keeps YARD annotations in sync with the codebase. To check for missing or outdated docs:
|
|
176
|
+
|
|
177
|
+
```shell
|
|
178
|
+
bundle exec docscribe lib
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
To regenerate annotations using RBS type information:
|
|
182
|
+
|
|
183
|
+
```shell
|
|
184
|
+
bundle exec docscribe -A --rbs-collection lib
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Project style guide
|
|
188
|
+
|
|
189
|
+
To make the code base much cleaner gem has its own style guides. They are defined in a root folder of the gem in
|
|
190
|
+
a [CONTRIBUTING.md](https://github.com/unurgunite/genius-api/blob/master/CONTRIBUTING.md) file. Check it for more
|
|
191
|
+
details.
|
|
192
|
+
|
|
193
|
+
## Contributing
|
|
194
|
+
|
|
195
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/unurgunite/genius-api. This project is
|
|
196
|
+
intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
|
|
197
|
+
the [code of conduct](https://github.com/unurgunite/genius-api/blob/master/CODE_OF_CONDUCT.md). To contribute you should
|
|
198
|
+
fork this project and create there new branch:
|
|
199
|
+
|
|
200
|
+
```shell
|
|
201
|
+
git clone https://github.com/your-beautiful-username/genius-api.git && \
|
|
202
|
+
git checkout -b refactor && \
|
|
203
|
+
git commit -m "Affected new changes" && \
|
|
204
|
+
git push origin refactor
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
And then make new pull request with additional notes of what you have done. The better the changes are scheduled, the
|
|
208
|
+
faster the PR will be checked.
|
|
209
|
+
|
|
210
|
+
## License
|
|
211
|
+
|
|
212
|
+
The gem is available as open source under the terms of the [GPLv3 License](https://opensource.org/licenses/GPL-3.0). The
|
|
213
|
+
copy of the license is stored in project under the `LICENSE.txt` file
|
|
214
|
+
name: [copy of the License](https://github.com/unurgunite/genius-api/blob/master/LICENSE.txt)
|
|
215
|
+
|
|
216
|
+
The documentation is available as open source under the terms of
|
|
217
|
+
the [CC BY-SA 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/)
|
|
218
|
+
|
|
219
|
+
The other libs are available as open source under the terms of
|
|
220
|
+
the [New BSD License](https://opensource.org/licenses/BSD-3-Clause)
|
|
221
|
+
|
|
222
|
+

|
|
223
|
+

|
|
224
|
+

|
|
225
|
+
|
|
226
|
+
[1]:https://github.com/unurgunite/genius-api#overview
|
|
227
|
+
|
|
228
|
+
[2]:https://github.com/unurgunite/genius-api#installation
|
|
229
|
+
|
|
230
|
+
[2.1]:https://github.com/unurgunite/genius-api#build-from-source
|
|
231
|
+
|
|
232
|
+
[2.1.1]:https://github.com/unurgunite/genius-api#manual-installation
|
|
233
|
+
|
|
234
|
+
[2.1.2]:https://github.com/unurgunite/genius-api#automatic-installation
|
|
235
|
+
|
|
236
|
+
[2.2]:https://github.com/unurgunite/genius-api#build-via-bundler
|
|
237
|
+
|
|
238
|
+
[3]:https://github.com/unurgunite/genius-api#usage
|
|
239
|
+
|
|
240
|
+
[4]:https://github.com/unurgunite/genius-api#requirements
|
|
241
|
+
|
|
242
|
+
[4.1]:https://github.com/unurgunite/genius-api#common-usage
|
|
243
|
+
|
|
244
|
+
[4.2]:https://github.com/unurgunite/genius-api#development-purposes
|
|
245
|
+
|
|
246
|
+
[5]:https://github.com/unurgunite/genius-api#development
|
|
247
|
+
|
|
248
|
+
[6]:https://github.com/unurgunite/genius-api#type-checking
|
|
249
|
+
|
|
250
|
+
[6.1]:https://github.com/unurgunite/genius-api#rbs
|
|
251
|
+
|
|
252
|
+
[6.2]:https://github.com/unurgunite/genius-api#steep
|
|
253
|
+
|
|
254
|
+
[7]:https://github.com/unurgunite/genius-api#documentation
|
|
255
|
+
|
|
256
|
+
[7.1]:https://github.com/unurgunite/genius-api#yard
|
|
257
|
+
|
|
258
|
+
[7.2]:https://github.com/unurgunite/genius-api#docscribe
|
|
259
|
+
|
|
260
|
+
[8]:https://github.com/unurgunite/genius-api#project-style-guide
|
|
261
|
+
|
|
262
|
+
[9]:https://github.com/unurgunite/genius-api#contributing
|
|
263
|
+
|
|
264
|
+
[10]:https://github.com/unurgunite/genius-api#license
|
|
265
|
+
|
|
266
|
+
[11]:https://github.com/unurgunite/genius-api#code-of-conduct
|
|
267
|
+
|
|
268
|
+
[101]:https://rubygems.org/gems/httparty
|
|
269
|
+
|
|
270
|
+
[102]:https://rubygems.org/gems/nokogiri
|
|
271
|
+
|
|
272
|
+
[201]:https://rubygems.org/gems/rspec
|
|
273
|
+
|
|
274
|
+
[202]:https://rubygems.org/gems/rubocop
|
|
275
|
+
|
|
276
|
+
[203]:https://rubygems.org/gems/rake
|
|
277
|
+
|
|
278
|
+
[204]:https://rubygems.org/gems/dotenv
|
|
279
|
+
|
|
280
|
+
[205]:https://rubygems.org/gems/coderay
|
|
281
|
+
|
|
282
|
+
[206]:https://rubygems.org/gems/yard
|
|
283
|
+
|
|
284
|
+
[207]:https://rubygems.org/gems/rbs
|
|
285
|
+
|
|
286
|
+
[208]:https://rubygems.org/gems/steep
|
|
287
|
+
|
|
288
|
+
[209]:https://rubygems.org/gems/docscribe
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
| Version | Supported |
|
|
6
|
+
|---------|--------------------|
|
|
7
|
+
| 0.3.x | :white_check_mark: |
|
|
8
|
+
| < 0.3.0 | :x: |
|
|
9
|
+
|
|
10
|
+
## Reporting a Vulnerability
|
|
11
|
+
|
|
12
|
+
If you discover a security vulnerability, please do **not** open a public issue. Instead, send a private email to the maintainers at the address listed in the gem specification.
|
|
13
|
+
|
|
14
|
+
We will acknowledge receipt within 48 hours and provide an estimated timeline for a fix.
|
data/Steepfile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'genius/api'
|
|
6
|
+
|
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
+
|
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
+
# require "pry"
|
|
12
|
+
# Pry.start
|
|
13
|
+
|
|
14
|
+
require 'irb'
|
|
15
|
+
IRB.start(__FILE__)
|
data/bin/release
ADDED
data/bin/setup
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
IFS=$'\n\t'
|
|
4
|
+
set -vx
|
|
5
|
+
|
|
6
|
+
PROJECT_NAME='genius-api'
|
|
7
|
+
if pwd | grep $PROJECT_NAME; then
|
|
8
|
+
cd "${PWD%$PROJECT_NAME*}$PROJECT_NAME"
|
|
9
|
+
else
|
|
10
|
+
echo "Change your working directory to the $PROJECT_NAME dir or its relative directories. Exiting with error code 1"
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
bundle install
|
|
15
|
+
|
|
16
|
+
gem build "$PROJECT_NAME".gemspec
|
|
17
|
+
GEM_VERSION=$(bundle info $PROJECT_NAME | head -n 1 | sed 's/.*(\(.*\))/\1/')
|
|
18
|
+
GEM_ARCHIVE="$PROJECT_NAME-$GEM_VERSION.gem"
|
|
19
|
+
gem install "$GEM_ARCHIVE"
|
|
20
|
+
# @todo: add params to `bin/console` script
|
|
21
|
+
bin/console
|
data/docscribe.yml
ADDED
data/exe/genius-api
ADDED
data/genius-api.gemspec
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/genius/api/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'genius-api'
|
|
7
|
+
spec.version = Genius::Api::VERSION
|
|
8
|
+
spec.authors = ['unurgunite']
|
|
9
|
+
|
|
10
|
+
spec.summary = 'Library to work with Genius API'
|
|
11
|
+
spec.description = 'Library to work with Genius API, written in Ruby'
|
|
12
|
+
spec.homepage = 'https://github.com/unurgunite/genius-api'
|
|
13
|
+
spec.license = 'GPL-3.0'
|
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 3.2')
|
|
15
|
+
|
|
16
|
+
spec.metadata = {
|
|
17
|
+
'homepage_uri' => spec.homepage,
|
|
18
|
+
'source_code_uri' => 'https://github.com/unurgunite/genius-api',
|
|
19
|
+
'changelog_uri' => 'https://github.com/unurgunite/genius-api/blob/master/CHANGELOG.md',
|
|
20
|
+
'rubygems_mfa_required' => 'true'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
|
25
|
+
end
|
|
26
|
+
spec.bindir = 'exe'
|
|
27
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
28
|
+
spec.require_paths = ['lib']
|
|
29
|
+
|
|
30
|
+
spec.post_install_message = "Thanks for installing!\nA Ruby gem for scraping with Genius API🤓"
|
|
31
|
+
|
|
32
|
+
spec.add_dependency 'httparty', '~> 0.21'
|
|
33
|
+
spec.add_dependency 'nokogiri'
|
|
34
|
+
spec.add_development_dependency 'coderay'
|
|
35
|
+
spec.add_development_dependency 'docscribe'
|
|
36
|
+
spec.add_development_dependency 'dotenv', '~> 2.7.6'
|
|
37
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
|
38
|
+
spec.add_development_dependency 'rbs'
|
|
39
|
+
spec.add_development_dependency 'rspec', '~> 3.4'
|
|
40
|
+
spec.add_development_dependency 'rubocop'
|
|
41
|
+
spec.add_development_dependency 'rubocop-performance'
|
|
42
|
+
spec.add_development_dependency 'rubocop-rake'
|
|
43
|
+
spec.add_development_dependency 'rubocop-rspec'
|
|
44
|
+
spec.add_development_dependency 'rubocop-sorted_methods_by_call'
|
|
45
|
+
spec.add_development_dependency 'steep'
|
|
46
|
+
spec.add_development_dependency 'yard'
|
|
47
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Hash # :nodoc:
|
|
4
|
+
# Searches for a key in nested hashes and arrays. Returns matching values or +nil+.
|
|
5
|
+
#
|
|
6
|
+
# @param [Object] key Key to search for.
|
|
7
|
+
# @param [Boolean] uniq If +true+, deduplicates results.
|
|
8
|
+
# @return [nil, Object]
|
|
9
|
+
def deep_find(key, uniq: true)
|
|
10
|
+
result = collect_values(key)
|
|
11
|
+
result.compact!
|
|
12
|
+
result.delete_if { |i| i.is_a?(Array) && i.empty? }
|
|
13
|
+
result.uniq! if uniq
|
|
14
|
+
return nil if result.empty?
|
|
15
|
+
|
|
16
|
+
result.size == 1 ? result.first : result
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
# Recursively collects values for a key from nested hashes.
|
|
22
|
+
#
|
|
23
|
+
# @private
|
|
24
|
+
# @param [Object] key Key to search for.
|
|
25
|
+
# @return [Array]
|
|
26
|
+
def collect_values(key)
|
|
27
|
+
result = [self[key]]
|
|
28
|
+
each_value do |value|
|
|
29
|
+
values = value.is_a?(Array) ? value : [value]
|
|
30
|
+
values.each do |v|
|
|
31
|
+
result << v.deep_find(key) if v.is_a?(Hash)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
result
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This file is an extension initializer. That means that it includes extension files
|
|
4
|
+
# during initialization and extension methods are visible from everywhere
|
|
5
|
+
require_relative 'deep_find'
|
|
6
|
+
require_relative 'unescape'
|
|
7
|
+
require_relative 'token_ext'
|
|
8
|
+
require_relative 'options_helper'
|
|
9
|
+
|
|
10
|
+
require 'json'
|
|
11
|
+
require 'nokogiri'
|
|
12
|
+
require 'httparty'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: false
|
|
2
|
+
|
|
3
|
+
class Object # :nodoc:
|
|
4
|
+
# +Object#options_helper+ -> String
|
|
5
|
+
#
|
|
6
|
+
# @param [Hash] options Hash with params for response.
|
|
7
|
+
# @param [Array] arry Array of possible params for response.
|
|
8
|
+
# @return [String]
|
|
9
|
+
def options_helper(options, arry)
|
|
10
|
+
params = ''
|
|
11
|
+
opt = arry
|
|
12
|
+
options.each do |k, v|
|
|
13
|
+
params.insert(params.length, "&#{k}=#{v}") if opt.include? k
|
|
14
|
+
end
|
|
15
|
+
params
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Object # :nodoc:
|
|
4
|
+
# +Object#token_ext+ -> String
|
|
5
|
+
#
|
|
6
|
+
# Helper method to check if token is correct
|
|
7
|
+
# @param [String?] token Token to access https://api.genius.com.
|
|
8
|
+
# @return [String]
|
|
9
|
+
def token_ext(token)
|
|
10
|
+
token || Genius::Auth.instance_variable_get(:@token)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class String # :nodoc:
|
|
4
|
+
# +String#unescape+ -> String
|
|
5
|
+
#
|
|
6
|
+
# String#unescape method unescapes input JSON strings.
|
|
7
|
+
#
|
|
8
|
+
# @return [String]
|
|
9
|
+
def unescape
|
|
10
|
+
string = gsub(/(?<!\\)(\\")/, '"')
|
|
11
|
+
string.gsub(/(?<!\\)(\\\\")/, '\"')
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Genius
|
|
4
|
+
# +Genius::Account+ module provides methods to work with Genius account
|
|
5
|
+
module Account
|
|
6
|
+
class << self
|
|
7
|
+
# +Genius::Account.account+ -> value
|
|
8
|
+
#
|
|
9
|
+
# An alias to {Genius::Account.account me} method
|
|
10
|
+
#
|
|
11
|
+
# @param [String?] token Token to access https://api.genius.com.
|
|
12
|
+
# @raise [TokenError] if +token+ or +Genius::Auth.token+ are invalid.
|
|
13
|
+
# @return [Hash, nil] if TokenError exception raised.
|
|
14
|
+
# This method is a standard Genius API {request}[https://docs.genius.com/#search-h2] to get
|
|
15
|
+
# account info. Output +JSON+ is translated to Hash structure to make it easy to work with account fields.
|
|
16
|
+
#
|
|
17
|
+
# @example
|
|
18
|
+
# Genius::Auth.login="yuiaYqbncErCVwItjQxFspNWUZLhGpXrPbkvgbgHSEKJRAlToamzMfdOeDB"
|
|
19
|
+
# Genius::Account.account #=> {"meta"=>{"status"=>200}, "response"=>{"user"=>{...}}}
|
|
20
|
+
# @todo somehow refactor 50/52 exceptions
|
|
21
|
+
def account(token: nil)
|
|
22
|
+
return if token.nil? && !Auth.authorized?.nil?
|
|
23
|
+
|
|
24
|
+
Errors.validate_token(token) unless token.nil?
|
|
25
|
+
|
|
26
|
+
response = HTTParty.get("https://api.genius.com/account?access_token=#{token_ext(token)}").body
|
|
27
|
+
JSON.parse(response)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
alias me account
|
|
31
|
+
|
|
32
|
+
Genius::Errors::DynamicRescue.rescue(Module.nesting[1])
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Genius
|
|
4
|
+
# An annotation is a piece of content about a part of a document. The document may be a song (hosted on Genius) or a
|
|
5
|
+
# web page (hosted anywhere). The part of a document that an annotation is attached to is called a referent.
|
|
6
|
+
module Annotations
|
|
7
|
+
class << self
|
|
8
|
+
# Data for a specific annotation. Supports GET, POST, PUT, DELETE verbs with optional voting actions.
|
|
9
|
+
#
|
|
10
|
+
# @param [Integer] id ID of the annotation.
|
|
11
|
+
# @param [String?] action Action for PUT request: +nil+, +upvote+, +downvote+, or +unvote+.
|
|
12
|
+
# @param [String?] token Token to access https://api.genius.com.
|
|
13
|
+
# @param [String] http_verb HTTP verb: +get+, +post+, +put+, +delete+.
|
|
14
|
+
# @param [Hash] options Options for POST/PUT payload.
|
|
15
|
+
# @raise [ArgumentError] if +action+ is set for non-PUT request.
|
|
16
|
+
# @return [Hash, nil]
|
|
17
|
+
def annotations(id:, action:, token:, http_verb: 'get', options: {})
|
|
18
|
+
return if token.nil? && !Auth.authorized?.nil?
|
|
19
|
+
|
|
20
|
+
Errors.validate_token(token) unless token.nil?
|
|
21
|
+
raise ArgumentError, 'only PUT accepts `action` param' if http_verb != 'put' && !action.nil?
|
|
22
|
+
|
|
23
|
+
JSON.parse(request(id: id, action: action, token: token, http_verb: http_verb, options: options).body)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
# Sends an HTTP request based on the verb and returns the raw response.
|
|
29
|
+
#
|
|
30
|
+
# @private
|
|
31
|
+
# @param [Integer] id ID of the annotation.
|
|
32
|
+
# @param [String?] action Action for PUT request.
|
|
33
|
+
# @param [String?] token Token to access https://api.genius.com.
|
|
34
|
+
# @param [String] http_verb HTTP verb.
|
|
35
|
+
# @param [Hash] options Options for POST/PUT payload.
|
|
36
|
+
# @raise [ArgumentError] if HTTP verb is invalid.
|
|
37
|
+
# @return [HTTParty::Response]
|
|
38
|
+
def request(id:, action:, token:, http_verb:, options:)
|
|
39
|
+
case http_verb
|
|
40
|
+
when 'get' then HTTParty.get("#{Api::RESOURCE}/annotations/#{id}?access_token=#{token_ext(token)}")
|
|
41
|
+
when 'post' then HTTParty.post("#{Api::RESOURCE}/annotations/#{id}?access_token=#{token_ext(token)}",
|
|
42
|
+
body: post_payload(options: options))
|
|
43
|
+
when 'put' then put_request(id: id, action: action, token: token, options: options)
|
|
44
|
+
when 'delete' then HTTParty.delete("#{Api::RESOURCE}/annotations/#{id}?access_token=#{token_ext(token)}")
|
|
45
|
+
else raise ArgumentError, 'Something bad happened...'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Sends a PUT request with optional voting action.
|
|
50
|
+
#
|
|
51
|
+
# @private
|
|
52
|
+
# @param [Integer] id ID of the annotation.
|
|
53
|
+
# @param [String?] action Action: +nil+, +upvote+, +downvote+, or +unvote+.
|
|
54
|
+
# @param [String?] token Token to access https://api.genius.com.
|
|
55
|
+
# @param [Hash] options Options for PUT payload.
|
|
56
|
+
# @raise [ArgumentError] if +action+ is invalid.
|
|
57
|
+
# @return [HTTParty::Response]
|
|
58
|
+
def put_request(id:, action:, token:, options:)
|
|
59
|
+
case action
|
|
60
|
+
when nil then HTTParty.put("#{Api::RESOURCE}/annotations/#{id}/#{action}?access_token=#{token_ext(token)}",
|
|
61
|
+
body: post_payload(options: options))
|
|
62
|
+
when 'upvote', 'downvote', 'unvote' then HTTParty.put("#{Api::RESOURCE}/annotations/#{id}/#{action}?access_token=#{token_ext(token)}")
|
|
63
|
+
else
|
|
64
|
+
actions = %w[upvote downvote unvote]
|
|
65
|
+
raise ArgumentError,
|
|
66
|
+
"Invalid value for `action` param. Allowed values are: #{actions.join(', ')}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Builds a JSON payload for POST and PUT requests from options.
|
|
71
|
+
#
|
|
72
|
+
# @private
|
|
73
|
+
# @param [Hash] options Options containing +:markdown+, +:raw_annotatable_url+, +:fragment+, etc.
|
|
74
|
+
# @return [String]
|
|
75
|
+
def post_payload(options: {})
|
|
76
|
+
{
|
|
77
|
+
annotation: { body: { markdown: options[:markdown] } },
|
|
78
|
+
referent: {
|
|
79
|
+
raw_annotatable_url: options[:raw_annotatable_url],
|
|
80
|
+
fragment: options[:fragment],
|
|
81
|
+
context_for_display: { before_html: options[:before_html], after_html: options[:after_html] }
|
|
82
|
+
},
|
|
83
|
+
web_page: { canonical_url: options[:canonical_url], og_url: options[:og_url], title: options[:title] }
|
|
84
|
+
}.to_json
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
Genius::Errors::DynamicRescue.rescue(Module.nesting[1])
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|