comic_walker 0.2.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 31c86d5ee6917c1d2443b444ad0af64ea30312b7
4
- data.tar.gz: ad9a19cdaba4cc3ef9e78caaf4283e1024e25e1e
3
+ metadata.gz: 7fe84087441847fad172320a68b0a4849d5ccb0f
4
+ data.tar.gz: ad4627cd74295d5e64c457d74729cd379dedb10f
5
5
  SHA512:
6
- metadata.gz: 484678c62454decd50c4153b0f3b9f2ab5e018f4cf08d26ffa61196a3d3132968a1c6cf09df458aef884a179874936c90e4d3a5fdadcb18989eaee0b83d56034
7
- data.tar.gz: 0265eec741fde6d0d8a647d4023ab5578e66d3e6917341295fa5fe53c8d414606965a12225da895d2dedb9bdad3c688555b2be4cf54f4d16c5358e368de2ccce
6
+ metadata.gz: 7ca5b14ea61e4a6118ee906b64e7dff21b95ec07b9c9e70827b765d6952fb8d824973bb1ba50ffe8ed918a40030d2f625d29621d41a69d2380cadc43d4bedbcf
7
+ data.tar.gz: 62076faf1ff081f17c5f42e5e9cba25949ad523eb87c3e2b54fda226524cfdd7b9e4be0bd6db98670776eca38666ea4a63c8b9c576c05020650989c1ca68a14c
@@ -1,3 +1,9 @@
1
+ # 0.3.0 (2014-05-12)
2
+ - Download configuration_pack and images directly
3
+ - Drop jar file download
4
+ - Drop base64-encoded image decoder
5
+ - Many internal method changes
6
+
1
7
  # 0.2.2 (2014-05-11)
2
8
  - Fix image fetch errors for recent comics
3
9
 
@@ -23,7 +23,8 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "yard"
24
24
  spec.add_dependency "addressable"
25
25
  spec.add_dependency "http-cookie"
26
+ spec.add_dependency "net-http-persistent"
27
+ spec.add_dependency "retryable"
26
28
  spec.add_dependency "rmagick"
27
- spec.add_dependency "rubyzip"
28
29
  spec.add_dependency "thor"
29
30
  end
@@ -4,7 +4,7 @@ require 'pp'
4
4
  require 'thor'
5
5
  require 'yaml'
6
6
  require 'comic_walker/client'
7
- require 'comic_walker/end_layer_decoder'
7
+ require 'comic_walker/content_downloader'
8
8
  require 'comic_walker/item_decoder'
9
9
  require 'comic_walker/v1/client'
10
10
 
@@ -20,7 +20,7 @@ module ComicWalker
20
20
  def save(*cids)
21
21
  client = Client.new
22
22
  cids.each do |cid|
23
- save_content(client, cid)
23
+ ContentDownloader.new(client, cid).save
24
24
  end
25
25
  end
26
26
 
@@ -45,9 +45,7 @@ module ComicWalker
45
45
  jar = HTTP::CookieJar.new
46
46
  load_cookies(jar)
47
47
  client = V1::Client.new(jar, load_uuid)
48
- json = client.start do
49
- client.contents(per_page: options[:per_page], page: options[:page])
50
- end
48
+ json = client.contents(per_page: options[:per_page], page: options[:page])
51
49
  save_cookies(jar)
52
50
 
53
51
  json['contents'].sort_by { |content| Time.parse(content['updated_at']) }.reverse_each do |content|
@@ -72,48 +70,6 @@ module ComicWalker
72
70
 
73
71
  private
74
72
 
75
- def save_content(client, cid)
76
- license = client.get_license(cid)
77
- info = license.get_info.first
78
- last_update = Time.strptime(info['last_update'], '%Y%m%d%H%M')
79
- title = info['issues'].first['content_name']
80
-
81
- license.with_jar do |zip|
82
- pages = []
83
- items = {}
84
- decoder = nil
85
- while entry = zip.get_next_entry
86
- case entry.name
87
- when 'configuration_pack.json'
88
- config = JSON.parse(zip.read)
89
- decoder = ItemDecoder.new(config)
90
- when /end_layer\.json/
91
- begin
92
- pp EndLayerDecoder.new(license.key).decode(zip.read)
93
- rescue JSON::ParserError
94
- $stderr.puts "WARNING: #{cid}: Could not decode end_layer.json.enc"
95
- end
96
- when %r{\Aitem/}
97
- items[entry.name] = zip.read
98
- end
99
- end
100
-
101
- img_dir = Pathname.new(title).join(cid).tap(&:mkpath)
102
- decoder.pages.each.with_index do |file, i|
103
- dat_path = Pathname.new(file).join('0.dat')
104
- img_fname = dat_path.parent.basename.sub_ext('.jpg')
105
- img_path = img_dir.join(sprintf('%03d_%s', i, img_fname))
106
-
107
- if data = items[dat_path.to_s]
108
- decoder.decode_b64(file, dat_path, img_path, data)
109
- else
110
- decoder.decode(file, dat_path, img_path, license.get_jpeg(file))
111
- end
112
- puts "#{dat_path} -> #{img_path}"
113
- end
114
- end
115
- end
116
-
117
73
  def load_cookies(jar)
