mangadex 5.5.8 → 5.7.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '038676da7b94f64da0e1ba27d2a0f2563153bf785fc027830132330fcaa6db41'
4
- data.tar.gz: 219bc69785823ce34145b10103149d3f397803a7a8a77732a5ee98983162e211
3
+ metadata.gz: 52dec750d8fbff40af52a2be9375a2b9729d8b7a3422b8f6dac5504d79be8eff
4
+ data.tar.gz: 277f46e56d6f84b10e3b16878d4a9196eb70323e99133bbd6294f608e3dc6137
5
5
  SHA512:
6
- metadata.gz: fab8f18bd656d148f42513e316389b6505aa63c24fc9be2722f8ac4752f9dfb2bfde8749769af69acdf2d90714aa64e87f82ad40a0405cc3bd7158240bb998cc
7
- data.tar.gz: 4f539c62ada95b984cf96f04b2450385b3bf348d8efcbbb501ab67ac9f21f70c38fb082763b68a3c3851fb572047a07650ab4f80a975987aadea9fb5f4ae505a
6
+ metadata.gz: 81f339164b6a02619c57f9c9d25daf5c1f652b6e547f3923a7957f7a8afed622c14cc11f4368009d9a37d8c414a60e5210cc83785b4409895e045e3bf6b024a0
7
+ data.tar.gz: ccd3bc3cad6e3f140df1bc79a9b402508178baabb2730364aecf1270a99a20fd932d4e5e9af301e93b879b808c72db2044e4cd197c9edd562cb159f03ce901bd
@@ -0,0 +1,19 @@
1
+ name: Docker Image CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["culture"]
6
+ pull_request:
7
+ branches: ["culture"]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+ - name: Build the Docker image
16
+ run: docker build . --file Dockerfile --tag mangadex
17
+
18
+ - name: Run tests
19
+ run: docker run --rm -t mangadex:latest bundle exec rspec
@@ -0,0 +1,20 @@
1
+ name: Publish Gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - v*
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+ - uses: actions/checkout@v1
13
+
14
+ - name: Release Gem
15
+ if: contains(github.ref, 'refs/tags/v')
16
+ uses: cadwallion/publish-rubygems-action@master
17
+ env:
18
+ GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
19
+ RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
20
+ RELEASE_COMMAND: rake release
data/.gitignore CHANGED
@@ -15,3 +15,7 @@
15
15
 
16
16
  # Misc
17
17
  .DS_Store
18
+ .env*
19
+
20
+ # Docker
21
+ .devcontainer/
data/Dockerfile CHANGED
@@ -5,3 +5,10 @@ WORKDIR /app
5
5
  COPY . /app
6
6
 
7
7
  RUN bundle install --jobs 4 --retry 5 --quiet
8
+
9
+ COPY entrypoint.sh /usr/bin/
10
+ RUN chmod +x /usr/bin/entrypoint.sh
11
+
12
+ ENTRYPOINT [ "entrypoint.sh" ]
13
+
14
+ CMD [ "bin/console" ]
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mangadex (5.5.8)
4
+ mangadex (5.7.5.1)
5
5
  psych (~> 4.0.1)
6
6
  rest-client (~> 2.1)
7
7
  sorbet-runtime
@@ -9,91 +9,50 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- activesupport (7.0.2.3)
13
- concurrent-ruby (~> 1.0, >= 1.0.2)
14
- i18n (>= 1.6, < 2)
15
- minitest (>= 5.1)
16
- tzinfo (~> 2.0)
17
- addressable (2.8.0)
18
- public_suffix (>= 2.0.2, < 5.0)
19
12
  coderay (1.1.3)
20
- concurrent-ruby (1.1.9)
21
- crack (0.4.5)
22
- rexml
23
13
  diff-lcs (1.5.0)
24
14
  domain_name (0.5.20190701)
25
15
  unf (>= 0.0.5, < 1.0.0)
26
- hashdiff (1.0.1)
27
16
  http-accept (1.7.0)
28
17
  http-cookie (1.0.5)
29
18
  domain_name (~> 0.5)
30
- i18n (1.10.0)
31
- concurrent-ruby (~> 1.0)
32
19
  method_source (1.0.0)
33
20
  mime-types (3.4.1)
34
21
  mime-types-data (~> 3.2015)
35
22
  mime-types-data (3.2022.0105)
36
- minitest (5.15.0)
37
- mustermann (1.1.1)
38
- ruby2_keywords (~> 0.0.1)
39
23
  netrc (0.11.0)
40
24
  pry (0.14.1)
41
25
  coderay (~> 1.1)
42
26
  method_source (~> 1.0)
43
- psych (4.0.4)
27
+ psych (4.0.6)
44
28
  stringio
45
- public_suffix (4.0.6)
46
- rack (2.2.3)
47
- rack-protection (2.2.0)
48
- rack
49
29
  rake (13.0.6)
50
- request_interceptor (1.0.0)
51
- activesupport (>= 4.0)
52
- rack
53
- sinatra
54
- smart_properties (~> 1.0)
55
- webmock (~> 3.0)
56
30
  rest-client (2.1.0)
57
31
  http-accept (>= 1.7.0, < 2.0)
58
32
  http-cookie (>= 1.0.2, < 2.0)
