berrypod/lib/berrypod_web/controllers/favicon_controller.ex

105 lines
2.8 KiB
Elixir
Raw Normal View History

defmodule BerrypodWeb.FaviconController do
use BerrypodWeb, :controller
alias Berrypod.Media
alias Berrypod.Settings
@one_day 86_400
def favicon_svg(conn, _params) do
case Media.get_favicon_variants() do
%{svg: svg} when is_binary(svg) ->
conn
|> maybe_not_modified("svg")
|> serve("image/svg+xml", svg)
_ ->
send_resp(conn, 404, "")
end
end
def favicon_32(conn, _params), do: serve_variant(conn, :png_32)
def apple_touch_icon(conn, _params), do: serve_variant(conn, :png_180)
def icon_192(conn, _params), do: serve_variant(conn, :png_192)
def icon_512(conn, _params), do: serve_variant(conn, :png_512)
def webmanifest(conn, _params) do
settings = Settings.get_theme_settings()
short_name =
case settings.favicon_short_name do
name when is_binary(name) and name != "" -> name
_ -> String.slice(settings.site_name, 0, 12)
end
manifest = %{
name: settings.site_name,
short_name: short_name,
theme_color: settings.accent_color || "#000000",
background_color: settings.icon_background_color || "#ffffff",
display: "minimal-ui",
start_url: "/",
icons: [
%{src: "/icon-192.png", sizes: "192x192", type: "image/png"},
%{src: "/icon-512.png", sizes: "512x512", type: "image/png", purpose: "maskable"}
]
}
conn
|> put_resp_content_type("application/manifest+json")
|> put_resp_header("cache-control", "public, max-age=#{@one_day}")
|> json(manifest)
end
defp serve_variant(conn, field) do
case Media.get_favicon_variants() do
nil ->
send_resp(conn, 404, "")
variants ->
case Map.get(variants, field) do
data when is_binary(data) ->
conn
|> maybe_not_modified(variants)
|> serve("image/png", data)
_ ->
send_resp(conn, 404, "")
end
end
end
defp maybe_not_modified(%{halted: true} = conn, _), do: conn
defp maybe_not_modified(conn, variants) do
etag = build_etag(variants)
case get_req_header(conn, "if-none-match") do
[^etag] ->
conn
|> put_resp_header("cache-control", "public, max-age=#{@one_day}")
|> put_resp_header("etag", etag)
|> send_resp(304, "")
|> halt()
_ ->
conn
|> put_resp_header("cache-control", "public, max-age=#{@one_day}")
|> put_resp_header("etag", etag)
end
end
defp serve(%{halted: true} = conn, _content_type, _data), do: conn
defp serve(conn, content_type, data) do
conn
|> put_resp_content_type(content_type)
|> send_resp(200, data)
end
defp build_etag(%{generated_at: %DateTime{} = dt}),
do: ~s("fav-#{DateTime.to_unix(dt)}")
defp build_etag(_), do: ~s("fav-0")
end