Can scrobble individual discs

This commit is contained in:
Claudio Ortolina
2025-05-10 09:46:07 +01:00
parent 919af2db63
commit b831a2e1d7
4 changed files with 118 additions and 24 deletions
+63 -18
View File
@@ -35,28 +35,73 @@ defmodule MusicLibrary.ScrobbleActivity do
{scrobbles, _finished_at} =
release_with_tracks
|> MusicBrainz.Release.tracks()
|> Enum.map_reduce(started_at, fn track, time ->
album_artist =
if release_with_tracks.artists !== track.artists do
main_artist_name(release_with_tracks.artists)
end
time = time |> DateTime.add(track.length, :millisecond)
scrobble = %Scrobble{
artist: main_artist_name(track.artists),
album: release_with_tracks.title,
album_artist: album_artist,
track: track.title,
timestamp: DateTime.to_unix(time)
}
{scrobble, time}
end)
|> to_scrobbles(release_with_tracks, started_at)
LastFm.scrobble(scrobbles, session_key)
end
def scrobble_medium(number, release_with_tracks, opts) when is_list(opts) do
case Enum.sort(opts) do
[finished_at: _, started_at: _] ->
raise ArgumentError, """
Cannot scobble a medium with both started_at and finished_at.
Remove either of them.
"""
[started_at: started_at] ->
scrobble_medium(number, release_with_tracks, {:started_at, started_at})
[finished_at: finished_at] ->
scrobble_medium(number, release_with_tracks, {:finished_at, finished_at})
end
end
def scrobble_medium(number, release_with_tracks, {:finished_at, finished_at}) do
medium_duration =
release_with_tracks.media
|> Enum.find(fn medium -> medium.number == number end)
|> Release.medium_duration()
started_at = DateTime.add(finished_at, -medium_duration, :millisecond)
scrobble_medium(number, release_with_tracks, {:started_at, started_at})
end
def scrobble_medium(number, release_with_tracks, {:started_at, started_at}) do
session_key = Secrets.get!("last_fm_session_key").value
medium =
release_with_tracks.media
|> Enum.find(fn medium -> medium.number == number end)
{scrobbles, _finished_at} =
medium.tracks
|> to_scrobbles(release_with_tracks, started_at)
LastFm.scrobble(scrobbles, session_key)
end
defp to_scrobbles(tracks, release_with_tracks, started_at) do
tracks
|> Enum.map_reduce(started_at, fn track, time ->
album_artist =
if release_with_tracks.artists !== track.artists do
main_artist_name(release_with_tracks.artists)
end
time = time |> DateTime.add(track.length, :millisecond)
scrobble = %Scrobble{
artist: main_artist_name(track.artists),
album: release_with_tracks.title,
album_artist: album_artist,
track: track.title,
timestamp: DateTime.to_unix(time)
}
{scrobble, time}
end)
end
defp main_artist_name([]), do: nil
defp main_artist_name([artist | _rest]), do: artist.name
@@ -66,12 +66,24 @@ defmodule MusicLibraryWeb.ReleaseComponent do
</div>
</:failed>
<div :for={medium <- release_with_tracks.media} class="space-y-4">
<h4
:if={MusicBrainz.Release.media_count(release_with_tracks) > 1}
class="text-sm font-semibold text-zinc-700 dark:text-zinc-300"
>
{medium_title(medium)}
</h4>
<div class="flex justify-between items-center gap-4">
<h4
:if={MusicBrainz.Release.media_count(release_with_tracks) > 1}
class="text-sm font-semibold text-zinc-700 dark:text-zinc-300"
>
{medium_title(medium)}
</h4>
<Fluxon.Components.Button.button
:if={@can_scrobble?}
size="xs"
phx-click="scrobble_medium"
phx-value-number={medium.number}
phx-target={@myself}
phx-disable-with={gettext("Scrobbling...")}
>
{gettext("Scrobble disc")}
</Fluxon.Components.Button.button>
</div>
<ul id={"disc-#{medium.number}"} class="w-full table table-auto">
<li
:for={track <- medium.tracks}
@@ -140,6 +152,33 @@ defmodule MusicLibraryWeb.ReleaseComponent do
end
end
def handle_event("scrobble_medium", %{"number" => number}, socket) do
release_with_tracks_async_result =
socket.assigns.release_with_tracks
number = String.to_integer(number)
if release_with_tracks =
release_with_tracks_async_result && release_with_tracks_async_result.result do
case ScrobbleActivity.scrobble_medium(number, release_with_tracks,
finished_at: DateTime.utc_now()
) do
{:ok, _} ->
{:noreply,
socket
|> put_flash(:info, gettext("Disc scrobbled successfully"))}
{:error, reason} ->
{:noreply,
socket
|> put_flash(
:error,
gettext("Error scrobbling disc") <> "," <> inspect(reason)
)}
end
end
end
defp medium_duration(medium) do
medium
|> MusicBrainz.Release.medium_duration()
+5
View File
@@ -819,3 +819,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Error scrobbling disc"
msgstr ""
#: lib/music_library_web/components/release_component.ex
#, elixir-autogen, elixir-format
msgid "Scrobble disc"
msgstr ""
+5
View File
@@ -819,3 +819,8 @@ msgstr ""
#, elixir-autogen, elixir-format, fuzzy
msgid "Error scrobbling disc"
msgstr ""
#: lib/music_library_web/components/release_component.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Scrobble disc"
msgstr ""