59
33
  mime-types (>= 1.16, < 4.0)
60
34
  netrc (~> 0.8)
61
- rexml (3.2.5)
62
- rspec (3.11.0)
63
- rspec-core (~> 3.11.0)
64
- rspec-expectations (~> 3.11.0)
65
- rspec-mocks (~> 3.11.0)
66
- rspec-core (3.11.0)
67
- rspec-support (~> 3.11.0)
68
- rspec-expectations (3.11.0)
35
+ rspec (3.12.0)
36
+ rspec-core (~> 3.12.0)
37
+ rspec-expectations (~> 3.12.0)
38
+ rspec-mocks (~> 3.12.0)
39
+ rspec-core (3.12.0)
40
+ rspec-support (~> 3.12.0)
41
+ rspec-expectations (3.12.0)
69
42
  diff-lcs (>= 1.2.0, < 2.0)
70
- rspec-support (~> 3.11.0)
71
- rspec-mocks (3.11.0)
43
+ rspec-support (~> 3.12.0)
44
+ rspec-mocks (3.12.0)
72
45
  diff-lcs (>= 1.2.0, < 2.0)
73
- rspec-support (~> 3.11.0)
74
- rspec-support (3.11.0)
75
- ruby2_keywords (0.0.5)
76
- sinatra (2.2.0)
77
- mustermann (~> 1.0)
78
- rack (~> 2.2)
79
- rack-protection (= 2.2.0)
80
- tilt (~> 2.0)
81
- smart_properties (1.17.0)
82
- sorbet (0.5.9742)
83
- sorbet-static (= 0.5.9742)
84
- sorbet-runtime (0.5.10030)
85
- sorbet-static (0.5.9742-x86_64-linux)
46
+ rspec-support (~> 3.12.0)
47
+ rspec-support (3.12.0)
48
+ sorbet (0.5.10535)
49
+ sorbet-static (= 0.5.10535)
50
+ sorbet-runtime (0.5.10539)
51
+ sorbet-static (0.5.10535-x86_64-linux)
86
52
  stringio (3.0.2)
87
- tilt (2.0.10)
88
- tzinfo (2.0.4)
89
- concurrent-ruby (~> 1.0)
90
53
  unf (0.1.4)
91
54
  unf_ext
92
55
  unf_ext (0.0.8.2)
93
- webmock (3.14.0)
94
- addressable (>= 2.8.0)
95
- crack (>= 0.3.2)
96
- hashdiff (>= 0.4.0, < 2.0.0)
97
56
 
98
57
  PLATFORMS
99
58
  x86_64-linux
@@ -103,7 +62,6 @@ DEPENDENCIES
103
62
  mangadex!
104
63
  pry
105
64
  rake (~> 13.0)
106
- request_interceptor (~> 1.0.0)
107
65
  rspec (~> 3.0)
108
66
  sorbet
