require 'rmagick' require 'timeout' require 'securerandom' require 'thread' require 'open3' class ScreenshotWorker SCREENSHOTS_PATH = Site::SCREENSHOTS_ROOT HARD_TIMEOUT = 20.freeze include Sidekiq::Worker sidekiq_options queue: :screenshots, retry: 3, backtrace: true def perform(username, path) path = "/#{path}" unless path[0] == '/' screenshot = Tempfile.new 'neocities_screenshot' screenshot.close screenshot_output_path = screenshot.path+'.png' line = Cocaine::CommandLine.new( "timeout #{HARD_TIMEOUT} phantomjs #{File.join DIR_ROOT, 'files', 'phantomjs_screenshot.js'}", ":url :output", expected_outcodes: [0] ) begin output = line.run( url: "http://#{username}.neocities.org#{path}", output: screenshot_output_path ) rescue Cocaine::ExitStatusError => e if e.message && e.message.match(/returned 124/) puts "#{username}/#{path} is timing out, discontinuing" site = Site[username: username] site.is_crashing = true site.save_changes validate: false return true =begin if site.email EmailWorker.perform_async({ from: 'web@neocities.org', to: site.email, subject: "[NeoCities] The web page \"#{path}\" on your site (#{username}.neocities.org) is slow", body: "Hi there! This is an automated email to inform you that we're having issues loading your site to take a "+ "screenshot. It is possible that this is an error specific to our screenshot program, but it is much more "+ "likely that your site is too slow to be used with browsers. We don't want Neocities sites crashing browsers, "+ "so we're taking steps to inform you and see if you can resolve the issue. "+ "We may have to de-list your web site from being viewable in our browse page if it is not resolved shortly. "+ "We will review the site manually before taking this step, so don't worry if your site is fine and we made "+ "a mistake."+ "\n\nOur best,\n- Neocities" }) end =end else raise end end img_list = Magick::ImageList.new img_list.from_blob File.read(screenshot_output_path) screenshot.unlink File.unlink screenshot_output_path img_list.new_image(img_list.first.columns, img_list.first.rows) { self.background_color = "white" } img = img_list.reverse.flatten_images user_screenshots_path = File.join SCREENSHOTS_PATH, username screenshot_path = File.join user_screenshots_path, File.dirname(path) FileUtils.mkdir_p screenshot_path unless Dir.exists?(screenshot_path) Site::SCREENSHOT_RESOLUTIONS.each do |res| width, height = res.split('x').collect {|r| r.to_i} if width == height new_img = img.crop_resized width, height, Magick::NorthGravity else new_img = img.scale width, height end new_img.write(File.join(user_screenshots_path, "#{path}.#{res}.jpg")) { self.quality = 90 } end end end