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
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2013 whiteleaf. All rights reserved.
5
+ #
6
+
7
+ module Command
8
+ class Log < CommandBase
9
+ # based on https://qiita.com/ymmtmdk/items/10cf80ec2fc7962ff9fc
10
+ class Tail
11
+ CHUNK_SIZE = 1024 * 16
12
+
13
+ attr_accessor :path, :num, :stream_io
14
+
15
+ def initialize(path, num)
16
+ self.path = path
17
+ self.num = num
18
+ raise unless num.to_i > 0
19
+ end
20
+
21
+ def stream
22
+ execute do |file|
23
+ loop do
24
+ stream_io.print file.read
25
+ sleep 0.1
26
+ end
27
+ end
28
+ end
29
+
30
+ def display
31
+ execute do |file|
32
+ stream_io.puts file.read
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def execute
39
+ File.open(path, "r:UTF-8") do |file|
40
+ offset = offset_of_nth_chr_from_tail(file, num, "\n")
41
+ file.seek(file.size - offset)
42
+ yield file
43
+ end
44
+ end
45
+
46
+ def reverse_chunks(file, size)
47
+ n = file.size / size
48
+ n -= 1 if file.size == n * size
49
+ len = file.size - n * size
50
+ until n < 0
51
+ file.seek(n * size)
52
+ yield file.read(len)
53
+ n -= 1
54
+ len = size
55
+ end
56
+ end
57
+
58
+ def offset_of_nth_chr_from_tail(file, count, target)
59
+ offset = 0
60
+ reverse_chunks(file, CHUNK_SIZE) do |chunk|
61
+ chunk.size.times do |i|
62
+ chr = chunk[chunk.size - i - 1]
63
+ next unless chr == target || (offset == 0 && i == 0 && chr != target)
64
+ count -= 1
65
+ if count < 0
66
+ offset += i
67
+ return offset
68
+ end
69
+ end
70
+ offset += chunk.size
71
+ end
72
+ offset
73
+ end
74
+ end
75
+ end
76
+ 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
  #
@@ -50,7 +51,7 @@ module Command
50
51
  install_mailer_setting
51
52
  return
52
53
  rescue Mailer::SettingUncompleteError => e
53
- error e.message
54
+ stream_io.error e.message
54
55
  exit Narou::EXIT_ERROR_CODE
55
56
  end
56
57
  if argv.empty?
@@ -76,11 +77,11 @@ module Command
76
77
  end
77
78
  end
78
79
  unless ebook_paths[0]
79
- error "#{target} は存在しません" unless send_all
80
+ stream_io.error "#{target} は存在しません" unless send_all
80
81
  next
81
82
  end
82
83
  unless File.exist?(ebook_paths[0])
83
- error "まだファイル(#{File.basename(ebook_paths[0])})が無いようです" unless send_all
84
+ stream_io.error "まだファイル(#{File.basename(ebook_paths[0])})が無いようです" unless send_all
84
85
  next
85
86
  end
86
87
  if target == "hotentry"
@@ -90,8 +91,8 @@ module Command
90
91
  title = data["title"]
91
92
  display_target = "ID:#{id} #{TermColorLight.escape(title)}"
92
93
  end
93
- puts "<bold><green>#{display_target}</green></bold>".termcolor
94
- print "メールを送信しています"
94
+ stream_io.puts "<bold><green>#{display_target}</green></bold>".termcolor
95
+ stream_io.print "メールを送信しています"
95
96
  ebook_paths.each do |ebook_path|
96
97
  exit_mail = false
97
98
  mail_result = nil
@@ -100,36 +101,38 @@ module Command
100
101
  exit_mail = true
101
102
  end
102
103
  until exit_mail
103
- print "."
104
+ stream_io.print "."
104
105
  sleep(0.5)
105
106
  end
106
- puts
107
+ stream_io.puts
107
108
  if mail_result
