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 +4 -4
- data/ChangeLog.md +9 -0
- data/README.md +5 -2
- data/commitversion +1 -1
- data/lib/command/diff.rb +2 -2
- data/lib/command/setting.rb +4 -0
- data/lib/command/tag.rb +1 -1
- data/lib/command/update/general_lastup_updater.rb +1 -1
- data/lib/converterbase.rb +3 -3
- data/lib/downloader.rb +40 -3
- data/lib/extension.rb +3 -0
- data/lib/helper.rb +1 -1
- data/lib/narou.rb +1 -1
- data/lib/novelconverter.rb +4 -1
- data/lib/sitesetting.rb +13 -8
- data/lib/sitesettinghandler.rb +123 -0
- data/lib/version.rb +1 -1
- data/narou.gemspec +5 -2
- data/webnovel/kakuyomu.jp.yaml +84 -31
- data/webnovel/ncode.syosetu.com.yaml +5 -1
- data/webnovel/novel18.syosetu.com.yaml +5 -1
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a9fafd6af1ebb3b07da36ae193a2de21a750b00797ef805f6d3ade778e65dff
|
4
|
+
data.tar.gz: 3e260f769599b31e1e52290c78842be937b6dc34b6a002ca73dd30f351fe079c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
-
|
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.
|
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)
|
data/lib/command/setting.rb
CHANGED
@@ -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
@@ -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
|
943
|
-
"#{
|
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 =
|
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("/:*?\"
|
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
data/lib/novelconverter.rb
CHANGED
@@ -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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
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
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.
|
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
|
data/webnovel/kakuyomu.jp.yaml
CHANGED
@@ -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:
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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:
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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:
|
110
|
+
nt: ^serialStatus::(?<novel_type>.+?)$
|
57
111
|
novel_type_string:
|
58
|
-
|
59
|
-
|
112
|
+
RUNNING: 1
|
113
|
+
COMPLETED: 3
|
60
114
|
|
61
115
|
# general_all_no 掲載話数
|
62
|
-
ga:
|
116
|
+
ga: ^publicEpisodeCount::(?<general_all_no>.+?)$
|
63
117
|
|
64
118
|
# story あらすじ
|
65
119
|
s: *story
|
66
120
|
|
67
121
|
# general_firstup 初回掲載日
|
68
|
-
gf:
|
122
|
+
gf: ^publishedAt::(?<general_firstup>.+?)$
|
69
123
|
|
70
|
-
# novelupdated_at
|
71
|
-
nu:
|
124
|
+
# novelupdated_at 小説の更新時刻
|
125
|
+
nu: ^editedAt::(?<novelupdated_at>.+?)$
|
72
126
|
|
73
127
|
# general_lastup 最新話掲載日
|
74
|
-
gl:
|
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:
|
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.
|
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:
|
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.
|
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.
|
736
|
+
rubygems_version: 3.5.3
|
733
737
|
signing_key:
|
734
738
|
specification_version: 4
|
735
739
|
summary: Narou.rb ― 小説家になろうダウンローダ&縦書用整形スクリプト
|