mangadex 5.5.8 → 5.7.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '038676da7b94f64da0e1ba27d2a0f2563153bf785fc027830132330fcaa6db41'
4
- data.tar.gz: 219bc69785823ce34145b10103149d3f397803a7a8a77732a5ee98983162e211
3
+ metadata.gz: 16387ee156618cba16f7f1a730c94a8e6856dd379886cf7ef0124826efe010c5
4
+ data.tar.gz: f5edff601db0ccef8580a3b108a0a79b123e427c64607317b05cdcba6cc460fc
5
5
  SHA512:
6
- metadata.gz: fab8f18bd656d148f42513e316389b6505aa63c24fc9be2722f8ac4752f9dfb2bfde8749769af69acdf2d90714aa64e87f82ad40a0405cc3bd7158240bb998cc
7
- data.tar.gz: 4f539c62ada95b984cf96f04b2450385b3bf348d8efcbbb501ab67ac9f21f70c38fb082763b68a3c3851fb572047a07650ab4f80a975987aadea9fb5f4ae505a
6
+ metadata.gz: 10affdcc160415a2a38187ef0518011d2982364d1df79a02e0253df05a4aacefc1b489895cf0b81b39d1c172ce0632b9432869f65103962308cc080c70693166
7
+ data.tar.gz: e2eaa50eaed120768286a3c76f55f27ee43d258b7d445891c0ff941c5bf5364f468b3e171607d04542840b28ef729fdfbca7a823865cff95ea8d6cbf61f3cd72
@@ -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
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.6.0.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.10526)
49
+ sorbet-static (= 0.5.10526)
50
+ sorbet-runtime (0.5.10520)
51
+ sorbet-static (0.5.10526-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
@@ -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
@@ -94,7 +100,10 @@ module Mangadex
94
100
 
95
101
  class << self
96
102
  def converts(key=nil)
97
- procs = { to_a: -> ( x ) { Array(x) } }
103
+ procs = {
104
+ to_a: -> ( x ) { Array(x) },
105
+ to_i: -> ( x ) { Integer(x.to_s, 10) if x },
106
+ }
98
107
  return procs if key.nil?
99
108
 
100
109
  procs[key]
@@ -115,13 +124,16 @@ module Mangadex
115
124
  translated_language: { accepts: [String], converts: converts(:to_a) },
116
125
  original_language: { accepts: [String] },
117
126
  excluded_original_language: { accepts: [String] },
118
- content_rating: { accepts: %w(safe suggestive erotica pornographic), converts: converts(:to_a) },
127
+ content_rating: Definitions::ContentRating,
119
128
  include_future_updates: { accepts: %w(0 1) },
120
129
  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
130
  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
131
  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
132
  order: { accepts: Hash },
124
133
  includes: { accepts: [String], converts: converts(:to_a) },
134
+ include_empty_pages: { accepts: [0, 1], converts: converts(:to_i) },
135
+ include_future_publish_at: { accepts: [0, 1], converts: converts(:to_i) },
136
+ include_external_url: { accepts: [0, 1], converts: converts(:to_i) },
125
137
  },
126
138
  )
127
139
  end
@@ -151,8 +163,17 @@ module Mangadex
151
163
  end
152
164
 
153
165
  definition.each do |key, definition|
154
- validator = Definition.new(key, args[key], **definition.symbolize_keys)
155
- validation_error = validator.error
166
+ validation_error = if definition.is_a?(Class) && definition < Definitions::Base
167
+ validator = definition.new(args[key])
168
+ validator.validate
169
+ validator.error_message
170
+ elsif !definition.is_a?(Class)
171
+ validator = Definition.new(key, args[key], **definition.symbolize_keys)
172
+ validator.error
173
+ else
174
+ raise "Invalid definition class: #{definition}"
175
+ end
176
+
156
177
  if validation_error
157
178
  errors << { message: validation_error }
