Module: Narou

Extended by:
Memoist, Mixin::Locker
Defined in:
lib/version.rb,
lib/input.rb,
lib/narou.rb,
lib/worker.rb,
lib/narou/api.rb,
lib/backtracer.rb,
lib/mixin/locker.rb,
lib/narou_logger.rb,
lib/web/pushserver.rb,
lib/web/web_worker.rb,
lib/mixin/output_error.rb,
lib/web/streaminginput.rb,
lib/web/settingmessages.rb,
lib/web/streaminglogger.rb,
lib/extensions/monkey_patches/pathname.rb

Overview

標準出力をフックする

$stdout を介した出力は echo イベントとして全てのクライアントへ送信される

Defined Under Namespace

Modules: Backtracer, Eventable, Input, LoggerModule, Mixin, MonkyPatches, ServerHelpers Classes: API, AppServer, ConcurrencyConvertLogger, ConcurrencyDefaultLogger, Logger, LoggerError, NullIO, PushServer, StreamingLogger, WebWorker, Worker

Constant Summary collapse

LOCAL_SETTING_DIR_NAME =
".narou"
GLOBAL_SETTING_DIR_NAME =
".narousetting"
AOZORAEPUB3_JAR_NAME =
"AozoraEpub3.jar"
AOZORAEPUB3_DIR =
"AozoraEpub3"
PRESET_DIR =
"preset"
MISC_DIR =
"misc"
LOG_DIR =
"log"
GLOBAL_REPLACE_NAME =
"replace.txt"
EXIT_SUCCESS =
0
EXIT_ERROR_CODE =
127
EXIT_INTERRUPT =
126
EXIT_REQUEST_REBOOT =
125
MODIFIED_TAG =
"modified"
LINE_HEIGHT_DEFAULT =

単位em

1.6
UPDATE_SORT_KEYS =
{
  "id" => "ID", "last_update" => "更新日", "title" => "タイトル", "author" => "作者名",
  "new_arrivals_date" => "新着日", "general_lastup" => "最新話掲載日"
}
VERSION =
"3.4.7.1"
SETTING_VARIABLES_WEBUI_MESSAGES =

WEB UI > 環境設定画面で表示する各項目の説明 ここになければ元々の説明が表示される

{
  "convert.multi-device" => "複数の端末用に同時に変換する。deviceよりも優先される。\nただのEPUBを出力したい場合はepubを指定",
  "device" => "変換、送信対象の端末",
  "difftool" => "%%ORIG%%。※WEB UIでは使われません",
  "update.sort-by" => "アップデートを指定した項目順で行う",
  "default.title_date_align" => "enable_add_date_to_title で付与する日付の位置",
  "force.title_date_align" => "enable_add_date_to_title で付与する日付の位置",
  "difftool.arg" => "difftoolで使う引数(指定しなければ単純に新旧ファイルを引数に呼び出す)\n" \
                    "特殊な変数\n" \
                    "<b>%NEW</b> : 最新データの差分用ファイルパス\n" \
                    "<b>%OLD</b> : 古い方の差分用ファイルパス",
  "no-color" => "コンソールのカラー表示を無効にする\n※要サーバ再起動",
  "economy" => "容量節約に関する設定",
  "send.without-freeze" => "一括送信時に凍結された小説は対象外にする。(個別送信時は凍結済みでも送信可能)",
  "server-digest-auth.enable" => "%%ORIG%%\n※digest-auth関連の設定を変更した場合サーバの再起動が必要",
  "server-digest-auth.hashed-password" => "サーバのDigest認証のパスワードを、Realmを\"narou.rb\"としてハッシュにしたもの。\n" \
                                          "https://tgws.plus/app/digest/ などで生成できる",
  "concurrency" => "%%ORIG%% ※要サーバ再起動",
  "logging" => "%%ORIG%%\n※要サーバ再起動",
  "logging.format-filename" => "%%ORIG%%\n※要サーバ再起動",
  "logging.format-timestamp" => "%%ORIG%%\n※要サーバ再起動",
}
@@is_web =
false

Class Method Summary collapse

Methods included from Mixin::Locker

lock, locked?, unlock

Class Method Details

.alias_to_id(target) ⇒ Object

target が alias だった場合はIDに変換する