108
- puts File.basename(ebook_path) + " をメールで送信しました"
109
+ stream_io.puts File.basename(ebook_path) + " をメールで送信しました"
109
110
  database[id]["last_mail_date"] = Time.now if target != "hotentry"
110
111
  else
111
- error mailer.error_message
112
+ stream_io.error mailer.error_message
112
113
  exit Narou::EXIT_ERROR_CODE # next しても次も失敗する可能性が高いのでここで終了
113
114
  end
114
115
  end
115
116
  end
116
117
  rescue Interrupt
117
- puts "メール送信を中断しました"
118
+ stream_io.puts "メール送信を中断しました"
118
119
  exit Narou::EXIT_INTERRUPT
119
120
  ensure
120
121
  database.save_database if database
121
122
  end
122
123
 
123
124
  def install_mailer_setting
124
- setting_file_path = File.join(Narou.get_preset_dir, Mailer::SETTING_FILE)
125
- install_path = File.join(Narou.get_root_dir, Mailer::SETTING_FILE)
125
+ setting_file_path = File.join(Narou.preset_dir, Mailer::SETTING_FILE)
126
+ install_path = File.join(Narou.root_dir, Mailer::SETTING_FILE)
126
127
  FileUtils.cp(setting_file_path, install_path)
127
128
  alter_database_add_column_last_mail_date
128
- puts "created #{install_path}"
129
- puts "メールの設定用ファイルを作成しました。設定ファイルを書き換えることで mail コマンドが有効になります。"
130
- puts "注意:次回以降のupdateで新着があった場合に送信可能フラグが立ちます"
129
+ stream_io.puts <<~MSG
130
+ created #{install_path}
131
+ メールの設定用ファイルを作成しました。設定ファイルを書き換えることで mail コマンドが有効になります。
132
+ 注意:次回以降のupdateで新着があった場合に送信可能フラグが立ちます
133
+ MSG
131
134
  unless Narou.web?
132
- Helper.open_directory(Narou.get_root_dir, "設定ファイルがあるフォルダを開きますか")
135
+ Helper.open_directory(Narou.root_dir, "設定ファイルがあるフォルダを開きますか")
133
136
  end
134
137
  end
135
138
 
@@ -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
  end
61
62
  argv += novels.map { |n| n["id"].to_s }
62
63
  end
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
  argv.each_with_index do |target, i|
69
67
  Helper.print_horizontal_rule if i > 0
@@ -73,7 +71,10 @@ module Command
73
71
  next
74
72
  end
75
73
  title = data["title"]
76
- if Narou.novel_frozen?(target)
74
+ if Narou.locked?(target)
75
+ error "#{title} は変換中なため削除出来ませんでした"
76
+ next
77
+ elsif Narou.novel_frozen?(target)
77
78
  puts "#{title} は凍結中です\n削除を中止しました"
78
79
  next
79
80
  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
  #
@@ -65,17 +66,19 @@ module Command
65
66
  super
66
67
  device = get_device(argv)
67
68
  unless device
68
- error "デバイス名が指定されていないか、間違っています。\n" +
69
- "narou setting device=デバイス名 で指定出来ます。\n" +
70
- "指定出来るデバイス名:" + Device::DEVICES.keys.join(", ")
69
+ stream_io.error <<~ERR
70
+ デバイス名が指定されていないか、間違っています。
71
+ narou setting device=デバイス名 で指定出来ます。
72
+ 指定出来るデバイス名:#{Device::DEVICES.keys.join(", ")}
73
+ ERR
71
74
  exit Narou::EXIT_ERROR_CODE
72
75
  end
73
76
  unless device.physical_support?
74
- error "#{device.display_name} への直接送信は対応していません"
77
+ stream_io.error "#{device.display_name} への直接送信は対応していません"
75
78
  exit Narou::EXIT_ERROR_CODE
76
79
  end
77
80
  unless device.connecting?
78
- error "#{device.display_name} が接続されていません"
81
+ stream_io.error "#{device.display_name} が接続されていません"
79
82
  exit Narou::EXIT_ERROR_CODE