158
179
  elsif !validator.empty?
@@ -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
 
@@ -34,13 +35,14 @@ module Mangadex
34
35
  limit: { accepts: Integer },
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, {
@@ -12,6 +12,7 @@ module T
12
12
  T::Array[Text],
13
13
  Integer,
14
14
  T::Hash[Text, Text],
15
+ Mangadex::ContentRating,
15
16
  )
16
17
  end
17
18
  MangaResponse = T.type_alias do
@@ -26,6 +27,12 @@ module T
26
27
  Mangadex::Api::Response[T::Array[Mangadex::Chapter]]
27
28
  )
28
29
  end
30
+ UserResponse = T.type_alias do
31
+ T.any(
32
+ Mangadex::Api::Response[Mangadex::User],
33
+ Mangadex::Api::Response[T::Array[Mangadex::User]]
34
+ )
35
+ end
29
36
  GenericResponse = T.type_alias do
30
37
  T.any(
31
38
  ::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,8 +2,8 @@
2
2
  module Mangadex
3
3
  module Version
4
4
  MAJOR = "5"
5
- MINOR = "5"
6
- TINY = "8"
5
+ MINOR = "7"
6
+ TINY = "5"
7
7
  PATCH = nil
8
8
 
9
9
  STRING = [MAJOR, MINOR, TINY].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
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-03 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,7 @@ extensions: []
144
130
  extra_rdoc_files: []
145
131
  files:
146
132
  - ".github/dependabot.yml"
133
+ - ".github/workflows/docker-image.yml"
147
134
  - ".github/workflows/ruby.yml"
148
135
  - ".gitignore"
149
136
  - ".rspec"
@@ -161,6 +148,7 @@ files:
161
148
  - docker-compose.yml
162
149
  - docs/authentication.md
163
150
  - docs/context.md
151
+ - entrypoint.sh
164
152
  - lib/config.rb
165
153
  - lib/errors.rb
166
154
  - lib/extensions.rb
@@ -175,20 +163,27 @@ files:
175
163
  - lib/mangadex/auth.rb
176
164
  - lib/mangadex/author.rb
177
165
  - lib/mangadex/chapter.rb
166
+ - lib/mangadex/chapter_read_marker.rb
178
167
  - lib/mangadex/content_rating.rb
179
168
  - lib/mangadex/cover_art.rb
180
169
  - lib/mangadex/custom_list.rb
181
170
  - lib/mangadex/internal.rb
182
171
  - lib/mangadex/internal/context.rb
183
172
  - lib/mangadex/internal/definition.rb
173
+ - lib/mangadex/internal/definitions/accepts.rb
174
+ - lib/mangadex/internal/definitions/base.rb
175
+ - lib/mangadex/internal/definitions/content_rating.rb
184
176
  - lib/mangadex/internal/request.rb
185
177
  - lib/mangadex/internal/with_attributes.rb
186
178
  - lib/mangadex/manga.rb
187
179
  - lib/mangadex/mangadex_object.rb
180
+ - lib/mangadex/rating.rb
188
181
  - lib/mangadex/relationship.rb
182
+ - lib/mangadex/report.rb
189
183
  - lib/mangadex/report_reason.rb
190
184
  - lib/mangadex/scanlation_group.rb
191
185
  - lib/mangadex/sorbet.rb
186
+ - lib/mangadex/statistic.rb
192
187
  - lib/mangadex/storage.rb
193
188
  - lib/mangadex/storage/basic.rb
194
189
  - lib/mangadex/storage/memory.rb
@@ -250,7 +245,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
250
245
  - !ruby/object:Gem::Version
251
246
  version: '0'
252
247
  requirements: []
253
- rubygems_version: 3.2.32
248
+ rubygems_version: 3.2.15
254
249
  signing_key:
255
250
  specification_version: 4
256
251
  summary: Your next favourite Ruby gem for interacting with Mangadex.org