全てのtarget照合系はこのメソッドを通過するので、ここで小文字にしてしまう



116
117
118
119
120
121
122
# File 'lib/narou.rb', line 116

def alias_to_id(target)
  aliases = Inventory.load("alias")
  if aliases[target]
    return aliases[target]
  end
  target.kind_of?(Numeric) ? target : target.downcase
end

.already_init?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/narou.rb', line 100

def already_init?
  root_dir.present?
end

.aozoraepub3_directory?(path) ⇒ Boolean

Returns:

  • (Boolean)


133
134
135
# File 'lib/narou.rb', line 133

def aozoraepub3_directory?(path)
  create_aozoraepub3_jar_path(path).exist?
end

.aozoraepub3_pathObject

AozoraEpub3 の実行ファイル(.jar)のフルパス取得 検索順序

  1. グローバルセッティング (global_setting aozoraepub3dir)

  2. 小説保存ディレクトリ(Narou.root_dir) 直下の AozoraEpub3

  3. スクリプト保存ディレクトリ(Narou.script_dir) 直下の AozoraEpub3



185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/narou.rb', line 185

def aozoraepub3_path
  global_setting_aozora_path = Inventory.load("global_setting", :global)["aozoraepub3dir"]
  if global_setting_aozora_path
    aozora_jar_path = create_aozoraepub3_jar_path(global_setting_aozora_path)
    if aozora_jar_path.exist?
      return aozora_jar_path
    end
  end
  [Narou.root_dir, Narou.script_dir].each do |dir|
    aozora_jar_path = create_aozoraepub3_jar_path(dir, AOZORAEPUB3_DIR)
    return aozora_jar_path if aozora_jar_path.exist?
  end
  nil
end

.commit_versionObject



335
336
337
338
# File 'lib/narou.rb', line 335

def commit_version
  cv_path = File.expand_path("commitversion", script_dir)
  File.read(cv_path) if File.exist?(cv_path)
end

.concurrency_call(&block) ⇒ Object

同時実行が有効ならキューに積んで、無効なら普通に実行する



358
359
360
361
362
363
364
365
# File 'lib/narou.rb', line 358

def concurrency_call(&block)
  if concurrency_enabled?
    Worker.push(&block)
    EXIT_SUCCESS
  else
    block.call
  end
end

.concurrency_enabled?Boolean

Returns:

  • (Boolean)


352
353
354
# File 'lib/narou.rb', line 352

def concurrency_enabled?
  $stdout != $stdout2
end

.create_aozoraepub3_jar_path(*paths) ⇒ Object



129
130
131
# File 'lib/narou.rb', line 129

def create_aozoraepub3_jar_path(*paths)
  Pathname(File.expand_path(File.join(*paths, AOZORAEPUB3_JAR_NAME)))
end

.create_novel_filename(novel_data, ext = "") ⇒ Object

書籍ファイル名を生成する convert.filename-to-ncode を設定している場合に novel_data に ncode、domain を 設定しない場合は id カラムが必須



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/narou.rb', line 206

def create_novel_filename(novel_data, ext = "")
  filename_to_ncode = Inventory.load("local_setting")["convert.filename-to-ncode"]
  novel_setting =
    if novel_data["id"]
      NovelSetting.load(novel_data["id"])
    else
      OpenStruct.new
    end
  if novel_setting.output_filename.present?
    %!#{novel_setting.output_filename}#{ext}!
  elsif filename_to_ncode
    ncode, domain = novel_data["ncode"], novel_data["domain"]
    if !ncode || !domain
      id = novel_data["id"]
      unless id
        raise ArgumentError, %!novel_data["id"] を設定して下さい!
      end
      site_setting = Downloader.get_sitesetting_by_target(id)
      ncode = site_setting["ncode"]
      domain = site_setting["domain"]
    end
    serialized_domain = domain.to_s.gsub(".", "_")
    %!#{serialized_domain}_#{ncode}#{ext}!
  else
    author = Helper.replace_filename_special_chars(
      novel_setting.novel_author.presence || novel_data["author"],
      true
    )
    title = Helper.replace_filename_special_chars(
      novel_setting.novel_title.presence || novel_data["title"],
      true
    )
    filename = "[#{author}] #{title}#{ext}"
    length_limit = Inventory.load["ebook-filename-length-limit"]
    length_limit ? Helper.truncate_path(filename, length_limit) : filename
  end
