narou 3.1.11 → 3.2.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +12 -9
- data/ChangeLog.md +42 -2
- data/README.md +32 -17
- data/lib/command/convert.rb +22 -7
- data/lib/command/init.rb +65 -29
- data/lib/command/mail.rb +24 -22
- data/lib/command/send.rb +26 -23
- data/lib/command/setting.rb +20 -5
- data/lib/command/update.rb +1 -1
- data/lib/command/update/general_lastup_updater.rb +4 -3
- data/lib/converterbase.rb +0 -33
- data/lib/downloader.rb +25 -4
- data/lib/helper.rb +19 -2
- data/lib/html.rb +4 -0
- data/lib/narou.rb +42 -10
- data/lib/novelconverter.rb +87 -38
- data/lib/novelinfo.rb +2 -1
- data/lib/novelsetting.rb +25 -14
- data/lib/version.rb +1 -1
- data/lib/web/appserver.rb +25 -122
- data/lib/web/public/resources/narou.library.js +34 -1
- data/lib/web/public/resources/narou.ui.js +66 -12
- data/lib/web/server_helpers.rb +121 -0
- data/lib/web/views/settings.haml +1 -1
- data/lib/web/views/style.scss +12 -0
- data/narou.gemspec +1 -0
- data/narou.rb +3 -7
- data/preset/ncode.syosetu.com/n9463br/setting.ini +0 -4
- data/preset/vertical_font.css +1 -1
- data/preset/vertical_font_with_dakuten.css +1 -1
- data/webnovel/kakuyomu.jp.yaml +12 -7
- data/webnovel/ncode.syosetu.com.yaml +5 -0
- data/webnovel/novel18.syosetu.com.yaml +5 -0
- data/webnovel/syosetu.org.yaml +3 -0
- metadata +17 -4
- data/preset/doubledash.png +0 -0
- data/preset/singledash.png +0 -0
data/lib/command/send.rb
CHANGED
@@ -113,20 +113,21 @@ module Command
|
|
113
113
|
next
|
114
114
|
end
|
115
115
|
if target == "hotentry"
|
116
|
-
|
116
|
+
ebook_paths = [Update.get_newest_hotentry_file_path(device)]
|
117
117
|
else
|
118
|
-
|
118
|
+
ebook_paths = Narou.get_ebook_file_paths(target, device.ebook_file_ext)
|
119
119
|
end
|
120
|
-
unless
|
120
|
+
unless ebook_paths[0]
|
121
121
|
error "#{target} は存在しません"
|
122
122
|
next
|
123
123
|
end
|
124
|
-
unless File.exist?(
|
125
|
-
error "まだファイル(#{File.basename(
|
124
|
+
unless File.exist?(ebook_paths[0])
|
125
|
+
error "まだファイル(#{File.basename(ebook_paths[0])})が無いようです" unless send_all
|
126
126
|
next
|
127
127
|
end
|
128
128
|
|
129
|
-
|
129
|
+
# TODO: should check all items in ebook_paths
|
130
|
+
if !@options["force"] && !device.ebook_file_old?(ebook_paths[0])
|
130
131
|
next
|
131
132
|
end
|
132
133
|
display_target =
|
@@ -138,23 +139,25 @@ module Command
|
|
138
139
|
puts "<bold><green>#{display_target}</green></bold>".termcolor
|
139
140
|
|
140
141
|
print "#{device.name}へ送信しています"
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
142
|
+
ebook_paths.each do |ebook_path|
|
143
|
+
exit_copy = false
|
144
|
+
copy_to_path = nil
|
145
|
+
Thread.abort_on_exception = true
|
146
|
+
Thread.new do
|
147
|
+
copy_to_path = device.copy_to_documents(ebook_path)
|
148
|
+
exit_copy = true
|
149
|
+
end
|
150
|
+
until exit_copy
|
151
|
+
print "."
|
152
|
+
sleep(0.5)
|
153
|
+
end
|
154
|
+
puts
|
155
|
+
if copy_to_path
|
156
|
+
puts copy_to_path + " へコピーしました"
|
157
|
+
else
|
158
|
+
error "#{device.name}が見つからなかったためコピー出来ませんでした"
|
159
|
+
exit Narou::EXIT_ERROR_CODE # next しても次も失敗すると分かりきっているためここで終了する
|
160
|
+
end
|
158
161
|
end
|
159
162
|
end
|
160
163
|
if send_all && @options["backup-bookmark"]
|
data/lib/command/setting.rb
CHANGED
@@ -319,6 +319,7 @@ module Command
|
|
319
319
|
SETTING_TAB_NAMES = {
|
320
320
|
general: "一般",
|
321
321
|
detail: "詳細",
|
322
|
+
webui: "WEB UI",
|
322
323
|
global: "Global",
|
323
324
|
default: "default.*",
|
324
325
|
force: "force.*",
|
@@ -326,6 +327,7 @@ module Command
|
|
326
327
|
}
|
327
328
|
|
328
329
|
SETTING_TAB_INFO = {
|
330
|
+
webui: "WEB UI 専用の設定です",
|
329
331
|
global: "Global な設定はユーザープロファイルに保存され、すべての narou コマンドで使われます",
|
330
332
|
default: "default.* 系の設定は個別の変換設定で未設定の項目の挙動を指定することが出来ます",
|
331
333
|
force: "force.* 系の設定は個別設定、default.* 等の設定を無視して反映されるようになります",
|
@@ -478,22 +480,35 @@ module Command
|
|
478
480
|
help: "ネタバレ防止機能。ダウンロード時の各話タイトルを伏せ字で表示する",
|
479
481
|
tab: :detail
|
480
482
|
},
|
481
|
-
"
|
483
|
+
"normalize-filename" => {
|
484
|
+
type: :boolean, help: "ファイル名の文字列をNFCで正規化する。※既存データとの互換性が無くなる可能性があるので、バックアップを取った上で機能を理解の上有効にして下さい",
|
485
|
+
tab: :detail,
|
486
|
+
},
|
487
|
+
"webui.theme" => {
|
482
488
|
type: :select, help: "WEB UI 用テーマ選択",
|
483
489
|
invisible: true,
|
484
490
|
select_keys: Narou.get_theme_names,
|
485
491
|
select_summaries: Narou.get_theme_names,
|
486
|
-
tab: :
|
492
|
+
tab: :webui
|
487
493
|
},
|
488
|
-
"
|
489
|
-
type: :
|
490
|
-
|
494
|
+
"webui.table.reload-timing" => {
|
495
|
+
type: :select, help: "小説リストの更新タイミングを選択。未設定時は1作品ごとに更新",
|
496
|
+
invisible: true,
|
497
|
+
select_keys: %w(every queue),
|
498
|
+
select_summaries: %w(
|
499
|
+
1作品ごとに更新
|
500
|
+
キューごとに更新
|
501
|
+
),
|
502
|
+
tab: :webui
|
491
503
|
},
|
492
504
|
},
|
493
505
|
global: {
|
494
506
|
"aozoraepub3dir" => {
|
495
507
|
type: :directory, help: "AozoraEpub3のあるフォルダを指定", invisible: true
|
496
508
|
},
|
509
|
+
"line-height" => {
|
510
|
+
type: :float, help: "行間サイズ(narou init から指定しないと反映されません)", invisible: true
|
511
|
+
},
|
497
512
|
"difftool" => {
|
498
513
|
type: :string, help: "Diffで使うツールのパスを指定する",
|
499
514
|
tab: :global
|
data/lib/command/update.rb
CHANGED
@@ -35,7 +35,7 @@ module Command
|
|
35
35
|
|
36
36
|
def update_narou_novels
|
37
37
|
@narou_novels.each do |api_url, ncodes|
|
38
|
-
api = Narou::API.new(api_url: api_url, ncodes: ncodes, of: "nu-gl")
|
38
|
+
api = Narou::API.new(api_url: api_url, ncodes: ncodes, of: "nu-gl-l")
|
39
39
|
api.request.each do |result|
|
40
40
|
ncode = result["ncode"]
|
41
41
|
data = Downloader.get_data_by_target(ncode)
|
@@ -43,6 +43,7 @@ module Command
|
|
43
43
|
if result["novelupdated_at"] > last_check_date
|
44
44
|
data["novelupdated_at"] = result["novelupdated_at"]
|
45
45
|
data["general_lastup"] = result["general_lastup"]
|
46
|
+
data["length"] = result["length"]
|
46
47
|
tags = data["tags"] ||= []
|
47
48
|
tags << Narou::MODIFIED_TAG unless tags.include?(Narou::MODIFIED_TAG)
|
48
49
|
end
|
@@ -64,10 +65,10 @@ module Command
|
|
64
65
|
next unless downloader.get_latest_table_of_contents(through_error: true)
|
65
66
|
dates = {
|
66
67
|
"novelupdated_at" => downloader.get_novelupdated_at,
|
67
|
-
"general_lastup" => downloader.get_general_lastup
|
68
|
+
"general_lastup" => downloader.get_general_lastup,
|
69
|
+
"length" => downloader.novel_length
|
68
70
|
}
|
69
71
|
rescue OpenURI::HTTPError, Errno::ECONNRESET
|
70
|
-
downloader.setting.clear
|
71
72
|
next
|
72
73
|
end
|
73
74
|
data = @database[id]
|
data/lib/converterbase.rb
CHANGED
@@ -1314,7 +1314,6 @@ class ConverterBase
|
|
1314
1314
|
(io = after_convert(io)).rewind
|
1315
1315
|
data = replace_by_replace_txt(io.read)
|
1316
1316
|
data = insert_separator_for_selection(data)
|
1317
|
-
data = double_dash_to_image(data, output_text_dir)
|
1318
1317
|
return data
|
1319
1318
|
end
|
1320
1319
|
|
@@ -1430,38 +1429,6 @@ class ConverterBase
|
|
1430
1429
|
result
|
1431
1430
|
end
|
1432
1431
|
|
1433
|
-
DASH_FILES = %w(singledash.png doubledash.png)
|
1434
|
-
|
1435
|
-
def double_dash_to_image(text, output_text_dir)
|
1436
|
-
return text unless @setting.enable_double_dash_to_image
|
1437
|
-
# サブタイトルの中の場合は無視する
|
1438
|
-
# (サブタイトルは文字を大きくしているので、画像の位置がずれてしまうため)
|
1439
|
-
return text if @text_type == "subtitle"
|
1440
|
-
|
1441
|
-
begin
|
1442
|
-
# AozoraEpub3 は相対パスじゃないとエラーになるので相対パスに変換
|
1443
|
-
dash_paths = dash_image_relative_paths(Narou.get_preset_dir, output_text_dir)
|
1444
|
-
rescue ArgumentError => e
|
1445
|
-
if e.message =~ /^different prefix/
|
1446
|
-
# Windowsにおいて、スクリプト本体のあるドライブと小説フォルダがあるドライブが
|
1447
|
-
# 違う場合、相対パスを計算できなくなる。そのための対処として、.narou ディレクトリ
|
1448
|
-
# に画像データをコピーし、同一ドライブ内で相対パスを取れるようにする
|
1449
|
-
copy_dash_images_to_local_setting_dir
|
1450
|
-
dash_paths = dash_image_relative_paths(Narou.local_setting_dir, output_text_dir)
|
1451
|
-
else
|
1452
|
-
raise
|
1453
|
-
end
|
1454
|
-
end
|
1455
|
-
text.gsub(/―{2,}/) do |match|
|
1456
|
-
len = match.length
|
1457
|
-
result = "※[#(#{dash_paths[1]})]" * (len / 2)
|
1458
|
-
if len.odd?
|
1459
|
-
result += "※[#(#{dash_paths[0]})]"
|
1460
|
-
end
|
1461
|
-
result
|
1462
|
-
end
|
1463
|
-
end
|
1464
|
-
|
1465
1432
|
def dash_image_relative_paths(base_dir, output_text_dir)
|
1466
1433
|
DASH_FILES.map do |name|
|
1467
1434
|
pathname = Pathname(File.join(base_dir, name))
|
data/lib/downloader.rb
CHANGED
@@ -579,6 +579,17 @@ class Downloader
|
|
579
579
|
end
|
580
580
|
end
|
581
581
|
|
582
|
+
#
|
583
|
+
# 小説の文字数
|
584
|
+
#
|
585
|
+
# 小説情報から取得するため、実際に計算するわけではない。
|
586
|
+
# 情報から取得出来ない(記載がない)場合は無視する
|
587
|
+
#
|
588
|
+
def novel_length
|
589
|
+
info = @setting["info"] || {}
|
590
|
+
info["length"]
|
591
|
+
end
|
592
|
+
|
582
593
|
#
|
583
594
|
# データベース更新
|
584
595
|
#
|
@@ -599,6 +610,7 @@ class Downloader
|
|
599
610
|
"general_firstup" => info["general_firstup"],
|
600
611
|
"novelupdated_at" => get_novelupdated_at,
|
601
612
|
"general_lastup" => get_general_lastup,
|
613
|
+
"length" => novel_length,
|
602
614
|
}
|
603
615
|
if @@database[@id]
|
604
616
|
@@database[@id].merge!(data)
|
@@ -884,7 +896,11 @@ class Downloader
|
|
884
896
|
end
|
885
897
|
|
886
898
|
def title_to_filename(title)
|
887
|
-
Helper.replace_filename_special_chars(
|
899
|
+
Helper.replace_filename_special_chars(
|
900
|
+
Helper.truncate_path(
|
901
|
+
HTML.new(title).delete_ruby_tag
|
902
|
+
)
|
903
|
+
)
|
888
904
|
end
|
889
905
|
|
890
906
|
#
|
@@ -916,7 +932,7 @@ class Downloader
|
|
916
932
|
"href" => @setting["href"],
|
917
933
|
"chapter" => @setting["chapter"].to_s,
|
918
934
|
"subchapter" => @setting["subchapter"].to_s,
|
919
|
-
"subtitle" => @setting["subtitle"]
|
935
|
+
"subtitle" => slim_subtitle(@setting["subtitle"]),
|
920
936
|
"file_subtitle" => title_to_filename(@setting["subtitle"]),
|
921
937
|
"subdate" => subdate,
|
922
938
|
"subupdate" => @setting["subupdate"]
|
@@ -933,7 +949,7 @@ class Downloader
|
|
933
949
|
"index" => "1",
|
934
950
|
"href" => @setting.replace_group_values("href", "index" => "1"),
|
935
951
|
"chapter" => "",
|
936
|
-
"subtitle" => @setting["title"],
|
952
|
+
"subtitle" => slim_subtitle(@setting["title"]),
|
937
953
|
"file_subtitle" => title_to_filename(@setting["title"]),
|
938
954
|
"subdate" => info["general_firstup"],
|
939
955
|
"subupdate" => info["novelupdated_at"] || info["general_lastup"] || info["general_firstup"]
|
@@ -941,6 +957,11 @@ class Downloader
|
|
941
957
|
[subtitle]
|
942
958
|
end
|
943
959
|
|
960
|
+
def slim_subtitle(string)
|
961
|
+
# HTML.new(string).delete_ruby_tag.delete("\n")
|
962
|
+
HTML.new(string).delete_ruby_tag.delete("\n")
|
963
|
+
end
|
964
|
+
|
944
965
|
#
|
945
966
|
# 小説本文をまとめてダウンロードして保存
|
946
967
|
#
|
@@ -971,7 +992,7 @@ class Downloader
|
|
971
992
|
@stream.print "短編 "
|
972
993
|
end
|
973
994
|
printable_subtitle = @gurad_spoiler ? Helper.to_unprintable_words(subtitle) : subtitle
|
974
|
-
@stream.print "#{printable_subtitle} (#{i+1}/#{max})"
|
995
|
+
@stream.print "#{HTML.new(printable_subtitle).delete_ruby_tag} (#{i + 1}/#{max})"
|
975
996
|
|
976
997
|
section_file_name = "#{index} #{file_subtitle}.yaml"
|
977
998
|
section_file_relative_path = File.join(SECTION_SAVE_DIR_NAME, section_file_name)
|
data/lib/helper.rb
CHANGED
@@ -294,7 +294,7 @@ module Helper
|
|
294
294
|
when Time
|
295
295
|
date
|
296
296
|
when String
|
297
|
-
Time.parse(date.sub(/[\((].+?[\))]/, "").tr("年月日時分秒@;", "///::: :"))
|
297
|
+
Time.parse(date.sub(/[\((].+?[\))]/, "").tr("年月日時分秒@;", "///::: :")).getlocal
|
298
298
|
end
|
299
299
|
rescue ArgumentError
|
300
300
|
nil
|
@@ -325,7 +325,7 @@ module Helper
|
|
325
325
|
# 数字やスペース、句読点、感嘆符はそのままにする
|
326
326
|
#
|
327
327
|
def to_unprintable_words(string, mask = "●")
|
328
|
-
result = ""
|
328
|
+
result = "".dup
|
329
329
|
string.each_char do |char|
|
330
330
|
result += case char
|
331
331
|
when /[0-90-9 、。!?!?]/
|
@@ -354,6 +354,23 @@ module Helper
|
|
354
354
|
end
|
355
355
|
end
|
356
356
|
|
357
|
+
#
|
358
|
+
# src をERBとして読み込んでから dst に書き出す
|
359
|
+
#
|
360
|
+
def erb_copy(src, dst, _binding)
|
361
|
+
data = File.read(src, mode: "r:BOM|UTF-8")
|
362
|
+
result = ERB.new(data, nil, "-").result(_binding)
|
363
|
+
File.write(dst, result)
|
364
|
+
end
|
365
|
+
|
366
|
+
#
|
367
|
+
# カンマ付き数字列を数値に変換
|
368
|
+
#
|
369
|
+
def numeric_length(len)
|
370
|
+
return len unless len.is_a?(String)
|
371
|
+
len.delete(",").to_i
|
372
|
+
end
|
373
|
+
|
357
374
|
#
|
358
375
|
# 外部コマンド実行中の待機ループの処理を書けるクラス
|
359
376
|
#
|
data/lib/html.rb
CHANGED
data/lib/narou.rb
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
|
6
6
|
require "fileutils"
|
7
7
|
require "memoist"
|
8
|
+
require "active_support/core_ext/object/blank"
|
8
9
|
require_relative "helper"
|
9
10
|
require_relative "inventory"
|
10
11
|
if Helper.engine_jruby?
|
@@ -23,6 +24,7 @@ module Narou
|
|
23
24
|
EXIT_INTERRUPT = 126
|
24
25
|
EXIT_REQUEST_REBOOT = 125
|
25
26
|
MODIFIED_TAG = "modified"
|
27
|
+
LINE_HEIGHT_DEFAULT = 1.6 # 単位em
|
26
28
|
|
27
29
|
UPDATE_SORT_KEYS = {
|
28
30
|
"id" => "ID", "last_update" => "更新日", "title" => "タイトル", "author" => "作者名",
|
@@ -35,7 +37,7 @@ module Narou
|
|
35
37
|
@@is_web = false
|
36
38
|
|
37
39
|
def last_commit_year
|
38
|
-
|
40
|
+
2018
|
39
41
|
end
|
40
42
|
|
41
43
|
def get_root_dir
|
@@ -199,7 +201,15 @@ module Narou
|
|
199
201
|
#
|
200
202
|
def create_novel_filename(novel_data, ext = "")
|
201
203
|
filename_to_ncode = Inventory.load("local_setting")["convert.filename-to-ncode"]
|
202
|
-
|
204
|
+
novel_setting =
|
205
|
+
if novel_data["id"]
|
206
|
+
NovelSetting.load(novel_data["id"])
|
207
|
+
else
|
208
|
+
OpenStruct.new
|
209
|
+
end
|
210
|
+
if novel_setting.output_filename.present?
|
211
|
+
%!#{novel_setting.output_filename}#{ext}!
|
212
|
+
elsif filename_to_ncode
|
203
213
|
ncode, domain = novel_data["ncode"], novel_data["domain"]
|
204
214
|
if !ncode || !domain
|
205
215
|
id = novel_data["id"]
|
@@ -213,22 +223,39 @@ module Narou
|
|
213
223
|
serialized_domain = domain.to_s.gsub(".", "_")
|
214
224
|
%!#{serialized_domain}_#{ncode}#{ext}!
|
215
225
|
else
|
216
|
-
author
|
217
|
-
|
218
|
-
|
226
|
+
author = Helper.replace_filename_special_chars(
|
227
|
+
novel_setting.novel_author.presence || novel_data["author"],
|
228
|
+
true
|
229
|
+
)
|
230
|
+
title = Helper.replace_filename_special_chars(
|
231
|
+
novel_setting.novel_title.presence || novel_data["title"],
|
232
|
+
true
|
233
|
+
)
|
219
234
|
"[#{author}] #{title}#{ext}"
|
220
235
|
end
|
221
236
|
end
|
222
237
|
|
223
|
-
def
|
224
|
-
|
238
|
+
def get_mobi_paths(target)
|
239
|
+
get_ebook_file_paths(target, ".mobi")
|
225
240
|
end
|
226
241
|
|
227
|
-
def
|
242
|
+
def get_ebook_file_paths(target, ext)
|
228
243
|
data = Downloader.get_data_by_target(target)
|
229
244
|
return nil unless data
|
230
245
|
dir = Downloader.get_novel_data_dir_by_target(target)
|
231
|
-
|
246
|
+
fname = create_novel_filename(data, ext)
|
247
|
+
base = File.basename(fname, ext)
|
248
|
+
get_ebook_file_paths_from_components(dir, base, ext)
|
249
|
+
end
|
250
|
+
|
251
|
+
def get_ebook_file_paths_from_components(dir, base, ext)
|
252
|
+
paths = [File.join(dir, "#{base}#{ext}")]
|
253
|
+
index = 2
|
254
|
+
while File.exist?(path = File.join(dir, "#{base}_#{index}#{ext}"))
|
255
|
+
paths.push(path)
|
256
|
+
index += 1
|
257
|
+
end
|
258
|
+
paths
|
232
259
|
end
|
233
260
|
|
234
261
|
def get_misc_dir
|
@@ -262,7 +289,7 @@ module Narou
|
|
262
289
|
end
|
263
290
|
|
264
291
|
def get_theme
|
265
|
-
Inventory.load("local_setting")["theme"]
|
292
|
+
Inventory.load("local_setting")["webui.theme"]
|
266
293
|
end
|
267
294
|
|
268
295
|
def get_theme_dir(name = nil)
|
@@ -311,5 +338,10 @@ module Narou
|
|
311
338
|
end
|
312
339
|
memoize :kindlegen_path
|
313
340
|
|
341
|
+
def line_height
|
342
|
+
global_setting = Inventory.load("global_setting", :global)
|
343
|
+
global_setting["line-height"] || LINE_HEIGHT_DEFAULT
|
344
|
+
end
|
345
|
+
|
314
346
|
end
|
315
347
|
end
|
data/lib/novelconverter.rb
CHANGED
@@ -25,6 +25,16 @@ class NovelConverter
|
|
25
25
|
|
26
26
|
attr_reader :use_dakuten_font
|
27
27
|
|
28
|
+
def self.extensions_of_converted_files(device)
|
29
|
+
exts = [".txt"]
|
30
|
+
if device && device.kobo?
|
31
|
+
exts.push(device.ebook_file_ext)
|
32
|
+
else
|
33
|
+
exts.push(".epub", device.ebook_file_ext)
|
34
|
+
end
|
35
|
+
exts
|
36
|
+
end
|
37
|
+
|
28
38
|
#
|
29
39
|
# 指定の小説を整形・変換する
|
30
40
|
#
|
@@ -38,7 +48,7 @@ class NovelConverter
|
|
38
48
|
if setting
|
39
49
|
novel_converter = new(setting, options[:output_filename], options[:display_inspector])
|
40
50
|
return {
|
41
|
-
|
51
|
+
converted_txt_paths: novel_converter.convert_main,
|
42
52
|
use_dakuten_font: novel_converter.use_dakuten_font
|
43
53
|
}
|
44
54
|
end
|
@@ -69,22 +79,28 @@ class NovelConverter
|
|
69
79
|
text.force_encoding(options[:encoding]).encode!(Encoding::UTF_8)
|
70
80
|
end
|
71
81
|
{
|
72
|
-
|
82
|
+
converted_txt_paths: novel_converter.convert_main(text),
|
73
83
|
use_dakuten_font: novel_converter.use_dakuten_font
|
74
84
|
}
|
75
85
|
end
|
76
86
|
|
77
87
|
DAKUTEN_FROM = ["vertical_font_with_dakuten.css", "DMincho.ttf"]
|
78
88
|
DAKUTEN_TO = ["template/OPS/css_custom/vertical_font.css", "template/OPS/fonts/DMincho.ttf"]
|
89
|
+
DAKUTEN_ERB = [true, false]
|
79
90
|
|
80
91
|
def self.activate_dakuten_font_files
|
81
92
|
preset_dir = Narou.get_preset_dir
|
82
93
|
aozora_dir = File.dirname(Narou.get_aozoraepub3_path)
|
94
|
+
line_height = Narou.line_height
|
83
95
|
|
84
96
|
DAKUTEN_FROM.each_with_index do |name, i|
|
85
97
|
src = File.join(preset_dir, name)
|
86
98
|
dst = File.join(aozora_dir, DAKUTEN_TO[i])
|
87
|
-
|
99
|
+
if DAKUTEN_ERB[i]
|
100
|
+
Helper.erb_copy(src, dst, binding)
|
101
|
+
else
|
102
|
+
FileUtils.copy(src, dst)
|
103
|
+
end
|
88
104
|
end
|
89
105
|
end
|
90
106
|
|
@@ -92,8 +108,9 @@ class NovelConverter
|
|
92
108
|
preset_dir = Narou.get_preset_dir
|
93
109
|
aozora_dir = File.dirname(Narou.get_aozoraepub3_path)
|
94
110
|
path_normal_vertical_css = File.join(preset_dir, "vertical_font.css")
|
111
|
+
line_height = Narou.line_height
|
95
112
|
|
96
|
-
|
113
|
+
Helper.erb_copy(path_normal_vertical_css, File.join(aozora_dir, DAKUTEN_TO[0]), binding)
|
97
114
|
FileUtils.remove(File.join(aozora_dir, DAKUTEN_TO[1]))
|
98
115
|
end
|
99
116
|
|
@@ -305,7 +322,7 @@ class NovelConverter
|
|
305
322
|
else
|
306
323
|
epub_ext = ".epub"
|
307
324
|
end
|
308
|
-
epub_path = txt_path.sub(
|
325
|
+
epub_path = txt_path.sub(/\.txt$/, epub_ext)
|
309
326
|
|
310
327
|
if !device || !device.kindle? || options[:no_mobi]
|
311
328
|
puts File.basename(epub_path) + " を出力しました"
|
@@ -348,9 +365,10 @@ class NovelConverter
|
|
348
365
|
def initialize(setting, output_filename = nil, display_inspector = false, output_text_dir = nil)
|
349
366
|
@setting = setting
|
350
367
|
@novel_id = setting.id
|
351
|
-
@novel_author = setting.
|
352
|
-
@novel_title = setting.
|
368
|
+
@novel_author = setting.novel_author.empty? ? setting.author : setting.novel_author
|
369
|
+
@novel_title = setting.novel_title.empty? ? setting.title : setting.novel_title
|
353
370
|
@output_filename = (output_filename || setting.output_filename)
|
371
|
+
@output_filename = nil if @output_filename.empty?
|
354
372
|
@inspector = Inspector.new(@setting)
|
355
373
|
@illustration = Illustration.new(@setting, @inspector)
|
356
374
|
@display_inspector = display_inspector
|
@@ -368,32 +386,35 @@ class NovelConverter
|
|
368
386
|
initialize_event
|
369
387
|
|
370
388
|
if text
|
371
|
-
|
389
|
+
array_of_converted_text = convert_main_for_text(text)
|
372
390
|
else
|
373
|
-
|
391
|
+
array_of_converted_text = convert_main_for_novel
|
374
392
|
update_latest_convert_novel
|
375
393
|
end
|
394
|
+
inspect_novel(array_of_converted_text)
|
376
395
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
396
|
+
array_of_output_path = []
|
397
|
+
array_of_converted_text.each_with_index do |converted_text, i|
|
398
|
+
output_path = create_output_path(text, converted_text, i + 1)
|
399
|
+
File.write(output_path, converted_text)
|
400
|
+
array_of_output_path.push(output_path)
|
401
|
+
end
|
381
402
|
|
382
403
|
display_footer
|
383
404
|
|
384
|
-
|
405
|
+
array_of_output_path
|
385
406
|
end
|
386
407
|
|
387
408
|
def initialize_event
|
388
409
|
progressbar = nil
|
389
410
|
|
390
|
-
|
411
|
+
on(:"convert_main.init") do |subtitles|
|
391
412
|
progressbar = ProgressBar.new(subtitles.size)
|
392
413
|
end
|
393
414
|
on(:"convert_main.loop") do |i|
|
394
415
|
progressbar.output(i) if progressbar
|
395
416
|
end
|
396
|
-
|
417
|
+
on(:"convert_main.finish") do
|
397
418
|
progressbar.clear if progressbar
|
398
419
|
end
|
399
420
|
end
|
@@ -419,13 +440,15 @@ class NovelConverter
|
|
419
440
|
|
420
441
|
# is_hotentry を有効にすると、テンプレートで作成するテキストファイルに
|
421
442
|
# あらすじ、作品タイトル、本の読み終わり表示が付与されなくなる
|
422
|
-
def create_novel_text_by_template(sections, toc, is_hotentry = false)
|
443
|
+
def create_novel_text_by_template(sections, toc, is_hotentry = false, index = nil)
|
423
444
|
cover_chuki = create_cover_chuki
|
424
445
|
device = Narou.get_device
|
425
446
|
setting = @setting
|
426
|
-
toc["title"] = setting
|
427
|
-
toc["author"] = setting
|
428
|
-
|
447
|
+
toc["title"] = setting.novel_title unless setting.novel_title.empty?
|
448
|
+
toc["author"] = setting.novel_author unless setting.novel_author.empty?
|
449
|
+
processing_title = toc["title"]
|
450
|
+
processing_title += "_#{index}" if index
|
451
|
+
processed_title = decorate_title(processing_title)
|
429
452
|
tempalte_name = (device && device.ibunko? ? NOVEL_TEXT_TEMPLATE_NAME_FOR_IBUNKO : NOVEL_TEXT_TEMPLATE_NAME)
|
430
453
|
Template.get(tempalte_name, binding, 1.1)
|
431
454
|
end
|
@@ -543,7 +566,7 @@ class NovelConverter
|
|
543
566
|
#
|
544
567
|
# 最終的に出力するパスを生成
|
545
568
|
#
|
546
|
-
def create_output_path(is_text_file_mode, converted_text)
|
569
|
+
def create_output_path(is_text_file_mode, converted_text, index)
|
547
570
|
output_path = ""
|
548
571
|
if @output_filename
|
549
572
|
output_path = File.join(@setting.archive_path, File.basename(@output_filename))
|
@@ -560,9 +583,15 @@ class NovelConverter
|
|
560
583
|
end
|
561
584
|
filename = Narou.create_novel_filename(info)
|
562
585
|
output_path = File.join(@setting.archive_path, filename)
|
563
|
-
|
564
|
-
|
565
|
-
|
586
|
+
end
|
587
|
+
if output_path !~ /\.\w+$/
|
588
|
+
output_path += ".txt"
|
589
|
+
end
|
590
|
+
# change output_path to "basename_#{index}.ext" if index is greater than 1
|
591
|
+
if index > 1
|
592
|
+
ext = File.extname(output_path)
|
593
|
+
output_path = File.join(File.dirname(output_path), File.basename(output_path, ext))
|
594
|
+
output_path += "_#{index}#{ext}"
|
566
595
|
end
|
567
596
|
output_path
|
568
597
|
end
|
@@ -582,7 +611,7 @@ class NovelConverter
|
|
582
611
|
|
583
612
|
@use_dakuten_font = @converter.use_dakuten_font
|
584
613
|
|
585
|
-
converted_text
|
614
|
+
[converted_text]
|
586
615
|
end
|
587
616
|
|
588
617
|
#
|
@@ -590,24 +619,43 @@ class NovelConverter
|
|
590
619
|
#
|
591
620
|
# 引数 subtitles にデータを渡した場合はそれを直接使う
|
592
621
|
# is_hotentry を有効にすると出力されるテキストファイルにあらすじや作品タイトル等が含まれなくなる
|
622
|
+
# また、 is_hotentry を有効にすると分割も行われなくなる
|
593
623
|
#
|
594
624
|
def convert_main_for_novel(subtitles = nil, is_hotentry = false)
|
595
625
|
toc = Downloader.get_toc_data(@setting.archive_path)
|
596
626
|
unless subtitles
|
597
627
|
subtitles = cut_subtitles(toc["subtitles"])
|
598
628
|
end
|
599
|
-
@
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
629
|
+
if is_hotentry == false && @setting.slice_size > 0 && subtitles.length > @setting.slice_size
|
630
|
+
puts "#{@setting.slice_size}話ごとに分割して変換します"
|
631
|
+
array_of_subtitles = subtitles.each_slice(@setting.slice_size).to_a
|
632
|
+
else
|
633
|
+
array_of_subtitles = [subtitles]
|
634
|
+
end
|
635
|
+
array_of_converted_text = []
|
636
|
+
array_of_subtitles.each_with_index do |sliced_subtitles, index|
|
637
|
+
@converter.subtitles = sliced_subtitles
|
638
|
+
toc["story"] = @converter.convert(toc["story"], "story")
|
639
|
+
html = HTML.new
|
640
|
+
html.strip_decoration_tag = @setting.enable_strip_decoration_tag
|
641
|
+
site_setting = SiteSetting.find(toc["toc_url"])
|
642
|
+
html.set_illust_setting({ current_url: site_setting["illust_current_url"],
|
643
|
+
grep_pattern: site_setting["illust_grep_pattern"] })
|
644
|
+
|
645
|
+
sections = subtitles_to_sections(sliced_subtitles, html)
|
646
|
+
array_of_converted_text.push(
|
647
|
+
create_novel_text_by_template(
|
648
|
+
sections, toc, is_hotentry,
|
649
|
+
array_of_subtitles.length == 1 ? nil : index + 1
|
650
|
+
)
|
651
|
+
)
|
652
|
+
end
|
653
|
+
|
654
|
+
if is_hotentry
|
655
|
+
array_of_converted_text[0]
|
656
|
+
else
|
657
|
+
array_of_converted_text
|
658
|
+
end
|
611
659
|
end
|
612
660
|
|
613
661
|
def cut_subtitles(subtitles)
|
@@ -668,8 +716,9 @@ class NovelConverter
|
|
668
716
|
{ "title" => title, "author" => author }
|
669
717
|
end
|
670
718
|
|
671
|
-
def inspect_novel(
|
719
|
+
def inspect_novel(array_of_text)
|
672
720
|
if @setting.enable_inspect
|
721
|
+
text = array_of_text.flatten
|
673
722
|
@inspector.inspect_end_touten_conditions(text) # 行末読点の現在状況を調査する
|
674
723
|
@inspector.countup_return_in_brackets(text) # カギ括弧内の改行状況を調査する
|
675
724
|
end
|