From 88244e6f8f5b3a9198d2fe6a8196a92643073930 Mon Sep 17 00:00:00 2001 From: miteruzo Date: Sat, 25 Apr 2026 15:52:08 +0900 Subject: [PATCH] #200 --- backend/lib/tasks/export_nico.rake | 23 ++++++ backend/spec/tasks/nico_export_spec.rb | 100 +++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 backend/lib/tasks/export_nico.rake create mode 100644 backend/spec/tasks/nico_export_spec.rb diff --git a/backend/lib/tasks/export_nico.rake b/backend/lib/tasks/export_nico.rake new file mode 100644 index 0000000..c0c6c9f --- /dev/null +++ b/backend/lib/tasks/export_nico.rake @@ -0,0 +1,23 @@ +namespace :nico do + desc 'ニコニコ DB 逆連携' + task export: :environment do + require 'open3' + + mysql_user = ENV.fetch('MYSQL_USER') + mysql_pass = ENV.fetch('MYSQL_PASS') + nizika_nico_path = ENV.fetch('NIZIKA_NICO_PATH') + + videos = Post.where('url LIKE ?', '%nicovideo.jp/watch/%').pluck(:url).filter_map { + _1[%r{nicovideo\.jp/watch/([^/?#]+)}, 1] + }.uniq + + next if videos.empty? + + _, stderr, status = Open3.capture3( + { 'MYSQL_USER' => mysql_user, 'MYSQL_PASS' => mysql_pass }, + 'python3', '-m', 'tracked_videos.put_bulk_upsert', *videos, + chdir: nizika_nico_path) + + raise stderr unless status.success? + end +end diff --git a/backend/spec/tasks/nico_export_spec.rb b/backend/spec/tasks/nico_export_spec.rb new file mode 100644 index 0000000..e6ed87c --- /dev/null +++ b/backend/spec/tasks/nico_export_spec.rb @@ -0,0 +1,100 @@ +require 'rails_helper' +require 'rake' +require 'open3' + +RSpec.describe 'nico:export' do + let(:task) { Rake::Task['nico:export'] } + let(:success_status) { instance_double(Process::Status, success?: true) } + let(:failure_status) { instance_double(Process::Status, success?: false) } + + def create_post(url) + Post.create!(url:) + end + + before(:all) do + Rails.application.load_tasks unless Rake::Task.task_defined?('nico:export') + end + + before do + task.reenable + + allow(ENV).to receive(:fetch).with('MYSQL_USER').and_return('mysql-user') + allow(ENV).to receive(:fetch).with('MYSQL_PASS').and_return('mysql-pass') + allow(ENV).to receive(:fetch).with('NIZIKA_NICO_PATH').and_return('/srv/nizika-nico') + end + + describe 'export' do + it 'exports nicovideo ids to shared nico DB' do + create_post('https://www.nicovideo.jp/watch/sm12345?ref=foo') + create_post('https://www.nicovideo.jp/watch/so67890#comments') + create_post('https://www.nicovideo.jp/watch/nm24680') + create_post('https://example.com/watch/sm99999') + + expect(Open3).to receive(:capture3) do |env, *args, **kwargs| + expect(env).to eq( + { + 'MYSQL_USER' => 'mysql-user', + 'MYSQL_PASS' => 'mysql-pass', + }, + ) + + expect(args.take(3)).to eq( + [ + 'python3', + '-m', + 'tracked_videos.put_bulk_upsert', + ], + ) + + expect(args.drop(3)).to contain_exactly( + 'sm12345', + 'so67890', + 'nm24680', + ) + + expect(kwargs).to eq(chdir: '/srv/nizika-nico') + + ['', '', success_status] + end + + task.invoke + end + + it 'deduplicates video ids' do + create_post('https://www.nicovideo.jp/watch/sm12345') + create_post('https://www.nicovideo.jp/watch/sm12345?from=1') + + expect(Open3).to receive(:capture3) do |_env, *args, **_kwargs| + expect(args.drop(3)).to eq(['sm12345']) + + ['', '', success_status] + end + + task.invoke + end + + it 'does not call python when there are no nicovideo posts' do + create_post('https://example.com/watch/sm12345') + + expect(Open3).not_to receive(:capture3) + + task.invoke + end + + it 'raises stderr when python command fails' do + create_post('https://www.nicovideo.jp/watch/sm12345') + + allow(Open3).to receive(:capture3).and_return( + [ + '', + 'bulk upsert failed', + failure_status, + ], + ) + + expect { + task.invoke + }.to raise_error(RuntimeError, 'bulk upsert failed') + end + end +end -- 2.34.1