80
83
  end
81
84
 
@@ -118,11 +121,11 @@ module Command
118
121
  ebook_paths = Narou.get_ebook_file_paths(target, device.ebook_file_ext)
119
122
  end
120
123
  unless ebook_paths[0]
121
- error "#{target} は存在しません"
124
+ stream_io.error "#{target} は存在しません"
122
125
  next
123
126
  end
124
127
  unless File.exist?(ebook_paths[0])
125
- error "まだファイル(#{File.basename(ebook_paths[0])})が無いようです" unless send_all
128
+ stream_io.error "まだファイル(#{File.basename(ebook_paths[0])})が無いようです" unless send_all
126
129
  next
127
130
  end
128
131
 
@@ -136,9 +139,9 @@ module Command
136
139
  else
137
140
  "ID:#{target} #{TermColorLight.escape(titles[target])}"
138
141
  end
139
- puts "<bold><green>#{display_target}</green></bold>".termcolor
142
+ stream_io.puts "<bold><green>#{display_target}</green></bold>".termcolor
140
143
 
141
- print "#{device.name}へ送信しています"
144
+ stream_io.print "#{device.name}へ送信しています"
142
145
  ebook_paths.each do |ebook_path|
143
146
  exit_copy = false
144
147
  copy_to_path = nil
@@ -148,14 +151,14 @@ module Command
148
151
  exit_copy = true
149
152
  end
150
153
  until exit_copy
151
- print "."
154
+ stream_io.print "."
152
155
  sleep(0.5)
153
156
  end
154
- puts
157
+ stream_io.puts
155
158
  if copy_to_path
156
- puts copy_to_path + " へコピーしました"
159
+ stream_io.puts copy_to_path + " へコピーしました"
157
160
  else
158
- error "#{device.name}が見つからなかったためコピー出来ませんでした"
161
+ stream_io.error "#{device.name}が見つからなかったためコピー出来ませんでした"
159
162
  exit Narou::EXIT_ERROR_CODE # next しても次も失敗すると分かりきっているためここで終了する
160
163
  end
161
164
  end
@@ -164,31 +167,31 @@ module Command
164
167
  process_backup_bookmark(device)
165
168
  end
166
169
  rescue Device::SendFailure, Interrupt
167
- puts "送信を中断しました"
170
+ stream_io.puts "送信を中断しました"
168
171
  exit Narou::EXIT_INTERRUPT
169
172
  end
170
173
 
171
174
  def process_backup_bookmark(device)
172
175
  device.extend(device.get_hook_module)
173
176
  unless device.respond_to?(:backup_bookmark)
174
- error "ご利用の端末での栞データのバックアップは対応していません"
177
+ stream_io.error "ご利用の端末での栞データのバックアップは対応していません"
175
178
  return
176
179
  end
177
180
  if device.backup_bookmark > 0
178
- puts "端末の栞データをバックアップしました"
181
+ stream_io.puts "端末の栞データをバックアップしました"
179
182
  end
180
183
  end
181
184
 
182
185
  def process_restore_bookmark(device)
183
186
  device.extend(device.get_hook_module)
184
187
  unless device.respond_to?(:restore_bookmark)
185
- error "ご利用の端末での栞データのバックアップは対応していません"
188
+ stream_io.error "ご利用の端末での栞データのバックアップは対応していません"
186
189
  return
187
190
  end
188
191
  if device.restore_bookmark > 0
189
- puts "栞データを端末にコピーしました"
192
+ stream_io.puts "栞データを端末にコピーしました"
190
193
  else
191
- puts "栞データが無いようです"
194
+ stream_io.puts "栞データが無いようです"
192
195
  end
193
196
  end
194
197
  end
@@ -1,8 +1,10 @@
1
- # -*- coding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
2
3
  #
3
4
  # Copyright 2013 whiteleaf. All rights reserved.
4
5
  #
5
6
 
