1
0
mirror of https://github.com/algora-io/tv.git synced 2025-02-14 01:59:50 +02:00

Choose thumbnail UI (#108)

This commit is contained in:
Giles Thompson 2024-10-07 06:48:09 +13:00 committed by GitHub
parent dace52a204
commit e363662880
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 92 additions and 15 deletions

View File

@ -435,6 +435,11 @@ defmodule Algora.Library do
Phoenix.PubSub.unsubscribe(@pubsub, topic(channel.user_id))
end
def get_thumbnails_for_video(%Video{} = video) do
Repo.all(from vt in VideoThumbnail,
where: vt.video_id == ^video.id, order_by: vt.minutes)
end
defp create_thumbnail_from_file(%Video{} = video, src_path, marker, opts \\ []) do
dst_path = Path.join(System.tmp_dir!(), "#{video.uuid}-#{marker.minutes}.jpeg")
@ -454,7 +459,7 @@ defmodule Algora.Library do
end
def store_thumbnail_from_file(%Video{} = video, src_path, marker \\ %{ minutes: 0 }, opts \\ []) do
with {:ok, thumbnail} <- create_thumbnail_from_file(video, src_path, opts),
with {:ok, thumbnail} <- create_thumbnail_from_file(video, src_path, marker, opts),
{:ok, _} <-
Storage.upload(thumbnail, "#{video.uuid}/#{thumbnail_filename(marker.minutes)}",
content_type: "image/jpeg"

View File

@ -60,6 +60,12 @@ defmodule Algora.Library.Video do
|> validate_required([:title])
end
def change_thumbnail(video, thumbnail_url \\ "") do
video
|> change()
|> put_change(:thumbnail_url, thumbnail_url)
end
def put_user(%Ecto.Changeset{} = changeset, %User{} = user) do
put_assoc(changeset, :user, user)
end

View File

@ -1,7 +1,6 @@
defmodule Algora.Library.VideoThumbnail do
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query
alias Algora.Library.Video

View File

@ -493,7 +493,7 @@ defmodule AlgoraWeb.CoreComponents do
id={@id}
phx-mounted={@show && show_modal(@id)}
phx-remove={hide_modal(@id)}
class="relative z-50 hidden"
class="relative z-[1001] hidden"
>
<div
id={"#{@id}-bg"}
@ -795,6 +795,30 @@ defmodule AlgoraWeb.CoreComponents do
"""
end
def input(%{type: "radio", value: value} = assigns) do
assigns =
assign_new(assigns, :checked, fn -> Phoenix.HTML.Form.normalize_value("radio", value) end)
~H"""
<div phx-feedback-for={@name}>
<label class="flex items-center gap-4 text-sm leading-6 text-gray-300">
<input
type="radio"
id={@id || @name}
name={@name}
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
checked={@checked}
class="rounded-full border-gray-600 text-gray-500 focus:ring-gray-50 sr-only peer"
{@rest}
/>
<%= @label %>
<%= render_slot(@inner_block) %>
</label>
<.error :for={msg <- @errors}><%= msg %></.error>
</div>
"""
end
def input(%{type: "select"} = assigns) do
~H"""
<div phx-feedback-for={@name}>

View File

@ -9,6 +9,7 @@ defmodule AlgoraWeb.VideoLive do
alias Algora.Events.Event
alias AlgoraWeb.{
CoreComponents,
LayoutComponent,
Presence,
RTMPDestinationIconComponent,
@ -22,6 +23,31 @@ defmodule AlgoraWeb.VideoLive do
~H"""
<div class="lg:mr-[24rem]">
<.pwa_install_prompt />
<.modal id="choose_thumbnail">
<:title>
Choose thumbnail
</:title>
<:subtitle>
New thumbnails are added periodically
</:subtitle>
<.simple_form for={assigns.thumbnail_form} phx-submit="save_thumbnail">
<div class="mt-4 grid-cols-2 grid gap-8">
<label :for={video_thumbnail <- assigns.video_thumbnails} class="flex items-center">
<.input
field={assigns.thumbnail_form[:thumbnail_url]}
type="radio"
value={video_thumbnail.thumbnail_url}
checked={assigns.thumbnail_form[:thumbnail_url].value == video_thumbnail.thumbnail_url}
>
<img src={video_thumbnail.thumbnail_url} class="border-2 rounded-lg opacity-50 peer-checked:opacity-100 peer-checked:border-white" />
</.input>
</label>
</div>
<:actions>
<.button phx-click={CoreComponents.hide_modal("choose_thumbnail")}>Save</.button>
</:actions>
</.simple_form>
</.modal>
<div class="px-4" id="video-player-container" phx-update="ignore">
<.live_component module={PlayerComponent} id="video-player" />
</div>
@ -49,18 +75,25 @@ defmodule AlgoraWeb.VideoLive do
]}>
<p><%= @video.title %></p>
</blockquote>
<.button :if={@current_user} phx-click="toggle_subscription">
<%= if @subscribed? do %>
Unsubscribe
<% else %>
Subscribe
<div class="flex items-center gap-2 whitespace-nowrap">
<%= if @current_user && (@video.user_id == @current_user.id || Accounts.admin?(@current_user)) && @has_many_thumbnails? do %>
<.button phx-click={CoreComponents.show_modal("choose_thumbnail")}>
Choose thumbnail
</.button>
<% end %>
</.button>
<.button :if={!@current_user && @authorize_url}>
<.link navigate={@authorize_url}>
Subscribe
</.link>
</.button>
<.button :if={@current_user} phx-click="toggle_subscription">
<%= if @subscribed? do %>
Unsubscribe
<% else %>
Subscribe
<% end %>
</.button>
<.button :if={!@current_user && @authorize_url}>
<.link navigate={@authorize_url}>
Subscribe
</.link>
</.button>
</div>
</div>
<div
:if={@channel.solving_challenge}
@ -594,6 +627,7 @@ defmodule AlgoraWeb.VideoLive do
|> Ecto.Changeset.cast(%{subtitles: encoded_subtitles}, Map.keys(types))
tabs = [:chat] |> append_if(length(subtitles) > 0, :transcript)
video_thumbnails = Library.get_thumbnails_for_video(video)
socket =
socket
@ -609,7 +643,10 @@ defmodule AlgoraWeb.VideoLive do
can_edit: false,
subscribed?: subscribed?(current_user, video),
transcript_form: to_form(transcript_changeset, as: :data),
chat_form: to_form(Chat.change_message(%Chat.Message{}))
chat_form: to_form(Chat.change_message(%Chat.Message{})),
video_thumbnails: video_thumbnails,
has_many_thumbnails?: length(video_thumbnails) > 1,
thumbnail_form: to_form(Library.Video.change_thumbnail(video, video.thumbnail_url))
)
|> stream(:videos, videos)
|> stream(:messages, Chat.list_messages(video))
@ -787,6 +824,12 @@ defmodule AlgoraWeb.VideoLive do
{:noreply, socket |> assign(subscribed?: !socket.assigns.subscribed?)}
end
def handle_event("save_thumbnail", params, socket) do
Library.Video.change_thumbnail(socket.assigns.video, params["video"]["thumbnail_url"])
|> Repo.update()
{:noreply, socket}
end
# TODO: move into events context
defp toggle_subscription_event(user, video) do
name = if subscribed?(user, video), do: :unsubscribed, else: :subscribed