diff --git a/assets/js/app.js b/assets/js/app.js
index ffc5ec6..e696062 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -1,7 +1,7 @@
import "phoenix_html"
import {Socket} from "phoenix"
-// import {LiveSocket} from "./phoenix_live_view"
-import {LiveSocket} from "phoenix_live_view"
+import {LiveSocket} from "./phoenix_live_view"
+// import {LiveSocket} from "phoenix_live_view"
import topbar from "../vendor/topbar"
let nowSeconds = () => Math.round(Date.now() / 1000)
@@ -54,9 +54,8 @@ Hooks.AudioPlayer = {
this.play({sync: true})
}
})
- this.handleEvent("pause", () => {
- this.pause()
- })
+ this.handleEvent("pause", () => this.pause())
+ this.handleEvent("stop", () => this.stop())
},
play(opts = {}){
@@ -76,10 +75,19 @@ Hooks.AudioPlayer = {
this.player.pause()
},
+ stop(){
+ clearInterval(this.progressTimer)
+ this.player.pause()
+ this.player.currentTime = 0
+ this.updateProgress()
+ this.duration.innerText = ""
+ this.currentTime.innerText = ""
+ },
+
updateProgress(){
if(isNaN(this.player.duration)){ return false }
if(this.player.currentTime >= this.player.duration){
- this.pushEvent("next-song-auto")
+ this.pushEvent("next_song_auto")
clearInterval(this.progressTimer)
return
}
diff --git a/lib/live_beats/accounts.ex b/lib/live_beats/accounts.ex
index c063d2f..22ad860 100644
--- a/lib/live_beats/accounts.ex
+++ b/lib/live_beats/accounts.ex
@@ -6,6 +6,17 @@ defmodule LiveBeats.Accounts do
alias LiveBeats.Accounts.{User, Identity}
@admin_emails ["chris@chrismccord.com"]
+ @pubsub LiveBeats.PubSub
+
+ def subscribe(user_id) do
+ Phoenix.PubSub.subscribe(@pubsub, topic(user_id))
+ end
+
+ def unsubscribe(user_id) do
+ Phoenix.PubSub.unsubscribe(@pubsub, topic(user_id))
+ end
+
+ defp topic(user_id), do: "user:#{user_id}"
def list_users(opts) do
Repo.all(from u in User, limit: ^Keyword.fetch!(opts, :limit))
@@ -47,6 +58,27 @@ defmodule LiveBeats.Accounts do
"""
def get_user!(id), do: Repo.get!(User, id)
+ def get_user_by!(fields), do: Repo.get_by!(User, fields)
+
+ def update_active_profile(%User{active_profile_user_id: same_id} = current_user, same_id) do
+ current_user
+ end
+
+ def update_active_profile(%User{} = current_user, profile_user_id) do
+ {1, _} =
+ Repo.update_all(from(u in User, where: u.id == ^current_user.id),
+ set: [active_profile_user_id: profile_user_id]
+ )
+
+ Phoenix.PubSub.broadcast!(
+ @pubsub,
+ topic(current_user.id),
+ {__MODULE__, :active_profile_changed, current_user, %{user_id: profile_user_id}}
+ )
+
+ %User{current_user | active_profile_user_id: profile_user_id}
+ end
+
## User registration
@doc """
diff --git a/lib/live_beats/accounts/user.ex b/lib/live_beats/accounts/user.ex
index b4c2a8c..456f83e 100644
--- a/lib/live_beats/accounts/user.ex
+++ b/lib/live_beats/accounts/user.ex
@@ -11,6 +11,7 @@ defmodule LiveBeats.Accounts.User do
field :confirmed_at, :naive_datetime
field :role, :string, default: "subscriber"
field :profile_tagline, :string
+ field :active_profile_user_id, :id
has_many :identities, Identity
diff --git a/lib/live_beats/media_library.ex b/lib/live_beats/media_library.ex
index dba6c4f..46c9f66 100644
--- a/lib/live_beats/media_library.ex
+++ b/lib/live_beats/media_library.ex
@@ -6,7 +6,7 @@ defmodule LiveBeats.MediaLibrary do
require Logger
import Ecto.Query, warn: false
alias LiveBeats.{Repo, MP3Stat, Accounts}
- alias LiveBeats.MediaLibrary.{Song, Genre}
+ alias LiveBeats.MediaLibrary.{Profile, Song, Genre}
alias Ecto.{Multi, Changeset}
@pubsub LiveBeats.PubSub
@@ -16,15 +16,25 @@ defmodule LiveBeats.MediaLibrary do
defdelegate playing?(song), to: Song
defdelegate paused?(song), to: Song
- def subscribe(%Accounts.User{} = user) do
- Phoenix.PubSub.subscribe(@pubsub, topic(user.id))
+ def subscribe_to_profile(%Profile{} = profile, from \\ nil) do
+ Phoenix.PubSub.subscribe(@pubsub, topic(profile.user_id))
+ end
+
+ def unsubscribe_to_profile(%Profile{} = profile) do
+ Phoenix.PubSub.unsubscribe(@pubsub, topic(profile.user_id))
end
def local_filepath(filename_uuid) when is_binary(filename_uuid) do
Path.join("priv/uploads/songs", filename_uuid)
end
- def play_song(%Song{id: id}), do: play_song(id)
+ def can_control_playback?(%Accounts.User{} = user, %Song{} = song) do
+ user.id == song.user_id
+ end
+
+ def play_song(%Song{id: id}) do
+ play_song(id)
+ end
def play_song(id) do
song = get_song!(id)
@@ -60,7 +70,14 @@ defmodule LiveBeats.MediaLibrary do
|> Repo.transaction()
elapsed = elapsed_playback(new_song)
- Phoenix.PubSub.broadcast!(@pubsub, topic(song.user_id), {:play, song, %{elapsed: elapsed}})
+
+ Phoenix.PubSub.broadcast!(
+ @pubsub,
+ topic(song.user_id),
+ {__MODULE__, :play, song, %{elapsed: elapsed}}
+ )
+
+ new_song
end
def pause_song(%Song{} = song) do
@@ -79,36 +96,36 @@ defmodule LiveBeats.MediaLibrary do
|> Multi.update_all(:now_paused, fn _ -> pause_query end, [])
|> Repo.transaction()
- Phoenix.PubSub.broadcast!(@pubsub, topic(song.user_id), {:pause, song})
+ Phoenix.PubSub.broadcast!(@pubsub, topic(song.user_id), {__MODULE__, :pause, song})
end
- def play_next_song_auto(user_id) do
- song = get_current_active_song(user_id) || get_first_song(user_id)
+ def play_next_song_auto(%Profile{} = profile) do
+ song = get_current_active_song(profile) || get_first_song(profile)
if song && elapsed_playback(song) >= song.duration - @auto_next_threshold_seconds do
song
- |> get_next_song()
+ |> get_next_song(profile)
|> play_song()
end
end
- def play_prev_song(user_id) do
- song = get_current_active_song(user_id) || get_first_song(user_id)
+ def play_prev_song(%Profile{} = profile) do
+ song = get_current_active_song(profile) || get_first_song(profile)
- if prev_song = get_prev_song(song) do
+ if prev_song = get_prev_song(song, profile) do
play_song(prev_song)
end
end
- def play_next_song(user_id) do
- song = get_current_active_song(user_id) || get_first_song(user_id)
+ def play_next_song(%Profile{} = profile) do
+ song = get_current_active_song(profile) || get_first_song(profile)
- if next_song = get_next_song(song) do
+ if next_song = get_next_song(song, profile) do
play_song(next_song)
end
end
- defp topic(user_id), do: "room:#{user_id}"
+ defp topic(user_id) when is_integer(user_id), do: "profile:#{user_id}"
def store_mp3(%Song{} = song, tmp_path) do
File.mkdir_p!(Path.dirname(song.mp3_filepath))
@@ -170,16 +187,28 @@ defmodule LiveBeats.MediaLibrary do
Repo.all(Genre, order_by: [asc: :title])
end
- def list_songs(limit \\ 100) do
- from(s in Song, limit: ^limit)
+ def list_profile_songs(%Profile{} = profile, limit \\ 100) do
+ from(s in Song, where: s.user_id == ^profile.user_id, limit: ^limit)
|> order_by_playlist(:asc)
|> Repo.all()
end
- def get_current_active_song(user_id) do
+ def get_current_active_song(%Profile{user_id: user_id}) do
Repo.one(from s in Song, where: s.user_id == ^user_id and s.status in [:playing, :paused])
end
+ def get_profile!(%Accounts.User{} = user) do
+ %Profile{user_id: user.id, username: user.username, tagline: user.profile_tagline}
+ end
+
+ def owns_profile?(%Accounts.User{} = user, %Profile{} = profile) do
+ user.id == profile.user_id
+ end
+
+ def owns_song?(%Profile{} = profile, %Song{} = song) do
+ profile.user_id == song.user_id
+ end
+
def elapsed_playback(%Song{} = song) do
cond do
playing?(song) ->
@@ -196,7 +225,7 @@ defmodule LiveBeats.MediaLibrary do
def get_song!(id), do: Repo.get!(Song, id)
- def get_first_song(user_id) do
+ def get_first_song(%Profile{user_id: user_id}) do
from(s in Song,
where: s.user_id == ^user_id,
limit: 1
@@ -205,7 +234,7 @@ defmodule LiveBeats.MediaLibrary do
|> Repo.one()
end
- def get_last_song(user_id) do
+ def get_last_song(%Profile{user_id: user_id}) do
from(s in Song,
where: s.user_id == ^user_id,
limit: 1
@@ -214,7 +243,7 @@ defmodule LiveBeats.MediaLibrary do
|> Repo.one()
end
- def get_next_song(%Song{} = song) do
+ def get_next_song(%Song{} = song, %Profile{} = profile) do
next =
from(s in Song,
where: s.user_id == ^song.user_id and s.id > ^song.id,
@@ -223,10 +252,10 @@ defmodule LiveBeats.MediaLibrary do
|> order_by_playlist(:asc)
|> Repo.one()
- next || get_first_song(song.user_id)
+ next || get_first_song(profile)
end
- def get_prev_song(%Song{} = song) do
+ def get_prev_song(%Song{} = song, %Profile{} = profile) do
prev =
from(s in Song,
where: s.user_id == ^song.user_id and s.id < ^song.id,
@@ -236,7 +265,7 @@ defmodule LiveBeats.MediaLibrary do
|> order_by_playlist(:desc)
|> Repo.one()
- prev || get_last_song(song.user_id)
+ prev || get_last_song(profile)
end
def create_song(attrs \\ %{}) do
diff --git a/lib/live_beats/media_library/profile.ex b/lib/live_beats/media_library/profile.ex
new file mode 100644
index 0000000..a8a1026
--- /dev/null
+++ b/lib/live_beats/media_library/profile.ex
@@ -0,0 +1,3 @@
+defmodule LiveBeats.MediaLibrary.Profile do
+ defstruct user_id: nil, username: nil, tagline: nil
+end
diff --git a/lib/live_beats_web/controllers/file_controller.ex b/lib/live_beats_web/controllers/file_controller.ex
index 1db590b..3b3a60b 100644
--- a/lib/live_beats_web/controllers/file_controller.ex
+++ b/lib/live_beats_web/controllers/file_controller.ex
@@ -5,9 +5,17 @@ defmodule LiveBeatsWeb.FileController do
def show(conn, %{"id" => filename_uuid, "token" => token}) do
case Phoenix.Token.verify(conn, "file", token, max_age: :timer.minutes(10)) do
- {:ok, ^filename_uuid} -> send_file(conn, 200, MediaLibrary.local_filepath(filename_uuid))
+ {:ok, ^filename_uuid} -> do_send_file(conn, MediaLibrary.local_filepath(filename_uuid))
{:ok, _} -> send_resp(conn, :unauthorized, "")
{:error, _} -> send_resp(conn, :unauthorized, "")
- end
+ end
+ end
+
+ defp do_send_file(conn, path) do
+ # accept-ranges headers required for chrome to seek via currentTime
+ conn
+ |> put_resp_header("content-type", "audio/mp3")
+ |> put_resp_header("accept-ranges", "bytes")
+ |> send_file(200, path)
end
end
diff --git a/lib/live_beats_web/live/home_live.ex b/lib/live_beats_web/live/home_live.ex
index 19ea926..d4de3dd 100644
--- a/lib/live_beats_web/live/home_live.ex
+++ b/lib/live_beats_web/live/home_live.ex
@@ -1,7 +1,7 @@
defmodule LiveBeatsWeb.HomeLive do
use LiveBeatsWeb, :live_view
- alias LiveBeats.MediaLibrary
+ # alias LiveBeats.MediaLibrary
def render(assigns) do
~H"""
@@ -346,6 +346,6 @@ defmodule LiveBeatsWeb.HomeLive do
end
defp fetch_songs(_socket) do
- MediaLibrary.list_songs()
+ []
end
end
diff --git a/lib/live_beats_web/live/player_live.ex b/lib/live_beats_web/live/player_live.ex
index 5bf92cd..d47188a 100644
--- a/lib/live_beats_web/live/player_live.ex
+++ b/lib/live_beats_web/live/player_live.ex
@@ -1,7 +1,7 @@
defmodule LiveBeatsWeb.PlayerLive do
use LiveBeatsWeb, {:live_view, container: {:div, []}}
- alias LiveBeats.MediaLibrary
+ alias LiveBeats.{Accounts, MediaLibrary}
alias LiveBeats.MediaLibrary.Song
on_mount {LiveBeatsWeb.UserAuth, :current_user}
@@ -36,14 +36,20 @@ defmodule LiveBeatsWeb.PlayerLive do
-
+ <%= if @profile do %>
+ <.link
+ redirect_to={Routes.song_index_path(@socket, :index, @profile.username)}
+ class="mx-auto flex outline border-2 border-white border-opacity-20 rounded-md p-1 pr-2"
+ >
+
<.icon name={:user_circle}/>
+
<%= @profile.username %>
+
+ <% else %>
+
+ <% end %>
-
"""
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)
+ %{current_user: current_user} = socket.assigns
+
+ if connected?(socket) do
+ Accounts.subscribe(current_user.id)
end
socket =
- assign(socket,
+ socket
+ |> assign(
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
+ profile: nil,
+ current_user_id: current_user.id,
+ own_profile?: false
)
+ |> switch_profile(current_user.active_profile_user_id || current_user.id)
- {:ok, socket, layout: false, temporary_assigns: [current_user: nil]}
+ {:ok, socket, layout: false, temporary_assigns: []}
+ end
+
+ defp switch_profile(socket, nil) do
+ current_user = Accounts.update_active_profile(socket.assigns.current_user, nil)
+
+ socket
+ |> assign(current_user: current_user)
+ |> assign_profile(nil)
+ end
+
+ defp switch_profile(socket, profile_user_id) do
+ profile = get_profile(profile_user_id)
+
+ if connected?(socket) and profile do
+ current_user = Accounts.update_active_profile(socket.assigns.current_user, profile.user_id)
+
+ send(self(), :play_current)
+
+ socket
+ |> assign(current_user: current_user)
+ |> assign_profile(profile)
+ else
+ assign_profile(socket, nil)
+ end
+ end
+
+ defp assign_profile(socket, profile) do
+ if prev_profile = connected?(socket) && socket.assigns.profile do
+ MediaLibrary.unsubscribe_to_profile(prev_profile)
+ end
+ if profile, do: MediaLibrary.subscribe_to_profile(profile)
+
+ assign(socket,
+ profile: profile,
+ own_profile?: profile && MediaLibrary.owns_profile?(socket.assigns.current_user, profile)
+ )
+ end
+
+ defp assign_inactive_profile(socket, %Song{} = song) do
+ if socket.assigns.profile && MediaLibrary.owns_song?(socket.assigns.profile, song) do
+ socket
+ else
+ switch_profile(socket, song.user_id)
+ end
end
def handle_event("play_pause", _, socket) do
- %{song: song, playing: playing} = socket.assigns
+ %{song: song, playing: playing, current_user: current_user} = socket.assigns
+ song = MediaLibrary.get_song!(song.id)
cond do
- song && playing ->
+ song && playing and MediaLibrary.can_control_playback?(current_user, song) ->
MediaLibrary.pause_song(song)
{:noreply, assign(socket, playing: false)}
- song ->
+ song && MediaLibrary.can_control_playback?(current_user, song) ->
MediaLibrary.play_song(song)
{:noreply, assign(socket, playing: true)}
true ->
- {:noreply, assign(socket, playing: false)}
+ {:noreply, socket}
end
end
- def handle_event("next-song", _, socket) do
- if socket.assigns.song do
- MediaLibrary.play_next_song(socket.assigns.song.user_id)
+ def handle_event("switch_profile", %{"user_id" => user_id}, socket) do
+ {:noreply, switch_profile(socket, user_id)}
+ end
+
+ def handle_event("next_song", _, socket) do
+ %{song: song, current_user: current_user} = socket.assigns
+
+ if song && MediaLibrary.can_control_playback?(current_user, song) do
+ MediaLibrary.play_next_song(socket.assigns.profile)
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)
+ def handle_event("prev_song", _, socket) do
+ %{song: song, current_user: current_user} = socket.assigns
+
+ if song && MediaLibrary.can_control_playback?(current_user, song) do
+ MediaLibrary.play_prev_song(socket.assigns.profile)
end
+
{:noreply, socket}
end
- def handle_event("next-song-auto", _, socket) do
+ def handle_event("next_song_auto", _, socket) do
if socket.assigns.song do
- MediaLibrary.play_next_song_auto(socket.assigns.song.user_id)
+ MediaLibrary.play_next_song_auto(socket.assigns.profile)
end
+
{:noreply, socket}
end
+ def handle_info({Accounts, :active_profile_changed, _cur_user, %{user_id: user_id}}, socket) do
+ if user_id do
+ {:noreply, assign(socket, profile: get_profile(user_id))}
+ else
+ {:noreply, socket |> assign_profile(nil) |> stop_song()}
+ end
+ 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
+ {:noreply, play_current_song(socket)}
end
- def handle_info({:pause, _}, socket) do
- {:noreply,
- socket
- |> push_event("pause", %{})
- |> assign(playing: false)}
+ def handle_info({MediaLibrary, :pause, _}, socket) do
+ {:noreply, push_pause(socket)}
end
- def handle_info({:play, %Song{} = song, %{elapsed: elapsed}}, socket) do
+ def handle_info({MediaLibrary, :play, %Song{} = song, %{elapsed: elapsed}}, socket) do
{:noreply, play_song(socket, song, elapsed)}
end
@@ -170,18 +245,17 @@ defmodule LiveBeatsWeb.PlayerLive do
socket
|> push_play(song, elapsed)
|> assign(song: song, playing: true)
+ |> assign_inactive_profile(song)
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")
+ defp stop_song(socket) do
+ socket
+ |> push_event("stop", %{})
+ |> assign(song: nil, playing: false)
end
defp play_current_song(socket) do
- song = MediaLibrary.get_current_active_song(socket.assigns.room_user_id)
+ song = MediaLibrary.get_current_active_song(socket.assigns.profile)
cond do
song && MediaLibrary.playing?(song) ->
@@ -197,6 +271,7 @@ defmodule LiveBeatsWeb.PlayerLive do
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,
@@ -204,4 +279,43 @@ defmodule LiveBeatsWeb.PlayerLive do
url: song.mp3_url
})
end
+
+ defp push_pause(socket) do
+ socket
+ |> push_event("pause", %{})
+ |> assign(playing: false)
+ end
+
+ defp js_play_pause(own_profile?) do
+ if own_profile? do
+ JS.push("play_pause")
+ |> JS.dispatch("js:play_pause", to: "#audio-player")
+ else
+ show_modal("not-authorized")
+ end
+ end
+
+ defp js_prev(own_profile?) do
+ if own_profile? do
+ JS.push("prev_song")
+ else
+ show_modal("not-authorized")
+ end
+ end
+
+ defp js_next(own_profile?) do
+ if own_profile? do
+ JS.push("next_song")
+ else
+ show_modal("not-authorized")
+ end
+ end
+
+ defp js_listen_now(js \\ %JS{}) do
+ JS.dispatch(js, "js:listen_now", to: "#audio-player")
+ end
+
+ defp get_profile(user_id) do
+ user_id && Accounts.get_user!(user_id) |> MediaLibrary.get_profile!()
+ end
end
diff --git a/lib/live_beats_web/live/song_live/index.ex b/lib/live_beats_web/live/song_live/index.ex
index e8924ca..f6d2705 100644
--- a/lib/live_beats_web/live/song_live/index.ex
+++ b/lib/live_beats_web/live/song_live/index.ex
@@ -1,17 +1,34 @@
defmodule LiveBeatsWeb.SongLive.Index do
use LiveBeatsWeb, :live_view
- alias LiveBeats.{MediaLibrary, MP3Stat}
+ alias LiveBeats.{Accounts, MediaLibrary, MP3Stat}
alias LiveBeatsWeb.LayoutComponent
alias LiveBeatsWeb.SongLive.{SongRowComponent, UploadFormComponent}
def render(assigns) do
~H"""
<.title_bar>
- Listing Songs
+ <%= @profile.tagline %> <%= if @owns_profile? do %>(you)<% end %>
<:actions>
- <.button primary patch_to={Routes.song_index_path(@socket, :new)}>Upload Songs
+ <%= if @active_profile_id == @profile.user_id do %>
+ <.button primary
+ phx-click={JS.push("switch_profile", value: %{user_id: nil}, target: "#player", loading: "#player")}
+ >
+ <.icon name={:stop}/>Stop Listening
+
+ <% else %>
+ <.button primary
+ phx-click={JS.push("switch_profile", value: %{user_id: @profile.user_id}, target: "#player", loading: "#player")}
+ >
+ <.icon name={:play}/>Listen
+
+ <% end %>
+ <%= if @owns_profile? do %>
+ <.button primary patch_to={Routes.song_index_path(@socket, :new)}>
+ <.icon name={:upload}/>Upload Songs
+
+ <% end %>
@@ -45,20 +62,35 @@ defmodule LiveBeatsWeb.SongLive.Index do
"""
end
- def mount(_params, _session, socket) do
+ def mount(%{"profile_username" => profile_username}, _session, socket) do
%{current_user: current_user} = socket.assigns
+ profile =
+ Accounts.get_user_by!(username: profile_username)
+ |> MediaLibrary.get_profile!()
+
if connected?(socket) do
- MediaLibrary.subscribe(current_user)
+ MediaLibrary.subscribe_to_profile(profile, __MODULE__)
+ Accounts.subscribe(current_user.id)
end
- active_id =
- if song = MediaLibrary.get_current_active_song(current_user.id) do
+ active_song_id =
+ if song = MediaLibrary.get_current_active_song(profile) do
SongRowComponent.send_status(song.id, song.status)
song.id
end
- {:ok, assign(socket, songs: list_songs(), active_id: active_id), temporary_assigns: [songs: []]}
+ socket =
+ socket
+ |> assign(
+ active_song_id: active_song_id,
+ active_profile_id: current_user.active_profile_user_id,
+ profile: profile,
+ owns_profile?: MediaLibrary.owns_profile?(current_user, profile)
+ )
+ |> list_songs()
+
+ {:ok, socket, temporary_assigns: [songs: []]}
end
def handle_params(params, _url, socket) do
@@ -67,10 +99,17 @@ defmodule LiveBeatsWeb.SongLive.Index do
def handle_event("play_or_pause", %{"id" => id}, socket) do
song = MediaLibrary.get_song!(id)
- if socket.assigns.active_id == id and MediaLibrary.playing?(song) do
- MediaLibrary.pause_song(song)
- else
- MediaLibrary.play_song(id)
+ can_playback? = MediaLibrary.can_control_playback?(socket.assigns.current_user, song)
+
+ cond do
+ can_playback? and socket.assigns.active_song_id == id and MediaLibrary.playing?(song) ->
+ MediaLibrary.pause_song(song)
+
+ can_playback? ->
+ MediaLibrary.play_song(id)
+
+ true ->
+ :noop
end
{:noreply, socket}
@@ -78,23 +117,29 @@ defmodule LiveBeatsWeb.SongLive.Index do
def handle_event("delete", %{"id" => id}, socket) do
song = MediaLibrary.get_song!(id)
- {:ok, _} = MediaLibrary.delete_song(song)
+ if song.user_id == socket.assigns.current_user.id do
+ {:ok, _} = MediaLibrary.delete_song(song)
+ end
{:noreply, socket}
end
- def handle_info({:play, %MediaLibrary.Song{} = song, _meta}, socket) do
+ def handle_info({Accounts, :active_profile_changed, _cur_user, %{user_id: user_id}}, socket) do
+ {:noreply, assign(socket, active_profile_id: user_id)}
+ end
+
+ def handle_info({MediaLibrary, :play, %MediaLibrary.Song{} = song, _meta}, socket) do
{:noreply, play_song(socket, song)}
end
- def handle_info({:pause, %MediaLibrary.Song{} = song}, socket) do
+ def handle_info({MediaLibrary, :pause, %MediaLibrary.Song{} = song}, socket) do
{:noreply, pause_song(socket, song.id)}
end
defp stop_song(socket, song_id) do
SongRowComponent.send_status(song_id, :stopped)
- if socket.assigns.active_id == song_id do
- assign(socket, :active_id, nil)
+ if socket.assigns.active_song_id == song_id do
+ assign(socket, :active_song_id, nil)
else
socket
end
@@ -106,23 +151,23 @@ defmodule LiveBeatsWeb.SongLive.Index do
end
defp play_song(socket, %MediaLibrary.Song{} = song) do
- %{active_id: active_id} = socket.assigns
+ %{active_song_id: active_song_id} = socket.assigns
cond do
- active_id == song.id ->
+ active_song_id == song.id ->
SongRowComponent.send_status(song.id, :playing)
socket
- active_id ->
+ active_song_id ->
SongRowComponent.send_status(song.id, :playing)
socket
- |> stop_song(active_id)
- |> assign(active_id: song.id)
+ |> stop_song(active_song_id)
+ |> assign(active_song_id: song.id)
true ->
SongRowComponent.send_status(song.id, :playing)
- assign(socket, active_id: song.id)
+ assign(socket, active_song_id: song.id)
end
end
@@ -155,7 +200,7 @@ defmodule LiveBeatsWeb.SongLive.Index do
|> assign(:song, nil)
end
- defp list_songs do
- MediaLibrary.list_songs(50)
+ defp list_songs(socket) do
+ assign(socket, songs: MediaLibrary.list_profile_songs(socket.assigns.profile, 50))
end
end
diff --git a/lib/live_beats_web/router.ex b/lib/live_beats_web/router.ex
index 33469da..1db8141 100644
--- a/lib/live_beats_web/router.ex
+++ b/lib/live_beats_web/router.ex
@@ -56,7 +56,7 @@ defmodule LiveBeatsWeb.Router do
live_session :authenticated,
on_mount: [{LiveBeatsWeb.UserAuth, :ensure_authenticated}, LiveBeatsWeb.Nav] do
live "/songs/new", SongLive.Index, :new
- live "/:user_id", SongLive.Index, :index
+ live "/:profile_username", SongLive.Index, :index
live "/profile/settings", SettingsLive, :edit
end
end
diff --git a/priv/repo/migrations/20210905021010_create_user_auth.exs b/priv/repo/migrations/20210905021010_create_user_auth.exs
index 00ec7ea..b297571 100644
--- a/priv/repo/migrations/20210905021010_create_user_auth.exs
+++ b/priv/repo/migrations/20210905021010_create_user_auth.exs
@@ -11,6 +11,7 @@ defmodule LiveBeats.Repo.Migrations.CreateUserAuth do
add :role, :string, null: false
add :confirmed_at, :naive_datetime
add :profile_tagline, :string
+ add :active_profile_user_id, references(:users, on_delete: :nilify_all)
timestamps()
end