109
67
 
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Ruby](https://github.com/thedrummeraki/mangadex/actions/workflows/ruby.yml/badge.svg)](https://github.com/thedrummeraki/mangadex/actions/workflows/ruby.yml)<a href="https://rubygems.org/gems/mangadex"><img src="https://badgen.net/rubygems/v/mangadex" /></a>
1
+ [![Docker Image CI](https://github.com/thedrummeraki/mangadex/actions/workflows/docker-image.yml/badge.svg)](https://github.com/thedrummeraki/mangadex/actions/workflows/docker-image.yml)<a href="https://rubygems.org/gems/mangadex"><img src="https://badgen.net/rubygems/v/mangadex" /></a>
2
2
 
3
3
  # Mangadex
4
4
 
@@ -7,6 +7,7 @@ Welcome to `mangadex`, your next favourite Ruby gem for interacting with [Mangad
7
7
  ## Important information
8
8
 
9
9
  **By using this gem you accept**:
10
+
10
11
  - To **credit [Mangadex](https://mangadex.org)**. This gem is your friendly neighbourhood wrapper on _their_ API.
11
12
  - To **credit scanlation groups**, especially if you offer the ability to read chapters.
12
13
  - **Not to run any ads** on the service that will use this gem. Please do not make money off of Mangadex's services.
@@ -196,6 +197,7 @@ end
196
197
  ```
197
198
 
198
199
  Already created your `User` class? Make sure it has all of the following:
200
+
199
201
  - `mangade_user_id`: ID used to identify your user on Mangadex
200
202
  - `username`: Your username
201
203
  - `session`: The session token (valid for 15 minutes)
@@ -282,7 +284,7 @@ class SessionController < ApplicationController
282
284
  rescue Mangadex::Errors::AuthenticationError => error
283
285
  # See https://api.mangadex.org/docs.html to learn more about errors
284
286
  Rails.logger.error(error.response.errors)
285
-
287
+
286
288
  # Handle authentication errors here
287
289
  end
288
290
 
@@ -325,7 +327,7 @@ class ProtectedController < ApplicationController
325
327
  end
326
328
  ```
327
329
 
328
- 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)__.
330
+ 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)**.
329
331
 
330
332
  ```ruby
331
333
  class CustomListsController < ProtectedController
@@ -384,10 +386,34 @@ end
384
386
 
385
387
  ## Development
386
388
 
389
+ ### Docker
390
+
391
+ You can use Docker to get started with dev work on the repo. After installing Dcoker, you can build the image:
392
+
393
+ ```
394
+ docker build -t mangadex .
395
+ ```
396
+
397
+ Then run the ruby console with the gem loaded
398
+
399
+ ```
400
+ docker run --rm -it mangadex:latest
401
+ ```
402
+
403
+ You can also log in directly when setting the `MD_USERNAME` and `MD_PASSWORD` (or `MD_EMAIL`) environment variables:
404
+
405
+ ```
406
+ docker run --rm -e MD_USERNAME=username -e MD_PASSWORD=password -it mangadex:latest
407
+ ```
408
+
409
+ ### Locally
410
+
387
411
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
388
412
 
389
413
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
390
414
 
415
+ You can also
416
+
391
417
  ## Contributing
392
418
 
393
419
  Bug reports and pull requests are welcome on GitHub at https://github.com/thedrummeraki/mangadex. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
data/entrypoint.sh ADDED
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # Then exec the container's main process (what's set as CMD in the Dockerfile).
5
+ exec "$@"
data/lib/mangadex/auth.rb CHANGED
@@ -48,7 +48,7 @@ module Mangadex
48
48
  Mangadex.context.user = user
49
49
 
50
50
  if block_given?
51
- return yield(user)
51
+ return yield(user)
52
52
  end
53
53
 
54
54
  user
@@ -58,12 +58,7 @@ module Mangadex
58
58
 
59
59
  sig { returns(Hash) }
60
60
  def self.check_token
61
- JSON.parse(
62
- Mangadex::Internal::Request.get(
63
- '/auth/check',
64
- raw: true,
65
- )
66
- )
61
+ Mangadex::Internal::Request.get('/auth/check')
67
62
  end
68
63
 
69
64
  sig { returns(T.any(T::Boolean, Mangadex::Api::Response)) }
@@ -0,0 +1,47 @@
1
+ module Mangadex
2
+ class ChapterReadMarker
3
+ extend T::Sig
4
+
5
+ sig { params(id: String).returns(T::Api::GenericResponse) }
6
+ def self.get(id)
7
+ Mangadex::Internal::Definition.must(id)
8
+
9
+ Mangadex::Internal::Request.get(
10
+ '/manga/{id}/read' % {id: id}
11
+ )
12
+ end
13
+
14
+ sig { params(id: String, args: T::Api::Arguments).returns(T::Api::GenericResponse) }
15
+ def self.create(id, **args)
16
+ Mangadex::Internal::Definition.must(id)
17
+
18
+ Mangadex::Internal::Request.post(
19
+ '/manga/{id}/read' % {id: id},
20
+ payload: Mangadex::Internal::Definition.validate(args, {
21
+ update_history: { accepts: [true, false] }
22
+ })
23
+ )
24
+ end
25
+
26
+ sig { sig(args: T::Api::Arguments).returns(T::Api::GenericResponse) }
27
+ def self.list(**args)
28
+ to_a = Mangadex::Internal::Definition.converts(:to_a)
29
+
30
+ Mangadex::Internal::Request.get(
31
+ '/manga/list',
32
+ Mangadex::Internal::Definition.validate(args, {
33
+ ids: { accepts: [String], converts: to_a, required: true },
34
+ grouped: { accepts: [true, false] },
35
+ })
36
+ )
37
+ end
38
+
39
+ sig { returns(T::Api::GenericResponse) }
40
+ def self.user_list
41
+ Mangadex::Internal::Request.get(
42
+ '/user/history',
43
+ auth: true,
44
+ )
45
+ end
46
+ end
47
+ end
@@ -1,4 +1,10 @@
1
1
  # typed: true
2
+
3
+ require_relative "definitions/accepts"
4
+
5
+ require_relative "definitions/base"
6
+ require_relative "definitions/content_rating"
7
+
2
8
  module Mangadex
3
9
  module Internal
4
10
  class Definition
@@ -8,7 +14,7 @@ module Mangadex
8
14
  def initialize(key, value, converts: nil, accepts: nil, required: false)
9
15
  @converts = converts
10
16
  @key = key
11
- @value = convert_value(value)
17
+ @value = convert_value(value.presence)
12
18
  @raw_value = value
13
19
  @accepts = accepts
14
20
  @required = required ? true : false
@@ -39,6 +45,10 @@ module Mangadex
39
45
  end
40
46
 
41
47
  def convert_value(value)
48
+ if converts.is_a?(Symbol)
49
+ converts_proc = self.class.converts(converts)
50
+ return converts_proc.call(value) if converts_proc
51
+ end
42
52
  if converts.is_a?(Proc)
43
53
  converts.call(value)
44
54
  elsif converts.is_a?(String) || converts.is_a?(Symbol)
@@ -94,7 +104,10 @@ module Mangadex
94
104
 
95
105
  class << self
96
106
  def converts(key=nil)
97
- procs = { to_a: -> ( x ) { Array(x) } }
107
+ procs = {
108
+ to_a: -> ( x ) { Array(x) },
109
+ to_i: -> ( x ) { Integer(x.to_s, 10) if x },
110
+ }
98
111
  return procs if key.nil?
99
112
 
100
113
  procs[key]
@@ -115,13 +128,16 @@ module Mangadex
115
128
  translated_language: { accepts: [String], converts: converts(:to_a) },
116
129
  original_language: { accepts: [String] },
117
130
  excluded_original_language: { accepts: [String] },
118
- content_rating: { accepts: %w(safe suggestive erotica pornographic), converts: converts(:to_a) },
131
+ content_rating: Definitions::ContentRating,
119
132
  include_future_updates: { accepts: %w(0 1) },
120
133
  created_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$} },
121
134
  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$} },
122
135
  publish_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$} },
123
136
  order: { accepts: Hash },
124
137
  includes: { accepts: [String], converts: converts(:to_a) },
138
+ include_empty_pages: { accepts: [0, 1], converts: converts(:to_i) },
139
+ include_future_publish_at: { accepts: [0, 1], converts: converts(:to_i) },
140
+ include_external_url: { accepts: [0, 1], converts: converts(:to_i) },
125
141
  },
126
142
  )
127
143
  end
@@ -151,11 +167,20 @@ module Mangadex
151
167
  end
152
168
 
153
169
  definition.each do |key, definition|
154
- validator = Definition.new(key, args[key], **definition.symbolize_keys)
155
- validation_error = validator.error
170
+ validation_error = if definition.is_a?(Class) && definition < Definitions::Base
171
+ validator = definition.new(args[key])
172
+ validator.validate
173
+ validator.error_message
174
+ elsif !definition.is_a?(Class)
175
+ validator = Definition.new(key, args[key], **definition.symbolize_keys)
176
+ validator.error
177
+ else
178
+ raise "Invalid definition class: #{definition}"
179
+ end
180
+
156
181
  if validation_error
157
182
  errors << { message: validation_error }
158
- elsif !validator.empty?
183
+ elsif !validator.empty? && validator.value
159
184
  args[key] = validator.value
160
185
  end
161
186
  end
@@ -173,7 +198,9 @@ module Mangadex
173
198
  raise ArgumentError, "Validation error: #{error_message}"
174
199
  end
175
200
 
176
- args.symbolize_keys
201
+ args.symbolize_keys.select do |_, value|
202
+ value.presence
203
+ end
177
204
  end
178
205
  end
179
206
  end
@@ -0,0 +1,72 @@
1
+ # typed: false
2
+
3
+ module Mangadex
4
+ module Internal
5
+ module Definitions
6
+ class Accepts
7
+ VALID_CONDITIONS = [:and, :or]
8
+
9
+ class Possibility
10
+ def initialize(accepted:)
11
+ @accepted = accepted
12
+ end
13
+
14
+ def inspect
15
+ "{#{@accepted.class.name}: #{@accepted}}"
16
+ end
17
+ end
18
+
19
+ def initialize(array: nil, class: nil, value: nil, condition: :and)
20
+ @array = array
21
+ @class = binding.local_variable_get(:class)
22
+ @value = value
23
+ @condition = ensure_valid_condition!(condition.to_s.to_sym)
24
+ end
25
+
26
+ def validate!(value)
27
+ valid = if @condition == :or
28
+ validate_or!(value)
29
+ else
30
+ validate_and!(value)
31
+ end
32
+
33
+ raise ArgumentError, "Value `#{value}` must be #{nature}: #{possibilities}" unless valid
34
+ end
35
+
36
+ private
37
+
38
+ def ensure_valid_condition!(condition)
39
+ return condition if VALID_CONDITIONS.include?(condition)
40
+
41
+ raise "Condition `#{condition}` must be one of #{VALID_CONDITIONS}"
42
+ end
43
+
44
+ def nature
45
+ @condition == :or ? "one of" : "all of"
46
+ end
47
+
48
+ def validate_and!(value)
49
+ possibilities.all? { potentially_valid?(value) }
50
+ end
51
+
52
+ def validate_or!(value)
53
+ possibilities.any? { potentially_valid?(value) }
54
+ end
55
+
56
+ def possibilities
57
+ @possibilities ||= [
58
+ @array,
59
+ @class,
60
+ @value,
61
+ ].compact.map { |pos| Possibility.new(accepted: pos) }
62
+ end
63
+
64
+ def potentially_valid?(value)
65
+ @array.include?(value) || \
66
+ value.is_a?(@class) || \
67
+ value == @value
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,94 @@
1
+ # typed: false
2
+
3
+ module Mangadex
4
+ module Internal
5
+ module Definitions
6
+ class Base
7
+ attr_reader :key, :accepts, :converts, :errors
8
+
9
+ def initialize(value, key:, accepts:, required: false, converts: nil)
10
+ @value = value
11
+ @key = key
12
+ @accepts = accepts
13
+ @required = required
14
+ @converts = converts
15
+ @errors = Array.new
16
+ end
17
+
18
+ def validate
19
+ validate_required
20
+ return if !@required && empty?
21
+
22
+ validate_accepts
23
+
24
+ nil
25
+ end
26
+
27
+ def validate!
28
+ validate
29
+
30
+ raise_if_any_errors!
31
+ end
32
+
33
+ def valid?
34
+ validate!
35
+ true
36
+ rescue ArgumentError
37
+ false
38
+ end
39
+
40
+ def error_message
41
+ return unless errors.any?
42
+
43
+ compile_error_message
44
+ end
45
+
46
+ def empty?
47
+ converted_value.respond_to?(:empty?) ? converted_value.empty? : converted_value.to_s.strip.empty?
48
+ end
49
+
50
+ def value
51
+ converted_value
52
+ end
53
+
54
+ protected
55
+
56
+ def validate_required
57
+ return unless @required
58
+
59
+ add_error("Missing :#{key}") if empty?
60
+ false
61
+ end
62
+
63
+ def validate_accepts
64
+ raise NotImplementedError
65
+ end
66
+
67
+ def converted_value
68
+ @converted_value ||= if converts.is_a?(Proc)
69
+ converts.call(@value)
70
+ elsif converts.is_a?(String) || converts.is_a?(Symbol)
71
+ @value.send(converts)
72
+ else
73
+ @value
74
+ end
75
+ end
76
+
77
+ def add_error(message)
78
+ @errors << message
79
+ @errors.uniq!
80
+ end
81
+
82
+ def compile_error_message
83
+ errors.join(', ')
84
+ end
85
+
86
+ private
87
+
88
+ def raise_if_any_errors!
89
+ raise ArgumentError, "Validation error: #{compile_error_message}" if errors.any?
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,33 @@
1
+ # typed: false
2
+
3
+ module Mangadex
4
+ module Internal
5
+ module Definitions
6
+ class ContentRating < Base
7
+ def initialize(value)
8
+ super(
9
+ value,
10
+ key: :content_rating,
11
+ accepts: Accepts.new(
12
+ array: Mangadex::ContentRating::VALUES,
13
+ class: Mangadex::ContentRating,
14
+ condition: :or,
15
+ ),
16
+ converts: :to_s,
17
+ required: false,
18
+ )
19
+ end
20
+
21
+ def validate_accepts
22
+ @accepts.validate!(converted_value)
23
+ rescue ArgumentError => error
24
+ add_error(error.message)
25
+ end
26
+
27
+ def validate_condition
28
+
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -6,6 +6,7 @@ module Mangadex
6
6
  module Internal
7
7
  class Request
8
8
  ALLOWED_METHODS = %i(get post put delete).freeze
9
+ SENSITIVE_FIELDS = %w(password token oldPassword newPassword)
9
10
 
10
11
  attr_accessor :path, :headers, :payload, :method, :raw
11
12
  attr_reader :response
@@ -16,19 +17,19 @@ module Mangadex
16
17
  method: :get,
17
18
  headers: headers,
18
19
  payload: nil,
19
- ).run!(raw: raw, auth: auth)
20
+ ).run_with_info!(raw: raw, auth: auth)
20
21
  end
21
22
 
22
23
  def self.post(path, headers: nil, auth: false, payload: nil, raw: false)
23
- new(path, method: :post, headers: headers, payload: payload).run!(raw: raw, auth: auth)
24
+ new(path, method: :post, headers: headers, payload: payload).run_with_info!(raw: raw, auth: auth)
24
25
  end
25
26
 
26
27
  def self.put(path, headers: nil, auth: false, payload: nil, raw: false)
27
- new(path, method: :put, headers: headers, payload: payload).run!(raw: raw, auth: auth)
28
+ new(path, method: :put, headers: headers, payload: payload).run_with_info!(raw: raw, auth: auth)
28
29
  end
29
30
 
30
31
  def self.delete(path, headers: nil, auth: false, payload: nil, raw: false)
31
- new(path, method: :delete, headers: headers, payload: payload).run!(raw: raw, auth: auth)
32
+ new(path, method: :delete, headers: headers, payload: payload).run_with_info!(raw: raw, auth: auth)
32
33
  end
33
34
 
34
35
  def initialize(path, method:, headers: nil, payload: nil)
@@ -47,19 +48,16 @@ module Mangadex
47
48
  )
