diff --git a/lib/music_brainz/api_behaviour.ex b/lib/music_brainz/api_behaviour.ex index 715007d2..90991f36 100644 --- a/lib/music_brainz/api_behaviour.ex +++ b/lib/music_brainz/api_behaviour.ex @@ -7,5 +7,6 @@ defmodule MusicBrainz.APIBehaviour do @callback search_release_group(String.t(), Keyword.t()) :: {:ok, [map()]} | {:error, String.t()} - @callback get_cover_art(musicbrainz_id) :: {:ok, binary()} | {:error, String.t()} + @callback get_cover_art({:musicbrainz_id, musicbrainz_id()} | {:url, String.t()}) :: + {:ok, binary()} | {:error, String.t()} end diff --git a/lib/music_brainz/api_impl.ex b/lib/music_brainz/api_impl.ex index af0ee506..fb9ffc06 100644 --- a/lib/music_brainz/api_impl.ex +++ b/lib/music_brainz/api_impl.ex @@ -421,17 +421,19 @@ defmodule MusicBrainz.APIImpl do Uses the [cover art](https://musicbrainz.org/doc/Cover_Art_Archive/API) endpoint with the release group id to get the cover image. """ @impl true - def get_cover_art(musicbrainz_id) do + def get_cover_art({:musicbrainz_id, musicbrainz_id}) do url = "https://coverartarchive.org/release-group/#{musicbrainz_id}/front" + get_cover_art({:url, url}) + end + + def get_cover_art({:url, url}) do with {:ok, cover_data} <- blob_get(url), {:ok, thumb} = Vix.Vips.Operation.thumbnail_buffer(cover_data, 400) do Vix.Vips.Image.write_to_buffer(thumb, ".jpg") else {:error, reason} -> - Logger.error( - "Failed to fetch cover art for #{musicbrainz_id}, reason: #{inspect(reason)}" - ) + Logger.error("Failed to fetch cover art for #{url}, reason: #{inspect(reason)}") {:ok, @fallback_cover} end diff --git a/lib/music_library/records.ex b/lib/music_library/records.ex index aacfd410..d3c63fd1 100644 --- a/lib/music_library/records.ex +++ b/lib/music_library/records.ex @@ -96,7 +96,7 @@ defmodule MusicLibrary.Records do with format = Keyword.get(opts, :format, "cd"), purchased_at = Keyword.get(opts, :purchased_at), {:ok, release_group} <- musicbrainz().get_release_group(musicbrainz_id), - {:ok, cover_data} <- musicbrainz().get_cover_art(musicbrainz_id), + {:ok, cover_data} <- musicbrainz().get_cover_art({:musicbrainz_id, musicbrainz_id}), record_params = build_record_params(release_group, cover_data, format, purchased_at) do create_record(record_params) else @@ -104,6 +104,17 @@ defmodule MusicLibrary.Records do end end + def refresh_cover(record) do + with {:ok, cover_data} <- musicbrainz().get_cover_art({:url, record.cover_url}) do + {:ok, thumb} = Vix.Vips.Operation.thumbnail_buffer(cover_data, 400) + {:ok, thumb_data} = Vix.Vips.Image.write_to_buffer(thumb, ".jpg") + + record + |> Record.add_cover_data(thumb_data) + |> Repo.update!() + end + end + defp build_record_params(release_group, cover_data, format, purchased_at) do musicbrainz_id = release_group["id"] diff --git a/lib/music_library/records/batch.ex b/lib/music_library/records/batch.ex index c06896e8..5ab493b7 100644 --- a/lib/music_library/records/batch.ex +++ b/lib/music_library/records/batch.ex @@ -5,117 +5,6 @@ defmodule MusicLibrary.Records.Batch do alias MusicLibrary.Records.Record alias MusicLibrary.Repo - def import_all_artists do - Record - |> Repo.all() - |> Enum.each(fn r -> - import_artists(r) - Process.sleep(1000) - end) - end - - def import_missing_artists do - q = from(r in Record, where: is_nil(r.artists)) - - q - |> Repo.all() - |> Enum.each(fn r -> - import_artists(r) - Process.sleep(1000) - end) - end - - def import_artists(record) do - with {:ok, data} <- musicbrainz().get_release_group(record.musicbrainz_id) do - artists_attrs = - data - |> get_in(["artist-credit", Access.all(), "artist"]) - |> Enum.map(fn artist -> - %{ - name: artist["name"], - musicbrainz_id: artist["id"], - sort_name: artist["sort-name"], - disambiguation: artist["disambiguation"] - } - end) - - record - |> Record.add_artists(artists_attrs) - |> Repo.update!() - end - end - - @doc """ - Pull the cover from the stored url and keep a local, resized copy in - the database for fast access/use. - """ - def import_cover(record) do - with {:ok, cover_data} <- blob_get(record.cover_url) do - {:ok, thumb} = Vix.Vips.Operation.thumbnail_buffer(cover_data, 400) - {:ok, thumb_data} = Vix.Vips.Image.write_to_buffer(thumb, ".jpg") - - record - |> Record.add_cover_data(thumb_data) - |> Repo.update!() - end - end - - @doc """ - Given an already stored cover, resize it to a 400px wide thumbnail. - """ - def resize_cover(record) do - {:ok, thumb} = Vix.Vips.Operation.thumbnail_buffer(record.cover_data, 400) - {:ok, thumb_data} = Vix.Vips.Image.write_to_buffer(thumb, ".jpg") - - record - |> Record.add_cover_data(thumb_data) - |> Repo.update!() - end - - def import_all_covers do - Record - |> Repo.all() - |> Enum.each(fn r -> - if r.cover_data == nil do - import_cover(r) - IO.puts("Imported cover for #{r.title}") - end - end) - end - - def resize_all_covers do - Record - |> Repo.all() - |> Enum.each(fn r -> - if r.cover_data != nil do - resize_cover(r) - IO.puts("Resized cover for #{r.title}") - end - end) - end - - def generate_all_cover_hashes do - Record - |> Repo.all() - |> Enum.each(fn r -> - if r.cover_data != nil do - generate_cover_hash(r) - IO.puts("Generated cover hash for #{r.title}") - end - end) - end - - def import_missing_musicbrainz_data do - q = from(r in Record, where: is_nil(r.musicbrainz_data)) - - q - |> Repo.all() - |> Enum.each(fn r -> - import_musicbrainz_data(r) - Process.sleep(1000) - end) - end - def refresh_musicbrainz_data do Record |> Repo.all() @@ -125,7 +14,7 @@ defmodule MusicLibrary.Records.Batch do end) end - def import_musicbrainz_data(record) do + defp import_musicbrainz_data(record) do with {:ok, data} <- musicbrainz().get_release_group(record.musicbrainz_id) do record |> Record.add_musicbrainz_data(data) @@ -133,36 +22,6 @@ defmodule MusicLibrary.Records.Batch do end end - def generate_cover_hash(record) do - record - |> Record.generate_cover_hash() - |> Repo.update!() - end - - defp blob_get(url) do - req = - Finch.build(:get, url, [ - {"User-Agent", "MusicLibrary/0.1.0 ( cloud8421@gmail.com )"} - ]) - - Logger.debug("Fetching data from #{url}") - - case Finch.request(req, MusicBrainz.Finch) do - {:ok, response} when response.status == 200 -> - {:ok, response.body} - - {:ok, response} when response.status in 301..308 -> - location = :proplists.get_value("location", response.headers) - Logger.debug("Following redirect to #{location}") - blob_get(location) - - other -> - msg = "Failed to fetch data from #{url}, reason: #{inspect(other)}" - Logger.error(msg) - {:error, msg} - end - end - defp musicbrainz do Application.get_env(:music_library, :musicbrainz, MusicBrainz.APIImpl) end diff --git a/test/music_library_web/live/record_index_test.exs b/test/music_library_web/live/record_index_test.exs index a1b78a7b..60757163 100644 --- a/test/music_library_web/live/record_index_test.exs +++ b/test/music_library_web/live/record_index_test.exs @@ -393,7 +393,7 @@ defmodule MusicLibraryWeb.RecordIndexTest do cover_data = File.read!(marbles_cover_fixture()) - expect(APIBehaviourMock, :get_cover_art, fn ^first_result_id -> + expect(APIBehaviourMock, :get_cover_art, fn {:musicbrainz_id, ^first_result_id} -> {:ok, cover_data} end)