narou 3.8.2 → 3.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e639fd7c7a2808c632f85812866ca9614978e152f177eedc69c8559f515af525
4
- data.tar.gz: 8b406a232555c9e0625ac261183ab1017ebef6a50f6602ed9d694fce29db1307
3
+ metadata.gz: 1a9fafd6af1ebb3b07da36ae193a2de21a750b00797ef805f6d3ade778e65dff
4
+ data.tar.gz: 3e260f769599b31e1e52290c78842be937b6dc34b6a002ca73dd30f351fe079c
5
5
  SHA512:
6
- metadata.gz: 9ec435fd5f1cd7b5f9c28a9a8e461450102e3083ebbbe04f4bcdc4cffcff1e5a90ef352a72c2f7c2d4e70f1bad1569403fc1c65309bee9e4e6137292ec19aaa3
7
- data.tar.gz: 305f538e204dcdb0bb2ae02d5c8f770f40fd94e33913ab6b436de6db8d55f4ecb03e2cf8e22b03fcb3d14300031ec994e4ea4b094d7762a59dbeb0961f30055b
6
+ metadata.gz: 9cd647d5a413bb188640688ff07fcd82f21604e3aca83faebaf3e3bb8f39db91a517c13483cddc69ffef0f674570835273b6a9a57487565d6ab4fe61c2e8053c
7
+ data.tar.gz: a568312cc5fd8349789c1061a227bd39e31db63769ad75011f8d0bcd36fe95bb6cd0e57749930f8d0d7cf4572e862c2a51499235dd04b7590c6fd04af0259039
data/ChangeLog.md CHANGED
@@ -1,6 +1,15 @@
1
1
  更新履歴 - ChangeLog
2
2
  ====================
3
3
 
4
+ 3.9.0: 2024-04-02
5
+ -----------------
6
+ #### 修正内容
7
+ - 小説家になろうの目次修正に対応
8
+ - カクヨムの目次修正に対応
9
+
10
+ thanks for contributors: @topstone, @rogenobl, @happynow, @etg-lt
11
+
12
+
4
13
  3.8.2: 2022/09/10
5
14
  -----------------
6
15
  #### 修正内容
data/README.md CHANGED
@@ -34,10 +34,13 @@ Narou.rb - 小説家になろうのダウンローダ&縦書き整形&管理
34
34
  更新履歴 - ChangeLog
35
35
  --------------------
36
36
 
37
- 3.8.2: 2022/09/10
37
+ 3.9.0: 2024-04-02
38
38
  -----------------
39
39
  #### 修正内容
40
- - フォルダが存在しない場合に自動で作成する様に修正
40
+ - 小説家になろうの目次修正に対応
41
+ - カクヨムの目次修正に対応
42
+
43
+ thanks for contributors: @topstone, @rogenobl, @happynow, @etg-lt
41
44
 
42
45
  ----
43
46
 
data/commitversion CHANGED
@@ -1 +1 @@
1
- 4660df5
1
+ 89566d7
data/lib/command/diff.rb CHANGED
@@ -70,7 +70,7 @@ module Command
70
70
  # 引数の中の -数字 オプション(-n 数字の省略形)を -n 数字 に変換する
71
71
  def short_number_option_parse(argv)
72
72
  argv.map! { |arg|
73
- if arg =~ /^-(\d+)$/
73
+ if arg.to_s =~ /^-(\d+)$/
74
74
  ["-n", $1.to_s]
75
75
  else
76
76
  arg
@@ -250,7 +250,7 @@ module Command
250
250
  list: []
251
251
  }
252
252
  cache_list = get_sorted_cache_list(id)
253
- return list if cache_list.empty?
253
+ return list if cache_list.blank?
254
254
  cache_list.each.with_index(1) do |cache_path, i|
255
255
  objects = []
256
256
  version_string = File.basename(cache_path)
@@ -534,6 +534,10 @@ module Command
534
534
  "エラーは出ないが読めなくなる)",
535
535
  tab: :detail
536
536
  },
