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