Merge branch 'feat/rich-media-improvements' into 'develop'
Rich media improvements See merge request pleroma/pleroma!2944
This commit is contained in:
commit
d6e979aebe
|
@ -5,8 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
## unreleased-patch - ???
|
## unreleased-patch - ???
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Rich media failure tracking (along with `:failure_backoff` option)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Mastodon API: Search parameter `following` now correctly returns the followings rather than the followers
|
- Mastodon API: Search parameter `following` now correctly returns the followings rather than the followers
|
||||||
|
- Mastodon API: Timelines hanging for (`number of posts with links * rich media timeout`) in the worst case.
|
||||||
|
Reduced to just rich media timeout.
|
||||||
|
|
||||||
## [2.1.0] - 2020-08-28
|
## [2.1.0] - 2020-08-28
|
||||||
|
|
||||||
|
|
|
@ -412,6 +412,7 @@
|
||||||
Pleroma.Web.RichMedia.Parsers.TwitterCard,
|
Pleroma.Web.RichMedia.Parsers.TwitterCard,
|
||||||
Pleroma.Web.RichMedia.Parsers.OEmbed
|
Pleroma.Web.RichMedia.Parsers.OEmbed
|
||||||
],
|
],
|
||||||
|
failure_backoff: 60_000,
|
||||||
ttl_setters: [Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl]
|
ttl_setters: [Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl]
|
||||||
|
|
||||||
config :pleroma, :media_proxy,
|
config :pleroma, :media_proxy,
|
||||||
|
|
|
@ -2385,6 +2385,13 @@
|
||||||
suggestions: [
|
suggestions: [
|
||||||
Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl
|
Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :failure_backoff,
|
||||||
|
type: :integer,
|
||||||
|
description:
|
||||||
|
"Amount of milliseconds after request failure, during which the request will not be retried.",
|
||||||
|
suggestions: [60_000]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -361,6 +361,7 @@ config :pleroma, Pleroma.Web.MediaProxy.Invalidation.Http,
|
||||||
* `ignore_hosts`: list of hosts which will be ignored by the metadata parser. For example `["accounts.google.com", "xss.website"]`, defaults to `[]`.
|
* `ignore_hosts`: list of hosts which will be ignored by the metadata parser. For example `["accounts.google.com", "xss.website"]`, defaults to `[]`.
|
||||||
* `ignore_tld`: list TLDs (top-level domains) which will ignore for parse metadata. default is ["local", "localdomain", "lan"].
|
* `ignore_tld`: list TLDs (top-level domains) which will ignore for parse metadata. default is ["local", "localdomain", "lan"].
|
||||||
* `parsers`: list of Rich Media parsers.
|
* `parsers`: list of Rich Media parsers.
|
||||||
|
* `failure_backoff`: Amount of milliseconds after request failure, during which the request will not be retried.
|
||||||
|
|
||||||
## HTTP server
|
## HTTP server
|
||||||
|
|
||||||
|
|
|
@ -109,8 +109,9 @@ def extract_first_external_url(object, content) do
|
||||||
result =
|
result =
|
||||||
content
|
content
|
||||||
|> Floki.parse_fragment!()
|
|> Floki.parse_fragment!()
|
||||||
|> Floki.filter_out("a.mention,a.hashtag,a.attachment,a[rel~=\"tag\"]")
|
|> Floki.find("a:not(.mention,.hashtag,.attachment,[rel~=\"tag\"])")
|
||||||
|> Floki.attribute("a", "href")
|
|> Enum.take(1)
|
||||||
|
|> Floki.attribute("href")
|
||||||
|> Enum.at(0)
|
|> Enum.at(0)
|
||||||
|
|
||||||
{:commit, {:ok, result}}
|
{:commit, {:ok, result}}
|
||||||
|
|
|
@ -23,6 +23,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
||||||
|
|
||||||
import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1, visible_for_user?: 2]
|
import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1, visible_for_user?: 2]
|
||||||
|
|
||||||
|
# This is a naive way to do this, just spawning a process per activity
|
||||||
|
# to fetch the preview. However it should be fine considering
|
||||||
|
# pagination is restricted to 40 activities at a time
|
||||||
|
defp fetch_rich_media_for_activities(activities) do
|
||||||
|
Enum.each(activities, fn activity ->
|
||||||
|
spawn(fn ->
|
||||||
|
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: Add cached version.
|
# TODO: Add cached version.
|
||||||
defp get_replied_to_activities([]), do: %{}
|
defp get_replied_to_activities([]), do: %{}
|
||||||
|
|
||||||
|
@ -80,6 +91,11 @@ def render("index.json", opts) do
|
||||||
|
|
||||||
# To do: check AdminAPIControllerTest on the reasons behind nil activities in the list
|
# To do: check AdminAPIControllerTest on the reasons behind nil activities in the list
|
||||||
activities = Enum.filter(opts.activities, & &1)
|
activities = Enum.filter(opts.activities, & &1)
|
||||||
|
|
||||||
|
# Start fetching rich media before doing anything else, so that later calls to get the cards
|
||||||
|
# only block for timeout in the worst case, as opposed to
|
||||||
|
# length(activities_with_links) * timeout
|
||||||
|
fetch_rich_media_for_activities(activities)
|
||||||
replied_to_activities = get_replied_to_activities(activities)
|
replied_to_activities = get_replied_to_activities(activities)
|
||||||
|
|
||||||
parent_activities =
|
parent_activities =
|
||||||
|
|
|
@ -17,14 +17,25 @@ def parse(url), do: parse_url(url)
|
||||||
else
|
else
|
||||||
@spec parse(String.t()) :: {:ok, map()} | {:error, any()}
|
@spec parse(String.t()) :: {:ok, map()} | {:error, any()}
|
||||||
def parse(url) do
|
def parse(url) do
|
||||||
Cachex.fetch!(:rich_media_cache, url, fn _ ->
|
with {:ok, data} <- get_cached_or_parse(url),
|
||||||
with {:ok, data} <- parse_url(url) do
|
{:ok, _} <- set_ttl_based_on_image(data, url) do
|
||||||
{:commit, {:ok, data}}
|
{:ok, data}
|
||||||
else
|
else
|
||||||
error -> {:ignore, error}
|
error ->
|
||||||
|
Logger.error(fn -> "Rich media error: #{inspect(error)}" end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_cached_or_parse(url) do
|
||||||
|
case Cachex.fetch!(:rich_media_cache, url, fn _ -> {:commit, parse_url(url)} end) do
|
||||||
|
{:ok, _data} = res ->
|
||||||
|
res
|
||||||
|
|
||||||
|
{:error, _} = e ->
|
||||||
|
ttl = Pleroma.Config.get([:rich_media, :failure_backoff], 60_000)
|
||||||
|
Cachex.expire(:rich_media_cache, url, ttl)
|
||||||
|
e
|
||||||
end
|
end
|
||||||
end)
|
|
||||||
|> set_ttl_based_on_image(url)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -50,22 +61,21 @@ def ttl(data, url) do
|
||||||
config :pleroma, :rich_media,
|
config :pleroma, :rich_media,
|
||||||
ttl_setters: [MyModule]
|
ttl_setters: [MyModule]
|
||||||
"""
|
"""
|
||||||
@spec set_ttl_based_on_image({:ok, map()} | {:error, any()}, String.t()) ::
|
@spec set_ttl_based_on_image(map(), String.t()) ::
|
||||||
{:ok, map()} | {:error, any()}
|
{:ok, Integer.t() | :noop} | {:error, :no_key}
|
||||||
def set_ttl_based_on_image({:ok, data}, url) do
|
def set_ttl_based_on_image(data, url) do
|
||||||
with {:ok, nil} <- Cachex.ttl(:rich_media_cache, url),
|
case get_ttl_from_image(data, url) do
|
||||||
{:ok, ttl} when is_number(ttl) <- get_ttl_from_image(data, url) do
|
{:ok, ttl} when is_number(ttl) ->
|
||||||
Cachex.expire_at(:rich_media_cache, url, ttl * 1000)
|
ttl = ttl * 1000
|
||||||
{:ok, data}
|
|
||||||
else
|
case Cachex.expire_at(:rich_media_cache, url, ttl) do
|
||||||
_ ->
|
{:ok, true} -> {:ok, ttl}
|
||||||
{:ok, data}
|
{:ok, false} -> {:error, :no_key}
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_ttl_based_on_image({:error, _} = error, _) do
|
_ ->
|
||||||
Logger.error("parsing error: #{inspect(error)}")
|
{:ok, :noop}
|
||||||
error
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_ttl_from_image(data, url) do
|
defp get_ttl_from_image(data, url) do
|
||||||
|
|
|
@ -55,7 +55,7 @@ test "s3 signed url is parsed and correct ttl is set for rich media" do
|
||||||
|
|
||||||
Cachex.put(:rich_media_cache, url, metadata)
|
Cachex.put(:rich_media_cache, url, metadata)
|
||||||
|
|
||||||
Pleroma.Web.RichMedia.Parser.set_ttl_based_on_image({:ok, metadata}, url)
|
Pleroma.Web.RichMedia.Parser.set_ttl_based_on_image(metadata, url)
|
||||||
|
|
||||||
{:ok, cache_ttl} = Cachex.ttl(:rich_media_cache, url)
|
{:ok, cache_ttl} = Cachex.ttl(:rich_media_cache, url)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue