kindai 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|