118
74
  if COOKIE_PATH.readable?
119
75
  jar.load(COOKIE_PATH.to_s, session: true)
@@ -147,20 +103,18 @@ module ComicWalker
147
103
  page = 1
148
104
  per_page = 200
149
105
  child_cids = {}
150
- client.start do
151
- until child_cids.size == parent_cids do
152
- json = client.contents(page: page, per_page: per_page)
153
- contents = json['contents']
154
- if contents.empty?
155
- break
156
- end
157
- contents.each do |c|
158
- if parent_cids.include?(c['content_id'])
159
- child_cids[c['content_id']] = c['sub_contents']
160
- end
106
+ until child_cids.size == parent_cids do
107
+ json = client.contents(page: page, per_page: per_page)
108
+ contents = json['contents']
109
+ if contents.empty?
110
+ break
111
+ end
112
+ contents.each do |c|
113
+ if parent_cids.include?(c['content_id'])
114
+ child_cids[c['content_id']] = c['sub_contents']
161
115
  end
162
- page += 1
163
116
  end
117
+ page += 1
164
118
  end
165
119
  parent_cids.each do |cid|
166
120
  unless child_cids.has_key?(cid)
@@ -1,23 +1,19 @@
1
- require 'addressable/uri'
1
+ require 'uri'
2
2
  require 'base64'
3
- require 'net/http'
4
- require 'zip'
3
+ require 'net/http/persistent'
5
4
 
6
5
  module ComicWalker
7
6
  class Client
8
7
  class License
9
8
  def initialize(json)
10
9
  @json = json
10
+ @http = Net::HTTP::Persistent.new('comic_walker')
11
11
  end
12
12
 
13
13
  def agreement
14
14
  @json['agreement']
15
15
  end
16
16
 
17
- def jar_url
18
- url_prefix + agreement['jar_file_name']
19
- end
20
-
21
17
  def info_url
22
18
  url_prefix + agreement['info_file_name']
23
19
  end
@@ -26,31 +22,26 @@ module ComicWalker
26
22
  agreement['url_prefix']
27
23
  end
28
24
 
29
- def key
30
- Base64.decode64(agreement['key'])
25
+ CONFIGURATION_PACK_FILENAME = 'configuration_pack.json'
26
+
27
+ def configuration_pack_url
28
+ url_prefix + CONFIGURATION_PACK_FILENAME
29
+ end
30
+
31
+ def get(url)
32
+ @http.request(URI.parse(url))
31
33
  end
32
34
 
33
- def with_jar(&block)
34
- uri = Addressable::URI.parse(jar_url)
35
- body = Net::HTTP.start(uri.host) do |http|
36
- http.get(uri.request_uri).body
37
- end
38
- Zip::InputStream.open(StringIO.new(body), &block)
35
+ def get_configuration_pack
36
+ JSON.parse(get(configuration_pack_url).body)
39
37
  end
40
38
 
41
39
  def get_info
42
- uri = Addressable::URI.parse(info_url)
43
- body = Net::HTTP.start(uri.host) do |http|
44
- http.get(uri.request_uri).body
45
- end
46
- JSON.parse(body)
40
+ JSON.parse(get(info_url).body)
47
41
  end
48
42
 
49
43
  def get_jpeg(file)
50
- uri = Addressable::URI.parse(url_prefix + file + '/0.jpeg')
51
- Net::HTTP.start(uri.host) do |http|
52
- http.get(uri.request_uri).body
53
- end
44
+ get(url_prefix + file + '/0.jpeg').body
54
45
  end
55
46
  end
56
47
  end
