logo

pleroma

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

media_helper.ex (2547B)


  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.Helpers.MediaHelper do
  5. @moduledoc """
  6. Handles common media-related operations.
  7. """
  8. alias Pleroma.HTTP
  9. alias Vix.Vips.Operation
  10. require Logger
  11. @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
  12. def missing_dependencies do
  13. Enum.reduce([ffmpeg: "ffmpeg"], [], fn {sym, executable}, acc ->
  14. if Pleroma.Utils.command_available?(executable) do
  15. acc
  16. else
  17. [sym | acc]
  18. end
  19. end)
  20. end
  21. def image_resize(url, options) do
  22. with {:ok, env} <- HTTP.get(url, [], http_client_opts()),
  23. {:ok, resized} <-
  24. Operation.thumbnail_buffer(env.body, options.max_width,
  25. height: options.max_height,
  26. size: :VIPS_SIZE_DOWN
  27. ) do
  28. if options[:format] == "png" do
  29. Operation.pngsave_buffer(resized, Q: options[:quality])
  30. else
  31. Operation.jpegsave_buffer(resized, Q: options[:quality], interlace: true)
  32. end
  33. else
  34. {:error, _} = error -> error
  35. end
  36. end
  37. # Note: video thumbnail is intentionally not resized (always has original dimensions)
  38. @spec video_framegrab(String.t()) :: {:ok, binary()} | {:error, any()}
  39. def video_framegrab(url) do
  40. with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
  41. {:ok, false} <- @cachex.exists?(:failed_media_helper_cache, url),
  42. {:ok, env} <- HTTP.get(url, [], http_client_opts()),
  43. {:ok, pid} <- StringIO.open(env.body) do
  44. body_stream = IO.binstream(pid, 1)
  45. task =
  46. Task.async(fn ->
  47. Exile.stream!(
  48. [
  49. executable,
  50. "-i",
  51. "pipe:0",
  52. "-vframes",
  53. "1",
  54. "-f",
  55. "mjpeg",
  56. "pipe:1"
  57. ],
  58. input: body_stream,
  59. ignore_epipe: true,
  60. stderr: :disable
  61. )
  62. |> Enum.into(<<>>)
  63. end)
  64. case Task.yield(task, 5_000) do
  65. {:ok, result} ->
  66. {:ok, result}
  67. _ ->
  68. Task.shutdown(task)
  69. @cachex.put(:failed_media_helper_cache, url, nil)
  70. {:error, {:ffmpeg, :timeout}}
  71. end
  72. else
  73. nil -> {:error, {:ffmpeg, :command_not_found}}
  74. {:error, _} = error -> error
  75. end
  76. end
  77. defp http_client_opts, do: Pleroma.Config.get([:media_proxy, :proxy_opts, :http], pool: :media)
  78. end