Make MusicBrainz user agent configurable
This commit is contained in:
@@ -1,12 +1,14 @@
|
|||||||
defmodule MusicBrainz.APIBehaviour do
|
defmodule MusicBrainz.APIBehaviour do
|
||||||
@type musicbrainz_id :: String.t()
|
@type musicbrainz_id :: String.t()
|
||||||
|
@type config :: MusicBrainz.Config.t()
|
||||||
|
|
||||||
@callback get_release_group(musicbrainz_id) :: {:ok, map()} | {:error, String.t()}
|
@callback get_release_group(musicbrainz_id, config) :: {:ok, map()} | {:error, String.t()}
|
||||||
|
|
||||||
@callback get_release(musicbrainz_id) :: {:ok, map()} | {:error, String.t()}
|
@callback get_release(musicbrainz_id, config) :: {:ok, map()} | {:error, String.t()}
|
||||||
|
|
||||||
@callback search_release_group(String.t(), Keyword.t()) :: {:ok, [map()]} | {:error, String.t()}
|
@callback search_release_group(String.t(), Keyword.t(), config) ::
|
||||||
|
{:ok, [map()]} | {:error, String.t()}
|
||||||
|
|
||||||
@callback get_cover_art({:musicbrainz_id, musicbrainz_id()} | {:url, String.t()}) ::
|
@callback get_cover_art({:musicbrainz_id, musicbrainz_id()} | {:url, String.t()}, config) ::
|
||||||
{:ok, binary()} | {:error, String.t()}
|
{:ok, binary()} | {:error, String.t()}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -209,11 +209,11 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def get_release_group(id) do
|
def get_release_group(id, config) do
|
||||||
url =
|
url =
|
||||||
"https://musicbrainz.org/ws/2/release-group/#{id}?fmt=json&inc=artists+genres+releases+release-group-rels"
|
"https://musicbrainz.org/ws/2/release-group/#{id}?fmt=json&inc=artists+genres+releases+release-group-rels"
|
||||||
|
|
||||||
json_get(url)
|
json_get(url, config)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@@ -280,11 +280,11 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@impl true
|
@impl true
|
||||||
def get_release(id) do
|
def get_release(id, config) do
|
||||||
url =
|
url =
|
||||||
"https://musicbrainz.org/ws/2/release/#{id}?fmt=json&inc=release-groups"
|
"https://musicbrainz.org/ws/2/release/#{id}?fmt=json&inc=release-groups"
|
||||||
|
|
||||||
json_get(url)
|
json_get(url, config)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@@ -388,7 +388,7 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
@impl true
|
@impl true
|
||||||
def search_release_group(query, opts) do
|
def search_release_group(query, opts, config) do
|
||||||
limit = Keyword.fetch!(opts, :limit)
|
limit = Keyword.fetch!(opts, :limit)
|
||||||
offset = Keyword.fetch!(opts, :offset)
|
offset = Keyword.fetch!(opts, :offset)
|
||||||
|
|
||||||
@@ -402,7 +402,7 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
url =
|
url =
|
||||||
"https://musicbrainz.org/ws/2/release-group?#{URI.encode_query(qs)}"
|
"https://musicbrainz.org/ws/2/release-group?#{URI.encode_query(qs)}"
|
||||||
|
|
||||||
with {:ok, result} <- json_get(url) do
|
with {:ok, result} <- json_get(url, config) do
|
||||||
{:ok, Enum.map(result["release-groups"], &ReleaseGroup.from_api_response/1)}
|
{:ok, Enum.map(result["release-groups"], &ReleaseGroup.from_api_response/1)}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -411,14 +411,14 @@ 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.
|
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
|
@impl true
|
||||||
def get_cover_art({:musicbrainz_id, musicbrainz_id}) do
|
def get_cover_art({:musicbrainz_id, musicbrainz_id}, config) do
|
||||||
url = "https://coverartarchive.org/release-group/#{musicbrainz_id}/front"
|
url = "https://coverartarchive.org/release-group/#{musicbrainz_id}/front"
|
||||||
|
|
||||||
get_cover_art({:url, url})
|
get_cover_art({:url, url}, config)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_cover_art({:url, url}) do
|
def get_cover_art({:url, url}, config) do
|
||||||
case blob_get(url) do
|
case blob_get(url, config) do
|
||||||
{:error, reason} ->
|
{:error, reason} ->
|
||||||
Logger.error("Failed to fetch cover art for #{url}, reason: #{inspect(reason)}")
|
Logger.error("Failed to fetch cover art for #{url}, reason: #{inspect(reason)}")
|
||||||
|
|
||||||
@@ -429,10 +429,10 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp json_get(url) do
|
defp json_get(url, config) do
|
||||||
req =
|
req =
|
||||||
Finch.build(:get, url, [
|
Finch.build(:get, url, [
|
||||||
{"User-Agent", "MusicLibrary/0.1.0 ( cloud8421@gmail.com )"}
|
{"User-Agent", config.user_agent}
|
||||||
])
|
])
|
||||||
|
|
||||||
Logger.debug("Fetching data from #{url}")
|
Logger.debug("Fetching data from #{url}")
|
||||||
@@ -444,7 +444,7 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
{:ok, response} when response.status in 301..308 ->
|
{:ok, response} when response.status in 301..308 ->
|
||||||
location = :proplists.get_value("location", response.headers)
|
location = :proplists.get_value("location", response.headers)
|
||||||
Logger.debug("Following redirect to #{location}")
|
Logger.debug("Following redirect to #{location}")
|
||||||
json_get(location)
|
json_get(location, config)
|
||||||
|
|
||||||
other ->
|
other ->
|
||||||
msg = "Failed to fetch data from #{url}, reason: #{inspect(other)}"
|
msg = "Failed to fetch data from #{url}, reason: #{inspect(other)}"
|
||||||
@@ -453,10 +453,10 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp blob_get(url) do
|
defp blob_get(url, config) do
|
||||||
req =
|
req =
|
||||||
Finch.build(:get, url, [
|
Finch.build(:get, url, [
|
||||||
{"User-Agent", "MusicLibrary/0.1.0 ( cloud8421@gmail.com )"}
|
{"User-Agent", config.user_agent}
|
||||||
])
|
])
|
||||||
|
|
||||||
Logger.debug("Fetching data from #{url}")
|
Logger.debug("Fetching data from #{url}")
|
||||||
@@ -468,7 +468,7 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
{:ok, response} when response.status in 301..308 ->
|
{:ok, response} when response.status in 301..308 ->
|
||||||
location = :proplists.get_value("location", response.headers)
|
location = :proplists.get_value("location", response.headers)
|
||||||
Logger.debug("Following redirect to #{location}")
|
Logger.debug("Following redirect to #{location}")
|
||||||
blob_get(location)
|
blob_get(location, config)
|
||||||
|
|
||||||
# all non-success responses can be treated as errors
|
# all non-success responses can be treated as errors
|
||||||
{:ok, response} ->
|
{:ok, response} ->
|
||||||
|
|||||||
@@ -127,11 +127,16 @@ defmodule MusicLibrary.Records do
|
|||||||
def search_release_group(query, opts \\ []) do
|
def search_release_group(query, opts \\ []) do
|
||||||
limit = Keyword.get(opts, :limit, 20)
|
limit = Keyword.get(opts, :limit, 20)
|
||||||
offset = Keyword.get(opts, :offset, 0)
|
offset = Keyword.get(opts, :offset, 0)
|
||||||
music_brainz_config().api.search_release_group(query, limit: limit, offset: offset)
|
|
||||||
|
music_brainz_config().api.search_release_group(
|
||||||
|
query,
|
||||||
|
[limit: limit, offset: offset],
|
||||||
|
music_brainz_config()
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def import_from_musicbrainz_release(musicbrainz_id, opts \\ []) do
|
def import_from_musicbrainz_release(musicbrainz_id, opts \\ []) do
|
||||||
case music_brainz_config().api.get_release(musicbrainz_id) do
|
case music_brainz_config().api.get_release(musicbrainz_id, music_brainz_config()) do
|
||||||
{:ok, release} ->
|
{:ok, release} ->
|
||||||
release_group_id = release["release-group"]["id"]
|
release_group_id = release["release-group"]["id"]
|
||||||
import_from_musicbrainz_release_group(release_group_id, opts)
|
import_from_musicbrainz_release_group(release_group_id, opts)
|
||||||
@@ -144,7 +149,8 @@ defmodule MusicLibrary.Records do
|
|||||||
def import_from_musicbrainz_release_group(musicbrainz_id, opts \\ []) do
|
def import_from_musicbrainz_release_group(musicbrainz_id, opts \\ []) do
|
||||||
with format = Keyword.get(opts, :format, "cd"),
|
with format = Keyword.get(opts, :format, "cd"),
|
||||||
purchased_at = Keyword.get(opts, :purchased_at),
|
purchased_at = Keyword.get(opts, :purchased_at),
|
||||||
{:ok, release_group} <- music_brainz_config().api.get_release_group(musicbrainz_id),
|
{:ok, release_group} <-
|
||||||
|
music_brainz_config().api.get_release_group(musicbrainz_id, music_brainz_config()),
|
||||||
{:ok, cover_data} <- get_cover_art_or_default(musicbrainz_id),
|
{:ok, cover_data} <- get_cover_art_or_default(musicbrainz_id),
|
||||||
record_attrs =
|
record_attrs =
|
||||||
build_record_attrs(release_group, %{
|
build_record_attrs(release_group, %{
|
||||||
@@ -159,14 +165,21 @@ defmodule MusicLibrary.Records do
|
|||||||
end
|
end
|
||||||
|
|
||||||
defp get_cover_art_or_default(musicbrainz_id) do
|
defp get_cover_art_or_default(musicbrainz_id) do
|
||||||
case music_brainz_config().api.get_cover_art({:musicbrainz_id, musicbrainz_id}) do
|
case music_brainz_config().api.get_cover_art(
|
||||||
|
{:musicbrainz_id, musicbrainz_id},
|
||||||
|
music_brainz_config()
|
||||||
|
) do
|
||||||
{:error, :cover_not_available} -> {:ok, Record.fallback_cover_data()}
|
{:error, :cover_not_available} -> {:ok, Record.fallback_cover_data()}
|
||||||
{:ok, cover_data} -> Cover.resize(cover_data)
|
{:ok, cover_data} -> Cover.resize(cover_data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def refresh_cover(record) do
|
def refresh_cover(record) do
|
||||||
with {:ok, cover_data} <- music_brainz_config().api.get_cover_art({:url, record.cover_url}) do
|
with {:ok, cover_data} <-
|
||||||
|
music_brainz_config().api.get_cover_art(
|
||||||
|
{:url, record.cover_url},
|
||||||
|
music_brainz_config()
|
||||||
|
) do
|
||||||
{:ok, thumb_data} = Cover.resize(cover_data)
|
{:ok, thumb_data} = Cover.resize(cover_data)
|
||||||
|
|
||||||
record
|
record
|
||||||
@@ -184,7 +197,11 @@ defmodule MusicLibrary.Records do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def refresh_musicbrainz_data(record) do
|
def refresh_musicbrainz_data(record) do
|
||||||
with {:ok, data} <- music_brainz_config().api.get_release_group(record.musicbrainz_id) do
|
with {:ok, data} <-
|
||||||
|
music_brainz_config().api.get_release_group(
|
||||||
|
record.musicbrainz_id,
|
||||||
|
music_brainz_config()
|
||||||
|
) do
|
||||||
record
|
record
|
||||||
|> Record.add_musicbrainz_data(data)
|
|> Record.add_musicbrainz_data(data)
|
||||||
|> Repo.update()
|
|> Repo.update()
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ defmodule MusicLibrary.RecordsTest do
|
|||||||
assert record.release_ids == []
|
assert record.release_ids == []
|
||||||
assert record.included_release_group_ids == []
|
assert record.included_release_group_ids == []
|
||||||
|
|
||||||
expect(APIBehaviourMock, :get_release_group, fn ^release_group_id ->
|
expect(APIBehaviourMock, :get_release_group, fn ^release_group_id, _config ->
|
||||||
{:ok, release_group_with_includes()}
|
{:ok, release_group_with_includes()}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -193,7 +193,9 @@ defmodule MusicLibrary.RecordsTest do
|
|||||||
test "it returns results with correct limit and offset" do
|
test "it returns results with correct limit and offset" do
|
||||||
mock_results = release_group_search_results()
|
mock_results = release_group_search_results()
|
||||||
|
|
||||||
expect(APIBehaviourMock, :search_release_group, fn "Marillion", limit: 20, offset: 10 ->
|
expect(APIBehaviourMock, :search_release_group, fn "Marillion",
|
||||||
|
[limit: 20, offset: 10],
|
||||||
|
_config ->
|
||||||
{:ok, mock_results}
|
{:ok, mock_results}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -209,13 +211,13 @@ defmodule MusicLibrary.RecordsTest do
|
|||||||
release_group = release_group()
|
release_group = release_group()
|
||||||
release_group_id = release_group_id()
|
release_group_id = release_group_id()
|
||||||
|
|
||||||
expect(APIBehaviourMock, :get_release_group, fn ^release_group_id ->
|
expect(APIBehaviourMock, :get_release_group, fn ^release_group_id, _config ->
|
||||||
{:ok, release_group}
|
{:ok, release_group}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
cover_data = File.read!(marbles_cover_fixture())
|
cover_data = File.read!(marbles_cover_fixture())
|
||||||
|
|
||||||
expect(APIBehaviourMock, :get_cover_art, fn {:musicbrainz_id, ^release_group_id} ->
|
expect(APIBehaviourMock, :get_cover_art, fn {:musicbrainz_id, ^release_group_id}, _config ->
|
||||||
{:ok, cover_data}
|
{:ok, cover_data}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -258,17 +260,17 @@ defmodule MusicLibrary.RecordsTest do
|
|||||||
release_group = release_group()
|
release_group = release_group()
|
||||||
release_group_id = release_group_id()
|
release_group_id = release_group_id()
|
||||||
|
|
||||||
expect(APIBehaviourMock, :get_release, fn ^release_id ->
|
expect(APIBehaviourMock, :get_release, fn ^release_id, _config ->
|
||||||
{:ok, release}
|
{:ok, release}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
expect(APIBehaviourMock, :get_release_group, fn ^release_group_id ->
|
expect(APIBehaviourMock, :get_release_group, fn ^release_group_id, _config ->
|
||||||
{:ok, release_group}
|
{:ok, release_group}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
cover_data = File.read!(marbles_cover_fixture())
|
cover_data = File.read!(marbles_cover_fixture())
|
||||||
|
|
||||||
expect(APIBehaviourMock, :get_cover_art, fn {:musicbrainz_id, ^release_group_id} ->
|
expect(APIBehaviourMock, :get_cover_art, fn {:musicbrainz_id, ^release_group_id}, _config ->
|
||||||
{:ok, cover_data}
|
{:ok, cover_data}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -309,7 +311,7 @@ defmodule MusicLibrary.RecordsTest do
|
|||||||
|
|
||||||
cover_url = record.cover_url
|
cover_url = record.cover_url
|
||||||
|
|
||||||
expect(APIBehaviourMock, :get_cover_art, fn {:url, ^cover_url} ->
|
expect(APIBehaviourMock, :get_cover_art, fn {:url, ^cover_url}, _config ->
|
||||||
{:ok, raven_cover_data}
|
{:ok, raven_cover_data}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|||||||
@@ -275,8 +275,8 @@ defmodule MusicLibraryWeb.CollectionLive.IndexTest do
|
|||||||
mock_results = release_group_search_results()
|
mock_results = release_group_search_results()
|
||||||
|
|
||||||
expect(APIBehaviourMock, :search_release_group, fn "Marillion Marbles",
|
expect(APIBehaviourMock, :search_release_group, fn "Marillion Marbles",
|
||||||
limit: 10,
|
[limit: 10, offset: 0],
|
||||||
offset: 0 ->
|
_config ->
|
||||||
{:ok, mock_results}
|
{:ok, mock_results}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -297,13 +297,13 @@ defmodule MusicLibraryWeb.CollectionLive.IndexTest do
|
|||||||
|
|
||||||
release_group = release_group()
|
release_group = release_group()
|
||||||
|
|
||||||
expect(APIBehaviourMock, :get_release_group, fn ^first_result_id ->
|
expect(APIBehaviourMock, :get_release_group, fn ^first_result_id, _config ->
|
||||||
{:ok, release_group}
|
{:ok, release_group}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
cover_data = File.read!(marbles_cover_fixture())
|
cover_data = File.read!(marbles_cover_fixture())
|
||||||
|
|
||||||
expect(APIBehaviourMock, :get_cover_art, fn {:musicbrainz_id, ^first_result_id} ->
|
expect(APIBehaviourMock, :get_cover_art, fn {:musicbrainz_id, ^first_result_id}, _config ->
|
||||||
{:ok, cover_data}
|
{:ok, cover_data}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user