537
+ "user-agent" => {
538
+ type: :string, help: "User-Agent 設定\n未指定時 Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
539
+ tab: :detail
540
+ },
537
541
  "webui.theme" => {
538
542
  type: :select, help: "WEB UI 用テーマ選択",
539
543
  invisible: true,
data/lib/command/tag.rb CHANGED
@@ -12,7 +12,7 @@ module Command
12
12
  class Tag < CommandBase
13
13
  COLORS = %w(green yellow blue magenta cyan red white)
14
14
  # 禁止文字
15
- BAN_CHAR = /[:;"'><$@&^\\\|%'\/`]/
15
+ BAN_CHAR = /[:;"'><$@&^\\\|%\/`]/
16
16
  # 禁止ワード
17
17
  BAN_WORD = %w(hotentry)
18
18
 
@@ -70,7 +70,7 @@ module Command
70
70
  "general_lastup" => downloader.get_general_lastup,
71
71
  "length" => downloader.novel_length
72
72
  }
73
- rescue OpenURI::HTTPError, Errno::ECONNRESET, Errno::ETIMEDOUT, Net::OpenTimeout
73
+ rescue OpenURI::HTTPError, Errno::ECONNRESET, Errno::ETIMEDOUT, Net::OpenTimeout, IO::TimeoutError
74
74
  next
75
75
  end
76
76
  data = @database[id]
data/lib/converterbase.rb CHANGED
@@ -15,7 +15,7 @@ require_relative "inspector"
15
15
 
16
16
  class ConverterBase
17
17
  KANJI_NUM = "〇一二三四五六七八九"
18
- ENGLISH_SENTENCES_CHARACTERS = /[\w.,!?'" &:;_-]+/
18
+ ENGLISH_SENTENCES_CHARACTERS = /[\w.,!?'" &:;-]+/
19
19
  ENGLISH_SENTENCES_MIN_LENGTH = 8 # この文字数以上アルファベットが続くと半角のまま
20
20
 
21
21
  attr_reader :use_dakuten_font
@@ -939,8 +939,8 @@ class ConverterBase
939
939
  "#{m1[0...-1]}#{openclose_symbols[0]}#{m2}#{openclose_symbols[1]}"
940
940
  when is_sesame?(m1, m2, last_char)
941
941
  sesame(m1)
942
- when m1.include?("")
943
- "#{m1.sub(/|([^|]*)$/, "[#ルビ用縦線]\\1")}《#{ruby_youon_to_big(m2)}》"
942
+ when m1 =~ /^(.*)([^|≪≫()《》]+)$/
943
+ "#{$1}[#ルビ用縦線]#{$2}《#{ruby_youon_to_big(m2)}》"
944
944
  when object_of_ruby?(last_char)
945
945
  if openclose_symbols[0] == "≪" && m2 !~ /^#{AUTO_RUBY_CHARACTERS}$/
946
946
  # 《 》タイプのルビであっても、|が存在しない場合の自動ルビ化対象はひらがな等だけである
data/lib/downloader.rb CHANGED
@@ -11,6 +11,7 @@ require_relative "narou"
11
11
  require_relative "helper"
12
12
  require_relative "sitesetting"
13
13
  require_relative "template"
14
+ require_relative "progressbar"
14
15
  require_relative "database"
15
16
  require_relative "inventory"
16
17
  require_relative "eventable"
@@ -40,6 +41,7 @@ class Downloader
40
41
 
41
42
  class InvalidTarget < StandardError; end
42
43
  class SuspendDownload < StandardError; end
44
+ class IO::TimeoutError; end # for 3.1 or earlier
43
45
 
44
46
  def initialize(target, options = {})
45
47
  id = Downloader.get_id_by_target(target)
@@ -724,6 +726,7 @@ class Downloader
724
726
  toc_source = ""
725
727
  cookie = @setting["cookie"] || ""
726
728
  open_uri_options = make_open_uri_options("Cookie" => cookie, allow_redirections: :safe)
729
+ sleep_for_download
727
730
  begin
728
731
  URI.open(toc_url, open_uri_options) do |toc_fp|
729
732
  if toc_fp.base_uri.to_s != toc_url
@@ -783,7 +786,7 @@ class Downloader
783
786
  @setting["title"] = get_title
784
787
  if series_novel?
785
788
  # 連載小説
786
- subtitles = get_subtitles(toc_source, old_toc)
789
+ subtitles = get_subtitles_multipage(toc_source, old_toc)
787
790
  else
788
791
  # 短編小説
789
792
  subtitles = create_short_story_subtitles(info)
@@ -798,7 +801,7 @@ class Downloader
798
801
  "subtitles" => subtitles
799
802
  }
800
803
  toc_objects
801
- rescue OpenURI::HTTPError, Errno::ECONNRESET, Errno::ETIMEDOUT, Net::OpenTimeout => e
804
+ rescue OpenURI::HTTPError, Errno::ECONNRESET, Errno::ETIMEDOUT, Net::OpenTimeout, IO::TimeoutError => e
802
805
  raise if through_error # エラー処理はしなくていいからそのまま例外を受け取りたい時用
803
806
  if e.message.include?("404")
804
807
  @stream.error "小説が削除されているか非公開な可能性があります"
@@ -813,6 +816,40 @@ class Downloader
813
816
  false
814
817
  end
815
818
 
819
+ def get_subtitles_multipage(toc_source, old_toc)
820
+ subtitles = []
821
+ # 元々のURLを保存する
822
+ toc_url_orig = @setting["toc_url"]
823
+ # 全ページ数を得る
824
+ @setting.multi_match(toc_source, "toc_page_max")
825
+ toc_page_max = @setting["toc_page_max"].to_i
826
+ # toc_page_maxが設定されていない、正規表現にマッチしない場合などでも最低限は1にする
827
+ toc_page_max = 1 unless toc_page_max > 0
828
+ # 5ページ以上でプログレスバーを表示する
829
+ progressbar = nil
830
+ if toc_page_max >= 5
831
+ @stream.puts "#{@setting["title"]} の目次ページを取得中..."
832
+ progressbar = ProgressBar.new(toc_page_max, io: @stream)
833
+ end
834
+ ret = toc_page_max.times do |i|
835
+ progressbar&.output(i + 1)
836
+ subtitles.concat(get_subtitles(toc_source, old_toc))
837
+ break unless @setting.multi_match(toc_source, "next_toc")
838
+ # 得られたURLをセットしてページ内容を取得する
839
+ @setting["toc_url"] = @setting["next_url"]
840
+ toc_source = get_toc_source
841
+ end
842
+ progressbar&.clear
843
+ if ret
844
+ # 通常ならbreakでループを抜けるはず
845
+ # breakでループを抜けなかったら例外を出す
846
+ raise "目次ページが多すぎます"
847
+ end
848
+ subtitles
849
+ ensure
850
+ @setting["toc_url"] = toc_url_orig
851
+ end
852
+
816
853
  def __search_index_in_subtitles(subtitles, index)
817
854
  subtitles.index { |item|
818
855
  item["index"] == index
@@ -1137,7 +1174,7 @@ class Downloader
1137
1174
  URI.open(url, "r:#{@setting["encoding"]}", open_uri_options) do |fp|
1138
1175
  raw = Helper.pretreatment_source(fp.read, @setting["encoding"])
1139
1176
  end
1140
- rescue OpenURI::HTTPError, Errno::ECONNRESET, Errno::ETIMEDOUT, Net::OpenTimeout => e
1177
+ rescue OpenURI::HTTPError, Errno::ECONNRESET, Errno::ETIMEDOUT, Net::OpenTimeout, IO::TimeoutError => e
1141
1178
  case e.message
1142
1179
  when /^503/
1143
1180
  # 503 はアクセス規制やメンテ等でリトライしてもほぼ意味がないことが多いため一度で諦める
data/lib/extension.rb CHANGED
@@ -6,13 +6,16 @@
6
6
 
7
7
  require "open-uri"
8
8
  require "openssl"
9
+ require_relative "inventory"
9
10
 
10
11
  # open-uri で http → https へのリダイレクトを有効にする
11
12
  require "open_uri_redirections"
12
13
 
13
14
  # open-uri に渡すオプションを生成(必要に応じて extensions/*.rb でオーバーライドする)
14
15
  def make_open_uri_options(add)
16
+ ua = Inventory.load("local_setting")["user-agent"] || "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
15
17
  add.merge(ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
18
+ add.merge("User-Agent" => ua)
16
19
  end
17
20
 
18
21
  #
data/lib/helper.rb CHANGED
@@ -102,7 +102,7 @@ module Helper
102
102
  end
103
103
 
104
104
  def replace_filename_special_chars(str, invalid_replace = false)
105
- result = str.tr("/:*?\"<>|.`", "/:*?”〈〉|.`").gsub("\\", "¥").gsub("\t", "").gsub("\n", "")
105
+ result = str.tr("/:*?\"<>[]{}|.`", "/:*?”〈〉[]{}|.`").gsub("\\", "¥").gsub("\t", "").gsub("\n", "")
106
106
  if Inventory.load("local_setting")["normalize-filename"]
107
107
  begin
108
108
  result.unicode_normalize!
data/lib/narou.rb CHANGED
@@ -44,7 +44,7 @@ module Narou
44
44
  @@is_web = false
45
45
 
46
46
  def last_commit_year
47
- 2022
47
+ 2024
48
48
  end
49
49
 
50
50
  def root_dir
@@ -100,6 +100,7 @@ class NovelConverter
100
100
  if DAKUTEN_ERB[i]
101
101
  Helper.erb_copy(src, dst, binding)
102
102
  else
103
+ FileUtils.mkdir_p(File.dirname(dst))
103
104
  FileUtils.copy(src, dst)
104
105
  end
105
106
  end
@@ -165,7 +166,9 @@ class NovelConverter
165
166
  aozoraepub3_basename = File.basename(aozoraepub3_path)
166
167
  aozoraepub3_dir = File.dirname(aozoraepub3_path)
167
168
 
168
- java_encoding = "-Dfile.encoding=UTF-8"
169
+ java_encoding = "-Dfile.encoding=UTF-8" +
170
+ " -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8" +
171
+ " -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8"
169
172
 
170
173
  if Helper.os_cygwin?
171
174
  abs_srcpath = Helper.convert_to_windows_path(abs_srcpath)
data/lib/sitesetting.rb CHANGED
@@ -6,6 +6,7 @@
6
6
 
7
7
  require "yaml"
8
8
  require_relative "narou/api"
9
+ require_relative "sitesettinghandler"
9
10
 
10
11
  class SiteSetting
11
12
  NOVEL_SITE_SETTING_DIR = "webnovel/"
@@ -101,14 +102,18 @@ class SiteSetting
101
102
  keys.each do |key|
102
103
  setting_value = self[key] or next
103
104
  [*setting_value].each do |value|
104
- match_data = source.match(/#{value}/m)
105
- if match_data
106
- @match_values[key] = value # yamlのキーでもmatch_valuesに設定しておくが、
107
- update_match_values(match_data) # ←ここで同名のグループ名が定義されていたら上書きされるので注意
108
- # 例えば、title: <title>(?<title>.+?)</title> と定義されていた場合、
109
- # @match_values["title"] には (?<title>.+?) 部分の要素が反映される
110
- break
111
- end
105
+ handle = SiteSettingHandler.handler(self, value)
106
+ match_data = handle&.match(source) # ハンドルオブジェクトを得て、それにより処理する
107
+ next unless match_data
108
+ value = handle.value if handle.respond_to?(:value)
109
+ # rubocop:disable Layout/CommentIndentation
110
+ # 通常はこれまで通りだが、valueを変更することも可能にする
111
+ @match_values[key] = value # yamlのキーでもmatch_valuesに設定しておくが、
112
+ update_match_values(match_data) # ←ここで同名のグループ名が定義されていたら上書きされるので注意
113
+ # 例えば、title: <title>(?<title>.+?)</title> と定義されていた場合、
114
+ # @match_values["title"] には (?<title>.+?) 部分の要素が反映される
115
+ # rubocop:enable Layout/CommentIndentation
116
+ break
112
117
  end
113
118
  end
114
119
  match_data
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "weakref"
4
+ require_relative "worker"
5
+
6
+ class SiteSettingHandler
7
+ HANDLER_DIR = "handler"
8
+ HANDLER_EXT = ".rb"
9
+
10
+ @@klasses = {}
11
+
12
+ class << self
13
+ # @type : ハンドラのタイプ名
14
+ attr_reader :type
15
+
16
+ #
17
+ # ハンドラを登録する
18
+ #
19
+ # 継承したクラスで呼び出してハンドラを登録する
20
+ # 通常、ファイル名からタイプ名を作るが、引数で直接指定も出来る
21
+ # クラスを継承していない場合はクラスを指定して登録する
22
+ #
23
+ def add_handler(path_or_type: @@current_path, klass: self)
24
+ @type = File.basename(path_or_type, HANDLER_EXT)
25
+ @@klasses[@type] = klass
26
+ end
27
+
28
+ #
29
+ # ハンドラの呼び出し
30
+ #
31
+ # 引数から対応するハンドラを呼び出しインスタンスを作る
32
+ # 引数がこのクラスの派生オブジェクトならそのまま返す
33
+ # それ以外でもメソッドmatchを持つならそのまま返す
34
+ # それ以外なら正規表現であるので正規表現ハンドラにして返す
35
+ #
36
+ def handler(parent, value)
37
+ case value
38
+ when Array
39
+ # key:
40
+ # type: value
41
+ _make_handler(parent, *value)
42
+ when Hash
43
+ # key:
44
+ # - type: value
45
+ _make_handler(parent, *value.flatten)
46
+ when String
47
+ # key:
48
+ # value
49
+ /#{value}/m
50
+ when self
51
+ # 派生オブジェクトならそのまま返す
52
+ value
53
+ else
54
+ if value.respond_to?(:match)
55
+ # matchメソッドを持つオブジェクトならそのまま返す
56
+ value
57
+ else
58
+ # その他であれば正規表現として生成
59
+ /#{value}/m
60
+ end
61
+ end
62
+ end
63
+
64
+ def _make_handler(parent, type, value)
65
+ # typeが未登録の場合、例外が発生する
66
+ klass = @@klasses.fetch(type)
67
+ klass.make(value, WeakRef.new(parent))
68
+ end
69
+
70
+ # makeを再定義すれば別のインスタンスを返すことも可能
71
+ alias make new
72
+
73
+ end
74
+
75
+ def initialize(value, parent)
76
+ @value = value
77
+ @parent = parent
78
+ end
79
+
80
+ # ハンドラタイプ名
81
+ # class_attribute :type, instance_writer: false
82
+ def type
83
+ self.class.type
84
+ end
85
+
86
+ # 呼び出し元のオブジェクト
87
+ def parent
88
+ @parent&.weakref_alive? ? @parent : nil
89
+ end
90
+
91
+ # valueを定義すれば変更できる
92
+ # def value()
93
+ # self
94
+ # end
95
+ #
96
+ # sourceから値が得られるかチェックし、得られるなら値をセットする
97
+ # 継承したクラスにて実装する
98
+ # def match(source)
99
+ # PseudoMatchData.new("post_match", {"key" => "value"})
100
+ # end
101
+
102
+ # matchが返すmatch_dataのためのクラス
103
+ class PseudoMatchData < Hash
104
+ attr_reader :post_match
105
+
106
+ def initialize(post_match, hash)
107
+ super()
108
+ @post_match = post_match
109
+ replace(hash)
110
+ end
111
+
112
+ def names
113
+ keys.map(&:to_s)
114
+ end
115
+ end
116
+ end
117
+
118
+ class EvalHandler < SiteSettingHandler
119
+ def match(source)
120
+ eval(@value, binding, parent&.path || "(nil)") # rubocop:disable Security/Eval
121
+ end
122
+ add_handler(path_or_type: "eval")
123
+ end
data/lib/version.rb CHANGED
@@ -5,5 +5,5 @@
5
5
  #
6
6
 
7
7
  module Narou
8
- VERSION = "3.8.2"
8
+ VERSION = "3.9.0"
9
9
  end
data/narou.gemspec CHANGED
@@ -32,10 +32,13 @@ Gem::Specification.new do |gem|
32
32
  install_message = <<-EOS
33
33
  #{"*" * 60}
34
34
 
35
- 3.8.2: 2022/09/10
35
+ 3.9.0: 2024-04-02
36
36
  -----------------
37
37
  #### 修正内容
38
- - フォルダが存在しない場合に自動で作成する様に修正
38
+ - 小説家になろうの目次修正に対応
39
+ - カクヨムの目次修正に対応
40
+
41
+ thanks for contributors: @topstone, @rogenobl, @happynow, @etg-lt
39
42
 
40
43
  #{"*" * 60}
41
44
  EOS
@@ -10,33 +10,87 @@ confirm_over18: no
10
10
  append_title_to_folder_name: yes
11
11
  title_strip_pattern: null
12
12
  sitename: *name
13
- version: 1.0
13
+ version: 2.0
14
+
15
+ # ------------------------------------------------------------
16
+ # 前処理設定
17
+ # jsonを処理して正規表現で取得可能なデータへ変換し挿入する
18
+ code: &code
19
+ eval: |-
20
+ magicword = "KakuyomuPreprocessEvalMagicWord"
21
+ # magicwordがある場合、既にこの前処理が行われているので何もしない
22
+ unless source.include?(magicword)
23
+ require "json"
24
+ source.match(%r|<script id="__NEXT_DATA__" type="application/json">(.*)</script>|) do |m|
25
+ json = JSON.parse($1)
26
+ # data: 各データが収められたハッシュ
27
+ data = json["props"]["pageProps"]["__APOLLO_STATE__"]
28
+ # work: この作品のデータ
29
+ work = data["Work:#{json["query"]["workId"]}"]
30
+ # まずTOCを処理する
31
+ toc = work["tableOfContents"]
32
+ # workのTOCはTableOfContentsChapterの参照の配列となっているので、それを解決する
33
+ toc.map! {|v| data[v["__ref"]]}
34
+ # TableOfContentsChapterにはChapterと各話の配列があるのでそれを取り出し
35
+ toc.map! {|v| [v["chapter"], v["episodeUnions"]]}
36
+ # Chapterと各話を一つの配列にフラットにし
37
+ toc.flatten!
38
+ # Chapterが使われていない場合にあるnilを排除し
39
+ toc.compact!
40
+ # Chapterと各話は参照なので、それを解決し
41
+ toc.map! {|v| data[v["__ref"]]}
42
+ # 必要な属性値を取り出して「;」でつないでまとめる
43
+ # __typename: ChapterかEpisodeかの判別用
44
+ # level: Chapterにあり1か2かでchapterかsubchapterか判別する
45
+ # id: Episodeならindex値として必要。Chapterなら必要ないが処理の簡略化のため付加している
46
+ # publishedAt: Episodeにありsubupdateとして利用する
47
+ # title: Chapter、Episode共にタイトルとなる
48
+ # 最後のtitle以外で「;」を含む事は無いはず
49
+ toc_attr = %w(__typename level id publishedAt title)
50
+ toc.map! {|v| v.slice(*toc_attr).values.join(";")}
51
+ # 続いてworkの著者を処理する
52
+ # 著者の参照から表示用の名前 activityName を取得する
53
+ work["author"] = data[work["author"]["__ref"]]["activityName"]
54
+ # alternateAuthorName がある場合は、それも使う。
55
+ work["author"] = work["alternateAuthorName"] + "/" + work["author"] if work["alternateAuthorName"]
56
+ # あらすじの改行を<br>に変換し、正規表現を単純化する。<br>はnarourb側で再変換される
57
+ work["introduction"].gsub!("\n", "<br>")
58
+ # workからTOC以外に利用する属性を列挙している
59
+ work_attr = %w(author title serialStatus publicEpisodeCount publishedAt
60
+ editedAt lastEpisodePublishedAt totalCharacterCount introduction)
61
+ # HTMLコメントの開始、前処理済みか検知するためのmagicword、
62
+ # TOC以外のworkの利用する属性値、TOC、HTMLコメントの終了を生成し
63
+ str = ["<!---", magicword,
64
+ work.slice(*work_attr).map {|v| v.join("::")},
65
+ toc, "--->"].join("\n")
66
+ # 元のページデータに挿入する。デバッグ時用に元々のデータはすべて残す。
67
+ source.insert(m.begin(0), str)
68
+ # 元々のデータは基本必要ないのでreplaceを使えば元々のデータはすべて消える。
69
+ #source.replace(str)
70
+ end
71
+ end
72
+ nil
14
73
 
15
74
  # ------------------------------------------------------------
16
75
  # 書籍情報取得設定
17
- title: &title |-
18
- <h1 id="workTitle"><a href=".+?">(?<title>.+?)</a></h1>
19
- author: |-
20
- (?:<span class="activityName" itemprop="author">(?<author>.+?)</span>)|(?:<span class="screenName.*?">(?<author>.+?)</span>)
21
- story: &story |-
22
- <p id="introduction" class="ui-truncateTextButton js-work-introduction">(?<story>.+?)(?:[\n ]*?</span>|[\n ]*?</p>)
76
+ title: &title
77
+ - *code
78
+ - ^title::(?<title>.+?)$
79
+ author:
80
+ - ^author::(?<author>.+?)$
81
+ story: &story
82
+ - ^introduction::(?<story>.+?)$
23
83
 
24
84
  # ------------------------------------------------------------
25
85
  # 目次取得設定
26
86
  toc_url: \\k<top_url>/works/\\k<ncode>
27
- subtitles: |-2
28
- (?:<li class="widget-toc-chapter widget-toc-level1.*?">
29
- <span>(?<chapter>.+?)</span>
30
- </li>
31
- )?(?:<li class="widget-toc-chapter widget-toc-level2.*?">
32
- <span>(?<subchapter>.+?)</span>
33
- </li>
34
- )?<li class="widget-toc-episode">
35
- <a href="(?<href>/works/\d+/episodes/(?<index>\d+))".*?>
36
- <span class="widget-toc-episode-titleLabel.*?">(?<subtitle>.+?)</span>
37
- <time class="widget-toc-episode-datePublished" datetime="(?<subupdate>.+?)">.+?</time>
38
- </a>
39
- </li>
87
+ subtitles:
88
+ - *code
89
+ - (?x)
90
+ ^(?:Chapter;1;\d+;(?<chapter>.+?)\n)?
91
+ (?:Chapter;2;\d+;(?<subchapter>.+?)\n)?
92
+ Episode;(?<index>\d+);(?<subupdate>.+?);(?<subtitle>.+?)$
93
+ href: /works/\\k<ncode>/episodes/\\k<index>
40
94
 
41
95
  # ------------------------------------------------------------
42
96
  # 本文取得設定
@@ -53,29 +107,28 @@ novel_info_url: \\k<toc_url>
53
107
  t: *title
54
108
 
55
109
  # novel_type 小説種別
56
- nt: '<dt><span>執筆状況</span></dt>\n *?<dd>(?<novel_type>.+?)</dd>'
110
+ nt: ^serialStatus::(?<novel_type>.+?)$
57
111
  novel_type_string:
58
- 連載中: 1
59
- 完結済: 3
112
+ RUNNING: 1
113
+ COMPLETED: 3
60
114
 
61
115
  # general_all_no 掲載話数
62
- ga: '<dt><span>エピソード</span></dt>\n *?<dd>(?<general_all_no>\d+)話</dd>'
116
+ ga: ^publicEpisodeCount::(?<general_all_no>.+?)$
63
117
 
64
118
  # story あらすじ
65
119
  s: *story
66
120
 
67
121
  # general_firstup 初回掲載日
68
- gf: '<dt><span>公開日</span></dt>\n *?<dd><time itemprop="datePublished" datetime="(?<general_firstup>.+?)">.+?</time>'
122
+ gf: ^publishedAt::(?<general_firstup>.+?)$
69
123
 
70
- # novelupdated_at 小説の更新時刻。最終掲載日で代用
71
- nu: '<dt><span>最終更新日</span></dt>\n *?<dd><time itemprop="dateModified" datetime="(?<novelupdated_at>.+?)">.+?</time>'
124
+ # novelupdated_at 小説の更新時刻
125
+ nu: ^editedAt::(?<novelupdated_at>.+?)$
72
126
 
73
127
  # general_lastup 最新話掲載日
74
- gl: null
128
+ gl: ^lastEpisodePublishedAt::(?<general_lastup>.+?)$
75
129
 
76
130
  # writer 作者名
77
- w: |-
78
- (?:<span class="activityName" itemprop="author">(?<writer>.+?)</span>)|(?:<span class="screenName.*?">(?<writer>.+?)</span>)
131
+ w: ^author::(?<writer>.+?)$
79
132
 
80
133
  # length 文字数
81
- l: '<dt><span>総文字数</span></dt>\n *?<dd>(?<length>.+?)文字</dd>'
134
+ l: ^totalCharacterCount::(?<length>.+?)$
@@ -17,7 +17,7 @@ version: 2.0
17
17
  toc_url: https://\\k<domain>/\\k<ncode>/
18
18
  subtitles: |-
19
19
  (?:<div class="chapter_title">(?<chapter>.+?)</div>
20
-
20
+
21
21
  )?<dl class="novel_sublist2">
22
22
  <dd class="subtitle">
23
23
  <a href="(?<href>/.+?/(?<index>\d+?)/)">(?<subtitle>.+?)</a>
@@ -25,6 +25,10 @@ subtitles: |-
25
25
  <dt class="long_update">
26
26
  (?<subdate>.+?)(?:<span title="(?<subupdate>.+?) 改稿">(<u>改</u>)</span>)?</dt>
27
27
  </dl>
28
+ next_toc: <a href="/(?<next_page>[^"]+)" class="novelview_pager-next">
29
+ next_url: https://\\k<domain>/\\k<next_page>
30
+ # 最大のページ数を得る。固定の数字でも可。
31
+ toc_page_max: <a href="/[^"]+p=(?<toc_page_max>\d+)" class="novelview_pager-last">
28
32
 
29
33
  # ------------------------------------------------------------
30
34
  # 本文取得設定
@@ -22,7 +22,7 @@ version: 2.0
22
22
  toc_url: https://\\k<domain>/\\k<ncode>/
23
23
  subtitles: |-
24
24
  (?:<div class="chapter_title">(?<chapter>.+?)</div>
25
-
25
+
26
26
  )?<dl class="novel_sublist2">
27
27
  <dd class="subtitle">
28
28
  <a href="(?<href>/.+?/(?<index>\d+?)/)">(?<subtitle>.+?)</a>
@@ -30,6 +30,10 @@ subtitles: |-
30
30
  <dt class="long_update">
31
31
  (?<subdate>.+?)(?:<span title="(?<subupdate>.+?) 改稿">(<u>改</u>)</span>)?</dt>
32
32
  </dl>
33
+ next_toc: <a href="/(?<next_page>[^"]+)" class="novelview_pager-next">
34
+ next_url: https://\\k<domain>/\\k<next_page>
35
+ # 最大のページ数を得る。固定の数字でも可。
36
+ toc_page_max: <a href="/[^"]+p=(?<toc_page_max>\d+)" class="novelview_pager-last">
33
37
 
34
38
  # ------------------------------------------------------------
35
39
  # 本文取得設定
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: narou
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.8.2
4
+ version: 3.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - whiteleaf7
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-10 00:00:00.000000000 Z
11
+ date: 2024-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: termcolorlight
@@ -570,6 +570,7 @@ files:
570
570
  - lib/novelsetting.rb
571
571
  - lib/progressbar.rb
572
572
  - lib/sitesetting.rb
573
+ - lib/sitesettinghandler.rb
573
574
  - lib/template.rb
574
575
  - lib/version.rb
575
576
  - lib/web/all.rb
@@ -709,10 +710,13 @@ metadata: {}
709
710
  post_install_message: |
710
711
  ************************************************************
711
712
 
712
- 3.8.2: 2022/09/10
713
+ 3.9.0: 2024-04-02
713
714
  -----------------
714
715
  #### 修正内容
715
- - フォルダが存在しない場合に自動で作成する様に修正
716
+ - 小説家になろうの目次修正に対応
717
+ - カクヨムの目次修正に対応
718
+
719
+ thanks for contributors: @topstone, @rogenobl, @happynow, @etg-lt
716
720
 
717
721
  ************************************************************
718
722
  rdoc_options: []
@@ -729,7 +733,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
729
733
  - !ruby/object:Gem::Version
730
734
  version: '0'
731
735
  requirements: []
732
- rubygems_version: 3.2.15
736
+ rubygems_version: 3.5.3
733
737
  signing_key:
734
738
  specification_version: 4
735
739
  summary: Narou.rb ― 小説家になろうダウンローダ&縦書用整形スクリプト