Improve the detection of a banner image.

- Also accept attachments of type Image
- Prefer the key "image" if it is set as the banner image (https://www.w3.org/TR/activitystreams-vocabulary/#dfn-object)
- solves #1399

Co-authored-by: Thomas Citharel <tcit@tcit.fr>
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
André Menrath 2024-01-20 09:28:07 +01:00 committed by Thomas Citharel
parent fae480c24e
commit 0d7462de06
No known key found for this signature in database
GPG key ID: A061B9DDE0CA0773
5 changed files with 422 additions and 15 deletions

View file

@ -205,9 +205,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do
@spec process_pictures(map(), integer()) :: Keyword.t() @spec process_pictures(map(), integer()) :: Keyword.t()
def process_pictures(object, actor_id) do def process_pictures(object, actor_id) do
attachements = Map.get(object, "attachment", []) {banner, media_attachements} = get_medias(object)
{banner, media_attachements} = get_medias(attachements)
media_attachements_map = media_attachements_map =
media_attachements media_attachements
@ -259,24 +257,46 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do
do: String.replace(body, old_url, new_url) do: String.replace(body, old_url, new_url)
@spec get_medias(list(map())) :: {map(), list(map())} @spec get_medias(list(map())) :: {map(), list(map())}
defp get_medias(attachments) do def get_medias(object) do
banner = get_banner_picture(attachments) banner = get_banner_picture(object)
{banner, Enum.filter(attachments, &(&1["type"] == "Document" && &1["url"] != banner["url"]))} attachments = Map.get(object, "attachment", [])
{banner, Enum.filter(attachments, &(valid_banner_media?(&1) && &1["url"] != banner["url"]))}
end end
@spec get_banner_picture(list(map())) :: map() @spec get_banner_picture(map()) :: map()
defp get_banner_picture(attachments) do defp get_banner_picture(object) do
# Prefer media with attachments = Map.get(object, "attachment", [])
media_with_picture_name = image = Map.get(object, "image", %{})
Enum.find(attachments, &(&1["type"] == "Document" && &1["name"] == @banner_picture_name))
case media_with_picture_name do media_with_picture_name =
# If no banner found, use the first media Enum.find(attachments, &(valid_banner_media?(&1) && &1["name"] == @banner_picture_name))
nil -> Enum.find(attachments, &(&1["type"] == "Document"))
media_with_picture_name -> media_with_picture_name cond do
# Check if the "image" key is set and of type "Document" or "Image"
is_nil(media_with_picture_name) and valid_banner_media?(image) ->
image
is_nil(media_with_picture_name) and Enum.find(attachments, &valid_banner_media?/1) ->
Enum.find(attachments, &valid_banner_media?/1)
!is_nil(media_with_picture_name) ->
media_with_picture_name
true ->
nil
end end
end end
@spec valid_banner_media?(map()) :: boolean()
defp valid_banner_media?(media) do
media |> Map.get("type") |> valid_attachment_type?()
end
@spec valid_attachment_type?(any()) :: boolean()
defp valid_attachment_type?(type) do
type in ["Document", "Image"]
end
@spec get_address(map | binary | nil) :: Address.t() | nil @spec get_address(map | binary | nil) :: Address.t() | nil
def get_address(text_address) when is_binary(text_address) do def get_address(text_address) when is_binary(text_address) do
get_address(%{"type" => "Place", "name" => text_address}) get_address(%{"type" => "Place", "name" => text_address})

View file

@ -0,0 +1,76 @@
defmodule Mobilizon.Federation.ActivityStream.Converter.UtilsTest do
@moduledoc """
Module to test converting from EventMetadata to AS
"""
use Mobilizon.DataCase
import Mobilizon.Factory
alias Mobilizon.Federation.ActivityStream.Converter.Utils
describe "get_medias/1" do
test "getting banner from Document attachment" do
data =
File.read!("test/fixtures/mobilizon-post-activity-media.json")
|> Jason.decode!()
|> Map.get("object")
assert Utils.get_medias(data) ==
{%{
"blurhash" => "U5SY?Z00nOxu7ORP.8-pU^kVS#NGXyxbMxM{",
"mediaType" => "image/png",
"name" => nil,
"type" => "Document",
"url" => "https://mobilizon.fr/some-image"
}, []}
end
test "getting banner from image property" do
data =
File.read!("test/fixtures/mobilizon-post-activity-media-1.json")
|> Jason.decode!()
|> Map.get("object")
assert Utils.get_medias(data) ==
{%{
"blurhash" => "U5SY?Z00nOxu7ORP.8-pU^kVS#NGXyxbMxM{",
"mediaType" => "image/png",
"name" => nil,
"type" => "Image",
"url" => "https://mobilizon.fr/some-image-1"
},
[
%{
"blurhash" => "U5SY?Z00nOxu7ORP.8-pU^kVS#NGXyxbMxM{",
"mediaType" => "image/png",
"name" => nil,
"type" => "Document",
"url" => "https://mobilizon.fr/some-image"
}
]}
end
test "getting banner from attachment named \"Banner\"" do
data =
File.read!("test/fixtures/mobilizon-post-activity-media-2.json")
|> Jason.decode!()
|> Map.get("object")
assert Utils.get_medias(data) ==
{%{
"blurhash" => "U5SY?Z00nOxu7ORP.8-pU^kVS#NGXyxbMxM{",
"mediaType" => "image/png",
"name" => "Banner",
"type" => "Document",
"url" => "https://mobilizon.fr/some-image-2"
},
[
%{
"blurhash" => "U5SY?Z00nOxu7ORP.8-pU^kVS#NGXyxbMxM{",
"mediaType" => "image/png",
"name" => nil,
"type" => "Document",
"url" => "https://mobilizon.fr/some-image-1"
}
]}
end
end
end

View file

@ -0,0 +1,106 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://litepub.social/litepub/context.jsonld",
{
"Hashtag": "as:Hashtag",
"category": "sc:category",
"ical": "http://www.w3.org/2002/12/cal/ical#",
"joinMode": {
"@id": "mz:joinMode",
"@type": "mz:joinModeType"
},
"joinModeType": {
"@id": "mz:joinModeType",
"@type": "rdfs:Class"
},
"maximumAttendeeCapacity": "sc:maximumAttendeeCapacity",
"mz": "https://joinmobilizon.org/ns#",
"repliesModerationOption": {
"@id": "mz:repliesModerationOption",
"@type": "mz:repliesModerationOptionType"
},
"repliesModerationOptionType": {
"@id": "mz:repliesModerationOptionType",
"@type": "rdfs:Class"
},
"sc": "http://schema.org#",
"uuid": "sc:identifier"
}
],
"actor": "https://mobilizon.fr/@metacartes",
"cc": [
"https://framapiaf.org/users/admin/followers",
"https://framapiaf.org/users/tcit"
],
"id": "https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93/activity",
"object": {
"attachment": [
{
"href": "https://something.org",
"mediaType": "text/html",
"name": "Another link",
"type": "Link"
},
{
"href": "https://google.com",
"mediaType": "text/html",
"name": "Website",
"type": "Link"
},
{
"type": "Document",
"mediaType": "image/png",
"url": "https://mobilizon.fr/some-image",
"name": null,
"blurhash": "U5SY?Z00nOxu7ORP.8-pU^kVS#NGXyxbMxM{"
}
],
"attributedTo": "https://mobilizon.fr/@metacartes",
"startTime": "2018-02-12T14:08:20Z",
"cc": [
"https://framapiaf.org/users/admin/followers",
"https://framapiaf.org/users/tcit"
],
"content": "<p><span class=\"h-card\"><a href=\"https://framapiaf.org/users/tcit\" class=\"u-url mention\">@<span>tcit</span></a></span></p>",
"category": "TODO remove me",
"id": "https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93",
"image": {
"type": "Image",
"mediaType": "image/png",
"url": "https://mobilizon.fr/some-image-1",
"name": null,
"blurhash": "U5SY?Z00nOxu7ORP.8-pU^kVS#NGXyxbMxM{"
},
"inReplyTo": null,
"location": {
"type": "Place",
"name": "Locaux de Framasoft",
"id": "https://event1.tcit.fr/address/eeecc11d-0030-43e8-a897-6422876372jd",
"address": {
"type": "PostalAddress",
"streetAddress": "10 Rue Jangot",
"postalCode": "69007",
"addressLocality": "Lyon",
"addressRegion": "Auvergne Rhône Alpes",
"addressCountry": "France"
}
},
"name": "My first event",
"published": "2018-02-12T14:08:20Z",
"tag": [
{
"href": "https://framapiaf.org/users/tcit",
"name": "@tcit@framapiaf.org",
"type": "Mention"
}
],
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"type": "Event",
"url": "https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93",
"uuid": "109ccdfd-ee3e-46e1-a877-6c228763df0c"
},
"published": "2018-02-12T14:08:20Z",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"type": "Create"
}

