mirror of
https://github.com/algora-io/tv.git
synced 2025-02-14 01:59:50 +02:00
generate og image with svg overlay
This commit is contained in:
parent
edf1c32e59
commit
4006027385
@ -396,6 +396,100 @@ defmodule Algora.Library do
|
||||
end
|
||||
end
|
||||
|
||||
defp create_og(src_path, dst_path, _opts) do
|
||||
base_image = Image.open!(src_path)
|
||||
|
||||
{width, height, _} = Image.shape(base_image)
|
||||
|
||||
overlay_svg = """
|
||||
<svg viewbox="0 0 #{width} #{height}" width="#{width}" height="#{height}"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<filter x="0" y="0" width="1.06" height="1" id="solid">
|
||||
<feFlood flood-color="#ef4444" result="bg" />
|
||||
<feMerge>
|
||||
<feMergeNode in="bg" />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
|
||||
<filter id="rounded-corners" x="-8%" width="122%" y="-37%" height="150%">
|
||||
<feFlood flood-color="#ef4444" />
|
||||
<feGaussianBlur stdDeviation="42" />
|
||||
<feComponentTransfer>
|
||||
<feFuncA type="table" tableValues="0 0 0 1" />
|
||||
</feComponentTransfer>
|
||||
|
||||
<feComponentTransfer>
|
||||
<feFuncA type="table" tableValues="0 1 1 1 1 1 1 1" />
|
||||
</feComponentTransfer>
|
||||
<feComposite operator="over" in="SourceGraphic" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g filter="url(#rounded-corners)">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="180" viewBox="0 0 24 24"
|
||||
x="#{trunc(width / 2) - 180}" y="20"
|
||||
fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-tabler icons-tabler-outline icon-tabler-access-point">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 12l0 .01" />
|
||||
<path d="M14.828 9.172a4 4 0 0 1 0 5.656" />
|
||||
<path d="M17.657 6.343a8 8 0 0 1 0 11.314" />
|
||||
<path d="M9.168 14.828a4 4 0 0 1 0 -5.656" />
|
||||
<path d="M6.337 17.657a8 8 0 0 1 0 -11.314" />
|
||||
</svg>
|
||||
<text font-style="normal" font-weight="bold" xml:space="preserve" font-family="'Bangers'"
|
||||
font-size="122" x="#{trunc(width / 2) + 150}" y="150" dominant-baseline="middle"
|
||||
text-anchor="middle"
|
||||
stroke-width="0" stroke="#000" fill="#fff">LIVE</text>
|
||||
</g>
|
||||
</svg>
|
||||
"""
|
||||
|
||||
{overlay, _} = Vix.Vips.Operation.svgload_buffer!(overlay_svg)
|
||||
|
||||
og_image = Image.compose!(base_image, overlay)
|
||||
Image.write!(og_image, dst_path)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
defp create_og_image_from_file(%Video{} = video, src_path, opts) do
|
||||
dst_path = Path.join(System.tmp_dir!(), "#{video.uuid}-og.png")
|
||||
|
||||
with :ok <- create_og(src_path, dst_path, opts) do
|
||||
File.read(dst_path)
|
||||
end
|
||||
end
|
||||
|
||||
defp create_og_image(%Video{} = video, opts \\ []) do
|
||||
src_path = Path.join(System.tmp_dir!(), "#{video.uuid}.jpeg")
|
||||
create_og_image_from_file(video, src_path, opts)
|
||||
end
|
||||
|
||||
def store_og_image_from_file(%Video{} = video, src_path, opts \\ []) do
|
||||
with {:ok, og_image} <- create_og_image_from_file(video, src_path, opts),
|
||||
{:ok, _} <-
|
||||
Storage.upload(og_image, "#{video.uuid}/og.png", content_type: "image/png") do
|
||||
video
|
||||
|> change()
|
||||
|> put_change(:og_image_url, "#{video.url_root}/og.png")
|
||||
|> Repo.update()
|
||||
end
|
||||
end
|
||||
|
||||
def store_og_image(%Video{} = video) do
|
||||
with {:ok, og_image} <- create_og_image(video),
|
||||
{:ok, _} <-
|
||||
Storage.upload(og_image, "#{video.uuid}/og.png", content_type: "image/png") do
|
||||
video
|
||||
|> change()
|
||||
|> put_change(:og_image_url, "#{video.url_root}/og.png")
|
||||
|> Repo.update()
|
||||
end
|
||||
end
|
||||
|
||||
def get_thumbnail_url(%Video{} = video) do
|
||||
video.thumbnail_url || "#{AlgoraWeb.Endpoint.url()}/images/og/default.png"
|
||||
end
|
||||
|
@ -7,12 +7,13 @@ defmodule Algora.Storage do
|
||||
@pubsub Algora.PubSub
|
||||
|
||||
@enforce_keys [:video]
|
||||
defstruct @enforce_keys ++ [video_header: <<>>, video_segment: <<>>]
|
||||
defstruct @enforce_keys ++ [video_header: <<>>, video_segment: <<>>, setup_completed?: false]
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
video: Library.Video.t(),
|
||||
video_header: <<>>,
|
||||
video_segment: <<>>
|
||||
video_segment: <<>>,
|
||||
setup_completed?: boolean()
|
||||
}
|
||||
|
||||
@impl true
|
||||
@ -67,19 +68,19 @@ defmodule Algora.Storage do
|
||||
contents,
|
||||
_metadata,
|
||||
%{type: :segment, mode: :binary},
|
||||
%{video: %{thumbnail_url: nil} = video, video_header: video_header} = state
|
||||
%{setup_completed?: false, video: video, video_header: video_header} = state
|
||||
) do
|
||||
Task.Supervisor.start_child(Algora.TaskSupervisor, fn ->
|
||||
case Library.store_thumbnail(video, video_header <> contents) do
|
||||
{:ok, video} ->
|
||||
broadcast_thumbnails_generated!(video)
|
||||
|
||||
with {:ok, video} <- Library.store_thumbnail(video, video_header <> contents),
|
||||
{:ok, video} <- Library.store_og_image(video) do
|
||||
broadcast_thumbnails_generated!(video)
|
||||
else
|
||||
_ ->
|
||||
Membrane.Logger.error("Could not generate thumbnails for video #{video.id}")
|
||||
end
|
||||
end)
|
||||
|
||||
{:ok, %{state | video_segment: contents}}
|
||||
{:ok, %{state | setup_completed?: true, video_segment: contents}}
|
||||
end
|
||||
|
||||
defp process_contents(
|
||||
|
1
mix.exs
1
mix.exs
@ -51,6 +51,7 @@ defmodule Algora.MixProject do
|
||||
{:gettext, "~> 0.18"},
|
||||
{:heroicons, "~> 0.5.0"},
|
||||
{:hnswlib, "~> 0.1.0"},
|
||||
{:image, "~> 0.37"},
|
||||
{:jason, "~> 1.2"},
|
||||
{:libcluster, "~> 3.3.1"},
|
||||
{:membrane_core, "~> 1.0"},
|
||||
|
2
mix.lock
2
mix.lock
@ -49,6 +49,7 @@
|
||||
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
|
||||
"httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"},
|
||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
||||
"image": {:hex, :image, "0.45.0", "4cd463b89b4a0db011ab542dd1599d5822f224b96099ce8f5b749176c74f33a7", [:mix], [{:bumblebee, "~> 0.3", [hex: :bumblebee, repo: "hexpm", optional: true]}, {:evision, "~> 0.1.33", [hex: :evision, repo: "hexpm", optional: true]}, {:exla, "~> 0.5", [hex: :exla, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: true]}, {:kino, "~> 0.11", [hex: :kino, repo: "hexpm", optional: true]}, {:nx, "~> 0.5", [hex: :nx, repo: "hexpm", optional: true]}, {:nx_image, "~> 0.1", [hex: :nx_image, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.1 or ~> 3.2 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: true]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: true]}, {:rustler, "> 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: false]}, {:vix, "~> 0.23", [hex: :vix, repo: "hexpm", optional: false]}], "hexpm", "4d0aeed0236ed28d54f3835a6c99010425f72c3d44a03b8c631292788f3598d8"},
|
||||
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
|
||||
"libcluster": {:hex, :libcluster, "3.3.1", "e7a4875cd1290cee7a693d6bd46076863e9e433708b01339783de6eff5b7f0aa", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b575ca63c1cd84e01f3fa0fc45e6eb945c1ee7ae8d441d33def999075e9e5398"},
|
||||
"makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"},
|
||||
@ -132,6 +133,7 @@
|
||||
"unifex": {:hex, :unifex, "1.1.0", "26b1bcb6c3b3454e1ea15f85b2e570aaa5b5c609566aa9f5c2e0a8b213379d6b", [:mix], [{:bunch, "~> 1.0", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.0", [hex: :bundlex, repo: "hexpm", optional: false]}, {:shmex, "~> 0.5.0", [hex: :shmex, repo: "hexpm", optional: false]}], "hexpm", "d8f47e9e3240301f5b20eec5792d1d4341e1a3a268d94f7204703b48da4aaa06"},
|
||||
"unpickler": {:hex, :unpickler, "0.1.0", "c2262c0819e6985b761e7107546cef96a485f401816be5304a65fdd200d5bd6a", [:mix], [], "hexpm", "e2b3f61e62406187ac52afead8a63bfb4e49394028993f3c4c42712743cab79e"},
|
||||
"unzip": {:hex, :unzip, "0.10.0", "374e0059e48e982076f3fd22cd4817ab11016c1bae3f09421511901ddda95c5c", [:mix], [], "hexpm", "101c06b0fa97a858a83beb618f4bc20370624f73ab3954f756d9b52194056de6"},
|
||||
"vix": {:hex, :vix, "0.27.0", "c9d6be17abe6fd1b3daed52964331c67ff1f980ea188499d8ac5e723cf215576", [:make, :mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:cc_precompiler, "~> 0.1.4 or ~> 0.2", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7.3 or ~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: true]}], "hexpm", "ae4ba5bb9882753396baadfff93b6cab5d4275b13751fd49723591eb116f373a"},
|
||||
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
|
||||
"websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"},
|
||||
"xla": {:hex, :xla, "0.6.0", "67bb7695efa4a23b06211dc212de6a72af1ad5a9e17325e05e0a87e4c241feb8", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "dd074daf942312c6da87c7ed61b62fb1a075bced157f1cc4d47af2d7c9f44fb7"},
|
||||
|
Loading…
x
Reference in New Issue
Block a user