Merge branch 'ffmpeg-limiter' into 'develop'
Prevent Media Helper from respawning ffmpeg for bad media See merge request pleroma/pleroma!4086
This commit is contained in:
commit
71a0373232
|
@ -0,0 +1 @@
|
||||||
|
Framegrabs with ffmpeg will execute with a 5 second timeout and cache the URLs of failures with a TTL of 15 minutes to prevent excessive retries.
|
|
@ -156,6 +156,7 @@ defp cachex_children do
|
||||||
build_cachex("web_resp", limit: 2500),
|
build_cachex("web_resp", limit: 2500),
|
||||||
build_cachex("emoji_packs", expiration: emoji_packs_expiration(), limit: 10),
|
build_cachex("emoji_packs", expiration: emoji_packs_expiration(), limit: 10),
|
||||||
build_cachex("failed_proxy_url", limit: 2500),
|
build_cachex("failed_proxy_url", limit: 2500),
|
||||||
|
build_cachex("failed_media_helper_url", default_ttl: :timer.minutes(15), limit: 2_500),
|
||||||
build_cachex("banned_urls", default_ttl: :timer.hours(24 * 30), limit: 5_000),
|
build_cachex("banned_urls", default_ttl: :timer.hours(24 * 30), limit: 5_000),
|
||||||
build_cachex("chat_message_id_idempotency_key",
|
build_cachex("chat_message_id_idempotency_key",
|
||||||
expiration: chat_message_id_idempotency_key_expiration(),
|
expiration: chat_message_id_idempotency_key_expiration(),
|
||||||
|
|
|
@ -12,6 +12,8 @@ defmodule Pleroma.Helpers.MediaHelper do
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
||||||
|
|
||||||
def missing_dependencies do
|
def missing_dependencies do
|
||||||
Enum.reduce([ffmpeg: "ffmpeg"], [], fn {sym, executable}, acc ->
|
Enum.reduce([ffmpeg: "ffmpeg"], [], fn {sym, executable}, acc ->
|
||||||
if Pleroma.Utils.command_available?(executable) do
|
if Pleroma.Utils.command_available?(executable) do
|
||||||
|
@ -43,29 +45,40 @@ def image_resize(url, options) do
|
||||||
@spec video_framegrab(String.t()) :: {:ok, binary()} | {:error, any()}
|
@spec video_framegrab(String.t()) :: {:ok, binary()} | {:error, any()}
|
||||||
def video_framegrab(url) do
|
def video_framegrab(url) do
|
||||||
with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
|
with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
|
||||||
|
false <- @cachex.exists?(:failed_media_helper_cache, url),
|
||||||
{:ok, env} <- HTTP.get(url, [], pool: :media),
|
{:ok, env} <- HTTP.get(url, [], pool: :media),
|
||||||
{:ok, pid} <- StringIO.open(env.body) do
|
{:ok, pid} <- StringIO.open(env.body) do
|
||||||
body_stream = IO.binstream(pid, 1)
|
body_stream = IO.binstream(pid, 1)
|
||||||
|
|
||||||
result =
|
task =
|
||||||
Exile.stream!(
|
Task.async(fn ->
|
||||||
[
|
Exile.stream!(
|
||||||
executable,
|
[
|
||||||
"-i",
|
executable,
|
||||||
"pipe:0",
|
"-i",
|
||||||
"-vframes",
|
"pipe:0",
|
||||||
"1",
|
"-vframes",
|
||||||
"-f",
|
"1",
|
||||||
"mjpeg",
|
"-f",
|
||||||
"pipe:1"
|
"mjpeg",
|
||||||
],
|
"pipe:1"
|
||||||
input: body_stream,
|
],
|
||||||
ignore_epipe: true,
|
input: body_stream,
|
||||||
stderr: :disable
|
ignore_epipe: true,
|
||||||
)
|
stderr: :disable
|
||||||
|> Enum.into(<<>>)
|
)
|
||||||
|
|> Enum.into(<<>>)
|
||||||
|
end)
|
||||||
|
|
||||||
{:ok, result}
|
case Task.yield(task, 5_000) do
|
||||||
|
nil ->
|
||||||
|
Task.shutdown(task)
|
||||||
|
@cachex.put(:failed_media_helper_cache, url, nil)
|
||||||
|
{:error, {:ffmpeg, :timeout}}
|
||||||
|
|
||||||
|
result ->
|
||||||
|
{:ok, result}
|
||||||
|
end
|
||||||
else
|
else
|
||||||
nil -> {:error, {:ffmpeg, :command_not_found}}
|
nil -> {:error, {:ffmpeg, :command_not_found}}
|
||||||
{:error, _} = error -> error
|
{:error, _} = error -> error
|
||||||
|
|
Loading…
Reference in New Issue