myanimelist_client 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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +196 -0
- data/Rakefile +9 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/myanimelist_client.rb +8 -0
- data/lib/myanimelist_client/myanimelist_client.rb +107 -0
- data/lib/myanimelist_client/search_entry.rb +124 -0
- data/lib/myanimelist_client/search_response.rb +122 -0
- data/lib/myanimelist_client/user_response.rb +53 -0
- data/lib/myanimelist_client/version.rb +4 -0
- data/myanimelist_client.gemspec +42 -0
- metadata +146 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 322a8bcf59174eb6fc400792ec2d5217d034655f
|
4
|
+
data.tar.gz: f93f47d5ff102dca9d61b94bc5838d7eab2dd083
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 516a2cfacb909d01e1cdc2f3e92a1e79b519ea075e8f42e200fb10107cd8c9c0f9747142a9dec3eac8b3d3b6cd6ee70d5cf8ae88d99356df570f4a1da3ccc972
|
7
|
+
data.tar.gz: a49ba46023cc1d23b66e85e468bc7fef4b6a7518dcd46c15dfbaedfccfd9760bd8e5f9fe7848954365a156aa58ab29f7e3b770331a83b8aa7d99969c3d582960
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
- LICENSE.txt
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Oli4242
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
# MyAnimeList Client
|
2
|
+
A gem for the [MyAnimeList.net API](https://myanimelist.net/modules.php?go=api).
|
3
|
+
|
4
|
+
For now you can:
|
5
|
+
|
6
|
+
* [Search anime](https://myanimelist.net/modules.php?go=api#animemangasearch)
|
7
|
+
* [Search manga](https://myanimelist.net/modules.php?go=api#animemangasearch)
|
8
|
+
* [Verify credentials](https://myanimelist.net/modules.php?go=api#verifycred)
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'myanimelist_client'
|
16
|
+
```
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install myanimelist_client
|
25
|
+
|
26
|
+
## Overview
|
27
|
+
```ruby
|
28
|
+
require 'myanimelist_client'
|
29
|
+
|
30
|
+
# First, create a client
|
31
|
+
# MyAnimeList.net requires a valid account to consume their API
|
32
|
+
client = MyanimelistClient.new 'username', 'password'
|
33
|
+
|
34
|
+
# Then you may want to check if your username / password are ok
|
35
|
+
if client.verify_credentials.ok?
|
36
|
+
|
37
|
+
# Now you can use the API
|
38
|
+
# Let's search a good anime!
|
39
|
+
results = client.search_anime 'K-On'
|
40
|
+
|
41
|
+
# Everything is nicely wrapped in small objects
|
42
|
+
results.sort_by(&:score).reverse!.each do |anime|
|
43
|
+
puts "#{anime.title} (#{anime.english}) - #{anime.score}"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
Nice, isn't it?
|
50
|
+
|
51
|
+
## Usage
|
52
|
+
|
53
|
+
### The Client
|
54
|
+
The client memorizes your username and password (myanimelist.net requires a valid account in order to consume their API) then it allows you to use the API:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
client = MyanimelistClient.new('username', 'password')
|
58
|
+
```
|
59
|
+
|
60
|
+
### Verify Credentials
|
61
|
+
Check your username / password with `#verify_credentials`:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
user = client.verify_credentials # => MyanimelistClient::UserResponse
|
65
|
+
|
66
|
+
user.ok? # true when everything went right
|
67
|
+
user.error? # true when an error occured
|
68
|
+
user.raw # the raw response from the API or the error message
|
69
|
+
```
|
70
|
+
|
71
|
+
### Search Anime
|
72
|
+
Search anime with `#search_anime`:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
results = client.search_anime('anime name')
|
76
|
+
# => MyanimelistClient::SearchResponse
|
77
|
+
|
78
|
+
results.length # => Fixnum
|
79
|
+
results.size # => Fixnum
|
80
|
+
results.empty? # => true or false
|
81
|
+
results.to_a # => Array
|
82
|
+
results[0] # => MyanimelistClient::SearchEntry or nil
|
83
|
+
|
84
|
+
# It includes Ruby's Enumerable module:
|
85
|
+
results.each do |anime|
|
86
|
+
anime.id # => String or nil
|
87
|
+
anime.title # => String or nil
|
88
|
+
anime.english # => String or nil
|
89
|
+
anime.synonyms # => String or nil
|
90
|
+
anime.episodes # => Fixnum or nil
|
91
|
+
anime.score # => Float or nil
|
92
|
+
anime.type # => String or nil
|
93
|
+
anime.status # => String or nil
|
94
|
+
anime.start_date # => String or nil
|
95
|
+
anime.end_date # => String or nil
|
96
|
+
anime.synopsis # => String or nil
|
97
|
+
anime.image # => String or nil
|
98
|
+
|
99
|
+
anime.manga? # => true
|
100
|
+
anime.anime? # => false
|
101
|
+
anime.upcoming? # => true when the anime is not yet aired
|
102
|
+
anime.ongoing? # => true when the anime is currently airing
|
103
|
+
anime.finished? # => true when the anime is finished
|
104
|
+
|
105
|
+
anime.ok? # when no error occured
|
106
|
+
anime.error? # when an error occured
|
107
|
+
anime.raw # => String containing the raw response from the API or the error message
|
108
|
+
|
109
|
+
anime.to_h # => Hash
|
110
|
+
end
|
111
|
+
|
112
|
+
```
|
113
|
+
|
114
|
+
### Search Manga
|
115
|
+
Search manga with `#search_manga`:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
results = client.search_manga('anime name')
|
119
|
+
# => MyanimelistClient::SearchResponse
|
120
|
+
|
121
|
+
results.length # => Fixnum
|
122
|
+
results.size # => Fixnum
|
123
|
+
results.empty? # => true or false
|
124
|
+
results.to_a # => Array
|
125
|
+
results[0] # => MyanimelistClient::SearchEntry or nil
|
126
|
+
|
127
|
+
# It includes Ruby's Enumerable module:
|
128
|
+
results.each do |manga|
|
129
|
+
manga.id # => String or nil
|
130
|
+
manga.title # => String or nil
|
131
|
+
manga.english # => String or nil
|
132
|
+
manga.synonyms # => String or nil
|
133
|
+
manga.chapters # => Fixnum or nil
|
134
|
+
manga.volumes # => Fixnum or nil
|
135
|
+
manga.score # => Float or nil
|
136
|
+
manga.type # => String or nil
|
137
|
+
manga.status # => String or nil
|
138
|
+
manga.start_date # => String or nil
|
139
|
+
manga.end_date # => String or nil
|
140
|
+
manga.synopsis # => String or nil
|
141
|
+
manga.image # => String or nil
|
142
|
+
|
143
|
+
manga.manga? # => true
|
144
|
+
manga.anime? # => false
|
145
|
+
manga.upcoming? # => true when the manga is not yet published
|
146
|
+
manga.ongoing? # => true when the manga is currently publishing
|
147
|
+
manga.finished? # => true when the manga is finished
|
148
|
+
|
149
|
+
manga.ok? # when no error occured
|
150
|
+
manga.error? # when an error occured
|
151
|
+
manga.raw # => String containing the raw response from the API or the error message
|
152
|
+
|
153
|
+
manga.to_h # => Hash
|
154
|
+
end
|
155
|
+
|
156
|
+
```
|
157
|
+
|
158
|
+
## Contributing
|
159
|
+
Report issues at https://github.com/Oli4242/myanimelist_client.
|
160
|
+
|
161
|
+
If you want to make a pull request:
|
162
|
+
|
163
|
+
1. Fork it
|
164
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
165
|
+
3. Write and run the specs before you commit (`rake spec`)
|
166
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
167
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
168
|
+
6. Create new Pull Request
|
169
|
+
|
170
|
+
## Thanks
|
171
|
+
Thanks to [harveyico](https://github.com/harveyico) for his [myanimelist gem](https://github.com/harveyico/myanimelist), it helped me (I was using it before and its code kinda influenced me).
|
172
|
+
|
173
|
+
Of course, thanks to the myanimelist.net team for their work.
|
174
|
+
|
175
|
+
## License MIT
|
176
|
+
> The MIT License (MIT)
|
177
|
+
>
|
178
|
+
> Copyright (c) 2016 Oli4242
|
179
|
+
>
|
180
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
181
|
+
> of this software and associated documentation files (the "Software"), to deal
|
182
|
+
> in the Software without restriction, including without limitation the rights
|
183
|
+
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
184
|
+
> copies of the Software, and to permit persons to whom the Software is
|
185
|
+
> furnished to do so, subject to the following conditions:
|
186
|
+
>
|
187
|
+
> The above copyright notice and this permission notice shall be included in
|
188
|
+
> all copies or substantial portions of the Software.
|
189
|
+
>
|
190
|
+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
191
|
+
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
192
|
+
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
193
|
+
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
194
|
+
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
195
|
+
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
196
|
+
> THE SOFTWARE.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "myanimelist_client"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
require 'myanimelist_client/version'
|
5
|
+
require 'myanimelist_client/myanimelist_client'
|
6
|
+
require 'myanimelist_client/user_response'
|
7
|
+
require 'myanimelist_client/search_response'
|
8
|
+
require 'myanimelist_client/search_entry'
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# This is the main class. It represents a client that can consume the {https://myanimelist.net/modules.php?go=api MyAnimeList.net API}.
|
2
|
+
#
|
3
|
+
# It allows to search for anime and manga titles as well as verify your username / password.
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
# require 'myanimelist_client'
|
7
|
+
#
|
8
|
+
# # MyAnimeList requires a valid account in order to consume their API:
|
9
|
+
# client = MyanimelistClient.new 'username', 'password'
|
10
|
+
#
|
11
|
+
# # Verify credentials:
|
12
|
+
# user = client.verify_credentials # => UserResponse
|
13
|
+
#
|
14
|
+
# if user.error?
|
15
|
+
# STDERR.puts "An error occured: #{user.raw}"
|
16
|
+
# exit
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # Search anime:
|
20
|
+
# results = client.search_anime 'anime name' # => SearchResponse
|
21
|
+
#
|
22
|
+
# puts 'Error...' if results.error?
|
23
|
+
# puts 'Found nothing...' if results.ok? && results.empty?
|
24
|
+
#
|
25
|
+
# results.sort_by(:score).reverse!.each do |anime|
|
26
|
+
# puts "#{anime.title} - #{anime.score}"
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # Search manga:
|
30
|
+
# results = client.search_manga 'manga name' # => SearchResponse
|
31
|
+
#
|
32
|
+
# results.select{ |manga| manga.volumes < 10 }.each do |manga|
|
33
|
+
# puts "#{manga.title} - #{manga.english}"
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# @attr [String] username Returns the username
|
37
|
+
# @attr [String] password Returns the password
|
38
|
+
#
|
39
|
+
class MyanimelistClient
|
40
|
+
attr_accessor :username, :password
|
41
|
+
|
42
|
+
# @param [String] username A valid myanimelist username
|
43
|
+
# @param [String] password A valid myanimelist password
|
44
|
+
#
|
45
|
+
def initialize username, password
|
46
|
+
@username = username
|
47
|
+
@password = password
|
48
|
+
end
|
49
|
+
|
50
|
+
# Allows to check username/password.
|
51
|
+
# @see https://myanimelist.net/modules.php?go=api#verifycred The MyAnimeList's API Documentation about verify_credentials.xml
|
52
|
+
# @return [UserResponse] The API response or the error message nicely wraped in an object.
|
53
|
+
#
|
54
|
+
def verify_credentials
|
55
|
+
begin
|
56
|
+
response = RestClient::Request.execute(
|
57
|
+
method: :get,
|
58
|
+
url: 'https://myanimelist.net/api/account/verify_credentials.xml',
|
59
|
+
user: @username,
|
60
|
+
password: @password
|
61
|
+
)
|
62
|
+
UserResponse.new response.body
|
63
|
+
rescue RestClient::ExceptionWithResponse => e
|
64
|
+
UserResponse.new e.response.body
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Allows to search anime titles.
|
69
|
+
# @see https://myanimelist.net/modules.php?go=api#animemangasearch The MyAnimeList's API Documentation about search.xml
|
70
|
+
# @param [String] query The search query.
|
71
|
+
# @return [SearchResponse] The API response or the error message nicely wraped in an object.
|
72
|
+
#
|
73
|
+
def search_anime query
|
74
|
+
begin
|
75
|
+
escaped_query = CGI::escape query
|
76
|
+
response = RestClient::Request.execute(
|
77
|
+
method: :get,
|
78
|
+
url: "https://myanimelist.net/api/anime/search.xml?q=#{escaped_query}",
|
79
|
+
user: @username,
|
80
|
+
password: @password
|
81
|
+
)
|
82
|
+
SearchResponse.new response.body
|
83
|
+
rescue RestClient::ExceptionWithResponse => e
|
84
|
+
SearchResponse.new e.response.body, :error
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Allows to search manga titles.
|
89
|
+
# @see https://myanimelist.net/modules.php?go=api#animemangasearch The MyAnimeList's API Documentation about search.xml
|
90
|
+
# @param [String] query The search query.
|
91
|
+
# @return [SearchResponse] The API response or the error message nicely wraped in an object.
|
92
|
+
#
|
93
|
+
def search_manga query
|
94
|
+
begin
|
95
|
+
escaped_query = CGI::escape query
|
96
|
+
response = RestClient::Request.execute(
|
97
|
+
method: :get,
|
98
|
+
url: "https://myanimelist.net/api/manga/search.xml?q=#{escaped_query}",
|
99
|
+
user: @username,
|
100
|
+
password: @password
|
101
|
+
)
|
102
|
+
SearchResponse.new response.body
|
103
|
+
rescue RestClient::ExceptionWithResponse => e
|
104
|
+
SearchResponse.new e.response.body, :error
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# This class is used to reprensent an entry within a {SearchResponse}. It can describe either an anime or a manga.
|
2
|
+
#
|
3
|
+
# @example
|
4
|
+
# require 'myanimelist_client'
|
5
|
+
#
|
6
|
+
# client = MyanimelistClient.new 'username', 'password'
|
7
|
+
#
|
8
|
+
# client.search_anime('anime name').each do |entry|
|
9
|
+
# # entry is a SearchResponse.
|
10
|
+
#
|
11
|
+
# # It exposes all its attributes:
|
12
|
+
# entry.id # => String or nil
|
13
|
+
# entry.title # => String or nil
|
14
|
+
# entry.english # => String or nil
|
15
|
+
# entry.synonyms # => String or nil
|
16
|
+
# entry.episodes # => Fixnum or nil
|
17
|
+
# entry.chapters # => Fixnum or nil
|
18
|
+
# entry.volumes # => Fixnum or nil
|
19
|
+
# entry.score # => Float or nil
|
20
|
+
# entry.type # => String or nil
|
21
|
+
# entry.status # => String or nil
|
22
|
+
# entry.start_date # => String or nil
|
23
|
+
# entry.end_date # => String or nil
|
24
|
+
# entry.synopsis # => String or nil
|
25
|
+
# entry.image # => String or nil
|
26
|
+
#
|
27
|
+
# # It provides some useful predicates:
|
28
|
+
# entry.manga? # => true or false
|
29
|
+
# entry.anime? # => true or false
|
30
|
+
# entry.upcoming? # => true or false
|
31
|
+
# entry.ongoing? # => true or false
|
32
|
+
# entry.finished? # => true or false
|
33
|
+
#
|
34
|
+
# # It can be converted to a hash:
|
35
|
+
# entry.to_h # => Hash
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# @attr [String, nil] id Returns the ID.
|
39
|
+
# @attr [String, nil] title Returns the title.
|
40
|
+
# @attr [String, nil] english Returns the english title.
|
41
|
+
# @attr [String, nil] synonyms Returns the synonyms.
|
42
|
+
# @attr [Fixnum, nil] episodes Returns the number of episodes (+nil+ when the entry describes a manga).
|
43
|
+
# @attr [Fixnum, nil] chapters Returns the number of chapters (+nil+ when the entry describes an anime).
|
44
|
+
# @attr [Fixnum, nil] volumes Returns the number of volumes (+nil+ when the entry describes an anime).
|
45
|
+
# @attr [Float, nil] score Returns the score.
|
46
|
+
# @attr [String, nil] type Returns the type.
|
47
|
+
# @attr [String, nil] status Returns the status.
|
48
|
+
# @attr [String, nil] start_date Returns the start date.
|
49
|
+
# @attr [String, nil] end_date Returns the end date.
|
50
|
+
# @attr [String, nil] synopsis Returns the synopsis.
|
51
|
+
# @attr [String, nil] image Returns the image's URL.
|
52
|
+
#
|
53
|
+
class MyanimelistClient::SearchEntry
|
54
|
+
|
55
|
+
# The list of attributes defining the entry for internal usage.
|
56
|
+
ATTRIBUTES = %w(
|
57
|
+
id
|
58
|
+
title
|
59
|
+
english
|
60
|
+
synonyms
|
61
|
+
episodes
|
62
|
+
chapters
|
63
|
+
volumes
|
64
|
+
score
|
65
|
+
type
|
66
|
+
status
|
67
|
+
start_date
|
68
|
+
end_date
|
69
|
+
synopsis
|
70
|
+
image
|
71
|
+
)
|
72
|
+
|
73
|
+
# attr_reader *ATTRIBUTES # this line cause a warning in yard
|
74
|
+
send :attr_reader, *ATTRIBUTES # this line doesn't... :/
|
75
|
+
|
76
|
+
# @param [Hash] options A hash used to hydrate the object.
|
77
|
+
def initialize options={}
|
78
|
+
ATTRIBUTES.each do |attribute|
|
79
|
+
instance_variable_set "@#{attribute}", options[attribute] || options[attribute.to_sym]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Creates a hash representing the entry.
|
84
|
+
# @return [Hash]
|
85
|
+
def to_h
|
86
|
+
values = ATTRIBUTES.map{|attribute| send attribute }
|
87
|
+
Hash[ATTRIBUTES.zip values]
|
88
|
+
end
|
89
|
+
|
90
|
+
# Performs a loose equality based on the value of the attributes (see {ATTRIBUTES}).
|
91
|
+
def == other
|
92
|
+
ATTRIBUTES.each do |attribute|
|
93
|
+
if !other.respond_to?(attribute) || send(attribute) != other.send(attribute)
|
94
|
+
return false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
true
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns +true+ when the entry describes an anime.
|
101
|
+
def anime?
|
102
|
+
!!@episodes
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns +true+ when the entry describes a manga.
|
106
|
+
def manga?
|
107
|
+
!!(@chapters && @volumes)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns +true+ when the anime is not yet aired / when the manga is not yet published.
|
111
|
+
def upcoming?
|
112
|
+
!!(/not\s+yet/i =~ @status)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns +true+ when the anime is currently airing / when the manga is currently publishing.
|
116
|
+
def ongoing?
|
117
|
+
!!(/currently|publishing/i =~ @status)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns +true+ when the anime or manga is finished.
|
121
|
+
def finished?
|
122
|
+
!!(/finished/i =~ @status)
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# This class represents a response to a search request. It is returned by {#search_anime} and {#search_manga}.
|
2
|
+
#
|
3
|
+
# +SearchResponse+ is responsible for parsing and wraping the XML response from the myanimelist API (or the error message).
|
4
|
+
#
|
5
|
+
# It wraps every entry in a {SearchEntry} instance and it includes the Ruby's +Enumerable+ module so it is easy to iterate over, sort it, etc.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# require 'myanimelist_client'
|
9
|
+
#
|
10
|
+
# client = MyanimelistClient.new 'username', 'password'
|
11
|
+
#
|
12
|
+
# results = client.search_anime 'anime name'
|
13
|
+
# # => SearchResponse
|
14
|
+
#
|
15
|
+
# # It provides two predicates for error handling:
|
16
|
+
# results.ok? # => true or false
|
17
|
+
# results.error? # => true or false
|
18
|
+
#
|
19
|
+
# # On error, results.raw may contain an error message:
|
20
|
+
# if results.error?
|
21
|
+
# results.raw # => String or nil
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # On success you can browse the results:
|
25
|
+
# if results.ok?
|
26
|
+
# # It provides basic informations:
|
27
|
+
# results.length # => Fixnum
|
28
|
+
# results.empty? # => true or false
|
29
|
+
#
|
30
|
+
# # It is browsable more or less like an Array would be:
|
31
|
+
# results.first == results[0]
|
32
|
+
# # => true
|
33
|
+
#
|
34
|
+
# # It is enumerable so you can use #each, #map, #sort_by, #select, etc.
|
35
|
+
# # An exemple:
|
36
|
+
# top3 = results.sort_by(&:score).reverse!.take(3).to_a
|
37
|
+
# top3.each_with_index do |entry, index|
|
38
|
+
# puts "#{index+1}. #{entry.title} - #{entry.score}"
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# # Yes, it is awesome ! :3
|
42
|
+
#
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# @attr [String, nil] raw Returns the raw response from the API or the error message.
|
46
|
+
#
|
47
|
+
class MyanimelistClient::SearchResponse
|
48
|
+
include Enumerable
|
49
|
+
attr_reader :raw
|
50
|
+
|
51
|
+
# @param [String, nil] raw_xml The raw XML response from the API or an error message.
|
52
|
+
# @param [String, nil] error The error flag, set it to true if an error occured.
|
53
|
+
def initialize raw_xml, error=false
|
54
|
+
@raw = raw_xml
|
55
|
+
@error = !!error
|
56
|
+
@entries = []
|
57
|
+
|
58
|
+
parsed_xml = Nokogiri::XML raw_xml
|
59
|
+
animes = parsed_xml.css 'anime entry'
|
60
|
+
mangas = parsed_xml.css 'manga entry'
|
61
|
+
|
62
|
+
(animes + mangas).each do |entry|
|
63
|
+
@entries.push MyanimelistClient::SearchEntry.new(
|
64
|
+
id: entry.at_css('id')&.content,
|
65
|
+
title: entry.at_css('title')&.content,
|
66
|
+
english: entry.at_css('english')&.content,
|
67
|
+
synonyms: entry.at_css('synonyms')&.content,
|
68
|
+
episodes: entry.at_css('episodes')&.content&.to_i,
|
69
|
+
chapters: entry.at_css('chapters')&.content&.to_i,
|
70
|
+
volumes: entry.at_css('volumes')&.content&.to_i,
|
71
|
+
score: entry.at_css('score')&.content&.to_f,
|
72
|
+
type: entry.at_css('type')&.content,
|
73
|
+
status: entry.at_css('status')&.content,
|
74
|
+
start_date: entry.at_css('start_date')&.content,
|
75
|
+
end_date: entry.at_css('end_date')&.content,
|
76
|
+
synopsis: entry.at_css('synopsis')&.content,
|
77
|
+
image: entry.at_css('image')&.content
|
78
|
+
)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Similar to +Array+'s +#each+.
|
83
|
+
# @return [self, Enumerator]
|
84
|
+
def each &block
|
85
|
+
if block_given?
|
86
|
+
@entries.each &block
|
87
|
+
self
|
88
|
+
else
|
89
|
+
@entries.each
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns the number of entries returned by the search request.
|
94
|
+
# @return [Fixnum] The number of entries (either animes or mangas) in the search response.
|
95
|
+
def length
|
96
|
+
@entries.size
|
97
|
+
end
|
98
|
+
|
99
|
+
alias_method :size, :length
|
100
|
+
|
101
|
+
# Is it empty?
|
102
|
+
def empty?
|
103
|
+
@entries.empty?
|
104
|
+
end
|
105
|
+
|
106
|
+
# Allows to browse the entries like with an array.
|
107
|
+
# @param [Fixnum] index The index of the desired entry.
|
108
|
+
# @return [SearchEntry, nil]
|
109
|
+
def [] index
|
110
|
+
@entries[index]
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns +true+ if an error occured.
|
114
|
+
def error?
|
115
|
+
@error
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns +true+ if no error occured.
|
119
|
+
def ok?
|
120
|
+
not error?
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# This class represents a User. It is returned by {#verify_credentials}.
|
2
|
+
#
|
3
|
+
# +UserResponse+ is responsible for parsing and wraping the XML (or any error message) from the API.
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
# require 'myanimelist_client'
|
7
|
+
#
|
8
|
+
# client = MyanimelistClient.new 'username', 'password'
|
9
|
+
#
|
10
|
+
# user = client.verify_credentials
|
11
|
+
# # => UserResponse
|
12
|
+
#
|
13
|
+
# # It provides two predicates to handle login errors:
|
14
|
+
# user.error? # => true or false
|
15
|
+
# user.ok? # => true or false
|
16
|
+
#
|
17
|
+
# # On error, user.raw may contain an error message:
|
18
|
+
# if user.error?
|
19
|
+
# user.raw # => String or nil
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # On success you can access to user's attributes:
|
23
|
+
# if user.ok?
|
24
|
+
# user.id # => String or nil
|
25
|
+
# user.username # => String or nil
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# @attr [String, nil] raw Returns the raw response from the API. Or the raw error message.
|
29
|
+
# @attr [String, nil] id Return the MyAnimeList ID of the current account.
|
30
|
+
# @attr [String, nil] username Returns the MyAnimeList username of the current account.
|
31
|
+
#
|
32
|
+
class MyanimelistClient::UserResponse
|
33
|
+
attr_reader :raw, :id, :username
|
34
|
+
|
35
|
+
# @param [String, nil] raw_xml The raw response from the API or an error message (or even +nil+).
|
36
|
+
def initialize raw_xml
|
37
|
+
@raw = raw_xml
|
38
|
+
|
39
|
+
parsed_xml = Nokogiri::XML raw_xml
|
40
|
+
@id = parsed_xml.at_css('id')&.content
|
41
|
+
@username = parsed_xml.at_css('username')&.content
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns +true+ if an error occured.
|
45
|
+
def error?
|
46
|
+
@raw.nil? || @id.nil? || @username.nil?
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns +true+ if no error occured.
|
50
|
+
def ok?
|
51
|
+
not error?
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'myanimelist_client/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "myanimelist_client"
|
8
|
+
spec.version = MyanimelistClient::VERSION
|
9
|
+
spec.authors = ["Oli4242"]
|
10
|
+
spec.email = ["Oli4242@users.noreply.github.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A client for the MyAnimeList.net API}
|
13
|
+
# spec.description = %q{TODO: Write a longer description or delete this line.}
|
14
|
+
spec.homepage = "https://github.com/Oli4242/myanimelist_client"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
21
|
+
else
|
22
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
23
|
+
"public gem pushes."
|
24
|
+
end
|
25
|
+
|
26
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
27
|
+
f.match(%r{^(test|spec|features)/})
|
28
|
+
end
|
29
|
+
spec.bindir = "exe"
|
30
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ["lib"]
|
32
|
+
|
33
|
+
spec.required_ruby_version = '>= 2.3'
|
34
|
+
|
35
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
36
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
37
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
38
|
+
spec.add_development_dependency "yard", "~> 0.9"
|
39
|
+
|
40
|
+
spec.add_dependency "rest-client", "~> 2.0"
|
41
|
+
spec.add_dependency "nokogiri", "~> 1.6"
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: myanimelist_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Oli4242
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-11-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: yard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.9'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.9'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rest-client
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: nokogiri
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.6'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.6'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- Oli4242@users.noreply.github.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".rspec"
|
106
|
+
- ".travis.yml"
|
107
|
+
- ".yardopts"
|
108
|
+
- Gemfile
|
109
|
+
- LICENSE.txt
|
110
|
+
- README.md
|
111
|
+
- Rakefile
|
112
|
+
- bin/console
|
113
|
+
- bin/setup
|
114
|
+
- lib/myanimelist_client.rb
|
115
|
+
- lib/myanimelist_client/myanimelist_client.rb
|
116
|
+
- lib/myanimelist_client/search_entry.rb
|
117
|
+
- lib/myanimelist_client/search_response.rb
|
118
|
+
- lib/myanimelist_client/user_response.rb
|
119
|
+
- lib/myanimelist_client/version.rb
|
120
|
+
- myanimelist_client.gemspec
|
121
|
+
homepage: https://github.com/Oli4242/myanimelist_client
|
122
|
+
licenses:
|
123
|
+
- MIT
|
124
|
+
metadata:
|
125
|
+
allowed_push_host: https://rubygems.org
|
126
|
+
post_install_message:
|
127
|
+
rdoc_options: []
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '2.3'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 2.5.1
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: A client for the MyAnimeList.net API
|
146
|
+
test_files: []
|