From d13000b2b9768449e9d0c09633e8b1d193b64018 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Tue, 13 Oct 2026 21:39:43 +0400 Subject: [PATCH 1/2] RichMedia: skip the quote fallback link when picking the card URL Mastodon, Misskey and InlineQuotePolicy put "RE: " in a .quote-inline element at the start of a quote post. Its link was taken for the link card, which then showed the quoted post a second time. --- changelog.d/card-skip-quote-link.fix | 1 + lib/pleroma/html.ex | 8 +++--- test/pleroma/html_test.exs | 37 ++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 changelog.d/card-skip-quote-link.fix diff --git a/changelog.d/card-skip-quote-link.fix b/changelog.d/card-skip-quote-link.fix new file mode 100644 index 000000000..27fe096fa --- /dev/null +++ b/changelog.d/card-skip-quote-link.fix @@ -0,0 +1 @@ +Link preview cards skip the fallback link of quote posts (`RE: `), which pointed at the quoted post and showed it twice. diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 4de7cbb76..aeac8bd04 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -66,14 +66,16 @@ defmodule Pleroma.HTML do end @spec extract_first_external_url_from_object(Pleroma.Object.t()) :: String.t() | nil - def extract_first_external_url_from_object(%{data: %{"content" => content}}) + def extract_first_external_url_from_object(%{data: %{"content" => content} = data}) when is_binary(content) do + # A quote post's fallback link ("RE: ", in a .quote-inline element or + # bare) points at the quoted post, which is shown already. content |> Floki.parse_fragment!() + |> Floki.filter_out(".quote-inline") |> Floki.find("a:not(.mention,.hashtag,.attachment,[rel~=\"tag\"])") - |> Enum.take(1) |> Floki.attribute("href") - |> Enum.at(0) + |> Enum.find(&(&1 != data["quoteUrl"])) end def extract_first_external_url_from_object(_), do: nil diff --git a/test/pleroma/html_test.exs b/test/pleroma/html_test.exs index d17b07540..5e7ad4749 100644 --- a/test/pleroma/html_test.exs +++ b/test/pleroma/html_test.exs @@ -299,5 +299,42 @@ defmodule Pleroma.HTMLTest do assert nil == HTML.extract_first_external_url_from_object(object) end + + test "skips the link in a Mastodon quote fallback paragraph" do + object = %Object{ + data: %{ + "quoteUrl" => "https://raru.re/users/ocean/statuses/116235427788617987", + "content" => + "

RE: raru.re/@ocean/116235427788617987

" <> + "

Berapa lapis?

youtube.com/watch?v=S0dJMhWDRDE

" + } + } + + assert HTML.extract_first_external_url_from_object(object) == + "https://www.youtube.com/watch?v=S0dJMhWDRDE" + end + + test "skips the link in a quote fallback span (Misskey, InlineQuotePolicy)" do + object = %Object{ + data: %{ + "content" => + "hello

RE: https://misskey.example/notes/abc
" + } + } + + assert nil == HTML.extract_first_external_url_from_object(object) + end + + test "skips a link to the quoted post without fallback markup" do + object = %Object{ + data: %{ + "quoteUrl" => "https://remote.example/objects/1", + "content" => + "RE: https://remote.example/objects/1 cofe" + } + } + + assert HTML.extract_first_external_url_from_object(object) == "https://cofe.example/" + end end end From 0667705b773162f86ae4ddc6ceef200219e1d984 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Tue, 3 Nov 2026 22:29:49 +0400 Subject: [PATCH 2/2] test: use sigils for HTML strings in quote link tests --- test/pleroma/html_test.exs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/pleroma/html_test.exs b/test/pleroma/html_test.exs index 2bb918556..b8b694db2 100644 --- a/test/pleroma/html_test.exs +++ b/test/pleroma/html_test.exs @@ -343,8 +343,8 @@ defmodule Pleroma.HTMLTest do data: %{ "quoteUrl" => "https://raru.re/users/ocean/statuses/116235427788617987", "content" => - "

RE: raru.re/@ocean/116235427788617987

" <> - "

Berapa lapis?

youtube.com/watch?v=S0dJMhWDRDE

" + ~s(

RE: raru.re/@ocean/116235427788617987

) <> + ~s(

Berapa lapis?

youtube.com/watch?v=S0dJMhWDRDE

) } } @@ -356,7 +356,7 @@ defmodule Pleroma.HTMLTest do object = %Object{ data: %{ "content" => - "hello

RE: https://misskey.example/notes/abc
" + ~s(hello

RE: https://misskey.example/notes/abc
) } } @@ -368,7 +368,7 @@ defmodule Pleroma.HTMLTest do data: %{ "quoteUrl" => "https://remote.example/objects/1", "content" => - "RE: https://remote.example/objects/1 cofe" + ~s(RE: https://remote.example/objects/1 cofe) } }