48
49
  end
49
50
 
50
- def run!(raw: false, auth: false)
51
- payload_details = request_payload ? "Payload: #{sensitive_request_payload}" : "{no-payload}"
52
- puts("[#{self.class.name}] #{method.to_s.upcase} #{request_url} #{payload_details}")
51
+ def run_with_info!(*args, **kwargs)
52
+ measure_time_taken do
53
+ run!(*args, **kwargs)
54
+ end
55
+ end
53
56
 
57
+ def run!(raw: false, auth: false)
54
58
  raise Mangadex::Errors::UserNotLoggedIn.new if auth && Mangadex.context.user.nil?
55
59
 
56
- start_time = Time.now
57
-
58
60
  @response = request.execute
59
- end_time = Time.now
60
- elapsed_time = ((end_time - start_time) * 1000).to_i
61
- puts("[#{self.class.name}] took #{elapsed_time} ms")
62
-
63
61
  raw_request = raw || Mangadex.context.force_raw_requests
64
62
 
65
63
  if (body = @response.body)
@@ -95,6 +93,18 @@ module Mangadex
95
93
  data
96
94
  end
97
95
 
96
+ def measure_time_taken(&block)
97
+ payload_details = request_payload ? "Payload: #{sensitive_request_payload}" : "{no-payload}"
98
+ puts("[#{self.class.name}] #{method.to_s.upcase} #{request_url} #{payload_details}")
99
+ start_time = Time.now
100
+ result = yield
101
+
102
+ result
103
+ ensure
104
+ elapsed_time = ((Time.now - start_time) * 1000).to_i
105
+ puts("[#{self.class.name}] took #{elapsed_time} ms")
106
+ end
107
+
98
108
  def request_url
