narou 3.2.5.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of narou might be problematic. Click here for more details.

Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -5
  3. data/.haml-lint.yml +7 -0
  4. data/.rubocop.yml +23 -5
  5. data/.scss-lint.yml +9 -0
  6. data/ChangeLog.md +86 -0
  7. data/Gemfile.lock +35 -35
  8. data/README.md +80 -64
  9. data/lib/backtracer.rb +2 -2
  10. data/lib/color.rb +5 -1
  11. data/lib/command.rb +7 -2
  12. data/lib/command/alias.rb +3 -5
  13. data/lib/command/backup.rb +3 -5
  14. data/lib/command/browser.rb +3 -5
  15. data/lib/command/clean.rb +5 -1
  16. data/lib/command/console.rb +33 -0
  17. data/lib/command/convert.rb +143 -117
  18. data/lib/command/csv.rb +2 -1
  19. data/lib/command/diff.rb +20 -18
  20. data/lib/command/download.rb +25 -14
  21. data/lib/command/folder.rb +3 -5
  22. data/lib/command/freeze.rb +3 -5
  23. data/lib/command/help.rb +20 -18
  24. data/lib/command/init.rb +4 -3
  25. data/lib/command/inspect.rb +2 -1
  26. data/lib/command/list.rb +10 -8
  27. data/lib/command/list/novel_decorator.rb +2 -1
  28. data/lib/command/log.rb +100 -0
  29. data/lib/command/log/tail.rb +76 -0
  30. data/lib/command/mail.rb +20 -17
  31. data/lib/command/remove.rb +7 -6
  32. data/lib/command/send.rb +23 -20
  33. data/lib/command/setting.rb +74 -40
  34. data/lib/command/tag.rb +16 -15
  35. data/lib/command/trace.rb +2 -2
  36. data/lib/command/update.rb +78 -128
  37. data/lib/command/update/general_lastup_updater.rb +3 -2
  38. data/lib/command/update/hotentry_manager.rb +2 -1
  39. data/lib/command/update/interval.rb +2 -1
  40. data/lib/command/version.rb +2 -1
  41. data/lib/command/web.rb +17 -3
  42. data/lib/commandbase.rb +34 -7
  43. data/lib/commandline.rb +54 -35
  44. data/lib/converterbase.rb +21 -15
  45. data/lib/database.rb +3 -2
  46. data/lib/device.rb +5 -4
  47. data/lib/device/epub.rb +2 -1
  48. data/lib/device/ibooks.rb +2 -1
  49. data/lib/device/ibunko.rb +2 -1
  50. data/lib/device/kindle.rb +2 -1
  51. data/lib/device/kobo.rb +2 -1
  52. data/lib/device/library/cygwin.rb +2 -1
  53. data/lib/device/library/linux.rb +2 -1
  54. data/lib/device/library/mac.rb +2 -1
  55. data/lib/device/library/windows.rb +2 -1
  56. data/lib/device/library/windows/eject.rb +2 -1
  57. data/lib/device/reader.rb +2 -1
  58. data/lib/diffviewer.rb +8 -11
  59. data/lib/downloader.rb +159 -151
  60. data/lib/eventable.rb +2 -1
  61. data/lib/extension.rb +16 -14
  62. data/lib/extensions/jruby.rb +2 -1
  63. data/lib/extensions/monkey_patches.rb +7 -0
  64. data/lib/extensions/monkey_patches/pathname.rb +22 -0
  65. data/lib/extensions/windows.rb +2 -1
  66. data/lib/extensions/windows_write_color.rb +2 -1
  67. data/lib/helper.rb +35 -20
  68. data/lib/html.rb +2 -1
  69. data/lib/illustration.rb +2 -1
  70. data/lib/ini.rb +2 -1
  71. data/lib/input.rb +2 -1
  72. data/lib/inspector.rb +3 -2
  73. data/lib/inventory.rb +3 -3
  74. data/lib/mailer.rb +3 -2
  75. data/lib/mixin/all.rb +8 -0
  76. data/lib/mixin/locker.rb +40 -0
  77. data/lib/mixin/output_error.rb +28 -0
  78. data/lib/narou.rb +69 -51
  79. data/lib/narou/api.rb +2 -4
  80. data/lib/narou_logger.rb +236 -108
  81. data/lib/novelconverter.rb +77 -69
  82. data/lib/novelinfo.rb +4 -2
  83. data/lib/novelsetting.rb +15 -12
  84. data/lib/progressbar.rb +13 -9
  85. data/lib/sitesetting.rb +39 -18
  86. data/lib/template.rb +5 -4
  87. data/lib/version.rb +3 -2
  88. data/lib/web/all.rb +2 -1
  89. data/lib/web/appserver.rb +83 -65
  90. data/lib/web/helper4web.rb +10 -5
  91. data/lib/web/progressbar4web.rb +8 -4
  92. data/lib/web/public/resources/default-style.css +2 -3
  93. data/lib/web/public/resources/narou.library.js +86 -60
  94. data/lib/web/public/resources/narou.queue.js +24 -30
  95. data/lib/web/public/resources/narou.ui.js +22 -3
  96. data/lib/web/public/theme/Cerulean/style.css +5 -5
  97. data/lib/web/public/theme/Darkly/style.css +5 -5
  98. data/lib/web/public/theme/Readable/style.css +5 -5
  99. data/lib/web/public/theme/Slate/style.css +2 -3
  100. data/lib/web/public/theme/Superhero/style.css +2 -3
  101. data/lib/web/public/theme/United/style.css +5 -5
  102. data/lib/web/pushserver.rb +10 -7
  103. data/lib/web/server_helpers.rb +16 -1
  104. data/lib/web/settingmessages.rb +10 -7
  105. data/lib/web/streaminginput.rb +2 -1
  106. data/lib/web/streaminglogger.rb +45 -32
  107. data/lib/web/views/_about.haml +6 -3
  108. data/lib/web/views/_header.haml +2 -3
  109. data/lib/web/views/_move_to_top.haml +2 -0
  110. data/lib/web/views/_queue.haml +7 -0
  111. data/lib/web/views/bookmarklet/insert_button.js.erb +1 -1
  112. data/lib/web/views/index.haml +30 -27
  113. data/lib/web/views/layout.haml +2 -0
  114. data/lib/web/views/novels/setting.haml +3 -4
  115. data/lib/web/views/settings.haml +22 -8
  116. data/lib/web/views/style.scss +54 -3
  117. data/lib/web/views/widget/download.haml +9 -3
  118. data/lib/web/views/widget/drag_and_drop.haml +10 -4
  119. data/lib/web/web_worker.rb +132 -0
  120. data/lib/worker.rb +142 -0
  121. data/narou.gemspec +80 -45
  122. data/narou.rb +6 -4
  123. data/template/novel.txt.erb +1 -0
  124. data/webnovel/kakuyomu.jp.yaml +9 -13
  125. data/webnovel/ncode.syosetu.com.yaml +3 -1
  126. data/webnovel/novel18.syosetu.com.yaml +8 -1
  127. data/webnovel/syosetu.org.yaml +3 -1
  128. data/webnovel/www.akatsuki-novels.com.yaml +4 -2
  129. data/webnovel/www.mai-net.net.yaml +3 -1
  130. metadata +109 -48
  131. data/lib/web/worker.rb +0 -126
