Refactor MusicBrainz.APIImpl to use Req
This commit is contained in:
+105
-80
@@ -7,7 +7,6 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@behaviour MusicBrainz.APIBehaviour
|
@behaviour MusicBrainz.APIBehaviour
|
||||||
@base_url "https://musicbrainz.org/ws/2"
|
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@@ -116,7 +115,7 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
"id": "0e3fc579-2d24-4f20-9dae-736e1ec78798",
|
"id": "0e3fc579-2d24-4f20-9dae-736e1ec78798",
|
||||||
"disambiguation": "",
|
"disambiguation": "",
|
||||||
"count": 2,
|
"count": 2,
|
||||||
"name": "rock"
|
"name": "rock"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"count": 2,
|
"count": 2,
|
||||||
@@ -211,10 +210,16 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def get_release_group(id, config) do
|
def get_release_group(id, config) do
|
||||||
url =
|
config
|
||||||
@base_url <> "/release-group/#{id}?fmt=json&inc=artists+genres+releases+release-group-rels"
|
|> new_request()
|
||||||
|
|> Req.merge(
|
||||||
json_get(url, config)
|
url: "/release-group/#{id}",
|
||||||
|
params: [
|
||||||
|
fmt: "json",
|
||||||
|
inc: "artists+genres+releases+release-group-rels"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|> get_request()
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@@ -282,37 +287,53 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
"""
|
"""
|
||||||
@impl true
|
@impl true
|
||||||
def get_release(id, config) do
|
def get_release(id, config) do
|
||||||
url =
|
config
|
||||||
@base_url <> "/release/#{id}?fmt=json&inc=release-groups"
|
|> new_request()
|
||||||
|
|> Req.merge(
|
||||||
json_get(url, config)
|
url: "/release/#{id}",
|
||||||
|
params: [
|
||||||
|
fmt: "json",
|
||||||
|
inc: "release-groups"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|> get_request()
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def get_releases(release_group_id, opts, config) do
|
def get_releases(release_group_id, opts, config) do
|
||||||
Keyword.validate!(opts, [:limit, :offset])
|
Keyword.validate!(opts, [:limit, :offset])
|
||||||
|
|
||||||
opts =
|
params =
|
||||||
Keyword.merge(opts,
|
Keyword.merge(opts,
|
||||||
fmt: "json",
|
fmt: "json",
|
||||||
"release-group": release_group_id,
|
"release-group": release_group_id,
|
||||||
inc: "media"
|
inc: "media"
|
||||||
)
|
)
|
||||||
|
|
||||||
url =
|
config
|
||||||
@base_url <> "/release?" <> URI.encode_query(opts)
|
|> new_request()
|
||||||
|
|> Req.merge(
|
||||||
json_get(url, config)
|
url: "/release",
|
||||||
|
params: params
|
||||||
|
)
|
||||||
|
|> get_request()
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def search_release_by_barcode(barcode, config) do
|
def search_release_by_barcode(barcode, config) do
|
||||||
url =
|
config
|
||||||
@base_url <> "/release?query=barcode:#{barcode}&fmt=json"
|
|> new_request()
|
||||||
|
|> Req.merge(
|
||||||
with {:ok, result} <- json_get(url, config) do
|
url: "/release",
|
||||||
{:ok, Enum.map(result["releases"], &ReleaseSearchResult.from_api_response/1)}
|
params: [
|
||||||
end
|
fmt: "json",
|
||||||
|
query: "barcode:#{barcode}"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|> Req.Request.append_response_steps(
|
||||||
|
parse_release_search_results: &parse_release_search_results/1
|
||||||
|
)
|
||||||
|
|> get_request()
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@@ -417,22 +438,24 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
"""
|
"""
|
||||||
@impl true
|
@impl true
|
||||||
def search_release_group(query, opts, config) do
|
def search_release_group(query, opts, config) do
|
||||||
limit = Keyword.fetch!(opts, :limit)
|
Keyword.validate!(opts, [:limit, :offset])
|
||||||
offset = Keyword.fetch!(opts, :offset)
|
|
||||||
|
|
||||||
qs = [
|
params =
|
||||||
query: query,
|
Keyword.merge(opts,
|
||||||
limit: limit,
|
query: query,
|
||||||
offset: offset,
|
fmt: "json"
|
||||||
fmt: "json"
|
)
|
||||||
]
|
|
||||||
|
|
||||||
url =
|
config
|
||||||
@base_url <> "/release-group?#{URI.encode_query(qs)}"
|
|> new_request()
|
||||||
|
|> Req.merge(
|
||||||
with {:ok, result} <- json_get(url, config) do
|
url: "/release-group",
|
||||||
{:ok, Enum.map(result["release-groups"], &ReleaseGroupSearchResult.from_api_response/1)}
|
params: params
|
||||||
end
|
)
|
||||||
|
|> Req.Request.append_response_steps(
|
||||||
|
parse_release_group_search_results: &parse_release_group_search_results/1
|
||||||
|
)
|
||||||
|
|> get_request()
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
@@ -446,64 +469,66 @@ defmodule MusicBrainz.APIImpl do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def get_cover_art({:url, url}, config) do
|
def get_cover_art({:url, url}, config) do
|
||||||
case blob_get(url, config) do
|
case Req.new(url: url, max_retries: 1, user_agent: config.user_agent)
|
||||||
{:error, reason} ->
|
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||||
Logger.error("Failed to fetch cover art for #{url}, reason: #{inspect(reason)}")
|
|> Req.Request.append_response_steps(log_error: &log_error/1)
|
||||||
|
|> get_request() do
|
||||||
{:error, :cover_not_available}
|
{:ok, data} -> {:ok, data}
|
||||||
|
{:error, _reason} -> {:error, :cover_not_available}
|
||||||
success ->
|
|
||||||
success
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp json_get(url, config) do
|
defp new_request(config) do
|
||||||
req =
|
Req.new(
|
||||||
Finch.build(:get, url, [
|
base_url: "https://musicbrainz.org/ws/2",
|
||||||
{"User-Agent", config.user_agent}
|
max_retries: 1,
|
||||||
])
|
user_agent: config.user_agent
|
||||||
|
)
|
||||||
Logger.debug("Fetching data from #{url}")
|
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||||
|
|
||||||
case Finch.request(req, MusicBrainz.Finch) do
|
|
||||||
{:ok, response} when response.status == 200 ->
|
|
||||||
{:ok, JSON.decode!(response.body)}
|
|
||||||
|
|
||||||
{:ok, response} when response.status in 301..308 ->
|
|
||||||
location = :proplists.get_value("location", response.headers)
|
|
||||||
Logger.debug("Following redirect to #{location}")
|
|
||||||
json_get(location, config)
|
|
||||||
|
|
||||||
other ->
|
|
||||||
msg = "Failed to fetch data from #{url}, reason: #{inspect(other)}"
|
|
||||||
Logger.error(msg)
|
|
||||||
{:error, msg}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp blob_get(url, config) do
|
defp get_request(request) do
|
||||||
req =
|
case Req.get(request) do
|
||||||
Finch.build(:get, url, [
|
|
||||||
{"User-Agent", config.user_agent}
|
|
||||||
])
|
|
||||||
|
|
||||||
Logger.debug("Fetching data from #{url}")
|
|
||||||
|
|
||||||
case Finch.request(req, MusicBrainz.Finch) do
|
|
||||||
{:ok, response} when response.status == 200 ->
|
{:ok, response} when response.status == 200 ->
|
||||||
{:ok, response.body}
|
{: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, config)
|
|
||||||
|
|
||||||
# all non-success responses can be treated as errors
|
# all non-success responses can be treated as errors
|
||||||
{:ok, response} ->
|
{:ok, response} ->
|
||||||
{:error, response}
|
{:error, response.body}
|
||||||
|
|
||||||
error ->
|
error ->
|
||||||
error
|
error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_attempt(request) do
|
||||||
|
url = URI.to_string(request.url)
|
||||||
|
Logger.debug("Fetching data from #{url}")
|
||||||
|
request
|
||||||
|
end
|
||||||
|
|
||||||
|
defp log_error({request, response}) do
|
||||||
|
if response.status in 400..499 or response.status in 500..599 do
|
||||||
|
Logger.error(fn ->
|
||||||
|
url = URI.to_string(request.url)
|
||||||
|
"Failed to fetch data from #{url}, reason: #{inspect(response.body)}"
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
{request, response}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp parse_release_search_results({request, response}) do
|
||||||
|
releases =
|
||||||
|
Enum.map(response.body["releases"], &ReleaseSearchResult.from_api_response/1)
|
||||||
|
|
||||||
|
{request, Map.put(response, :body, releases)}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp parse_release_group_search_results({request, response}) do
|
||||||
|
releases =
|
||||||
|
Enum.map(response.body["release-groups"], &ReleaseGroupSearchResult.from_api_response/1)
|
||||||
|
|
||||||
|
{request, Map.put(response, :body, releases)}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
defmodule MusicBrainz.Supervisor do
|
|
||||||
use Supervisor
|
|
||||||
|
|
||||||
def start_link(config) do
|
|
||||||
Supervisor.start_link(__MODULE__, config, name: __MODULE__)
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
|
||||||
def init(_config) do
|
|
||||||
children = [
|
|
||||||
{Finch, name: MusicBrainz.Finch}
|
|
||||||
]
|
|
||||||
|
|
||||||
Supervisor.init(children, strategy: :one_for_one)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -15,7 +15,6 @@ defmodule MusicLibrary.Application do
|
|||||||
repos: Application.fetch_env!(:music_library, :ecto_repos), skip: skip_migrations?()},
|
repos: Application.fetch_env!(:music_library, :ecto_repos), skip: skip_migrations?()},
|
||||||
{DNSCluster, query: Application.get_env(:music_library, :dns_cluster_query) || :ignore},
|
{DNSCluster, query: Application.get_env(:music_library, :dns_cluster_query) || :ignore},
|
||||||
{Phoenix.PubSub, name: MusicLibrary.PubSub},
|
{Phoenix.PubSub, name: MusicLibrary.PubSub},
|
||||||
MusicBrainz.Supervisor,
|
|
||||||
{LastFm.Supervisor, LastFm.Config.resolve(:music_library)},
|
{LastFm.Supervisor, LastFm.Config.resolve(:music_library)},
|
||||||
# Start a worker by calling: MusicLibrary.Worker.start_link(arg)
|
# Start a worker by calling: MusicLibrary.Worker.start_link(arg)
|
||||||
# {MusicLibrary.Worker, arg},
|
# {MusicLibrary.Worker, arg},
|
||||||
|
|||||||
Reference in New Issue
Block a user