Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

163 行
3.8KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 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. require Logger
  10. def missing_dependencies do
  11. Enum.reduce([imagemagick: "convert", ffmpeg: "ffmpeg"], [], fn {sym, executable}, acc ->
  12. if Pleroma.Utils.command_available?(executable) do
  13. acc
  14. else
  15. [sym | acc]
  16. end
  17. end)
  18. end
  19. def image_resize(url, options) do
  20. with executable when is_binary(executable) <- System.find_executable("convert"),
  21. {:ok, args} <- prepare_image_resize_args(options),
  22. {:ok, env} <- HTTP.get(url, [], pool: :media),
  23. {:ok, fifo_path} <- mkfifo() do
  24. args = List.flatten([fifo_path, args])
  25. run_fifo(fifo_path, env, executable, args)
  26. else
  27. nil -> {:error, {:convert, :command_not_found}}
  28. {:error, _} = error -> error
  29. end
  30. end
  31. defp prepare_image_resize_args(
  32. %{max_width: max_width, max_height: max_height, format: "png"} = options
  33. ) do
  34. quality = options[:quality] || 85
  35. resize = Enum.join([max_width, "x", max_height, ">"])
  36. args = [
  37. "-resize",
  38. resize,
  39. "-quality",
  40. to_string(quality),
  41. "png:-"
  42. ]
  43. {:ok, args}
  44. end
  45. defp prepare_image_resize_args(%{max_width: max_width, max_height: max_height} = options) do
  46. quality = options[:quality] || 85
  47. resize = Enum.join([max_width, "x", max_height, ">"])
  48. args = [
  49. "-interlace",
  50. "Plane",
  51. "-resize",
  52. resize,
  53. "-quality",
  54. to_string(quality),
  55. "jpg:-"
  56. ]
  57. {:ok, args}
  58. end
  59. defp prepare_image_resize_args(_), do: {:error, :missing_options}
  60. # Note: video thumbnail is intentionally not resized (always has original dimensions)
  61. def video_framegrab(url) do
  62. with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
  63. {:ok, env} <- HTTP.get(url, [], pool: :media),
  64. {:ok, fifo_path} <- mkfifo(),
  65. args = [
  66. "-y",
  67. "-i",
  68. fifo_path,
  69. "-vframes",
  70. "1",
  71. "-f",
  72. "mjpeg",
  73. "-loglevel",
  74. "error",
  75. "-"
  76. ] do
  77. run_fifo(fifo_path, env, executable, args)
  78. else
  79. nil -> {:error, {:ffmpeg, :command_not_found}}
  80. {:error, _} = error -> error
  81. end
  82. end
  83. defp run_fifo(fifo_path, env, executable, args) do
  84. pid =
  85. Port.open({:spawn_executable, executable}, [
  86. :use_stdio,
  87. :stream,
  88. :exit_status,
  89. :binary,
  90. args: args
  91. ])
  92. fifo = Port.open(to_charlist(fifo_path), [:eof, :binary, :stream, :out])
  93. fix = Pleroma.Helpers.QtFastStart.fix(env.body)
  94. true = Port.command(fifo, fix)
  95. :erlang.port_close(fifo)
  96. loop_recv(pid)
  97. after
  98. File.rm(fifo_path)
  99. end
  100. defp mkfifo do
  101. path = Path.join(System.tmp_dir!(), "pleroma-media-preview-pipe-#{Ecto.UUID.generate()}")
  102. case System.cmd("mkfifo", [path]) do
  103. {_, 0} ->
  104. spawn(fifo_guard(path))
  105. {:ok, path}
  106. {_, err} ->
  107. {:error, {:fifo_failed, err}}
  108. end
  109. end
  110. defp fifo_guard(path) do
  111. pid = self()
  112. fn ->
  113. ref = Process.monitor(pid)
  114. receive do
  115. {:DOWN, ^ref, :process, ^pid, _} ->
  116. File.rm(path)
  117. end
  118. end
  119. end
  120. defp loop_recv(pid) do
  121. loop_recv(pid, <<>>)
  122. end
  123. defp loop_recv(pid, acc) do
  124. receive do
  125. {^pid, {:data, data}} ->
  126. loop_recv(pid, acc <> data)
  127. {^pid, {:exit_status, 0}} ->
  128. {:ok, acc}
  129. {^pid, {:exit_status, status}} ->
  130. {:error, status}
  131. after
  132. 5000 ->
  133. :erlang.port_close(pid)
  134. {:error, :timeout}
  135. end
  136. end
  137. end