このコミットが含まれているのは:
2026-07-09 23:11:31 +09:00
コミット b19c24cb8e
8個のファイルの変更366行の追加46行の削除
+40 -38
ファイルの表示
@@ -1,50 +1,52 @@
class PreviewController < ApplicationController
before_action :require_member!
def title
# TODO: # 既知サイトなら決まったフォーマットで title 取得するやぅに.
return head :unauthorized unless current_user
return render_bad_request('URL は必須です.') if params[:url].blank?
url = params[:url]
return render_bad_request('URL は必須です.') unless url.present?
unless url.start_with?(/http(s)?:\/\//)
url = 'http://' + url
end
html = URI.open(url, open_timeout: 5, read_timeout: 5).read
doc = Nokogiri::HTML.parse(html)
title = doc.at('title')&.text&.strip
render json: { title: title }
rescue => e
render_bad_request(e.message)
render json: { title: Preview::ThumbnailFetcher.title(params[:url]) }
rescue Preview::UrlSafety::UnsafeUrl => e
render_preview_error(e.message, :unprocessable_entity)
rescue Preview::HttpFetcher::FetchTimeout => e
render_preview_error(e.message, :gateway_timeout)
rescue Preview::HttpFetcher::FetchFailed => e
render_preview_error(e.message, :bad_gateway)
end
def thumbnail
# TODO: 既知ドメインであれば指定のアドレスからサムネールを取得するやぅにする.
return render_bad_request('URL は必須です.') if params[:url].blank?
image = MiniMagick::Image.read(Preview::ThumbnailFetcher.fetch(params[:url]))
image.auto_orient
image.resize '180x180>'
image.format 'png'
send_data image.to_blob, type: 'image/png', disposition: 'inline'
rescue Preview::UrlSafety::UnsafeUrl => e
render_preview_error(e.message, :unprocessable_entity)
rescue Preview::Screenshot::Busy => e
render_preview_error(e.message, :too_many_requests)
rescue Preview::Screenshot::TimedOut, Preview::HttpFetcher::FetchTimeout => e
render_preview_error(e.message, :gateway_timeout)
rescue Preview::HttpFetcher::FetchFailed => e
render_preview_error(e.message, :bad_gateway)
rescue Preview::Screenshot::Unavailable, MiniMagick::Error => e
render_preview_error(e.message, :unprocessable_entity)
end
private
def require_member!
return head :unauthorized unless current_user
return if current_user.gte_member?
url = params[:url]
return render_bad_request('URL は必須です.') if url.blank?
head :forbidden
end
unless url.start_with?(/http(s)?:\/\//)
url = 'http://' + url
end
path = Rails.root.join('tmp', "thumb_#{ SecureRandom.hex }.png")
system("node #{ Rails.root }/lib/screenshot.js #{ Shellwords.escape(url) } #{ path }")
if File.exist?(path)
image = MiniMagick::Image.open(path)
image.resize '180x180'
File.delete(path) rescue nil
send_file image.path, type: 'image/png', disposition: 'inline'
else
render json: { type: 'internal_server_error',
message: 'サムネールを生成できませんでした.',
errors: { },
base_errors: ['サムネールを生成できませんでした.'] },
status: :internal_server_error
end
def render_preview_error(message, status)
render json: { type: status.to_s,
message:,
errors: { },
base_errors: [message] },
status:
end
end