# frozen_string_literal: true SEARCH_URL = $config['search_url'] SEARCH_CONNECT_TIMEOUT = $config['search_connect_timeout'] SEARCH_WRITE_TIMEOUT = $config['search_write_timeout'] SEARCH_READ_TIMEOUT = $config['search_read_timeout'] post '/search/?' do query = params[:q].to_s.strip redirect query.blank? ? '/search' : "/search?#{Rack::Utils.build_query(q: query)}" end get '/search/?' do @query = params[:q].to_s.strip @title = @query.blank? ? 'Neocities Search' : 'Site Search' @description = 'Search websites hosted on Neocities.' if !@query.blank? @start = params[:start].to_i @start = 0 if @start < 0 @items = [] @total_results = 0 begin @resp = JSON.parse HTTP.timeout(connect: SEARCH_CONNECT_TIMEOUT, write: SEARCH_WRITE_TIMEOUT, read: SEARCH_READ_TIMEOUT).get(SEARCH_URL, params: { num: 100, start: @start, q: Rack::Utils.escape(@query) + ' -filetype:pdf -filetype:txt site:*.neocities.org' }).to_s rescue HTTP::Error, JSON::ParserError @resp = {} end if @resp.is_a?(Hash) && @resp['error'].nil? && @resp.dig('searchInformation', 'totalResults').to_i != 0 @total_results = @resp['searchInformation']['totalResults'].to_i @resp['items'].each do |item| link = Addressable::URI.parse(item['link']) path = link.path || '/' unencoded_path = begin Rack::Utils.unescape(Rack::Utils.unescape(path)) # Yes, it needs to be decoded twice rescue ArgumentError path # Fall back when the path includes invalid %-encoding end item['unencoded_link'] = unencoded_path == '/' ? link.host : link.host+unencoded_path item['link'] = link next if link.host == 'neocities.org' username = link.host.split('.').first site = Site[username: username] next if site.nil? || site.is_deleted || site.is_nsfw item['username'] = username if site.profile_enabled screenshot_path = unencoded_path screenshot_path << 'index' if screenshot_path[-1] == '/' if ENV['RACK_ENV'] == 'development' screenshot_path += '.html' screenshot_found = true else ['.html', '.htm'].each do |ext| if site.screenshot_exists?(screenshot_path + ext, '540x405') screenshot_path += ext screenshot_found = true break end end end item['screenshot_url'] = site.screenshot_url(screenshot_path, '540x405') @items << item if screenshot_found end end else @items = nil @total_results = 0 end erb :'search' end