logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

analyze_metadata.ex (2948B)


  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. defmodule Pleroma.Upload.Filter.AnalyzeMetadata do
  5. @moduledoc """
  6. Extracts metadata about the upload, such as width/height
  7. """
  8. require Logger
  9. alias Vix.Vips.Image
  10. alias Vix.Vips.Operation
  11. @behaviour Pleroma.Upload.Filter
  12. @spec filter(Pleroma.Upload.t()) ::
  13. {:ok, :filtered, Pleroma.Upload.t()} | {:ok, :noop} | {:error, String.t()}
  14. def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _} = upload) do
  15. try do
  16. {:ok, image} = Image.new_from_file(file)
  17. {width, height} = {Image.width(image), Image.height(image)}
  18. upload =
  19. upload
  20. |> Map.put(:width, width)
  21. |> Map.put(:height, height)
  22. |> Map.put(:blurhash, get_blurhash(image))
  23. {:ok, :filtered, upload}
  24. rescue
  25. e in ErlangError ->
  26. Logger.warning("#{__MODULE__}: #{inspect(e)}")
  27. {:ok, :noop}
  28. end
  29. end
  30. def filter(%Pleroma.Upload{tempfile: file, content_type: "video" <> _} = upload) do
  31. try do
  32. result = media_dimensions(file)
  33. upload =
  34. upload
  35. |> Map.put(:width, result.width)
  36. |> Map.put(:height, result.height)
  37. {:ok, :filtered, upload}
  38. rescue
  39. e in ErlangError ->
  40. Logger.warning("#{__MODULE__}: #{inspect(e)}")
  41. {:ok, :noop}
  42. end
  43. end
  44. def filter(_), do: {:ok, :noop}
  45. defp get_blurhash(file) do
  46. with {:ok, blurhash} <- vips_blurhash(file) do
  47. blurhash
  48. else
  49. _ -> nil
  50. end
  51. end
  52. defp media_dimensions(file) do
  53. with executable when is_binary(executable) <- System.find_executable("ffprobe"),
  54. args = [
  55. "-v",
  56. "error",
  57. "-show_entries",
  58. "stream=width,height",
  59. "-of",
  60. "csv=p=0:s=x",
  61. file
  62. ],
  63. {result, 0} <- System.cmd(executable, args),
  64. [width, height] <-
  65. String.split(String.trim(result), "x") |> Enum.map(&String.to_integer(&1)) do
  66. %{width: width, height: height}
  67. else
  68. nil -> {:error, {:ffprobe, :command_not_found}}
  69. error -> {:error, error}
  70. end
  71. end
  72. defp vips_blurhash(%Vix.Vips.Image{} = image) do
  73. with {:ok, resized_image} <- Operation.thumbnail_image(image, 100),
  74. {height, width} <- {Image.height(resized_image), Image.width(resized_image)},
  75. max <- max(height, width),
  76. {x, y} <- {max(round(width * 5 / max), 1), max(round(height * 5 / max), 1)} do
  77. {:ok, rgb} =
  78. if Image.has_alpha?(resized_image) do
  79. # remove alpha channel
  80. resized_image
  81. |> Operation.extract_band!(0, n: 3)
  82. |> Image.write_to_binary()
  83. else
  84. Image.write_to_binary(resized_image)
  85. end
  86. Blurhash.encode(rgb, width, height, x, y)
  87. else
  88. _ -> nil
  89. end
  90. end
  91. end