1
0
mirror of https://github.com/algora-io/tv.git synced 2025-03-27 20:20:18 +02:00
algora-tv/lib/algora_web/live/settings_live.ex
2024-05-27 15:20:53 +03:00

227 lines
8.4 KiB
Elixir

defmodule AlgoraWeb.SettingsLive do
use AlgoraWeb, :live_view
alias Algora.Accounts
alias Algora.Accounts.Destination
alias AlgoraWeb.RTMPDestinationIconComponent
def render(assigns) do
~H"""
<div class="max-w-3xl mx-auto pt-2 pb-6 px-4 sm:px-6 space-y-6">
<div class="space-y-6 bg-white/5 rounded-lg p-6 ring-1 ring-white/15">
<.header>
Settings
<:subtitle>
Update your account details
</:subtitle>
</.header>
<.simple_form for={@form} phx-change="validate" phx-submit="save">
<.input field={@form[:handle]} label="Handle" />
<.input field={@form[:name]} label="Name" />
<.input label="Email" name="email" value={@current_user.email} disabled />
<.input field={@form[:channel_tagline]} label="Stream tagline" />
<div>
<.input
label="Stream URL"
name="stream_url"
value={"rtmp://#{URI.parse(AlgoraWeb.Endpoint.url()).host}:#{Algora.config([:rtmp_port])}/#{@current_user.stream_key}"}
disabled
/>
<p class="mt-2 text-sm text-gray-400">
<%= "Paste into OBS Studio > File > Settings > Stream > Server" %>
</p>
</div>
<:actions>
<.button>Save</.button>
</:actions>
</.simple_form>
</div>
<div class="space-y-6 bg-white/5 rounded-lg p-6 ring-1 ring-white/15">
<.header>
Integrations
<:subtitle>
Manage your connected accounts and services
</:subtitle>
</.header>
<div class="space-y-6">
<.button :if={!@connected_with_restream}>
<.link href={"/oauth/login/restream?#{URI.encode_query(return_to: "/channel/settings")}"}>
Connect with Restream
</.link>
</.button>
<.button :if={@connected_with_restream} class="bg-green-600 hover:bg-green-500 text-white">
<.link
href={"/oauth/login/restream?#{URI.encode_query(return_to: "/channel/settings")}"}
class="flex items-center"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="h-5 w-5 -ml-0.5"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M5 12l5 5l10 -10" />
</svg>
<span class="ml-1">Connected with Restream</span>
</.link>
</.button>
</div>
</div>
<div class="space-y-6 bg-white/5 rounded-lg p-6 ring-1 ring-white/15">
<.header>
Multistreaming
<:subtitle>
Stream to multiple destinations
</:subtitle>
</.header>
<div class="space-y-6">
<ul :if={length(@destinations) > 0} class="space-y-2">
<%= for destination <- @destinations do %>
<li class="w-full gap-4 py-2 px-3 border border-gray-600 bg-gray-950 rounded-md shadow-sm focus:outline-none focus:ring-gray-900 focus:border-gray-900 flex items-center justify-between">
<div class="flex items-center gap-2 truncate">
<RTMPDestinationIconComponent.render
class="w-6 h-6 shrink-0"
url={destination.rtmp_url}
/>
<span class="text-sm truncate"><%= destination.rtmp_url %></span>
</div>
<label class="inline-flex items-center cursor-pointer">
<span class="hidden sm:inline mr-3 text-sm font-medium text-gray-900 dark:text-gray-300">
<%= if destination.active do %>
Active
<% else %>
Inactive
<% end %>
</span>
<input
type="checkbox"
value=""
class="sr-only peer"
checked={destination.active}
phx-value-id={destination.id}
phx-click="toggle_destination"
/>
<div class="relative w-11 h-6 bg-gray-200 rounded-full peer dark:bg-gray-700 peer-focus:ring-4 peer-focus:ring-purple-300 dark:peer-focus:ring-purple-800 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-purple-600">
</div>
</label>
</li>
<% end %>
</ul>
<.button phx-click="show_add_destination_modal">Add Destination</.button>
</div>
</div>
</div>
<!-- Add Destination Modal -->
<.modal :if={@show_add_destination_modal} id="add-destination-modal" show>
<.header>
Add Destination
</.header>
<.simple_form for={@destination_form} phx-submit="add_destination">
<.input field={@destination_form[:rtmp_url]} label="RTMP URL" />
<.input
field={@destination_form[:stream_key]}
label="Stream key"
autocomplete="off"
type="password"
/>
<:actions>
<.button>Add Destination</.button>
</:actions>
</.simple_form>
</.modal>
"""
end
def mount(_params, _session, socket) do
%{current_user: current_user} = socket.assigns
{:ok, current_user} =
if current_user.stream_key do
{:ok, current_user}
else
Accounts.gen_stream_key(current_user)
end
changeset = Accounts.change_settings(current_user, %{})
destinations = Accounts.list_destinations(current_user.id)
destination_changeset = Accounts.change_destination(%Destination{})
connected_with_restream = Accounts.has_restream_token?(current_user)
{:ok,
socket
|> assign(current_user: current_user)
|> assign_form(changeset)
|> assign(destinations: destinations)
|> assign(destination_form: to_form(destination_changeset))
|> assign(show_add_destination_modal: false)
|> assign(connected_with_restream: connected_with_restream)}
end
def handle_event("validate", %{"user" => params}, socket) do
changeset =
socket.assigns.current_user
|> Accounts.change_settings(params)
|> Map.put(:action, :validate)
{:noreply, assign_form(socket, changeset)}
end
def handle_event("save", %{"user" => params}, socket) do
case Accounts.update_settings(socket.assigns.current_user, params) do
{:ok, user} ->
{:noreply,
socket
|> assign(current_user: user)
|> put_flash(:info, "Settings updated!")}
{:error, changeset} ->
{:noreply, assign_form(socket, changeset)}
end
end
def handle_event("toggle_destination", %{"id" => id}, socket) do
destination = Accounts.get_destination!(id)
Accounts.update_destination(destination, %{active: !destination.active})
{:noreply,
assign(socket, :destinations, Accounts.list_destinations(socket.assigns.current_user.id))}
end
def handle_event("show_add_destination_modal", _params, socket) do
{:noreply, assign(socket, show_add_destination_modal: true)}
end
def handle_event("add_destination", %{"destination" => destination_params}, socket) do
case Accounts.create_destination(socket.assigns.current_user, destination_params) do
{:ok, _destination} ->
{:noreply,
socket
|> assign(:show_add_destination_modal, false)
|> assign(:destinations, Accounts.list_destinations(socket.assigns.current_user.id))
|> put_flash(:info, "Destination added successfully!")}
{:error, changeset} ->
{:noreply, assign(socket, destination_form: to_form(changeset))}
end
end
def handle_params(params, _url, socket) do
{:noreply, socket |> apply_action(socket.assigns.live_action, params)}
end
defp apply_action(socket, :edit, _params) do
socket |> assign(:page_title, "Settings")
end
defp assign_form(socket, %Ecto.Changeset{} = changeset) do
assign(socket, :form, to_form(changeset))
end
end