@@ -22,14 +22,17 @@ defmodule MusicLibrary.Assets.Image do
|
||||
[:music_library, :assets, :image, :resize],
|
||||
%{},
|
||||
fn ->
|
||||
{:ok, thumb} = Operation.thumbnail_buffer(cover_data, size)
|
||||
result = Image.write_to_buffer(thumb, extension(format))
|
||||
{result, %{}}
|
||||
with {:ok, thumb} <- Operation.thumbnail_buffer(cover_data, size),
|
||||
{:ok, _binary} = result <- Image.write_to_buffer(thumb, extension(format)) do
|
||||
{result, %{}}
|
||||
else
|
||||
{:error, _reason} = error -> {error, %{}}
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
@spec convert(binary(), String.t(), String.t()) :: {:ok, binary()}
|
||||
@spec convert(binary(), String.t(), String.t()) :: {:ok, binary()} | {:error, term()}
|
||||
def convert(cover_data, data_format, target_format) do
|
||||
if data_format == target_format do
|
||||
{:ok, cover_data}
|
||||
@@ -38,9 +41,12 @@ defmodule MusicLibrary.Assets.Image do
|
||||
[:music_library, :assets, :image, :convert],
|
||||
%{},
|
||||
fn ->
|
||||
{:ok, image} = Image.new_from_buffer(cover_data)
|
||||
result = Image.write_to_buffer(image, extension(target_format))
|
||||
{result, %{}}
|
||||
with {:ok, image} <- Image.new_from_buffer(cover_data),
|
||||
{:ok, _binary} = result <- Image.write_to_buffer(image, extension(target_format)) do
|
||||
{result, %{}}
|
||||
else
|
||||
{:error, _reason} = error -> {error, %{}}
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
@@ -25,6 +25,30 @@ defmodule MusicLibrary.Assets.Transform do
|
||||
|> Base.url_encode64(padding: false)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Decodes a Base64-encoded JSON payload into a transform struct.
|
||||
|
||||
Returns `{:error, :invalid_payload}` if the payload is not valid Base64 or JSON.
|
||||
|
||||
iex> alias MusicLibrary.Assets.Transform
|
||||
iex> payload = "eyJoYXNoIjoiYWJjMTIzIiwid2lkdGgiOjMwMH0"
|
||||
iex> Transform.decode(payload)
|
||||
{:ok, %Transform{hash: "abc123", width: 300}}
|
||||
|
||||
iex> alias MusicLibrary.Assets.Transform
|
||||
iex> Transform.decode("!!!invalid")
|
||||
{:error, :invalid_payload}
|
||||
"""
|
||||
@spec decode(payload()) :: {:ok, t()} | {:error, :invalid_payload}
|
||||
def decode(payload) do
|
||||
with {:ok, decoded} <- Base.url_decode64(payload, padding: false),
|
||||
{:ok, params} when is_map(params) <- JSON.decode(decoded) do
|
||||
{:ok, struct!(__MODULE__, %{hash: params["hash"], width: params["width"]})}
|
||||
else
|
||||
_ -> {:error, :invalid_payload}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
iex> alias MusicLibrary.Assets.Transform
|
||||
iex> payload = "eyJoYXNoIjoiYWJjMTIzIiwid2lkdGgiOjMwMH0"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
defmodule MusicLibraryWeb.AssetController do
|
||||
use MusicLibraryWeb, :controller
|
||||
|
||||
require Logger
|
||||
|
||||
alias MusicLibrary.Assets
|
||||
alias MusicLibrary.Assets.{Cache, Image, Transform}
|
||||
|
||||
@@ -9,16 +11,21 @@ defmodule MusicLibraryWeb.AssetController do
|
||||
|
||||
def show(conn, %{"transform_payload" => payload}) do
|
||||
format = pick_format(conn)
|
||||
transform = Transform.decode!(payload)
|
||||
|
||||
case cached_get(payload, transform, format) do
|
||||
nil ->
|
||||
not_found(conn)
|
||||
case Transform.decode(payload) do
|
||||
{:error, :invalid_payload} ->
|
||||
bad_request(conn)
|
||||
|
||||
content when is_binary(content) ->
|
||||
case get_req_header(conn, "if-none-match") do
|
||||
[^payload] -> extend_cache(conn)
|
||||
_ -> respond_with_cache(conn, content, format, payload)
|
||||
{:ok, transform} ->
|
||||
case cached_get(payload, transform, format) do
|
||||
nil ->
|
||||
not_found(conn)
|
||||
|
||||
content when is_binary(content) ->
|
||||
case get_req_header(conn, "if-none-match") do
|
||||
[^payload] -> extend_cache(conn)
|
||||
_ -> respond_with_cache(conn, content, format, payload)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -31,15 +38,22 @@ defmodule MusicLibraryWeb.AssetController do
|
||||
case Cache.get(payload, format) do
|
||||
:not_found ->
|
||||
if asset = Assets.get(transform.hash) do
|
||||
{:ok, image_data} =
|
||||
result =
|
||||
if transform.width do
|
||||
Image.resize(asset.content, transform.width, format)
|
||||
else
|
||||
Image.convert(asset.content, asset.format, format)
|
||||
end
|
||||
|
||||
Cache.set(payload, format, image_data)
|
||||
image_data
|
||||
case result do
|
||||
{:ok, image_data} ->
|
||||
Cache.set(payload, format, image_data)
|
||||
image_data
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.error("Asset transform failed for #{transform.hash}: #{inspect(reason)}")
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
{:found, content} ->
|
||||
@@ -61,6 +75,12 @@ defmodule MusicLibraryWeb.AssetController do
|
||||
end
|
||||
end
|
||||
|
||||
defp bad_request(conn) do
|
||||
conn
|
||||
|> put_status(:bad_request)
|
||||
|> text("Bad request")
|
||||
end
|
||||
|
||||
defp not_found(conn) do
|
||||
conn
|
||||
|> put_status(:not_found)
|
||||
|
||||
Reference in New Issue
Block a user