View file

@ -0,0 +1,106 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://litepub.social/litepub/context.jsonld",
{
"Hashtag": "as:Hashtag",
"category": "sc:category",
"ical": "http://www.w3.org/2002/12/cal/ical#",
"joinMode": {
"@id": "mz:joinMode",
"@type": "mz:joinModeType"
},
"joinModeType": {
"@id": "mz:joinModeType",
"@type": "rdfs:Class"
},
"maximumAttendeeCapacity": "sc:maximumAttendeeCapacity",
"mz": "https://joinmobilizon.org/ns#",
"repliesModerationOption": {
"@id": "mz:repliesModerationOption",
"@type": "mz:repliesModerationOptionType"
},
"repliesModerationOptionType": {
"@id": "mz:repliesModerationOptionType",
"@type": "rdfs:Class"
},
"sc": "http://schema.org#",
"uuid": "sc:identifier"
}
],
"actor": "https://mobilizon.fr/@metacartes",
"cc": [
"https://framapiaf.org/users/admin/followers",
"https://framapiaf.org/users/tcit"
],
"id": "https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93/activity",
"object": {
"attachment": [
{
"href": "https://something.org",
"mediaType": "text/html",
"name": "Another link",
"type": "Link"
},
{
"href": "https://google.com",
"mediaType": "text/html",
"name": "Website",
"type": "Link"
},
{
"type": "Document",
"mediaType": "image/png",
"url": "https://mobilizon.fr/some-image-1",
"name": null,
"blurhash": "U5SY?Z00nOxu7ORP.8-pU^kVS#NGXyxbMxM{"
},
{
"type": "Document",
"mediaType": "image/png",
"url": "https://mobilizon.fr/some-image-2",
"name": "Banner",
"blurhash": "U5SY?Z00nOxu7ORP.8-pU^kVS#NGXyxbMxM{"
}
],
"attributedTo": "https://mobilizon.fr/@metacartes",
"startTime": "2018-02-12T14:08:20Z",
"cc": [
"https://framapiaf.org/users/admin/followers",
"https://framapiaf.org/users/tcit"
],
"content": "<p><span class=\"h-card\"><a href=\"https://framapiaf.org/users/tcit\" class=\"u-url mention\">@<span>tcit</span></a></span></p>",
"category": "TODO remove me",
"id": "https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93",
"inReplyTo": null,
"location": {
"type": "Place",
"name": "Locaux de Framasoft",
"id": "https://event1.tcit.fr/address/eeecc11d-0030-43e8-a897-6422876372jd",
"address": {
"type": "PostalAddress",
"streetAddress": "10 Rue Jangot",
"postalCode": "69007",
"addressLocality": "Lyon",
"addressRegion": "Auvergne Rhône Alpes",
"addressCountry": "France"
}
},
"name": "My first event",
"published": "2018-02-12T14:08:20Z",
"tag": [
{
"href": "https://framapiaf.org/users/tcit",
"name": "@tcit@framapiaf.org",
"type": "Mention"
}
],
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"type": "Event",
"url": "https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93",
"uuid": "109ccdfd-ee3e-46e1-a877-6c228763df0c"
},
"published": "2018-02-12T14:08:20Z",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"type": "Create"
}

