Allow processors to indicate the thumbnail types they can generate

This commit is contained in:
byte[] 2022-02-07 22:12:40 -05:00
parent d961d6151f
commit 6e4771a57a
10 changed files with 93 additions and 29 deletions

View file

@ -17,7 +17,6 @@ config :philomena,
elasticsearch_url: System.get_env("ELASTICSEARCH_URL", "http://localhost:9200"),
advert_file_root: System.fetch_env!("ADVERT_FILE_ROOT"),
avatar_file_root: System.fetch_env!("AVATAR_FILE_ROOT"),
channel_url_root: System.fetch_env!("CHANNEL_URL_ROOT"),
badge_file_root: System.fetch_env!("BADGE_FILE_ROOT"),
password_pepper: System.fetch_env!("PASSWORD_PEPPER"),
avatar_url_root: System.fetch_env!("AVATAR_URL_ROOT"),
@ -32,6 +31,7 @@ config :philomena,
tag_url_root: System.fetch_env!("TAG_URL_ROOT"),
redis_host: System.get_env("REDIS_HOST", "localhost"),
proxy_host: System.get_env("PROXY_HOST"),
s3_bucket: System.fetch_env!("S3_BUCKET")
camo_host: System.get_env("CAMO_HOST"),
camo_key: System.get_env("CAMO_KEY"),
cdn_host: System.fetch_env!("CDN_HOST")

View file

@ -17,17 +17,16 @@ services:
- PASSWORD_PEPPER=dn2e0EpZrvBLoxUM3gfQveBhjf0bG/6/bYhrOyq3L3hV9hdo/bimJ+irbDWsuXLP
- TUMBLR_API_KEY=fuiKNFp9vQFvjLNvx4sUwti4Yb5yGutBN4Xh10LXZhhRKjWlV4
- OTP_SECRET_KEY=Wn7O/8DD+qxL0X4X7bvT90wOkVGcA90bIHww4twR03Ci//zq7PnMw8ypqyyT/b/C
- ADVERT_FILE_ROOT=priv/static/system/images/adverts
- AVATAR_FILE_ROOT=priv/static/system/images/avatars
- BADGE_FILE_ROOT=priv/static/system/images
- IMAGE_FILE_ROOT=priv/static/system/images
- TAG_FILE_ROOT=priv/static/system/images
- CHANNEL_URL_ROOT=/media
- ADVERT_FILE_ROOT=adverts
- AVATAR_FILE_ROOT=avatars
- BADGE_FILE_ROOT=badges
- IMAGE_FILE_ROOT=images
- TAG_FILE_ROOT=tags
- AVATAR_URL_ROOT=/avatars
- ADVERT_URL_ROOT=/spns
- IMAGE_URL_ROOT=/img
- BADGE_URL_ROOT=/media
- TAG_URL_ROOT=/media
- BADGE_URL_ROOT=/badges
- TAG_URL_ROOT=/tags
- ELASTICSEARCH_URL=http://elasticsearch:9200
- REDIS_HOST=redis
- DATABASE_URL=ecto://postgres:postgres@postgres/philomena_dev

View file