@@ -0,0 +1,27 @@
1
+ module ComicWalker
2
+ class ContentDownloader
3
+ def initialize(client, cid)
4
+ @client = client
5
+ @cid = cid
6
+ end
7
+
8
+ def save
9
+ license = @client.get_license(@cid)
10
+ decoder = ItemDecoder.new(license.get_configuration_pack)
11
+ img_dir = image_dir(license)
12
+ decoder.pages.each.with_index do |file, i|
13
+ dat_path = Pathname.new(file).join('0.dat')
14
+ img_fname = dat_path.parent.basename.sub_ext('.jpg')
15
+ img_path = img_dir.join(sprintf('%03d_%s', i, img_fname))
16
+ decoder.decode(file, dat_path, img_path, license.get_jpeg(file))
17
+ puts "#{dat_path} -> #{img_path}"
18
+ end
19
+ end
20
+
21
+ def image_dir(license)
22
+ info = license.get_info.first
23
+ title = info['issues'].first['content_name']
24
+ Pathname.new(title).join(@cid).tap(&:mkpath)
25
+ end
26
+ end
27
+ end
@@ -5,18 +5,7 @@ module ComicWalker
5
5
  class ItemDecoder
6
6
  attr_reader :pages
7
7
 
8
- DEFAULT_CT = '20000101000000'
9
- DEFAULT_ST = '20000101000000'
10
- DEFAULT_ET = '99991231235959'
11
-
12
8
  def initialize(configuration_pack)
13
- fname = '0.dat'
14
- ct = configuration_pack['ct'] || DEFAULT_CT
15
- st = configuration_pack['st'] || DEFAULT_ST
16
- et = configuration_pack['et'] || DEFAULT_ET
17
- @key1 = (ct + st + fname).unpack('C*')
18
- @key2 = (ct + fname + et).unpack('C*')
19
- @key3 = (fname + st + et).unpack('C*')
20
9
  @pages = []
21
10
  configuration_pack['configuration']['contents'].each do |content|
22
11
  pages[content['index']-1] = content['file']
@@ -27,19 +16,6 @@ module ComicWalker
27
16
  end
28
17
  end
29
18
 
30
- def decode_b64(file, dat_path, img_path, b64data)
31
- bs = 128
32
- hs = 1024
33
- blob = Unknown.finish(@key1, hs,
34
- Unknown.decrypt(@key2, bs,
35
- Unknown.prepare(@key3,
36
- Base64.decode64(b64data).unpack('C*')
37
- )
38
- )
39
- ).pack('C*')
40
- decode(file, dat_path, img_path, blob)
41
- end
42
-
43
19
  def decode(file, dat_path, img_path, blob)
44
20
  src = Magick::Image.from_blob(blob).first
45
21
  width = src.columns
@@ -5,47 +5,6 @@ module ComicWalker
5
5
  module Unknown
6
6
  module_function
7
7
 
8
- # @param [Array<Fixnum>] key
9
- # @param [Array<Fixnum>] data Encrypted data
10
- # @return [Array<Fixnum>]
11
- def prepare(key, data)
12
- s = Cipher.gen_rc4_table(key)
13
- data.map.with_index do |b, i|
14
- b ^ s[i % 256]
15
- end
16
- end
17
-
18
- # @param [Array<Fixnum>] key
19
- # @param [Integer] bsize block size?
20
- # @param [Array<Fixnum>] data Encrypted data
21
- # @return [Array<Fixnum>] Chunked decrypted data
22
- def decrypt(key, bsize, data)
23
- s = []
24
- 0.step(data.size-1, bsize) do |i|
25
- s << data[i]
26
- end
27
-
28
- c = Cipher.decrypt_rc4(key, s)
29
- # s.size == c.size
30
-
31
- 0.step(data.size-1, bsize) do |i|
32
- data[i] = c.shift
33
- end
34
- data
35
- end
36
-
37
- # @param [Array<Fixnum>] key
38
- # @param [Integer] hsize header size?
39
- # @param [Array<Fixnum>] data Encrypted data
40
- # @return [Array<Fixnum>] data
41
- def finish(key, hsize, data)
42
- hsize = [hsize, data.size].min
43
- Cipher.decrypt_rc4(key, data.slice(0, hsize)).each.with_index do |x, i|
44
- data[i] = x
45
- end
46
- data
47
- end
48
-
49
8
  # Calculate moves.
50
9
  # @param [Integer] width Width of the image
51
10
  # @param [Integer] height Height of the image
@@ -1,7 +1,9 @@
1
1
  require 'addressable/uri'
2
2
  require 'http-cookie'
3
3
  require 'json'
