defmodule LiveBeatsWeb.PlayerLive do
use LiveBeatsWeb, {:live_view, container: {:div, []}}
alias LiveBeats.MediaLibrary
alias LiveBeats.MediaLibrary.Song
on_mount {LiveBeatsWeb.UserAuth, :current_user}
def render(assigns) do
~H"""
<%= if @song, do: @song.title, else: raw(" ") %>
<%= if @song, do: @song.artist, else: raw(" ") %>
<.progress_bar id="player-progress" />
<.modal
id="enable-audio"
on_confirm={js_listen_now() |> hide_modal("enable-audio")}
data-js-show={show_modal("enable-audio")}
>
<:title>Start Listening now
Your browser needs a click event to enable playback
<:confirm>Listen Now
"""
end
def mount(_parmas, _session, socket) do
if connected?(socket) and socket.assigns.current_user do
MediaLibrary.subscribe(socket.assigns.current_user)
send(self(), :play_current)
end
socket =
assign(socket,
song: nil,
playing: false,
current_user_id: socket.assigns.current_user.id,
# todo use actual room user id
room_user_id: socket.assigns.current_user.id
)
{:ok, socket, layout: false, temporary_assigns: [current_user: nil]}
end
def handle_event("play_pause", _, socket) do
%{song: song, playing: playing} = socket.assigns
cond do
song && playing ->
MediaLibrary.pause_song(song)
{:noreply, assign(socket, playing: false)}
song ->
MediaLibrary.play_song(song)
{:noreply, assign(socket, playing: true)}
true ->
{:noreply, assign(socket, playing: false)}
end
end
def handle_event("next-song", _, socket) do
if socket.assigns.song do
MediaLibrary.play_next_song(socket.assigns.song.user_id)
end
{:noreply, socket}
end
def handle_event("prev-song", _, socket) do
if socket.assigns.song do
MediaLibrary.play_prev_song(socket.assigns.song.user_id)
end
{:noreply, socket}
end
def handle_event("next-song-auto", _, socket) do
if socket.assigns.song do
MediaLibrary.play_next_song_auto(socket.assigns.song.user_id)
end
{:noreply, socket}
end
def handle_info(:play_current, socket) do
# we raced a pubsub, noop
if socket.assigns.song do
{:noreply, socket}
else
{:noreply, play_current_song(socket)}
end
end
def handle_info({:pause, _}, socket) do
{:noreply,
socket
|> push_event("pause", %{})
|> assign(playing: false)}
end
def handle_info({:play, %Song{} = song, %{elapsed: elapsed}}, socket) do
{:noreply, play_song(socket, song, elapsed)}
end
defp play_song(socket, %Song{} = song, elapsed) do
socket
|> push_play(song, elapsed)
|> assign(song: song, playing: true)
end
defp js_play_pause(%JS{} = js) do
JS.dispatch(js, "js:play_pause", to: "#audio-player")
end
defp js_listen_now(js \\ %JS{}) do
JS.dispatch(js, "js:listen_now", to: "#audio-player")
end
defp play_current_song(socket) do
song = MediaLibrary.get_current_active_song(socket.assigns.room_user_id)
cond do
song && MediaLibrary.playing?(song) ->
play_song(socket, song, MediaLibrary.elapsed_playback(song))
song && MediaLibrary.paused?(song) ->
assign(socket, song: song, playing: false)
true ->
socket
end
end
defp push_play(socket, %Song{} = song, elapsed) do
token = Phoenix.Token.sign(socket.endpoint, "file", song.mp3_filename)
push_event(socket, "play", %{
paused: Song.paused?(song),
elapsed: elapsed,
token: token,
url: song.mp3_url
})
end
end