7
+ require_relative "../narou_logger"
6
8
  require_relative "../inventory"
7
9
  require_relative "../novelsetting"
8
10
  require_relative "../eventable"
@@ -114,19 +116,19 @@ module Command
114
116
  global: Inventory.load("global_setting", :global)
115
117
  }
116
118
  settings.each do |scope, scoped_settings|
117
- puts "[#{scope.capitalize} Variables]"
119
+ stream_io.puts "[#{scope.capitalize} Variables]"
118
120
  scoped_settings.each do |name, value|
119
121
  if value =~ / /
120
122
  value = "'#{value}'"
121
123
  end
122
- puts "<bold><green>#{name}</green></bold>=#{value}".termcolor
124
+ stream_io.puts "<bold><green>#{name}</green></bold>=#{value}".termcolor
123
125
  end
124
126
  end
125
127
  end
126
128
 
127
129
  def output_error(msg, name = nil)
128
130
  @error_count += 1
129
- error msg
131
+ stream_io.error msg
130
132
  trigger(:error, msg, name)
131
133
  end
132
134
 
@@ -144,7 +146,7 @@ module Command
144
146
  def output_value(name, settings)
145
147
  scope = get_scope_of_variable_name(name)
146
148
  if scope
147
- puts settings[scope][name]
149
+ stream_io.puts settings[scope][name]
148
150
  else
149
151
  output_error("#{name} という変数は存在しません", name)
150
152
  end
@@ -156,10 +158,7 @@ module Command
156
158
  burn_default_settings(argv)
157
159
  return
158
160
  end
159
- if argv.empty?
160
- puts @opt.help
161
- return
162
- end
161
+ display_help! if argv.empty?
163
162
  settings = {
164
163
  local: Inventory.load("local_setting", :local),
165
164
  global: Inventory.load("global_setting", :global)
@@ -183,7 +182,7 @@ module Command
183
182
  # 定義上ではすでに存在しないが、設定ファイルには残っている古い変数
184
183
  # を削除できるようにする
185
184
  if sweep_dust_variable(name, settings)
186
- puts "#{name} の設定を削除しました"
185
+ stream_io.puts "#{name} の設定を削除しました"
187
186
  else
188
187
  output_error("#{name} という変数は存在しません", name)
189
188
  end
@@ -212,10 +211,10 @@ module Command
212
211
  def modify_settings(scoped_settings, name, value)
213
212
  if value.nil?
214
213
  scoped_settings.delete(name)
215
- puts "#{name} の設定を削除しました"
214
+ stream_io.puts "#{name} の設定を削除しました"
216
215
  else
217
216
  scoped_settings[name] = value
218
- puts "#{name} を #{value} に設定しました"
217
+ stream_io.puts "#{name} を #{value} に設定しました"
219
218
  end
220
219
  if name == "device" && value
221
220
  modify_settings_when_device_changed(scoped_settings)
@@ -235,17 +234,18 @@ module Command
235
234
  end
236
235
  end
237
236
  if message.length > 0
238
- puts "端末を#{device.display_name}に指定したことで、以下の関連設定が変更されました"
239
- puts message.string
237
+ stream_io.puts "端末を#{device.display_name}に指定したことで、以下の関連設定が変更されました"
238
+ stream_io.puts message.string
240
239
  end
241
240
  rescue Device::UnknownDevice => e
242
241
  output_error("#{e.message}\n設定できるのは #{Device::DEVICES.keys.join(", ")} です", "device")
243
242
  end
244
243
 
245
244
  def get_variable_list_strings(scope)
246
- result = ""
245
+ result = +""
247
246
  SETTING_VARIABLES[scope].each do |name, info|
248
247
  if @options["all"] || !info[:invisible]
248
+ raise "変数名「#{name}」のtypeが未設定です" unless info[:type]
249
249
  type_description = Helper.variable_type_to_description(info[:type])
250
250
  result << " <bold><green>#{name.ljust(18)}</green></bold> #{type_description} #{info[:help]}\n".termcolor
251
251
  end
@@ -254,11 +254,11 @@ module Command
254
254
  end
255
255
 
256
256
  def display_variable_list
257
- puts "Local Variable List:"
258
- puts get_variable_list_strings(:local).gsub(/^ {4}/, "")
259
- puts
260
- puts "Global Variable List:"
261
- puts get_variable_list_strings(:global).gsub(/^ {4}/, "")
257
+ stream_io.puts "Local Variable List:"
258
+ stream_io.puts get_variable_list_strings(:local).gsub(/^ {4}/, "")
259
+ stream_io.puts
260
+ stream_io.puts "Global Variable List:"
261
+ stream_io.puts get_variable_list_strings(:global).gsub(/^ {4}/, "")
262
262
  end
263
263
 
264
264
  #
@@ -300,7 +300,7 @@ module Command
300
300
  end
301
301
 
302
302
  novel_setting.save_settings
303
- puts "#{data["title"]} の設定を保存しました"
303
+ stream_io.puts "#{data["title"]} の設定を保存しました"
304
304
  end
305
305
  end
306
306
 
@@ -354,6 +354,39 @@ module Command
354
354
  type: :boolean, help: "hotentryをメールで送る(mail設定済みの場合)",
355
355
  tab: :detail
356
356
  },
