diff --git a/docker/mediaproc/Dockerfile b/docker/mediaproc/Dockerfile index 98e18261a..56af24756 100644 --- a/docker/mediaproc/Dockerfile +++ b/docker/mediaproc/Dockerfile @@ -12,7 +12,7 @@ ADD https://api.github.com/repos/philomena-dev/mediatools/git/refs/heads/master RUN wget -qO /tmp/FFmpeg.tar.gz https://github.com/philomena-dev/FFmpeg/archive/refs/heads/release/8.0.tar.gz \ && wget -qO /tmp/cli_intensities.tar.gz https://github.com/philomena-dev/cli_intensities/archive/refs/heads/master.tar.gz \ - && wget -qO /tmp/mediatools.tar.gz https://github.com/philomena-dev/mediatools/archive/refs/heads/master.tar.gz + && wget -qO /tmp/mediatools.tar.gz https://github.com/philomena-dev/mediatools/archive/refs/tags/1.2.3.tar.gz RUN cd /tmp \ && tar -xf FFmpeg.tar.gz \ @@ -57,7 +57,7 @@ RUN cd /tmp \ && make -j$(nproc) install \ && cd /tmp/cli_intensities-master \ && make -j$(nproc) install \ - && cd /tmp/mediatools-master \ + && cd /tmp/mediatools-1.2.3 \ && make -j$(nproc) install COPY native/philomena /tmp/philomena diff --git a/lib/philomena/images/image.ex b/lib/philomena/images/image.ex index b9a35125f..eaf713bbf 100644 --- a/lib/philomena/images/image.ex +++ b/lib/philomena/images/image.ex @@ -242,7 +242,9 @@ defmodule Philomena.Images.Image do :image_size, :image_width, :image_height, - :image_aspect_ratio + :image_aspect_ratio, + :image_is_animated, + :image_duration ]) |> change(thumbnails_generated: true, duplication_checked: true) end @@ -254,7 +256,9 @@ defmodule Philomena.Images.Image do :image_size, :image_width, :image_height, - :image_aspect_ratio + :image_aspect_ratio, + :image_is_animated, + :image_duration ]) |> change(processed: true) end diff --git a/lib/philomena/images/thumbnailer.ex b/lib/philomena/images/thumbnailer.ex index 1beea1465..5b850d6e6 100644 --- a/lib/philomena/images/thumbnailer.ex +++ b/lib/philomena/images/thumbnailer.ex @@ -132,7 +132,9 @@ defmodule Philomena.Images.Thumbnailer do end defp recompute_meta(image, file, changeset_fn) do - {:ok, %{dimensions: {width, height}}} = Analyzers.analyze_path(file) + {:ok, analysis} = Analyzers.analyze_path(file) + + %{dimensions: {width, height}} = analysis image |> changeset_fn.(%{ @@ -140,7 +142,9 @@ defmodule Philomena.Images.Thumbnailer do "image_size" => File.stat!(file).size, "image_width" => width, "image_height" => height, - "image_aspect_ratio" => width / height + "image_aspect_ratio" => width / height, + "image_is_animated" => analysis.animated?, + "image_duration" => analysis.duration }) |> Repo.update!() end diff --git a/lib/philomena_media/analyzers.ex b/lib/philomena_media/analyzers.ex index 7c97e8454..a74cf3358 100644 --- a/lib/philomena_media/analyzers.ex +++ b/lib/philomena_media/analyzers.ex @@ -65,6 +65,7 @@ defmodule PhilomenaMedia.Analyzers do :error = Analyzers.analyze_path(file) """ + @spec analyze_path(Path.t()) :: {:ok, Result.t()} | {:unsupported_mime, Mime.t()} def analyze_path(path) when is_binary(path) do with {:ok, mime} <- Mime.file(path), {:ok, analyzer} <- analyzer(mime) do diff --git a/lib/philomena_media/analyzers/gif.ex b/lib/philomena_media/analyzers/gif.ex index 2c1365d0e..52d15cd60 100644 --- a/lib/philomena_media/analyzers/gif.ex +++ b/lib/philomena_media/analyzers/gif.ex @@ -23,7 +23,7 @@ defmodule PhilomenaMedia.Analyzers.Gif do defp stats(file) do case Remote.cmd("mediastat", [file]) do {output, 0} -> - [_size, frames, width, height, num, den] = + [_animated, frames, width, height, num, den] = output |> String.trim() |> String.split(" ") diff --git a/lib/philomena_media/analyzers/jpeg.ex b/lib/philomena_media/analyzers/jpeg.ex index cca1d8810..cf671aaad 100644 --- a/lib/philomena_media/analyzers/jpeg.ex +++ b/lib/philomena_media/analyzers/jpeg.ex @@ -23,7 +23,7 @@ defmodule PhilomenaMedia.Analyzers.Jpeg do defp stats(file) do case Remote.cmd("mediastat", [file]) do {output, 0} -> - [_size, _frames, width, height, num, den] = + [_animated, _frames, width, height, num, den] = output |> String.trim() |> String.split(" ") diff --git a/lib/philomena_media/analyzers/png.ex b/lib/philomena_media/analyzers/png.ex index a01d68abf..9f031c33b 100644 --- a/lib/philomena_media/analyzers/png.ex +++ b/lib/philomena_media/analyzers/png.ex @@ -23,13 +23,13 @@ defmodule PhilomenaMedia.Analyzers.Png do defp stats(file) do case Remote.cmd("mediastat", [file]) do {output, 0} -> - [_size, frames, width, height, num, den] = + [animated, _frames, width, height, num, den] = output |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1) - %{animated?: frames > 1, dimensions: {width, height}, duration: num / den} + %{animated?: animated != 0, dimensions: {width, height}, duration: num / den} _ -> %{animated?: false, dimensions: {0, 0}, duration: 0.0} diff --git a/lib/philomena_media/analyzers/svg.ex b/lib/philomena_media/analyzers/svg.ex index 0b55a5681..6b7256835 100644 --- a/lib/philomena_media/analyzers/svg.ex +++ b/lib/philomena_media/analyzers/svg.ex @@ -23,7 +23,7 @@ defmodule PhilomenaMedia.Analyzers.Svg do defp stats(file) do case Remote.cmd("svgstat", [file]) do {output, 0} -> - [_size, _frames, width, height, _num, _den] = + [_animated, _frames, width, height, _num, _den] = output |> String.trim() |> String.split(" ") diff --git a/lib/philomena_media/analyzers/webm.ex b/lib/philomena_media/analyzers/webm.ex index fb785923e..8f010a4ce 100644 --- a/lib/philomena_media/analyzers/webm.ex +++ b/lib/philomena_media/analyzers/webm.ex @@ -23,7 +23,7 @@ defmodule PhilomenaMedia.Analyzers.Webm do defp stats(file) do case Remote.cmd("mediastat", [file]) do {output, 0} -> - [_size, frames, width, height, num, den] = + [_animated, frames, width, height, num, den] = output |> String.trim() |> String.split(" ") diff --git a/lib/philomena_media/processors/png.ex b/lib/philomena_media/processors/png.ex index 30d60d94e..2a5573629 100644 --- a/lib/philomena_media/processors/png.ex +++ b/lib/philomena_media/processors/png.ex @@ -2,6 +2,7 @@ defmodule PhilomenaMedia.Processors.Png do @moduledoc false alias PhilomenaMedia.Intensities + alias PhilomenaMedia.Analyzers alias PhilomenaMedia.Analyzers.Result alias PhilomenaMedia.Remote alias PhilomenaMedia.Processors.Processor @@ -17,9 +18,7 @@ defmodule PhilomenaMedia.Processors.Png do @spec process(Result.t(), Path.t(), Processors.version_list()) :: Processors.edit_script() def process(analysis, file, versions) do - animated? = analysis.animated? - - stripped = strip(file, animated?) + {stripped, animated?} = strip(file, analysis.animated?) {:ok, intensities} = Intensities.file(stripped) @@ -55,8 +54,36 @@ defmodule PhilomenaMedia.Processors.Png do intensities end - defp strip(file, true = _animated?), do: file - defp strip(file, _animated?), do: Strip.strip(file, ".png") + @spec strip(Path.t(), boolean()) :: {Path.t(), boolean()} + defp strip(file, false = animated?), do: {Strip.strip(file, ".png"), animated?} + + defp strip(file, _animated?) do + stripped = Briefly.create!(extname: ".png") + + # Transcode animated PNG to normalize the format + {_output, 0} = + Remote.cmd("ffmpeg", [ + "-loglevel", + "0", + "-y", + "-i", + file, + "-plays", + "0", + "-f", + "apng", + stripped + ]) + + analysis = Analyzers.Png.analyze(stripped) + + if analysis.animated? do + {stripped, analysis.animated?} + else + # If not considered animated after normalization, perform strip + {Strip.strip(stripped, ".png"), analysis.animated?} + end + end # Sobelow misidentifies removing the .bak file # sobelow_skip ["Traversal.FileModule"]