@@ -42,8 +42,8 @@ module Narou
42
42
  end
43
43
 
44
44
  def log_path
45
- if Narou.get_root_dir
46
- File.join(Narou.get_root_dir, LOG_NAME)
45
+ if Narou.root_dir
46
+ File.join(Narou.root_dir, LOG_NAME)
47
47
  else
48
48
  LOG_NAME
49
49
  end
@@ -1,4 +1,8 @@
1
- # -*- coding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2013 whiteleaf. All rights reserved.
5
+ #
2
6
 
3
7
  def write_color(str, console = STDOUT)
4
8
  console.write str
@@ -1,9 +1,9 @@
1
- # -*- coding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
2
3
  #
3
4
  # Copyright 2013 whiteleaf. All rights reserved.
4
5
  #
5
6
 
6
- require "optparse"
7
7
  require_relative "commandbase"
8
8
  Dir.glob(File.expand_path(File.join(File.dirname(__FILE__), "command", "*.rb"))) do |path|
9
9
  require path
@@ -38,12 +38,17 @@ module Command
38
38
  "backup" => Backup,
39
39
  "csv" => Csv,
40
40
  "clean" => Clean,
41
+ "log" => Log,
41
42
  "trace" => Trace,
42
43
  "help" => Help,
43
44
  "version" => Version,
44
45
  "init" => Init
45
46
  }
46
47
 
48
+ if $development
49
+ COMMAND_LIST["console"] = Console
50
+ end
51
+
47
52
  # ショートカット定義
48
53
  # COMMAND_LIST の上から順に優先度が高い
