narou 1.1.0.rc1 → 1.1.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

data/lib/converterbase.rb CHANGED
@@ -41,6 +41,7 @@ class ConverterBase
41
41
  @english_sentences = []
42
42
  @url_list = []
43
43
  @illust_chuki_list = []
44
+ @in_author_comment_block = nil
44
45
  end
45
46
 
46
47
  def outputs(data = "", force = false)
@@ -59,7 +60,21 @@ class ConverterBase
59
60
  # すべての行の行末空白を削除
60
61
  #
61
62
  def rstrip_all_lines(data)
62
- data.gsub(/^[  \t]+$/m, "")
63
+ data.gsub(/[  \t]+$/m, "")
64
+ end
65
+
66
+ #
67
+ # 数字の変換
68
+ #
69
+ def convert_numbers(data)
70
+ # 小数点を・に
71
+ data.gsub!(/([\d0-9#{KANJI_NUM}]+?)[\..]([\d0-9#{KANJI_NUM}]+?)/, "\\1・\\2")
72
+ if @setting.enable_convert_num_to_kanji
73
+ num_to_kanji(data)
74
+ else
75
+ hankaku_num_to_zenkaku_num(data)
76
+ end
77
+ data
63
78
  end
64
79
 
65
80
  #
@@ -68,8 +83,6 @@ class ConverterBase
68
83
  # カンマ区切りの数字はアラビア数字のままにしておく
69
84
  #
70
85
  def num_to_kanji(data)
71
- data.gsub!(/([\d0-9#{KANJI_NUM}]+?)[\..]([\d0-9#{KANJI_NUM}]+?)/, "\\1・\\2")
72
- return unless @setting.enable_convert_num_to_kanji
73
86
  data.gsub!(/[\d0-9,,]+/) do |match|
74
87
  if match =~ /[,,]/
75
88
  match
@@ -77,6 +90,7 @@ class ConverterBase
77
90
  zenkaku_num_to_kanji(match.tr("0-9", KANJI_NUM))
78
91
  end
79
92
  end
93
+ data
80
94
  end
81
95
 
82
96
  #
@@ -86,16 +100,26 @@ class ConverterBase
86
100
  str.tr("0-9", KANJI_NUM)
87
101
  end
88
102
 
89
- KANJI_NUM_UNITS = %w(万 億 兆 京).unshift("")
103
+ KANJI_NUM_UNITS = %w(万 億 兆 京).unshift("")
90
104
  KANJI_KURAI = %w(十 百 千).unshift("")
105
+ KANJI_NUM_UNITS_DIGIT = {
106
+ "十" => 1, "百" => 2, "千" => 3, "万" => 4, "億" => 8, "兆" => 12, "京" => 16
107
+ }
91
108
  #
92
109
  # 漢数字を単位を使った表現に変換
93
110
  #
111
+ # 800万1000 といったような表現は、内部一度で 8001000 に変換する。
112
+ # lower_digit_zero はこの最後の 000 に適用される
113
+ #
94
114
  def convert_kanji_num_with_unit(data, lower_digit_zero = 0)
95
- data.gsub!(/([#{KANJI_NUM}]+)([十百千万億兆京垓]?)/) do |match|
96
- next match unless $2.empty?
97
- m1 = $1
98
- if m1 =~ /^[一二三四五六七八九]+〇{#{lower_digit_zero},}$/
115
+ #data.gsub!(/([#{KANJI_NUM}]+)([十百千万億兆京]?)/) do |match|
116
+ data.gsub!(/([#{KANJI_NUM}十百千万億兆京]+)/) do |match|
117
+ total = 0
118
+ $1.scan(/([#{KANJI_NUM}]+)([十百千万億兆京]*)/) do |num, units|
119
+ total += (num.tr(KANJI_NUM, "0-9") + units.each_char.map { |c| "0" * KANJI_NUM_UNITS_DIGIT[c] }.join).to_i
120
+ end
121
+ m1 = total.to_s.tr("0-9", KANJI_NUM)
122
+ if m1 =~ /〇{#{lower_digit_zero},}$/
99
123
  digits = m1.reverse.scan(/.{1,4}/).map(&:reverse).reverse # 下の桁から4桁ずつ区切った配列を作成
100
124
  keta = digits.count - 1
101
125
  digits.map.with_index { |nums, keta_i|
@@ -162,9 +186,7 @@ class ConverterBase
162
186
  rescue ArgumentError
163
187
  match
164
188
  else
165
- buf = date.strftime(@setting.date_format)
166
- num_to_kanji(buf)
167
- buf
189
+ convert_numbers(date.strftime(@setting.date_format))
168
190
  end
169
191
  end
170
192
  else
@@ -174,7 +196,7 @@ class ConverterBase
174
196
  end
175
197
 
176
198
  #
177
- # 特定の記号の直後は全角スペースを挿入する
199
+ # 特定の記号の直後は全角アキを挿入する
178
200
  #
179
201
  def insert_separate_space(data)
180
202
  data.gsub!(/([!?!?]+)([^!?!?])/) do
@@ -332,16 +354,14 @@ class ConverterBase
332
354
  #
333
355
  def rebuild_english_sentences(data)
334
356
  @english_sentences.each_with_index do |sentence, id|
335
- buf = id.to_s
336
- num_to_kanji(buf)
337
- data.sub!("[#英文=#{buf}]", sentence)
357
+ data.sub!("[#英文=#{convert_numbers(id.to_s)}]", sentence)
338
358
  end
339
359
  end
340
360
 
341
361
  #
342
362
  # コメントブロックを検出する
343
363
  #
344
- # コメントブロックの定義は - のみがが50回以上連続された行に囲まれている間
364
+ # コメントブロックの定義は - のみが50回以上連続された行に囲まれている間
345
365
  #
346
366
  def comments_block?(line)
347
367
  if line =~ /^-{50,}$/
@@ -364,17 +384,27 @@ class ConverterBase
364
384
  def zenkaku_num_to_hankaku_num(num)
365
385
  num.tr("0-9#{KANJI_NUM}", "0-90-9")
366
386
  end
387
+
388
+ #
389
+ # 3桁以上の半角数字を全角アラビア数字に
390
+ #
391
+ def hankaku_num_to_zenkaku_num(data)
392
+ data.gsub!(/\d{3,}/) do |num|
393
+ num.tr("0-9", "0-9")
394
+ end
395
+ data
396
+ end
367
397
 
368
398
  HALF_INDENT_TARGET = /^[  \t]*([「『((【〈《≪])/
369
399
  FULL_INDENT_TARGET = /^[  \t]*(――)/
370
400
  #
371
- # 半字下げ
401
+ # 行頭鍵カッコ(等)に二分アキを追加する
372
402
  #
373
- # 「や(などの前にカスタム注記([#半字下げ])を追加し、半文字分字下げする
403
+ # 「や(などの前にカスタム注記([#二分アキ])を追加し、半文字分字下げする(二分アキ)。
374
404
  # kindle paperwhite で鍵括弧のインデントがおかしいことへの対応
375
405
  #
376
- def hanji_sage(data)
377
- data.gsub!(HALF_INDENT_TARGET, "[#半字下げ]\\1") if @setting.enable_hanji_sage
406
+ def half_indent_bracket(data)
407
+ data.gsub!(HALF_INDENT_TARGET, "[#二分アキ]\\1") if @setting.enable_half_indent_bracket
378
408
  end
379
409
 
380
410
  #
@@ -444,7 +474,7 @@ class ConverterBase
444
474
  #
445
475
  # 改ページある?
446
476
  #
447
- def kai_page?(line)
477
+ def page_break?(line)
448
478
  line =~ /[#改ページ]/
449
479
  end
450
480
 
@@ -452,8 +482,8 @@ class ConverterBase
452
482
  # 前書き・後書きの検出及び処理 ==============================
453
483
  #
454
484
 
455
- AUTHOR_INTRODUCTION_SPLITTER = /^[\**]{44}$/
456
- AUTHOR_POSTSCRIPT_SPLITTER = /^[\**]{48}$/
485
+ AUTHOR_INTRODUCTION_SPLITTER = /^ *[\**]{44}$/
486
+ AUTHOR_POSTSCRIPT_SPLITTER = /^ *[\**]{48}$/
457
487
  AUTHOR_COMMENT_CHUKI = {
458
488
  introduction: {
459
489
  open: "[#ここから前書き]", close: "[#ここで前書き終わり]"
@@ -465,17 +495,7 @@ class ConverterBase
465
495
 
466
496
  def process_author_comment(line)
467
497
  if @setting.enable_author_comments
468
- unless @in_author_comment_block
469
- if inclusion_author_comment_block?(line)
470
- # outputs を使うと改ページより前に注記が入ってしまうため、
471
- # delay_outputs を使って出力を line 出力の後に遅らせる
472
- delay_outputs(AUTHOR_COMMENT_CHUKI[@in_author_comment_block][:open])
473
- if @in_author_comment_block == :postscript
474
- @request_skip_output_line = true
475
- line.clear
476
- end
477
- end
478
- else
498
+ if @in_author_comment_block
479
499
  if leave_author_comment_block?(line)
480
500
  outputs(AUTHOR_COMMENT_CHUKI[@in_author_comment_block][:close])
481
501
  if @in_author_comment_block == :introduction
@@ -489,6 +509,16 @@ class ConverterBase
489
509
  process_author_comment(line)
490
510
  end
491
511
  end
512
+ else
513
+ if inclusion_author_comment_block?(line)
514
+ # outputs を使うと改ページより前に注記が入ってしまうため、
515
+ # delay_outputs を使って出力を line 出力の後に遅らせる
516
+ delay_outputs(AUTHOR_COMMENT_CHUKI[@in_author_comment_block][:open])
517
+ if @in_author_comment_block == :postscript
518
+ @request_skip_output_line = true
519
+ line.clear
520
+ end
521
+ end
492
522
  end
493
523
  end
494
524
  end
@@ -498,7 +528,7 @@ class ConverterBase
498
528
  pos = @read_fp.pos
499
529
  result = false
500
530
  @read_fp.each do |line|
501
- break if kai_page?(line)
531
+ break if page_break?(line)
502
532
  if line =~ AUTHOR_INTRODUCTION_SPLITTER
503
533
  result = true
504
534
  break
@@ -510,7 +540,7 @@ class ConverterBase
510
540
 
511
541
  def inclusion_author_comment_block?(line)
512
542
  result = false
513
- if kai_page?(line)
543
+ if page_break?(line)
514
544
  if find_introduction?
515
545
  @in_author_comment_block = :introduction
516
546
  result = true
@@ -530,7 +560,7 @@ class ConverterBase
530
560
  result = true
531
561
  end
532
562
  when :postscript
533
- if kai_page?(line)
563
+ if page_break?(line)
534
564
  result = true
535
565
  end
536
566
  end
@@ -686,7 +716,7 @@ class ConverterBase
686
716
  # 全角版 String#rstrip!
687
717
  #
688
718
  def zenkaku_rstrip(line)
689
- line.gsub!(/[ \s]*$/, "")
719
+ line.gsub!(/[ \s]+\z/, "")
690
720
  end
691
721
 
692
722
  #
@@ -701,10 +731,8 @@ class ConverterBase
701
731
 
702
732
  def rebuild_url(data)
703
733
  @url_list.each_with_index do |url, id|
704
- buf = id.to_s
705
- num_to_kanji(buf)
706
- data.sub!("[#URL=#{buf}]", "[#リンク開始]#{url}[#リンクアドレスここまで]#{url}[#リンク終了]")
707
-
734
+ data.sub!("[#URL=#{convert_numbers(id.to_s)}]",
735
+ "[#リンク開始]#{url}[#リンクアドレスここまで]#{url}[#リンク終了]")
708
736
  end
709
737
  end
710
738
 
@@ -727,9 +755,7 @@ class ConverterBase
727
755
 
728
756
  def rebuild_illust(data)
729
757
  @illust_chuki_list.each_with_index do |chuki, id|
730
- buf = id.to_s
731
- num_to_kanji(buf)
732
- data.sub!("[#挿絵=#{buf}]", chuki)
758
+ data.sub!("[#挿絵=#{convert_numbers(id.to_s)}]", chuki)
733
759
  end
734
760
  end
735
761
 
@@ -738,7 +764,7 @@ class ConverterBase
738
764
  #
739
765
  def enchant_midashi(data)
740
766
  def midashi(str)
741
- midashi_title = str.gsub("[#半字下げ]", "")
767
+ midashi_title = str.gsub("[#半字下げ]", "").gsub(/^[ \s]+/, "").gsub(/[ \s]+$/, "")
742
768
  @inspector.subtitle = midashi_title
743
769
  "[#3字下げ][#ここから中見出し]#{midashi_title}[#ここで中見出し終わり]"
744
770
  end
@@ -801,7 +827,7 @@ class ConverterBase
801
827
  replace_narou_tag(data)
802
828
  convert_rome_numeric(data)
803
829
  alphabet_to_zenkaku(data, @setting.enable_alphabet_force_zenkaku)
804
- num_to_kanji(data)
830
+ convert_numbers(data)
805
831
  exception_reconvert_kanji_to_num(data)
806
832
  if @setting.enable_kanji_num_with_units
807
833
  convert_kanji_num_with_unit(data, @setting.kanji_num_with_units_lower_digit_zero)
@@ -810,7 +836,7 @@ class ConverterBase
810
836
  convert_special_characters(data)
811
837
  convert_fraction_and_date(data)
812
838
  if text_type == "body" || text_type == "textfile"
813
- hanji_sage(data)
839
+ half_indent_bracket(data)
814
840
  auto_indent(data)
815
841
  end
816
842
  convert_dakuten_char_to_font(data)
@@ -861,23 +887,21 @@ class ConverterBase
861
887
  progressbar.output(i) if text_type == "textfile"
862
888
  @request_skip_output_line = false
863
889
  zenkaku_rstrip(line)
864
- if !comments_block?(line)
865
- if @request_insert_blank_next_line
866
- outputs unless blank_line?(line)
867
- @request_insert_blank_next_line = false
868
- end
869
- process_author_comment(line) if text_type == "textfile"
870
- insert_blank_line_to_border_symbol(line)
871
- force_indent_special_chapter(line)
872
-
873
- outputs(line)
874
- unless @delay_outputs_buffer.empty?
875
- @write_fp.write(@delay_outputs_buffer)
876
- @before_line = @delay_outputs_buffer
877
- @delay_outputs_buffer = ""
878
- else
879
- @before_line = line
880
- end
890
+ if @request_insert_blank_next_line
891
+ outputs unless blank_line?(line)
892
+ @request_insert_blank_next_line = false
893
+ end
894
+ process_author_comment(line) if text_type == "textfile"
895
+ insert_blank_line_to_border_symbol(line)
896
+ force_indent_special_chapter(line)
897
+
898
+ outputs(line)
899
+ unless @delay_outputs_buffer.empty?
900
+ @write_fp.write(@delay_outputs_buffer)
901
+ @before_line = @delay_outputs_buffer
902
+ @delay_outputs_buffer = ""
903
+ else
904
+ @before_line = line
881
905
  end
882
906
  end
883
907
  author_comment_force_close if text_type == "textfile"
data/lib/downloader.rb CHANGED
@@ -56,8 +56,8 @@ class Downloader
56
56
  return false
57
57
  end
58
58
  end
59
- downloader = Downloader.new(setting)
60
- result = downloader.start_download(force)
59
+ downloader = Downloader.new(setting, force)
60
+ result = downloader.start_download
61
61
  setting.clear
62
62
  result
63
63
  end
@@ -267,29 +267,53 @@ class Downloader
267
267
  #
268
268
  # コンストラクタ
269
269
  #
270
- def initialize(site_setting)
270
+ def initialize(site_setting, force = false)
271
271
  @setting = site_setting
272
+ @force = force
273
+ @cache_dir = nil
272
274
  @id = @@database.get_id("toc_url", @setting["toc_url"]) || @@database.get_new_id
273
275
  end
274
276
 
277
+ #
278
+ # 18歳以上か確認する
279
+ #
280
+ def confirm_over18?
281
+ global_setting = GlobalSetting.get["global_setting"]
282
+ if global_setting.include?("over18")
283
+ return global_setting["over18"]
284
+ end
285
+ if Helper.confirm("年齢認証:あなたは18歳以上ですか")
286
+ global_setting["over18"] = true
287
+ GlobalSetting.get.save_settings
288
+ return true
289
+ else
290
+ return false
291
+ end
292
+ end
293
+
275
294
  #
276
295
  # ダウンロード処理本体
277
296
  #
278
- # force が true なら全話強制ダウンロード
279
297
  # 返り値:ダウンロードしたものが1話でもあったかどうか(Boolean)
280
298
  #
281
- def start_download(force = false)
299
+ def start_download
282
300
  latest_toc = get_latest_table_of_contents
283
301
  unless latest_toc
284
302
  warn "目次データが取得出来ませんでした"
285
303
  exit 1
286
304
  end
305
+ if @setting["confirm_over18"]
306
+ unless confirm_over18?
307
+ puts "18歳以上のみ閲覧出来る小説です。ダウンロードを中止しました"
308
+ return false
309
+ end
310
+ end
287
311
  old_toc = load_novel_data(TOC_FILE_NAME)
288
312
  unless old_toc
289
313
  init_novel_dir
290
314
  old_toc = {}
291
315
  end
292
- if force
316
+ if @force
293
317
  update_subtitles = latest_toc["subtitles"]
294
318
  else
295
319
  update_subtitles = update_check(old_toc["subtitles"], latest_toc["subtitles"])
@@ -299,7 +323,7 @@ class Downloader
299
323
  begin
300
324
  sections_download_and_save(update_subtitles)
301
325
  rescue Interrupt
302
- FileUtils.remove_entry_secure(@cache_dir) if @cache_dir
326
+ remove_cache_dir
303
327
  puts "ダウンロードを中断しました"
304
328
  exit 1
305
329
  end
@@ -322,6 +346,13 @@ class Downloader
322
346
  cache_dir
323
347
  end
324
348
 
349
+ #
350
+ # 差分用キャッシュ保存ディレクトリを削除
351
+ #
352
+ def remove_cache_dir
353
+ FileUtils.remove_entry_secure(@cache_dir) if @cache_dir
354
+ end
355
+
325
356
  #
326
357
  # データベース更新
327
358
  #
@@ -433,6 +464,7 @@ class Downloader
433
464
  puts "ID:#{@id} #{@title} のDL開始"
434
465
  interval_sleep_time = LocalSetting.get["local_setting"]["download.interval"] || 0
435
466
  interval_sleep_time = 0 if interval_sleep_time < 0
467
+ save_least_one = false
436
468
  subtitles.each_with_index do |subtitle_info, i|
437
469
  if @setting["domain"] =~ /syosetu.com/ && (i % 10 == 0 && i >= 10)
438
470
  # MEMO:
@@ -444,14 +476,32 @@ class Downloader
444
476
  sleep(interval_sleep_time) if i > 0
445
477
  end
446
478
  index, subtitle, file_subtitle = %w(index subtitle file_subtitle).map {|k| subtitle_info[k] }
447
- puts "第#{index}部分 #{subtitle} (#{i+1}/#{max})"
479
+ print "第#{index}部分 #{subtitle} (#{i+1}/#{max})"
448
480
  section_element = a_section_download(subtitle_info)
449
481
  info = subtitle_info.dup
450
482
  info["element"] = section_element
451
483
  section_file_name = "#{index} #{file_subtitle}.yaml"
452
484
  section_file_path = File.join(SECTION_SAVE_DIR_NAME, section_file_name)
453
- move_to_cache_dir(section_file_path)
454
- save_novel_data(section_file_path, info)
485
+ if different_section?(section_file_path, info)
486
+ print " (更新あり)" if @force
487
+ move_to_cache_dir(section_file_path)
488
+ save_novel_data(section_file_path, info)
489
+ save_least_one = true
490
+ end
491
+ puts
492
+ end
493
+ remove_cache_dir unless save_least_one
494
+ end
495
+
496
+ #
497
+ # すでに保存されている内容とDLした内容が違うかどうか
498
+ #
499
+ def different_section?(relative_path, subtitle_info)
500
+ path = File.join(get_novel_data_dir, relative_path)
501
+ if File.exists?(path)
502
+ return YAML.load_file(path) != subtitle_info
503
+ else
504
+ return true
455
505
  end
456
506
  end
457
507