View file

@ -0,0 +1,99 @@
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://litepub.social/litepub/context.jsonld",
{
"Hashtag": "as:Hashtag",
"category": "sc:category",
"ical": "http://www.w3.org/2002/12/cal/ical#",
"joinMode": {
"@id": "mz:joinMode",
"@type": "mz:joinModeType"
},
"joinModeType": {
"@id": "mz:joinModeType",
"@type": "rdfs:Class"
},
"maximumAttendeeCapacity": "sc:maximumAttendeeCapacity",
"mz": "https://joinmobilizon.org/ns#",
"repliesModerationOption": {
"@id": "mz:repliesModerationOption",
"@type": "mz:repliesModerationOptionType"
},
"repliesModerationOptionType": {
"@id": "mz:repliesModerationOptionType",
"@type": "rdfs:Class"
},
"sc": "http://schema.org#",
"uuid": "sc:identifier"
}
],
"actor": "https://mobilizon.fr/@metacartes",
"cc": [
"https://framapiaf.org/users/admin/followers",
"https://framapiaf.org/users/tcit"
],
"id": "https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93/activity",
"object": {
"attachment": [
{
"href": "https://something.org",
"mediaType": "text/html",
"name": "Another link",
"type": "Link"
},
{
"href": "https://google.com",
"mediaType": "text/html",
"name": "Website",
"type": "Link"
},
{
"type": "Document",
"mediaType": "image/png",
"url": "https://mobilizon.fr/some-image",
"name": null,
"blurhash": "U5SY?Z00nOxu7ORP.8-pU^kVS#NGXyxbMxM{"
}
],
"attributedTo": "https://mobilizon.fr/@metacartes",
"startTime": "2018-02-12T14:08:20Z",
"cc": [
"https://framapiaf.org/users/admin/followers",
"https://framapiaf.org/users/tcit"
],
"content": "<p><span class=\"h-card\"><a href=\"https://framapiaf.org/users/tcit\" class=\"u-url mention\">@<span>tcit</span></a></span></p>",
"category": "TODO remove me",
"id": "https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93",
"inReplyTo": null,
"location": {
"type": "Place",
"name": "Locaux de Framasoft",
"id": "https://event1.tcit.fr/address/eeecc11d-0030-43e8-a897-6422876372jd",
"address": {
"type": "PostalAddress",
"streetAddress": "10 Rue Jangot",
"postalCode": "69007",
"addressLocality": "Lyon",
"addressRegion": "Auvergne Rhône Alpes",
"addressCountry": "France"
}
},
"name": "My first event",
"published": "2018-02-12T14:08:20Z",
"tag": [
{
"href": "https://framapiaf.org/users/tcit",
"name": "@tcit@framapiaf.org",
"type": "Mention"
}
],
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"type": "Event",
"url": "https://mobilizon.fr/events/39a0c4a6-f2b6-41dc-bbe2-fc5bff76cc93",
"uuid": "109ccdfd-ee3e-46e1-a877-6c228763df0c"
},
"published": "2018-02-12T14:08:20Z",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"type": "Create"
}