mangadex 5.5.6 → 5.7.5

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: 9af83b63f2dd0e3b6a23a1536fbf726979ba352a28d9625f8056366709520c19
4
- data.tar.gz: 92587895df8db92ef0910f2e3ee6adb6b0a92891f77e358a90a49f08a24b8eb2
3
+ metadata.gz: 16387ee156618cba16f7f1a730c94a8e6856dd379886cf7ef0124826efe010c5
4
+ data.tar.gz: f5edff601db0ccef8580a3b108a0a79b123e427c64607317b05cdcba6cc460fc
5
5
  SHA512:
6
- metadata.gz: a236969d31689030cc2695cbb2f5faaba6a449e950c651a8bf008967580e1ca81989b997c33d9d69b594d5f81406c4797300388dc01d6446c010506ab4e81b67
7
- data.tar.gz: 9bc990f30a1a2962f40cce8b3bff9b95903a17b46840708f1016ee0b4dffe5e990a4a2ecb0d24c461a160d0947b0ada7034840f281de0c620ad7e55ad9b86959
6
+ metadata.gz: 10affdcc160415a2a38187ef0518011d2982364d1df79a02e0253df05a4aacefc1b489895cf0b81b39d1c172ce0632b9432869f65103962308cc080c70693166
7
+ data.tar.gz: e2eaa50eaed120768286a3c76f55f27ee43d258b7d445891c0ff941c5bf5364f468b3e171607d04542840b28ef729fdfbca7a823865cff95ea8d6cbf61f3cd72
@@ -0,0 +1,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "bundler" # See documentation for possible values
9
+ directory: "/" # Location of package manifests
10
+ schedule:
11
+ interval: "daily"
@@ -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.6)
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.1)
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
- http-cookie (1.0.4)
17
+ http-cookie (1.0.5)
29
18
  domain_name (~> 0.5)
30
- i18n (1.9.1)
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.3)
27
+ psych (4.0.6)
44
28
  stringio
45
- public_suffix (4.0.6)
46
- rack (2.2.3)
47
- rack-protection (2.1.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.10.0)
63
- rspec-core (~> 3.10.0)
64
- rspec-expectations (~> 3.10.0)
65
- rspec-mocks (~> 3.10.0)
66
- rspec-core (3.10.2)
67
- rspec-support (~> 3.10.0)
68
- rspec-expectations (3.10.2)
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.10.0)
71
- rspec-mocks (3.10.3)
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.10.0)
74
- rspec-support (3.10.3)
75
- ruby2_keywords (0.0.5)
76
- sinatra (2.1.0)
77
- mustermann (~> 1.0)
78
- rack (~> 2.2)
79
- rack-protection (= 2.1.0)
80
- tilt (~> 2.0)
81
- smart_properties (1.17.0)
82
- sorbet (0.5.9619)
83
- sorbet-static (= 0.5.9619)
84
- sorbet-runtime (0.5.9724)
85
- sorbet-static (0.5.9619-x86_64-linux)
86
- stringio (3.0.1)
87
- tilt (2.0.10)
88
- tzinfo (2.0.4)
89
- concurrent-ruby (~> 1.0)
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)
52
+ stringio (3.0.2)
90
53
  unf (0.1.4)
91
54
  unf_ext
92
- unf_ext (0.0.8)
93
- webmock (3.14.0)
94
- addressable (>= 2.8.0)
95
- crack (>= 0.3.2)
96
- hashdiff (>= 0.4.0, < 2.0.0)
55
+ unf_ext (0.0.8.2)
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)
@@ -92,6 +92,12 @@ module Mangadex
92
92
  Array(relationships).any?
93
93
  end
94
94
 
95
+ def every(relationship_type)
96
+ Array(relationships).select do |relationship|
97
+ relationship.type == relationship_type.to_s
98
+ end
99
+ end
100
+
95
101
  def method_missing(method_name, *args, **kwargs)
96
102
  if self.class.attributes.include?(method_name.to_sym)
97
103
  return if attributes.nil?
@@ -103,10 +109,10 @@ module Mangadex
103
109
  looking_for_relationship = method_name.to_s
104
110
 
105
111
  if existing_relationships.include?(looking_for_relationship)
106
- result = relationships.select do |relationship|
112
+ relationships.find do |relationship|
107
113
  relationship.type == looking_for_relationship
108
114
  end
109
- result.size == 1 ? result.first : result
115
+ # result.size == 1 ? result.first : result
110
116
  else
111
117
  super
112
118
  end
@@ -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 = "6"
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.6
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-03-06 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
@@ -143,6 +129,8 @@ executables: []
143
129
  extensions: []
144
130
  extra_rdoc_files: []
145
131
  files:
132
+ - ".github/dependabot.yml"
133
+ - ".github/workflows/docker-image.yml"
146
134
  - ".github/workflows/ruby.yml"
147
135
  - ".gitignore"
148
136
  - ".rspec"
@@ -160,6 +148,7 @@ files:
160
148
  - docker-compose.yml
161
149
  - docs/authentication.md
162
150
  - docs/context.md
151
+ - entrypoint.sh
163
152
  - lib/config.rb
164
153
  - lib/errors.rb
165
154
  - lib/extensions.rb
@@ -174,20 +163,27 @@ files:
174
163
  - lib/mangadex/auth.rb
175
164
  - lib/mangadex/author.rb
176
165
  - lib/mangadex/chapter.rb
166
+ - lib/mangadex/chapter_read_marker.rb
177
167
  - lib/mangadex/content_rating.rb
178
168
  - lib/mangadex/cover_art.rb
179
169
  - lib/mangadex/custom_list.rb
180
170
  - lib/mangadex/internal.rb
181
171
  - lib/mangadex/internal/context.rb
182
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
183
176
  - lib/mangadex/internal/request.rb
184
177
  - lib/mangadex/internal/with_attributes.rb
185
178
  - lib/mangadex/manga.rb
186
179
  - lib/mangadex/mangadex_object.rb
180
+ - lib/mangadex/rating.rb
187
181
  - lib/mangadex/relationship.rb
182
+ - lib/mangadex/report.rb
188
183
  - lib/mangadex/report_reason.rb
189
184
  - lib/mangadex/scanlation_group.rb
190
185
  - lib/mangadex/sorbet.rb
186
+ - lib/mangadex/statistic.rb
191
187
  - lib/mangadex/storage.rb
192
188
  - lib/mangadex/storage/basic.rb
193
189
  - lib/mangadex/storage/memory.rb