Import artists on top of existing records

This commit is contained in:
Claudio Ortolina
2024-09-15 20:18:27 +01:00
parent affa7a007e
commit ce1ecf06a7
2 changed files with 44 additions and 33 deletions
+40 -31
View File
@@ -1,7 +1,10 @@
defmodule MusicLibrary.Records.Importer do defmodule MusicLibrary.Records.Importer do
alias Ecto.Multi require Logger
import Ecto.Query, warn: false
@doc """ alias MusicLibrary.Records.Record, as: Rec
@moduledoc """
The original data from Obsidian maps records to release groups, so to find artists for a record we can The original data from Obsidian maps records to release groups, so to find artists for a record we can
use the [lookup](https://musicbrainz.org/doc/MusicBrainz_API#Lookups) endpoint with the release group id and include the use the [lookup](https://musicbrainz.org/doc/MusicBrainz_API#Lookups) endpoint with the release group id and include the
artist credits. artist credits.
@@ -40,52 +43,58 @@ defmodule MusicLibrary.Records.Importer do
"https://musicbrainz.org/ws/2/release-group/#{record.musicbrainz_id}?fmt=json&inc=artist-credits" "https://musicbrainz.org/ws/2/release-group/#{record.musicbrainz_id}?fmt=json&inc=artist-credits"
with {:ok, data} <- json_get(url) do with {:ok, data} <- json_get(url) do
current_time = artists_attrs =
DateTime.utc_now()
|> DateTime.truncate(:second)
artist_entries =
data data
|> get_in(["artist-credit", Access.all(), "artist"]) |> get_in(["artist-credit", Access.all(), "artist"])
|> Enum.map(fn artist -> |> Enum.map(fn artist ->
%{ %{
name: artist["name"], name: artist["name"],
musicbrainz_id: artist["id"], musicbrainz_id: artist["id"],
inserted_at: current_time, sort_name: artist["sort-name"],
updated_at: current_time disambiguation: artist["disambiguation"]
} }
end) end)
Multi.new() record
|> Multi.insert_all(:artists, MusicLibrary.Records.Artist, artist_entries, |> Rec.add_artists(artists_attrs)
on_conflict: :nothing, |> MusicLibrary.Repo.update!()
returning: true
)
|> Multi.insert_all(:artists_records, MusicLibrary.Records.ArtistRecord, fn %{
artists:
{_inserted_count,
artists}
} ->
Enum.map(artists, fn a ->
%{
artist_id: a.id,
record_id: record.id,
inserted_at: current_time,
updated_at: current_time
}
end)
end)
|> MusicLibrary.Repo.transaction()
end end
end end
def import_all do
Rec
|> MusicLibrary.Repo.all()
|> Enum.each(fn r ->
import_artists(r)
Process.sleep(1000)
end)
end
def import_missing do
q = from(r in Rec, where: is_nil(r.artists))
q
|> MusicLibrary.Repo.all()
|> Enum.each(fn r ->
import_artists(r)
Process.sleep(1000)
end)
end
defp json_get(url) do defp json_get(url) do
case Finch.build(:get, url) |> Finch.request(MusicLibrary.Finch) do req =
Finch.build(:get, url, [
{"User-Agent", "MusicLibrary/0.1.0 ( cloud8421@gmail.com )"}
])
case Finch.request(req, MusicLibrary.Finch) do
{:ok, response} when response.status == 200 -> {:ok, response} when response.status == 200 ->
{:ok, Jason.decode!(response.body)} {:ok, Jason.decode!(response.body)}
other -> other ->
{:error, "Failed to fetch data from #{url}, reason: #{inspect(other)}"} msg = "Failed to fetch data from #{url}, reason: #{inspect(other)}"
Logger.error(msg)
{:error, msg}
end end
end end
end end
+4 -2
View File
@@ -14,6 +14,8 @@ defmodule MusicLibrary.Records.Record do
embeds_many :artists, Artist do embeds_many :artists, Artist do
field :name, :string field :name, :string
field :sort_name, :string
field :disambiguation, :string
field :musicbrainz_id, Ecto.UUID field :musicbrainz_id, Ecto.UUID
end end
@@ -23,8 +25,8 @@ defmodule MusicLibrary.Records.Record do
@doc false @doc false
def changeset(record, attrs) do def changeset(record, attrs) do
record record
|> cast(attrs, [:type, :title, :musicbrainz_id, :year, :genres, :image]) |> cast(attrs, [:type, :title, :musicbrainz_id, :year, :genres, :image, :artists])
|> validate_required([:type, :title, :musicbrainz_id, :year, :genres, :image]) |> validate_required([:type, :title, :musicbrainz_id, :year, :genres, :image, :artists])
end end
def add_artists(record, artists_attrs) do def add_artists(record, artists_attrs) do