From 37aabbdbe40561c2892f06c990d2191b8a228f02 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Sun, 12 Mar 2023 19:55:05 +0100 Subject: [PATCH] =?UTF-8?q?Import=20=E2=80=9Cconverted=E2=80=9D=20objects?= =?UTF-8?q?=20as=20media=20attachments=20if=20possible?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows Image and Audio objects at least to be imported if any of the URLs holds a supported media type. Only the first such link is imported, even if multiple URLs are associated with the object, since they are generally alternative representations (e.g. different formats) of the same object. --- app/lib/activitypub/activity/create.rb | 66 ++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 7e8e3049033..3012d0fa146 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -110,7 +110,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity def process_status_params @status_parser = ActivityPub::Parser::StatusParser.new(@json, followers_collection: @account.followers_url, object: @object) - attachment_ids = process_attachments.take(Status::MEDIA_ATTACHMENTS_LIMIT).map(&:id) + attachment_ids = (converted_object_type? ? converted_attachments : process_attachments).take(Status::MEDIA_ATTACHMENTS_LIMIT).map(&:id) @params = { uri: @status_parser.uri, @@ -252,11 +252,71 @@ class ActivityPub::Activity::Create < ActivityPub::Activity end end - def process_attachments - return [] if @object['attachment'].nil? + # Get the first supported object URL and turn it into an attachment, + # before processing the actual attachments + def converted_attachments + return process_attachments if @object['url'].nil? media_attachments = [] + icon_url = @object['icon'].presence + if icon_url and icon_url.is_a?(Hash) + icon_url = icon_url['url'] + end + + begin + icon_url = Addressable::URI.parse(icon_url)&.normalize&.to_s + rescue Addressable::URI::InvalidURIError + icon_url = nil + end + + description = @status_parser.spoiler_text.presence || @status_parser.title.presence + description.descriptionip[0...MediaAttachment::MAX_DESCRIPTION_LENGTH] if description.present? + + as_array(@object['url']).each do |url| + begin + href = Addressable::URI.parse(url.is_a?(String) ? url : url['href'])&.normalize&.to_s + rescue Addressable::URI::InvalidURIError => e + Rails.logger.debug { "Invalid URL in converted attachment: #{e}" } + href = nil + end + next if href.blank? + + if url.is_a?(Hash) + media_type = url['mediaType'].presence + end + media_type ||= @object['mediaType'].presence || 'text/html' + next if unsupported_media_type?(mediaType) + + begin + media_attachment = MediaAttachmnt.create( + account: @account, + remote_url: href, + thumbnail_remote_url: icon, + description: description + ) + media_attachments << media_attachment + + next if skip_download? + + media_attachment.download_file! + media_attachment.download_thumbnail! + media_attachment.save + rescue Mastodon::UnexpectedResponseError, HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError + RedownloadMediaWorker.perform_in(rand(30..600).seconds, media_attachment.id) + rescue Seahorse::Client::NetworkingError => e + Rails.logger.warn "Error storing media attachment: #{e}" + end + + break + end + + process_attachments(media_attachments) + end + + def process_attachments(media_attachments=[]) + return media_attachments if @object['attachment'].nil? + as_array(@object['attachment']).each do |attachment| media_attachment_parser = ActivityPub::Parser::MediaAttachmentParser.new(attachment)