49
54
  Shortcuts = Hash[*get_list.keys.reverse.map { |s|
@@ -1,4 +1,5 @@
1
- # -*- coding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
2
3
  #
3
4
  # Copyright 2013 whiteleaf. All rights reserved.
4
5
  #
@@ -48,10 +49,7 @@ module Command
48
49
 
49
50
  def execute(argv)
50
51
  super
51
- if argv.empty?
52
- puts @opt.help
53
- return
54
- end
52
+ display_help! if argv.empty?
55
53
  aliases = Inventory.load("alias")
56
54
  argv.each_with_index do |arg, i|
57
55
  Helper.print_horizontal_rule if i > 0
@@ -1,4 +1,5 @@
1
- # -*- coding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
2
3
  #
3
4
  # Copyright 2013 whiteleaf. All rights reserved.
4
5
  #
@@ -60,10 +61,7 @@ module Command
60
61
 
61
62
  def execute(argv)
62
63
  super
63
- if argv.empty?
64
- puts @opt.help
65
- return
66
- end
64
+ display_help! if argv.empty?
67
65
  tagname_to_ids(argv)
68
66
  require "zip"
69
67
  argv.each_with_index do |target, i|
@@ -1,4 +1,5 @@
1
- # -*- coding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
2
3
  #
3
4
  # Copyright 2013 whiteleaf. All rights reserved.
4
5
  #
@@ -32,10 +33,7 @@ module Command
32
33
 
33
34
  def execute(argv)
34
35
  super
35
- if argv.empty?
36
- puts @opt.help
37
- return
38
- end
36
+ display_help! if argv.empty?
39
37
  tagname_to_ids(argv)
40
38
  argv.each do |target|
41
39
  data = Downloader.get_data_by_target(target)
@@ -1,4 +1,8 @@
1
- # -*- coding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2013 whiteleaf. All rights reserved.
5
+ #
2
6
 
3
7
  require "fileutils"
4
8
  require_relative "../downloader"
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2013 whiteleaf. All rights reserved.
5
+ #
6
+
7
+ if $development
8
+ module Command
9
+ class Console < CommandBase
10
+ def self.oneline_help
11
+ "開発用コンソール"
12
+ end
13
+
14
+ def initialize
15
+ super()
16
+ @opt.separator <<~HELP
17
+
18
+ ・開発時のみ有効になるコンソール。pry のインストール必須
19
+ HELP
20
+ end
21
+
22
+ def execute(argv)
23
+ $stdout = STDOUT
24
+ super
25
+ unless defined?(Pry)
26
+ error "gem install pry をが必要です"
27
+ exit Narou::EXIT_ERROR_CODE
28
+ end
29
+ Pry.start(TOPLEVEL_BINDING)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,4 +1,5 @@
1
- # -*- coding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
2
3
  #
3
4
  # Copyright 2013 whiteleaf. All rights reserved.
4
5
  #
@@ -8,6 +9,7 @@ require_relative "../downloader"
8
9
  require_relative "../novelconverter"
9
10
  require_relative "../inventory"
10
11
  require_relative "../kindlestrip"
12
+ require_relative "../worker"
11
13
 
12
14
  module Command
13
15
  class Convert < CommandBase
@@ -20,23 +22,23 @@ module Command
20
22
  @@sending_error_list = []
21
23
 
22
24
  def self.display_sending_error_list
23
- puts
24
- puts "-" * 79
25
- puts "・送信失敗リスト"
26
- puts @@sending_error_list
27
- puts
28
- puts "<red><bold>上記のファイルの送信に失敗しました。</bold></red>".termcolor
29
- puts "送信出来なかった原因を解消し、send コマンドを実行して下さい。"
25
+ return unless exists_sending_error_list?
26
+ $stdout2.puts <<~MSG
27
+ #{"=" * 79}
28
+ ・送信失敗リスト
29
+ #{@@sending_error_list.join("\n")}
30
+
31
+ MSG
32
+ $stdout2.puts "<red><bold>上記のファイルの送信に失敗しました。</bold></red>".termcolor
33
+ $stdout2.puts <<~MSG
34
+ 送信出来なかった原因を解消し、send コマンドを実行して下さい。
35
+ #{"=" * 79}
36
+ MSG
30
37
  @@sending_error_list.clear
31
- if $stdin.tty? && Narou.web?.!
32
- puts
33
- puts "(何かキーを押して下さい)"
34
- $stdin.getch
35
- end
36
38
  end
37
39
 
38
40
  def self.exists_sending_error_list?
39
- @@sending_error_list.empty?.!
41
+ @@sending_error_list.present?
40
42
  end
41
43
 
42
44
  def initialize
@@ -110,12 +112,29 @@ module Command
110
112
  EOS
111
113
  end
112
114
 
115
+ def self.execute!(*argv, io: $stdout2, sync: false)
116
+ if sync
117
+ # cocurrency が有効だろうが必ず同期実行する
118
+ status = super(*argv, io: io)
119
+ yield if block_given?
120
+ status
121
+ else
122
+ Narou.concurrency_call do
123
+ status = super(*argv, io: io)
124
+ yield if block_given?
125
+ status
126
+ end
127
+ end
128
+ end
129
+
113
130
  def execute(argv)
114
131
  super
115
- if argv.empty?
116
- puts @opt.help
117
- return
118
- end
132
+ init(argv)
133
+ main(argv)
134
+ end
135
+
136
+ def init(argv)
137
+ display_help! if argv.empty?
119
138
  @output_filename = @options["output"]
120
139
  if @output_filename
121
140
  @ext = File.extname(@output_filename)
@@ -123,121 +142,126 @@ module Command
123
142
  else
124
143
  @basename = nil
125
144
  end
126
- if @options["encoding"]
127
- @enc = Encoding.find(@options["encoding"]) rescue nil
128
- unless @enc
129
- error "--enc で指定された文字コードは存在しません。sjis, eucjp, utf-8 等を指定して下さい"
130
- return
145
+ return unless @options["encoding"]
146
+ @enc = Encoding.find(@options["encoding"]) rescue nil
147
+ return if @enc
148
+ $stdout2.error "--enc で指定された文字コードは存在しません。sjis, eucjp, utf-8 等を指定して下さい"
149
+ end
150
+
151
+ def main(argv)
152
+ build_device_names.each do |name|
153
+ @device = Narou.get_device(name)
154
+ if name
155
+ $stdout2.puts "<bold><magenta>&gt;&gt; #{@device.display_name}用に変換します</magenta></bold>".termcolor
131
156
  end
157
+ self.extend(@device.get_hook_module) if @device
158
+ hook_call(:change_settings)
159
+ convert_novels(argv)
132
160
  end
161
+ return unless @options["multi-device"]
162
+ # device の設定に戻す
163
+ device = Narou.get_device
164
+ force_change_settings_function(device.get_relative_variables) if device
165
+ end
133
166
 
134
- @multi_device = @options["multi-device"]
135
- device_names = if @multi_device
136
- @multi_device.split(",").map(&:strip).map(&:downcase).select { |name|
137
- Device.exists?(name).tap { |this|
167
+ def build_device_names
168
+ multi_device = @options["multi-device"]
169
+ device_names = if multi_device
170
+ multi_device.split(",").map(&:strip).map(&:downcase).select do |name|
171
+ Device.exists?(name).tap do |this|
138
172
  unless this
139
- error "[convert.multi-device] #{name} は有効な端末名ではありません"
173
+ $stdout2.error "[convert.multi-device] #{name} は有効な端末名ではありません"
140
174
  end
141
- }
142
- }
175
+ end
176
+ end
143
177
  else
144
- [nil] # nil で device 設定が読まれる
178
+ [nil] # nil で device 設定が読まれる
145
179
  end
146
180
  # kindle用のmobiを作る過程でepubが作成され、上書きされてしまうので、最初に作るようにする
147
181
  kindle = device_names.delete("kindle")
148
182
  device_names.unshift(kindle) if kindle
149
-
150
- if @multi_device && device_names.empty?
151
- error "有効な端末名がひとつもありませんでした"
183
+ if multi_device && device_names.empty?
184
+ $stdout2.error "有効な端末名がひとつもありませんでした"
152
185
  exit Narou::EXIT_ERROR_CODE
153
186
  end
154
-
155
- device_names.each do |name|
156
- @device = Narou.get_device(name)
157
- if name
158
- puts "<bold><magenta>&gt;&gt; #{@device.display_name}用に変換します</magenta></bold>".termcolor
159
- end
160
- self.extend(@device.get_hook_module) if @device
161
- hook_call(:change_settings)
162
- convert_novels(argv)
163
- end
164
-
165
- # device の設定に戻す
166
- if @multi_device
167
- device = Narou.get_device
168
- force_change_settings_function(device.get_relative_variables) if device
169
- end
187
+ device_names
170
188
  end
171
189
 
172
190
  def change_settings
173
191
  return unless @device
174
- if @multi_device
192
+ if @options["multi-device"]
175
193
  force_change_settings_function(@device.get_relative_variables)
176
194
  end
177
195
  end
178
196
 
179
197
  def convert_novels(argv)
180
198
  tagname_to_ids(argv)
181
- argv.each.with_index(1) do |target, i|
182
- @target = target
183
- @novel_data = nil
184
-
185
- Helper.print_horizontal_rule if i > 1
186
- if @basename
187
- @basename << " (#{i})" if argv.length > 1
188
- @output_filename = @basename + @ext
199
+ argv.each.with_index(1) do |target, index|
200
+ Narou.lock(target) do
201
+ convert_novel_main(target, index)
189
202
  end
203
+ end
204
+ rescue Interrupt
205
+ $stdout2.puts "変換を中断しました"
206
+ exit Narou::EXIT_INTERRUPT
207
+ end
190
208
 
191
- if File.file?(target.to_s)
192
- using_send_command = false
193
- # not remove output files for text file conversion
194
- res = convert_txt(target)
195
- else
196
- using_send_command = true
197
- # remove output files for novel conversion
198
- NovelConverter.extensions_of_converted_files(@device).each do |ext|
199
- ebook_paths = Narou.get_ebook_file_paths(target, ext)
200
- NovelConverter.clean_up_temp_files(ebook_paths)
201
- end
202
- # start novel conversion
203
- @argument_target_type = :novel
204
- unless Downloader.novel_exists?(target)
205
- error "#{target} は存在しません"
206
- next
207
- end
208
- res = NovelConverter.convert(target, {
209
- output_filename: @output_filename,
210
- display_inspector: @options["inspect"],
211
- ignore_force: @options["ignore-force"],
212
- ignore_default: @options["ignore-default"],
213
- })
214
- @novel_data = Downloader.get_data_by_target(target)
215
- @options["yokogaki"] = NovelSetting.load(target)["enable_yokogaki"]
209
+ def convert_novel_main(target, index)
210
+ @target = target
211
+ @novel_data = nil
212
+
213
+ Helper.print_horizontal_rule($stdout2) if index > 1
214
+ if @basename
215
+ @basename << " (#{index})" if argv.length > 1
216
+ @output_filename = @basename + @ext
217
+ end
218
+
219
+ if File.file?(target.to_s)
220
+ using_send_command = false
221
+ # not remove output files for text file conversion
222
+ res = convert_txt(target)
223
+ else
224
+ using_send_command = true
225
+ unless Downloader.novel_exists?(target)
226
+ $stdout2.error "#{target} は存在しません"
227
+ return
216
228
  end
217
- next unless res
218
- array_of_converted_txt_path = res[:converted_txt_paths]
219
- ebook_file = nil
220
- array_of_converted_txt_path.each do |converted_txt_path|
221
- @converted_txt_path = converted_txt_path
222
- @use_dakuten_font = res[:use_dakuten_font]
223
-
224
- ebook_file = hook_call(:convert_txt_to_ebook_file)
225
- next if ebook_file.nil?
226
- if ebook_file
227
- copy_to_converted_file(ebook_file)
228
- send_file_to_device(ebook_file) unless using_send_command
229
- end
229
+ # remove output files for novel conversion
230
+ NovelConverter.extensions_of_converted_files(@device).each do |ext|
231
+ ebook_paths = Narou.get_ebook_file_paths(target, ext)
232
+ NovelConverter.clean_up_temp_files(ebook_paths)
230
233
  end
231
- send_file_to_device(ebook_file) if
232
- using_send_command && ebook_file
234
+ # start novel conversion
235
+ @argument_target_type = :novel
236
+ res = NovelConverter.convert(target, {
237
+ output_filename: @output_filename,
238
+ display_inspector: @options["inspect"],
239
+ ignore_force: @options["ignore-force"],
240
+ ignore_default: @options["ignore-default"],
241
+ })
242
+ @novel_data = Downloader.get_data_by_target(target)
243
+ @options["yokogaki"] = NovelSetting.load(target)["enable_yokogaki"]
244
+ end
245
+ return unless res
246
+ array_of_converted_txt_path = res[:converted_txt_paths]
247
+ ebook_file = nil
248
+ array_of_converted_txt_path.each do |converted_txt_path|
249
+ @converted_txt_path = converted_txt_path
250
+ @use_dakuten_font = res[:use_dakuten_font]
233
251
 
234
- if @options["no-open"].! && Narou.web?.!
235
- Helper.open_directory(File.dirname(@converted_txt_path), "小説の保存フォルダを開きますか")
252
+ ebook_file = hook_call(:convert_txt_to_ebook_file)
253
+ next if ebook_file.nil?
254
+ if ebook_file
255
+ copy_to_converted_file(ebook_file)
256
+ send_file_to_device(ebook_file) unless using_send_command
236
257
  end
237
258
  end
238
- rescue Interrupt
239
- puts "変換を中断しました"
240
- exit Narou::EXIT_INTERRUPT
259
+ send_file_to_device(ebook_file) if
260
+ using_send_command && ebook_file
261
+
262
+ if @options["no-open"].! && Narou.web?.!
263
+ Helper.open_directory(File.dirname(@converted_txt_path), "小説の保存フォルダを開きますか")
264
+ end
241
265
  end
242
266
 
243
267
  #
@@ -253,17 +277,19 @@ module Command
253
277
  })
