[#2497] Added video preview proxy. Switched from exexec to Port.
This commit is contained in:
parent
27e7999a15
commit
da116d81fb
|
@ -6,8 +6,6 @@ variables: &global_variables
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
DB_HOST: postgres
|
DB_HOST: postgres
|
||||||
MIX_ENV: test
|
MIX_ENV: test
|
||||||
SHELL: /bin/sh
|
|
||||||
USER: root
|
|
||||||
|
|
||||||
cache: &global_cache_policy
|
cache: &global_cache_policy
|
||||||
key: ${CI_COMMIT_REF_SLUG}
|
key: ${CI_COMMIT_REF_SLUG}
|
||||||
|
|
|
@ -761,10 +761,6 @@
|
||||||
|
|
||||||
config :pleroma, Pleroma.Web.Auth.Authenticator, Pleroma.Web.Auth.PleromaAuthenticator
|
config :pleroma, Pleroma.Web.Auth.Authenticator, Pleroma.Web.Auth.PleromaAuthenticator
|
||||||
|
|
||||||
config :pleroma, :exexec,
|
|
||||||
root_mode: false,
|
|
||||||
options: %{}
|
|
||||||
|
|
||||||
# Import environment specific config. This must remain at the bottom
|
# Import environment specific config. This must remain at the bottom
|
||||||
# of this file so it overrides the configuration defined above.
|
# of this file so it overrides the configuration defined above.
|
||||||
import_config "#{Mix.env()}.exs"
|
import_config "#{Mix.env()}.exs"
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Exec do
|
|
||||||
@moduledoc "Pleroma wrapper around Exexec commands."
|
|
||||||
|
|
||||||
alias Pleroma.Config
|
|
||||||
|
|
||||||
def ensure_started(options_overrides \\ %{}) do
|
|
||||||
options =
|
|
||||||
if Config.get([:exexec, :root_mode]) || System.get_env("USER") == "root" do
|
|
||||||
# Note: running as `root` is discouraged (yet Gitlab CI does that by default)
|
|
||||||
%{root: true, user: "root", limit_users: ["root"]}
|
|
||||||
else
|
|
||||||
%{}
|
|
||||||
end
|
|
||||||
|
|
||||||
options =
|
|
||||||
options
|
|
||||||
|> Map.merge(Config.get([:exexec, :options], %{}))
|
|
||||||
|> Map.merge(options_overrides)
|
|
||||||
|
|
||||||
with {:error, {:already_started, pid}} <- Exexec.start(options) do
|
|
||||||
{:ok, pid}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def run(cmd, options \\ %{}) do
|
|
||||||
ensure_started()
|
|
||||||
Exexec.run(cmd, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
def cmd(cmd, options \\ %{}) do
|
|
||||||
options = Map.merge(%{sync: true, stdout: true}, options)
|
|
||||||
run(cmd, options)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -7,19 +7,24 @@ defmodule Pleroma.Helpers.MediaHelper do
|
||||||
Handles common media-related operations.
|
Handles common media-related operations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def ffmpeg_resize_remote(uri, %{max_width: max_width, max_height: max_height}) do
|
def ffmpeg_resize(uri_or_path, %{max_width: max_width, max_height: max_height}) do
|
||||||
cmd = ~s"""
|
cmd = ~s"""
|
||||||
curl -L "#{uri}" |
|
ffmpeg -i #{uri_or_path} -f lavfi -i color=c=white \
|
||||||
ffmpeg -i pipe:0 -f lavfi -i color=c=white \
|
|
||||||
-filter_complex "[0:v] scale='min(#{max_width},iw)':'min(#{max_height},ih)': \
|
-filter_complex "[0:v] scale='min(#{max_width},iw)':'min(#{max_height},ih)': \
|
||||||
force_original_aspect_ratio=decrease [scaled]; \
|
force_original_aspect_ratio=decrease [scaled]; \
|
||||||
[1][scaled] scale2ref [bg][img]; [bg] setsar=1 [bg]; [bg][img] overlay=shortest=1" \
|
[1][scaled] scale2ref [bg][img]; [bg] setsar=1 [bg]; [bg][img] overlay=shortest=1" \
|
||||||
-f image2 -vcodec mjpeg -frames:v 1 pipe:1 | \
|
-loglevel quiet -f image2 -vcodec mjpeg -frames:v 1 pipe:1
|
||||||
cat
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with {:ok, [stdout: stdout_list]} <- Pleroma.Exec.cmd(cmd) do
|
pid = Port.open({:spawn, cmd}, [:use_stdio, :in, :stream, :exit_status, :binary])
|
||||||
{:ok, Enum.join(stdout_list)}
|
|
||||||
|
receive do
|
||||||
|
{^pid, {:data, data}} ->
|
||||||
|
send(pid, {self(), :close})
|
||||||
|
{:ok, data}
|
||||||
|
|
||||||
|
{^pid, {:exit_status, status}} when status > 0 ->
|
||||||
|
{:error, status}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,6 +66,35 @@ defp handle_preview(conn, url) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp handle_preview("image/" <> _ = _content_type, conn, url) do
|
||||||
|
handle_image_or_video_preview(conn, url)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_preview("video/" <> _ = _content_type, conn, url) do
|
||||||
|
handle_image_or_video_preview(conn, url)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_preview(content_type, conn, _url) do
|
||||||
|
send_resp(conn, :unprocessable_entity, "Unsupported content type: #{content_type}.")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_image_or_video_preview(%{params: params} = conn, url) do
|
||||||
|
with {thumbnail_max_width, thumbnail_max_height} <- thumbnail_max_dimensions(params),
|
||||||
|
media_proxy_url <- MediaProxy.url(url),
|
||||||
|
{:ok, thumbnail_binary} <-
|
||||||
|
MediaHelper.ffmpeg_resize(
|
||||||
|
media_proxy_url,
|
||||||
|
%{max_width: thumbnail_max_width, max_height: thumbnail_max_height}
|
||||||
|
) do
|
||||||
|
conn
|
||||||
|
|> put_resp_header("content-type", "image/jpeg")
|
||||||
|
|> send_resp(200, thumbnail_binary)
|
||||||
|
else
|
||||||
|
_ ->
|
||||||
|
send_resp(conn, :failed_dependency, "Can't handle preview.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp thumbnail_max_dimensions(params) do
|
defp thumbnail_max_dimensions(params) do
|
||||||
config = Config.get([:media_preview_proxy], [])
|
config = Config.get([:media_preview_proxy], [])
|
||||||
|
|
||||||
|
@ -86,27 +115,6 @@ defp thumbnail_max_dimensions(params) do
|
||||||
{thumbnail_max_width, thumbnail_max_height}
|
{thumbnail_max_width, thumbnail_max_height}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_preview("image/" <> _ = _content_type, %{params: params} = conn, url) do
|
|
||||||
with {thumbnail_max_width, thumbnail_max_height} <- thumbnail_max_dimensions(params),
|
|
||||||
media_proxy_url <- MediaProxy.url(url),
|
|
||||||
{:ok, thumbnail_binary} <-
|
|
||||||
MediaHelper.ffmpeg_resize_remote(
|
|
||||||
media_proxy_url,
|
|
||||||
%{max_width: thumbnail_max_width, max_height: thumbnail_max_height}
|
|
||||||
) do
|
|
||||||
conn
|
|
||||||
|> put_resp_header("content-type", "image/jpeg")
|
|
||||||
|> send_resp(200, thumbnail_binary)
|
|
||||||
else
|
|
||||||
_ ->
|
|
||||||
send_resp(conn, :failed_dependency, "Can't handle image preview.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp handle_preview(content_type, conn, _url) do
|
|
||||||
send_resp(conn, :unprocessable_entity, "Unsupported content type: #{content_type}.")
|
|
||||||
end
|
|
||||||
|
|
||||||
defp preview_head_request_timeout do
|
defp preview_head_request_timeout do
|
||||||
Config.get([:media_preview_proxy, :proxy_opts, :head_request_max_read_duration]) ||
|
Config.get([:media_preview_proxy, :proxy_opts, :head_request_max_read_duration]) ||
|
||||||
preview_timeout()
|
preview_timeout()
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -186,8 +186,6 @@ defp deps do
|
||||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
|
git: "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git",
|
||||||
ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"},
|
ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"},
|
||||||
{:restarter, path: "./restarter"},
|
{:restarter, path: "./restarter"},
|
||||||
# Note: `runtime: true` for :exexec makes CI fail due to `root` user (see Pleroma.Exec)
|
|
||||||
{:exexec, "~> 0.2", runtime: false},
|
|
||||||
{:open_api_spex,
|
{:open_api_spex,
|
||||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/open_api_spex.git",
|
git: "https://git.pleroma.social/pleroma/elixir-libraries/open_api_spex.git",
|
||||||
ref: "f296ac0924ba3cf79c7a588c4c252889df4c2edd"},
|
ref: "f296ac0924ba3cf79c7a588c4c252889df4c2edd"},
|
||||||
|
|
2
mix.lock
2
mix.lock
|
@ -33,7 +33,6 @@
|
||||||
"ecto_sql": {:hex, :ecto_sql, "3.4.5", "30161f81b167d561a9a2df4329c10ae05ff36eca7ccc84628f2c8b9fa1e43323", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31990c6a3579b36a3c0841d34a94c275e727de8b84f58509da5f1b2032c98ac2"},
|
"ecto_sql": {:hex, :ecto_sql, "3.4.5", "30161f81b167d561a9a2df4329c10ae05ff36eca7ccc84628f2c8b9fa1e43323", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31990c6a3579b36a3c0841d34a94c275e727de8b84f58509da5f1b2032c98ac2"},
|
||||||
"eimp": {:hex, :eimp, "1.0.14", "fc297f0c7e2700457a95a60c7010a5f1dcb768a083b6d53f49cd94ab95a28f22", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "501133f3112079b92d9e22da8b88bf4f0e13d4d67ae9c15c42c30bd25ceb83b6"},
|
"eimp": {:hex, :eimp, "1.0.14", "fc297f0c7e2700457a95a60c7010a5f1dcb768a083b6d53f49cd94ab95a28f22", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "501133f3112079b92d9e22da8b88bf4f0e13d4d67ae9c15c42c30bd25ceb83b6"},
|
||||||
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
|
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
|
||||||
"erlexec": {:hex, :erlexec, "1.10.9", "3cbb3476f942bfb8b68b85721c21c1835061cf6dd35f5285c2362e85b100ddc7", [:rebar3], [], "hexpm", "271e5b5f2d91cdb9887efe74d89026c199bfc69f074cade0d08dab60993fa14e"},
|
|
||||||
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
|
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
|
||||||
"eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"},
|
"eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"},
|
||||||
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},
|
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},
|
||||||
|
@ -44,7 +43,6 @@
|
||||||
"ex_machina": {:hex, :ex_machina, "2.4.0", "09a34c5d371bfb5f78399029194a8ff67aff340ebe8ba19040181af35315eabb", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "a20bc9ddc721b33ea913b93666c5d0bdca5cbad7a67540784ae277228832d72c"},
|
"ex_machina": {:hex, :ex_machina, "2.4.0", "09a34c5d371bfb5f78399029194a8ff67aff340ebe8ba19040181af35315eabb", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "a20bc9ddc721b33ea913b93666c5d0bdca5cbad7a67540784ae277228832d72c"},
|
||||||
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
|
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
|
||||||
"excoveralls": {:hex, :excoveralls, "0.13.1", "b9f1697f7c9e0cfe15d1a1d737fb169c398803ffcbc57e672aa007e9fd42864c", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b4bb550e045def1b4d531a37fb766cbbe1307f7628bf8f0414168b3f52021cce"},
|
"excoveralls": {:hex, :excoveralls, "0.13.1", "b9f1697f7c9e0cfe15d1a1d737fb169c398803ffcbc57e672aa007e9fd42864c", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b4bb550e045def1b4d531a37fb766cbbe1307f7628bf8f0414168b3f52021cce"},
|
||||||
"exexec": {:hex, :exexec, "0.2.0", "a6ffc48cba3ac9420891b847e4dc7120692fb8c08c9e82220ebddc0bb8d96103", [:mix], [{:erlexec, "~> 1.10", [hex: :erlexec, repo: "hexpm", optional: false]}], "hexpm", "312cd1c9befba9e078e57f3541e4f4257eabda6eb9c348154fe899d6ac633299"},
|
|
||||||
"fast_html": {:hex, :fast_html, "2.0.1", "e126c74d287768ae78c48938da6711164517300d108a78f8a38993df8d588335", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "bdd6f8525c95ad391a4f10d9a1b3da4cea94078ec8638487aa8c24015ad9393a"},
|
"fast_html": {:hex, :fast_html, "2.0.1", "e126c74d287768ae78c48938da6711164517300d108a78f8a38993df8d588335", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "bdd6f8525c95ad391a4f10d9a1b3da4cea94078ec8638487aa8c24015ad9393a"},
|
||||||
"fast_sanitize": {:hex, :fast_sanitize, "0.2.0", "004b40d5bbecda182b6fdba762a51fffd3501e689e8eafe196e1a97eb0caf733", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "11fcb37f26d272a3a2aff861872bf100be4eeacea69505908b8cdbcea5b0813a"},
|
"fast_sanitize": {:hex, :fast_sanitize, "0.2.0", "004b40d5bbecda182b6fdba762a51fffd3501e689e8eafe196e1a97eb0caf733", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "11fcb37f26d272a3a2aff861872bf100be4eeacea69505908b8cdbcea5b0813a"},
|
||||||
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
|
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.ExecTest do
|
|
||||||
alias Pleroma.Exec
|
|
||||||
|
|
||||||
use Pleroma.DataCase
|
|
||||||
|
|
||||||
test "it starts" do
|
|
||||||
assert {:ok, _} = Exec.ensure_started()
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in a new issue