jnc_api 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/examples/feed/models.rb +18 -0
- data/examples/feed/tracker.rb +42 -25
- data/lib/jnc_api/version.rb +1 -1
- data/lib/jnc_api.rb +21 -12
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3974d29ba88445303cbe19210402f6b3acfb1ad8aa9ca9ee5f662025f04a9ab0
|
4
|
+
data.tar.gz: b50c7ba9e5ff1666565241497a974c35fef74ba957037d476d0a169d317b4ad9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5849dc5efaf3877966a24d1d399e41b1aaacece2969a9e1dcd05924c38712b1906f24d249b3a11144fb888f3edfaea4de1f6e96180463aab5cf64555a875901
|
7
|
+
data.tar.gz: 0ed4905c22b8ae2ea72d125bab66df8ff544879ecb6f8196afa853457aab45bf5246220c423066566422963d6fbde0bca0fb0775d67f496f757d36f5c25b423a
|
data/examples/feed/models.rb
CHANGED
@@ -46,8 +46,26 @@ ActiveRecord::Schema.define do
|
|
46
46
|
t.timestamps
|
47
47
|
end
|
48
48
|
end
|
49
|
+
|
50
|
+
unless table_exists?(:manga_parts)
|
51
|
+
create_table :manga_parts, force: :cascade do |t|
|
52
|
+
t.integer :part_id, null: false
|
53
|
+
t.text :uuid
|
54
|
+
t.text :ngtoken
|
55
|
+
t.text :kgtoken
|
56
|
+
t.text :webpub
|
57
|
+
t.timestamps
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
49
61
|
end
|
50
62
|
|
51
63
|
class Part < ActiveRecord::Base
|
64
|
+
has_many :manga_parts
|
52
65
|
serialize :crypt_data, coder: JSON
|
53
66
|
end
|
67
|
+
|
68
|
+
class MangaPart < ActiveRecord::Base
|
69
|
+
belongs_to :part
|
70
|
+
serialize :webpub, coder: JSON
|
71
|
+
end
|
data/examples/feed/tracker.rb
CHANGED
@@ -23,7 +23,7 @@ gemfile do
|
|
23
23
|
gem "activerecord", "~> 7.1", require: "active_record"
|
24
24
|
gem "sqlite3", "~> 1.4", require: "sqlite3"
|
25
25
|
gem "addressable", "~> 2.8", require: "addressable"
|
26
|
-
gem
|
26
|
+
gem "optparse", require: "optparse"
|
27
27
|
|
28
28
|
gem "jnc_api", path: "../..", require: "jnc_api"
|
29
29
|
end
|
@@ -55,18 +55,22 @@ def assign_part_from_json(part, p)
|
|
55
55
|
part.series_type = p["type"]
|
56
56
|
part.legacy_id = p["partLegacyId"]
|
57
57
|
part.title = p["partTitle"]
|
58
|
-
part.updated = p["updated"]
|
59
58
|
part.clear_data = p["clearData"]
|
60
59
|
end
|
61
60
|
|
62
61
|
options = {}
|
63
|
-
OptionParser
|
64
|
-
|
65
|
-
|
62
|
+
OptionParser
|
63
|
+
.new do |opts|
|
64
|
+
opts.on(
|
65
|
+
"--slug=SLUG",
|
66
|
+
"Only download this part as identified by the slug"
|
67
|
+
) { |s| options[:slug] = s }
|
66
68
|
end
|
67
|
-
|
69
|
+
.parse!
|
68
70
|
|
69
|
-
|
71
|
+
me = api.me
|
72
|
+
puts me
|
73
|
+
user_id = JSON.parse(me)["legacyId"]
|
70
74
|
|
71
75
|
if options[:slug]
|
72
76
|
opt_slug = options[:slug]
|
@@ -74,6 +78,7 @@ if options[:slug]
|
|
74
78
|
part = Part.find_or_create_by(slug: opt_slug)
|
75
79
|
|
76
80
|
assign_part_from_json(part, p)
|
81
|
+
part.updated = p["updated"]
|
77
82
|
|
78
83
|
part.save!
|
79
84
|
|
@@ -96,39 +101,51 @@ else
|
|
96
101
|
|
97
102
|
# skip items if the feed item is already seen
|
98
103
|
if part.date_published &&
|
99
|
-
|
104
|
+
item["date_published"].to_datetime == part.date_published.to_datetime
|
100
105
|
puts "Skipping part #{part.slug} (feed item already seen)"
|
106
|
+
|
101
107
|
next
|
102
108
|
end
|
103
109
|
|
104
|
-
|
110
|
+
puts "sleeping for 5s"
|
111
|
+
sleep 5
|
105
112
|
|
106
113
|
p = JSON.parse(api.parts_data(slug))
|
107
|
-
|
108
114
|
assign_part_from_json(part, p)
|
109
115
|
|
110
|
-
part.image = item["image"]
|
111
|
-
part.date_published = item["date_published"]
|
112
|
-
|
113
|
-
part.save!
|
114
|
-
|
115
|
-
# skip items that are not novels e.g. manga
|
116
|
-
# we currently have no way to decode the manga parts
|
117
|
-
if p["type"] != "NOVEL"
|
118
|
-
puts "Skipping part #{part.slug} (not NOVEL type unsupported)"
|
119
|
-
next
|
120
|
-
end
|
121
|
-
|
122
116
|
# skip items if the part is already up-to-date
|
123
117
|
if part.data && p["updated"].to_datetime == part.updated.to_datetime
|
124
118
|
puts "Skipping part #{part.slug} (feed item updated)"
|
119
|
+
|
125
120
|
next
|
126
121
|
end
|
127
122
|
|
128
|
-
|
123
|
+
# note: we currently have no way to descramble the manga parts
|
124
|
+
if p["type"] == "MANGA"
|
125
|
+
puts "part #{part.slug} is manga, downloading webpub"
|
126
|
+
tokens = JSON.parse(api.manga_parts(part.legacy_id))
|
127
|
+
manga_part = part.manga_parts.find_or_create_by(uuid: tokens["uuid"])
|
128
|
+
manga_part.uuid = tokens["uuid"]
|
129
|
+
manga_part.ngtoken = tokens["ngtoken"]
|
130
|
+
manga_part.kgtoken = tokens["kgtoken"]
|
131
|
+
|
132
|
+
puts tokens
|
133
|
+
puts "sleeping for 30s"
|
134
|
+
sleep 5
|
135
|
+
|
136
|
+
manga_part.webpub = api.webpub(tokens["uuid"], tokens["ngtoken"])
|
137
|
+
manga_part.save!
|
138
|
+
else
|
139
|
+
e = api.embed(p["partLegacyId"])
|
140
|
+
|
141
|
+
part.data = e
|
142
|
+
part.crypt_data = p["cryptData"]
|
143
|
+
end
|
144
|
+
|
145
|
+
part.image = item["image"]
|
146
|
+
part.date_published = item["date_published"]
|
147
|
+
part.updated = p["updated"]
|
129
148
|
|
130
|
-
part.data = e
|
131
|
-
part.crypt_data = p["cryptData"]
|
132
149
|
part.save!
|
133
150
|
|
134
151
|
puts "Updated part #{part.slug}"
|
data/lib/jnc_api/version.rb
CHANGED
data/lib/jnc_api.rb
CHANGED
@@ -32,7 +32,7 @@ module JncApi
|
|
32
32
|
embed: "https://labs.j-novel.club/embed/",
|
33
33
|
completion: "https://labs.j-novel.club/app/v1/me/completion",
|
34
34
|
manga_parts: "https://api.j-novel.club/api/mangaParts",
|
35
|
-
webpub: "https://m11.j-novel.club/nebel/wp"
|
35
|
+
webpub: "https://m11.j-novel.club/nebel/wp"
|
36
36
|
}
|
37
37
|
|
38
38
|
class Api
|
@@ -44,7 +44,7 @@ module JncApi
|
|
44
44
|
routes[:login] + "?format=json",
|
45
45
|
body:
|
46
46
|
JSON.generate(
|
47
|
-
{"login" => login, "password" => password, "slim" => true}
|
47
|
+
{ "login" => login, "password" => password, "slim" => true }
|
48
48
|
),
|
49
49
|
headers: {
|
50
50
|
"Content-Type" => "application/json"
|
@@ -61,8 +61,15 @@ module JncApi
|
|
61
61
|
def initialize(routes: V1_ROUTES, token: nil)
|
62
62
|
@routes = routes
|
63
63
|
@token = token
|
64
|
-
@default_headers = {
|
65
|
-
|
64
|
+
@default_headers = {
|
65
|
+
"User-Agent" =>
|
66
|
+
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:127.0) Gecko/20100101 Firefox/127.0",
|
67
|
+
"Accept" =>
|
68
|
+
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
69
|
+
"Accept-Language" => "en-US,en;q=0.5",
|
70
|
+
"Content-Type" => "application/json"
|
71
|
+
}
|
72
|
+
@bearer = { "Authorization" => "Bearer #{@token}" }
|
66
73
|
end
|
67
74
|
|
68
75
|
def series_list(limit: 500, skip: 0)
|
@@ -163,9 +170,10 @@ module JncApi
|
|
163
170
|
# we can't seem to use bearer tokens for the manga endpoints
|
164
171
|
def manga_parts(part_id)
|
165
172
|
response =
|
166
|
-
|
167
|
-
|
168
|
-
|
173
|
+
HTTParty.get(
|
174
|
+
@routes[:manga_parts] + "/#{part_id}/token?access_token=#{@token}",
|
175
|
+
headers: @default_headers
|
176
|
+
)
|
169
177
|
|
170
178
|
if response.success?
|
171
179
|
response.body
|
@@ -178,10 +186,12 @@ module JncApi
|
|
178
186
|
# likely for cheaper static hosting (as long as the locations are
|
179
187
|
# difficult to guess such as uuid)
|
180
188
|
def webpub(uuid, ngtoken)
|
181
|
-
response =
|
182
|
-
|
183
|
-
|
184
|
-
|
189
|
+
response =
|
190
|
+
HTTParty.post(
|
191
|
+
@routes[:webpub] + "/#{uuid}",
|
192
|
+
body: ngtoken,
|
193
|
+
headers: @default_headers
|
194
|
+
)
|
185
195
|
|
186
196
|
if response.success?
|
187
197
|
response.body
|
@@ -189,6 +199,5 @@ module JncApi
|
|
189
199
|
raise Error.new(response.inspect)
|
190
200
|
end
|
191
201
|
end
|
192
|
-
|
193
202
|
end
|
194
203
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jnc_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- parasquid
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -71,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
71
|
- !ruby/object:Gem::Version
|
72
72
|
version: '0'
|
73
73
|
requirements: []
|
74
|
-
rubygems_version: 3.4.
|
74
|
+
rubygems_version: 3.4.20
|
75
75
|
signing_key:
|
76
76
|
specification_version: 4
|
77
77
|
summary: Light wrapper for the J-Novel Club API.
|