lib/command/update.rb in narou-2.9.5 vs lib/command/update.rb in narou-3.0.0

- old
+ new

@@ -7,36 +7,17 @@ require "memoist" require_relative "../database" require_relative "../downloader" require_relative "../template" require_relative "../novelconverter" +require_relative "update/interval" +require_relative "update/general_lastup_updater" module Command class Update < CommandBase extend Memoist - class Interval - MIN = 2.5 # 作品間ウェイトの最低秒数(処理時間含む) - FORCE_WAIT_TIME = 2.0 # 強制待機時間 - - def initialize(interval) - @time = Time.now - MIN - interval = interval.to_f - @interval_time = interval >= MIN ? interval : MIN - end - - def wait - wait_time = Time.now - @time - sleep(@interval_time - wait_time) if wait_time < @interval_time - @time = Time.now - end - - def force_wait - sleep(FORCE_WAIT_TIME) - end - end - LOG_DIR_NAME = "log" LOG_NUM_LIMIT = 30 # ログの保存する上限数 LOG_FILENAME_FORMAT = "update_log_%s.txt" HOTENTRY_DIR_NAME = "hotentry" @@ -64,10 +45,17 @@ narou u # 短縮コマンド narou update 0 1 2 4 narou update n9669bk 異世界迷宮で奴隷ハーレムを narou update http://ncode.syosetu.com/n9669bk/ + # foo タグが付いた小説と bar タグが付いた小説を更新(タグのOR指定) + narou u foo bar + + # foo タグ及び bar タグが両方付いた小説のみ更新(タグのAND指定) + narou tag foo bar | narou u + narou l -t "foo bar" | narou # こっちでも同じ(覚えやすい方を使う) + Options: EOS @opt.on("-n", "--no-convert", "変換をせずアップデートのみ実行する") { @options["no-convert"] = true } @@ -79,20 +67,33 @@ n -= 1 if n > 0 @options["log"] = n view_log exit 0 } - @opt.on("--gl", "データベースに最新話掲載日を反映させる") { - update_general_lastup + @opt.on("--gl [OPT]", <<-EOS) { |option| +データベースに最新話掲載日を反映させる + | OPT | 概要 + | 指定なし | 全ての小説を対象にする + | narou | なろうAPIを使える小説のみ対象 + | other | なろうAPIが使えない小説のみ対象 + EOS + if option && !["narou", "other"].include?(option) + error "--gl で指定可能なオプションではありません。詳細は narou u -h を参照" + exit Narou::EXIT_ERROR_CODE + end + update_general_lastup(option) exit 0 } @opt.on("-f", "--force", "凍結済みも更新する") { @options["force"] = true } @opt.on("-s", "--sort-by KEY", "アップデートする順番を変更する\n#{Narou.update_sort_key_summaries}") { |key| @options["sort-by"] = key } + @opt.on("-i", "--ignore-all", "<target>を省略した場合の全件更新処理を無効化する") { + @options["ignore-all"] = true + } end def get_data_value(target, key) data = Downloader.get_data_by_target(target) or return nil value = data[key] @@ -129,19 +130,19 @@ def valid_sort_key?(key) Narou::UPDATE_SORT_KEYS.keys.include?(key) end + # rubocop:disable Metrics/BlockLength def execute(argv) super mistook_count = 0 update_target_list = argv.dup @options["no-open"] = false if update_target_list.empty? - Database.instance.each_key do |id| - update_target_list << id - end + exit 0 if @options["ignore-all"] + update_target_list += Database.instance.get_object.keys @options["no-open"] = true end tagname_to_ids(update_target_list) sort_key = @options["sort-by"] @@ -160,87 +161,94 @@ @options["hotentry.auto-mail"] = inv["hotentry.auto-mail"] hotentry = {} interval = Interval.new(@options["interval"]) - update_log = $stdout.capture(quiet: false) do - sort_by_key(sort_key, update_target_list).each_with_index do |target, i| - display_message = nil - data = Downloader.get_data_by_target(target) - if !data - display_message = "<bold><red>[ERROR]</red></bold> #{target} は管理小説の中に存在しません".termcolor - elsif Narou.novel_frozen?(target) && !@options["force"] - if argv.length > 0 + begin + update_log = $stdout.capture(quiet: false) do + sort_by_key(sort_key, update_target_list).each_with_index do |target, i| + display_message = nil + data = Downloader.get_data_by_target(target) + if !data + display_message = "<bold><red>[ERROR]</red></bold> #{target} は管理小説の中に存在しません".termcolor + elsif Narou.novel_frozen?(target) && !@options["force"] + next if argv.empty? display_message = "ID:#{data["id"]} #{data["title"]} は凍結中です" - else + end + Helper.print_horizontal_rule if i > 0 + if display_message + puts display_message + mistook_count += 1 next end - end - Helper.print_horizontal_rule if i > 0 - if display_message - puts display_message - mistook_count += 1 - next - end - interval.wait - downloader = Downloader.new(target) + interval.wait + downloader = Downloader.new(target) - if @options["hotentry"] - downloader.on(:newarrival) do |hash| - entry = hotentry[hash[:id]] ||= [] - entry << hash[:subtitle_info] + if @options["hotentry"] + downloader.on(:newarrival) do |hash| + entry = hotentry[hash[:id]] ||= [] + entry << hash[:subtitle_info] + end end - end - result = downloader.start_download - case result.status - when :ok - if @options["no-convert"] || - (@options["convert-only-new-arrival"] && !result.new_arrivals) - interval.force_wait + delete_modified_tag = -> do + tags = data["tags"] || [] + data["tags"] = tags - [Narou::MODIFIED_TAG] if tags.include?(Narou::MODIFIED_TAG) + data["last_check_date"] = Time.now + end + + result = downloader.start_download + case result.status + when :ok + delete_modified_tag.call + if @options["no-convert"] || + (@options["convert-only-new-arrival"] && !result.new_arrivals) + interval.force_wait + next + end + when :failed + puts "ID:#{data["id"]} #{data["title"]} の更新は失敗しました" + mistook_count += 1 next + when :canceled + puts "ID:#{data["id"]} #{data["title"]} の更新はキャンセルされました" + mistook_count += 1 + next + when :none + delete_modified_tag.call + puts "#{data["title"]} に更新はありません" + next unless data["_convert_failure"] end - when :failed - puts "ID:#{data["id"]} #{data["title"]} の更新は失敗しました" - mistook_count += 1 - next - when :canceled - puts "ID:#{data["id"]} #{data["title"]} の更新はキャンセルされました" - mistook_count += 1 - next - when :none - puts "#{data["title"]} に更新はありません" - next unless data["_convert_failure"] - end - if data["_convert_failure"] - puts "<yellow>前回変換できなかったので再変換します</yellow>".termcolor + if data["_convert_failure"] + puts "<yellow>前回変換できなかったので再変換します</yellow>".termcolor + end + convert_argv = [target] + convert_argv << "--no-open" if @options["no-open"] + convert_status = Convert.execute!(convert_argv) + if convert_status > 0 + # 変換が失敗したか、中断された + data["_convert_failure"] = true + # 中断された場合には残りのアップデートも中止する + raise Interrupt if convert_status == Narou::EXIT_INTERRUPT + else + # 変換に成功した + data.delete("_convert_failure") + end end - convert_argv = [target] - convert_argv << "--no-open" if @options["no-open"] - convert_status = Convert.execute!(convert_argv) - if convert_status > 0 - # 変換が失敗したか、中断された - data["_convert_failure"] = true - # 中断された場合には残りのアップデートも中止する - raise Interrupt if convert_status == Narou::EXIT_INTERRUPT - else - # 変換に成功した - data.delete("_convert_failure") - end - end - process_hotentry(hotentry) + process_hotentry(hotentry) + end + ensure + save_log(update_log) + Database.instance.save_database end exit mistook_count if mistook_count > 0 rescue Interrupt puts "アップデートを中断しました" exit Narou::EXIT_INTERRUPT - ensure - save_log(update_log) - Database.instance.save_database end def get_log_paths Dir.glob(File.join(log_dirname, LOG_FILENAME_FORMAT % "*")).sort.reverse end @@ -282,63 +290,21 @@ (list[LOG_NUM_LIMIT..-1] || []).each do |path| File.delete(path) end end - def update_general_lastup(through_frozen_novel: true) - completed = false - database = Database.instance - puts "最新話掲載日を更新しています..." - progressbar = ProgressBar.new(database.get_object.size - 1) - interval = Interval.new(@options["interval"]) - database.each.with_index do |(id, data), i| - progressbar.output(i) - if through_frozen_novel - next if Narou.novel_frozen?(id) - end - setting = Downloader.get_sitesetting_by_target(id) - interval.wait - begin - info = NovelInfo.load(setting) - rescue OpenURI::HTTPError, Errno::ECONNRESET => e - setting.clear - next - end - if info - dates = { - "general_firstup" => info["general_firstup"], - "novelupdated_at" => info["novelupdated_at"], - "general_lastup" => info["general_lastup"] - } - else - # 小説情報ページがない場合は目次から取得する - begin - dates = get_latest_dates(id) - rescue OpenURI::HTTPError, Errno::ECONNRESET => e - setting.clear - next - end - end - database[id].merge!(dates) - setting.clear + def update_general_lastup(option = nil) + puts "最新話掲載日を確認しています..." + + updater = GeneralLastupUpdater.new(@options) + updater.update_narou_novels if !option || option == "narou" + if !option || option == "other" + sleep Narou::API::REQUEST_INTERVAL unless option + updater.update_other_novels end - database.save_database - completed = true - ensure - progressbar.clear if progressbar - puts "更新が完了しました" if completed - end + updater.save - # オンラインの目次からgeneral_lastupを取得する - # ただし、toc.yaml に最新話が存在し、かつsubdateが設定されていたらそれを使う - def get_latest_dates(target) - downloader = Downloader.new(target) - old_toc = downloader.load_toc_file - latest_toc = downloader.get_latest_table_of_contents(old_toc, through_error: true) - { - "novelupdated_at" => downloader.get_novelupdated_at, - "general_lastup" => downloader.get_general_lastup - } + puts "確認が完了しました" end # # 新着話をまとめたデータの作成に関する処理 #