You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
71 lines
1.7 KiB
71 lines
1.7 KiB
# frozen_string_literal: true |
|
|
|
class FetchOEmbedService |
|
attr_reader :url, :options, :format, :endpoint_url |
|
|
|
def call(url, options = {}) |
|
@url = url |
|
@options = options |
|
|
|
discover_endpoint! |
|
fetch! |
|
end |
|
|
|
private |
|
|
|
def discover_endpoint! |
|
return if html.nil? |
|
|
|
@format = @options[:format] |
|
page = Nokogiri::HTML(html) |
|
|
|
if @format.nil? || @format == :json |
|
@endpoint_url ||= page.at_xpath('//link[@type="application/json+oembed"]')&.attribute('href')&.value |
|
@format ||= :json if @endpoint_url |
|
end |
|
|
|
if @format.nil? || @format == :xml |
|
@endpoint_url ||= page.at_xpath('//link[@type="text/xml+oembed"]')&.attribute('href')&.value |
|
@format ||= :xml if @endpoint_url |
|
end |
|
|
|
return if @endpoint_url.blank? |
|
|
|
@endpoint_url = (Addressable::URI.parse(@url) + @endpoint_url).to_s |
|
rescue Addressable::URI::InvalidURIError |
|
@endpoint_url = nil |
|
end |
|
|
|
def fetch! |
|
return if @endpoint_url.blank? |
|
|
|
body = Request.new(:get, @endpoint_url).perform do |res| |
|
res.code != 200 ? nil : res.body_with_limit |
|
end |
|
|
|
validate(parse_for_format(body)) if body.present? |
|
rescue Oj::ParseError, Ox::ParseError |
|
nil |
|
end |
|
|
|
def parse_for_format(body) |
|
case @format |
|
when :json |
|
Oj.load(body, mode: :strict)&.with_indifferent_access |
|
when :xml |
|
Ox.load(body, mode: :hash_no_attrs)&.with_indifferent_access&.dig(:oembed) |
|
end |
|
end |
|
|
|
def validate(oembed) |
|
oembed if oembed[:version] == '1.0' && oembed[:type].present? |
|
end |
|
|
|
def html |
|
return @html if defined?(@html) |
|
|
|
@html = @options[:html] || Request.new(:get, @url).perform do |res| |
|
res.code != 200 || res.mime_type != 'text/html' ? nil : res.body_with_limit |
|
end |
|
end |
|
end
|
|
|