kindai 1.0.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.
- data/Gemfile +13 -0
- data/Gemfile.lock +34 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +85 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/bin/kindai.rb +15 -0
- data/kindai.gemspec +102 -0
- data/kindai.rb +17 -0
- data/lib/kindai/book.rb +110 -0
- data/lib/kindai/book_downloader.rb +62 -0
- data/lib/kindai/cli.rb +88 -0
- data/lib/kindai/interface.rb +30 -0
- data/lib/kindai/publisher.rb +157 -0
- data/lib/kindai/searcher.rb +52 -0
- data/lib/kindai/spread.rb +39 -0
- data/lib/kindai/spread_downloader.rb +65 -0
- data/lib/kindai/util.rb +239 -0
- data/lib/kindai.rb +24 -0
- data/publish.rb +17 -0
- data/spec/book_downloader_spec.rb +46 -0
- data/spec/book_spec.rb +39 -0
- data/spec/searcher_spec.rb +42 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/spread_downloader_spec.rb +44 -0
- data/spec/spread_spec.rb +26 -0
- metadata +195 -0
@@ -0,0 +1,157 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Kindai
|
3
|
+
class Publisher
|
4
|
+
attr_accessor :root_path
|
5
|
+
|
6
|
+
def self.new_from_path(root_path)
|
7
|
+
me = self.new
|
8
|
+
me.root_path = root_path
|
9
|
+
me
|
10
|
+
end
|
11
|
+
|
12
|
+
def name(n)
|
13
|
+
config(:name, n)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def resize(width, height)
|
18
|
+
config(:resize, {:width => width, :height => height})
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def trim(geometry = true)
|
23
|
+
config(:trim, geometry) unless config(:trim)
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def zip
|
28
|
+
config(:zip, true)
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def divide
|
33
|
+
config(:divide, true)
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def empty(glob)
|
38
|
+
FileUtils.rm_r(Dir.glob(File.join(self.root_path, glob)))
|
39
|
+
end
|
40
|
+
|
41
|
+
def publish
|
42
|
+
Kindai::Util.logger.info("publish #{root_path}, #{config(:name)}")
|
43
|
+
raise "no name" unless config(:name)
|
44
|
+
if seems_finished?
|
45
|
+
Kindai::Util.logger.info("already published")
|
46
|
+
return
|
47
|
+
end
|
48
|
+
create_directory
|
49
|
+
|
50
|
+
path = original_path
|
51
|
+
|
52
|
+
path = trim!(path) if trim?
|
53
|
+
path = divide!(path) if divide?
|
54
|
+
path = resize!(path) if resize?
|
55
|
+
path = zip!(path) if zip?
|
56
|
+
end
|
57
|
+
|
58
|
+
def publish_auto
|
59
|
+
self.clone.trim.resize(1280, 960).trim.zip.name('iphone').publish
|
60
|
+
self.clone.trim.resize(600, 800).divide.zip.name('kindle').publish
|
61
|
+
end
|
62
|
+
|
63
|
+
# ------------------------------------
|
64
|
+
protected
|
65
|
+
|
66
|
+
def config(k, v = nil)
|
67
|
+
@config ||= {}
|
68
|
+
return @config[k] unless v
|
69
|
+
@config[k] = v
|
70
|
+
@config
|
71
|
+
end
|
72
|
+
|
73
|
+
def trim?
|
74
|
+
config(:trim)
|
75
|
+
end
|
76
|
+
|
77
|
+
def resize?
|
78
|
+
config(:resize)
|
79
|
+
end
|
80
|
+
|
81
|
+
def zip?
|
82
|
+
config(:zip)
|
83
|
+
end
|
84
|
+
|
85
|
+
def divide?
|
86
|
+
config(:divide)
|
87
|
+
end
|
88
|
+
|
89
|
+
# ---------- aciton --------------
|
90
|
+
|
91
|
+
def trim!(source_path)
|
92
|
+
return trim_path if files(source_path).length == files(trim_path).length
|
93
|
+
info = config(:trim).kind_of?(Hash) ? config(:trim) : Kindai::Util.trim_info_by_files(original_files)
|
94
|
+
files(source_path).each{|file|
|
95
|
+
dst = File.join(trim_path, File.basename(file))
|
96
|
+
Kindai::Util.trim_file_to(file, dst, info)
|
97
|
+
GC.start
|
98
|
+
}
|
99
|
+
return trim_path
|
100
|
+
end
|
101
|
+
|
102
|
+
def resize!(source_path)
|
103
|
+
files(source_path).each{|file|
|
104
|
+
dst = File.join(output_path, File.basename(file))
|
105
|
+
Kindai::Util.resize_file_to(file, dst, config(:resize))
|
106
|
+
GC.start
|
107
|
+
}
|
108
|
+
return output_path
|
109
|
+
end
|
110
|
+
|
111
|
+
def divide!(source_path)
|
112
|
+
files(source_path).each{|file|
|
113
|
+
Kindai::Util.divide_43(file, output_path)
|
114
|
+
GC.start
|
115
|
+
}
|
116
|
+
return output_path
|
117
|
+
end
|
118
|
+
|
119
|
+
def zip!(source_path)
|
120
|
+
Kindai::Util.generate_zip(source_path)
|
121
|
+
FileUtils.rm_r(self.output_path)
|
122
|
+
return source_path
|
123
|
+
end
|
124
|
+
|
125
|
+
# ---------util------------
|
126
|
+
|
127
|
+
def create_directory
|
128
|
+
Dir.mkdir(trim_path) unless File.directory?(trim_path)
|
129
|
+
Dir.mkdir(output_path) unless File.directory?(output_path)
|
130
|
+
end
|
131
|
+
|
132
|
+
def trim_path
|
133
|
+
File.join(root_path, 'trim')
|
134
|
+
end
|
135
|
+
|
136
|
+
def original_path
|
137
|
+
File.join(root_path, 'original')
|
138
|
+
end
|
139
|
+
|
140
|
+
def output_path
|
141
|
+
File.join(root_path, File.basename(root_path) + '_' + config(:name))
|
142
|
+
end
|
143
|
+
|
144
|
+
def original_files
|
145
|
+
files(original_path)
|
146
|
+
end
|
147
|
+
|
148
|
+
def files(path)
|
149
|
+
Dir.glob(File.join(path, '*jpg'))
|
150
|
+
end
|
151
|
+
|
152
|
+
def seems_finished?
|
153
|
+
zip? ? File.exists?(output_path + '.zip') : File.directory?(output_path)
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Kindai
|
3
|
+
class Searcher
|
4
|
+
include Enumerable
|
5
|
+
attr_accessor :keyword
|
6
|
+
def self.search keyword
|
7
|
+
Kindai::Util.logger.debug "keyword: #{keyword}"
|
8
|
+
me = self.new
|
9
|
+
me.keyword = keyword
|
10
|
+
me
|
11
|
+
end
|
12
|
+
|
13
|
+
def length
|
14
|
+
@length ||= total_of(@keyword)
|
15
|
+
end
|
16
|
+
|
17
|
+
def each
|
18
|
+
(0..(1/0.0)).each{ |page|
|
19
|
+
Kindai::Util.logger.debug "page #{page}"
|
20
|
+
uris = result_for(@keyword, page)
|
21
|
+
return if uris.empty?
|
22
|
+
uris.each{ |uri|
|
23
|
+
yield Kindai::Book.new_from_permalink(uri)
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
def total_of(keyword)
|
30
|
+
page = Nokogiri(Kindai::Util.fetch_uri(uri_for(keyword)))
|
31
|
+
total = page.at('.//opensearch:totalResults', {"opensearch"=>"http://a9.com/-/spec/opensearchrss/1.0/"} ).content.to_i
|
32
|
+
|
33
|
+
Kindai::Util.logger.debug "total: #{total}"
|
34
|
+
total
|
35
|
+
end
|
36
|
+
|
37
|
+
def result_for keyword, page = 0
|
38
|
+
page = Nokogiri Kindai::Util.fetch_uri(uri_for(keyword, page))
|
39
|
+
page.search('item').map{ |item|
|
40
|
+
item.at('link').content
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def uri_for keyword, page = 0
|
45
|
+
count = 10
|
46
|
+
params = { :any => keyword, :dpid => 'kindai', :idx => page * count + 1, :cnt => count}
|
47
|
+
root = URI.parse("http://api.porta.ndl.go.jp/servicedp/opensearch")
|
48
|
+
path = '?' + Kindai::Util.expand_params(params)
|
49
|
+
root + path
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Kindai
|
3
|
+
class Spread
|
4
|
+
attr_accessor :book
|
5
|
+
attr_accessor :spread_number
|
6
|
+
|
7
|
+
def self.new_from_book_and_spread_number(book, spread_number)
|
8
|
+
raise TypeError, "#{book} is not Kindai::Book" unless book.is_a? Kindai::Book
|
9
|
+
me = new
|
10
|
+
me.book = book
|
11
|
+
me.spread_number = spread_number
|
12
|
+
me
|
13
|
+
end
|
14
|
+
|
15
|
+
def uri
|
16
|
+
book.base_uri.gsub(/koma=(\d+)/) { "koma=#{spread_number}" }
|
17
|
+
end
|
18
|
+
|
19
|
+
def image_uri
|
20
|
+
image = page.at("img#imMain")
|
21
|
+
raise "not exists" unless image
|
22
|
+
image['src']
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def has_local_file?
|
27
|
+
end
|
28
|
+
|
29
|
+
def local_file_path
|
30
|
+
end
|
31
|
+
|
32
|
+
# protected
|
33
|
+
# XXX: book use this
|
34
|
+
def page
|
35
|
+
@page ||= Nokogiri Kindai::Util.fetch_uri self.uri
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Kindai
|
3
|
+
class SpreadDownloader
|
4
|
+
attr_accessor :spread
|
5
|
+
attr_accessor :retry_count
|
6
|
+
attr_accessor :book_path
|
7
|
+
|
8
|
+
def self.new_from_spread(spread)
|
9
|
+
raise TypeError, "#{spread} is not Kindai::Spread" unless spread.is_a? Kindai::Spread
|
10
|
+
me = self.new
|
11
|
+
me.spread = spread
|
12
|
+
me.retry_count = 30
|
13
|
+
me.book_path = Pathname.new(ENV["HOME"]).to_s
|
14
|
+
me
|
15
|
+
end
|
16
|
+
|
17
|
+
def download
|
18
|
+
return false if self.has_file?
|
19
|
+
self.create_directory
|
20
|
+
self.download_spread
|
21
|
+
return true
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_directory
|
25
|
+
path = File.join self.book_path, "original"
|
26
|
+
Dir.mkdir(path) unless File.directory?(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def spread_path
|
30
|
+
path = File.join self.book_path, "original", "%03d.jpg" % self.spread.spread_number
|
31
|
+
File.expand_path path
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete
|
35
|
+
return File.delete(self.spread_path) && true rescue false
|
36
|
+
end
|
37
|
+
|
38
|
+
def has_file?
|
39
|
+
File.size? self.spread_path
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def download_spread
|
45
|
+
failed_count = 0
|
46
|
+
|
47
|
+
begin
|
48
|
+
Kindai::Util.logger.info "downloading " + [self.spread.book.author, self.spread.book.title, "spread #{self.spread.spread_number} / #{self.spread.book.total_spread}"].join(' - ')
|
49
|
+
Kindai::Util.rich_download(spread.image_uri, self.spread_path)
|
50
|
+
rescue Interrupt => err
|
51
|
+
Kindai::Util.logger.error "#{err.class}: #{err.message}"
|
52
|
+
exit 1
|
53
|
+
rescue StandardError, TimeoutError => err
|
54
|
+
Kindai::Util.logger.warn "failed (#{failed_count+1}/#{self.retry_count}) #{err.class}: #{err.message}"
|
55
|
+
raise err if failed_count == self.retry_count
|
56
|
+
|
57
|
+
Kindai::Util.logger.info "sleep and retry"
|
58
|
+
failed_count += 1
|
59
|
+
sleep 10
|
60
|
+
retry
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/lib/kindai/util.rb
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'open3'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'digest/sha1'
|
5
|
+
require 'RMagick'
|
6
|
+
require 'zipruby'
|
7
|
+
|
8
|
+
module Kindai::Util
|
9
|
+
def self.logger
|
10
|
+
return @logger if @logger
|
11
|
+
@logger ||= Logger.new(STDOUT)
|
12
|
+
@logger.level = Logger::INFO
|
13
|
+
@logger
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.debug_mode!
|
17
|
+
self.logger.level = Logger::DEBUG
|
18
|
+
Kindai::Util.logger.info "debug mode enabled"
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.download(uri, file)
|
22
|
+
total = nil
|
23
|
+
uri = URI.parse(uri) unless uri.kind_of? URI
|
24
|
+
|
25
|
+
got = fetch_uri(uri)
|
26
|
+
open(file, 'w') {|local|
|
27
|
+
local.write(got)
|
28
|
+
}
|
29
|
+
rescue Exception, TimeoutError => error
|
30
|
+
if File.exists?(file)
|
31
|
+
logger.debug "delete cache"
|
32
|
+
File.delete(file)
|
33
|
+
end
|
34
|
+
raise error
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.rich_download(uri, file)
|
38
|
+
total = nil
|
39
|
+
uri = URI.parse(uri) unless uri.kind_of? URI
|
40
|
+
|
41
|
+
got = fetch_uri(uri, true)
|
42
|
+
open(file, 'w') {|local|
|
43
|
+
local.write(got)
|
44
|
+
}
|
45
|
+
rescue Exception, TimeoutError => error
|
46
|
+
if File.exists?(file)
|
47
|
+
logger.debug "delete cache"
|
48
|
+
File.delete(file)
|
49
|
+
end
|
50
|
+
raise error
|
51
|
+
end
|
52
|
+
|
53
|
+
# input: {:a => 'a', :b => 'bbb'}
|
54
|
+
# output: 'a=a&b=bbb
|
55
|
+
def self.expand_params(params)
|
56
|
+
params.each_pair.map{ |k, v| [URI.escape(k.to_s), URI.escape(v.to_s)].join('=')}.join('&')
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.append_suffix(path, suffix)
|
60
|
+
path.gsub(/\.(\w+)$/, "-#{suffix}.\\1")
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.execute_and_log(command)
|
64
|
+
logger.debug command
|
65
|
+
system command or raise "#{commands} failed"
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.generate_zip(directory)
|
69
|
+
Kindai::Util.logger.info "zip #{directory}"
|
70
|
+
directory = File.expand_path(directory)
|
71
|
+
raise "#{directory} is not directory." unless File.directory? directory
|
72
|
+
|
73
|
+
filename = File.expand_path(File.join(directory, '..', "#{File.basename(directory)}.zip"))
|
74
|
+
files = Dir.glob(File.join(directory, '*jpg'))
|
75
|
+
begin
|
76
|
+
Zip::Archive.open(filename, Zip::CREATE) {|arc|
|
77
|
+
files.each{|f| arc.add_file(f) }
|
78
|
+
}
|
79
|
+
rescue => error
|
80
|
+
File.delete(filename) if File.exists?(filename)
|
81
|
+
logger.warn "#{error.class}: #{error.message}"
|
82
|
+
logger.warn "zipruby died. trying zip command"
|
83
|
+
generate_zip_system_command(directory)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.generate_zip_system_command(directory)
|
88
|
+
Kindai::Util.logger.info "zip(system) #{directory}"
|
89
|
+
from = Dir.pwd
|
90
|
+
Dir.chdir(directory)
|
91
|
+
execute_and_log "zip -q -r '../#{File.basename(directory)}.zip' *jpg"
|
92
|
+
Dir.chdir(from)
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.fetch_uri(uri, rich = false)
|
96
|
+
uri = URI.parse(uri) unless uri.kind_of? URI
|
97
|
+
self.logger.debug "fetch_uri #{uri}"
|
98
|
+
|
99
|
+
return uri.read unless rich
|
100
|
+
|
101
|
+
total = nil
|
102
|
+
from = Time.now
|
103
|
+
got = uri.read(
|
104
|
+
:content_length_proc => proc{|_total|
|
105
|
+
total = _total
|
106
|
+
},
|
107
|
+
:progress_proc => proc{|now|
|
108
|
+
if Time.now - from > 0.2
|
109
|
+
from = Time.now
|
110
|
+
print "%3d%% #{now}/#{total}\r" % (now/total.to_f*100)
|
111
|
+
$stdout.flush
|
112
|
+
end
|
113
|
+
})
|
114
|
+
raise "received size unmatch(#{got.bytesize}, #{total})" if got.bytesize != total
|
115
|
+
return got
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.trim_info_by_files(files)
|
119
|
+
Kindai::Util.logger.info "get trim info"
|
120
|
+
positions = {:x => [], :y => [], :width => [], :height => []}
|
121
|
+
files.each{|file|
|
122
|
+
pos = trim_info(file)
|
123
|
+
|
124
|
+
[:x, :y, :width, :height].each{|key|
|
125
|
+
positions[key] << pos[key]
|
126
|
+
}
|
127
|
+
|
128
|
+
GC.start
|
129
|
+
}
|
130
|
+
|
131
|
+
good_pos = {}
|
132
|
+
[:x, :y, :width, :height].each{|key|
|
133
|
+
good_pos[key] = average(positions[key])
|
134
|
+
}
|
135
|
+
Kindai::Util.logger.info "trim position #{good_pos}"
|
136
|
+
good_pos
|
137
|
+
end
|
138
|
+
|
139
|
+
# XXX: GC
|
140
|
+
def self.trim_info(img_path, erase_center_line = true)
|
141
|
+
debug = false
|
142
|
+
img = Magick::ImageList.new(img_path)
|
143
|
+
|
144
|
+
thumb = img.resize_to_fit(400, 400)
|
145
|
+
|
146
|
+
thumb.write('a1.jpg') if debug
|
147
|
+
# thumb = thumb.normalize
|
148
|
+
thumb = thumb.level(Magick::QuantumRange*0.4, Magick::QuantumRange*0.7)
|
149
|
+
thumb.write('a2.jpg') if debug
|
150
|
+
|
151
|
+
d = Magick::Draw.new
|
152
|
+
d.fill = 'white'
|
153
|
+
cut_x = 0.07
|
154
|
+
cut_y = 0.04
|
155
|
+
d.rectangle(thumb.columns * 0.4, 0, thumb.columns * 0.6, thumb.rows) if erase_center_line # center line
|
156
|
+
d.rectangle(0, 0, thumb.columns * cut_x, thumb.rows) # h
|
157
|
+
d.rectangle(0, thumb.rows * (1 - cut_y), thumb.columns, thumb.rows) # j
|
158
|
+
d.rectangle(0, 0, thumb.columns, thumb.rows * cut_y) # k
|
159
|
+
d.rectangle(thumb.columns * (1 - cut_x), 0, thumb.columns, thumb.rows) # l
|
160
|
+
d.draw(thumb)
|
161
|
+
thumb.write('a.jpg') if debug
|
162
|
+
|
163
|
+
# thumb = thumb.threshold(Magick::QuantumRange*0.8)
|
164
|
+
# thumb.write('b.jpg') if debug
|
165
|
+
|
166
|
+
thumb.fuzz = 50
|
167
|
+
thumb.trim!
|
168
|
+
thumb.write('c.jpg') if debug
|
169
|
+
|
170
|
+
scale = thumb.base_columns / thumb.page.width.to_f
|
171
|
+
|
172
|
+
info = {
|
173
|
+
:x => thumb.page.x * scale,
|
174
|
+
:y => thumb.page.y * scale,
|
175
|
+
:width => thumb.columns * scale,
|
176
|
+
:height => thumb.rows * scale
|
177
|
+
}
|
178
|
+
|
179
|
+
# erased by cente line?
|
180
|
+
if (thumb.page.x / thumb.page.width.to_f - 0.6).abs < 0.05 && erase_center_line
|
181
|
+
Kindai::Util.logger.info "retry trim(erased by center line?)"
|
182
|
+
new_info = trim_info(img_path, false)
|
183
|
+
Kindai::Util.logger.debug "x: #{info[:x]} -> #{new_info[:x]}"
|
184
|
+
Kindai::Util.logger.debug "width: #{info[:width]} -> #{new_info[:width]}"
|
185
|
+
info[:x] = new_info[:x]
|
186
|
+
info[:width] = new_info[:width]
|
187
|
+
end
|
188
|
+
|
189
|
+
img = nil
|
190
|
+
thumb = nil
|
191
|
+
|
192
|
+
return info
|
193
|
+
end
|
194
|
+
|
195
|
+
def self.trim_file_to(src_path, dst_path, info = nil)
|
196
|
+
info = trim_info(src_path) unless info
|
197
|
+
Kindai::Util.logger.info "trim #{src_path}"
|
198
|
+
|
199
|
+
img = Magick::ImageList.new(src_path)
|
200
|
+
img.crop! info[:x], info[:y], info[:width], info[:height]
|
201
|
+
img.write dst_path
|
202
|
+
|
203
|
+
img = nil
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
def self.resize_file_to(src_path, dst_path, info)
|
208
|
+
Kindai::Util.logger.info "resize #{src_path}"
|
209
|
+
img = Magick::ImageList.new(src_path)
|
210
|
+
img.resize_to_fit(info[:width], info[:height]).write dst_path
|
211
|
+
|
212
|
+
img = nil
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.average(array)
|
216
|
+
array.inject{|a, b| a + b} / array.length.to_f
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.divide_43(src_path, output_directory)
|
220
|
+
raise "#{src_path} not exist" unless File.exists? src_path
|
221
|
+
Kindai::Util.logger.info "divide #{src_path}"
|
222
|
+
|
223
|
+
output_base = File.join(output_directory, File.basename(src_path))
|
224
|
+
|
225
|
+
img = Magick::ImageList.new(src_path)
|
226
|
+
|
227
|
+
right = img.crop(img.columns - img.rows * 0.75, 0, img.columns * 0.75, img.rows)
|
228
|
+
right.write(append_suffix(output_base, '0'))
|
229
|
+
right = nil
|
230
|
+
|
231
|
+
left = img.crop(0, 0, img.rows * 0.75, img.rows)
|
232
|
+
left.write(append_suffix(output_base, '1'))
|
233
|
+
left = nil
|
234
|
+
|
235
|
+
File.delete(src_path) if File.basename(src_path) == output_directory
|
236
|
+
end
|
237
|
+
|
238
|
+
|
239
|
+
end
|
data/lib/kindai.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'rubygems'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'nkf'
|
6
|
+
require 'logger'
|
7
|
+
require 'open-uri'
|
8
|
+
require 'cgi'
|
9
|
+
require 'pathname'
|
10
|
+
require 'fileutils'
|
11
|
+
|
12
|
+
module Kindai
|
13
|
+
VERSION = File.read(File.join(File.dirname(__FILE__), '../VERSION')).strip
|
14
|
+
|
15
|
+
require 'kindai/cli'
|
16
|
+
require 'kindai/util'
|
17
|
+
require 'kindai/book'
|
18
|
+
require 'kindai/spread'
|
19
|
+
require 'kindai/book_downloader'
|
20
|
+
require 'kindai/spread_downloader'
|
21
|
+
require 'kindai/searcher'
|
22
|
+
require 'kindai/interface'
|
23
|
+
require 'kindai/publisher'
|
24
|
+
end
|
data/publish.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
self_file =
|
5
|
+
if File.symlink?(__FILE__)
|
6
|
+
require 'pathname'
|
7
|
+
Pathname.new(__FILE__).realpath
|
8
|
+
else
|
9
|
+
__FILE__
|
10
|
+
end
|
11
|
+
$:.unshift(File.dirname(self_file) + "/lib")
|
12
|
+
|
13
|
+
require 'kindai'
|
14
|
+
|
15
|
+
warn 'WARNING: This script is deprecated. Use bin/kindai.rb'
|
16
|
+
|
17
|
+
Kindai::CLI.execute(STDOUT, ['publish'].concat(ARGV))
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
3
|
+
|
4
|
+
describe Kindai::BookDownloader do
|
5
|
+
before do
|
6
|
+
@book = Kindai::Book.new_from_permalink('http://kindai.ndl.go.jp/info:ndljp/pid/922693')
|
7
|
+
@downloader = Kindai::BookDownloader.new_from_book(@book)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'has book' do
|
11
|
+
@downloader.book.should == @book
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'has retry_count' do
|
15
|
+
@downloader.retry_count.should == 30
|
16
|
+
@downloader.retry_count = 50
|
17
|
+
@downloader.retry_count.should == 50
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'has base path' do
|
21
|
+
@downloader.base_path = "/path/to/library"
|
22
|
+
@downloader.book_path.should == "/path/to/library/正義熱血社 - 正義の叫"
|
23
|
+
|
24
|
+
@downloader.base_path = "/path/to/library/"
|
25
|
+
@downloader.book_path.should == "/path/to/library/正義熱血社 - 正義の叫"
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can download book' do
|
29
|
+
base_path = File.join(ENV['TMPDIR'] || ENV['TMP'] || ENV['TEMP'] || '/tmp', rand.to_s)
|
30
|
+
Dir.mkdir(base_path)
|
31
|
+
@downloader.base_path = base_path
|
32
|
+
|
33
|
+
@downloader.has_file?.should be_false
|
34
|
+
@downloader.download.should be_true
|
35
|
+
@downloader.has_file?.should be_true
|
36
|
+
@downloader.download.should be_false
|
37
|
+
|
38
|
+
@downloader.delete.should be_true
|
39
|
+
@downloader.has_file?.should be_false
|
40
|
+
@downloader.delete.should be_false
|
41
|
+
|
42
|
+
Dir.delete(base_path)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
data/spec/book_spec.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
3
|
+
|
4
|
+
describe Kindai::Book do
|
5
|
+
before do
|
6
|
+
@book = Kindai::Book.new_from_permalink('http://kindai.ndl.go.jp/info:ndljp/pid/922693')
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'has title' do
|
10
|
+
@book.title.should == '正義の叫'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'has total spread' do
|
14
|
+
@book.total_spread.should == 20
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'has author' do
|
18
|
+
@book.author.should == '正義熱血社'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'has spreads' do
|
22
|
+
@book.spreads.should have_exactly(@book.total_spread).spreads
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'has base_uri' do
|
26
|
+
@book.base_uri.should == "http://kindai.da.ndl.go.jp/scrpt/ndlimageviewer-rgc.aspx?pid=info%3Andljp%2Fpid%2F922693&jp=42016454&vol=10010&koma=1&vs=10000,10000,0,0,0,0,0,0"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe Kindai::Book, 'with series' do
|
32
|
+
before do
|
33
|
+
@book = Kindai::Book.new_from_permalink('http://kindai.da.ndl.go.jp/info:ndljp/pid/890078')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'has title' do
|
37
|
+
@book.title.should == '講談日露戦争記[第3冊]第3編'
|
38
|
+
end
|
39
|
+
end
|