4
- require 'net/http'
4
+ require 'net/http/persistent'
5
+ require 'retryable'
6
+ require 'uri'
5
7
 
6
8
  module ComicWalker
7
9
  module V1
@@ -9,19 +11,11 @@ module ComicWalker
9
11
  BASE_URI = Addressable::URI.parse("https://cnts.comic-walker.com")
10
12
 
11
13
  def initialize(jar, uuid)
12
- @https = Net::HTTP.new(BASE_URI.host, 443)
13
- @https.use_ssl = true
14
- @https.verify_mode = OpenSSL::SSL::VERIFY_PEER
14
+ @https = Net::HTTP::Persistent.new('comic_walker')
15
15
  @jar = jar
16
16
  @uuid = uuid
17
17
  end
18
18
 
19
- def start(&block)
20
- @https.start do
21
- block.call
22
- end
23
- end
24
-
25
19
  AID = 'KDCWI_JP'
26
20
  AVER = '1.2.0'
27
21
 
@@ -31,8 +25,8 @@ module ComicWalker
31
25
  end
32
26
 
33
27
  def create_session
34
- retried = 0
35
- begin
28
+ on_exception = lambda { |exception| create_user }
29
+ retryable(tries: 2, on: UnknownDeviceError, sleep: 0, exception_cb: on_exception) do
36
30
  res = post('/user_sessions/create', {
37
31
  DID: @uuid,
38
32
  PIN: @uuid,
@@ -47,14 +41,6 @@ module ComicWalker
47
41
  else
48
42
  JSON.parse(res.body)
49
43
  end
50
- rescue UnknownDeviceError => e
51
- if retried == 0
52
- retried += 1
53
- create_user
54
- retry
55
- else
56
- raise e
57
- end
58
44
  end
59
45
  end
60
46
 
@@ -68,7 +54,6 @@ module ComicWalker
68
54
  end
69
55
 
70
56
  def contents(params = {})
71
- retried = 0
72
57
  params = {
73
58
  AID: AID,
74
59
  AVER: AVER,
@@ -80,7 +65,8 @@ module ComicWalker
80
65
  languages: 'ja',
81
66
  }.merge(params)
82
67
 
83
- begin
68
+ on_exception = lambda { |exception| create_session }
69
+ retryable(tries: 2, on: NoValidSessionError, sleep: 0, exception_cb: on_exception) do
84
70
  res = get('/v1/contents', params)
85
71
  case res.body
86
72
  when 'NoValidSessionError'
@@ -88,14 +74,6 @@ module ComicWalker
88
74
  else
89
75
  JSON.parse(res.body)
90
76
  end
91
- rescue NoValidSessionError => e
92
- if retried == 0
93
- retried += 1
94
- create_session
95
- retry
96
- else
97
- raise e
98
- end
99
77
  end
100
78
  end
101
79
 
@@ -117,7 +95,7 @@ module ComicWalker
117
95
 
118
96
  def request_with_cookie(uri, req)
119
97
  req['cookie'] = HTTP::Cookie.cookie_value(@jar.cookies(uri.to_s))
120
- @https.request(req).tap do |res|
98
+ @https.request(URI.parse(uri.to_s), req).tap do |res|
121
99
  @jar.parse(res['set-cookie'], uri.to_s)
122
100
  end
123
101
  end
@@ -1,5 +1,5 @@
1
1
  module ComicWalker
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
 
4
4
  VIEWER_VERSION = "1.0.5_2014-04-11"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: comic_walker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kohei Suzuki
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rmagick
84
+ name: net-http-persistent
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,21 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: rubyzip
98
+ name: retryable
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rmagick
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - ">="
@@ -143,7 +157,7 @@ files:
143
157
  - lib/comic_walker/cli.rb
144
158
  - lib/comic_walker/client.rb
145
159
  - lib/comic_walker/client/license.rb
146
- - lib/comic_walker/end_layer_decoder.rb
160
+ - lib/comic_walker/content_downloader.rb
147
161
  - lib/comic_walker/item_decoder.rb
148
162
  - lib/comic_walker/item_decoder/unknown.rb
149
163
  - lib/comic_walker/v1/client.rb
@@ -1,14 +0,0 @@
1
- require 'json'
2
- require 'comic_walker/cipher'
3
-
4
- module ComicWalker
5
- class EndLayerDecoder
6
- def initialize(key)
7
- @key = key
8
- end
9
-
10
- def decode(b64)
11
- JSON.parse(Cipher.decrypt_b64(@key, b64))
12
- end
13
- end
14
- end