2021-11-22 14:57:24 +00:00
|
|
|
|
defmodule LiveBeatsWeb.ProfileLive do
|
2021-10-29 16:12:23 +00:00
|
|
|
|
use LiveBeatsWeb, :live_view
|
|
|
|
|
|
2021-11-12 03:42:10 +00:00
|
|
|
|
alias LiveBeats.{Accounts, MediaLibrary, MP3Stat}
|
2024-04-09 00:53:14 +00:00
|
|
|
|
alias LiveBeatsWeb.Presence
|
2023-01-26 19:05:24 +00:00
|
|
|
|
alias LiveBeatsWeb.ProfileLive.{UploadFormComponent}
|
2021-10-29 16:12:23 +00:00
|
|
|
|
|
2022-01-31 19:27:06 +00:00
|
|
|
|
@max_presences 20
|
|
|
|
|
|
2021-10-29 16:12:23 +00:00
|
|
|
|
def render(assigns) do
|
|
|
|
|
~H"""
|
2024-04-09 00:53:14 +00:00
|
|
|
|
<.modal
|
|
|
|
|
id="upload"
|
|
|
|
|
patch={profile_path(@current_user)}
|
2024-06-05 14:17:37 +00:00
|
|
|
|
on_cancel={JS.push("cancel", target: "#song-form")}
|
2024-04-09 00:53:14 +00:00
|
|
|
|
phx-mounted={@live_action == :new && show_modal("upload")}
|
|
|
|
|
>
|
|
|
|
|
<:title>Add Music</:title>
|
|
|
|
|
<.live_component
|
|
|
|
|
id="upload-form"
|
|
|
|
|
module={UploadFormComponent}
|
|
|
|
|
current_user={@current_user}
|
|
|
|
|
on_complete={hide_modal("upload")}
|
|
|
|
|
/>
|
|
|
|
|
<:confirm type="submit" form="song-form">Save</:confirm>
|
|
|
|
|
<:cancel>Cancel</:cancel>
|
|
|
|
|
</.modal>
|
2021-10-29 16:12:23 +00:00
|
|
|
|
<.title_bar>
|
2021-11-16 16:58:22 +00:00
|
|
|
|
<div>
|
|
|
|
|
<div class="block">
|
2022-08-03 13:40:11 +00:00
|
|
|
|
<%= @profile.tagline %>
|
|
|
|
|
<%= if @owns_profile? do %>
|
|
|
|
|
(you)
|
|
|
|
|
<% end %>
|
2024-04-09 00:53:14 +00:00
|
|
|
|
<span>
|
|
|
|
|
– <%= ngettext("%{count} song", "%{count} songs", @songs_count) %>
|
|
|
|
|
</span>
|
2021-11-16 16:58:22 +00:00
|
|
|
|
</div>
|
2022-02-03 16:15:47 +00:00
|
|
|
|
<.link href={@profile.external_homepage_url} target="_blank" class="text-sm text-gray-600">
|
2022-08-03 13:40:11 +00:00
|
|
|
|
<.icon name={:code} /> <span class=""><%= url_text(@profile.external_homepage_url) %></span>
|
2021-11-16 16:58:22 +00:00
|
|
|
|
</.link>
|
|
|
|
|
</div>
|
2021-10-29 16:12:23 +00:00
|
|
|
|
<:actions>
|
2021-11-12 03:42:10 +00:00
|
|
|
|
<%= if @active_profile_id == @profile.user_id do %>
|
2022-08-03 13:40:11 +00:00
|
|
|
|
<.button
|
2024-06-04 21:27:51 +00:00
|
|
|
|
:if={@songs_count > 0}
|
2022-08-03 13:40:11 +00:00
|
|
|
|
primary
|
|
|
|
|
phx-click={
|
|
|
|
|
JS.push("switch_profile", value: %{user_id: nil}, target: "#player", loading: "#player")
|
|
|
|
|
}
|
2021-11-12 03:42:10 +00:00
|
|
|
|
>
|
2022-08-03 13:40:11 +00:00
|
|
|
|
<.icon name={:stop} /><span class="ml-2">Stop Listening</span>
|
2021-11-12 03:42:10 +00:00
|
|
|
|
</.button>
|
|
|
|
|
<% else %>
|
2022-08-03 13:40:11 +00:00
|
|
|
|
<.button
|
2024-06-04 21:27:51 +00:00
|
|
|
|
:if={@songs_count > 0}
|
2022-08-03 13:40:11 +00:00
|
|
|
|
primary
|
|
|
|
|
phx-click={
|
|
|
|
|
JS.push("switch_profile",
|
2024-04-09 00:53:14 +00:00
|
|
|
|
value: %{user_id: to_string(@profile.user_id)},
|
2022-08-03 13:40:11 +00:00
|
|
|
|
target: "#player",
|
|
|
|
|
loading: "#player"
|
|
|
|
|
)
|
|
|
|
|
}
|
2021-11-12 03:42:10 +00:00
|
|
|
|
>
|
2022-08-03 13:40:11 +00:00
|
|
|
|
<.icon name={:play} /><span class="ml-2">Listen</span>
|
2021-11-12 03:42:10 +00:00
|
|
|
|
</.button>
|
|
|
|
|
<% end %>
|
2024-04-09 00:53:14 +00:00
|
|
|
|
<.button
|
|
|
|
|
:if={@owns_profile?}
|
|
|
|
|
id="upload-btn"
|
|
|
|
|
primary
|
|
|
|
|
phx-click={show_modal("upload") |> JS.patch(profile_upload_path(@current_user))}
|
|
|
|
|
>
|
|
|
|
|
<.icon name={:upload} /><span class="ml-2">Upload Songs</span>
|
|
|
|
|
</.button>
|
2021-10-29 16:12:23 +00:00
|
|
|
|
</:actions>
|
|
|
|
|
</.title_bar>
|
|
|
|
|
|
2022-01-31 19:27:06 +00:00
|
|
|
|
<Presence.listening_now
|
2022-01-31 13:21:27 +00:00
|
|
|
|
presences={@presences}
|
2022-01-31 19:27:06 +00:00
|
|
|
|
presence_ids={@presence_ids}
|
|
|
|
|
total_count={@presences_count}
|
|
|
|
|
/>
|
2021-11-16 16:58:22 +00:00
|
|
|
|
|
2023-05-22 17:57:29 +00:00
|
|
|
|
<div id={"trascript-#{@active_song_id}"} phx-update="stream" class="mt-10 px-6">
|
|
|
|
|
<div :for={{id, segment} <- @streams.transcript_segments} id={id}>
|
|
|
|
|
<span class="text-gray-400">[<%= LiveBeats.MP3Stat.to_mmss(segment.ss) %>]</span>
|
|
|
|
|
<%= segment.text %>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2024-04-09 00:53:14 +00:00
|
|
|
|
<div :if={@owns_profile?} id="dialogs" phx-update="stream">
|
|
|
|
|
<.modal
|
|
|
|
|
:for={{_id, song} <- @streams.songs}
|
|
|
|
|
:if={song.id}
|
|
|
|
|
id={"delete-modal-#{song.id}"}
|
|
|
|
|
on_confirm={
|
|
|
|
|
JS.push("delete", value: %{id: to_string(song.id)})
|
|
|
|
|
|> hide_modal("delete-modal-#{song.id}")
|
|
|
|
|
|> focus_closest("#song-#{song.id}")
|
|
|
|
|
|> hide("#songs-#{song.id}")
|
|
|
|
|
}
|
|
|
|
|
on_cancel={focus("#delete-modal-#{song.id}", "#delete-song-#{song.id}")}
|
|
|
|
|
>
|
|
|
|
|
Are you sure you want to delete "<%= song.title %>"?
|
|
|
|
|
<:cancel>Cancel</:cancel>
|
|
|
|
|
<:confirm>Delete</:confirm>
|
|
|
|
|
</.modal>
|
2021-12-16 02:51:09 +00:00
|
|
|
|
</div>
|
2021-10-29 16:12:23 +00:00
|
|
|
|
|
2024-06-05 20:20:39 +00:00
|
|
|
|
<div :if={@songs_count == 0} class="my-2 text-center">
|
|
|
|
|
<.icon name={:music_note} class="mx-auto h-12 w-12 text-gray-400" />
|
|
|
|
|
<h3 class="mt-2 text-sm font-semibold text-gray-900">No music</h3>
|
|
|
|
|
<p class="mt-1 text-sm text-gray-500">Get started by uploading a new playlist</p>
|
|
|
|
|
<div class="mt-6">
|
|
|
|
|
<.button
|
|
|
|
|
primary
|
|
|
|
|
phx-click={show_modal("upload") |> JS.patch(profile_upload_path(@current_user))}
|
|
|
|
|
>
|
|
|
|
|
<.icon name={:upload} />
|
|
|
|
|
<span class="ml-2">Upload songs</span>
|
|
|
|
|
</.button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div :if={@songs_count > 0}>
|
2024-04-09 00:53:14 +00:00
|
|
|
|
<.table
|
|
|
|
|
id="songs"
|
|
|
|
|
rows={@streams.songs}
|
|
|
|
|
row_id={fn {id, _song} -> id end}
|
|
|
|
|
row_click={
|
2024-06-04 21:27:51 +00:00
|
|
|
|
@owns_profile? &&
|
|
|
|
|
fn {id, song} ->
|
|
|
|
|
JS.push("play_or_pause",
|
|
|
|
|
loading: "#songs tbody, ##{id}",
|
|
|
|
|
value: %{id: to_string(song.id)}
|
|
|
|
|
)
|
|
|
|
|
end
|
2024-04-09 00:53:14 +00:00
|
|
|
|
}
|
|
|
|
|
streamable
|
2024-06-04 21:27:51 +00:00
|
|
|
|
sortable_drop={@owns_profile? && "row_dropped"}
|
2023-01-28 19:18:34 +00:00
|
|
|
|
>
|
2024-04-09 00:53:14 +00:00
|
|
|
|
<:col
|
|
|
|
|
:let={{_id, song}}
|
|
|
|
|
label="Title"
|
2024-06-04 21:27:51 +00:00
|
|
|
|
class!={[
|
|
|
|
|
"px-6 py-3 text-sm font-medium text-gray-900 min-w-[200px] md:min-w-[20rem]",
|
|
|
|
|
@owns_profile? && "cursor-pointer"
|
|
|
|
|
]}
|
2022-02-04 16:41:05 +00:00
|
|
|
|
>
|
2024-04-09 00:53:14 +00:00
|
|
|
|
<span :if={song.status == :playing} class="flex pt-1 relative mr-2 w-4">
|
|
|
|
|
<span class="w-3 h-3 animate-ping bg-purple-400 rounded-full absolute"></span>
|
|
|
|
|
<.icon name={:volume_up} class="h-5 w-5 -mt-1 -ml-1" aria-label="Playing" role="button" />
|
|
|
|
|
</span>
|
|
|
|
|
<span :if={song.status == :paused} class="flex pt-1 relative mr-2 w-4">
|
|
|
|
|
<.icon
|
|
|
|
|
name={:volume_up}
|
|
|
|
|
class="h-5 w-5 -mt-1 -ml-1 text-gray-400"
|
|
|
|
|
aria-label="Paused"
|
|
|
|
|
role="button"
|
|
|
|
|
/>
|
|
|
|
|
</span>
|
|
|
|
|
<span :if={song.status == :stopped} class="flex relative w-6 -translate-x-1">
|
|
|
|
|
<.icon
|
|
|
|
|
:if={@owns_profile?}
|
|
|
|
|
name={:play}
|
|
|
|
|
class="h-5 w-5 text-gray-400"
|
|
|
|
|
aria-label="Play"
|
|
|
|
|
role="button"
|
|
|
|
|
/>
|
|
|
|
|
</span>
|
|
|
|
|
<%= song.title %>
|
|
|
|
|
</:col>
|
|
|
|
|
<:col :let={{_id, song}} label="Artist"><%= song.artist %></:col>
|
|
|
|
|
<:col
|
|
|
|
|
:let={{_id, song}}
|
|
|
|
|
label="Attribution"
|
|
|
|
|
class="max-w-5xl break-words text-gray-600 font-light"
|
|
|
|
|
>
|
|
|
|
|
<%= song.attribution %>
|
|
|
|
|
</:col>
|
|
|
|
|
<:col :let={{_id, song}} label="Duration">
|
|
|
|
|
<%= MP3Stat.to_mmss(song.duration) %>
|
|
|
|
|
</:col>
|
|
|
|
|
<:col :let={{_id, song}} :if={@owns_profile?} label="">
|
|
|
|
|
<.link
|
|
|
|
|
id={"delete-song-#{song.id}"}
|
|
|
|
|
phx-click={show_modal("delete-modal-#{song.id}")}
|
|
|
|
|
class="inline-flex items-center px-3 py-2 text-sm leading-4 font-medium"
|
|
|
|
|
>
|
|
|
|
|
<.icon name={:trash} class="-ml-0.5 mr-2 h-4 w-4" /> Delete
|
|
|
|
|
</.link>
|
|
|
|
|
</:col>
|
|
|
|
|
</.table>
|
|
|
|
|
</div>
|
2021-10-29 16:12:23 +00:00
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
2021-11-12 03:42:10 +00:00
|
|
|
|
def mount(%{"profile_username" => profile_username}, _session, socket) do
|
2021-11-05 19:57:33 +00:00
|
|
|
|
%{current_user: current_user} = socket.assigns
|
|
|
|
|
|
2024-04-09 00:53:14 +00:00
|
|
|
|
profile_user =
|
|
|
|
|
if current_user.username == profile_username do
|
|
|
|
|
current_user
|
|
|
|
|
else
|
|
|
|
|
Accounts.get_user_by!(username: profile_username)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
profile = MediaLibrary.get_profile!(profile_user)
|
2021-11-12 03:42:10 +00:00
|
|
|
|
|
2021-11-05 00:49:19 +00:00
|
|
|
|
if connected?(socket) do
|
2021-11-12 11:21:12 +00:00
|
|
|
|
MediaLibrary.subscribe_to_profile(profile)
|
2021-11-12 03:42:10 +00:00
|
|
|
|
Accounts.subscribe(current_user.id)
|
2022-04-06 16:20:23 +00:00
|
|
|
|
Presence.subscribe(profile)
|
2021-11-05 00:49:19 +00:00
|
|
|
|
end
|
2021-11-05 12:57:48 +00:00
|
|
|
|
|
2021-11-12 03:42:10 +00:00
|
|
|
|
socket =
|
|
|
|
|
socket
|
|
|
|
|
|> assign(
|
2024-04-09 00:53:14 +00:00
|
|
|
|
active_song_id: nil,
|
2021-11-12 03:42:10 +00:00
|
|
|
|
active_profile_id: current_user.active_profile_user_id,
|
|
|
|
|
profile: profile,
|
2024-04-09 00:53:14 +00:00
|
|
|
|
owns_profile?: MediaLibrary.owns_profile?(current_user, profile)
|
2021-11-12 03:42:10 +00:00
|
|
|
|
)
|
2024-04-09 00:53:14 +00:00
|
|
|
|
|> stream_configure(:transcript_segments, dom_id: &"ss-#{&1.ss}")
|
|
|
|
|
|> stream(:transcript_segments, [])
|
|
|
|
|
|> stream_songs()
|
2021-11-16 16:58:22 +00:00
|
|
|
|
|> assign_presences()
|
2021-11-12 03:42:10 +00:00
|
|
|
|
|
2023-01-26 19:05:24 +00:00
|
|
|
|
{:ok, socket, temporary_assigns: [presences: %{}]}
|
2021-10-29 16:12:23 +00:00
|
|
|
|
end
|
|
|
|
|
|
2024-04-09 00:53:14 +00:00
|
|
|
|
def stream_songs(socket) do
|
|
|
|
|
%{profile: profile} = socket.assigns
|
|
|
|
|
songs = MediaLibrary.list_profile_songs(profile, 50)
|
|
|
|
|
active_song = Enum.find(songs, fn song -> song.status in [:playing, :paused] end)
|
|
|
|
|
segments = if active_song, do: active_song.transcript.segments, else: []
|
|
|
|
|
|
|
|
|
|
socket
|
|
|
|
|
|> assign(
|
|
|
|
|
songs: songs,
|
|
|
|
|
active_song: active_song,
|
|
|
|
|
active_song_id: active_song && active_song.id,
|
|
|
|
|
segments: segments,
|
|
|
|
|
songs_count: Enum.count(songs)
|
|
|
|
|
)
|
|
|
|
|
|> stream(:songs, songs, reset: true)
|
|
|
|
|
end
|
|
|
|
|
|
2021-10-29 16:12:23 +00:00
|
|
|
|
def handle_params(params, _url, socket) do
|
2021-11-18 16:50:15 +00:00
|
|
|
|
{:noreply, socket |> apply_action(socket.assigns.live_action, params)}
|
2021-11-05 00:49:19 +00:00
|
|
|
|
end
|
|
|
|
|
|
2021-11-05 19:57:33 +00:00
|
|
|
|
def handle_event("play_or_pause", %{"id" => id}, socket) do
|
2024-04-09 00:53:14 +00:00
|
|
|
|
%{active_song_id: active_song_id} = socket.assigns
|
2021-11-05 19:57:33 +00:00
|
|
|
|
song = MediaLibrary.get_song!(id)
|
2021-11-12 03:42:10 +00:00
|
|
|
|
can_playback? = MediaLibrary.can_control_playback?(socket.assigns.current_user, song)
|
|
|
|
|
|
|
|
|
|
cond do
|
2024-04-09 00:53:14 +00:00
|
|
|
|
can_playback? and active_song_id == song.id and MediaLibrary.playing?(song) ->
|
2021-11-12 03:42:10 +00:00
|
|
|
|
MediaLibrary.pause_song(song)
|
|
|
|
|
|
2024-04-09 00:53:14 +00:00
|
|
|
|
receive do
|
|
|
|
|
{MediaLibrary, %MediaLibrary.Events.Pause{song: song}} ->
|
|
|
|
|
{:noreply, pause_song(socket, song)}
|
|
|
|
|
end
|
|
|
|
|
|
2021-11-12 03:42:10 +00:00
|
|
|
|
can_playback? ->
|
|
|
|
|
MediaLibrary.play_song(id)
|
|
|
|
|
|
2024-04-09 00:53:14 +00:00
|
|
|
|
receive do
|
|
|
|
|
{MediaLibrary, %MediaLibrary.Events.Play{song: song}} ->
|
|
|
|
|
{:noreply, play_song(socket, song)}
|
|
|
|
|
end
|
|
|
|
|
|
2021-11-12 03:42:10 +00:00
|
|
|
|
true ->
|
2024-04-09 00:53:14 +00:00
|
|
|
|
{:noreply, socket}
|
2021-11-05 19:57:33 +00:00
|
|
|
|
end
|
2021-11-05 00:49:19 +00:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def handle_event("delete", %{"id" => id}, socket) do
|
|
|
|
|
song = MediaLibrary.get_song!(id)
|
2021-11-12 11:42:07 +00:00
|
|
|
|
|
2021-11-12 03:42:10 +00:00
|
|
|
|
if song.user_id == socket.assigns.current_user.id do
|
2021-12-14 20:29:07 +00:00
|
|
|
|
:ok = MediaLibrary.delete_song(song)
|
2021-11-12 03:42:10 +00:00
|
|
|
|
end
|
2021-11-12 11:42:07 +00:00
|
|
|
|
|
2023-03-09 14:29:22 +00:00
|
|
|
|
if song.id == socket.assigns.active_song_id do
|
|
|
|
|
{:noreply, assign(socket, :active_song_id, nil)}
|
|
|
|
|
else
|
|
|
|
|
{:noreply, socket}
|
|
|
|
|
end
|
2021-11-05 00:49:19 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-01-26 19:05:24 +00:00
|
|
|
|
def handle_event("row_dropped", %{"id" => dom_id, "old" => old_idx, "new" => new_idx}, socket) do
|
|
|
|
|
"songs-" <> id = dom_id
|
|
|
|
|
song = MediaLibrary.get_song!(id)
|
2023-01-27 19:58:29 +00:00
|
|
|
|
|
2023-01-26 19:05:24 +00:00
|
|
|
|
if song.user_id == socket.assigns.current_user.id and song.position == old_idx do
|
|
|
|
|
:ok = MediaLibrary.update_song_position(song, new_idx)
|
|
|
|
|
{:noreply, socket}
|
|
|
|
|
else
|
|
|
|
|
{:noreply, socket}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2022-04-06 16:20:23 +00:00
|
|
|
|
def handle_info({LiveBeatsWeb.Presence, %{user_joined: presence}}, socket) do
|
2022-01-31 19:27:06 +00:00
|
|
|
|
{:noreply, assign_presence(socket, presence)}
|
2021-12-09 07:29:00 +00:00
|
|
|
|
end
|
|
|
|
|
|
2022-04-06 16:20:23 +00:00
|
|
|
|
def handle_info({LiveBeatsWeb.Presence, %{user_left: presence}}, socket) do
|
2022-01-11 19:57:06 +00:00
|
|
|
|
%{user: user} = presence
|
2022-01-31 13:21:27 +00:00
|
|
|
|
|
2022-01-12 19:15:06 +00:00
|
|
|
|
if presence.metas == [] do
|
2022-01-31 19:27:06 +00:00
|
|
|
|
{:noreply, remove_presence(socket, user)}
|
2022-01-12 19:15:06 +00:00
|
|
|
|
else
|
|
|
|
|
{:noreply, socket}
|
|
|
|
|
end
|
2021-12-09 07:29:00 +00:00
|
|
|
|
end
|
|
|
|
|
|
2021-11-12 17:41:16 +00:00
|
|
|
|
def handle_info({Accounts, %Accounts.Events.ActiveProfileChanged{} = event}, socket) do
|
|
|
|
|
{:noreply, assign(socket, active_profile_id: event.new_profile_user_id)}
|
2021-11-12 03:42:10 +00:00
|
|
|
|
end
|
|
|
|
|
|
2021-11-12 17:41:16 +00:00
|
|
|
|
def handle_info({MediaLibrary, %MediaLibrary.Events.PublicProfileUpdated{} = update}, socket) do
|
|
|
|
|
{:noreply,
|
|
|
|
|
socket
|
|
|
|
|
|> assign(profile: update.profile)
|
|
|
|
|
|> push_patch(to: profile_path(update.profile))}
|
|
|
|
|
end
|
|
|
|
|
|
2023-01-26 19:05:24 +00:00
|
|
|
|
def handle_info({MediaLibrary, %MediaLibrary.Events.NewPosition{song: song}}, socket) do
|
2024-04-09 00:53:14 +00:00
|
|
|
|
{:noreply,
|
|
|
|
|
socket
|
|
|
|
|
|> stream_delete(:songs, song)
|
|
|
|
|
|> stream_insert(:songs, song, at: song.position)}
|
2023-01-26 19:05:24 +00:00
|
|
|
|
end
|
|
|
|
|
|
2021-11-12 17:41:16 +00:00
|
|
|
|
def handle_info({MediaLibrary, %MediaLibrary.Events.Play{song: song}}, socket) do
|
2021-11-05 00:49:19 +00:00
|
|
|
|
{:noreply, play_song(socket, song)}
|
|
|
|
|
end
|
|
|
|
|
|
2021-11-12 17:41:16 +00:00
|
|
|
|
def handle_info({MediaLibrary, %MediaLibrary.Events.Pause{song: song}}, socket) do
|
2023-01-26 19:05:24 +00:00
|
|
|
|
{:noreply, pause_song(socket, song)}
|
2021-11-05 00:49:19 +00:00
|
|
|
|
end
|
|
|
|
|
|
2024-04-09 00:53:14 +00:00
|
|
|
|
def handle_info(
|
|
|
|
|
{MediaLibrary, {%MediaLibrary.Song.Transcript.Segment{} = seg, song_id}},
|
|
|
|
|
socket
|
|
|
|
|
) do
|
2023-05-22 17:57:29 +00:00
|
|
|
|
if socket.assigns.active_song_id == song_id do
|
|
|
|
|
{:noreply, stream_insert(socket, :transcript_segments, seg)}
|
|
|
|
|
else
|
|
|
|
|
{:noreply, socket}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2021-12-16 02:51:09 +00:00
|
|
|
|
def handle_info({MediaLibrary, %MediaLibrary.Events.SongsImported{songs: songs}}, socket) do
|
2023-03-09 14:29:22 +00:00
|
|
|
|
%{current_user: current_user, active_song_id: active_song_id} = socket.assigns
|
|
|
|
|
first = hd(songs)
|
|
|
|
|
|
|
|
|
|
if !active_song_id && MediaLibrary.can_control_playback?(current_user, first) do
|
2023-05-22 17:57:29 +00:00
|
|
|
|
MediaLibrary.play_song(first)
|
2023-03-09 14:29:22 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-01-28 19:18:34 +00:00
|
|
|
|
{:noreply,
|
|
|
|
|
Enum.reduce(songs, socket, fn song, acc ->
|
|
|
|
|
acc
|
|
|
|
|
|> update(:songs_count, &(&1 + 1))
|
|
|
|
|
|> stream_insert(:songs, song)
|
|
|
|
|
end)}
|
2023-01-27 00:39:59 +00:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def handle_info({MediaLibrary, %MediaLibrary.Events.SongDeleted{song: song}}, socket) do
|
2023-01-28 19:18:34 +00:00
|
|
|
|
{:noreply,
|
|
|
|
|
socket
|
|
|
|
|
|> update(:songs_count, &(&1 - 1))
|
|
|
|
|
|> stream_delete(:songs, song)}
|
2021-12-16 02:51:09 +00:00
|
|
|
|
end
|
|
|
|
|
|
2022-01-31 13:21:27 +00:00
|
|
|
|
def handle_info({MediaLibrary, {:ping, ping}}, socket) do
|
|
|
|
|
%{user: user, rtt: rtt, region: region} = ping
|
2022-01-31 19:27:06 +00:00
|
|
|
|
|
|
|
|
|
send_update(Presence.BadgeComponent,
|
|
|
|
|
id: user.id,
|
2022-01-31 13:21:27 +00:00
|
|
|
|
action: {:ping, %{user: user, ping: rtt, region: region}}
|
|
|
|
|
)
|
|
|
|
|
|
2022-01-29 01:40:48 +00:00
|
|
|
|
{:noreply, socket}
|
|
|
|
|
end
|
|
|
|
|
|
2021-11-12 17:41:16 +00:00
|
|
|
|
def handle_info({MediaLibrary, _}, socket), do: {:noreply, socket}
|
|
|
|
|
|
|
|
|
|
def handle_info({Accounts, _}, socket), do: {:noreply, socket}
|
|
|
|
|
|
2021-11-05 19:57:33 +00:00
|
|
|
|
defp stop_song(socket, song_id) do
|
2023-01-26 19:05:24 +00:00
|
|
|
|
song = MediaLibrary.get_song!(song_id)
|
2021-11-05 19:57:33 +00:00
|
|
|
|
|
2023-01-26 19:05:24 +00:00
|
|
|
|
socket =
|
|
|
|
|
if socket.assigns.active_song_id == song_id do
|
|
|
|
|
assign(socket, :active_song_id, nil)
|
|
|
|
|
else
|
|
|
|
|
socket
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
stream_insert(socket, :songs, %MediaLibrary.Song{song | status: :stopped})
|
2021-11-05 19:57:33 +00:00
|
|
|
|
end
|
|
|
|
|
|
2023-01-26 19:05:24 +00:00
|
|
|
|
defp pause_song(socket, %MediaLibrary.Song{} = song) do
|
|
|
|
|
stream_insert(socket, :songs, %MediaLibrary.Song{song | status: :paused})
|
2021-11-05 00:49:19 +00:00
|
|
|
|
end
|
|
|
|
|
|
2021-11-05 19:57:33 +00:00
|
|
|
|
defp play_song(socket, %MediaLibrary.Song{} = song) do
|
2021-11-12 03:42:10 +00:00
|
|
|
|
%{active_song_id: active_song_id} = socket.assigns
|
2023-03-13 15:04:27 +00:00
|
|
|
|
song = %MediaLibrary.Song{song | status: :playing}
|
2021-11-05 00:49:19 +00:00
|
|
|
|
|
2021-11-05 19:57:33 +00:00
|
|
|
|
cond do
|
2021-11-12 03:42:10 +00:00
|
|
|
|
active_song_id == song.id ->
|
2023-03-13 15:04:27 +00:00
|
|
|
|
stream_insert(socket, :songs, song)
|
2021-11-05 19:57:33 +00:00
|
|
|
|
|
2021-11-12 03:42:10 +00:00
|
|
|
|
active_song_id ->
|
2023-03-14 14:18:57 +00:00
|
|
|
|
socket
|
2021-11-12 03:42:10 +00:00
|
|
|
|
|> stop_song(active_song_id)
|
2023-03-13 15:04:27 +00:00
|
|
|
|
|> stream_insert(:songs, song)
|
2021-11-12 03:42:10 +00:00
|
|
|
|
|> assign(active_song_id: song.id)
|
2021-11-05 19:57:33 +00:00
|
|
|
|
|
|
|
|
|
true ->
|
2023-01-26 19:05:24 +00:00
|
|
|
|
socket
|
2023-03-13 15:04:27 +00:00
|
|
|
|
|> stream_insert(:songs, song)
|
2023-01-26 19:05:24 +00:00
|
|
|
|
|> assign(active_song_id: song.id)
|
2021-11-05 00:49:19 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2024-04-09 00:53:14 +00:00
|
|
|
|
defp apply_action(socket, :show, _params) do
|
|
|
|
|
socket
|
|
|
|
|
|> assign(:page_title, "Listing Songs")
|
|
|
|
|
|> assign(:song, nil)
|
|
|
|
|
end
|
|
|
|
|
|
2021-11-18 16:50:15 +00:00
|
|
|
|
defp apply_action(socket, :new, _params) do
|
|
|
|
|
if socket.assigns.owns_profile? do
|
2024-04-09 00:53:14 +00:00
|
|
|
|
assign(socket, :page_title, "Add Music")
|
2021-11-05 00:49:19 +00:00
|
|
|
|
else
|
2021-11-18 16:50:15 +00:00
|
|
|
|
socket
|
|
|
|
|
|> put_flash(:error, "You can't do that")
|
|
|
|
|
|> redirect(to: profile_path(socket.assigns.current_user))
|
2021-11-05 00:49:19 +00:00
|
|
|
|
end
|
2021-10-29 16:12:23 +00:00
|
|
|
|
end
|
|
|
|
|
|
2021-11-16 16:58:22 +00:00
|
|
|
|
defp assign_presences(socket) do
|
2024-06-04 21:27:51 +00:00
|
|
|
|
%{profile: profile} = socket.assigns
|
2022-01-31 19:27:06 +00:00
|
|
|
|
socket = assign(socket, presences_count: 0, presences: %{}, presence_ids: %{})
|
2021-11-30 18:06:35 +00:00
|
|
|
|
|
2024-06-04 21:27:51 +00:00
|
|
|
|
if profile do
|
2022-01-31 19:27:06 +00:00
|
|
|
|
profile
|
2022-04-06 16:20:23 +00:00
|
|
|
|
|> LiveBeatsWeb.Presence.list_profile_users()
|
2022-01-31 19:27:06 +00:00
|
|
|
|
|> Enum.reduce(socket, fn {_, presence}, acc -> assign_presence(acc, presence) end)
|
2022-01-12 17:27:30 +00:00
|
|
|
|
else
|
2022-01-31 19:27:06 +00:00
|
|
|
|
socket
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp assign_presence(socket, presence) do
|
|
|
|
|
%{user: user} = presence
|
|
|
|
|
%{presence_ids: presence_ids} = socket.assigns
|
|
|
|
|
|
|
|
|
|
cond do
|
|
|
|
|
Map.has_key?(presence_ids, user.id) ->
|
|
|
|
|
socket
|
|
|
|
|
|
|
|
|
|
Enum.count(presence_ids) < @max_presences ->
|
|
|
|
|
socket
|
|
|
|
|
|> update(:presences, &Map.put(&1, user.id, user))
|
|
|
|
|
|> update(:presence_ids, &Map.put(&1, user.id, System.system_time()))
|
|
|
|
|
|> update(:presences_count, &(&1 + 1))
|
|
|
|
|
|
|
|
|
|
true ->
|
|
|
|
|
update(socket, :presences_count, &(&1 + 1))
|
2022-01-12 17:27:30 +00:00
|
|
|
|
end
|
2021-11-16 16:58:22 +00:00
|
|
|
|
end
|
|
|
|
|
|
2022-01-31 19:27:06 +00:00
|
|
|
|
defp remove_presence(socket, user) do
|
|
|
|
|
socket
|
|
|
|
|
|> update(:presences, &Map.delete(&1, user.id))
|
|
|
|
|
|> update(:presence_ids, &Map.delete(&1, user.id))
|
|
|
|
|
|> update(:presences_count, &(&1 - 1))
|
|
|
|
|
end
|
|
|
|
|
|
2021-11-16 16:58:22 +00:00
|
|
|
|
defp url_text(nil), do: ""
|
2021-11-18 16:50:15 +00:00
|
|
|
|
|
2021-11-16 16:58:22 +00:00
|
|
|
|
defp url_text(url_str) do
|
|
|
|
|
uri = URI.parse(url_str)
|
|
|
|
|
uri.host <> uri.path
|
|
|
|
|
end
|
2021-10-29 16:12:23 +00:00
|
|
|
|
end
|