end

.economy?(mode) ⇒ Boolean

Returns:

  • (Boolean)


313
314
315
316
# File 'lib/narou.rb', line 313

def economy?(mode)
  eco_modes = Inventory.load("local_setting")["economy"].to_s.split(",").map(&:strip)
  eco_modes.include?(mode)
end

.get_device(device_name = nil) ⇒ Object



273
274
275
276
277
278
279
# File 'lib/narou.rb', line 273

def get_device(device_name = nil)
  device_name = Inventory.load("local_setting")["device"] unless device_name
  if device_name && Device.exists?(device_name)
    return Device.create(device_name)
  end
  nil
end

.get_ebook_file_paths(target, ext) ⇒ Object



248
249
250
251
252
253
254
255
# File 'lib/narou.rb', line 248

def get_ebook_file_paths(target, ext)
  data = Downloader.get_data_by_target(target)
  return nil unless data
  dir = Downloader.get_novel_data_dir_by_target(target)
  fname = create_novel_filename(data, ext)
  base = File.basename(fname, ext)
  get_ebook_file_paths_from_components(dir, base, ext)
end

.get_ebook_file_paths_from_components(dir, base, ext) ⇒ Object



257
258
259
260
261
262
263
264
265
# File 'lib/narou.rb', line 257

def get_ebook_file_paths_from_components(dir, base, ext)
  paths = [File.join(dir, "#{base}#{ext}")]
  index = 2
  while File.exist?(path = File.join(dir, "#{base}_#{index}#{ext}"))
    paths.push(Pathname(path))
    index += 1
  end
  paths
end

.get_mobi_paths(target) ⇒ Object



244
245
246
# File 'lib/narou.rb', line 244

def get_mobi_paths(target)
  get_ebook_file_paths(target, ".mobi")
end

.get_themeObject



297
298
299
# File 'lib/narou.rb', line 297

def get_theme
  Inventory.load("local_setting")["webui.theme"]
end

.get_theme_dir(name = nil) ⇒ Object



301
302
303
# File 'lib/narou.rb', line 301

def get_theme_dir(name = nil)
  Pathname(File.join([script_dir, "lib/web/public/theme", name].compact))
end

.get_theme_namesObject



305
306
307
308
309
310
# File 'lib/narou.rb', line 305

def get_theme_names
  Dir.glob(get_theme_dir("*")).map do |path|
    name = File.basename(path)
    name == "fonts" ? nil : name
  end.compact
end

.global_replace_patternObject



169
170
171
# File 'lib/narou.rb', line 169

def global_replace_pattern
  @@global_replace_pattern_pairs ||= load_global_replace_pattern
end

.global_setting_dirObject



75
76
77
78
79
80
81
82
83
# File 'lib/narou.rb', line 75

def global_setting_dir
  if root_dir
    dir = root_dir.join(GLOBAL_SETTING_DIR_NAME)
    return dir if dir.directory?
  end
  dir = Pathname(GLOBAL_SETTING_DIR_NAME).expand_path("~")
  dir.mkdir unless dir.exist?
  dir
end

.initObject



104
105
106
107
108
109
# File 'lib/narou.rb', line 104

def init
  return nil if already_init?
  FileUtils.mkdir(LOCAL_SETTING_DIR_NAME)
  puts "#{LOCAL_SETTING_DIR_NAME}/ を作成しました"
  Database.init
end

.kindlegen_pathObject



341
342
343
344
# File 'lib/narou.rb', line 341

def kindlegen_path
  postfix = Helper.os_windows? ? ".exe" : ""
  aozoraepub3_path.dirname.join("kindlegen#{postfix}")
end

.last_commit_yearObject



46
47
48
# File 'lib/narou.rb', line 46

def last_commit_year
  2019
end

.latest_versionObject

Narou.rb gem の最新バージョン番号を取得する

rubygems公式APIによる取得は、WindowsでのSSL証明書問題で取得出来ない 環境があるため、gemコマンド経由で取得する



328
329
330
331
332
333
# File 'lib/narou.rb', line 328

def latest_version
  response = `gem search ^narou$`.split("\n")
  if response.last =~ /\Anarou \(([0-9.]+).*?\)\z/
    $1
  end
