From f3425d8cb97f55f106fd44c9727113672fb85fdf Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Thu, 19 Jun 2025 17:17:51 +0300 Subject: [PATCH] Add top artist and top albums of all time Executed by Claude --- .claude/settings.local.json | 3 +- lib/music_library/scrobble_activity.ex | 65 +++++++++++++++++-- .../live/stats_live/index.html.heex | 11 +++- priv/gettext/default.pot | 5 ++ priv/gettext/en/LC_MESSAGES/default.po | 5 ++ 5 files changed, 81 insertions(+), 8 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 810c7f23..3186d07c 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -2,7 +2,8 @@ "permissions": { "allow": [ "mcp__tidewave__get_ecto_schemas", - "Bash(mix test:*)" + "Bash(mix test:*)", + "mcp__tidewave__get_source_location" ] }, "enableAllProjectMcpServers": false diff --git a/lib/music_library/scrobble_activity.ex b/lib/music_library/scrobble_activity.ex index 541d7d08..2d683a71 100644 --- a/lib/music_library/scrobble_activity.ex +++ b/lib/music_library/scrobble_activity.ex @@ -240,6 +240,57 @@ defmodule MusicLibrary.ScrobbleActivity do Repo.all(query) end + @doc """ + Gets the top albums by scrobble count across all time. + Returns a list of maps with album information and play counts. + """ + def get_top_albums(opts) do + limit = Keyword.get(opts, :limit, 10) + + query = + from t in Track, + group_by: [ + fragment("json_extract(album, '$.title')"), + fragment("json_extract(artist, '$.name')") + ], + select: %{ + album_title: fragment("json_extract(album, '$.title')"), + artist_name: fragment("json_extract(artist, '$.name')"), + artist_musicbrainz_id: fragment("json_extract(artist, '$.musicbrainz_id')"), + play_count: count(t.scrobbled_at_uts), + cover_url: fragment("max(?)", t.cover_url), + album_musicbrainz_id: fragment("json_extract(album, '$.musicbrainz_id')") + }, + order_by: [desc: count(t.scrobbled_at_uts)], + limit: ^limit + + Repo.all(query) + end + + @doc """ + Gets the top artists by scrobble count across all time. + Returns a list of maps with artist information and play counts. + """ + def get_top_artists(opts) do + limit = Keyword.get(opts, :limit, 10) + + query = + from t in Track, + group_by: [ + fragment("json_extract(artist, '$.name')"), + fragment("json_extract(artist, '$.musicbrainz_id')") + ], + select: %{ + artist_name: fragment("json_extract(artist, '$.name')"), + artist_musicbrainz_id: fragment("json_extract(artist, '$.musicbrainz_id')"), + play_count: count(t.scrobbled_at_uts) + }, + order_by: [desc: count(t.scrobbled_at_uts)], + limit: ^limit + + Repo.all(query) + end + @doc """ Gets the top artists by scrobble count for the given number of days. Returns a list of maps with artist information and play counts. @@ -275,7 +326,7 @@ defmodule MusicLibrary.ScrobbleActivity do end @doc """ - Gets top albums for multiple time periods (30, 90, 365 days). + Gets top albums for multiple time periods (30, 90, 365 days) and all time. Returns a map with the results for each period, along with collected and wishlisted releases. """ @@ -283,9 +334,10 @@ defmodule MusicLibrary.ScrobbleActivity do last_30_days = get_top_albums_by_days(30, opts) last_90_days = get_top_albums_by_days(90, opts) last_365_days = get_top_albums_by_days(365, opts) + all_time = get_top_albums(opts) all_album_ids = - (last_30_days ++ last_90_days ++ last_365_days) + (last_30_days ++ last_90_days ++ last_365_days ++ all_time) |> Enum.map(fn t -> t.album_musicbrainz_id end) |> Enum.uniq() |> Enum.reject(fn musicbrainz_id -> musicbrainz_id == "" end) @@ -298,23 +350,26 @@ defmodule MusicLibrary.ScrobbleActivity do wishlisted_releases: wishlisted_releases, last_30_days: last_30_days, last_90_days: last_90_days, - last_365_days: last_365_days + last_365_days: last_365_days, + all_time: all_time } end @doc """ - Gets top artists for multiple time periods (30, 90, 365 days). + Gets top artists for multiple time periods (30, 90, 365 days) and all time. Returns a map with the results for each period. """ def get_top_artists_by_periods(opts) do last_30_days = get_top_artists_by_days(30, opts) last_90_days = get_top_artists_by_days(90, opts) last_365_days = get_top_artists_by_days(365, opts) + all_time = get_top_artists(opts) %{ last_30_days: last_30_days, last_90_days: last_90_days, - last_365_days: last_365_days + last_365_days: last_365_days, + all_time: all_time } end diff --git a/lib/music_library_web/live/stats_live/index.html.heex b/lib/music_library_web/live/stats_live/index.html.heex index 5ed9a11e..304fc24f 100644 --- a/lib/music_library_web/live/stats_live/index.html.heex +++ b/lib/music_library_web/live/stats_live/index.html.heex @@ -76,7 +76,7 @@ <.refresh_lastfm_feed_button /> -
+
<.top_albums_by_period albums={@top_albums.last_30_days} title={gettext("Last 30 days")} @@ -95,6 +95,12 @@ collected_releases={@top_albums.collected_releases} wishlisted_releases={@top_albums.wishlisted_releases} /> + <.top_albums_by_period + albums={@top_albums.all_time} + title={gettext("All time")} + collected_releases={@top_albums.collected_releases} + wishlisted_releases={@top_albums.wishlisted_releases} + />
@@ -106,10 +112,11 @@ <.refresh_lastfm_feed_button /> -
+
<.top_artists_by_period artists={@top_artists.last_30_days} title={gettext("Last 30 days")} /> <.top_artists_by_period artists={@top_artists.last_90_days} title={gettext("Last 90 days")} /> <.top_artists_by_period artists={@top_artists.last_365_days} title={gettext("Last year")} /> + <.top_artists_by_period artists={@top_artists.all_time} title={gettext("All time")} />
diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index 1792804a..f21b1005 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -913,3 +913,8 @@ msgstr "" #, elixir-autogen, elixir-format msgid "Top Artists" msgstr "" + +#: lib/music_library_web/live/stats_live/index.html.heex +#, elixir-autogen, elixir-format +msgid "All time" +msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index b9d815e0..3c085430 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -913,3 +913,8 @@ msgstr "" #, elixir-autogen, elixir-format, fuzzy msgid "Top Artists" msgstr "" + +#: lib/music_library_web/live/stats_live/index.html.heex +#, elixir-autogen, elixir-format +msgid "All time" +msgstr ""