mangadex 5.3.3.2 → 5.4.11
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 +4 -4
- data/Dockerfile +7 -0
- data/Gemfile.lock +7 -5
- data/README.md +335 -1
- data/bin/console +14 -7
- data/docker-compose.yml +9 -0
- data/docs/authentication.md +1 -4
- data/lib/config.rb +5 -7
- data/lib/mangadex/api/response.rb +22 -0
- data/lib/mangadex/api/user.rb +49 -11
- data/lib/mangadex/api/version_checker.rb +1 -1
- data/lib/mangadex/artist.rb +20 -1
- data/lib/mangadex/at_home.rb +30 -0
- data/lib/mangadex/auth.rb +22 -5
- data/lib/mangadex/author.rb +2 -0
- data/lib/mangadex/chapter.rb +5 -14
- data/lib/mangadex/custom_list.rb +2 -1
- data/lib/mangadex/internal/context.rb +8 -7
- data/lib/mangadex/internal/definition.rb +7 -1
- data/lib/mangadex/internal/request.rb +11 -4
- data/lib/mangadex/internal/with_attributes.rb +5 -2
- data/lib/mangadex/manga.rb +23 -4
- data/lib/mangadex/relationship.rb +7 -2
- data/lib/mangadex/scanlation_group.rb +4 -0
- data/lib/mangadex/types.rb +3 -0
- data/lib/mangadex/version.rb +3 -3
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 29160bf116b71505a8b9697dd7c3940054e7f0b7a837c4f34470b5bff896879c
|
|
4
|
+
data.tar.gz: a245fdd04997fbc3ce6db61d2b3ab831d80df24db6431efc8a9a516a55111617
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0234ba9078a3927eecc7bf84acfde344612c4b4ae3ae0b8b30074daf320d874540bf2dfd4a4e82b7b23cfa534ed919271fa398ad22d0bdd8045ed6c2b2c5d1b6
|
|
7
|
+
data.tar.gz: 4ac033f5cfa89f851d2e8842b50b2bf487b5310c7c92391e0466bf6183a0b0fee1be1bb0b97765e6b8cf4597285edf8c84f7ee38f9892d7592d3cd4171180199
|
data/Dockerfile
ADDED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
mangadex (5.
|
|
4
|
+
mangadex (5.4.11)
|
|
5
5
|
activesupport (~> 6.1)
|
|
6
6
|
psych (~> 4.0.1)
|
|
7
7
|
rest-client (~> 2.1)
|
|
@@ -32,9 +32,9 @@ GEM
|
|
|
32
32
|
i18n (1.8.10)
|
|
33
33
|
concurrent-ruby (~> 1.0)
|
|
34
34
|
method_source (1.0.0)
|
|
35
|
-
mime-types (3.
|
|
35
|
+
mime-types (3.4.1)
|
|
36
36
|
mime-types-data (~> 3.2015)
|
|
37
|
-
mime-types-data (3.
|
|
37
|
+
mime-types-data (3.2022.0105)
|
|
38
38
|
minitest (5.14.4)
|
|
39
39
|
mustermann (1.1.1)
|
|
40
40
|
ruby2_keywords (~> 0.0.1)
|
|
@@ -42,7 +42,8 @@ GEM
|
|
|
42
42
|
pry (0.14.1)
|
|
43
43
|
coderay (~> 1.1)
|
|
44
44
|
method_source (~> 1.0)
|
|
45
|
-
psych (4.0.
|
|
45
|
+
psych (4.0.3)
|
|
46
|
+
stringio
|
|
46
47
|
public_suffix (4.0.6)
|
|
47
48
|
rack (2.2.3)
|
|
48
49
|
rack-protection (2.1.0)
|
|
@@ -82,9 +83,10 @@ GEM
|
|
|
82
83
|
smart_properties (1.16.3)
|
|
83
84
|
sorbet (0.5.9152)
|
|
84
85
|
sorbet-static (= 0.5.9152)
|
|
85
|
-
sorbet-runtime (0.5.
|
|
86
|
+
sorbet-runtime (0.5.9542)
|
|
86
87
|
sorbet-static (0.5.9152-universal-darwin-20)
|
|
87
88
|
sorbet-static (0.5.9152-x86_64-linux)
|
|
89
|
+
stringio (3.0.1)
|
|
88
90
|
tilt (2.0.10)
|
|
89
91
|
tzinfo (2.0.4)
|
|
90
92
|
concurrent-ruby (~> 1.0)
|
data/README.md
CHANGED
|
@@ -23,7 +23,341 @@ Or install it yourself as:
|
|
|
23
23
|
## Usage
|
|
24
24
|
|
|
25
25
|
Please note that I tried my best to follow Mangadex's naming conventions for [their documentation](https://api.mangadex.org). Track the progress [here in an issue](https://github.com/thedrummeraki/mangadex/issues/5).
|
|
26
|
-
|
|
26
|
+
Although a work a in progress, feel free to [check this out](lib/mangadex).
|
|
27
|
+
|
|
28
|
+
### Basic Usage
|
|
29
|
+
|
|
30
|
+
Here's a couple of cool things you can do with the gem:
|
|
31
|
+
|
|
32
|
+
#### Get a list of manga
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
response = Mangadex::Manga.list
|
|
36
|
+
manga = response.data # Array of #<Mangadex::Manga>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
#### Get a manga by id, with cover_art
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
manga_id = 'd86cf65b-5f6c-437d-a0af-19a31f94ec55'
|
|
43
|
+
response = Mangadex::Manga.get(manga_id, includes: :cover_art)
|
|
44
|
+
entity = response.data # Object of #<Mangadex::Manga>
|
|
45
|
+
|
|
46
|
+
# Original size
|
|
47
|
+
entity.cover_art.image_url(size: :original)
|
|
48
|
+
entity.cover_art.image_url(size: :medium)
|
|
49
|
+
entity.cover_art.image_url(size: :small) # default size
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### Get a manga's chapter list, ordered by volume and chapter number
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
manga_id = 'd86cf65b-5f6c-437d-a0af-19a31f94ec55'
|
|
56
|
+
manga_response = Mangadex::Manga.get(manga_id, includes: :cover_art)
|
|
57
|
+
entity = manga_response.data
|
|
58
|
+
|
|
59
|
+
chapter_response = Mangadex::Chapter.list(
|
|
60
|
+
manga: entity.id,
|
|
61
|
+
order: { volume: 'asc', chapter: 'asc' },
|
|
62
|
+
translated_language: 'en',
|
|
63
|
+
)
|
|
64
|
+
chapters = chapter_response.data # Array of #<Mangadex::Chapter>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### Get a chapter's pages
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
chapter_id = 'e7bb1892-7f83-4a89-bccc-0d6d403a85fc'
|
|
71
|
+
chapter = Mangadex::Chapter.get(chapter_id).data
|
|
72
|
+
pages = chapter.page_urls # Data saver true by default
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Search for manga by title
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
response = Mangadex::Manga.list(title: 'Ijiranaide nagatoro')
|
|
79
|
+
found_manga = response.data
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### Authenticate
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
Mangadex::Auth.login(username: 'username', password: 'password') do |user|
|
|
86
|
+
# `user` is of type Mangadex::Api::User
|
|
87
|
+
puts(user.mangadex_user_id)
|
|
88
|
+
puts(user.session)
|
|
89
|
+
puts(user.refresh)
|
|
90
|
+
puts(user.session_valid_until)
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
You can access the authenticated user by using context:
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
user = Mangadex.context.user
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### Refresh the user's token
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
Mangadex.context.user.refresh_session! do |user|
|
|
104
|
+
# `user` is of type Mangadex::Api::User
|
|
105
|
+
puts(user.mangadex_user_id)
|
|
106
|
+
puts(user.session)
|
|
107
|
+
puts(user.refresh)
|
|
108
|
+
puts(user.session_valid_until)
|
|
109
|
+
end
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### Create an public MDList, add then remove a manga
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
Mangadex::Auth.login(...)
|
|
116
|
+
response = Mangadex::CustomList.create(name: 'My awesome list!', visibility: 'public')
|
|
117
|
+
custom_list = response.data
|
|
118
|
+
|
|
119
|
+
manga_id = 'd86cf65b-5f6c-437d-a0af-19a31f94ec55'
|
|
120
|
+
# Add the manga
|
|
121
|
+
custom_list.add_manga(manga_id)
|
|
122
|
+
|
|
123
|
+
# Remove the manga
|
|
124
|
+
custom_list.remove_manga(manga_id)
|
|
125
|
+
|
|
126
|
+
# Get manga list
|
|
127
|
+
manga = custom_list.manga_details.data # Array of #<Mangadex::Manga>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Are you on Rails?
|
|
131
|
+
|
|
132
|
+
This gem tries its best to be agnostic to popular frameworks like Rails. Here's however a couple of things to can do to integrate the gem to your project.
|
|
133
|
+
|
|
134
|
+
First, add the gem to your `Gemfile`.
|
|
135
|
+
|
|
136
|
+
#### Configurating the gem
|
|
137
|
+
|
|
138
|
+
Create a initilizer file to `config/initializers/mangadex.rb`. You can add the following:
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
Mangadex.configure do |config|
|
|
142
|
+
# Override the default content ratings
|
|
143
|
+
config.default_content_ratings = %w(safe suggestive)
|
|
144
|
+
|
|
145
|
+
# Override the Mangadex API URL (ie: proxy)
|
|
146
|
+
config.mangadex_url = 'https://my-proxy-mangadex-url.com'
|
|
147
|
+
end
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### Authenticate your users
|
|
151
|
+
|
|
152
|
+
This could be useful if you want to support authentication. You will need to persist your user's session, refresh token and session expiry date.
|
|
153
|
+
|
|
154
|
+
##### Persist the user information
|
|
155
|
+
|
|
156
|
+
If you haven't done so, create your user.
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
class CreateUsers < ActiveRecord::Migration[6.1]
|
|
160
|
+
def change
|
|
161
|
+
create_table :users do |t|
|
|
162
|
+
t.string :mangadex_user_id, null: false
|
|
163
|
+
t.string :username
|
|
164
|
+
t.string :session
|
|
165
|
+
t.string :refresh
|
|
166
|
+
t.datetime :session_valid_until
|
|
167
|
+
|
|
168
|
+
t.timestamps
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Already created your `User` class? Make sure it has all of the following:
|
|
176
|
+
- `mangade_user_id`: ID used to identify your user on Mangadex
|
|
177
|
+
- `username`: Your username
|
|
178
|
+
- `session`: The session token (valid for 15 minutes)
|
|
179
|
+
- `refresh`: The refresh token, used to refresh the session (valid for 1 month)
|
|
180
|
+
- `session_valid_until`: The time `session` session expires at
|
|
181
|
+
|
|
182
|
+
If anything is missing, create a migration.
|
|
183
|
+
|
|
184
|
+
#### Authentication flow on the controller
|
|
185
|
+
|
|
186
|
+
Add these methods to your controller's helper (ie: `ApplicationHelper`):
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
module ApplicationHelper
|
|
190
|
+
def current_user
|
|
191
|
+
@current_user ||= User.find_by(id: session[:id])
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def logged_in?
|
|
195
|
+
current_user.present?
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def log_in(user)
|
|
199
|
+
# `user` is an instance of your `User` class
|
|
200
|
+
session[:id] = user.id6
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def log_out
|
|
204
|
+
# Logout from Mangadex
|
|
205
|
+
Mangadex::Auth.logout
|
|
206
|
+
|
|
207
|
+
# Remove the session
|
|
208
|
+
session.delete(:id)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
First make sure `ApplicationController` includes the helper above
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
class ApplicationController < ActionController::Base
|
|
217
|
+
include ApplicationHelper
|
|
218
|
+
|
|
219
|
+
# ...
|
|
220
|
+
end
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
We recommend creating a controller for authentication. Here's how you can implement the login and logout actions:
|
|
224
|
+
|
|
225
|
+
```ruby
|
|
226
|
+
# app/controllers/session_controller.rb
|
|
227
|
+
class SessionController < ApplicationController
|
|
228
|
+
# GET /login
|
|
229
|
+
def new
|
|
230
|
+
# render the login form
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# POST /login
|
|
234
|
+
def create
|
|
235
|
+
username = params[:username]
|
|
236
|
+
password = params[:password]
|
|
237
|
+
|
|
238
|
+
# You can also use `email` instead of `username` to log in
|
|
239
|
+
user = Mangadex::Auth.login(username: username, password: password) do |mangadex_user|
|
|
240
|
+
# Find the user by mangadex user id (or initialize if it doesn't exist)
|
|
241
|
+
our_user = User.find_or_initialize_by(mangadex_user_id: mangadex_user.mangadex_user_id) do |new_user|
|
|
242
|
+
new_user.username = mangadex_user.data.username
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Update the session info data
|
|
246
|
+
our_user.session = mangadex_user.session
|
|
247
|
+
our_user.refresh = mangadex_user.refresh
|
|
248
|
+
our_user.session_valid_until = mangadex_user.session_valid_until
|
|
249
|
+
|
|
250
|
+
# ...then save the user
|
|
251
|
+
our_user.save!
|
|
252
|
+
our_user
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# `user` will be an instance of your `User` class
|
|
256
|
+
# Now, we can log in then redirect to the root.
|
|
257
|
+
log_in(user)
|
|
258
|
+
redirect_to(root_path)
|
|
259
|
+
rescue Mangadex::Errors::AuthenticationError => error
|
|
260
|
+
# See https://api.mangadex.org/docs.html to learn more about errors
|
|
261
|
+
Rails.logger.error(error.response.errors)
|
|
262
|
+
|
|
263
|
+
# Handle authentication errors here
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# DELETE /logout
|
|
267
|
+
def destroy
|
|
268
|
+
log_out
|
|
269
|
+
|
|
270
|
+
redirect_to(root_path)
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Finally, add the routes.
|
|
276
|
+
|
|
277
|
+
```ruby
|
|
278
|
+
# config/routes.rb
|
|
279
|
+
Rails.application.routes.draw do
|
|
280
|
+
# ...
|
|
281
|
+
get '/login' => 'session#new'
|
|
282
|
+
post '/login' => 'session#create'
|
|
283
|
+
delete '/logout' => 'session#destroy'
|
|
284
|
+
end
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
#### Protected resources
|
|
288
|
+
|
|
289
|
+
Here's an example of a controller that requires every action to be logged in. This is based on the steps above.
|
|
290
|
+
|
|
291
|
+
```ruby
|
|
292
|
+
class ProtectedController < ApplicationController
|
|
293
|
+
before_action :ensure_logged_in!
|
|
294
|
+
|
|
295
|
+
private
|
|
296
|
+
|
|
297
|
+
def ensure_logged_in!
|
|
298
|
+
return if logged_in?
|
|
299
|
+
|
|
300
|
+
redirect_to(login_path) # go to /login
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
We're going with managing (list, create, show, edit, delete) MDLists (ie: custom lists). __We're not using strong params below to keep things simple, but you should, especially when mutating data (ie: creating and editing)__.
|
|
306
|
+
|
|
307
|
+
```ruby
|
|
308
|
+
class CustomListsController < ProtectedController
|
|
309
|
+
# GET /custom_list
|
|
310
|
+
def index
|
|
311
|
+
@custom_lists = Mangadex::CustomList.list
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# GET /custom_list/new
|
|
315
|
+
def new
|
|
316
|
+
# new custom list form
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# POST /custom_list
|
|
320
|
+
def create
|
|
321
|
+
@custom_list = Mangadex::CustomList.create(
|
|
322
|
+
name: params[:name],
|
|
323
|
+
visibility: params[:visibility],
|
|
324
|
+
manga: params[:manga], # Manga ID
|
|
325
|
+
)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# GET /custom_list/<id>
|
|
329
|
+
def show
|
|
330
|
+
@custom_list = Mangadex::CustomList.get(params[:id])
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# GET /custom_list/<id>/edit
|
|
334
|
+
def edit
|
|
335
|
+
@custom_list = Mangadex::CustomList.get(params[:id])
|
|
336
|
+
# edit custom list form
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# PUT /custom_list/<id>
|
|
340
|
+
# PATCH /custom_list/<id>
|
|
341
|
+
def update
|
|
342
|
+
# Note: when updating the custom list, be sure to pass in
|
|
343
|
+
# the current version number!
|
|
344
|
+
@custom_list = Mangadex::CustomList.update(
|
|
345
|
+
params[:id],
|
|
346
|
+
{
|
|
347
|
+
name: params[:name],
|
|
348
|
+
visibility: params[:visibility],
|
|
349
|
+
manga: params[:manga],
|
|
350
|
+
version: params[:version].to_i,
|
|
351
|
+
}
|
|
352
|
+
)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# DELETE /custom_list/<id>
|
|
356
|
+
def destroy
|
|
357
|
+
Mangadex::CustomList.delete(params[:id])
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
```
|
|
27
361
|
|
|
28
362
|
## Development
|
|
29
363
|
|
data/bin/console
CHANGED
|
@@ -3,16 +3,23 @@
|
|
|
3
3
|
require "bundler/setup"
|
|
4
4
|
require "mangadex"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
]
|
|
6
|
+
def try_logging_in
|
|
7
|
+
username, password, email = [
|
|
8
|
+
ENV['MD_USERNAME'],
|
|
9
|
+
ENV['MD_PASSWORD'],
|
|
10
|
+
ENV['MD_EMAIL'],
|
|
11
|
+
]
|
|
11
12
|
|
|
12
|
-
if (username || email) && password
|
|
13
|
-
|
|
13
|
+
if (username || email) && password
|
|
14
|
+
Mangadex::Auth.login(username: username, email: email, password: password)
|
|
15
|
+
end
|
|
16
|
+
rescue Mangadex::Errors::StandardError => e
|
|
17
|
+
puts e
|
|
18
|
+
false
|
|
14
19
|
end
|
|
15
20
|
|
|
21
|
+
try_logging_in
|
|
22
|
+
|
|
16
23
|
# You can add fixtures and/or initialization code here to make experimenting
|
|
17
24
|
# with your gem easier. You can also use a different console, if you like.
|
|
18
25
|
|
data/docker-compose.yml
ADDED
data/docs/authentication.md
CHANGED
|
@@ -61,10 +61,7 @@ user.data
|
|
|
61
61
|
|
|
62
62
|
```ruby
|
|
63
63
|
# Refreshes the tokens now (Boolean)
|
|
64
|
-
user.
|
|
65
|
-
|
|
66
|
-
# Refreshes the tokens if expired, then return user itself (Mangadex::Api::User)
|
|
67
|
-
user.with_valid_session
|
|
64
|
+
user.refresh_session!
|
|
68
65
|
|
|
69
66
|
# Returns if user.session has expired (Boolean)
|
|
70
67
|
user.session_expired?
|
data/lib/config.rb
CHANGED
|
@@ -4,11 +4,6 @@ module Mangadex
|
|
|
4
4
|
class Config
|
|
5
5
|
extend T::Sig
|
|
6
6
|
|
|
7
|
-
# Class used to persist users
|
|
8
|
-
# Must respond to: :session, :refresh, :mangadex_user_id
|
|
9
|
-
sig { returns(Class) }
|
|
10
|
-
attr_accessor :user_class
|
|
11
|
-
|
|
12
7
|
# Persisting strategy. See Mangadex::Storage::Base for more details.
|
|
13
8
|
sig { returns(Class) }
|
|
14
9
|
attr_accessor :storage_class
|
|
@@ -16,16 +11,19 @@ module Mangadex
|
|
|
16
11
|
sig { returns(T::Array[ContentRating]) }
|
|
17
12
|
attr_accessor :default_content_ratings
|
|
18
13
|
|
|
14
|
+
sig { returns(String) }
|
|
15
|
+
attr_accessor :mangadex_url
|
|
16
|
+
|
|
19
17
|
sig { void }
|
|
20
18
|
def initialize
|
|
21
|
-
@user_class = Api::User
|
|
22
19
|
@storage_class = Storage::Memory
|
|
23
20
|
@default_content_ratings = ContentRating.parse(['safe', 'suggestive', 'erotica'])
|
|
21
|
+
@mangadex_url = 'https://api.mangadex.org'
|
|
24
22
|
end
|
|
25
23
|
|
|
26
24
|
sig { params(klass: Class).void }
|
|
27
25
|
def user_class=(klass)
|
|
28
|
-
missing_methods = [:session, :refresh, :mangadex_user_id] - klass.
|
|
26
|
+
missing_methods = [:session, :refresh, :mangadex_user_id] - klass.new.methods
|
|
29
27
|
if missing_methods.empty?
|
|
30
28
|
@user_class = klass
|
|
31
29
|
else
|
|
@@ -48,6 +48,28 @@ module Mangadex
|
|
|
48
48
|
errors.select { |error| error.status.to_s == status.to_s }.any?
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
def more_results?
|
|
52
|
+
return unless data.is_a?(Array)
|
|
53
|
+
|
|
54
|
+
total > data.count
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def count
|
|
58
|
+
data.is_a?(Array) ? data.count : nil
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def each(&block)
|
|
62
|
+
if data.is_a?(Array)
|
|
63
|
+
data.each(&block)
|
|
64
|
+
else
|
|
65
|
+
raise ArgumentError, "Expect data to be Array, but got #{data.class}"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def to_a
|
|
70
|
+
each.to_a
|
|
71
|
+
end
|
|
72
|
+
|
|
51
73
|
def as_json(*)
|
|
52
74
|
Hash(raw_data)
|
|
53
75
|
end
|
data/lib/mangadex/api/user.rb
CHANGED
|
@@ -7,6 +7,13 @@ module Mangadex
|
|
|
7
7
|
attr_accessor :mangadex_user_id, :session, :refresh, :session_valid_until
|
|
8
8
|
attr_reader :data
|
|
9
9
|
|
|
10
|
+
SERIALIZABLE_KEYS = %i(
|
|
11
|
+
mangadex_user_id
|
|
12
|
+
session
|
|
13
|
+
refresh
|
|
14
|
+
session_valid_until
|
|
15
|
+
)
|
|
16
|
+
|
|
10
17
|
sig { params(mangadex_user_id: String, session: T.nilable(String), refresh: T.nilable(String), data: T.untyped, session_valid_until: T.nilable(Time)).void }
|
|
11
18
|
def initialize(mangadex_user_id:, session: nil, refresh: nil, data: nil, session_valid_until: nil)
|
|
12
19
|
raise ArgumentError, 'Missing mangadex_user_id' if mangadex_user_id.to_s.empty?
|
|
@@ -18,10 +25,33 @@ module Mangadex
|
|
|
18
25
|
@data = data
|
|
19
26
|
end
|
|
20
27
|
|
|
28
|
+
# true: The tokens were successfully refreshed if the session expired
|
|
29
|
+
# false: Error: refresh token empty or could not refresh the token on the server
|
|
30
|
+
sig do
|
|
31
|
+
params(
|
|
32
|
+
block: T.nilable(
|
|
33
|
+
T.proc.params(arg0: User).returns(
|
|
34
|
+
T.untyped)
|
|
35
|
+
)
|
|
36
|
+
).returns(T::Boolean)
|
|
37
|
+
end
|
|
38
|
+
def refresh_session(&block)
|
|
39
|
+
return true unless session_expired?
|
|
40
|
+
|
|
41
|
+
refresh_session!(&block)
|
|
42
|
+
end
|
|
43
|
+
|
|
21
44
|
# true: The tokens were successfully refreshed
|
|
22
45
|
# false: Error: refresh token empty or could not refresh the token on the server
|
|
23
|
-
sig
|
|
24
|
-
|
|
46
|
+
sig do
|
|
47
|
+
params(
|
|
48
|
+
block: T.nilable(
|
|
49
|
+
T.proc.params(arg0: User).returns(
|
|
50
|
+
T.untyped)
|
|
51
|
+
)
|
|
52
|
+
).returns(T::Boolean)
|
|
53
|
+
end
|
|
54
|
+
def refresh_session!(&block)
|
|
25
55
|
return false if refresh.nil?
|
|
26
56
|
|
|
27
57
|
response = Mangadex::Internal::Request.post('/auth/refresh', payload: { token: refresh })
|
|
@@ -31,15 +61,11 @@ module Mangadex
|
|
|
31
61
|
@refresh = response.dig('token', 'refresh')
|
|
32
62
|
@session = response.dig('token', 'session')
|
|
33
63
|
|
|
34
|
-
|
|
35
|
-
|
|
64
|
+
if block_given?
|
|
65
|
+
yield(self)
|
|
66
|
+
end
|
|
36
67
|
|
|
37
|
-
|
|
38
|
-
def with_valid_session
|
|
39
|
-
session_expired? && refresh!
|
|
40
|
-
self
|
|
41
|
-
ensure
|
|
42
|
-
self
|
|
68
|
+
true
|
|
43
69
|
end
|
|
44
70
|
|
|
45
71
|
sig { returns(T::Boolean) }
|
|
@@ -65,6 +91,18 @@ module Mangadex
|
|
|
65
91
|
!mangadex_user_id.nil? && !mangadex_user_id.strip.empty?
|
|
66
92
|
end
|
|
67
93
|
|
|
94
|
+
sig { params(except: T.any(Symbol, T::Array[Symbol])).returns(Hash) }
|
|
95
|
+
def to_h(except: [])
|
|
96
|
+
except = Array(except).map(&:to_sym)
|
|
97
|
+
keys = SERIALIZABLE_KEYS.reject do |key|
|
|
98
|
+
except.include?(key)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
keys.map do |key|
|
|
102
|
+
[key, send(key)]
|
|
103
|
+
end.to_h
|
|
104
|
+
end
|
|
105
|
+
|
|
68
106
|
sig { params(mangadex_user_id: T.nilable(String)).returns(T.nilable(User)) }
|
|
69
107
|
def self.from_storage(mangadex_user_id)
|
|
70
108
|
return if mangadex_user_id.nil?
|
|
@@ -81,7 +119,7 @@ module Mangadex
|
|
|
81
119
|
session: session,
|
|
82
120
|
refresh: refresh,
|
|
83
121
|
session_valid_until: session_valid_until,
|
|
84
|
-
)
|
|
122
|
+
)
|
|
85
123
|
else
|
|
86
124
|
nil
|
|
87
125
|
end
|
|
@@ -18,7 +18,7 @@ module Mangadex
|
|
|
18
18
|
if version != Mangadex::Version::STRING
|
|
19
19
|
warn(
|
|
20
20
|
"[Warning] This gem is compatible with #{Mangadex::Version::STRING} but it looks like Mangadex is at #{version}",
|
|
21
|
-
"[Warning] Check out #{Mangadex
|
|
21
|
+
"[Warning] Check out #{Mangadex.configuration.mangadex_url} for more information.",
|
|
22
22
|
)
|
|
23
23
|
end
|
|
24
24
|
|
data/lib/mangadex/artist.rb
CHANGED
|
@@ -2,10 +2,29 @@
|
|
|
2
2
|
require_relative "author"
|
|
3
3
|
|
|
4
4
|
module Mangadex
|
|
5
|
-
class Artist <
|
|
5
|
+
class Artist < MangadexObject
|
|
6
6
|
# Indicates if this is an artist
|
|
7
7
|
#
|
|
8
8
|
# @return [Boolean] whether this is an artist or not.
|
|
9
|
+
has_attributes \
|
|
10
|
+
:name,
|
|
11
|
+
:image_url,
|
|
12
|
+
:biography,
|
|
13
|
+
:twitter,
|
|
14
|
+
:pixiv,
|
|
15
|
+
:melon_book,
|
|
16
|
+
:fan_box,
|
|
17
|
+
:booth,
|
|
18
|
+
:nico_video,
|
|
19
|
+
:skeb,
|
|
20
|
+
:fantia,
|
|
21
|
+
:tumblr,
|
|
22
|
+
:youtube,
|
|
23
|
+
:website,
|
|
24
|
+
:version,
|
|
25
|
+
:created_at,
|
|
26
|
+
:updated_at
|
|
27
|
+
|
|
9
28
|
def artist?
|
|
10
29
|
true
|
|
11
30
|
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
|
|
3
|
+
module Mangadex
|
|
4
|
+
class AtHome
|
|
5
|
+
extend T::Sig
|
|
6
|
+
|
|
7
|
+
sig { params(chapter_id: String).returns(T::Api::GenericResponse) }
|
|
8
|
+
def self.server(chapter_id)
|
|
9
|
+
Mangadex::Internal::Request.get(
|
|
10
|
+
"/at-home/server/#{chapter_id}",
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
sig { params(chapter_id: String, data_saver: T::Boolean).returns(T.nilable(T::Array[String])) }
|
|
15
|
+
def self.page_urls(chapter_id, data_saver: true)
|
|
16
|
+
response = self.server(chapter_id)
|
|
17
|
+
return if response.is_a?(Mangadex::Api::Response)
|
|
18
|
+
|
|
19
|
+
base_url = response['baseUrl']
|
|
20
|
+
chapter_data = response['chapter']
|
|
21
|
+
hash = chapter_data['hash']
|
|
22
|
+
source = data_saver ? chapter_data['dataSaver'] : chapter_data['data']
|
|
23
|
+
data_source = data_saver ? 'data-saver' : 'data'
|
|
24
|
+
|
|
25
|
+
source.map do |filename|
|
|
26
|
+
[base_url, data_source, hash, filename].join('/')
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/mangadex/auth.rb
CHANGED
|
@@ -3,8 +3,17 @@ module Mangadex
|
|
|
3
3
|
class Auth
|
|
4
4
|
extend T::Sig
|
|
5
5
|
|
|
6
|
-
sig
|
|
7
|
-
|
|
6
|
+
sig do
|
|
7
|
+
params(
|
|
8
|
+
username: T.nilable(String),
|
|
9
|
+
email: T.nilable(String),
|
|
10
|
+
password: String,
|
|
11
|
+
block: T.nilable(T.proc.returns(T.untyped))
|
|
12
|
+
).returns(
|
|
13
|
+
T.nilable(T.untyped),
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
def self.login(username: nil, email: nil, password: nil, &block)
|
|
8
17
|
args = { password: password }
|
|
9
18
|
args.merge!(email: email) if email
|
|
10
19
|
args.merge!(username: username) if username
|
|
@@ -18,6 +27,8 @@ module Mangadex
|
|
|
18
27
|
}),
|
|
19
28
|
)
|
|
20
29
|
|
|
30
|
+
session_valid_until = Time.now + (15 * 60)
|
|
31
|
+
|
|
21
32
|
session = response.dig('token', 'session')
|
|
22
33
|
refresh = response.dig('token', 'refresh')
|
|
23
34
|
|
|
@@ -28,12 +39,18 @@ module Mangadex
|
|
|
28
39
|
session: session,
|
|
29
40
|
refresh: refresh,
|
|
30
41
|
data: mangadex_user.data,
|
|
42
|
+
session_valid_until: session_valid_until,
|
|
31
43
|
)
|
|
32
|
-
|
|
44
|
+
|
|
45
|
+
user.persist
|
|
46
|
+
user
|
|
33
47
|
|
|
34
48
|
Mangadex.context.user = user
|
|
35
49
|
|
|
36
|
-
|
|
50
|
+
if block_given?
|
|
51
|
+
return yield(user)
|
|
52
|
+
end
|
|
53
|
+
|
|
37
54
|
user
|
|
38
55
|
rescue Errors::UnauthorizedError => error
|
|
39
56
|
raise Errors::AuthenticationError.new(error.response)
|
|
@@ -67,7 +84,7 @@ module Mangadex
|
|
|
67
84
|
|
|
68
85
|
sig { returns(T::Boolean) }
|
|
69
86
|
def self.refresh_token
|
|
70
|
-
!(Mangadex.context.user&.
|
|
87
|
+
!(Mangadex.context.user&.refresh_session!).nil?
|
|
71
88
|
end
|
|
72
89
|
|
|
73
90
|
private
|
data/lib/mangadex/author.rb
CHANGED
data/lib/mangadex/chapter.rb
CHANGED
|
@@ -10,9 +10,7 @@ module Mangadex
|
|
|
10
10
|
:volume,
|
|
11
11
|
:chapter,
|
|
12
12
|
:translated_language,
|
|
13
|
-
:
|
|
14
|
-
:data,
|
|
15
|
-
:data_saver,
|
|
13
|
+
:pages,
|
|
16
14
|
:last_chapter,
|
|
17
15
|
:uploader,
|
|
18
16
|
:external_url,
|
|
@@ -90,16 +88,9 @@ module Mangadex
|
|
|
90
88
|
locale&.english_name
|
|
91
89
|
end
|
|
92
90
|
|
|
93
|
-
sig { returns(
|
|
94
|
-
def
|
|
95
|
-
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
sig { returns(T.nilable(String)) }
|
|
99
|
-
def preview_image_url
|
|
100
|
-
return if data_saver.empty?
|
|
101
|
-
|
|
102
|
-
"https://uploads.mangadex.org/data-saver/#{attributes.hash}/#{data_saver.first}"
|
|
91
|
+
sig { params(data_saver: T::Boolean).returns(T.nilable(T::Array[String])) }
|
|
92
|
+
def page_urls(data_saver: true)
|
|
93
|
+
Mangadex::AtHome.page_urls(id, data_saver: data_saver)
|
|
103
94
|
end
|
|
104
95
|
|
|
105
96
|
def as_json(*)
|
|
@@ -110,7 +101,7 @@ module Mangadex
|
|
|
110
101
|
end
|
|
111
102
|
|
|
112
103
|
def self.attributes_to_inspect
|
|
113
|
-
[:id, :type, :title, :volume, :chapter, :
|
|
104
|
+
[:id, :type, :title, :volume, :chapter, :pages, :publish_at]
|
|
114
105
|
end
|
|
115
106
|
end
|
|
116
107
|
end
|
data/lib/mangadex/custom_list.rb
CHANGED
|
@@ -135,7 +135,8 @@ module Mangadex
|
|
|
135
135
|
|
|
136
136
|
sig { params(args: T::Api::Arguments).returns(T.nilable(Mangadex::Api::Response[Manga])) }
|
|
137
137
|
def manga_details(**args)
|
|
138
|
-
|
|
138
|
+
custom_list = Mangadex::CustomList.get(id).data
|
|
139
|
+
ids = custom_list.mangas.map(&:id)
|
|
139
140
|
ids.any? ? Mangadex::Manga.list(**args.merge(ids: ids)) : nil
|
|
140
141
|
end
|
|
141
142
|
|
|
@@ -18,7 +18,7 @@ module Mangadex
|
|
|
18
18
|
|
|
19
19
|
sig { returns(T.nilable(Mangadex::Api::User)) }
|
|
20
20
|
def user
|
|
21
|
-
@ignore_user ? nil : @user
|
|
21
|
+
@ignore_user ? nil : @user
|
|
22
22
|
rescue Mangadex::Errors::UnauthorizedError
|
|
23
23
|
warn("A user is present but not authenticated!")
|
|
24
24
|
nil
|
|
@@ -29,7 +29,7 @@ module Mangadex
|
|
|
29
29
|
@tags ||= Mangadex::Tag.list.data
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
sig { params(user: T.nilable(T.
|
|
32
|
+
sig { params(user: T.nilable(T.untyped), block: T.proc.returns(T.untyped)).returns(T.untyped) }
|
|
33
33
|
def with_user(user, &block)
|
|
34
34
|
temp_set_value("user", user) do
|
|
35
35
|
yield
|
|
@@ -64,11 +64,12 @@ module Mangadex
|
|
|
64
64
|
session: user[:session],
|
|
65
65
|
refresh: user[:refresh],
|
|
66
66
|
)
|
|
67
|
-
elsif user_object?(user)
|
|
67
|
+
elsif Mangadex::Internal::Context.user_object?(user)
|
|
68
68
|
@user = Mangadex::Api::User.new(
|
|
69
69
|
mangadex_user_id: user.mangadex_user_id.to_s,
|
|
70
70
|
session: user.session,
|
|
71
71
|
refresh: user.refresh,
|
|
72
|
+
session_valid_until: user.session_valid_until,
|
|
72
73
|
data: user,
|
|
73
74
|
)
|
|
74
75
|
elsif user.nil?
|
|
@@ -113,18 +114,18 @@ module Mangadex
|
|
|
113
114
|
end
|
|
114
115
|
end
|
|
115
116
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def user_object?(user)
|
|
117
|
+
def self.user_object?(user)
|
|
119
118
|
return false if user.nil?
|
|
120
119
|
|
|
121
|
-
missing_methods = [:session, :refresh, :mangadex_user_id] - user.methods
|
|
120
|
+
missing_methods = [:session, :refresh, :mangadex_user_id, :save] - user.methods
|
|
122
121
|
return true if missing_methods.empty?
|
|
123
122
|
|
|
124
123
|
warn("Potential user object #{user} is missing #{missing_methods}")
|
|
125
124
|
false
|
|
126
125
|
end
|
|
127
126
|
|
|
127
|
+
private
|
|
128
|
+
|
|
128
129
|
def temp_set_value(name, value, &block)
|
|
129
130
|
setter_method_name = "#{name}="
|
|
130
131
|
|
|
@@ -106,7 +106,13 @@ module Mangadex
|
|
|
106
106
|
{
|
|
107
107
|
limit: { accepts: Integer },
|
|
108
108
|
offset: { accepts: Integer },
|
|
109
|
-
|
|
109
|
+
ids: { accepts: [String] },
|
|
110
|
+
title: { accepts: String },
|
|
111
|
+
manga: { accepts: String },
|
|
112
|
+
groups: { accepts: [String] },
|
|
113
|
+
uploader: { accepts: [String], converts: converts(:to_a) },
|
|
114
|
+
chapter: { accepts: [String], converts: converts(:to_a) },
|
|
115
|
+
translated_language: { accepts: [String], converts: converts(:to_a) },
|
|
110
116
|
original_language: { accepts: [String] },
|
|
111
117
|
excluded_original_language: { accepts: [String] },
|
|
112
118
|
content_rating: { accepts: %w(safe suggestive erotica pornographic), converts: converts(:to_a) },
|
|
@@ -7,7 +7,6 @@ require 'active_support/core_ext/hash/keys'
|
|
|
7
7
|
module Mangadex
|
|
8
8
|
module Internal
|
|
9
9
|
class Request
|
|
10
|
-
BASE_URI = 'https://api.mangadex.org'
|
|
11
10
|
ALLOWED_METHODS = %i(get post put delete).freeze
|
|
12
11
|
|
|
13
12
|
attr_accessor :path, :headers, :payload, :method, :raw
|
|
@@ -51,7 +50,7 @@ module Mangadex
|
|
|
51
50
|
end
|
|
52
51
|
|
|
53
52
|
def run!(raw: false, auth: false)
|
|
54
|
-
payload_details = request_payload ? "Payload: #{
|
|
53
|
+
payload_details = request_payload ? "Payload: #{sensitive_request_payload}" : "{no-payload}"
|
|
55
54
|
puts("[#{self.class.name}] #{method.to_s.upcase} #{request_url} #{payload_details}")
|
|
56
55
|
|
|
57
56
|
raise Mangadex::Errors::UserNotLoggedIn.new if auth && Mangadex.context.user.nil?
|
|
@@ -100,7 +99,7 @@ module Mangadex
|
|
|
100
99
|
|
|
101
100
|
def request_url
|
|
102
101
|
request_path = path.start_with?('/') ? path : "/#{path}"
|
|
103
|
-
"#{
|
|
102
|
+
"#{Mangadex.configuration.mangadex_url}#{request_path}"
|
|
104
103
|
end
|
|
105
104
|
|
|
106
105
|
def request_payload
|
|
@@ -108,12 +107,20 @@ module Mangadex
|
|
|
108
107
|
|
|
109
108
|
JSON.generate(payload)
|
|
110
109
|
end
|
|
110
|
+
|
|
111
|
+
def sensitive_request_payload(sensitive_fields: %w(password token))
|
|
112
|
+
payload = JSON.parse(request_payload)
|
|
113
|
+
sensitive_fields.map(&:to_s).each do |field|
|
|
114
|
+
payload[field] = '[REDACTED]' if payload.key?(field)
|
|
115
|
+
end
|
|
116
|
+
JSON.generate(payload)
|
|
117
|
+
end
|
|
111
118
|
|
|
112
119
|
def request_headers
|
|
113
120
|
return headers if Mangadex.context.user.nil?
|
|
114
121
|
|
|
115
122
|
headers.merge({
|
|
116
|
-
Authorization: Mangadex.context.user.
|
|
123
|
+
Authorization: Mangadex.context.user.session,
|
|
117
124
|
})
|
|
118
125
|
end
|
|
119
126
|
|
|
@@ -31,7 +31,7 @@ module Mangadex
|
|
|
31
31
|
self.name.split('::').last.underscore
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def from_data(data, related_type: nil)
|
|
34
|
+
def from_data(data, related_type: nil, source_obj: nil)
|
|
35
35
|
base_class_name = self.name.gsub('::', '_')
|
|
36
36
|
klass_name = self.name
|
|
37
37
|
target_attributes_class_name = "#{base_class_name}_Attributes"
|
|
@@ -57,7 +57,7 @@ module Mangadex
|
|
|
57
57
|
data = data.with_indifferent_access
|
|
58
58
|
|
|
59
59
|
relationships = data['relationships']&.map do |relationship_data|
|
|
60
|
-
Relationship.from_data(relationship_data)
|
|
60
|
+
Relationship.from_data(relationship_data, MangadexObject.new(**data))
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
attributes = klass.new(**Hash(data['attributes']))
|
|
@@ -69,8 +69,11 @@ module Mangadex
|
|
|
69
69
|
related_type: related_type,
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
relationships = [source_obj].compact unless relationships.present?
|
|
72
73
|
initialize_hash.merge!({relationships: relationships}) if relationships.present?
|
|
73
74
|
|
|
75
|
+
# binding.pry
|
|
76
|
+
|
|
74
77
|
new(**initialize_hash)
|
|
75
78
|
end
|
|
76
79
|
end
|
data/lib/mangadex/manga.rb
CHANGED
|
@@ -17,6 +17,7 @@ module Mangadex
|
|
|
17
17
|
:year,
|
|
18
18
|
:content_rating,
|
|
19
19
|
:tags,
|
|
20
|
+
:state,
|
|
20
21
|
:version,
|
|
21
22
|
:created_at,
|
|
22
23
|
:updated_at
|
|
@@ -49,6 +50,8 @@ module Mangadex
|
|
|
49
50
|
updated_at_since: { accepts: %r{^\d{4}-[0-1]\d-([0-2]\d|3[0-1])T([0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$} },
|
|
50
51
|
order: { accepts: Hash },
|
|
51
52
|
includes: { accepts: Array, converts: to_a },
|
|
53
|
+
has_available_chapters: { accepts: ['0', '1', 'true', 'false'] },
|
|
54
|
+
group: { accepts: String },
|
|
52
55
|
}),
|
|
53
56
|
content_rating: true,
|
|
54
57
|
)
|
|
@@ -67,12 +70,13 @@ module Mangadex
|
|
|
67
70
|
|
|
68
71
|
sig { params(id: String, args: T::Api::Arguments).returns(T::Api::MangaResponse) }
|
|
69
72
|
def self.view(id, **args)
|
|
73
|
+
to_a = Mangadex::Internal::Definition.converts(:to_a)
|
|
70
74
|
Mangadex::Internal::Definition.must(id)
|
|
71
75
|
|
|
72
76
|
Mangadex::Internal::Request.get(
|
|
73
77
|
'/manga/%{id}' % {id: id},
|
|
74
78
|
Mangadex::Internal::Definition.validate(args, {
|
|
75
|
-
includes: { accepts: Array },
|
|
79
|
+
includes: { accepts: Array, converts: to_a },
|
|
76
80
|
})
|
|
77
81
|
)
|
|
78
82
|
end
|
|
@@ -123,9 +127,9 @@ module Mangadex
|
|
|
123
127
|
)
|
|
124
128
|
end
|
|
125
129
|
|
|
126
|
-
sig { params(status: String).returns(T::Api::GenericResponse) }
|
|
127
|
-
def self.all_reading_status(status)
|
|
128
|
-
args = { status: status }
|
|
130
|
+
sig { params(status: T.nilable(String)).returns(T::Api::GenericResponse) }
|
|
131
|
+
def self.all_reading_status(status = nil)
|
|
132
|
+
args = { status: status } if status.present?
|
|
129
133
|
|
|
130
134
|
Mangadex::Internal::Request.get(
|
|
131
135
|
'/manga/status',
|
|
@@ -162,6 +166,15 @@ module Mangadex
|
|
|
162
166
|
)
|
|
163
167
|
end
|
|
164
168
|
|
|
169
|
+
sig { params(id: T.any(T::Array[String], String), grouped: T::Boolean).returns(T::Api::GenericResponse) }
|
|
170
|
+
def self.read_markers(id, grouped: false)
|
|
171
|
+
Mangadex::Internal::Request.get(
|
|
172
|
+
'/manga/read',
|
|
173
|
+
{ ids: Array(id), grouped: grouped },
|
|
174
|
+
auth: true,
|
|
175
|
+
)
|
|
176
|
+
end
|
|
177
|
+
|
|
165
178
|
# Untested API endpoints
|
|
166
179
|
sig { params(id: String, args: T::Api::Arguments).returns(T::Api::MangaResponse) }
|
|
167
180
|
def self.update(id, **args)
|
|
@@ -199,5 +212,11 @@ module Mangadex
|
|
|
199
212
|
|
|
200
213
|
ContentRating.new(attributes.content_rating)
|
|
201
214
|
end
|
|
215
|
+
|
|
216
|
+
sig { params(args: T::Api::Arguments).returns(Mangadex::Api::Response[Chapter]) }
|
|
217
|
+
def chapters(**args)
|
|
218
|
+
chapter_args = args.merge({manga: id})
|
|
219
|
+
Chapter.list(**chapter_args)
|
|
220
|
+
end
|
|
202
221
|
end
|
|
203
222
|
end
|
|
@@ -22,19 +22,24 @@ module Mangadex
|
|
|
22
22
|
).freeze
|
|
23
23
|
|
|
24
24
|
class << self
|
|
25
|
-
|
|
25
|
+
# data: Relationship data
|
|
26
|
+
# source_obj: The object to witch the object belongs to
|
|
27
|
+
def from_data(data, source_obj = nil)
|
|
26
28
|
data = data.with_indifferent_access
|
|
27
29
|
klass = class_for_relationship_type(data['type'])
|
|
28
30
|
|
|
29
31
|
if klass && data['attributes']&.any?
|
|
30
|
-
return klass.from_data(data, related_type: data['related'])
|
|
32
|
+
return klass.from_data(data, related_type: data['related'], source_obj: source_obj)
|
|
31
33
|
end
|
|
32
34
|
|
|
35
|
+
relationships = [source_obj] if source_obj
|
|
36
|
+
|
|
33
37
|
new(
|
|
34
38
|
id: data['id'],
|
|
35
39
|
type: data['type'],
|
|
36
40
|
attributes: OpenStruct.new(data['attributes']),
|
|
37
41
|
related: data['related'],
|
|
42
|
+
relationships: relationships,
|
|
38
43
|
)
|
|
39
44
|
end
|
|
40
45
|
|
data/lib/mangadex/types.rb
CHANGED
data/lib/mangadex/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mangadex
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.4.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Akinyele Cafe-Febrissy
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2022-01-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: psych
|
|
@@ -163,6 +163,7 @@ files:
|
|
|
163
163
|
- ".ruby-version"
|
|
164
164
|
- ".travis.yml"
|
|
165
165
|
- CODE_OF_CONDUCT.md
|
|
166
|
+
- Dockerfile
|
|
166
167
|
- Gemfile
|
|
167
168
|
- Gemfile.lock
|
|
168
169
|
- LICENSE.txt
|
|
@@ -170,6 +171,7 @@ files:
|
|
|
170
171
|
- Rakefile
|
|
171
172
|
- bin/console
|
|
172
173
|
- bin/setup
|
|
174
|
+
- docker-compose.yml
|
|
173
175
|
- docs/authentication.md
|
|
174
176
|
- docs/context.md
|
|
175
177
|
- lib/config.rb
|
|
@@ -182,6 +184,7 @@ files:
|
|
|
182
184
|
- lib/mangadex/api/user.rb
|
|
183
185
|
- lib/mangadex/api/version_checker.rb
|
|
184
186
|
- lib/mangadex/artist.rb
|
|
187
|
+
- lib/mangadex/at_home.rb
|
|
185
188
|
- lib/mangadex/auth.rb
|
|
186
189
|
- lib/mangadex/author.rb
|
|
187
190
|
- lib/mangadex/chapter.rb
|