357
+ "concurrency" => {
358
+ help: "ダウンロードと変換の同時実行を有効にする。有効にするとログの出力方式が変更される",
359
+ type: :boolean,
360
+ tab: :general
361
+ },
362
+ "concurrency.format-queue-text" => {
363
+ help: "同時実行時の変換キュー表示テキストのフォーマット。CUI専用。" \
364
+ "デフォルトは #{Narou::ConcurrencyDefaultLogger::FORMAT_TEXT.inspect.escape}",
365
+ type: :string,
366
+ invisible: true # 送信キュー実装時に変わる可能性があるので一旦隠しておく
367
+ },
368
+ "concurrency.format-queue-style" => {
369
+ help: "同時実行時の変換キュー表示スタイルのフォーマット。CUI専用。" \
370
+ "デフォルトは #{Narou::ConcurrencyDefaultLogger::FORMAT_STYLE.inspect.escape}。" \
371
+ "left:右寄せする場合に必要な幅。text:表示テキスト。space:半角スペース",
372
+ type: :string
373
+ },
374
+ "logging" => {
375
+ help: "ログの保存を有効にする。保存場所は#{Narou.log_dir&.basename}フォルダ。concurrencyが有効な場合、変換ログだけ別ファイルに出力される",
376
+ type: :boolean,
377
+ tab: :general
378
+ },
379
+ "logging.format-filename" => {
380
+ help: "ログファイル名のフォーマット。デフォルトは\"#{Narou::LoggerModule::LOG_FORMAT_FILENAME}\" 。" \
381
+ "日付でファイルを分けたくなければ固定ファイル名にする。書式は http://bit.ly/date_format 参照",
382
+ type: :string,
383
+ tab: :detail
384
+ },
385
+ "logging.format-timestamp" => {
386
+ help: "ログ内のタイムスタンプのフォーマット。デフォルトは\"#{Narou::LoggerModule::LOG_FORMAT_TIMESTAMP}\"。タイムスタンプを記録したくなければ $none とだけ入力",
387
+ type: :string,
388
+ tab: :detail
389
+ },
357
390
  "update.interval" => {
358
391
  type: :float, help: "更新時に各作品間で指定した秒数待機する(処理時間を含む)。最低#{Update::Interval::MIN}秒以上",
359
392
  tab: :general
@@ -362,12 +395,8 @@ module Command
362
395
  type: :boolean, help: "改稿日当日の連続更新でも更新漏れが起きないように、中身もチェックして更新を検知する(やや処理が重くなる)",
363
396
  tab: :general
364
397
  },
