Files
music_library/lib/music_library_web/live/scrobble_live/show.ex
T
2025-09-24 08:55:42 +03:00

146 lines
4.3 KiB
Elixir

defmodule MusicLibraryWeb.ScrobbleLive.Show do
use MusicLibraryWeb, :live_view
alias MusicLibrary.ScrobbleActivity
@impl true
def mount(%{"release_id" => release_id}, _session, socket) do
{:ok,
assign(socket,
current_section: :scrobble,
release_id: release_id,
release: nil,
loading: true,
can_scrobble: ScrobbleActivity.can_scrobble?(),
scrobble_form: %{
"type" => "finished_at",
"finished_at_date" => Date.utc_today() |> Date.to_string(),
"finished_at_time" => Time.utc_now() |> Time.truncate(:second) |> Time.to_string(),
"started_at_date" => Date.utc_today() |> Date.to_string(),
"started_at_time" => Time.utc_now() |> Time.truncate(:second) |> Time.to_string()
},
page_title: "Scrobble Release"
)}
end
@impl true
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
defp apply_action(socket, :show, _params) do
send(self(), :fetch_release)
socket
end
@impl true
def handle_event("update_scrobble_form", %{"scrobble" => scrobble_params}, socket) do
{:noreply, assign(socket, scrobble_form: scrobble_params)}
end
def handle_event("scrobble_release", _params, socket) do
case perform_scrobble(socket.assigns.release, :all, socket.assigns.scrobble_form) do
{:ok, _result} ->
{:noreply,
socket
|> put_flash(:info, "Release scrobbled successfully!")
|> push_navigate(to: ~p"/scrobble")}
{:error, reason} ->
{:noreply, put_flash(socket, :error, "Failed to scrobble release: #{inspect(reason)}")}
end
end
def handle_event("scrobble_medium", %{"medium_number" => medium_number_str}, socket) do
{medium_number, ""} = Integer.parse(medium_number_str)
case perform_scrobble(
socket.assigns.release,
{:medium, medium_number},
socket.assigns.scrobble_form
) do
{:ok, _result} ->
{:noreply,
socket
|> put_flash(:info, "Medium scrobbled successfully!")
|> push_navigate(to: ~p"/scrobble")}
{:error, reason} ->
{:noreply, put_flash(socket, :error, "Failed to scrobble medium: #{inspect(reason)}")}
end
end
@impl true
def handle_info(:fetch_release, socket) do
case MusicBrainz.get_release(socket.assigns.release_id) do
{:ok, release} ->
release = MusicBrainz.Release.from_api_response(release)
{:noreply,
assign(socket,
release: release,
loading: false,
page_title: "Scrobble: #{release.title}"
)}
{:error, _reason} ->
{:noreply,
socket
|> put_flash(:error, "Failed to fetch release details")
|> push_navigate(to: ~p"/scrobble")}
end
end
defp perform_scrobble(release, scope, scrobble_form) do
datetime_opts = build_datetime_opts(scrobble_form)
case scope do
:all ->
ScrobbleActivity.scrobble_release(release, datetime_opts)
{:medium, medium_number} ->
ScrobbleActivity.scrobble_medium(medium_number, release, datetime_opts)
end
end
defp build_datetime_opts(%{
"type" => "finished_at",
"finished_at_date" => date,
"finished_at_time" => time
}) do
with {:ok, date} <- Date.from_iso8601(date),
{:ok, time} <- Time.from_iso8601(time),
datetime <- DateTime.new!(date, time, "Etc/UTC") do
[finished_at: datetime]
else
_ -> [finished_at: DateTime.utc_now()]
end
end
defp build_datetime_opts(%{
"type" => "started_at",
"started_at_date" => date,
"started_at_time" => time
}) do
with {:ok, date} <- Date.from_iso8601(date),
{:ok, time} <- Time.from_iso8601(time),
datetime <- DateTime.new!(date, time, "Etc/UTC") do
[started_at: datetime]
else
_ -> [started_at: DateTime.utc_now()]
end
end
defp build_datetime_opts(_), do: [finished_at: DateTime.utc_now()]
defp format_duration(nil), do: "Unknown"
defp format_duration(milliseconds) when is_integer(milliseconds) do
seconds = div(milliseconds, 1000)
minutes = div(seconds, 60)
remaining_seconds = rem(seconds, 60)
"#{minutes}:#{String.pad_leading(Integer.to_string(remaining_seconds), 2, "0")}"
end
end