narou 3.5.0 → 3.7.1
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/.circleci/config.yml +2 -2
- data/.rubocop.yml +4 -4
- data/ChangeLog.md +27 -0
- data/Gemfile.lock +78 -71
- data/README.md +16 -2
- data/lib/command/setting.rb +3 -3
- data/lib/command/update/general_lastup_updater.rb +2 -1
- data/lib/converterbase.rb +1 -1
- data/lib/downloader.rb +1 -1
- data/lib/helper.rb +2 -2
- data/lib/illustration.rb +11 -2
- data/lib/narou.rb +276 -270
- data/lib/narou/api.rb +1 -1
- data/lib/novelconverter.rb +2 -2
- data/lib/version.rb +1 -1
- data/lib/web/appserver.rb +4 -2
- data/narou.gemspec +18 -8
- metadata +70 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80482340ee7d74119214a40ad48660c2348508340fdd93481efa53d99f5a3194
|
4
|
+
data.tar.gz: b3a5a426b5ff095bfd9ab8bbfeccee6559c5aabf9969f753226f4911f3bb7bfd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f5955fd8c737c0046e847a50b68677fdd34f2beb5b3f8301b22731a0db739b776a0ea6a30cf2616f5f8d67f0c9798d0d492a0bc08076dba582746b408790ee1
|
7
|
+
data.tar.gz: 03a59c16cc0b43760e7eded2b30a4086d3b22b9edcb48854fb9bbd0f087926fc923c2b80b634808265d068280a601eb82d5b5e92ae4dbefd8bb24b6cdf837a79
|
data/.circleci/config.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -56,9 +56,6 @@ Style/AndOr:
|
|
56
56
|
Style/BlockDelimiters:
|
57
57
|
Enabled: false
|
58
58
|
|
59
|
-
Style/BracesAroundHashParameters:
|
60
|
-
Enabled: false
|
61
|
-
|
62
59
|
Style/CollectionMethods:
|
63
60
|
PreferredMethods:
|
64
61
|
detect: "detect"
|
@@ -179,7 +176,7 @@ Style/StringLiterals:
|
|
179
176
|
Style/SymbolProc:
|
180
177
|
Enabled: true
|
181
178
|
|
182
|
-
Layout/
|
179
|
+
Layout/IndentationStyle:
|
183
180
|
Enabled: true
|
184
181
|
|
185
182
|
Layout/TrailingEmptyLines:
|
@@ -241,3 +238,6 @@ Style/FormatStringToken:
|
|
241
238
|
|
242
239
|
Layout/EmptyLineAfterGuardClause:
|
243
240
|
Enabled: false
|
241
|
+
|
242
|
+
Style/StderrPuts:
|
243
|
+
Enabled: false
|
data/ChangeLog.md
CHANGED
@@ -1,6 +1,33 @@
|
|
1
1
|
更新履歴 - ChangeLog
|
2
2
|
====================
|
3
3
|
|
4
|
+
3.7.1: 2021/04/01
|
5
|
+
-----------------
|
6
|
+
#### 修正内容
|
7
|
+
- その他の小説の最新話掲載日を確認しようとするとクラッシュする不具合を修正
|
8
|
+
|
9
|
+
|
10
|
+
3.7.0: 2021/01/23
|
11
|
+
-----------------
|
12
|
+
#### 修正内容
|
13
|
+
- Apple Silicon 搭載 Mac でも動く様にライブラリをアップデート
|
14
|
+
- device を kobo に設定し、ebook-filename-length-limit でファイル名が制限され
|
15
|
+
た場合に send コマンドが正常に実行できない不具合を修正
|
16
|
+
|
17
|
+
3.6.0: 2021/01/02
|
18
|
+
-----------------
|
19
|
+
#### 修正内容
|
20
|
+
- Ruby 3.0 に対応
|
21
|
+
|
22
|
+
|
23
|
+
3.5.1: 2020/03/21
|
24
|
+
-----------------
|
25
|
+
#### 修正内容
|
26
|
+
- 小説家になろう系列の挿絵をダウンロード時に、サムネイル画像を取得するように
|
27
|
+
なってしまっていたのを修正
|
28
|
+
- Ruby 2.7 で narou setting -l を実行時に警告が大量に出ていたのを修正
|
29
|
+
|
30
|
+
|
4
31
|
3.5.0: 2020/02/16
|
5
32
|
-----------------
|
6
33
|
#### 修正内容
|
data/Gemfile.lock
CHANGED
@@ -1,119 +1,126 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
narou (3.
|
5
|
-
activesupport (
|
4
|
+
narou (3.7.0)
|
5
|
+
activesupport (>= 6.1, < 8.0)
|
6
6
|
diff-lcs (~> 1.2, >= 1.2.5)
|
7
7
|
erubis (~> 2.7)
|
8
|
+
ffi (~> 1.4, >= 1.4.2)
|
8
9
|
haml (>= 5.1.2, < 6)
|
9
10
|
mail (~> 2.6.0, >= 2.6.6)
|
10
11
|
memoist (~> 0.11.0)
|
11
12
|
open_uri_redirections (~> 0.2, >= 0.2.1)
|
12
13
|
pony (~> 1, >= 1.11)
|
13
14
|
rubyzip (~> 2.0, >= 2.0.0)
|
14
|
-
|
15
|
-
sinatra (~>
|
16
|
-
sinatra-contrib (~>
|
15
|
+
sassc (~> 2.4)
|
16
|
+
sinatra (~> 2.0, >= 2.0.8.1)
|
17
|
+
sinatra-contrib (~> 2.0, >= 2.0.8.1)
|
17
18
|
systemu (~> 2.6, >= 2.6.5)
|
18
19
|
termcolorlight (~> 1.0, >= 1.1.1)
|
19
20
|
tilt (~> 2.0, >= 2.0.10)
|
20
21
|
unicode-display_width (~> 1.4)
|
22
|
+
webrick (~> 1.7)
|
21
23
|
|
22
24
|
GEM
|
23
25
|
remote: https://rubygems.org/
|
24
26
|
specs:
|
25
|
-
activesupport (
|
27
|
+
activesupport (6.1.1)
|
26
28
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
27
|
-
i18n (>=
|
28
|
-
minitest (
|
29
|
-
tzinfo (~>
|
29
|
+
i18n (>= 1.6, < 2)
|
30
|
+
minitest (>= 5.1)
|
31
|
+
tzinfo (~> 2.0)
|
32
|
+
zeitwerk (~> 2.3)
|
30
33
|
awesome_print (1.8.0)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
docile (1.3.2)
|
34
|
+
byebug (11.1.3)
|
35
|
+
coderay (1.1.3)
|
36
|
+
concurrent-ruby (1.1.8)
|
37
|
+
diff-lcs (1.4.4)
|
38
|
+
docile (1.3.5)
|
37
39
|
erubis (2.7.0)
|
38
|
-
ffi (1.
|
39
|
-
|
40
|
+
ffi (1.14.2)
|
41
|
+
ffi (1.14.2-java)
|
42
|
+
haml (5.2.1)
|
40
43
|
temple (>= 0.8.0)
|
41
44
|
tilt
|
42
|
-
i18n (1.7
|
45
|
+
i18n (1.8.7)
|
43
46
|
concurrent-ruby (~> 1.0)
|
44
47
|
mail (2.6.6)
|
45
48
|
mime-types (>= 1.16, < 4)
|
46
49
|
memoist (0.11.0)
|
47
|
-
method_source (0.
|
50
|
+
method_source (1.0.0)
|
48
51
|
mime-types (3.3.1)
|
49
52
|
mime-types-data (~> 3.2015)
|
50
|
-
mime-types-data (3.
|
51
|
-
minitest (5.
|
52
|
-
multi_json (1.
|
53
|
+
mime-types-data (3.2020.1104)
|
54
|
+
minitest (5.14.3)
|
55
|
+
multi_json (1.15.0)
|
56
|
+
mustermann (1.1.1)
|
57
|
+
ruby2_keywords (~> 0.0.1)
|
53
58
|
open_uri_redirections (0.2.1)
|
54
59
|
pony (1.13.1)
|
55
60
|
mail (>= 2.0)
|
56
|
-
pry (0.
|
57
|
-
coderay (~> 1.1
|
58
|
-
method_source (~>
|
59
|
-
pry
|
61
|
+
pry (0.13.1)
|
62
|
+
coderay (~> 1.1)
|
63
|
+
method_source (~> 1.0)
|
64
|
+
pry (0.13.1-java)
|
65
|
+
coderay (~> 1.1)
|
66
|
+
method_source (~> 1.0)
|
67
|
+
spoon (~> 0.0)
|
68
|
+
pry-byebug (3.9.0)
|
60
69
|
byebug (~> 11.0)
|
61
|
-
pry (~> 0.
|
62
|
-
rack (
|
63
|
-
rack-protection (1.
|
70
|
+
pry (~> 0.13.0)
|
71
|
+
rack (2.2.3)
|
72
|
+
rack-protection (2.1.0)
|
64
73
|
rack
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
rspec-expectations (~> 3.9.0)
|
73
|
-
rspec-mocks (~> 3.9.0)
|
74
|
-
rspec-core (3.9.1)
|
75
|
-
rspec-support (~> 3.9.1)
|
76
|
-
rspec-expectations (3.9.0)
|
74
|
+
rspec (3.10.0)
|
75
|
+
rspec-core (~> 3.10.0)
|
76
|
+
rspec-expectations (~> 3.10.0)
|
77
|
+
rspec-mocks (~> 3.10.0)
|
78
|
+
rspec-core (3.10.1)
|
79
|
+
rspec-support (~> 3.10.0)
|
80
|
+
rspec-expectations (3.10.1)
|
77
81
|
diff-lcs (>= 1.2.0, < 2.0)
|
78
|
-
rspec-support (~> 3.
|
79
|
-
rspec-mocks (3.
|
82
|
+
rspec-support (~> 3.10.0)
|
83
|
+
rspec-mocks (3.10.1)
|
80
84
|
diff-lcs (>= 1.2.0, < 2.0)
|
81
|
-
rspec-support (~> 3.
|
85
|
+
rspec-support (~> 3.10.0)
|
82
86
|
rspec-retry (0.6.2)
|
83
87
|
rspec-core (> 3.3)
|
84
|
-
rspec-support (3.
|
88
|
+
rspec-support (3.10.1)
|
85
89
|
rspec_junit_formatter (0.4.1)
|
86
90
|
rspec-core (>= 2, < 4, != 2.12.0)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
rb-inotify (~> 0.9, >= 0.9.7)
|
93
|
-
simplecov (0.18.2)
|
91
|
+
ruby2_keywords (0.0.4)
|
92
|
+
rubyzip (2.3.0)
|
93
|
+
sassc (2.4.0)
|
94
|
+
ffi (~> 1.9)
|
95
|
+
simplecov (0.21.2)
|
94
96
|
docile (~> 1.1)
|
95
97
|
simplecov-html (~> 0.11)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
98
|
+
simplecov_json_formatter (~> 0.1)
|
99
|
+
simplecov-html (0.12.3)
|
100
|
+
simplecov_json_formatter (0.1.2)
|
101
|
+
sinatra (2.1.0)
|
102
|
+
mustermann (~> 1.0)
|
103
|
+
rack (~> 2.2)
|
104
|
+
rack-protection (= 2.1.0)
|
105
|
+
tilt (~> 2.0)
|
106
|
+
sinatra-contrib (2.1.0)
|
103
107
|
multi_json
|
104
|
-
|
105
|
-
rack-
|
106
|
-
sinatra (
|
107
|
-
tilt (
|
108
|
+
mustermann (~> 1.0)
|
109
|
+
rack-protection (= 2.1.0)
|
110
|
+
sinatra (= 2.1.0)
|
111
|
+
tilt (~> 2.0)
|
112
|
+
spoon (0.0.6)
|
113
|
+
ffi
|
108
114
|
systemu (2.6.5)
|
109
115
|
temple (0.8.2)
|
110
116
|
termcolorlight (1.1.1)
|
111
|
-
thread_safe (0.3.6)
|
112
117
|
tilt (2.0.10)
|
113
|
-
timecop (0.9.
|
114
|
-
tzinfo (
|
115
|
-
|
116
|
-
unicode-display_width (1.
|
118
|
+
timecop (0.9.2)
|
119
|
+
tzinfo (2.0.4)
|
120
|
+
concurrent-ruby (~> 1.0)
|
121
|
+
unicode-display_width (1.7.0)
|
122
|
+
webrick (1.7.0)
|
123
|
+
zeitwerk (2.4.2)
|
117
124
|
|
118
125
|
PLATFORMS
|
119
126
|
java
|
@@ -124,11 +131,11 @@ DEPENDENCIES
|
|
124
131
|
narou!
|
125
132
|
pry (~> 0.12)
|
126
133
|
pry-byebug (~> 3.8)
|
127
|
-
rspec (~> 3.
|
134
|
+
rspec (~> 3.10)
|
128
135
|
rspec-retry (~> 0.6)
|
129
136
|
rspec_junit_formatter (~> 0.4)
|
130
|
-
simplecov (~> 0.
|
137
|
+
simplecov (~> 0.20)
|
131
138
|
timecop (~> 0.9)
|
132
139
|
|
133
140
|
BUNDLED WITH
|
134
|
-
|
141
|
+
2.2.3
|
data/README.md
CHANGED
@@ -34,10 +34,24 @@ Narou.rb - 小説家になろうのダウンローダ&縦書き整形&管理
|
|
34
34
|
更新履歴 - ChangeLog
|
35
35
|
--------------------
|
36
36
|
|
37
|
-
3.
|
37
|
+
3.7.1: 2021/04/01
|
38
38
|
-----------------
|
39
39
|
#### 修正内容
|
40
|
-
-
|
40
|
+
- その他の小説の最新話掲載日を確認しようとするとクラッシュする不具合を修正
|
41
|
+
|
42
|
+
|
43
|
+
3.7.0: 2021/01/23
|
44
|
+
-----------------
|
45
|
+
#### 修正内容
|
46
|
+
- Apple Silicon 搭載 Mac でも動く様にライブラリをアップデート
|
47
|
+
- device を kobo に設定し、ebook-filename-length-limit でファイル名が制限され
|
48
|
+
た場合に send コマンドが正常に実行できない不具合を修正
|
49
|
+
|
50
|
+
|
51
|
+
3.6.0: 2021/01/02
|
52
|
+
-----------------
|
53
|
+
#### 修正内容
|
54
|
+
- Ruby 3.0 に対応
|
41
55
|
|
42
56
|
----
|
43
57
|
|
data/lib/command/setting.rb
CHANGED
@@ -118,7 +118,7 @@ module Command
|
|
118
118
|
settings.each do |scope, scoped_settings|
|
119
119
|
stream_io.puts "[#{scope.capitalize} Variables]"
|
120
120
|
scoped_settings.each do |name, value|
|
121
|
-
if value =~ / /
|
121
|
+
if value.to_s =~ / /
|
122
122
|
value = "'#{value}'"
|
123
123
|
end
|
124
124
|
stream_io.puts "<bold><green>#{name}</green></bold>=#{value}".termcolor
|
@@ -537,8 +537,8 @@ module Command
|
|
537
537
|
"webui.theme" => {
|
538
538
|
type: :select, help: "WEB UI 用テーマ選択",
|
539
539
|
invisible: true,
|
540
|
-
select_keys: Narou.
|
541
|
-
select_summaries: Narou.
|
540
|
+
select_keys: Narou.theme_names,
|
541
|
+
select_summaries: Narou.theme_names,
|
542
542
|
tab: :webui
|
543
543
|
},
|
544
544
|
"webui.table.reload-timing" => {
|
@@ -4,6 +4,7 @@
|
|
4
4
|
# Copyright 2013 whiteleaf. All rights reserved.
|
5
5
|
#
|
6
6
|
|
7
|
+
require "net/http"
|
7
8
|
require_relative "../../narou/api"
|
8
9
|
|
9
10
|
module Command
|
@@ -63,7 +64,7 @@ module Command
|
|
63
64
|
interval.wait
|
64
65
|
begin
|
65
66
|
downloader = Downloader.new(id)
|
66
|
-
next unless downloader.get_latest_table_of_contents(through_error: true)
|
67
|
+
next unless downloader.get_latest_table_of_contents(downloader.load_toc_file, through_error: true)
|
67
68
|
dates = {
|
68
69
|
"novelupdated_at" => downloader.get_novelupdated_at,
|
69
70
|
"general_lastup" => downloader.get_general_lastup,
|
data/lib/converterbase.rb
CHANGED
@@ -995,7 +995,7 @@ class ConverterBase
|
|
995
995
|
# URL っぽい文字列を一旦別のIDに置き換えてあとで復元することで、変換処理の影響を受けさせない
|
996
996
|
#
|
997
997
|
def replace_url(data)
|
998
|
-
data.gsub!(URI.
|
998
|
+
data.gsub!(URI::DEFAULT_PARSER.make_regexp(%w(http https))) do |match|
|
999
999
|
@url_list << match
|
1000
1000
|
"[#URL=#{@url_list.size - 1}]"
|
1001
1001
|
end
|
data/lib/downloader.rb
CHANGED
data/lib/helper.rb
CHANGED
@@ -350,10 +350,10 @@ module Helper
|
|
350
350
|
# 長過ぎるファイルパスを詰める
|
351
351
|
# ファイル名部分のみを詰める。拡張子は維持する
|
352
352
|
#
|
353
|
-
def truncate_path(path, limit = Inventory.load["filename-length-limit"])
|
353
|
+
def truncate_path(path, limit = Inventory.load["filename-length-limit"], extname: nil)
|
354
354
|
limit ||= FILENAME_LENGTH_LIMIT
|
355
355
|
dirname = File.dirname(path)
|
356
|
-
extname
|
356
|
+
extname ||= File.extname(path)
|
357
357
|
basename = File.basename(path, extname)
|
358
358
|
if basename.length > limit
|
359
359
|
basename = basename[0...limit]
|
data/lib/illustration.rb
CHANGED
@@ -27,7 +27,7 @@ class Illustration
|
|
27
27
|
source.gsub!(/[#挿絵((.+?))入る]/) do |match|
|
28
28
|
url = $1
|
29
29
|
url = "https:#{url}" if url.start_with?("//")
|
30
|
-
if url =~ URI.
|
30
|
+
if url =~ URI::DEFAULT_PARSER.make_regexp
|
31
31
|
path = download_image(url)
|
32
32
|
path ? block.call(make_illust_chuki(path)) : ""
|
33
33
|
else
|
@@ -53,7 +53,9 @@ class Illustration
|
|
53
53
|
if path = search_image(basename)
|
54
54
|
return path
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
|
+
url = transform_mitemin_url(url)
|
58
|
+
URI.open(url, make_open_uri_options(allow_redirections: :safe)) do |fp|
|
57
59
|
content_type = fp.meta["content-type"]
|
58
60
|
ext = MIME[content_type] or raise UnknownMIMEType, content_type
|
59
61
|
illust_abs_path = create_illust_path(basename) + "." + ext
|
@@ -77,6 +79,13 @@ class Illustration
|
|
77
79
|
Dir.glob(path)[0]
|
78
80
|
end
|
79
81
|
|
82
|
+
def transform_mitemin_url(url)
|
83
|
+
uri = URI.parse(url)
|
84
|
+
return url unless uri.host.end_with?(".mitemin.net")
|
85
|
+
|
86
|
+
url.sub("viewimagebig", "viewimage")
|
87
|
+
end
|
88
|
+
|
80
89
|
def create_illust_path(basename)
|
81
90
|
illust_abs_dir = File.join(@setting.archive_path, ILLUST_DIR)
|
82
91
|
Dir.mkdir(illust_abs_dir) unless File.exist?(illust_abs_dir)
|
data/lib/narou.rb
CHANGED
@@ -38,330 +38,336 @@ module Narou
|
|
38
38
|
|
39
39
|
extend Mixin::Locker
|
40
40
|
|
41
|
-
|
42
|
-
|
41
|
+
class << self
|
42
|
+
extend Memoist
|
43
43
|
|
44
|
-
|
44
|
+
@@is_web = false
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
def last_commit_year
|
47
|
+
2021
|
48
|
+
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
50
|
+
def root_dir
|
51
|
+
root = nil
|
52
|
+
path = Dir.pwd
|
53
|
+
drive_letter = ""
|
54
|
+
if Helper.os_windows?
|
55
|
+
path.encode!(Encoding::UTF_8)
|
56
|
+
path.gsub!(/^[a-z]:/i, "")
|
57
|
+
drive_letter = $&
|
58
|
+
end
|
59
|
+
while path != ""
|
60
|
+
if File.directory?("#{drive_letter}#{path}/#{LOCAL_SETTING_DIR_NAME}")
|
61
|
+
root = drive_letter + path
|
62
|
+
break
|
63
|
+
end
|
64
|
+
path.gsub!(%r!/[^/]*$!, "")
|
63
65
|
end
|
64
|
-
|
66
|
+
Pathname(root) if root
|
65
67
|
end
|
66
|
-
|
67
|
-
end
|
68
|
-
memoize :root_dir
|
68
|
+
memoize :root_dir
|
69
69
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
70
|
+
def local_setting_dir
|
71
|
+
root_dir&.join(LOCAL_SETTING_DIR_NAME)
|
72
|
+
end
|
73
|
+
memoize :local_setting_dir
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
def global_setting_dir
|
76
|
+
if root_dir
|
77
|
+
dir = root_dir.join(GLOBAL_SETTING_DIR_NAME)
|
78
|
+
return dir if dir.directory?
|
79
|
+
end
|
80
|
+
dir = Pathname(GLOBAL_SETTING_DIR_NAME).expand_path("~")
|
81
|
+
dir.mkdir unless dir.exist?
|
82
|
+
dir
|
79
83
|
end
|
80
|
-
|
81
|
-
dir.mkdir unless dir.exist?
|
82
|
-
dir
|
83
|
-
end
|
84
|
-
memoize :global_setting_dir
|
84
|
+
memoize :global_setting_dir
|
85
85
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
def script_dir
|
87
|
+
Pathname(__dir__).join("..").expand_path
|
88
|
+
end
|
89
|
+
memoize :script_dir
|
90
90
|
|
91
|
-
|
92
|
-
|
93
|
-
|
91
|
+
def log_dir
|
92
|
+
root_dir&.join(LOG_DIR)
|
93
|
+
end
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
95
|
+
def preset_dir
|
96
|
+
script_dir&.join(PRESET_DIR)
|
97
|
+
end
|
98
|
+
memoize :preset_dir
|
99
99
|
|
100
|
-
|
101
|
-
|
102
|
-
|
100
|
+
def already_init?
|
101
|
+
root_dir.present?
|
102
|
+
end
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
104
|
+
def init
|
105
|
+
return nil if already_init?
|
106
|
+
FileUtils.mkdir(LOCAL_SETTING_DIR_NAME)
|
107
|
+
puts "#{LOCAL_SETTING_DIR_NAME}/ を作成しました"
|
108
|
+
Database.init
|
109
|
+
end
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
111
|
+
#
|
112
|
+
# target が alias だった場合はIDに変換する
|
113
|
+
#
|
114
|
+
# 全てのtarget照合系はこのメソッドを通過するので、ここで小文字にしてしまう
|
115
|
+
#
|
116
|
+
def alias_to_id(target)
|
117
|
+
aliases = Inventory.load("alias")
|
118
|
+
if aliases[target]
|
119
|
+
return aliases[target]
|
120
|
+
end
|
121
|
+
target.is_a?(Numeric) ? target : target.downcase
|
122
|
+
end
|
123
123
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
124
|
+
def novel_frozen?(target)
|
125
|
+
id = Downloader.get_id_by_target(target) or return false
|
126
|
+
Inventory.load("freeze").include?(id)
|
127
|
+
end
|
128
128
|
|
129
|
-
|
130
|
-
|
131
|
-
|
129
|
+
def create_aozoraepub3_jar_path(*paths)
|
130
|
+
Pathname(File.expand_path(File.join(*paths, AOZORAEPUB3_JAR_NAME)))
|
131
|
+
end
|
132
132
|
|
133
|
-
|
134
|
-
|
135
|
-
|
133
|
+
def aozoraepub3_directory?(path)
|
134
|
+
create_aozoraepub3_jar_path(path).exist?
|
135
|
+
end
|
136
136
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
137
|
+
def parse_replace_txt(text)
|
138
|
+
pattern = []
|
139
|
+
text.each_line do |line|
|
140
|
+
line.sub!(/[\r\n]+\z/, "")
|
141
|
+
next if line[0] == ";" # コメント記号
|
142
|
+
pair = line.split("\t", 2)
|
143
|
+
if pair.length == 2 && pair[0]
|
144
|
+
pattern << pair
|
145
|
+
end
|
145
146
|
end
|
147
|
+
pattern
|
146
148
|
end
|
147
|
-
pattern
|
148
|
-
end
|
149
149
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
150
|
+
def write_replace_txt(path, pairs)
|
151
|
+
buffer = pairs.each_with_object("\t").map(&:join).join("\n")
|
152
|
+
File.write(path, buffer)
|
153
|
+
end
|
154
154
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
155
|
+
def load_global_replace_pattern
|
156
|
+
path = root_dir.join(GLOBAL_REPLACE_NAME)
|
157
|
+
pairs =
|
158
|
+
if path.exist?
|
159
|
+
Helper::CacheLoader.memo(path) do |text|
|
160
|
+
parse_replace_txt(text)
|
161
|
+
end
|
162
|
+
else
|
163
|
+
[]
|
161
164
|
end
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
@@global_replace_pattern_pairs = pairs
|
166
|
-
pairs
|
167
|
-
end
|
165
|
+
@@global_replace_pattern_pairs = pairs
|
166
|
+
pairs
|
167
|
+
end
|
168
168
|
|
169
|
-
|
170
|
-
|
171
|
-
|
169
|
+
def global_replace_pattern
|
170
|
+
@@global_replace_pattern_pairs ||= load_global_replace_pattern
|
171
|
+
end
|
172
172
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
173
|
+
def save_global_replace_pattern
|
174
|
+
path = root_dir.join(GLOBAL_REPLACE_NAME)
|
175
|
+
write_replace_txt(path, @@global_replace_pattern_pairs)
|
176
|
+
end
|
177
177
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
178
|
+
#
|
179
|
+
# AozoraEpub3 の実行ファイル(.jar)のフルパス取得
|
180
|
+
# 検索順序
|
181
|
+
# 1. グローバルセッティング (global_setting aozoraepub3dir)
|
182
|
+
# 2. 小説保存ディレクトリ(Narou.root_dir) 直下の AozoraEpub3
|
183
|
+
# 3. スクリプト保存ディレクトリ(Narou.script_dir) 直下の AozoraEpub3
|
184
|
+
#
|
185
|
+
def aozoraepub3_path
|
186
|
+
global_setting_aozora_path = Inventory.load("global_setting", :global)["aozoraepub3dir"]
|
187
|
+
if global_setting_aozora_path
|
188
|
+
aozora_jar_path = create_aozoraepub3_jar_path(global_setting_aozora_path)
|
189
|
+
if aozora_jar_path.exist?
|
190
|
+
return aozora_jar_path
|
191
|
+
end
|
191
192
|
end
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
return aozora_jar_path if aozora_jar_path.exist?
|
196
|
-
end
|
197
|
-
nil
|
198
|
-
end
|
199
|
-
memoize :aozoraepub3_path
|
200
|
-
|
201
|
-
#
|
202
|
-
# 書籍ファイル名を生成する
|
203
|
-
# convert.filename-to-ncode を設定している場合に novel_data に ncode、domain を
|
204
|
-
# 設定しない場合は id カラムが必須
|
205
|
-
#
|
206
|
-
def create_novel_filename(novel_data, ext = "")
|
207
|
-
filename_to_ncode = Inventory.load("local_setting")["convert.filename-to-ncode"]
|
208
|
-
novel_setting =
|
209
|
-
if novel_data["id"]
|
210
|
-
NovelSetting.load(novel_data["id"])
|
211
|
-
else
|
212
|
-
OpenStruct.new
|
193
|
+
[Narou.root_dir, Narou.script_dir].each do |dir|
|
194
|
+
aozora_jar_path = create_aozoraepub3_jar_path(dir, AOZORAEPUB3_DIR)
|
195
|
+
return aozora_jar_path if aozora_jar_path.exist?
|
213
196
|
end
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
197
|
+
nil
|
198
|
+
end
|
199
|
+
memoize :aozoraepub3_path
|
200
|
+
|
201
|
+
#
|
202
|
+
# 書籍ファイル名を生成する
|
203
|
+
# convert.filename-to-ncode を設定している場合に novel_data に ncode、domain を
|
204
|
+
# 設定しない場合は id カラムが必須
|
205
|
+
#
|
206
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
207
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
208
|
+
def create_novel_filename(novel_data, ext = "")
|
209
|
+
filename_to_ncode = Inventory.load("local_setting")["convert.filename-to-ncode"]
|
210
|
+
novel_setting =
|
211
|
+
if novel_data["id"]
|
212
|
+
NovelSetting.load(novel_data["id"])
|
213
|
+
else
|
214
|
+
OpenStruct.new
|
215
|
+
end
|
216
|
+
if novel_setting.output_filename.present?
|
217
|
+
%!#{novel_setting.output_filename}#{ext}!
|
218
|
+
elsif filename_to_ncode
|
219
|
+
ncode = novel_data["ncode"]
|
220
|
+
domain = novel_data["domain"]
|
221
|
+
if !ncode || !domain
|
222
|
+
id = novel_data["id"]
|
223
|
+
unless id
|
224
|
+
raise ArgumentError, %!novel_data["id"] を設定して下さい!
|
225
|
+
end
|
226
|
+
site_setting = Downloader.get_sitesetting_by_target(id)
|
227
|
+
ncode = site_setting["ncode"]
|
228
|
+
domain = site_setting["domain"]
|
222
229
|
end
|
223
|
-
|
224
|
-
ncode
|
225
|
-
|
230
|
+
serialized_domain = domain.to_s.gsub(".", "_")
|
231
|
+
%!#{serialized_domain}_#{ncode}#{ext}!
|
232
|
+
else
|
233
|
+
author = Helper.replace_filename_special_chars(
|
234
|
+
novel_setting.novel_author.presence || novel_data["author"],
|
235
|
+
true
|
236
|
+
)
|
237
|
+
title = Helper.replace_filename_special_chars(
|
238
|
+
novel_setting.novel_title.presence || novel_data["title"],
|
239
|
+
true
|
240
|
+
)
|
241
|
+
filename = "[#{author}] #{title}#{ext}"
|
242
|
+
length_limit = Inventory.load["ebook-filename-length-limit"]
|
243
|
+
length_limit ? Helper.truncate_path(filename, length_limit, extname: ext) : filename
|
226
244
|
end
|
227
|
-
serialized_domain = domain.to_s.gsub(".", "_")
|
228
|
-
%!#{serialized_domain}_#{ncode}#{ext}!
|
229
|
-
else
|
230
|
-
author = Helper.replace_filename_special_chars(
|
231
|
-
novel_setting.novel_author.presence || novel_data["author"],
|
232
|
-
true
|
233
|
-
)
|
234
|
-
title = Helper.replace_filename_special_chars(
|
235
|
-
novel_setting.novel_title.presence || novel_data["title"],
|
236
|
-
true
|
237
|
-
)
|
238
|
-
filename = "[#{author}] #{title}#{ext}"
|
239
|
-
length_limit = Inventory.load["ebook-filename-length-limit"]
|
240
|
-
length_limit ? Helper.truncate_path(filename, length_limit) : filename
|
241
245
|
end
|
242
|
-
|
246
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
247
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
243
248
|
|
244
|
-
|
245
|
-
|
246
|
-
|
249
|
+
def get_mobi_paths(target)
|
250
|
+
get_ebook_file_paths(target, ".mobi")
|
251
|
+
end
|
247
252
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
dir = Downloader.get_novel_data_dir_by_target(target)
|
252
|
-
fname = create_novel_filename(data, ext)
|
253
|
-
base = File.basename(fname, ext)
|
254
|
-
get_ebook_file_paths_from_components(dir, base, ext)
|
255
|
-
end
|
253
|
+
def get_ebook_file_paths(target, ext)
|
254
|
+
data = Downloader.get_data_by_target(target)
|
255
|
+
return nil unless data
|
256
256
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
paths.push(Pathname(path))
|
262
|
-
index += 1
|
257
|
+
dir = Downloader.get_novel_data_dir_by_target(target)
|
258
|
+
fname = create_novel_filename(data, ext)
|
259
|
+
base = File.basename(fname, ext)
|
260
|
+
get_ebook_file_paths_from_components(dir, base, ext)
|
263
261
|
end
|
264
|
-
paths
|
265
|
-
end
|
266
262
|
|
267
|
-
|
268
|
-
|
269
|
-
|
263
|
+
def get_ebook_file_paths_from_components(dir, base, ext)
|
264
|
+
paths = [File.join(dir, "#{base}#{ext}")]
|
265
|
+
index = 2
|
266
|
+
while File.exist?(path = File.join(dir, "#{base}_#{index}#{ext}"))
|
267
|
+
paths.push(Pathname(path))
|
268
|
+
index += 1
|
269
|
+
end
|
270
|
+
paths
|
271
|
+
end
|
272
|
+
|
273
|
+
def misc_dir
|
274
|
+
root_dir.join(MISC_DIR)
|
275
|
+
end
|
270
276
|
|
271
|
-
|
277
|
+
require_relative "device"
|
272
278
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
279
|
+
def get_device(device_name = nil)
|
280
|
+
device_name ||= Inventory.load("local_setting")["device"]
|
281
|
+
if device_name && Device.exists?(device_name)
|
282
|
+
return Device.create(device_name)
|
283
|
+
end
|
284
|
+
nil
|
277
285
|
end
|
278
|
-
nil
|
279
|
-
end
|
280
286
|
|
281
|
-
|
282
|
-
|
283
|
-
|
287
|
+
def web=(bool)
|
288
|
+
@@is_web = bool
|
289
|
+
end
|
284
290
|
|
285
|
-
|
286
|
-
|
287
|
-
|
291
|
+
def web?
|
292
|
+
@@is_web
|
293
|
+
end
|
288
294
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
295
|
+
def update_sort_key_summaries(left_space = 28)
|
296
|
+
summaries = { "KEY" => " 対象" }.merge(UPDATE_SORT_KEYS)
|
297
|
+
key_max_width = summaries.keys.max_by(&:length).length
|
298
|
+
summaries.map do |(key, summary)|
|
299
|
+
"#{" " * left_space}| #{key.center(key_max_width)} | #{summary}"
|
300
|
+
end.join("\n")
|
301
|
+
end
|
296
302
|
|
297
|
-
|
298
|
-
|
299
|
-
|
303
|
+
def theme
|
304
|
+
Inventory.load("local_setting")["webui.theme"]
|
305
|
+
end
|
300
306
|
|
301
|
-
|
302
|
-
|
303
|
-
|
307
|
+
def get_theme_dir(name = nil)
|
308
|
+
Pathname(File.join([script_dir, "lib/web/public/theme", name].compact))
|
309
|
+
end
|
304
310
|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
311
|
+
def theme_names
|
312
|
+
Dir.glob(get_theme_dir("*")).map do |path|
|
313
|
+
name = File.basename(path)
|
314
|
+
name == "fonts" ? nil : name
|
315
|
+
end.compact
|
316
|
+
end
|
317
|
+
memoize :theme_names
|
312
318
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
319
|
+
def economy?(mode)
|
320
|
+
eco_modes = Inventory.load("local_setting")["economy"].to_s.split(",").map(&:strip)
|
321
|
+
eco_modes.include?(mode)
|
322
|
+
end
|
317
323
|
|
318
|
-
|
319
|
-
|
320
|
-
|
324
|
+
def novel_type_text(type)
|
325
|
+
type == 2 ? "短編" : "連載"
|
326
|
+
end
|
321
327
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
328
|
+
#
|
329
|
+
# Narou.rb gem の最新バージョン番号を取得する
|
330
|
+
#
|
331
|
+
# rubygems公式APIによる取得は、WindowsでのSSL証明書問題で取得出来ない
|
332
|
+
# 環境があるため、gemコマンド経由で取得する
|
333
|
+
#
|
334
|
+
def latest_version
|
335
|
+
response = `gem search ^narou$`.split("\n")
|
336
|
+
if response.last =~ /\Anarou \(([0-9.]+).*?\)\z/
|
337
|
+
$1
|
338
|
+
end
|
332
339
|
end
|
333
|
-
end
|
334
340
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
341
|
+
def commit_version
|
342
|
+
cv_path = File.expand_path("commitversion", script_dir)
|
343
|
+
File.read(cv_path) if File.exist?(cv_path)
|
344
|
+
end
|
345
|
+
memoize :commit_version
|
340
346
|
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
347
|
+
def kindlegen_path
|
348
|
+
postfix = Helper.os_windows? ? ".exe" : ""
|
349
|
+
aozoraepub3_path.dirname.join("kindlegen#{postfix}")
|
350
|
+
end
|
351
|
+
memoize :kindlegen_path
|
346
352
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
353
|
+
def line_height(default: LINE_HEIGHT_DEFAULT)
|
354
|
+
global_setting = Inventory.load("global_setting", :global)
|
355
|
+
global_setting["line-height"] || default
|
356
|
+
end
|
351
357
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
358
|
+
def concurrency_enabled?
|
359
|
+
$stdout != $stdout2
|
360
|
+
end
|
361
|
+
memoize :concurrency_enabled?
|
356
362
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
363
|
+
# 同時実行が有効ならキューに積んで、無効なら普通に実行する
|
364
|
+
def concurrency_call(&block)
|
365
|
+
if concurrency_enabled?
|
366
|
+
Worker.push(&block)
|
367
|
+
EXIT_SUCCESS
|
368
|
+
else
|
369
|
+
block.call
|
370
|
+
end
|
364
371
|
end
|
365
372
|
end
|
366
|
-
end
|
367
373
|
end
|