365
- "update.logging" => {
366
- type: :boolean, help: "更新時のログを保存する",
367
- tab: :detail
368
- },
369
398
  "update.convert-only-new-arrival" => {
370
- type: :boolean, help: "更新時に新着のみ変換を実行する",
399
+ type: :boolean, help: "更新時に新着がある場合のみ変換を実行する",
371
400
  tab: :general
372
401
  },
373
402
  "update.sort-by" => {
@@ -394,23 +423,19 @@ module Command
394
423
  type: :directory, help: "copy-toの昔の書き方(非推奨)", invisible: true
395
424
  },
396
425
  "convert.no-epub" => {
397
- type: :boolean, help: "EPUB変換を無効にする", invisible: true,
398
- tab: :detail
426
+ type: :boolean, help: "EPUB変換を無効にする", invisible: true
399
427
  },
400
428
  "convert.no-mobi" => {
401
- type: :boolean, help: "MOBI変換を無効にする", invisible: true,
402
- tab: :detail
429
+ type: :boolean, help: "MOBI変換を無効にする", invisible: true
403
430
  },
404
431
  "convert.no-strip" => {
405
432
  type: :boolean,
406
433
  help: "MOBIのstripを無効にする\n" \
407
434
  " ※注意:KDP用のMOBIはstripしないでください",
408
- invisible: true,
409
- tab: :detail
435
+ invisible: true
410
436
  },
411
437
  "convert.no-zip" => {
412
- type: :boolean, help: "i文庫用のzipファイル作成を無効にする", invisible: true,
413
- tab: :detail
438
+ type: :boolean, help: "i文庫用のzipファイル作成を無効にする", invisible: true
414
439
  },
415
440
  "convert.no-open" => {
416
441
  type: :boolean, help: "変換時に保存フォルダを開かないようにする",
@@ -484,9 +509,22 @@ module Command
484
509
  tab: :detail
485
510
  },
486
511
  "normalize-filename" => {
487
- type: :boolean, help: "ファイル名の文字列をNFCで正規化する。※既存データとの互換性が無くなる可能性があるので、バックアップを取った上で機能を理解の上有効にして下さい",
512
+ type: :boolean,
513
+ help: "ファイル名の文字列をNFCで正規化する。※既存データとの互換性が無くなる可能性があるので、" \
514
+ "バックアップを取った上で機能を理解の上有効にして下さい",
488
515
  tab: :detail,
489
516
  },
517
+ "folder-length-limit" => {
518
+ type: :integer,
519
+ help: "小説を格納するフォルダ名の長さを制限する。デフォルトは#{Helper::FOLDER_LENGTH_LIMIT}文字",
520
+ tab: :detail
521
+ },
522
+ "filename-length-limit" => {
523
+ type: :integer,
524
+ help: "各話保存時のファイル名の長さを制限する。※この設定は既存小説にも影響が出るので" \
525
+ "ファイル名の長さでエラーが出ない限り基本的にはいじらないこと。デフォルトは#{Helper::FILENAME_LENGTH_LIMIT}文字",
526
+ tab: :detail
527
+ },
490
528
  "webui.theme" => {
491
529
  type: :select, help: "WEB UI 用テーマ選択",
492
530
  invisible: true,
@@ -513,7 +551,7 @@ module Command
513
551
  type: :float, help: "行間サイズ(narou init から指定しないと反映されません)", invisible: true
514
552
  },
515
553
  "difftool" => {
516
- type: :string, help: "Diffで使うツールのパスを指定する",
554
+ type: :string, help: "diffで使うツールのパスを指定する",
517
555
  tab: :global
518
556
  },
519
557
  "difftool.arg" => {
@@ -572,10 +610,6 @@ module Command
572
610
  type: :boolean, help: "18歳以上かどうか", invisible: true,
573
611
  tab: :global
574
612
  },
575
- "dismiss-notice" => {
576
- type: :boolean, help: "お知らせを消す", invisible: true,
577
- tab: :global
578
- },
579
613
  }
580
614
  }
581
615