end

.line_height(default: LINE_HEIGHT_DEFAULT) ⇒ Object



347
348
349
350
# File 'lib/narou.rb', line 347

def line_height(default: LINE_HEIGHT_DEFAULT)
  global_setting = Inventory.load("global_setting", :global)
  global_setting["line-height"] || default
end

.load_global_replace_patternObject



155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/narou.rb', line 155

def load_global_replace_pattern
  path = root_dir.join(GLOBAL_REPLACE_NAME)
  pairs =
    if path.exist?
      Helper::CacheLoader.memo(path) do |text|
        parse_replace_txt(text)
      end
    else
      []
    end
  @@global_replace_pattern_pairs = pairs
  pairs
end

.local_setting_dirObject



70
71
72
# File 'lib/narou.rb', line 70

def local_setting_dir
  root_dir&.join(LOCAL_SETTING_DIR_NAME)
end

.log_dirObject



91
92
93
# File 'lib/narou.rb', line 91

def log_dir
  root_dir&.join(LOG_DIR)
end

.misc_dirObject



267
268
269
# File 'lib/narou.rb', line 267

def misc_dir
  root_dir.join(MISC_DIR)
end

.novel_frozen?(target) ⇒ Boolean

Returns:

  • (Boolean)


124
125
126
127
# File 'lib/narou.rb', line 124

def novel_frozen?(target)
  id = Downloader.get_id_by_target(target) or return false
  Inventory.load("freeze").include?(id)
end

.novel_type_text(type) ⇒ Object



318
319
320
# File 'lib/narou.rb', line 318

def novel_type_text(type)
  type == 2 ? "短編" : "連載"
end

.parse_replace_txt(text) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/narou.rb', line 137

def parse_replace_txt(text)
  pattern = []
  text.each_line do |line|
    line.sub!(/[\r\n]+\z/, "")
    next if line[0] == ";"    # コメント記号
    pair = line.split("\t", 2)
    if pair.length == 2 && pair[0]
      pattern << pair
    end
  end
  pattern
end

.preset_dirObject



95
96
97
# File 'lib/narou.rb', line 95

def preset_dir
  script_dir&.join(PRESET_DIR)
end

.root_dirObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/narou.rb', line 50

def root_dir
  root = nil
  path = Dir.pwd
  drive_letter = ""
  if Helper.os_windows?
    path.encode!(Encoding::UTF_8)
    path.gsub!(/^[a-z]:/i, "")
    drive_letter = $&
  end
  while path != ""
    if File.directory?("#{drive_letter}#{path}/#{LOCAL_SETTING_DIR_NAME}")
      root = drive_letter + path
      break
    end
    path.gsub!(%r!/[^/]*$!, "")
  end
  Pathname(root) if root
end

.save_global_replace_patternObject



173
174
175
176
# File 'lib/narou.rb', line 173

def save_global_replace_pattern
  path = root_dir.join(GLOBAL_REPLACE_NAME)
  write_replace_txt(path, @@global_replace_pattern_pairs)
end

.script_dirObject



86
87
88
# File 'lib/narou.rb', line 86

def script_dir
  Pathname(__dir__).join("..").expand_path
end

.update_sort_key_summaries(left_space = 28) ⇒ Object



289
290
291
292
293
294
295
# File 'lib/narou.rb', line 289

def update_sort_key_summaries(left_space = 28)
  summaries = { "KEY" => "   対象" }.merge(UPDATE_SORT_KEYS)
  key_max_width = summaries.keys.max_by(&:length).length
  summaries.map do |(key, summary)|
    "#{" " * left_space}| #{key.center(key_max_width)} | #{summary}"
  end.join("\n")
end

.web=(bool) ⇒ Object



281
282
283
# File 'lib/narou.rb', line 281

def web=(bool)
  @@is_web = bool
end

.web?Boolean

Returns:

  • (Boolean)


285
286
287
# File 'lib/narou.rb', line 285

def web?
  @@is_web
end

.write_replace_txt(path, pairs) ⇒ Object



150
151
152
153
# File 'lib/narou.rb', line 150

def write_replace_txt(path, pairs)
  buffer = pairs.each_with_object("\t").map(&:join).join("\n")
  File.write(path, buffer)
end