Support OpenGraph video embeds (#4897)

* Support OpenGraph video embeds

It's not really OpenGraph, it's twitter:player property, but it's
not OEmbed so that fits. For example, this allows Twitch clips to
be displayed as embeds.

Also, fixes glitch-soc/mastodon#135

* Fix invalid OpenGraph cards being saved through attaching and
revisit URLs after 14 days
This commit is contained in:
Eugen Rochko 2017-09-14 04:11:36 +02:00 committed by GitHub
parent 4f0597d579
commit 596dab06e9

View File

@ -1,6 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class FetchLinkCardService < BaseService class FetchLinkCardService < BaseService
include ActionView::Helpers::TagHelper
URL_PATTERN = %r{https?://\S+} URL_PATTERN = %r{https?://\S+}
def call(status) def call(status)
@ -14,11 +16,11 @@ class FetchLinkCardService < BaseService
RedisLock.acquire(lock_options) do |lock| RedisLock.acquire(lock_options) do |lock|
if lock.acquired? if lock.acquired?
@card = PreviewCard.find_by(url: @url) @card = PreviewCard.find_by(url: @url)
process_url if @card.nil? process_url if @card.nil? || @card.updated_at <= 2.weeks.ago
end end
end end
attach_card unless @card.nil? attach_card if @card&.persisted?
rescue HTTP::ConnectionError, OpenSSL::SSL::SSLError rescue HTTP::ConnectionError, OpenSSL::SSL::SSLError
nil nil
end end
@ -26,7 +28,7 @@ class FetchLinkCardService < BaseService
private private
def process_url def process_url
@card = PreviewCard.new(url: @url) @card ||= PreviewCard.new(url: @url)
res = Request.new(:head, @url).perform res = Request.new(:head, @url).perform
return if res.code != 200 || res.mime_type != 'text/html' return if res.code != 200 || res.mime_type != 'text/html'
@ -106,12 +108,25 @@ class FetchLinkCardService < BaseService
guess = detector.detect(html, response.charset) guess = detector.detect(html, response.charset)
page = Nokogiri::HTML(html, nil, guess&.fetch(:encoding)) page = Nokogiri::HTML(html, nil, guess&.fetch(:encoding))
if meta_property(page, 'twitter:player')
@card.type = :video
@card.width = meta_property(page, 'twitter:player:width') || 0
@card.height = meta_property(page, 'twitter:player:height') || 0
@card.html = content_tag(:iframe, nil, src: meta_property(page, 'twitter:player'),
width: @card.width,
height: @card.height,
allowtransparency: 'true',
scrolling: 'no',
frameborder: '0')
else
@card.type = :link @card.type = :link
@card.title = meta_property(page, 'og:title') || page.at_xpath('//title')&.content || ''
@card.description = meta_property(page, 'og:description') || meta_property(page, 'description') || ''
@card.image_remote_url = meta_property(page, 'og:image') if meta_property(page, 'og:image') @card.image_remote_url = meta_property(page, 'og:image') if meta_property(page, 'og:image')
end
return if @card.title.blank? @card.title = meta_property(page, 'og:title').presence || page.at_xpath('//title')&.content || ''
@card.description = meta_property(page, 'og:description').presence || meta_property(page, 'description') || ''
return if @card.title.blank? && @card.html.blank?
@card.save_with_optional_image! @card.save_with_optional_image!
end end