comic_walker 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e501759d14c46245526e2b8cbff03a38b9f390f9
4
+ data.tar.gz: a1eccbbfd4a9f823614adc8c1adf8b6a98bebc5b
5
+ SHA512:
6
+ metadata.gz: 1fe26f0cc27ad11cda330ff55e502e27b4a09a71a9f1c264026042765a0a311e68cec060b1e555fb9a5e58ca44319c8baa75e6e863e81fddf0adcfb37d0f6eed
7
+ data.tar.gz: 2d2393961e1859b017c960e29deed845913df53c98472382785418ccd9b51cf04675e17570f2c95d439efec7f1af9d6557651b0d0417e4a7220daae1660c24df
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in comic_walker.gemspec
4
+ gemspec
5
+
6
+ # https://github.com/rmagick/rmagick/pull/90 is needed
7
+ gem 'rmagick', github: 'rmagick', ref: '79e1708c7f6792a3a90cb8cb3ffaeb74c58e092e'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Kohei Suzuki
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # ComicWalker
2
+
3
+ Client library for [ComicWalker](http://comic-walker.com/).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'comic_walker'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install comic_walker
18
+
19
+ ## Usage
20
+
21
+ ### CLI
22
+
23
+ ```
24
+ % comic-walker KDCW_KS04000001010001_68
25
+ item/xhtml/p-cover.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/000_p-cover.jpg
26
+ item/xhtml/p-001.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/001_p-001.jpg
27
+ item/xhtml/p-002.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/002_p-002.jpg
28
+ item/xhtml/p-white.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/003_p-white.jpg
29
+ item/xhtml/p-004.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/004_p-004.jpg
30
+ item/xhtml/p-005.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/005_p-005.jpg
31
+ item/xhtml/p-006.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/006_p-006.jpg
32
+ item/xhtml/p-007.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/007_p-007.jpg
33
+ item/xhtml/p-008.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/008_p-008.jpg
34
+ item/xhtml/p-009.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/009_p-009.jpg
35
+ item/xhtml/p-010.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/010_p-010.jpg
36
+ item/xhtml/p-011.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/011_p-011.jpg
37
+ item/xhtml/p-012.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/012_p-012.jpg
38
+ item/xhtml/p-013.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/013_p-013.jpg
39
+ item/xhtml/p-014.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/014_p-014.jpg
40
+ item/xhtml/p-015.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/015_p-015.jpg
41
+ item/xhtml/p-016.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/016_p-016.jpg
42
+ item/xhtml/p-017.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/017_p-017.jpg
43
+ item/xhtml/p-018.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/018_p-018.jpg
44
+ item/xhtml/p-019.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/019_p-019.jpg
45
+ item/xhtml/p-020.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/020_p-020.jpg
46
+ item/xhtml/p-021.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/021_p-021.jpg
47
+ item/xhtml/p-022.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/022_p-022.jpg
48
+ item/xhtml/p-023.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/023_p-023.jpg
49
+ item/xhtml/p-024.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/024_p-024.jpg
50
+ item/xhtml/p-025.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/025_p-025.jpg
51
+ item/xhtml/p-026.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/026_p-026.jpg
52
+ item/xhtml/p-027.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/027_p-027.jpg
53
+ item/xhtml/p-028.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/028_p-028.jpg
54
+ item/xhtml/p-029.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/029_p-029.jpg
55
+ item/xhtml/p-030.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/030_p-030.jpg
56
+ item/xhtml/p-031.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/031_p-031.jpg
57
+ item/xhtml/p-032.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/032_p-032.jpg
58
+ item/xhtml/p-033.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/033_p-033.jpg
59
+ item/xhtml/p-034.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/034_p-034.jpg
60
+ item/xhtml/p-035.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/035_p-035.jpg
61
+ item/xhtml/p-036.xhtml/0.dat -> Fate/kaleid liner プリズマ☆イリヤ ドライ!!/KDCW_KS04000001010001_68/036_p-036.jpg
62
+ ```
63
+
64
+ ## Contributing
65
+
66
+ 1. Fork it ( https://github.com/eagletmt/comic_walker/fork )
67
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
68
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
69
+ 4. Push to the branch (`git push origin my-new-feature`)
70
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/comic-walker ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'comic_walker/cli'
3
+
4
+ ComicWalker::CLI.new.run(ARGV)
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'comic_walker/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "comic_walker"
8
+ spec.version = ComicWalker::VERSION
9
+ spec.authors = ["Kohei Suzuki"]
10
+ spec.email = ["eagletmt@gmail.com"]
11
+ spec.summary = %q{Client library for ComicWalker}
12
+ spec.description = %q{Client library for ComicWalker}
13
+ spec.homepage = "https://github.com/eagletmt/comic_walker"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "yard"
24
+ spec.add_dependency "addressable"
25
+ spec.add_dependency "http-cookie"
26
+ spec.add_dependency "rmagick"
27
+ spec.add_dependency "rubyzip"
28
+ end
@@ -0,0 +1,5 @@
1
+ require "comic_walker/version"
2
+
3
+ module ComicWalker
4
+ # Your code goes here...
5
+ end
@@ -0,0 +1,63 @@
1
+ require 'base64'
2
+ require 'digest'
3
+
4
+ module ComicWalker
5
+ module Cipher
6
+ module_function
7
+
8
+ BASE_KEY = [173, 43, 117, 127, 230, 58, 73, 84, 154, 177, 47, 81, 108, 200, 101, 65].pack('C*')
9
+
10
+ # Decrypt Base64-encoded license object
11
+ # @param [String] bid browser id
12
+ # @param [String] u1 got from cookie
13
+ # @param [String] license_b64 Base64-encoded license object
14
+ # @return [String]
15
+ def decrypt_license(bid, u1, license_b64)
16
+ h = bid.chars.map(&:ord)
17
+ if u1
18
+ h += u1.chars.map(&:ord)
19
+ end
20
+ decrypt_b64(h.pack('C*') + BASE_KEY, license_b64)
21
+ end
22
+
23
+ # Decrypt Base64-encoded data
24
+ # @param [String] key key
25
+ # @param [String] b64data Encrypted Base64-encoded data
26
+ # @return [String] Decrypted data
27
+ def decrypt_b64(key, b64data)
28
+ data = Base64.decode64(b64data)
29
+ md5 = Digest::MD5.hexdigest(key + data.byteslice(8, 8))
30
+ l = md5.scan(/.{2}/).map { |xy| Integer(xy, 16) }
31
+ decrypt_rc4(l, data[16 .. -1].unpack('C*')).pack('C*')
32
+ end
33
+
34
+ # Decrypt data
35
+ # @param [Array<Fixnum>] key
36
+ # @param [Array<Fixnum>] data
37
+ # @return [Array<Fixnum>] Decrypt data
38
+ def decrypt_rc4(key, data)
39
+ s = gen_rc4_table(key)
40
+ i = 0
41
+ j = 0
42
+ data.map do |x|
43
+ i = (i + 1) & 0xff
44
+ j = (j + s[i]) & 0xff
45
+ s[i], s[j] = s[j], s[i]
46
+ k = s[(s[i] + s[j]) & 0xff]
47
+ x ^ k
48
+ end
49
+ end
50
+
51
+ # @param [Array<Fixnum>] key
52
+ # @return [Array<Fixnum>] RC4 table
53
+ def gen_rc4_table(key)
54
+ s = 256.times.to_a
55
+ j = 0
56
+ 256.times do |i|
57
+ j = (j + s[i] + key[i % key.size]) & 0xff
58
+ s[i], s[j] = s[j], s[i]
59
+ end
60
+ s
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,54 @@
1
+ require 'json'
2
+ require 'pathname'
3
+ require 'pp'
4
+ require 'comic_walker/client'
5
+ require 'comic_walker/end_layer_decoder'
6
+ require 'comic_walker/item_decoder'
7
+
8
+ module ComicWalker
9
+ class CLI
10
+ def run(cids)
11
+ client = Client.new
12
+ cids.each do |cid|
13
+ save_content(client, cid)
14
+ end
15
+ end
16
+
17
+ def save_content(client, cid)
18
+ license = client.get_license(cid)
19
+ info = license.get_info.first
20
+ last_update = Time.strptime(info['last_update'], '%Y%m%d%H%M')
21
+ title = info['issues'].first['content_name']
22
+
23
+ license.with_jar do |zip|
24
+ pages = []
25
+ items = {}
26
+ decoder = nil
27
+ while entry = zip.get_next_entry
28
+ case entry.name
29
+ when 'configuration_pack.json'
30
+ config = JSON.parse(zip.read)
31
+ decoder = ItemDecoder.new(config)
32
+ config['configuration']['contents'].each do |content|
33
+ pages[content['index']-1] = content['file']
34
+ end
35
+ when /end_layer\.json/
36
+ pp EndLayerDecoder.new(license.key).decode(zip.read)
37
+ when %r{\Aitem/}
38
+ items[entry.name] = zip.read
39
+ end
40
+ end
41
+
42
+ img_dir = Pathname.new(title).join(cid).tap(&:mkpath)
43
+ pages.each.with_index do |file, i|
44
+ dat_path = Pathname.new(file).join('0.dat')
45
+ data = items[dat_path.to_s]
46
+ img_fname = dat_path.parent.basename.sub_ext('.jpg')
47
+ img_path = img_dir.join(sprintf('%03d_%s', i, img_fname))
48
+ puts "#{dat_path} -> #{img_path}"
49
+ decoder.decode(dat_path, img_path, data)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,52 @@
1
+ require 'addressable/uri'
2
+ require 'http-cookie'
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'comic_walker/cipher'
6
+ require 'comic_walker/client/license'
7
+
8
+ module ComicWalker
9
+ class Client
10
+ def initialize
11
+ @bid = '000000000000000000000NFBR'
12
+ end
13
+
14
+ def get_license(cid)
15
+ u1 = get_u1(cid)
16
+ json = get_li(cid, u1)
17
+ license_b64 = json['license']
18
+ License.new(JSON.parse(Cipher.decrypt_license(@bid, u1, license_b64)))
19
+ end
20
+
21
+ def get_u1(cid)
22
+ uri = Addressable::URI.parse("http://comic-walker.com/viewer/?cid=#{cid}")
23
+ Net::HTTP.start(uri.host, 80) do |http|
24
+ res = http.get(uri.request_uri)
25
+ Addressable::URI.unescape(HTTP::Cookie.cookie_value_to_hash(res['set-cookie'])['u1'])
26
+ end
27
+ end
28
+
29
+ def get_li(cid, u1)
30
+ uri = Addressable::URI.parse("https://cnts.comic-walker.com/api4js/v1/c/#{cid}/li")
31
+ uri.query_values = {
32
+ 'BID' => @bid,
33
+ 'AID' => 'browser',
34
+ 'AVER' => '1.2.0',
35
+ 'S' => u1,
36
+ 'FORMATS' => 'epub_brws,epub_brws_fixedlayout,epub_brws_omf',
37
+ 'W' => 720,
38
+ 'H' => 1280,
39
+ }
40
+
41
+ https = Net::HTTP.new(uri.host, 443)
42
+ https.use_ssl = true
43
+ https.verify_mode = OpenSSL::SSL::VERIFY_PEER
44
+ body = https.start do
45
+ req = Net::HTTP::Get.new(uri.request_uri)
46
+ res = https.request(req)
47
+ res.body
48
+ end
49
+ JSON.parse(body)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,46 @@
1
+ require 'addressable/uri'
2
+ require 'base64'
3
+ require 'net/http'
4
+ require 'zip'
5
+
6
+ module ComicWalker
7
+ class Client
8
+ class License
9
+ def initialize(json)
10
+ @json = json
11
+ end
12
+
13
+ def agreement
14
+ @json['agreement']
15
+ end
16
+
17
+ def jar_url
18
+ agreement['url_prefix'] + agreement['jar_file_name']
19
+ end
20
+
21
+ def info_url
22
+ agreement['url_prefix'] + agreement['info_file_name']
23
+ end
24
+
25
+ def key
26
+ Base64.decode64(agreement['key'])
27
+ end
28
+
29
+ def with_jar(&block)
30
+ uri = Addressable::URI.parse(jar_url)
31
+ body = Net::HTTP.start(uri.host) do |http|
32
+ http.get(uri.request_uri).body
33
+ end
34
+ Zip::InputStream.open(StringIO.new(body), &block)
35
+ end
36
+
37
+ def get_info
38
+ uri = Addressable::URI.parse(info_url)
39
+ body = Net::HTTP.start(uri.host) do |http|
40
+ http.get(uri.request_uri).body
41
+ end
42
+ JSON.parse(body)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,14 @@
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
@@ -0,0 +1,43 @@
1
+ require 'RMagick'
2
+ require 'comic_walker/item_decoder/unknown'
3
+
4
+ module ComicWalker
5
+ class ItemDecoder
6
+ def initialize(configuration_pack)
7
+ fname = '0.dat'
8
+ ct = configuration_pack['ct']
9
+ st = configuration_pack['st']
10
+ et = configuration_pack['et']
11
+ @key1 = (ct + st + fname).unpack('C*')
12
+ @key2 = (ct + fname + et).unpack('C*')
13
+ @key3 = (fname + st + et).unpack('C*')
14
+ end
15
+
16
+ def decode(dat_path, img_path, b64data)
17
+ bs = 128
18
+ hs = 1024
19
+ blob = Unknown.finish(@key1, hs,
20
+ Unknown.decrypt(@key2, bs,
21
+ Unknown.prepare(@key3,
22
+ Base64.decode64(b64data).unpack('C*')
23
+ )
24
+ )
25
+ ).pack('C*')
26
+
27
+ src = Magick::Image.from_blob(blob).first
28
+ width = src.columns
29
+ height = src.rows
30
+ t = dat_path.sub_ext('').to_s.chars.inject(0) { |acc, c| acc + c.ord }
31
+ pat = t%4 + 1
32
+ moves = Unknown.calculate_moves(width, height, 64, 64, pat)
33
+
34
+ dst = Magick::Image.new(width, height)
35
+ dst.format = 'jpeg'
36
+ moves.each do |move|
37
+ crop = src.excerpt(move[:destX], move[:destY], move[:width], move[:height])
38
+ dst.composite!(crop, move[:srcX], move[:srcY], Magick::SrcOverCompositeOp)
39
+ end
40
+ dst.write(img_path.to_s)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,183 @@
1
+ require 'comic_walker/cipher'
2
+
3
+ module ComicWalker
4
+ class ItemDecoder
5
+ module Unknown
6
+ module_function
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
+ # Calculate moves.
50
+ # @param [Integer] width Width of the image
51
+ # @param [Integer] height Height of the image
52
+ # @param [Integer] rect_width Width of the sub-image
53
+ # @param [Integer] rect_height Height of the sub-image
54
+ # @param [Integer] pattern pattern? integer ranging from 1 to 4
55
+ # @return [Array<Hash>] List of hash that represents a move
56
+ def calculate_moves(width, height, rect_width, rect_height, pattern)
57
+ wcnt = width / rect_width
58
+ hcnt = height / rect_height
59
+ width %= rect_width
60
+ height %= rect_height
61
+ moves = []
62
+ w_t0 = wcnt - (43*pattern)%wcnt
63
+ w_t1 =
64
+ if w_t0 % wcnt == 0
65
+ (wcnt - 4) % wcnt
66
+ else
67
+ w_t0
68
+ end
69
+ h_t0 = hcnt - 47 * pattern % hcnt;
70
+ h_t1 =
71
+ if h_t0 % hcnt == 0
72
+ (hcnt - 4) % hcnt
73
+ else
74
+ h_t0;
75
+ end
76
+
77
+ if width > 0 && height > 0
78
+ x = w_t1 * rect_width
79
+ y = h_t1 * rect_height
80
+ moves.push(srcX: x, srcY: y, destX: x, destY: y, width: width, height: height)
81
+ end
82
+
83
+ if height > 0
84
+ wcnt.times do |j|
85
+ l = calcXCoordinateXRest_(j, wcnt, pattern)
86
+ k = calcYCoordinateXRest_(l, w_t1, h_t1, hcnt, pattern)
87
+ destX = calcPositionWithRest_(l, w_t1, width, rect_width)
88
+ destY = k * rect_height
89
+ srcX = calcPositionWithRest_(j, w_t1, width, rect_width)
90
+ srcY = h_t1 * rect_height
91
+ moves.push(srcX: srcX, srcY: srcY, destX: destX, destY: destY, width: rect_width, height: height)
92
+ end
93
+ end
94
+ if width > 0
95
+ hcnt.times do |i|
96
+ k = calcYCoordinateYRest_(i, hcnt, pattern)
97
+ l = calcXCoordinateYRest_(k, w_t1, h_t1, wcnt, pattern)
98
+ destX = l * rect_width
99
+ destY = calcPositionWithRest_(k, h_t1, height, rect_height)
100
+ srcX = w_t1 * rect_width
101
+ srcY = calcPositionWithRest_(i, h_t1, height, rect_height)
102
+ moves.push(srcX: srcX, srcY: srcY, destX: destX, destY: destY, width: width, height: rect_height)
103
+ end
104
+ end
105
+ wcnt.times do |j|
106
+ hcnt.times do |i|
107
+ p = (j + 29 * pattern + 31 * i) % wcnt
108
+ k = (i + 37 * pattern + 41 * p) % hcnt
109
+ q = p >= calcXCoordinateYRest_(k, w_t1, h_t1, wcnt, pattern) ? width : 0
110
+ m = k >= calcYCoordinateXRest_(p, w_t1, h_t1, hcnt, pattern) ? height : 0
111
+ destX = p * rect_width + q
112
+ destY = k * rect_height + m
113
+ srcX = j * rect_width + (j >= w_t1 ? width : 0)
114
+ srcY = i * rect_height + (i >= h_t1 ? height : 0)
115
+ moves.push(srcX: srcX, srcY: srcY, destX: destX, destY: destY, width: rect_width, height: rect_height)
116
+ end
117
+ end
118
+ moves
119
+ end
120
+
121
+ # @param [Integer] a
122
+ # @param [Integer] f
123
+ # @param [Integer] b
124
+ # @param [Integer] e
125
+ # @return [Integer]
126
+ def calcPositionWithRest_(a, f, b, e)
127
+ a * e + (a >= f ? b : 0)
128
+ end
129
+
130
+ # @param [Integer] a
131
+ # @param [Integer] f
132
+ # @param [Integer] b
133
+ # @return [Integer]
134
+ def calcXCoordinateXRest_(a, f, b)
135
+ (a + 61 * b) % f
136
+ end
137
+
138
+ # @param [Integer] a
139
+ # @param [Integer] f
140
+ # @param [Integer] b
141
+ # @param [Integer] e
142
+ # @param [Integer] d
143
+ # @return [Integer]
144
+ def calcYCoordinateXRest_(a, f, b, e, d)
145
+ c = 1 == d % 2
146
+ if a < f ? c : !c
147
+ e = b
148
+ f = 0
149
+ else
150
+ e -= b
151
+ f = b
152
+ end
153
+ (a + 53*d + 59*b) % e + f
154
+ end
155
+
156
+ # @param [Integer] a
157
+ # @param [Integer] f
158
+ # @param [Integer] b
159
+ # @param [Integer] e
160
+ # @param [Integer] d
161
+ # @return [Integer]
162
+ def calcXCoordinateYRest_(a, f, b, e, d)
163
+ c = 1 == d % 2
164
+ if a < b ? c : !c
165
+ e -= f
166
+ b = f
167
+ else
168
+ e = f
169
+ b = 0
170
+ end
171
+ (a + 67*d + f + 71) % e + b
172
+ end
173
+
174
+ # @param [Integer] a
175
+ # @param [Integer] f
176
+ # @param [Integer] b
177
+ # @return [Integer]
178
+ def calcYCoordinateYRest_(a, f, b)
179
+ (a + 73*b) % f
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,5 @@
1
+ module ComicWalker
2
+ VERSION = "0.1.0"
3
+
4
+ VIEWER_VERSION = "1.0.2_2014-03-20"
5
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: comic_walker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kohei Suzuki
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: addressable
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: http-cookie
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rmagick
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubyzip
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
+ description: Client library for ComicWalker
112
+ email:
113
+ - eagletmt@gmail.com
114
+ executables:
115
+ - comic-walker
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - Gemfile
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - bin/comic-walker
125
+ - comic_walker.gemspec
126
+ - lib/comic_walker.rb
127
+ - lib/comic_walker/cipher.rb
128
+ - lib/comic_walker/cli.rb
129
+ - lib/comic_walker/client.rb
130
+ - lib/comic_walker/client/license.rb
131
+ - lib/comic_walker/end_layer_decoder.rb
132
+ - lib/comic_walker/item_decoder.rb
133
+ - lib/comic_walker/item_decoder/unknown.rb
134
+ - lib/comic_walker/version.rb
135
+ homepage: https://github.com/eagletmt/comic_walker
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubyforge_project:
155
+ rubygems_version: 2.2.2
156
+ signing_key:
157
+ specification_version: 4
158
+ summary: Client library for ComicWalker
159
+ test_files: []
160
+ has_rdoc: