Extract Artists context

This commit is contained in:
Claudio Ortolina
2024-12-18 11:12:06 +00:00
parent 76605a1114
commit 53b89dc329
7 changed files with 88 additions and 75 deletions
+1
View File
@@ -2,6 +2,7 @@ defmodule MusicLibrary do
@moduledoc """ @moduledoc """
Important contexts: Important contexts:
- `MusicLibrary.Artists` contains functions to access artists
- `MusicLibrary.Records` contains functions to access and manipulate records _irrespectively_ of being in the collection or wishlist - `MusicLibrary.Records` contains functions to access and manipulate records _irrespectively_ of being in the collection or wishlist
- `MusicLibrary.Collection` contains functions to access and manipulate records in the collection - `MusicLibrary.Collection` contains functions to access and manipulate records in the collection
- `MusicLibrary.Wishlist` contains functions to access and manipulate records in the wishlist - `MusicLibrary.Wishlist` contains functions to access and manipulate records in the wishlist
+64
View File
@@ -0,0 +1,64 @@
defmodule MusicLibrary.Artists do
import Ecto.Query, warn: false
alias MusicLibrary.Repo
alias MusicLibrary.Records.ArtistRecord
def get_artist!(musicbrainz_id) do
q =
from ar in ArtistRecord,
where: ar.musicbrainz_id == ^musicbrainz_id,
limit: 1,
select: ar.artist
Repo.one!(q)
end
def get_all_artist_ids do
q = from ar in ArtistRecord, distinct: true, select: ar.musicbrainz_id
q |> Repo.all() |> MapSet.new()
end
def get_artist_info(artist) do
last_fm_config = last_fm_config()
# Sometimes the artist info cannot be identified with the MusicBrainz ID,
# because Last.fm doesn't have that information. In that case, we try again with the artist name.
case last_fm_config.api.get_artist_info(
{:musicbrainz_id, artist.musicbrainz_id},
last_fm_config
) do
{:ok, info} ->
{:ok, info}
# TODO: remap error codes
{:error, %{"error" => 6}} ->
last_fm_config.api.get_artist_info({:name, artist.name}, last_fm_config)
error ->
error
end
end
def get_similar_artists(artist) do
last_fm_config = last_fm_config()
# Sometimes the artist info cannot be identified with the MusicBrainz ID,
# because Last.fm doesn't have that information. In that case, we try again with the artist name.
case last_fm_config.api.get_similar_artists(
{:musicbrainz_id, artist.musicbrainz_id},
last_fm_config
) do
{:ok, info} ->
{:ok, info}
# TODO: remap error codes
{:error, %{"error" => 6}} ->
last_fm_config.api.get_similar_artists({:name, artist.name}, last_fm_config)
error ->
error
end
end
defp last_fm_config, do: LastFm.Config.resolve(:music_library)
end
-58
View File
@@ -90,22 +90,6 @@ defmodule MusicLibrary.Records do
def get_record!(id), do: Repo.get!(Record, id) def get_record!(id), do: Repo.get!(Record, id)
def get_artist!(musicbrainz_id) do
q =
from ar in ArtistRecord,
where: ar.musicbrainz_id == ^musicbrainz_id,
limit: 1,
select: ar.artist
Repo.one!(q)
end
def get_all_artist_ids do
q = from ar in ArtistRecord, distinct: true, select: ar.musicbrainz_id
q |> Repo.all() |> MapSet.new()
end
def get_artist_records(musicbrainz_id) do def get_artist_records(musicbrainz_id) do
q = q =
from r in Record, from r in Record,
@@ -116,46 +100,6 @@ defmodule MusicLibrary.Records do
Repo.all(q) Repo.all(q)
end end
def get_artist_info(artist) do
last_fm_config = last_fm_config()
# Sometimes the artist info cannot be identified with the MusicBrainz ID,
# because Last.fm doesn't have that information. In that case, we try again with the artist name.
case last_fm_config.api.get_artist_info(
{:musicbrainz_id, artist.musicbrainz_id},
last_fm_config
) do
{:ok, info} ->
{:ok, info}
# TODO: remap error codes
{:error, %{"error" => 6}} ->
last_fm_config.api.get_artist_info({:name, artist.name}, last_fm_config)
error ->
error
end
end
def get_similar_artists(artist) do
last_fm_config = last_fm_config()
# Sometimes the artist info cannot be identified with the MusicBrainz ID,
# because Last.fm doesn't have that information. In that case, we try again with the artist name.
case last_fm_config.api.get_similar_artists(
{:musicbrainz_id, artist.musicbrainz_id},
last_fm_config
) do
{:ok, info} ->
{:ok, info}
# TODO: remap error codes
{:error, %{"error" => 6}} ->
last_fm_config.api.get_similar_artists({:name, artist.name}, last_fm_config)
error ->
error
end
end
def get_cover(id) do def get_cover(id) do
q = q =
from r in Record, from r in Record,
@@ -299,6 +243,4 @@ defmodule MusicLibrary.Records do
end end
defp music_brainz_config, do: MusicBrainz.Config.resolve(:music_library) defp music_brainz_config, do: MusicBrainz.Config.resolve(:music_library)
defp last_fm_config, do: LastFm.Config.resolve(:music_library)
end end
@@ -1,7 +1,7 @@
defmodule MusicLibraryWeb.ArtistLive.Show do defmodule MusicLibraryWeb.ArtistLive.Show do
use MusicLibraryWeb, :live_view use MusicLibraryWeb, :live_view
alias MusicLibrary.Records alias MusicLibrary.{Artists, Records}
@impl true @impl true
def mount(_params, _session, socket) do def mount(_params, _session, socket) do
@@ -10,7 +10,7 @@ defmodule MusicLibraryWeb.ArtistLive.Show do
@impl true @impl true
def handle_params(%{"musicbrainz_id" => musicbrainz_id}, _, socket) do def handle_params(%{"musicbrainz_id" => musicbrainz_id}, _, socket) do
artist = Records.get_artist!(musicbrainz_id) artist = Artists.get_artist!(musicbrainz_id)
grouped_artist_records = grouped_artist_records =
musicbrainz_id musicbrainz_id
@@ -24,7 +24,7 @@ defmodule MusicLibraryWeb.ArtistLive.Show do
# TODO: make it a stream # TODO: make it a stream
|> assign(:artist_records, grouped_artist_records) |> assign(:artist_records, grouped_artist_records)
|> assign_async(:artist_info, fn -> |> assign_async(:artist_info, fn ->
with {:ok, artist_info} <- Records.get_artist_info(artist) do with {:ok, artist_info} <- Artists.get_artist_info(artist) do
{:ok, %{artist_info: artist_info}} {:ok, %{artist_info: artist_info}}
end end
end) end)
@@ -3,7 +3,7 @@ defmodule MusicLibraryWeb.StatsLive.Index do
import MusicLibraryWeb.StatsLive.DataComponents import MusicLibraryWeb.StatsLive.DataComponents
alias MusicLibrary.{Collection, Records, Wishlist} alias MusicLibrary.{Artists, Collection, Records, Wishlist}
alias Records.Record alias Records.Record
def mount(_params, _session, socket) do def mount(_params, _session, socket) do
@@ -25,7 +25,7 @@ defmodule MusicLibraryWeb.StatsLive.Index do
collected_release_ids = Collection.collected_release_ids(release_ids) collected_release_ids = Collection.collected_release_ids(release_ids)
wishlisted_release_ids = Wishlist.wishlisted_release_ids(release_ids) wishlisted_release_ids = Wishlist.wishlisted_release_ids(release_ids)
artist_ids = Records.get_all_artist_ids() artist_ids = Artists.get_all_artist_ids()
if connected?(socket) do if connected?(socket) do
LastFm.Feed.subscribe() LastFm.Feed.subscribe()
@@ -88,7 +88,7 @@ defmodule MusicLibraryWeb.StatsLive.Index do
collected_release_ids = Collection.collected_release_ids(release_ids) collected_release_ids = Collection.collected_release_ids(release_ids)
wishlisted_release_ids = Wishlist.wishlisted_release_ids(release_ids) wishlisted_release_ids = Wishlist.wishlisted_release_ids(release_ids)
artist_ids = Records.get_all_artist_ids() artist_ids = Artists.get_all_artist_ids()
{:noreply, {:noreply,
socket socket
+17
View File
@@ -0,0 +1,17 @@
defmodule MusicLibrary.ArtistsTest do
use MusicLibrary.DataCase
alias MusicLibrary.Artists
import MusicLibrary.RecordsFixtures
describe "get_artist/1" do
test "it returns records with essential data" do
record = record_fixture()
[expected] = record.artists
artist = Artists.get_artist!(expected.musicbrainz_id)
assert expected == artist
end
end
end
-11
View File
@@ -168,17 +168,6 @@ defmodule MusicLibrary.RecordsTest do
end end
end end
describe "get_artist/1" do
test "it returns records with essential data" do
record = record_fixture()
[expected] = record.artists
artist = Records.get_artist!(expected.musicbrainz_id)
assert expected == artist
end
end
describe "get_cover/1" do describe "get_cover/1" do
test "it returns the record cover by id" do test "it returns the record cover by id" do
# while this test may seem redundant, it implicitely checks that ALL record fields are returned, # while this test may seem redundant, it implicitely checks that ALL record fields are returned,