Update all callers to use matching_records
Migrate StatsLive.Index, ScrobbledTracksLive.Index, and TopAlbums to consume matching_records list instead of scalar record IDs. Remove the derive_legacy_record_ids bridge function. TopAlbums now uses a dropdown for multi-record badges with play count display.
This commit is contained in:
@@ -123,12 +123,9 @@ defmodule MusicLibrary.ListeningStats do
|
|||||||
recent_tracks
|
recent_tracks
|
||||||
|> Enum.map(fn %{track: track, artist_id: artist_id, matching_records: matching_records} =
|
|> Enum.map(fn %{track: track, artist_id: artist_id, matching_records: matching_records} =
|
||||||
rt ->
|
rt ->
|
||||||
parsed = parse_matching_records(matching_records)
|
|
||||||
|
|
||||||
rt
|
rt
|
||||||
|> Map.put(:track, polyfill_track(track, timezone, artist_id))
|
|> Map.put(:track, polyfill_track(track, timezone, artist_id))
|
||||||
|> Map.put(:matching_records, parsed)
|
|> Map.put(:matching_records, parse_matching_records(matching_records))
|
||||||
|> derive_legacy_record_ids(parsed)
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
recent_albums =
|
recent_albums =
|
||||||
@@ -200,11 +197,7 @@ defmodule MusicLibrary.ListeningStats do
|
|||||||
from(t in ordered_query, limit: ^page_size, offset: ^offset)
|
from(t in ordered_query, limit: ^page_size, offset: ^offset)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|> Enum.map(fn result ->
|
|> Enum.map(fn result ->
|
||||||
parsed = parse_matching_records(result.matching_records)
|
%{result | matching_records: parse_matching_records(result.matching_records)}
|
||||||
|
|
||||||
result
|
|
||||||
|> Map.put(:matching_records, parsed)
|
|
||||||
|> derive_legacy_record_ids(parsed)
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -624,16 +617,4 @@ defmodule MusicLibrary.ListeningStats do
|
|||||||
{:ok, dt, _offset} = DateTime.from_iso8601(dt_string)
|
{:ok, dt, _offset} = DateTime.from_iso8601(dt_string)
|
||||||
dt
|
dt
|
||||||
end
|
end
|
||||||
|
|
||||||
# Temporary bridge: derive collected_record_id and wishlisted_record_id from
|
|
||||||
# matching_records so existing LiveView templates keep working until they are
|
|
||||||
# migrated to use matching_records directly.
|
|
||||||
defp derive_legacy_record_ids(result, matching_records) do
|
|
||||||
collected = Enum.find(matching_records, &(&1.purchased_at != nil))
|
|
||||||
wishlisted = Enum.find(matching_records, &is_nil(&1.purchased_at))
|
|
||||||
|
|
||||||
result
|
|
||||||
|> Map.put(:collected_record_id, collected && collected.id)
|
|
||||||
|> Map.put(:wishlisted_record_id, wishlisted && wishlisted.id)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -107,8 +107,7 @@ defmodule MusicLibraryWeb.ScrobbledTracksLive.Index do
|
|||||||
%{
|
%{
|
||||||
track: track,
|
track: track,
|
||||||
artist_id: artist_id,
|
artist_id: artist_id,
|
||||||
collected_record_id: collected_record_id,
|
matching_records: matching_records,
|
||||||
wishlisted_record_id: wishlisted_record_id,
|
|
||||||
cover_hash: cover_hash
|
cover_hash: cover_hash
|
||||||
}} <- @streams.tracks
|
}} <- @streams.tracks
|
||||||
}
|
}
|
||||||
@@ -147,16 +146,13 @@ defmodule MusicLibraryWeb.ScrobbledTracksLive.Index do
|
|||||||
|
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<.record_status_badges
|
<.record_status_badges
|
||||||
|
id={"status-#{track.scrobbled_at_uts}"}
|
||||||
musicbrainz_id={track.album.musicbrainz_id}
|
musicbrainz_id={track.album.musicbrainz_id}
|
||||||
collected_record_id={collected_record_id}
|
matching_records={matching_records}
|
||||||
wishlisted_record_id={wishlisted_record_id}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<.import_format_dropdown
|
<.import_format_dropdown
|
||||||
:if={
|
:if={track.album.musicbrainz_id !== "" and matching_records == []}
|
||||||
track.album.musicbrainz_id !== "" and !collected_record_id and
|
|
||||||
!wishlisted_record_id
|
|
||||||
}
|
|
||||||
id={"actions-#{track.scrobbled_at_uts}-tracks"}
|
id={"actions-#{track.scrobbled_at_uts}-tracks"}
|
||||||
musicbrainz_id={track.album.musicbrainz_id}
|
musicbrainz_id={track.album.musicbrainz_id}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -266,8 +266,7 @@ defmodule MusicLibraryWeb.StatsLive.Index do
|
|||||||
%{
|
%{
|
||||||
album: album,
|
album: album,
|
||||||
artist_id: artist_id,
|
artist_id: artist_id,
|
||||||
collected_record_id: collected_record_id,
|
matching_records: matching_records,
|
||||||
wishlisted_record_id: wishlisted_record_id,
|
|
||||||
cover_hash: cover_hash
|
cover_hash: cover_hash
|
||||||
}} <- @streams.recent_albums
|
}} <- @streams.recent_albums
|
||||||
}
|
}
|
||||||
@@ -316,16 +315,13 @@ defmodule MusicLibraryWeb.StatsLive.Index do
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<.record_status_badges
|
<.record_status_badges
|
||||||
|
id={"status-#{album.scrobbled_at_uts}-albums"}
|
||||||
musicbrainz_id={album.metadata.musicbrainz_id}
|
musicbrainz_id={album.metadata.musicbrainz_id}
|
||||||
collected_record_id={collected_record_id}
|
matching_records={matching_records}
|
||||||
wishlisted_record_id={wishlisted_record_id}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<.import_format_dropdown
|
<.import_format_dropdown
|
||||||
:if={
|
:if={album.metadata.musicbrainz_id !== "" and matching_records == []}
|
||||||
album.metadata.musicbrainz_id !== "" and !collected_record_id and
|
|
||||||
!wishlisted_record_id
|
|
||||||
}
|
|
||||||
id={"actions-#{album.scrobbled_at_uts}-albums"}
|
id={"actions-#{album.scrobbled_at_uts}-albums"}
|
||||||
musicbrainz_id={album.metadata.musicbrainz_id}
|
musicbrainz_id={album.metadata.musicbrainz_id}
|
||||||
/>
|
/>
|
||||||
@@ -347,8 +343,7 @@ defmodule MusicLibraryWeb.StatsLive.Index do
|
|||||||
%{
|
%{
|
||||||
track: track,
|
track: track,
|
||||||
artist_id: artist_id,
|
artist_id: artist_id,
|
||||||
collected_record_id: collected_record_id,
|
matching_records: matching_records,
|
||||||
wishlisted_record_id: wishlisted_record_id,
|
|
||||||
cover_hash: cover_hash
|
cover_hash: cover_hash
|
||||||
}} <- @streams.recent_tracks
|
}} <- @streams.recent_tracks
|
||||||
}
|
}
|
||||||
@@ -400,16 +395,13 @@ defmodule MusicLibraryWeb.StatsLive.Index do
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<.record_status_badges
|
<.record_status_badges
|
||||||
|
id={"status-#{track.scrobbled_at_uts}-tracks"}
|
||||||
musicbrainz_id={track.album.musicbrainz_id}
|
musicbrainz_id={track.album.musicbrainz_id}
|
||||||
collected_record_id={collected_record_id}
|
matching_records={matching_records}
|
||||||
wishlisted_record_id={wishlisted_record_id}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<.import_format_dropdown
|
<.import_format_dropdown
|
||||||
:if={
|
:if={track.album.musicbrainz_id !== "" and matching_records == []}
|
||||||
track.album.musicbrainz_id !== "" and !collected_record_id and
|
|
||||||
!wishlisted_record_id
|
|
||||||
}
|
|
||||||
id={"actions-#{track.scrobbled_at_uts}-tracks"}
|
id={"actions-#{track.scrobbled_at_uts}-tracks"}
|
||||||
musicbrainz_id={track.album.musicbrainz_id}
|
musicbrainz_id={track.album.musicbrainz_id}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
defmodule MusicLibraryWeb.StatsLive.TopAlbums do
|
defmodule MusicLibraryWeb.StatsLive.TopAlbums do
|
||||||
use MusicLibraryWeb, :html
|
use MusicLibraryWeb, :html
|
||||||
|
|
||||||
|
import MusicLibraryWeb.RecordComponents, only: [format_label: 1, type_label: 1]
|
||||||
|
|
||||||
alias MusicLibrary.Assets.Transform
|
alias MusicLibrary.Assets.Transform
|
||||||
alias MusicLibrary.ListeningStats
|
alias MusicLibrary.ListeningStats
|
||||||
|
alias MusicLibrary.Records
|
||||||
alias MusicLibraryWeb.StatsLive.TopByPeriod
|
alias MusicLibraryWeb.StatsLive.TopByPeriod
|
||||||
|
|
||||||
attr :id, :string, required: true
|
attr :id, :string, required: true
|
||||||
@@ -25,7 +28,7 @@ defmodule MusicLibraryWeb.StatsLive.TopAlbums do
|
|||||||
phx-click={navigate_to_record(album)}
|
phx-click={navigate_to_record(album)}
|
||||||
class={[
|
class={[
|
||||||
"flex items-center space-x-3 p-2",
|
"flex items-center space-x-3 p-2",
|
||||||
(album.collected_record_id || album.wishlisted_record_id) &&
|
navigable?(album) &&
|
||||||
"cursor-pointer hover:bg-zinc-100 dark:hover:bg-zinc-700"
|
"cursor-pointer hover:bg-zinc-100 dark:hover:bg-zinc-700"
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
@@ -45,46 +48,121 @@ defmodule MusicLibraryWeb.StatsLive.TopAlbums do
|
|||||||
{album.album_title}
|
{album.album_title}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<.badge :if={album.album_musicbrainz_id == ""}>
|
<.top_album_badge album={album} />
|
||||||
{album.play_count}
|
|
||||||
</.badge>
|
|
||||||
<.badge :if={
|
|
||||||
album.album_musicbrainz_id !== "" and !album.collected_record_id and
|
|
||||||
!album.wishlisted_record_id
|
|
||||||
}>
|
|
||||||
{album.play_count}
|
|
||||||
</.badge>
|
|
||||||
<.badge
|
|
||||||
:if={album.collected_record_id}
|
|
||||||
color="success"
|
|
||||||
>
|
|
||||||
{album.play_count}
|
|
||||||
</.badge>
|
|
||||||
<.badge
|
|
||||||
:if={album.wishlisted_record_id}
|
|
||||||
color="warning"
|
|
||||||
>
|
|
||||||
{album.play_count}
|
|
||||||
</.badge>
|
|
||||||
</div>
|
</div>
|
||||||
</:item>
|
</:item>
|
||||||
</TopByPeriod.live>
|
</TopByPeriod.live>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp navigate_to_record(album) do
|
attr :album, :map, required: true
|
||||||
|
|
||||||
|
defp top_album_badge(assigns) do
|
||||||
|
assigns =
|
||||||
|
assigns
|
||||||
|
|> assign(:status, badge_status(assigns.album.matching_records))
|
||||||
|
|> assign(:count, length(assigns.album.matching_records))
|
||||||
|
|
||||||
|
~H"""
|
||||||
|
<%= case {@count, @status} do %>
|
||||||
|
<% {0, _} -> %>
|
||||||
|
<.badge>{@album.play_count}</.badge>
|
||||||
|
<% {1, :collected} -> %>
|
||||||
|
<.badge color="success">{@album.play_count}</.badge>
|
||||||
|
<% {1, :wishlisted} -> %>
|
||||||
|
<.badge color="warning">{@album.play_count}</.badge>
|
||||||
|
<% {_, status} -> %>
|
||||||
|
<.dropdown
|
||||||
|
id={"top-album-#{@album.album_musicbrainz_id}"}
|
||||||
|
placement="bottom-end"
|
||||||
|
>
|
||||||
|
<:toggle>
|
||||||
|
<span class={[
|
||||||
|
"inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium cursor-pointer",
|
||||||
|
play_count_badge_classes(status)
|
||||||
|
]}>
|
||||||
|
{@album.play_count}
|
||||||
|
</span>
|
||||||
|
</:toggle>
|
||||||
|
<.top_album_dropdown_link
|
||||||
|
:for={record <- @album.matching_records}
|
||||||
|
record={record}
|
||||||
|
/>
|
||||||
|
</.dropdown>
|
||||||
|
<% end %>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
attr :record, :map, required: true
|
||||||
|
|
||||||
|
defp top_album_dropdown_link(assigns) do
|
||||||
|
path =
|
||||||
|
if assigns.record.purchased_at,
|
||||||
|
do: ~p"/collection/#{assigns.record.id}",
|
||||||
|
else: ~p"/wishlist/#{assigns.record.id}"
|
||||||
|
|
||||||
|
assigns = assign(assigns, :path, path)
|
||||||
|
|
||||||
|
~H"""
|
||||||
|
<.dropdown_link navigate={@path}>
|
||||||
|
<span class="flex items-center gap-2">
|
||||||
|
<.badge :if={@record.purchased_at} color="success" size="sm">
|
||||||
|
{gettext("C")}
|
||||||
|
</.badge>
|
||||||
|
<.badge :if={!@record.purchased_at} color="warning" size="sm">
|
||||||
|
{gettext("W")}
|
||||||
|
</.badge>
|
||||||
|
<span>
|
||||||
|
{format_label(String.to_existing_atom(@record.format))} · {type_label(
|
||||||
|
String.to_existing_atom(@record.type)
|
||||||
|
)}
|
||||||
|
<span :if={@record.purchased_at} class="text-zinc-500 dark:text-zinc-400">
|
||||||
|
· {Records.Record.format_as_date(@record.purchased_at)}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</.dropdown_link>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp navigate_to_record(%{matching_records: [record]}) do
|
||||||
|
if record.purchased_at do
|
||||||
|
JS.navigate(~p"/collection/#{record.id}")
|
||||||
|
else
|
||||||
|
JS.navigate(~p"/wishlist/#{record.id}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp navigate_to_record(_album), do: nil
|
||||||
|
|
||||||
|
defp navigable?(%{matching_records: [_]}), do: true
|
||||||
|
defp navigable?(_), do: false
|
||||||
|
|
||||||
|
defp badge_status([]), do: nil
|
||||||
|
|
||||||
|
defp badge_status(records) do
|
||||||
|
all_collected = Enum.all?(records, & &1.purchased_at)
|
||||||
|
all_wishlisted = Enum.all?(records, &is_nil(&1.purchased_at))
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
album.collected_record_id ->
|
all_collected -> :collected
|
||||||
JS.navigate(~p"/collection/#{album.collected_record_id}")
|
all_wishlisted -> :wishlisted
|
||||||
|
true -> :mixed
|
||||||
album.wishlisted_record_id ->
|
|
||||||
JS.navigate(~p"/wishlist/#{album.wishlisted_record_id}")
|
|
||||||
|
|
||||||
true ->
|
|
||||||
nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp play_count_badge_classes(:collected),
|
||||||
|
do:
|
||||||
|
"bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20 dark:bg-emerald-400/10 dark:text-emerald-400 dark:ring-emerald-400/20"
|
||||||
|
|
||||||
|
defp play_count_badge_classes(:wishlisted),
|
||||||
|
do:
|
||||||
|
"bg-yellow-50 text-yellow-800 ring-1 ring-yellow-600/20 dark:bg-yellow-400/10 dark:text-yellow-500 dark:ring-yellow-400/20"
|
||||||
|
|
||||||
|
defp play_count_badge_classes(:mixed),
|
||||||
|
do:
|
||||||
|
"bg-yellow-50 text-emerald-700 ring-1 ring-emerald-600/40 dark:bg-yellow-400/10 dark:text-emerald-400 dark:ring-emerald-400/40"
|
||||||
|
|
||||||
defp cover_url(album) when is_nil(album.cover_hash) do
|
defp cover_url(album) when is_nil(album.cover_hash) do
|
||||||
album.cover_url
|
album.cover_url
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2424,11 +2424,13 @@ msgid "Chat"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/components/scrobble_components.ex
|
#: lib/music_library_web/components/scrobble_components.ex
|
||||||
|
#: lib/music_library_web/live/stats_live/top_albums.ex
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "C"
|
msgid "C"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/components/scrobble_components.ex
|
#: lib/music_library_web/components/scrobble_components.ex
|
||||||
|
#: lib/music_library_web/live/stats_live/top_albums.ex
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "W"
|
msgid "W"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -2424,11 +2424,13 @@ msgid "Chat"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/components/scrobble_components.ex
|
#: lib/music_library_web/components/scrobble_components.ex
|
||||||
|
#: lib/music_library_web/live/stats_live/top_albums.ex
|
||||||
#, elixir-autogen, elixir-format, fuzzy
|
#, elixir-autogen, elixir-format, fuzzy
|
||||||
msgid "C"
|
msgid "C"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/components/scrobble_components.ex
|
#: lib/music_library_web/components/scrobble_components.ex
|
||||||
|
#: lib/music_library_web/live/stats_live/top_albums.ex
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "W"
|
msgid "W"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
Reference in New Issue
Block a user