[#2497] Image preview proxy: implemented ffmpeg-based resizing, removed eimp & mogrif...
[akkoma] / lib / pleroma / helpers / media_helper.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Helpers.MediaHelper do
6 @moduledoc """
7 Handles common media-related operations.
8 """
9
10 @ffmpeg_opts [{:sync, true}, {:stdout, true}]
11
12 def ffmpeg_resize_remote(uri, max_width, max_height) do
13 cmd = ~s"""
14 curl -L "#{uri}" |
15 ffmpeg -i pipe:0 -vf \
16 "scale='min(#{max_width},iw)':min'(#{max_height},ih)':force_original_aspect_ratio=decrease" \
17 -f image2 pipe:1 | \
18 cat
19 """
20
21 with {:ok, [stdout: stdout_list]} <- Exexec.run(cmd, @ffmpeg_opts) do
22 {:ok, Enum.join(stdout_list)}
23 end
24 end
25
26 @doc "Returns a temporary path for an URI"
27 def temporary_path_for(uri) do
28 name = Path.basename(uri)
29 random = rand_uniform(999_999)
30 Path.join(System.tmp_dir(), "#{random}-#{name}")
31 end
32
33 @doc "Stores binary content fetched from specified URL as a temporary file."
34 @spec store_as_temporary_file(String.t(), binary()) :: {:ok, String.t()} | {:error, atom()}
35 def store_as_temporary_file(url, body) do
36 path = temporary_path_for(url)
37 with :ok <- File.write(path, body), do: {:ok, path}
38 end
39
40 @doc "Modifies image file at specified path by resizing to specified limit dimensions."
41 @spec mogrify_resize_to_limit(String.t(), String.t()) :: :ok | any()
42 def mogrify_resize_to_limit(path, resize_dimensions) do
43 with %Mogrify.Image{} <-
44 path
45 |> Mogrify.open()
46 |> Mogrify.resize_to_limit(resize_dimensions)
47 |> Mogrify.save(in_place: true) do
48 :ok
49 end
50 end
51
52 defp rand_uniform(high) do
53 Code.ensure_loaded(:rand)
54
55 if function_exported?(:rand, :uniform, 1) do
56 :rand.uniform(high)
57 else
58 # Erlang/OTP < 19
59 apply(:crypto, :rand_uniform, [1, high])
60 end
61 end
62 end