move to 2.5.5
[anni] / lib / pleroma / upload / filter / analyze_metadata.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Upload.Filter.AnalyzeMetadata do
6   @moduledoc """
7   Extracts metadata about the upload, such as width/height
8   """
9   require Logger
10
11   @behaviour Pleroma.Upload.Filter
12
13   @spec filter(Pleroma.Upload.t()) ::
14           {:ok, :filtered, Pleroma.Upload.t()} | {:ok, :noop} | {:error, String.t()}
15   def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _} = upload) do
16     try do
17       image =
18         file
19         |> Mogrify.open()
20         |> Mogrify.verbose()
21
22       upload =
23         upload
24         |> Map.put(:width, image.width)
25         |> Map.put(:height, image.height)
26         |> Map.put(:blurhash, get_blurhash(file))
27
28       {:ok, :filtered, upload}
29     rescue
30       e in ErlangError ->
31         Logger.warn("#{__MODULE__}: #{inspect(e)}")
32         {:ok, :noop}
33     end
34   end
35
36   def filter(%Pleroma.Upload{tempfile: file, content_type: "video" <> _} = upload) do
37     try do
38       result = media_dimensions(file)
39
40       upload =
41         upload
42         |> Map.put(:width, result.width)
43         |> Map.put(:height, result.height)
44
45       {:ok, :filtered, upload}
46     rescue
47       e in ErlangError ->
48         Logger.warn("#{__MODULE__}: #{inspect(e)}")
49         {:ok, :noop}
50     end
51   end
52
53   def filter(_), do: {:ok, :noop}
54
55   defp get_blurhash(file) do
56     with {:ok, blurhash} <- :eblurhash.magick(file) do
57       blurhash
58     else
59       _ -> nil
60     end
61   end
62
63   defp media_dimensions(file) do
64     with executable when is_binary(executable) <- System.find_executable("ffprobe"),
65          args = [
66            "-v",
67            "error",
68            "-show_entries",
69            "stream=width,height",
70            "-of",
71            "csv=p=0:s=x",
72            file
73          ],
74          {result, 0} <- System.cmd(executable, args),
75          [width, height] <-
76            String.split(String.trim(result), "x") |> Enum.map(&String.to_integer(&1)) do
77       %{width: width, height: height}
78     else
79       nil -> {:error, {:ffprobe, :command_not_found}}
80       {:error, _} = error -> error
81     end
82   end
83 end