@ -10,6 +10,7 @@ defmodule Philomena.Images.Thumbnailer do
alias Philomena.Analyzers
alias Philomena.Sha512
alias Philomena.Repo
alias ExAws.S3
@versions [
thumb_tiny: {50, 50},
@ -18,27 +19,24 @@ defmodule Philomena.Images.Thumbnailer do
small: {320, 240},
medium: {800, 600},
large: {1280, 1024},
tall: {1024, 4096},
full: nil
tall: {1024, 4096}
]
def thumbnail_versions do
Enum.filter(@versions, fn {_name, dimensions} ->
not is_nil(dimensions)
end)
@versions
end
def thumbnail_urls(image, hidden_key) do
Path.join([image_thumb_dir(image), "*"])
|> Path.wildcard()
|> Enum.map(fn version_name ->
Path.join([image_url_base(image, hidden_key), Path.basename(version_name)])
# A list of version sizes that should be generated for the image,
# based on its dimensions. The processor can generate a list of paths.
def generated_sizes(%{image_width: image_width, image_height: image_height}) do
Enum.filter(@versions, fn
{_name, {width, height}} -> image_width > width or image_height > height
end)
end
def generate_thumbnails(image_id) do
image = Repo.get!(Image, image_id)
file = image_file(image)
file = download_image_file(image)
{:ok, analysis} = Analyzers.analyze(file)
apply_edit_script(image, Processors.process(analysis, file, @versions))
@ -135,6 +133,24 @@ defmodule Philomena.Images.Thumbnailer do
def image_file(%Image{image: image}),
do: Path.join(image_file_root(), image)
defp download_image_file(%Image{image: path} = image) do
tempfile = Briefly.create!(extname: "." <> image.image_format)
path = Path.join(image_file_root(), path)
ExAws.request!(S3.download_file(bucket(), path, tempfile))
tempfile
end
defp upload_image_file(%Image{image: path}, new_file) do
path = Path.join(image_file_root(), path)
new_file
|> S3.Upload.stream_file()
|> S3.upload(bucket(), path, acl: :public_read)
|> ExAws.request!()
end
def image_thumb_dir(%Image{
created_at: created_at,
id: id,
@ -163,4 +179,8 @@ defmodule Philomena.Images.Thumbnailer do
defp image_url_root,
do: Application.get_env(:philomena, :image_url_root)
defp bucket() do
Application.fetch_env!(:philomena, :s3_bucket)
end
end

View file

@ -40,6 +40,15 @@ defmodule Philomena.Processors do
def processor("video/webm"), do: Webm
def processor(_content_type), do: nil
@doc """
Takes an analyzer and version list and generates a list of versions to be
generated (e.g., ["thumb.png"]). List contents differ based on file type.
"""
@spec versions(map(), keyword) :: [String.t()]
def versions(analysis, valid_sizes) do
processor(analysis.mime_type).versions(valid_sizes)
end
@doc """
Takes an analyzer, file path, and version list and runs the appropriate
processor's process/3.

View file

@ -1,6 +1,12 @@
defmodule Philomena.Processors.Gif do
alias Philomena.Intensities
def versions(sizes) do
sizes
|> Enum.map(fn {name, _} -> "#{name}.gif" end)
|> Kernel.++(["full.webm", "full.mp4", "rendered.png"])
end
def process(analysis, file, versions) do
dimensions = analysis.dimensions
duration = analysis.duration

View file

@ -1,6 +1,10 @@
defmodule Philomena.Processors.Jpeg do
alias Philomena.Intensities
def versions(sizes) do
Enum.map(sizes, fn {name, _} -> "#{name}.jpg" end)
end
def process(analysis, file, versions) do
dimensions = analysis.dimensions
stripped = optimize(strip(file))

View file

@ -1,6 +1,10 @@
defmodule Philomena.Processors.Png do
alias Philomena.Intensities
def versions(sizes) do
Enum.map(sizes, fn {name, _} -> "#{name}.png" end)
end
def process(analysis, file, versions) do
dimensions = analysis.dimensions
animated? = analysis.animated?

View file

@ -1,6 +1,12 @@
defmodule Philomena.Processors.Svg do
alias Philomena.Intensities
def versions(sizes) do
sizes
|> Enum.map(fn {name, _} -> "#{name}.png" end)
|> Kernel.++(["rendered.png", "full.png"])
end
def process(analysis, file, versions) do
preview = preview(file)

View file

@ -2,6 +2,17 @@ defmodule Philomena.Processors.Webm do
alias Philomena.Intensities
import Bitwise
def versions(sizes) do
webm_versions = Enum.map(sizes, fn {name, _} -> "#{name}.webm" end)
mp4_versions = Enum.map(sizes, fn {name, _} -> "#{name}.mp4" end)
gif_versions =
sizes
|> Enum.filter(fn {name, _} -> name in [:thumb_tiny, :thumb_small, :thumb] end)
|> Enum.map(fn {name, _} -> "#{name}.gif" end)
webm_versions ++ mp4_versions ++ gif_versions
end
def process(analysis, file, versions) do
dimensions = analysis.dimensions
duration = analysis.duration

View file

@ -6,6 +6,7 @@ defmodule Philomena.Uploader do
alias Philomena.Filename
alias Philomena.Analyzers
alias Philomena.Sha512
alias ExAws.S3
import Ecto.Changeset
@doc """
@ -58,18 +59,15 @@ defmodule Philomena.Uploader do
in the transaction.
"""
@spec persist_upload(any(), String.t(), String.t()) :: any()
# sobelow_skip ["Traversal"]
def persist_upload(model, file_root, field_name) do
source = Map.get(model, field(upload_key(field_name)))
dest = Map.get(model, field(field_name))
target = Path.join(file_root, dest)
dir = Path.dirname(target)
# Create the target directory if it doesn't exist yet,
# then write the file.
File.mkdir_p!(dir)
File.cp!(source, target)
source
|> S3.Upload.stream_file()
|> S3.upload(bucket(), target, acl: :public_read)
|> ExAws.request!()
end
@doc """
@ -107,8 +105,11 @@ defmodule Philomena.Uploader do
defp try_remove("", _file_root), do: nil
defp try_remove(nil, _file_root), do: nil
# sobelow_skip ["Traversal.FileModule"]
defp try_remove(file, file_root), do: File.rm(Path.join(file_root, file))
defp try_remove(file, file_root) do
path = Path.join(file_root, file)
ExAws.request!(S3.delete_object(bucket(), path))
end
defp prefix_attributes(map, prefix),
do: Map.new(map, fn {key, value} -> {"#{prefix}_#{key}", value} end)
@ -118,4 +119,8 @@ defmodule Philomena.Uploader do
defp remove_key(field_name), do: "removed_#{field_name}"
defp field(field_name), do: String.to_existing_atom(field_name)
defp bucket do
Application.fetch_env!(:philomena, :s3_bucket)
end
end