X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fhelpers%2Fmedia_helper.ex;h=cfb091f8252507e7807adc3f6531fba360db339d;hb=f25b0e87f3dd73e02c954c5baab3c52becdd9c9e;hp=e11038052d6bd5df2c99c91617bf13cfd85901ac;hpb=aa0a5ffb4849880b5adbcc9188de01ef778381e3;p=akkoma diff --git a/lib/pleroma/helpers/media_helper.ex b/lib/pleroma/helpers/media_helper.ex index e11038052..cfb091f82 100644 --- a/lib/pleroma/helpers/media_helper.ex +++ b/lib/pleroma/helpers/media_helper.ex @@ -7,26 +7,143 @@ defmodule Pleroma.Helpers.MediaHelper do Handles common media-related operations. """ - def ffmpeg_resize(uri_or_path, %{max_width: max_width, max_height: max_height} = options) do - quality = options[:quality] || 1 + @tmp_base "/tmp/pleroma-media_preview-pipe" - cmd = ~s""" - ffmpeg -i #{uri_or_path} -f lavfi -i color=c=white \ - -filter_complex "[0:v] scale='min(#{max_width},iw)':'min(#{max_height},ih)': \ - force_original_aspect_ratio=decrease [scaled]; \ - [1][scaled] scale2ref [bg][img]; [bg] setsar=1 [bg]; [bg][img] overlay=shortest=1" \ - -loglevel quiet -f image2 -vcodec mjpeg -frames:v 1 -q:v #{quality} pipe:1 - """ + def image_resize(url, options) do + with executable when is_binary(executable) <- System.find_executable("convert"), + {:ok, args} <- prepare_image_resize_args(options), + {:ok, env} <- Pleroma.HTTP.get(url, [], [adapter: [pool: :preview]]), + {:ok, fifo_path} <- mkfifo() do + args = List.flatten([fifo_path, args]) + run_fifo(fifo_path, env, executable, args) + else + nil -> {:error, {:convert, :command_not_found}} + {:error, _} = error -> error + end + end + + defp prepare_image_resize_args( + %{max_width: max_width, max_height: max_height, format: "png"} = options + ) do + quality = options[:quality] || 85 + resize = Enum.join([max_width, "x", max_height, ">"]) + + args = [ + "-resize", + resize, + "-quality", + to_string(quality), + "png:-" + ] - pid = Port.open({:spawn, cmd}, [:use_stdio, :in, :stream, :exit_status, :binary]) + {:ok, args} + end + + defp prepare_image_resize_args(%{max_width: max_width, max_height: max_height} = options) do + quality = options[:quality] || 85 + resize = Enum.join([max_width, "x", max_height, ">"]) + args = [ + "-interlace", + "Plane", + "-resize", + resize, + "-quality", + to_string(quality), + "jpg:-" + ] + + {:ok, args} + end + + defp prepare_image_resize_args(_), do: {:error, :missing_options} + + def video_framegrab(url) do + with executable when is_binary(executable) <- System.find_executable("ffmpeg"), + {:ok, env} <- Pleroma.HTTP.get(url, [], [adapter: [pool: :preview]]), + {:ok, fifo_path} <- mkfifo(), + args = [ + "-y", + "-i", + fifo_path, + "-vframes", + "1", + "-f", + "mjpeg", + "-loglevel", + "error", + "-" + ] do + run_fifo(fifo_path, env, executable, args) + else + nil -> {:error, {:ffmpeg, :command_not_found}} + {:error, _} = error -> error + end + end + + defp run_fifo(fifo_path, env, executable, args) do + pid = + Port.open({:spawn_executable, executable}, [ + :use_stdio, + :stream, + :exit_status, + :binary, + args: args + ]) + + fifo = Port.open(to_charlist(fifo_path), [:eof, :binary, :stream, :out]) + fix = Pleroma.Helpers.QtFastStart.fix(env.body) + true = Port.command(fifo, fix) + :erlang.port_close(fifo) + loop_recv(pid) + after + File.rm(fifo_path) + end + + defp mkfifo do + path = "#{@tmp_base}#{to_charlist(:erlang.phash2(self()))}" + + case System.cmd("mkfifo", [path]) do + {_, 0} -> + spawn(fifo_guard(path)) + {:ok, path} + + {_, err} -> + {:error, {:fifo_failed, err}} + end + end + + defp fifo_guard(path) do + pid = self() + + fn -> + ref = Process.monitor(pid) + + receive do + {:DOWN, ^ref, :process, ^pid, _} -> + File.rm(path) + end + end + end + + defp loop_recv(pid) do + loop_recv(pid, <<>>) + end + + defp loop_recv(pid, acc) do receive do {^pid, {:data, data}} -> - send(pid, {self(), :close}) - {:ok, data} + loop_recv(pid, acc <> data) + + {^pid, {:exit_status, 0}} -> + {:ok, acc} - {^pid, {:exit_status, status}} when status > 0 -> + {^pid, {:exit_status, status}} -> {:error, status} + after + 5000 -> + :erlang.port_close(pid) + {:error, :timeout} end end end