@@ -1,111 +1,27 @@
|
|||||||
defmodule MusicLibraryWeb.StatsLive.TopAlbums do
|
defmodule MusicLibraryWeb.StatsLive.TopAlbums do
|
||||||
use MusicLibraryWeb, :live_component
|
use MusicLibraryWeb, :html
|
||||||
|
|
||||||
alias MusicLibrary.Assets.Transform
|
alias MusicLibrary.Assets.Transform
|
||||||
alias MusicLibrary.ListeningStats
|
alias MusicLibrary.ListeningStats
|
||||||
|
alias MusicLibraryWeb.StatsLive.TopByPeriod
|
||||||
|
|
||||||
|
attr :id, :string, required: true
|
||||||
|
attr :timezone, :string, required: true
|
||||||
|
attr :last_updated_uts, :any
|
||||||
|
|
||||||
def live(assigns) do
|
def live(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<.live_component module={__MODULE__} {assigns} id={@id} />
|
<TopByPeriod.live
|
||||||
"""
|
id={@id}
|
||||||
end
|
timezone={@timezone}
|
||||||
|
last_updated_uts={@last_updated_uts}
|
||||||
@impl true
|
title={gettext("Top Albums")}
|
||||||
def render(assigns) do
|
key={:top_albums}
|
||||||
~H"""
|
fetch_fn={&ListeningStats.get_top_albums_by_period/1}
|
||||||
<div>
|
>
|
||||||
<h1 class="text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
|
<:item :let={albums}>
|
||||||
{gettext("Top Albums")}
|
|
||||||
</h1>
|
|
||||||
<.tabs class="mt-4">
|
|
||||||
<.tabs_list active_tab={name_from_period(@period)} variant="segmented" size="xs">
|
|
||||||
<:tab
|
|
||||||
class="flex-1"
|
|
||||||
name="top_albums_last_7_days"
|
|
||||||
phx-click={JS.push("set_period", value: %{period: "last_7_days"})}
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
{gettext("7d")}
|
|
||||||
</:tab>
|
|
||||||
<:tab
|
|
||||||
class="flex-1"
|
|
||||||
name="top_albums_last_30_days"
|
|
||||||
phx-click={JS.push("set_period", value: %{period: "last_30_days"})}
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
{gettext("30d")}
|
|
||||||
</:tab>
|
|
||||||
<:tab
|
|
||||||
class="flex-1"
|
|
||||||
name="top_albums_last_90_days"
|
|
||||||
phx-click={JS.push("set_period", value: %{period: "last_90_days"})}
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
{gettext("90d")}
|
|
||||||
</:tab>
|
|
||||||
<:tab
|
|
||||||
class="flex-1"
|
|
||||||
name="top_albums_last_365_days"
|
|
||||||
phx-click={JS.push("set_period", value: %{period: "last_365_days"})}
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
{gettext("1y")}
|
|
||||||
</:tab>
|
|
||||||
<:tab
|
|
||||||
class="flex-1"
|
|
||||||
name="top_albums_all_time"
|
|
||||||
phx-click={JS.push("set_period", value: %{period: "all_time"})}
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
{gettext("All time")}
|
|
||||||
</:tab>
|
|
||||||
</.tabs_list>
|
|
||||||
<.async_result :let={top_albums} assign={@top_albums}>
|
|
||||||
<:loading>
|
|
||||||
<div class="h-182 flex items-center justify-center">
|
|
||||||
<.loading />
|
|
||||||
</div>
|
|
||||||
</:loading>
|
|
||||||
<.top_albums_by_period albums={top_albums} />
|
|
||||||
</.async_result>
|
|
||||||
</.tabs>
|
|
||||||
</div>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
defp name_from_period(period), do: "top_albums_#{period}"
|
|
||||||
|
|
||||||
@impl true
|
|
||||||
def mount(socket) do
|
|
||||||
{:ok,
|
|
||||||
socket
|
|
||||||
|> assign(:period, :last_7_days)}
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
|
||||||
def update(assigns, socket) do
|
|
||||||
{:ok,
|
|
||||||
socket
|
|
||||||
|> assign(assigns)
|
|
||||||
|> assign_top_albums()}
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
|
||||||
def handle_event("set_period", %{"period" => period}, socket) do
|
|
||||||
{:noreply,
|
|
||||||
socket
|
|
||||||
|> assign(:period, String.to_existing_atom(period))
|
|
||||||
|> assign_top_albums()}
|
|
||||||
end
|
|
||||||
|
|
||||||
attr :albums, :list, required: true
|
|
||||||
|
|
||||||
defp top_albums_by_period(assigns) do
|
|
||||||
~H"""
|
|
||||||
<div class="mt-4 p-4 bg-white dark:bg-zinc-800 rounded-md shadow-sm">
|
|
||||||
<div class="space-y-2">
|
|
||||||
<div
|
<div
|
||||||
:for={album <- @albums}
|
:for={album <- albums}
|
||||||
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",
|
||||||
@@ -151,33 +67,11 @@ defmodule MusicLibraryWeb.StatsLive.TopAlbums do
|
|||||||
{album.play_count}
|
{album.play_count}
|
||||||
</.badge>
|
</.badge>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</:item>
|
||||||
</div>
|
</TopByPeriod.live>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp assign_top_albums(socket) do
|
|
||||||
%{timezone: timezone, period: period} = socket.assigns
|
|
||||||
current_time = DateTime.utc_now()
|
|
||||||
|
|
||||||
assign_async(
|
|
||||||
socket,
|
|
||||||
:top_albums,
|
|
||||||
fn ->
|
|
||||||
top_albums =
|
|
||||||
ListeningStats.get_top_albums_by_period(
|
|
||||||
limit: 10,
|
|
||||||
current_time: current_time,
|
|
||||||
timezone: timezone,
|
|
||||||
period: period
|
|
||||||
)
|
|
||||||
|
|
||||||
{:ok, %{top_albums: top_albums}}
|
|
||||||
end,
|
|
||||||
reset: true
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp navigate_to_record(album) do
|
defp navigate_to_record(album) do
|
||||||
cond do
|
cond do
|
||||||
album.collected_record_id ->
|
album.collected_record_id ->
|
||||||
|
|||||||
@@ -1,112 +1,28 @@
|
|||||||
defmodule MusicLibraryWeb.StatsLive.TopArtists do
|
defmodule MusicLibraryWeb.StatsLive.TopArtists do
|
||||||
use MusicLibraryWeb, :live_component
|
use MusicLibraryWeb, :html
|
||||||
|
|
||||||
import MusicLibraryWeb.RecordComponents, only: [artist_image: 1]
|
import MusicLibraryWeb.RecordComponents, only: [artist_image: 1]
|
||||||
|
|
||||||
alias MusicLibrary.ListeningStats
|
alias MusicLibrary.ListeningStats
|
||||||
|
alias MusicLibraryWeb.StatsLive.TopByPeriod
|
||||||
|
|
||||||
|
attr :id, :string, required: true
|
||||||
|
attr :timezone, :string, required: true
|
||||||
|
attr :last_updated_uts, :any
|
||||||
|
|
||||||
def live(assigns) do
|
def live(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<.live_component module={__MODULE__} {assigns} id={@id} />
|
<TopByPeriod.live
|
||||||
"""
|
id={@id}
|
||||||
end
|
timezone={@timezone}
|
||||||
|
last_updated_uts={@last_updated_uts}
|
||||||
@impl true
|
title={gettext("Top Artists")}
|
||||||
def render(assigns) do
|
key={:top_artists}
|
||||||
~H"""
|
fetch_fn={&ListeningStats.get_top_artists_by_period/1}
|
||||||
<div>
|
>
|
||||||
<h1 class="text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
|
<:item :let={artists}>
|
||||||
{gettext("Top Artists")}
|
|
||||||
</h1>
|
|
||||||
<.tabs class="mt-4">
|
|
||||||
<.tabs_list active_tab={name_from_period(@period)} variant="segmented" size="xs">
|
|
||||||
<:tab
|
|
||||||
class="flex-1"
|
|
||||||
name="top_artists_last_7_days"
|
|
||||||
phx-click={JS.push("set_period", value: %{period: "last_7_days"})}
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
{gettext("7d")}
|
|
||||||
</:tab>
|
|
||||||
<:tab
|
|
||||||
class="flex-1"
|
|
||||||
name="top_artists_last_30_days"
|
|
||||||
phx-click={JS.push("set_period", value: %{period: "last_30_days"})}
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
{gettext("30d")}
|
|
||||||
</:tab>
|
|
||||||
<:tab
|
|
||||||
class="flex-1"
|
|
||||||
name="top_artists_last_90_days"
|
|
||||||
phx-click={JS.push("set_period", value: %{period: "last_90_days"})}
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
{gettext("90d")}
|
|
||||||
</:tab>
|
|
||||||
<:tab
|
|
||||||
class="flex-1"
|
|
||||||
name="top_artists_last_365_days"
|
|
||||||
phx-click={JS.push("set_period", value: %{period: "last_365_days"})}
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
{gettext("1y")}
|
|
||||||
</:tab>
|
|
||||||
<:tab
|
|
||||||
class="flex-1"
|
|
||||||
name="top_artists_all_time"
|
|
||||||
phx-click={JS.push("set_period", value: %{period: "all_time"})}
|
|
||||||
phx-target={@myself}
|
|
||||||
>
|
|
||||||
{gettext("All time")}
|
|
||||||
</:tab>
|
|
||||||
</.tabs_list>
|
|
||||||
<.async_result :let={top_artists} assign={@top_artists}>
|
|
||||||
<:loading>
|
|
||||||
<div class="h-182 flex items-center justify-center">
|
|
||||||
<.loading />
|
|
||||||
</div>
|
|
||||||
</:loading>
|
|
||||||
<.top_artists_by_period artists={top_artists} />
|
|
||||||
</.async_result>
|
|
||||||
</.tabs>
|
|
||||||
</div>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
defp name_from_period(period), do: "top_artists_#{period}"
|
|
||||||
|
|
||||||
@impl true
|
|
||||||
def mount(socket) do
|
|
||||||
{:ok,
|
|
||||||
socket
|
|
||||||
|> assign(:period, :last_7_days)}
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
|
||||||
def update(assigns, socket) do
|
|
||||||
{:ok,
|
|
||||||
socket
|
|
||||||
|> assign(assigns)
|
|
||||||
|> assign_top_artists()}
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
|
||||||
def handle_event("set_period", %{"period" => period}, socket) do
|
|
||||||
{:noreply,
|
|
||||||
socket
|
|
||||||
|> assign(:period, String.to_existing_atom(period))
|
|
||||||
|> assign_top_artists()}
|
|
||||||
end
|
|
||||||
|
|
||||||
attr :artists, :list, required: true
|
|
||||||
|
|
||||||
def top_artists_by_period(assigns) do
|
|
||||||
~H"""
|
|
||||||
<div class="mt-4 p-4 bg-white dark:bg-zinc-800 rounded-md shadow-sm">
|
|
||||||
<div class="space-y-2">
|
|
||||||
<div
|
<div
|
||||||
:for={artist <- @artists}
|
:for={artist <- artists}
|
||||||
phx-click={
|
phx-click={
|
||||||
artist.musicbrainz_id != "" &&
|
artist.musicbrainz_id != "" &&
|
||||||
JS.navigate(~p"/artists/#{artist.musicbrainz_id}")
|
JS.navigate(~p"/artists/#{artist.musicbrainz_id}")
|
||||||
@@ -139,30 +55,8 @@ defmodule MusicLibraryWeb.StatsLive.TopArtists do
|
|||||||
{artist.play_count}
|
{artist.play_count}
|
||||||
</.badge>
|
</.badge>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</:item>
|
||||||
</div>
|
</TopByPeriod.live>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp assign_top_artists(socket) do
|
|
||||||
%{timezone: timezone, period: period} = socket.assigns
|
|
||||||
current_time = DateTime.utc_now()
|
|
||||||
|
|
||||||
assign_async(
|
|
||||||
socket,
|
|
||||||
:top_artists,
|
|
||||||
fn ->
|
|
||||||
top_artists =
|
|
||||||
ListeningStats.get_top_artists_by_period(
|
|
||||||
limit: 10,
|
|
||||||
current_time: current_time,
|
|
||||||
timezone: timezone,
|
|
||||||
period: period
|
|
||||||
)
|
|
||||||
|
|
||||||
{:ok, %{top_artists: top_artists}}
|
|
||||||
end,
|
|
||||||
reset: true
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
defmodule MusicLibraryWeb.StatsLive.TopByPeriod do
|
||||||
|
use MusicLibraryWeb, :live_component
|
||||||
|
|
||||||
|
attr :id, :string, required: true
|
||||||
|
attr :title, :string, required: true
|
||||||
|
attr :key, :atom, required: true
|
||||||
|
attr :fetch_fn, :any, required: true
|
||||||
|
attr :timezone, :string, required: true
|
||||||
|
attr :last_updated_uts, :any
|
||||||
|
|
||||||
|
slot :item, required: true
|
||||||
|
|
||||||
|
def live(assigns) do
|
||||||
|
~H"""
|
||||||
|
<.live_component module={__MODULE__} {assigns} id={@id} />
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def render(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div>
|
||||||
|
<h1 class="text-base lg:text-2xl text-zinc-900 dark:text-zinc-200 font-semibold">
|
||||||
|
{@title}
|
||||||
|
</h1>
|
||||||
|
<.tabs class="mt-4">
|
||||||
|
<.tabs_list active_tab={name_from_period(@key, @period)} variant="segmented" size="xs">
|
||||||
|
<:tab
|
||||||
|
class="flex-1"
|
||||||
|
name={"#{@key}_last_7_days"}
|
||||||
|
phx-click={JS.push("set_period", value: %{period: "last_7_days"})}
|
||||||
|
phx-target={@myself}
|
||||||
|
>
|
||||||
|
{gettext("7d")}
|
||||||
|
</:tab>
|
||||||
|
<:tab
|
||||||
|
class="flex-1"
|
||||||
|
name={"#{@key}_last_30_days"}
|
||||||
|
phx-click={JS.push("set_period", value: %{period: "last_30_days"})}
|
||||||
|
phx-target={@myself}
|
||||||
|
>
|
||||||
|
{gettext("30d")}
|
||||||
|
</:tab>
|
||||||
|
<:tab
|
||||||
|
class="flex-1"
|
||||||
|
name={"#{@key}_last_90_days"}
|
||||||
|
phx-click={JS.push("set_period", value: %{period: "last_90_days"})}
|
||||||
|
phx-target={@myself}
|
||||||
|
>
|
||||||
|
{gettext("90d")}
|
||||||
|
</:tab>
|
||||||
|
<:tab
|
||||||
|
class="flex-1"
|
||||||
|
name={"#{@key}_last_365_days"}
|
||||||
|
phx-click={JS.push("set_period", value: %{period: "last_365_days"})}
|
||||||
|
phx-target={@myself}
|
||||||
|
>
|
||||||
|
{gettext("1y")}
|
||||||
|
</:tab>
|
||||||
|
<:tab
|
||||||
|
class="flex-1"
|
||||||
|
name={"#{@key}_all_time"}
|
||||||
|
phx-click={JS.push("set_period", value: %{period: "all_time"})}
|
||||||
|
phx-target={@myself}
|
||||||
|
>
|
||||||
|
{gettext("All time")}
|
||||||
|
</:tab>
|
||||||
|
</.tabs_list>
|
||||||
|
<.async_result :let={items} assign={assigns[@key]}>
|
||||||
|
<:loading>
|
||||||
|
<div class="h-182 flex items-center justify-center">
|
||||||
|
<.loading />
|
||||||
|
</div>
|
||||||
|
</:loading>
|
||||||
|
<div class="mt-4 p-4 bg-white dark:bg-zinc-800 rounded-md shadow-sm">
|
||||||
|
<div class="space-y-2">
|
||||||
|
{render_slot(@item, items)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</.async_result>
|
||||||
|
</.tabs>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp name_from_period(key, period), do: "#{key}_#{period}"
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def mount(socket) do
|
||||||
|
{:ok, assign(socket, :period, :last_7_days)}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def update(assigns, socket) do
|
||||||
|
{:ok,
|
||||||
|
socket
|
||||||
|
|> assign(assigns)
|
||||||
|
|> assign_data()}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_event("set_period", %{"period" => period}, socket) do
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> assign(:period, String.to_existing_atom(period))
|
||||||
|
|> assign_data()}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp assign_data(socket) do
|
||||||
|
%{timezone: timezone, period: period, key: key, fetch_fn: fetch_fn} = socket.assigns
|
||||||
|
current_time = DateTime.utc_now()
|
||||||
|
|
||||||
|
assign_async(
|
||||||
|
socket,
|
||||||
|
key,
|
||||||
|
fn ->
|
||||||
|
items =
|
||||||
|
fetch_fn.(
|
||||||
|
limit: 10,
|
||||||
|
current_time: current_time,
|
||||||
|
timezone: timezone,
|
||||||
|
period: period
|
||||||
|
)
|
||||||
|
|
||||||
|
{:ok, %{key => items}}
|
||||||
|
end,
|
||||||
|
reset: true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -851,8 +851,7 @@ msgstr ""
|
|||||||
msgid "Top Artists"
|
msgid "Top Artists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/live/stats_live/top_albums.ex
|
#: lib/music_library_web/live/stats_live/top_by_period.ex
|
||||||
#: lib/music_library_web/live/stats_live/top_artists.ex
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "All time"
|
msgid "All time"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1304,26 +1303,22 @@ msgstr ""
|
|||||||
msgid "Read"
|
msgid "Read"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/live/stats_live/top_albums.ex
|
#: lib/music_library_web/live/stats_live/top_by_period.ex
|
||||||
#: lib/music_library_web/live/stats_live/top_artists.ex
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "1y"
|
msgid "1y"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/live/stats_live/top_albums.ex
|
#: lib/music_library_web/live/stats_live/top_by_period.ex
|
||||||
#: lib/music_library_web/live/stats_live/top_artists.ex
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "30d"
|
msgid "30d"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/live/stats_live/top_albums.ex
|
#: lib/music_library_web/live/stats_live/top_by_period.ex
|
||||||
#: lib/music_library_web/live/stats_live/top_artists.ex
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "7d"
|
msgid "7d"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/live/stats_live/top_albums.ex
|
#: lib/music_library_web/live/stats_live/top_by_period.ex
|
||||||
#: lib/music_library_web/live/stats_live/top_artists.ex
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "90d"
|
msgid "90d"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -851,8 +851,7 @@ msgstr ""
|
|||||||
msgid "Top Artists"
|
msgid "Top Artists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/live/stats_live/top_albums.ex
|
#: lib/music_library_web/live/stats_live/top_by_period.ex
|
||||||
#: lib/music_library_web/live/stats_live/top_artists.ex
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "All time"
|
msgid "All time"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1304,26 +1303,22 @@ msgstr ""
|
|||||||
msgid "Read"
|
msgid "Read"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/live/stats_live/top_albums.ex
|
#: lib/music_library_web/live/stats_live/top_by_period.ex
|
||||||
#: lib/music_library_web/live/stats_live/top_artists.ex
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "1y"
|
msgid "1y"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/live/stats_live/top_albums.ex
|
#: lib/music_library_web/live/stats_live/top_by_period.ex
|
||||||
#: lib/music_library_web/live/stats_live/top_artists.ex
|
|
||||||
#, elixir-autogen, elixir-format, fuzzy
|
#, elixir-autogen, elixir-format, fuzzy
|
||||||
msgid "30d"
|
msgid "30d"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/live/stats_live/top_albums.ex
|
#: lib/music_library_web/live/stats_live/top_by_period.ex
|
||||||
#: lib/music_library_web/live/stats_live/top_artists.ex
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "7d"
|
msgid "7d"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: lib/music_library_web/live/stats_live/top_albums.ex
|
#: lib/music_library_web/live/stats_live/top_by_period.ex
|
||||||
#: lib/music_library_web/live/stats_live/top_artists.ex
|
|
||||||
#, elixir-autogen, elixir-format, fuzzy
|
#, elixir-autogen, elixir-format, fuzzy
|
||||||
msgid "90d"
|
msgid "90d"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
Reference in New Issue
Block a user