254
278
  rescue ArgumentError => e
255
279
  if e.message =~ /invalid byte sequence in UTF-8/
256
- error "テキストファイルの文字コードがUTF-8ではありません。" +
257
- "--enc オプションでテキストの文字コードを指定して下さい"
280
+ $stdout2.error "テキストファイルの文字コードがUTF-8ではありません。" \
281
+ "--enc オプションでテキストの文字コードを指定して下さい"
258
282
  warn "(#{e.message})"
259
283
  return nil
260
284
  else
261
285
  raise
262
286
  end
263
287
  rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError
264
- warn "#{target}:"
265
- error "テキストファイルの文字コードは#{@options["encoding"]}ではありませんでした。" +
266
- "正しい文字コードを指定して下さい"
288
+ $stdout2.error <<~ERR
289
+ #{target}:
290
+ テキストファイルの文字コードは#{@options["encoding"]}ではありませんでした。
291
+ 正しい文字コードを指定して下さい
292
+ ERR
267
293
  return nil
268
294
  end
269
295
 
@@ -288,15 +314,15 @@ module Command
288
314
  #
289
315
  # convert.copy-to で指定されたディレクトリに書籍データをコピーする
290
316
  #
291
- def copy_to_converted_file(src_path)
317
+ def copy_to_converted_file(src_path, io: $stdout2)
292
318
  copy_to_dir = get_copy_to_directory
