narou 2.9.5 → 3.0.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 +7 -0
- data/.reek +34 -0
- data/.rspec +1 -0
- data/.rubocop.yml +9 -1
- data/ChangeLog.md +90 -0
- data/Gemfile +4 -0
- data/README.md +85 -8
- data/lib/command/convert.rb +1 -1
- data/lib/command/list.rb +59 -73
- data/lib/command/list/novel_decorator.rb +107 -0
- data/lib/command/send.rb +23 -13
- data/lib/command/setting.rb +5 -1
- data/lib/command/update.rb +104 -138
- data/lib/command/update/general_lastup_updater.rb +105 -0
- data/lib/command/update/interval.rb +29 -0
- data/lib/command/web.rb +1 -1
- data/lib/commandbase.rb +24 -17
- data/lib/converterbase.rb +10 -5
- data/lib/database.rb +16 -5
- data/lib/device.rb +5 -1
- data/lib/device/library/linux.rb +68 -8
- data/lib/downloader.rb +24 -23
- data/lib/extension.rb +16 -3
- data/lib/helper.rb +26 -3
- data/lib/html.rb +1 -1
- data/lib/inspector.rb +9 -0
- data/lib/inventory.rb +20 -6
- data/lib/logger.rb +8 -2
- data/lib/mailer.rb +2 -1
- data/lib/narou.rb +28 -18
- data/lib/narou/api.rb +62 -31
- data/lib/novelconverter.rb +8 -1
- data/lib/novelinfo.rb +8 -7
- data/lib/novelsetting.rb +1 -0
- data/lib/progressbar.rb +6 -2
- data/lib/sitesetting.rb +2 -1
- data/lib/version.rb +1 -1
- data/lib/web/appserver.rb +72 -9
- data/lib/web/public/resources/narou.library.js +130 -13
- data/lib/web/public/resources/narou.ui.js +96 -9
- data/lib/web/settingmessages.rb +2 -1
- data/lib/web/views/_about.haml +15 -2
- data/lib/web/views/index.haml +12 -3
- data/lib/web/views/layout.haml +2 -1
- data/lib/web/views/style.scss +12 -0
- data/narou.gemspec +88 -11
- data/narou.rb +7 -1
- data/preset/mail_setting.yaml +40 -6
- data/webnovel/kakuyomu.jp.yaml +8 -8
- metadata +95 -139
- data/spec/README.txt +0 -4
- data/spec/convert_spec.rb +0 -119
- data/spec/converterbase_spec.rb +0 -298
- data/spec/data/convert_test/auto_indent/correct_test_auto_indent.txt +0 -28
- data/spec/data/convert_test/auto_indent/test_auto_indent.txt +0 -32
- data/spec/data/convert_test/auto_join_bracket/correct_test_auto_join_bracket.txt +0 -24
- data/spec/data/convert_test/auto_join_bracket/test_auto_join_bracket.txt +0 -28
- data/spec/data/convert_test/auto_join_line/correct_test_auto_join_line.txt +0 -43
- data/spec/data/convert_test/auto_join_line/test_auto_join_line.txt +0 -59
- data/spec/data/convert_test/convert_page_break/correct_test_convert_page_break.txt +0 -22
- data/spec/data/convert_test/convert_page_break/setting.ini +0 -5
- data/spec/data/convert_test/convert_page_break/test_convert_page_break.txt +0 -60
- data/spec/data/convert_test/double_dash_to_image/correct_test_double_dash_to_image.txt +0 -14
- data/spec/data/convert_test/double_dash_to_image/setting.ini +0 -1
- data/spec/data/convert_test/double_dash_to_image/test_double_dash_to_image.txt +0 -12
- data/spec/data/convert_test/english/correct_test_english.txt +0 -27
- data/spec/data/convert_test/english/test_english.txt +0 -27
- data/spec/data/convert_test/force_indent_special_chapter/correct_test_force_indent_special_chapter.txt +0 -64
- data/spec/data/convert_test/force_indent_special_chapter/test_force_indent_special_chapter.txt +0 -61
- data/spec/data/convert_test/horizontal_ellipsis/correct_test_horizontal_ellipsis.txt +0 -53
- data/spec/data/convert_test/horizontal_ellipsis/test_horizontal_ellipsis.txt +0 -57
- data/spec/data/convert_test/insert_separator/correct_test_insert_separator.txt +0 -13
- data/spec/data/convert_test/insert_separator/setting.ini +0 -3
- data/spec/data/convert_test/insert_separator/test_insert_separator.txt +0 -12
- data/spec/data/convert_test/insert_separator_and_replace_txt/correct_test_insert_separator_and_replace_txt.txt +0 -12
- data/spec/data/convert_test/insert_separator_and_replace_txt/setting.ini +0 -3
- data/spec/data/convert_test/insert_separator_and_replace_txt/test_insert_separator_and_replace_txt.txt +0 -11
- data/spec/data/convert_test/kanji_num/correct_test_kanji_num.txt +0 -50
- data/spec/data/convert_test/kanji_num/test_kanji_num.txt +0 -56
- data/spec/data/convert_test/nonokagi/correct_test_nonokagi.txt +0 -30
- data/spec/data/convert_test/nonokagi/test_nonokagi.txt +0 -34
- data/spec/data/convert_test/replace/correct_test_replace.txt +0 -13
- data/spec/data/convert_test/replace/test_replace.txt +0 -14
- data/spec/data/convert_test/ruby/correct_test_ruby.txt +0 -161
- data/spec/data/convert_test/ruby/test_ruby.txt +0 -205
- data/spec/data/convert_test/ruby_youon/correct_test_ruby_youon.txt +0 -13
- data/spec/data/convert_test/ruby_youon/setting.ini +0 -2
- data/spec/data/convert_test/ruby_youon/test_ruby_youon.txt +0 -14
- data/spec/data/convert_test/sesame/correct_test_sesame.txt +0 -41
- data/spec/data/convert_test/sesame/test_sesame.txt +0 -52
- data/spec/data/convert_test/to_odd_leader/correct_test_to_odd_leader.txt +0 -21
- data/spec/data/convert_test/to_odd_leader/test_to_odd_leader.txt +0 -21
- data/spec/data/html_test.html +0 -5
- data/spec/data/html_test.txt +0 -4
- data/spec/data/test.ini +0 -10
- data/spec/device_spec.rb +0 -39
- data/spec/downloader_spec.rb +0 -37
- data/spec/eventable_spec.rb +0 -172
- data/spec/exit_code_spec.rb +0 -67
- data/spec/generator/convert_spec_gen.rb +0 -96
- data/spec/generator/num_to_kanji_test_gen.rb +0 -33
- data/spec/helper_spec.rb +0 -90
- data/spec/html_spec.rb +0 -83
- data/spec/ini_spec.rb +0 -145
- data/spec/input_spec.rb +0 -76
- data/spec/logger_spec.rb +0 -92
- data/spec/novelinfo_spec.rb +0 -15
- data/spec/novelsetting_spec.rb +0 -35
- data/spec/num_to_kanji_spec.rb +0 -2482
- data/spec/spec_helper.rb +0 -16
- data/spec/worker_spec.rb +0 -75
@@ -0,0 +1,105 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright 2013 whiteleaf. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
require_relative "../../narou/api"
|
7
|
+
|
8
|
+
module Command
|
9
|
+
class Update < CommandBase
|
10
|
+
class GeneralLastupUpdater
|
11
|
+
def initialize(options)
|
12
|
+
@options = options
|
13
|
+
@database = Database.instance
|
14
|
+
@narou_novels = Hash.new { |hash, key| hash[key] = [] }
|
15
|
+
@other_novels = []
|
16
|
+
prepare
|
17
|
+
end
|
18
|
+
|
19
|
+
def save
|
20
|
+
@database.save_database
|
21
|
+
end
|
22
|
+
|
23
|
+
def prepare
|
24
|
+
@database.each_key do |id|
|
25
|
+
next if Narou.novel_frozen?(id)
|
26
|
+
setting = Downloader.get_sitesetting_by_target(id)
|
27
|
+
if setting["narou_api_url"]
|
28
|
+
@narou_novels[setting["narou_api_url"]] << setting["ncode"]
|
29
|
+
else
|
30
|
+
@other_novels << id
|
31
|
+
end
|
32
|
+
setting.clear
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_narou_novels
|
37
|
+
@narou_novels.each do |api_url, ncodes|
|
38
|
+
api = Narou::API.new(api_url: api_url, ncodes: ncodes, of: "nu-gl")
|
39
|
+
api.request.each do |result|
|
40
|
+
ncode = result["ncode"]
|
41
|
+
data = Downloader.get_data_by_target(ncode)
|
42
|
+
last_check_date = data["last_check_date"] || data["last_update"]
|
43
|
+
if result["novelupdated_at"] > last_check_date
|
44
|
+
data["novelupdated_at"] = result["novelupdated_at"]
|
45
|
+
data["general_lastup"] = result["general_lastup"]
|
46
|
+
tags = data["tags"] ||= []
|
47
|
+
tags << Narou::MODIFIED_TAG unless tags.include?(Narou::MODIFIED_TAG)
|
48
|
+
end
|
49
|
+
data["last_check_date"] = Time.now
|
50
|
+
end
|
51
|
+
@other_novels += api.private_novels
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def update_other_novels
|
56
|
+
progressbar = ProgressBar.new(@other_novels.size - 1)
|
57
|
+
interval = Interval.new(@options["interval"])
|
58
|
+
|
59
|
+
@other_novels.each_with_index do |id, index|
|
60
|
+
progressbar.output(index)
|
61
|
+
interval.wait
|
62
|
+
begin
|
63
|
+
setting = Downloader.get_sitesetting_by_target(id)
|
64
|
+
info = NovelInfo.load(setting)
|
65
|
+
dates = if info
|
66
|
+
{
|
67
|
+
"novelupdated_at" => info["novelupdated_at"],
|
68
|
+
"general_lastup" => info["general_lastup"]
|
69
|
+
}
|
70
|
+
else
|
71
|
+
# 小説情報ページがない場合は目次から取得する
|
72
|
+
get_latest_dates(id)
|
73
|
+
end
|
74
|
+
rescue OpenURI::HTTPError, Errno::ECONNRESET
|
75
|
+
setting.clear
|
76
|
+
next
|
77
|
+
end
|
78
|
+
data = @database[id]
|
79
|
+
data.merge!(dates)
|
80
|
+
last_check_date = data["last_check_date"] || data["last_update"]
|
81
|
+
if data["novelupdated_at"] > last_check_date
|
82
|
+
tags = @database[id]["tags"] ||= []
|
83
|
+
tags << Narou::MODIFIED_TAG unless tags.include?(Narou::MODIFIED_TAG)
|
84
|
+
end
|
85
|
+
data["last_check_date"] = Time.now
|
86
|
+
setting.clear
|
87
|
+
end
|
88
|
+
ensure
|
89
|
+
progressbar.clear if progressbar
|
90
|
+
end
|
91
|
+
|
92
|
+
# オンラインの目次からgeneral_lastupを取得する
|
93
|
+
# ただし、toc.yaml に最新話が存在し、かつsubdateが設定されていたらそれを使う
|
94
|
+
def get_latest_dates(target)
|
95
|
+
downloader = Downloader.new(target)
|
96
|
+
old_toc = downloader.load_toc_file
|
97
|
+
downloader.get_latest_table_of_contents(old_toc, through_error: true)
|
98
|
+
{
|
99
|
+
"novelupdated_at" => downloader.get_novelupdated_at,
|
100
|
+
"general_lastup" => downloader.get_general_lastup
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright 2013 whiteleaf. All rights reserved.
|
4
|
+
#
|
5
|
+
|
6
|
+
module Command
|
7
|
+
class Update < CommandBase
|
8
|
+
class Interval
|
9
|
+
MIN = 2.5 # 作品間ウェイトの最低秒数(処理時間含む)
|
10
|
+
FORCE_WAIT_TIME = 2.0 # 強制待機時間
|
11
|
+
|
12
|
+
def initialize(interval)
|
13
|
+
@time = Time.now - MIN
|
14
|
+
interval = interval.to_f
|
15
|
+
@interval_time = interval >= MIN ? interval : MIN
|
16
|
+
end
|
17
|
+
|
18
|
+
def wait
|
19
|
+
wait_time = Time.now - @time
|
20
|
+
sleep(@interval_time - wait_time) if wait_time < @interval_time
|
21
|
+
@time = Time.now
|
22
|
+
end
|
23
|
+
|
24
|
+
def force_wait
|
25
|
+
sleep(FORCE_WAIT_TIME)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/command/web.rb
CHANGED
data/lib/commandbase.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
#
|
5
5
|
|
6
6
|
require "optparse"
|
7
|
+
require "termcolorlight"
|
7
8
|
require_relative "web/worker"
|
8
9
|
|
9
10
|
module Command
|
@@ -69,27 +70,33 @@ module Command
|
|
69
70
|
#
|
70
71
|
def tagname_to_ids(array)
|
71
72
|
database = Database.instance
|
72
|
-
tag_index =
|
73
|
-
database.
|
74
|
-
|
75
|
-
|
76
|
-
tag_index[tag] |= [id]
|
77
|
-
end
|
78
|
-
end
|
79
|
-
array.map! { |arg|
|
80
|
-
if arg =~ /^[0-9]+$/
|
73
|
+
tag_index = database.tag_indexies
|
74
|
+
all_ids = database.ids
|
75
|
+
expanded_array = array.map { |arg|
|
76
|
+
if arg =~ /\A\d+\z/
|
81
77
|
# 優先度はID>タグのため、数字のみ指定されたら
|
82
78
|
# そのIDが存在した場合はIDとみなす
|
83
|
-
|
84
|
-
|
85
|
-
if arg =~ /^tag:(.+)$/
|
86
|
-
# tag:タグ名 は直接タグと指定できる形式
|
87
|
-
# (数字タグとIDがかぶった場合にタグを指定出来るようにするもの)
|
88
|
-
arg = $1
|
79
|
+
id = arg.to_i
|
80
|
+
next id if database[id]
|
89
81
|
end
|
90
|
-
ids =
|
82
|
+
ids =
|
83
|
+
case arg
|
84
|
+
when /\Atag:(.+)\z/
|
85
|
+
# tag:タグ名 は直接タグと指定できる形式
|
86
|
+
# (数字タグとIDがかぶった場合にタグを指定出来るようにするもの)
|
87
|
+
arg = $1
|
88
|
+
tag_index[$1]
|
89
|
+
when /\A\^tag:(.+)\z/
|
90
|
+
# ^tag:タグ名 は除外タグ指定
|
91
|
+
arg = $1
|
92
|
+
indexies = tag_index[$1]
|
93
|
+
indexies.empty? ? [] : all_ids - indexies
|
94
|
+
else
|
95
|
+
tag_index[arg]
|
96
|
+
end
|
91
97
|
ids.empty? ? arg : ids
|
92
|
-
}.flatten
|
98
|
+
}.flatten.uniq
|
99
|
+
array.replace(expanded_array)
|
93
100
|
end
|
94
101
|
|
95
102
|
#
|
data/lib/converterbase.rb
CHANGED
@@ -345,7 +345,7 @@ class ConverterBase
|
|
345
345
|
data.replace(NKF.nkf("-wWX", data).tr("\u2014", "―"))
|
346
346
|
end
|
347
347
|
|
348
|
-
#
|
348
|
+
# ミニュート(ノノカギ)化する記号定義
|
349
349
|
SINGLE_MINUTE_FAMILY = %!‘’'!
|
350
350
|
DOUBLE_MINUTE_FAMILY = %!“”〝〟"!
|
351
351
|
|
@@ -353,11 +353,11 @@ class ConverterBase
|
|
353
353
|
# 半角記号を全角に変換
|
354
354
|
#
|
355
355
|
def symbols_to_zenkaku(data)
|
356
|
+
# MEMO: シングルミニュートを表示出来るフォントはほとんど無いためダブルにする
|
356
357
|
data.gsub!(/[#{SINGLE_MINUTE_FAMILY}]([^"\n]+?)[#{SINGLE_MINUTE_FAMILY}]/, "〝\\1〟")
|
357
|
-
# MEMO: シングルミュートを表示出来るフォントはほとんど無いためダブルにする
|
358
358
|
data.gsub!(/[#{DOUBLE_MINUTE_FAMILY}]([^"\n]+?)[#{DOUBLE_MINUTE_FAMILY}]/, "〝\\1〟")
|
359
359
|
data.tr!("-=+/*《》'\"%$#&!?<><>()|‐,._;:\[\]{}",
|
360
|
-
"
|
360
|
+
"-=+/*≪≫’〝%$#&!?〈〉〈〉()|-,._;:[]{}")
|
361
361
|
data.gsub!("\\", "¥")
|
362
362
|
data
|
363
363
|
end
|
@@ -484,6 +484,7 @@ class ConverterBase
|
|
484
484
|
# たまに見かける誤字対策
|
485
485
|
data.gsub!(/。 /, "。")
|
486
486
|
data.gsub!(/([?!])。/, "\\1")
|
487
|
+
data.gsub!(/([?!])、/, "\\1")
|
487
488
|
end
|
488
489
|
|
489
490
|
#
|
@@ -1416,6 +1417,10 @@ class ConverterBase
|
|
1416
1417
|
|
1417
1418
|
def double_dash_to_image(text, output_text_dir)
|
1418
1419
|
return text unless @setting.enable_double_dash_to_image
|
1420
|
+
# サブタイトルの中の場合は無視する
|
1421
|
+
# (サブタイトルは文字を大きくしているので、画像の位置がずれてしまうため)
|
1422
|
+
return text if @text_type == "subtitle"
|
1423
|
+
|
1419
1424
|
begin
|
1420
1425
|
# AozoraEpub3 は相対パスじゃないとエラーになるので相対パスに変換
|
1421
1426
|
dash_paths = dash_image_relative_paths(Narou.get_preset_dir, output_text_dir)
|
@@ -1425,7 +1430,7 @@ class ConverterBase
|
|
1425
1430
|
# 違う場合、相対パスを計算できなくなる。そのための対処として、.narou ディレクトリ
|
1426
1431
|
# に画像データをコピーし、同一ドライブ内で相対パスを取れるようにする
|
1427
1432
|
copy_dash_images_to_local_setting_dir
|
1428
|
-
dash_paths = dash_image_relative_paths(Narou.
|
1433
|
+
dash_paths = dash_image_relative_paths(Narou.local_setting_dir, output_text_dir)
|
1429
1434
|
else
|
1430
1435
|
raise
|
1431
1436
|
end
|
@@ -1449,7 +1454,7 @@ class ConverterBase
|
|
1449
1454
|
|
1450
1455
|
def copy_dash_images_to_local_setting_dir
|
1451
1456
|
DASH_FILES.each do |name|
|
1452
|
-
path = File.join(Narou.
|
1457
|
+
path = File.join(Narou.local_setting_dir, name)
|
1453
1458
|
unless File.exist?(path)
|
1454
1459
|
FileUtils.copy(File.join(Narou.get_preset_dir, name), path)
|
1455
1460
|
end
|
data/lib/database.rb
CHANGED
@@ -15,10 +15,6 @@ class Database
|
|
15
15
|
ARCHIVE_ROOT_DIR_PATH = "小説データ/"
|
16
16
|
DATABASE_NAME = "database"
|
17
17
|
|
18
|
-
if Narou.already_init?
|
19
|
-
@@archive_root_path = File.expand_path(File.join(Narou.get_root_dir, ARCHIVE_ROOT_DIR_PATH))
|
20
|
-
end
|
21
|
-
|
22
18
|
def [](key)
|
23
19
|
@database[key]
|
24
20
|
end
|
@@ -69,7 +65,7 @@ class Database
|
|
69
65
|
# 小説格納用のルートディレクトリを取得
|
70
66
|
#
|
71
67
|
def self.archive_root_path
|
72
|
-
|
68
|
+
@archive_root_path ||= File.expand_path(File.join(Narou.get_root_dir, ARCHIVE_ROOT_DIR_PATH))
|
73
69
|
end
|
74
70
|
|
75
71
|
def save_database
|
@@ -80,6 +76,10 @@ class Database
|
|
80
76
|
@database
|
81
77
|
end
|
82
78
|
|
79
|
+
def ids
|
80
|
+
@database.keys
|
81
|
+
end
|
82
|
+
|
83
83
|
def novel_exists?(id)
|
84
84
|
return nil if id.nil?
|
85
85
|
@database.keys.include?(id.to_i)
|
@@ -114,4 +114,15 @@ class Database
|
|
114
114
|
values
|
115
115
|
end
|
116
116
|
end
|
117
|
+
|
118
|
+
def tag_indexies
|
119
|
+
result = Hash.new { [] }
|
120
|
+
@database.each do |id, data|
|
121
|
+
tags = data["tags"] || []
|
122
|
+
tags.each do |tag|
|
123
|
+
result[tag.to_s] |= [id]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
result
|
127
|
+
end
|
117
128
|
end
|
data/lib/device.rb
CHANGED
@@ -104,7 +104,11 @@ class Device
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def ejectable?
|
107
|
-
Device.
|
107
|
+
if Device.respond_to?(:ejectable?)
|
108
|
+
Device.ejectable?(@device_module::VOLUME_NAME)
|
109
|
+
else
|
110
|
+
Device.support_eject? && connecting?
|
111
|
+
end
|
108
112
|
end
|
109
113
|
|
110
114
|
def find_documents_directory(device_root_dir)
|
data/lib/device/library/linux.rb
CHANGED
@@ -2,17 +2,77 @@
|
|
2
2
|
#
|
3
3
|
# Copyright 2013 whiteleaf. All rights reserved.
|
4
4
|
#
|
5
|
+
# rubocop:disable Lint/AssignmentInCondition
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
require "etc"
|
8
|
+
|
9
|
+
class Device
|
10
|
+
module Library
|
11
|
+
module Linux
|
12
|
+
username = Etc.getpwuid(Process.euid).name
|
13
|
+
@@mount_roots = %w(/media /mnt)
|
14
|
+
@@mount_roots << "/run/media/" + username # udisks2 による自動マウント(デフォルトの場所)
|
15
|
+
@@mount_roots << "/media/" + username # udisks2 による自動マウント(Ubuntuの場合)
|
16
|
+
|
17
|
+
# :reek:UtilityFunction
|
18
|
+
def get_device_root_dir(volume_name)
|
19
|
+
@@mount_roots.each do |mount_root|
|
20
|
+
path = File.join(mount_root, volume_name)
|
21
|
+
if File.directory?(path)
|
22
|
+
return path
|
23
|
+
end
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# 端末のデバイスファイル名と uhelper オプションの値を取得
|
29
|
+
def device_mount_info(volume_name)
|
30
|
+
device_root = get_device_root_dir(volume_name)
|
31
|
+
raise Device::CantEject, "端末が接続されていません" unless device_root
|
32
|
+
|
33
|
+
pattern = %r!^(/dev/[^ ]+) .* #{device_root} .*\Wuhelper=(\w+)!
|
34
|
+
open("|mount") do |io|
|
35
|
+
while line = io.gets
|
36
|
+
if line =~ pattern
|
37
|
+
return [$1, $2]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
[nil, nil]
|
42
|
+
end
|
43
|
+
|
44
|
+
def ejectable?(volume_name)
|
45
|
+
case device_mount_info(volume_name)[1]
|
46
|
+
when "udisks", "udisks2"
|
47
|
+
true
|
48
|
+
else
|
49
|
+
false
|
50
|
+
end
|
51
|
+
rescue Device::CantEject
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
def eject(volume_name)
|
56
|
+
device, uhelper = device_mount_info(volume_name)
|
57
|
+
|
58
|
+
case uhelper
|
59
|
+
when "udisks"
|
60
|
+
commands = ["udisks --unmount #{device}",
|
61
|
+
"udisks --detach #{device.chop}"]
|
62
|
+
when "udisks2"
|
63
|
+
commands = ["udisksctl unmount -b #{device} --no-user-interaction",
|
64
|
+
"udisksctl power-off -b #{device.chop} --no-user-interaction"]
|
65
|
+
else
|
66
|
+
raise Device::CantEject, "udisks または udisks2 によって自動マウントされたデバイスではありません。"
|
67
|
+
end
|
68
|
+
|
69
|
+
commands.each do |command|
|
70
|
+
status, _stdout, stderr = systemu(command)
|
71
|
+
unless status.success?
|
72
|
+
raise Device::CantEject, "#{command}: #{stderr.strip}"
|
73
|
+
end
|
13
74
|
end
|
14
75
|
end
|
15
|
-
nil
|
16
76
|
end
|
17
77
|
end
|
18
78
|
end
|
data/lib/downloader.rb
CHANGED
@@ -13,7 +13,6 @@ require_relative "template"
|
|
13
13
|
require_relative "database"
|
14
14
|
require_relative "inventory"
|
15
15
|
require_relative "eventable"
|
16
|
-
require_relative "narou/api"
|
17
16
|
require_relative "html"
|
18
17
|
require_relative "input"
|
19
18
|
|
@@ -214,10 +213,17 @@ class Downloader
|
|
214
213
|
#
|
215
214
|
# 小説サイトの定義ファイルを全部読み込む
|
216
215
|
#
|
216
|
+
# スクリプト同梱の設定ファイルを読み込んだあと、ユーザの小説の管理ディレクトリ内にある
|
217
|
+
# webnovel ディレクトリからも定義ファイルを読み込む
|
218
|
+
#
|
217
219
|
def self.load_settings
|
218
220
|
settings = @@__settings_cache ||= []
|
219
221
|
return settings unless settings.empty?
|
220
|
-
|
222
|
+
load_paths = [
|
223
|
+
File.join(Narou.get_script_dir, NOVEL_SITE_SETTING_DIR, "*.yaml"),
|
224
|
+
File.join(Narou.get_root_dir, NOVEL_SITE_SETTING_DIR, "*.yaml")
|
225
|
+
].join("\0")
|
226
|
+
Dir.glob(load_paths) do |path|
|
221
227
|
setting = SiteSetting.load_file(path)
|
222
228
|
if setting["name"] == "小説家になろう"
|
223
229
|
@@narou = setting
|
@@ -261,7 +267,8 @@ class Downloader
|
|
261
267
|
# サブディレクトリ名を生成
|
262
268
|
#
|
263
269
|
def self.create_subdirecotry_name(title)
|
264
|
-
title.start_with?("n") ? title[1..2] : title[0..1]
|
270
|
+
name = title.start_with?("n") ? title[1..2] : title[0..1]
|
271
|
+
name.strip
|
265
272
|
end
|
266
273
|
|
267
274
|
if Narou.already_init?
|
@@ -364,6 +371,7 @@ class Downloader
|
|
364
371
|
def run_download
|
365
372
|
old_toc = @new_novel ? nil : load_toc_file
|
366
373
|
latest_toc = get_latest_table_of_contents(old_toc)
|
374
|
+
latest_toc_subtitles = latest_toc["subtitles"]
|
367
375
|
unless latest_toc
|
368
376
|
@stream.error @setting["toc_url"] + " の目次データが取得出来ませんでした"
|
369
377
|
return :failed
|
@@ -381,12 +389,12 @@ class Downloader
|
|
381
389
|
end
|
382
390
|
init_raw_dir
|
383
391
|
if old_toc.empty? || @force
|
384
|
-
update_subtitles =
|
392
|
+
update_subtitles = latest_toc_subtitles
|
385
393
|
else
|
386
|
-
update_subtitles = update_body_check(old_toc["subtitles"],
|
394
|
+
update_subtitles = update_body_check(old_toc["subtitles"], latest_toc_subtitles)
|
387
395
|
end
|
388
396
|
|
389
|
-
if old_toc.empty? && update_subtitles.
|
397
|
+
if old_toc.empty? && update_subtitles.size.zero?
|
390
398
|
@stream.error "#{@setting['title']} の目次がありません"
|
391
399
|
return :failed
|
392
400
|
end
|
@@ -414,7 +422,7 @@ class Downloader
|
|
414
422
|
end
|
415
423
|
update_database
|
416
424
|
:ok
|
417
|
-
when old_toc["subtitles"].size >
|
425
|
+
when old_toc["subtitles"].size > latest_toc_subtitles.size
|
418
426
|
# 削除された節がある(かつ更新がない)場合
|
419
427
|
@stream.puts "#{id_and_title} は一部の話が削除されています"
|
420
428
|
:ok
|
@@ -430,6 +438,9 @@ class Downloader
|
|
430
438
|
else
|
431
439
|
:none
|
432
440
|
end
|
441
|
+
|
442
|
+
@@database[@id]["general_all_no"] = latest_toc_subtitles.size
|
443
|
+
|
433
444
|
save_novel_data(TOC_FILE_NAME, latest_toc)
|
434
445
|
tags = @new_novel ? [] : @@database[@id]["tags"] || []
|
435
446
|
if novel_end?
|
@@ -628,11 +639,7 @@ class Downloader
|
|
628
639
|
end
|
629
640
|
|
630
641
|
def get_novel_status
|
631
|
-
novel_status =
|
632
|
-
Narou::API.new(@setting, "nt-e")
|
633
|
-
else
|
634
|
-
NovelInfo.load(@setting)
|
635
|
-
end
|
642
|
+
novel_status = NovelInfo.load(@setting, of: "nt-e")
|
636
643
|
unless novel_status
|
637
644
|
novel_status = {
|
638
645
|
"novel_type" => NOVEL_TYPE_SERIES,
|
@@ -687,7 +694,7 @@ class Downloader
|
|
687
694
|
#
|
688
695
|
def get_title
|
689
696
|
return @title if @title
|
690
|
-
@title = @setting["title"]
|
697
|
+
@title = @setting["title"] || @@database[@id]["title"]
|
691
698
|
if @setting["title_strip_pattern"]
|
692
699
|
@title = @title.gsub(/#{@setting["title_strip_pattern"]}/, "").gsub(/^[ \s]*(.+?)[ \s]*?$/, "\\1")
|
693
700
|
end
|
@@ -736,7 +743,7 @@ class Downloader
|
|
736
743
|
@setting = s
|
737
744
|
toc_url = @setting["toc_url"]
|
738
745
|
end
|
739
|
-
toc_source = Helper.
|
746
|
+
toc_source = Helper.restore_entity(Helper.pretreatment_source(toc_fp.read, @setting["encoding"]))
|
740
747
|
raise DownloaderNotFoundError if Downloader.detect_error_message(@setting, toc_source)
|
741
748
|
end
|
742
749
|
rescue DownloaderForceRedirect
|
@@ -757,13 +764,7 @@ class Downloader
|
|
757
764
|
toc_source = get_toc_source
|
758
765
|
return nil unless toc_source
|
759
766
|
@setting.multi_match(toc_source, "tcode")
|
760
|
-
|
761
|
-
if false
|
762
|
-
# なろうAPIの出力がおかしいので直るまで使用中止
|
763
|
-
info = Narou::API.new(@setting, "t-s-gf-gl-nu-w")
|
764
|
-
else
|
765
|
-
info = NovelInfo.load(@setting, toc_source)
|
766
|
-
end
|
767
|
+
info = NovelInfo.load(@setting, toc_source: toc_source)
|
767
768
|
if info
|
768
769
|
raise DownloaderNotFoundError unless info["title"]
|
769
770
|
@setting["title"] = info["title"]
|
@@ -1089,7 +1090,7 @@ class Downloader
|
|
1089
1090
|
end
|
1090
1091
|
raw = download_raw_data(subtitle_url)
|
1091
1092
|
if @setting["is_narou"]
|
1092
|
-
raw = Helper.
|
1093
|
+
raw = Helper.restore_entity(raw)
|
1093
1094
|
save_raw_data(raw, subtitle_info)
|
1094
1095
|
element = extract_elements_in_section(raw, subtitle_info["subtitle"])
|
1095
1096
|
element["data_type"] = "text"
|
@@ -1136,7 +1137,7 @@ narou s download.wait-steps=5
|
|
1136
1137
|
cookie = @setting["cookie"] || ""
|
1137
1138
|
begin
|
1138
1139
|
open_uri_options = make_open_uri_options("Cookie" => cookie, allow_redirections: :safe)
|
1139
|
-
open(url, open_uri_options) do |fp|
|
1140
|
+
open(url, "r:#{@setting["encoding"]}", open_uri_options) do |fp|
|
1140
1141
|
raw = Helper.pretreatment_source(fp.read, @setting["encoding"])
|
1141
1142
|
end
|
1142
1143
|
rescue OpenURI::HTTPError => e
|