99
109
  request_path = path.start_with?('/') ? path : "/#{path}"
100
110
  "#{Mangadex.configuration.mangadex_url}#{request_path}"
@@ -106,7 +116,7 @@ module Mangadex
106
116
  JSON.generate(payload)
107
117
  end
108
118
 
109
- def sensitive_request_payload(sensitive_fields: %w(password token))
119
+ def sensitive_request_payload(sensitive_fields: SENSITIVE_FIELDS)
110
120
  payload = JSON.parse(request_payload)
111
121
  sensitive_fields.map(&:to_s).each do |field|
112
122
  payload[field] = '[REDACTED]' if payload.key?(field)
@@ -21,6 +21,7 @@ module Mangadex
21
21
  :version,
22
22
  :chapter_numbers_reset_on_new_volume,
23
23
  :available_translated_languages,
24
+ :latest_uploaded_chapter,
24
25
  :created_at,
25
26
  :updated_at
26
27
 
@@ -31,16 +32,17 @@ module Mangadex
31
32
  Mangadex::Internal::Request.get(
32
33
  '/manga',
33
34
  Mangadex::Internal::Definition.validate(args, {
34
- limit: { accepts: Integer },
35
+ limit: { accepts: Integer, converts: :to_i },
35
36
  offset: { accepts: Integer },
36
37
  title: { accepts: String },
38
+ author_or_artist: { accepts: String },
37
39
  authors: { accepts: [String] },
38
40
  artists: { accepts: [String] },
39
41
  year: { accepts: Integer },
40
42
  included_tags: { accepts: [String] },
41
- included_tags_mode: { accepts: %w(OR AND), converts: to_a },
43
+ included_tags_mode: { accepts: %w(OR AND) },
42
44
  excluded_tags: { accepts: [String] },
43
- excluded_tags_mode: { accepts: %w(OR AND), converts: to_a },
45
+ excluded_tags_mode: { accepts: %w(OR AND) },
44
46
  status: { accepts: %w(ongoing completed hiatus cancelled), converts: to_a },
45
47
  original_language: { accepts: [String] },
46
48
  excluded_original_language: { accepts: [String] },
@@ -114,11 +116,17 @@ module Mangadex
114
116
 
115
117
  sig { params(args: T::Api::Arguments).returns(T::Api::MangaResponse) }
116
118
  def self.random(**args)
119
+ to_a = Mangadex::Internal::Definition.converts(:to_a)
120
+
117
121
  Mangadex::Internal::Request.get(
118
122
  '/manga/random',
119
123
  Mangadex::Internal::Definition.validate(args, {
120
124
  includes: { accepts: Array },
121
125
  content_rating: { accepts: %w(safe suggestive erotica pornographic), converts: to_a },
126
+ included_tags: { accepts: [String] },
127
+ included_tags_mode: { accepts: %w(OR AND) },
128
+ excluded_tags: { accepts: [String] },
129
+ excluded_tags_mode: { accepts: %w(OR AND) },
122
130
  })
123
131
  )
124
132
  end
@@ -0,0 +1,19 @@
1
+ # typed: false
2
+
3
+ module Mangadex
4
+ class Rating < MangadexObject
5
+ has_attributes \
6
+ :rating,
7
+ :created_at
8
+
9
+ def self.list(**args)
10
+ Mangadex::Internal::Request.get(
11
+ '/rating',
12
+ Mangadex::Internal::Definition.validate(args, {
13
+ manga: { accepts: Array[String] },
14
+ }),
15
+ auth: true,
16
+ )
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,42 @@
1
+ module Mangadex
2
+ class Report < MangadexObject
3
+ has_attributes \
4
+ :details,
5
+ :object_id,
6
+ :status,
7
+ :created_at
8
+
9
+ sig { params(args: T::Api::Arguments).returns(Mangadex::Api::Response[Report]) }
10
+ def self.list(**args)
11
+ to_a = Mangadex::Internal::Definition.converts(:to_a)
12
+
13
+ Mangadex::Internal::Request.get(
14
+ '/report',
15
+ Mangadex::Internal::Definition.validate(args, {
16
+ limit: { accepts: Integer },
17
+ offset: { accepts: Integer },
18
+ category: { accepts: %w(manga chapter scanlation_group user author) },
19
+ reason_id: { accepts: String },
20
+ object_id: { accepts: String },
21
+ status: { accepts: %w(waiting accepted refused autoresolved) },
22
+ order: { accepts: Hash },
23
+ includes: { accepts: Array, converts: to_a },
24
+ }),
25
+ auth: true,
26
+ )
27
+ end
28
+
29
+ sig { params(args: T::Api::Arguments).returns(T::Api::GenericResponse) }
30
+ def create(**args)
31
+ Mangadex::Internal::Request.post(
32
+ '/report',
33
+ payload: Mangadex::Internal::Definition.validate(args, {
34
+ category: { accepts: %w(manga chapter scanlation_group user), required: true },
35
+ reason: { accepts: String, required: true },
36
+ object_id: { accepts: String, required: true },
37
+ details: { accepts: String },
38
+ }),
39
+ )
40
+ end
41
+ end
42
+ end
@@ -10,7 +10,7 @@ module Mangadex
10
10
  class << self
11
11
  def list(category)
12
12
  args = Mangadex::Internal::Definition.validate({category: category}, {
13
- category: { accepts: %w(manga chapter scanlation_group user), required: true },
13
+ category: { accepts: %w(manga chapter scanlation_group user author), required: true },
14
14
  })
15
15
 
16
16
  Mangadex::Internal::Request.get(
@@ -19,6 +19,9 @@ module Mangadex
19
19
  end
20
20
 
21
21
  def create(**args)
22
+ # TODO: create a "deprecated" log function
23
+ puts("[DEPRECATED] Use Mangadex::Report.create(...) instead.")
24
+
22
25
  Mangadex::Internal::Request.post(
23
26
  '/report',
24
27
  payload: Mangadex::Internal::Definition.validate(args, {
@@ -7,11 +7,14 @@ module T
7
7
  Text = T.type_alias { T.any(String, Symbol) }
8
8
 
9
9
  Arguments = T.type_alias do
10
- T.any(
11
- Text,
12
- T::Array[Text],
13
- Integer,
14
- T::Hash[Text, Text],
10
+ T.nilable(
11
+ T.any(
12
+ Text,
13
+ T::Array[Text],
14
+ Integer,
15
+ T::Hash[Text, Text],
16
+ Mangadex::ContentRating,
17
+ )
15
18
  )
16
19
  end
17
20
  MangaResponse = T.type_alias do
@@ -26,6 +29,12 @@ module T
26
29
  Mangadex::Api::Response[T::Array[Mangadex::Chapter]]
27
30
  )
28
31
  end
32
+ UserResponse = T.type_alias do
33
+ T.any(
34
+ Mangadex::Api::Response[Mangadex::User],
35
+ Mangadex::Api::Response[T::Array[Mangadex::User]]
36
+ )
37
+ end
29
38
  GenericResponse = T.type_alias do
30
39
  T.any(
31
40
  ::Hash,
@@ -0,0 +1,33 @@
1
+ # typed: false
2
+
3
+ module Mangadex
4
+ class Statistic < MangadexObject
5
+ has_attributes \
6
+ :rating,
7
+ :average,
8
+ :bayesian,
9
+ :distribution,
10
+ :follows
11
+
12
+ sig { params(uuid: String).returns(T::Api::GenericResponse) }
13
+ def self.get(uuid)
14
+ Mangadex::Internal::Definition.must(uuid)
15
+
16
+ Mangadex::Internal::Request.get(
17
+ '/statistics/manga/%{uuid}' % {uuid: uuid},
18
+ )
19
+ end
20
+
21
+ sig { params(args: T::Api::Arguments).returns(T::Api::GenericResponse) }
22
+ def self.list(**args)
23
+ to_a = Mangadex::Internal::Definition.converts(:to_a)
24
+
25
+ Mangadex::Internal::Request.get(
26
+ '/statistics/manga',
27
+ Mangadex::Internal::Definition.validate(args, {
28
+ manga: { accepts: [String], converts: to_a },
29
+ })
30
+ )
31
+ end
32
+ end
33
+ end
@@ -19,6 +19,9 @@ require_relative "user"
19
19
  require_relative "tag"
20
20
  require_relative "scanlation_group"
21
21
  require_relative "report_reason"
22
+ require_relative "report"
23
+ require_relative "rating"
24
+ require_relative "statistic"
22
25
 
23
26
  # Relationship
24
27
  require_relative "relationship"
data/lib/mangadex/user.rb CHANGED
@@ -6,6 +6,74 @@ module Mangadex
6
6
  :roles,
7
7
  :version
8
8
 
9
+ sig { params(args: T::Api::Arguments).returns(T::Api::UserResponse) }
10
+ def self.list(**args)
11
+ Mangadex::Internal::Request.get(
12
+ '/user',
13
+ Mangadex::Internal::Definition.validate(args, {
14
+ limit: { accepts: Integer },
15
+ offset: { accepts: Integer },
16
+ ids: { accepts: Array },
17
+ username: { accepts: String },
18
+ order: { accepts: Hash },
19
+ }),
20
+ auth: true,
21
+ )
22
+ end
23
+
24
+ sig { params(id: String).returns(T::Api::UserResponse) }
25
+ def self.get(id)
26
+ Mangadex::Internal::Request.get(
27
+ "/user/#{id}",
28
+ )
29
+ end
30
+
31
+ sig { params(id: String).returns(T::Api::GenericResponse) }
32
+ def self.delete(id)
33
+ Mangadex::Internal::Request.delete(
34
+ "/user/#{id}",
35
+ auth: true,
36
+ )
37
+ end
38
+
39
+ sig { params(code: String).returns(T::Api::GenericResponse) }
40
+ def self.delete_code(code)
41
+ Mangadex::Internal::Request.post(
42
+ "/user/delete/#{code}",
43
+ )
44
+ end
45
+
46
+ sig { params(old_password: String, new_password: String).returns(T::Api::GenericResponse) }
47
+ def self.update_password(old_password:, new_password:)
48
+ payload = {
49
+ oldPassword: old_password,
50
+ newPassword: new_password,
51
+ }
52
+
53
+ Mangadex::Internal::Request.post(
54
+ '/user/password',
55
+ payload: payload,
56
+ auth: true,
57
+ )
58
+ end
59
+
60
+ sig { params(email: String).returns(T::Api::GenericResponse) }
61
+ def self.update_email(email:)
62
+ Mangadex::Internal::Request.post(
63
+ '/user/email',
64
+ payload: { email: email },
65
+ auth: true,
66
+ )
67
+ end
68
+
69
+ sig { returns(T::Api::UserResponse) }
70
+ def self.current
71
+ Mangadex::Internal::Request.get(
72
+ '/user/me',
73
+ auth: true,
74
+ )
75
+ end
76
+
9
77
  sig { params(args: T::Api::Arguments).returns(Mangadex::Api::Response[Mangadex::Chapter]) }
10
78
  def self.feed(**args)
11
79
  Mangadex::Internal::Request.get(
@@ -2,9 +2,9 @@
2
2
  module Mangadex
3
3
  module Version
4
4
  MAJOR = "5"
5
- MINOR = "5"
6
- TINY = "8"
7
- PATCH = nil
5
+ MINOR = "7"
6
+ TINY = "5"
7
+ PATCH = "1"
8
8
 
9
9
  STRING = [MAJOR, MINOR, TINY].compact.join('.')
10
10
  FULL = [MAJOR, MINOR, TINY, PATCH].compact.join('.')
data/mangadex.gemspec CHANGED
@@ -29,7 +29,6 @@ Gem::Specification.new do |spec|
29
29
  spec.add_development_dependency "bundler", "~> 2.2.19"
30
30
  spec.add_development_dependency "rake", "~> 13.0"
31
31
  spec.add_development_dependency "rspec", "~> 3.0"
32
- spec.add_development_dependency "request_interceptor", "~> 1.0.0"
33
32
  spec.add_development_dependency "pry"
34
33
  spec.add_development_dependency "sorbet"
35
34
  end
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.5.8
4
+ version: 5.7.5.1
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: 2022-05-27 00:00:00.000000000 Z
11
+ date: 2022-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: psych
@@ -94,20 +94,6 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '3.0'
97
- - !ruby/object:Gem::Dependency
98
- name: request_interceptor
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: 1.0.0
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: 1.0.0
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: pry
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -144,6 +130,8 @@ extensions: []
144
130
  extra_rdoc_files: []
145
131
  files:
146
132
  - ".github/dependabot.yml"
133
+ - ".github/workflows/docker-image.yml"
134
+ - ".github/workflows/publish-gem.yml"
147
135
  - ".github/workflows/ruby.yml"
148
136
  - ".gitignore"
149
137
  - ".rspec"
@@ -161,6 +149,7 @@ files:
161
149
  - docker-compose.yml
162
150
  - docs/authentication.md
163
151
  - docs/context.md
152
+ - entrypoint.sh
164
153
  - lib/config.rb
165
154
  - lib/errors.rb
166
155
  - lib/extensions.rb
@@ -175,20 +164,27 @@ files:
175
164
  - lib/mangadex/auth.rb
176
165
  - lib/mangadex/author.rb
177
166
  - lib/mangadex/chapter.rb
167
+ - lib/mangadex/chapter_read_marker.rb
178
168
  - lib/mangadex/content_rating.rb
179
169
  - lib/mangadex/cover_art.rb
180
170
  - lib/mangadex/custom_list.rb
181
171
  - lib/mangadex/internal.rb
182
172
  - lib/mangadex/internal/context.rb
183
173
  - lib/mangadex/internal/definition.rb
174
+ - lib/mangadex/internal/definitions/accepts.rb
175
+ - lib/mangadex/internal/definitions/base.rb
176
+ - lib/mangadex/internal/definitions/content_rating.rb
184
177
  - lib/mangadex/internal/request.rb
185
178
  - lib/mangadex/internal/with_attributes.rb
186
179
  - lib/mangadex/manga.rb
187
180
  - lib/mangadex/mangadex_object.rb
181
+ - lib/mangadex/rating.rb
188
182
  - lib/mangadex/relationship.rb
183
+ - lib/mangadex/report.rb
189
184
  - lib/mangadex/report_reason.rb
190
185
  - lib/mangadex/scanlation_group.rb
191
186
  - lib/mangadex/sorbet.rb
187
+ - lib/mangadex/statistic.rb
192
188
  - lib/mangadex/storage.rb
193
189
  - lib/mangadex/storage/basic.rb
194
190
  - lib/mangadex/storage/memory.rb
@@ -250,7 +246,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
250
246
  - !ruby/object:Gem::Version
251
247
  version: '0'
252
248
  requirements: []
253
- rubygems_version: 3.2.32
249
+ rubygems_version: 3.3.7
254
250
  signing_key:
255
251
  specification_version: 4
256
252
  summary: Your next favourite Ruby gem for interacting with Mangadex.org