293
319
  return nil unless copy_to_dir
294
320
  FileUtils.copy(src_path, copy_to_dir)
295
321
  copied_file_path = File.join(copy_to_dir, File.basename(src_path))
296
- puts copied_file_path.encode(Encoding::UTF_8) + " へコピーしました"
322
+ io.puts copied_file_path.to_s.encode(Encoding::UTF_8) + " へコピーしました"
297
323
  copied_file_path
298
324
  rescue NoSuchDirectory => e
299
- error "#{e.message} はフォルダではないかすでに削除されています。コピー出来ませんでした"
325
+ io.error "#{e.message} はフォルダではないかすでに削除されています。コピー出来ませんでした"
300
326
  nil
301
327
  end
302
328
 
@@ -345,24 +371,24 @@ module Command
345
371
  result
346
372
  end
347
373
 
348
- def send_file_to_device(ebook_file)
374
+ def send_file_to_device(ebook_file, io: $stdout2)
349
375
  if @device && @device.physical_support? &&
350
376
  @device.connecting? && File.extname(ebook_file) == @device.ebook_file_ext
351
377
  if @argument_target_type == :novel
352
- if Send.execute!(@device.name, @target) > 0
378
+ if Send.execute!(@device.name, @target, io: io) > 0
353
379
  @@sending_error_list << ebook_file
354
380
  end
355
381
  else
356
- puts @device.name + "へ送信しています"
382
+ io.puts @device.name + "へ送信しています"
357
383
  copy_to_path = nil
358
384
  begin
359
385
  copy_to_path = @device.copy_to_documents(ebook_file)
360
386
  rescue Device::SendFailure
361
387
  end
362
388
  if copy_to_path
363
- puts copy_to_path.encode(Encoding::UTF_8) + " へコピーしました"
389
+ io.puts copy_to_path.to_s.encode(Encoding::UTF_8) + " へコピーしました"
364
390
  else
365
- error "送信に失敗しました"
391
+ io.error "送信に失敗しました"
366
392
  @@sending_error_list << ebook_file
367
393
  end
368
394
  end