1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Helpers.MediaHelper do
7 Handles common media-related operations.
11 alias Vix.Vips.Operation
15 @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
17 def missing_dependencies do
18 Enum.reduce([ffmpeg: "ffmpeg"], [], fn {sym, executable}, acc ->
19 if Pleroma.Utils.command_available?(executable) do
27 def image_resize(url, options) do
28 with {:ok, env} <- HTTP.get(url, [], pool: :media),
30 Operation.thumbnail_buffer(env.body, options.max_width,
31 height: options.max_height,
34 if options[:format] == "png" do
35 Operation.pngsave_buffer(resized, Q: options[:quality])
37 Operation.jpegsave_buffer(resized, Q: options[:quality], interlace: true)
40 {:error, _} = error -> error
44 # Note: video thumbnail is intentionally not resized (always has original dimensions)
45 @spec video_framegrab(String.t()) :: {:ok, binary()} | {:error, any()}
46 def video_framegrab(url) do
47 with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
48 false <- @cachex.exists?(:failed_media_helper_cache, url),
49 {:ok, env} <- HTTP.get(url, [], pool: :media),
50 {:ok, pid} <- StringIO.open(env.body) do
51 body_stream = IO.binstream(pid, 1)
73 case Task.yield(task, 5_000) do
76 @cachex.put(:failed_media_helper_cache, url, nil)
77 {:error, {:ffmpeg, :timeout}}
83 nil -> {:error, {:ffmpeg, :command_not_found}}
84 {:error, _} = error -> error