Enable unaliased modules ex_slop check
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
{ExSlop.Check.Readability.ObviousComment, []},
|
||||
{ExSlop.Check.Readability.StepComment, []},
|
||||
{ExSlop.Check.Readability.NarratorComment, []},
|
||||
{ExSlop.Check.Readability.UnaliasedModuleUse, []},
|
||||
{Credo.Check.Refactor.Nesting, max_nesting: 3},
|
||||
{Credo.Check.Readability.ModuleDoc,
|
||||
ignore_names: [
|
||||
|
||||
@@ -3,6 +3,8 @@ defmodule BraveSearch.API do
|
||||
Interface to the Brave Search API.
|
||||
"""
|
||||
|
||||
alias Req.Request
|
||||
|
||||
require Logger
|
||||
|
||||
@spec search_images(String.t(), keyword(), BraveSearch.Config.t()) ::
|
||||
@@ -40,9 +42,9 @@ defmodule BraveSearch.API do
|
||||
{:ok, binary()} | {:error, :download_failed}
|
||||
def download_image(url, config) do
|
||||
case Req.new(url: url, max_retries: 1, user_agent: config.user_agent)
|
||||
|> Req.Request.merge_options(config.req_options)
|
||||
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Req.Request.append_response_steps(log_error: &log_error/1)
|
||||
|> Request.merge_options(config.req_options)
|
||||
|> Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Request.append_response_steps(log_error: &log_error/1)
|
||||
|> get_request() do
|
||||
{:ok, data} -> {:ok, data}
|
||||
{:error, _reason} -> {:error, :download_failed}
|
||||
@@ -56,10 +58,10 @@ defmodule BraveSearch.API do
|
||||
user_agent: config.user_agent,
|
||||
headers: %{"x-subscription-token" => config.api_key}
|
||||
)
|
||||
|> Req.Request.merge_options(config.req_options)
|
||||
|> Request.merge_options(config.req_options)
|
||||
|> Req.RateLimiter.attach(name: :brave_search, cooldown: config.api_cooldown)
|
||||
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Req.Request.append_response_steps(log_error: &log_error/1)
|
||||
|> Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Request.append_response_steps(log_error: &log_error/1)
|
||||
end
|
||||
|
||||
defp get_request(request) do
|
||||
|
||||
+8
-6
@@ -3,6 +3,8 @@ defmodule Discogs.API do
|
||||
Interface to the Discogs API.
|
||||
"""
|
||||
|
||||
alias Req.Request
|
||||
|
||||
require Logger
|
||||
|
||||
@spec get_artist(integer() | String.t(), Discogs.Config.t()) :: {:ok, map()} | {:error, term()}
|
||||
@@ -20,9 +22,9 @@ defmodule Discogs.API do
|
||||
{:ok, binary()} | {:error, :cover_not_available}
|
||||
def get_artist_image(url, config) do
|
||||
case Req.new(url: url, max_retries: 1, user_agent: config.user_agent)
|
||||
|> Req.Request.merge_options(config.req_options)
|
||||
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Req.Request.append_response_steps(log_error: &log_error/1)
|
||||
|> Request.merge_options(config.req_options)
|
||||
|> Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Request.append_response_steps(log_error: &log_error/1)
|
||||
|> get_request() do
|
||||
{:ok, data} -> {:ok, data}
|
||||
{:error, _reason} -> {:error, :cover_not_available}
|
||||
@@ -36,10 +38,10 @@ defmodule Discogs.API do
|
||||
user_agent: config.user_agent,
|
||||
auth: "Discogs token=#{config.personal_access_token}"
|
||||
)
|
||||
|> Req.Request.merge_options(config.req_options)
|
||||
|> Request.merge_options(config.req_options)
|
||||
|> Req.RateLimiter.attach(name: :discogs, cooldown: config.api_cooldown)
|
||||
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Req.Request.append_response_steps(log_error: &log_error/1)
|
||||
|> Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Request.append_response_steps(log_error: &log_error/1)
|
||||
end
|
||||
|
||||
defp get_request(request) do
|
||||
|
||||
+15
-14
@@ -1,6 +1,7 @@
|
||||
defmodule LastFm.API do
|
||||
alias LastFm.API.{ErrorResponse, Signature}
|
||||
alias LastFm.{Artist, Session, Track}
|
||||
alias Req.Request
|
||||
|
||||
require Logger
|
||||
|
||||
@@ -22,8 +23,8 @@ defmodule LastFm.API do
|
||||
config
|
||||
|> new_request()
|
||||
|> Req.merge(url: "/", params: params)
|
||||
|> Req.Request.append_response_steps(parse_error: &parse_error/1)
|
||||
|> Req.Request.append_response_steps(parse_session: &parse_session/1)
|
||||
|> Request.append_response_steps(parse_error: &parse_error/1)
|
||||
|> Request.append_response_steps(parse_session: &parse_session/1)
|
||||
|> get_request()
|
||||
end
|
||||
|
||||
@@ -70,7 +71,7 @@ defmodule LastFm.API do
|
||||
config
|
||||
|> new_request()
|
||||
|> Req.merge(url: "/", params: params)
|
||||
|> Req.Request.append_response_steps(parse_tracks: &parse_tracks/1)
|
||||
|> Request.append_response_steps(parse_tracks: &parse_tracks/1)
|
||||
|> get_request()
|
||||
end
|
||||
|
||||
@@ -85,7 +86,7 @@ defmodule LastFm.API do
|
||||
config
|
||||
|> new_request()
|
||||
|> Req.merge(url: "/", params: params)
|
||||
|> Req.Request.append_response_steps(parse_tracks: &parse_artist/1)
|
||||
|> Request.append_response_steps(parse_tracks: &parse_artist/1)
|
||||
|> get_request()
|
||||
end
|
||||
|
||||
@@ -101,7 +102,7 @@ defmodule LastFm.API do
|
||||
config
|
||||
|> new_request()
|
||||
|> Req.merge(url: "/", params: params)
|
||||
|> Req.Request.append_response_steps(parse_tracks: &parse_similar_artists/1)
|
||||
|> Request.append_response_steps(parse_tracks: &parse_similar_artists/1)
|
||||
|> get_request()
|
||||
end
|
||||
|
||||
@@ -117,7 +118,7 @@ defmodule LastFm.API do
|
||||
config
|
||||
|> new_request()
|
||||
|> Req.merge(url: "/", params: params)
|
||||
|> Req.Request.append_response_steps(parse_tags: &parse_artist_tags/1)
|
||||
|> Request.append_response_steps(parse_tags: &parse_artist_tags/1)
|
||||
|> get_request()
|
||||
end
|
||||
|
||||
@@ -134,7 +135,7 @@ defmodule LastFm.API do
|
||||
config
|
||||
|> new_request()
|
||||
|> Req.merge(url: "/", params: params)
|
||||
|> Req.Request.append_response_steps(parse_user_info: &parse_user_info/1)
|
||||
|> Request.append_response_steps(parse_user_info: &parse_user_info/1)
|
||||
|> get_request()
|
||||
end
|
||||
|
||||
@@ -169,11 +170,11 @@ defmodule LastFm.API do
|
||||
],
|
||||
user_agent: config.user_agent
|
||||
)
|
||||
|> Req.Request.merge_options(config.req_options)
|
||||
|> Request.merge_options(config.req_options)
|
||||
|> Req.RateLimiter.attach(name: :last_fm, cooldown: config.api_cooldown)
|
||||
|> Req.Request.put_private(:api_key, config.api_key)
|
||||
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Req.Request.append_response_steps(parse_error: &parse_error/1)
|
||||
|> Request.put_private(:api_key, config.api_key)
|
||||
|> Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Request.append_response_steps(parse_error: &parse_error/1)
|
||||
end
|
||||
|
||||
defp get_request(request) do
|
||||
@@ -204,7 +205,7 @@ defmodule LastFm.API do
|
||||
|
||||
defp log_attempt(request) do
|
||||
url = URI.to_string(request.url)
|
||||
api_key = Req.Request.get_private(request, :api_key)
|
||||
api_key = Request.get_private(request, :api_key)
|
||||
Logger.debug("Fetching data from #{sanitize_url(url, api_key)}")
|
||||
request
|
||||
end
|
||||
@@ -221,11 +222,11 @@ defmodule LastFm.API do
|
||||
|
||||
Logger.error(fn ->
|
||||
url = URI.to_string(request.url)
|
||||
api_key = Req.Request.get_private(request, :api_key)
|
||||
api_key = Request.get_private(request, :api_key)
|
||||
"Failed to fetch data from #{sanitize_url(url, api_key)}, reason: #{message}."
|
||||
end)
|
||||
|
||||
Req.Request.halt(request, Map.put(response, :body, error))
|
||||
Request.halt(request, Map.put(response, :body, error))
|
||||
|
||||
_other ->
|
||||
{request, response}
|
||||
|
||||
@@ -37,6 +37,7 @@ defmodule Mix.Tasks.Scrobble.Audit do
|
||||
import Ecto.Query
|
||||
|
||||
alias LastFm.Track
|
||||
alias Mix.Shell.IO, as: ShellIO
|
||||
alias MusicLibrary.{ListeningStats, Maintenance, Repo}
|
||||
|
||||
@impl Mix.Task
|
||||
@@ -267,12 +268,12 @@ defmodule Mix.Tasks.Scrobble.Audit do
|
||||
defp output_json(report) do
|
||||
report
|
||||
|> Jason.encode!(pretty: true)
|
||||
|> Mix.Shell.IO.info()
|
||||
|> ShellIO.info()
|
||||
end
|
||||
|
||||
defp output_text(report, verbose) do
|
||||
Mix.Shell.IO.info("\n=== Scrobbled Tracks Data Quality Audit ===\n")
|
||||
Mix.Shell.IO.info("Total scrobbled tracks: #{report.total_tracks}\n")
|
||||
ShellIO.info("\n=== Scrobbled Tracks Data Quality Audit ===\n")
|
||||
ShellIO.info("Total scrobbled tracks: #{report.total_tracks}\n")
|
||||
|
||||
if Map.has_key?(report, :artist_issues) do
|
||||
output_artist_issues(report.artist_issues, verbose)
|
||||
@@ -286,71 +287,71 @@ defmodule Mix.Tasks.Scrobble.Audit do
|
||||
end
|
||||
|
||||
defp output_artist_issues(artist_issues, verbose) do
|
||||
Mix.Shell.IO.info("--- Artists with Missing MusicBrainz IDs ---")
|
||||
Mix.Shell.IO.info("Unique artists: #{artist_issues.total_artists}")
|
||||
Mix.Shell.IO.info("Affected tracks: #{artist_issues.total_tracks_affected}\n")
|
||||
ShellIO.info("--- Artists with Missing MusicBrainz IDs ---")
|
||||
ShellIO.info("Unique artists: #{artist_issues.total_artists}")
|
||||
ShellIO.info("Affected tracks: #{artist_issues.total_tracks_affected}\n")
|
||||
|
||||
if artist_issues.total_artists > 0 do
|
||||
Mix.Shell.IO.info("Top artists by track count:")
|
||||
ShellIO.info("Top artists by track count:")
|
||||
|
||||
artist_issues.artists
|
||||
|> Enum.take(10)
|
||||
|> Enum.each(fn %{name: name, track_count: count} ->
|
||||
Mix.Shell.IO.info(" • #{name} (#{count} tracks)")
|
||||
ShellIO.info(" • #{name} (#{count} tracks)")
|
||||
end)
|
||||
|
||||
Mix.Shell.IO.info("")
|
||||
ShellIO.info("")
|
||||
|
||||
if verbose and Map.has_key?(artist_issues, :sample_tracks) do
|
||||
Mix.Shell.IO.info("Sample tracks:")
|
||||
ShellIO.info("Sample tracks:")
|
||||
|
||||
Enum.each(artist_issues.sample_tracks, fn %{artist: artist, sample_tracks: tracks} ->
|
||||
Mix.Shell.IO.info("\n Artist: #{artist}")
|
||||
ShellIO.info("\n Artist: #{artist}")
|
||||
|
||||
# credo:disable-for-next-line Credo.Check.Refactor.Nesting
|
||||
Enum.each(tracks, fn track ->
|
||||
Mix.Shell.IO.info(" - #{track.title} (from #{track.album})")
|
||||
ShellIO.info(" - #{track.title} (from #{track.album})")
|
||||
end)
|
||||
end)
|
||||
|
||||
Mix.Shell.IO.info("")
|
||||
ShellIO.info("")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp output_album_issues(album_issues, verbose) do
|
||||
Mix.Shell.IO.info("--- Albums with Missing MusicBrainz IDs ---")
|
||||
Mix.Shell.IO.info("Unique albums: #{album_issues.total_albums}")
|
||||
Mix.Shell.IO.info("Affected tracks: #{album_issues.total_tracks_affected}\n")
|
||||
ShellIO.info("--- Albums with Missing MusicBrainz IDs ---")
|
||||
ShellIO.info("Unique albums: #{album_issues.total_albums}")
|
||||
ShellIO.info("Affected tracks: #{album_issues.total_tracks_affected}\n")
|
||||
|
||||
if album_issues.total_albums > 0 do
|
||||
Mix.Shell.IO.info("Top albums by track count:")
|
||||
ShellIO.info("Top albums by track count:")
|
||||
|
||||
album_issues.albums
|
||||
|> Enum.take(10)
|
||||
|> Enum.each(fn %{title: title, artist: artist, track_count: count} ->
|
||||
Mix.Shell.IO.info(" • #{title} by #{artist} (#{count} tracks)")
|
||||
ShellIO.info(" • #{title} by #{artist} (#{count} tracks)")
|
||||
end)
|
||||
|
||||
Mix.Shell.IO.info("")
|
||||
ShellIO.info("")
|
||||
|
||||
if verbose and Map.has_key?(album_issues, :sample_tracks) do
|
||||
Mix.Shell.IO.info("Sample tracks:")
|
||||
ShellIO.info("Sample tracks:")
|
||||
|
||||
Enum.each(album_issues.sample_tracks, fn %{
|
||||
album: album,
|
||||
artist: artist,
|
||||
sample_tracks: tracks
|
||||
} ->
|
||||
Mix.Shell.IO.info("\n Album: #{album} by #{artist}")
|
||||
ShellIO.info("\n Album: #{album} by #{artist}")
|
||||
|
||||
# credo:disable-for-next-line Credo.Check.Refactor.Nesting
|
||||
Enum.each(tracks, fn track ->
|
||||
Mix.Shell.IO.info(" - #{track.title}")
|
||||
ShellIO.info(" - #{track.title}")
|
||||
end)
|
||||
end)
|
||||
|
||||
Mix.Shell.IO.info("")
|
||||
ShellIO.info("")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -360,10 +361,10 @@ defmodule Mix.Tasks.Scrobble.Audit do
|
||||
(Map.get(report, :artist_issues, %{}) |> Map.get(:total_tracks_affected, 0)) +
|
||||
(Map.get(report, :album_issues, %{}) |> Map.get(:total_tracks_affected, 0))
|
||||
|
||||
Mix.Shell.IO.info("--- Summary ---")
|
||||
Mix.Shell.IO.info("Total tracks needing enrichment: #{total_issues}")
|
||||
ShellIO.info("--- Summary ---")
|
||||
ShellIO.info("Total tracks needing enrichment: #{total_issues}")
|
||||
|
||||
Mix.Shell.IO.info("""
|
||||
ShellIO.info("""
|
||||
|
||||
To fix these issues:
|
||||
1. Create scrobble rules for artists with missing MusicBrainz IDs:
|
||||
|
||||
@@ -7,6 +7,7 @@ defmodule MusicBrainz.API do
|
||||
"""
|
||||
|
||||
alias MusicBrainz.{Artist, ReleaseGroupSearchResult, ReleaseSearchResult}
|
||||
alias Req.Request
|
||||
|
||||
require Logger
|
||||
|
||||
@@ -330,7 +331,7 @@ defmodule MusicBrainz.API do
|
||||
query: "barcode:#{barcode} AND NOT format:digitalmedia"
|
||||
]
|
||||
)
|
||||
|> Req.Request.append_response_steps(
|
||||
|> Request.append_response_steps(
|
||||
parse_release_search_results: &parse_release_search_results/1
|
||||
)
|
||||
|> get_request()
|
||||
@@ -454,7 +455,7 @@ defmodule MusicBrainz.API do
|
||||
url: "/release-group",
|
||||
params: params
|
||||
)
|
||||
|> Req.Request.append_response_steps(
|
||||
|> Request.append_response_steps(
|
||||
parse_release_group_search_results: &parse_release_group_search_results/1
|
||||
)
|
||||
|> get_request()
|
||||
@@ -471,7 +472,7 @@ defmodule MusicBrainz.API do
|
||||
inc: "url-rels"
|
||||
]
|
||||
)
|
||||
|> Req.Request.append_response_steps(parse_artist: &parse_artist/1)
|
||||
|> Request.append_response_steps(parse_artist: &parse_artist/1)
|
||||
|> get_request()
|
||||
end
|
||||
|
||||
@@ -488,9 +489,9 @@ defmodule MusicBrainz.API do
|
||||
|
||||
def get_cover_art({:url, url}, config) do
|
||||
case Req.new(url: url, max_retries: 1, user_agent: config.user_agent)
|
||||
|> Req.Request.merge_options(config.req_options)
|
||||
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Req.Request.append_response_steps(log_error: &log_error/1)
|
||||
|> Request.merge_options(config.req_options)
|
||||
|> Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Request.append_response_steps(log_error: &log_error/1)
|
||||
|> get_request() do
|
||||
{:ok, data} -> {:ok, data}
|
||||
{:error, _reason} -> {:error, :cover_not_available}
|
||||
@@ -503,9 +504,9 @@ defmodule MusicBrainz.API do
|
||||
max_retries: 1,
|
||||
user_agent: config.user_agent
|
||||
)
|
||||
|> Req.Request.merge_options(config.req_options)
|
||||
|> Request.merge_options(config.req_options)
|
||||
|> Req.RateLimiter.attach(name: :music_brainz, cooldown: config.api_cooldown)
|
||||
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
end
|
||||
|
||||
defp get_request(request) do
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule MusicLibrary.RecordSets do
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
|
||||
alias Ecto.Changeset
|
||||
alias MusicLibrary.RecordSets.{RecordSet, RecordSetItem}
|
||||
alias MusicLibrary.Repo
|
||||
|
||||
@@ -64,7 +65,7 @@ defmodule MusicLibrary.RecordSets do
|
||||
|> Repo.preload(items: :record)
|
||||
end
|
||||
|
||||
@spec create_record_set(map()) :: {:ok, RecordSet.t()} | {:error, Ecto.Changeset.t()}
|
||||
@spec create_record_set(map()) :: {:ok, RecordSet.t()} | {:error, Changeset.t()}
|
||||
def create_record_set(attrs) do
|
||||
%RecordSet{}
|
||||
|> RecordSet.changeset(attrs)
|
||||
@@ -76,7 +77,7 @@ defmodule MusicLibrary.RecordSets do
|
||||
end
|
||||
|
||||
@spec update_record_set(RecordSet.t(), map()) ::
|
||||
{:ok, RecordSet.t()} | {:error, Ecto.Changeset.t()}
|
||||
{:ok, RecordSet.t()} | {:error, Changeset.t()}
|
||||
def update_record_set(%RecordSet{} = record_set, attrs) do
|
||||
record_set
|
||||
|> RecordSet.changeset(attrs)
|
||||
@@ -87,18 +88,18 @@ defmodule MusicLibrary.RecordSets do
|
||||
end
|
||||
end
|
||||
|
||||
@spec delete_record_set(RecordSet.t()) :: {:ok, RecordSet.t()} | {:error, Ecto.Changeset.t()}
|
||||
@spec delete_record_set(RecordSet.t()) :: {:ok, RecordSet.t()} | {:error, Changeset.t()}
|
||||
def delete_record_set(%RecordSet{} = record_set) do
|
||||
Repo.delete(record_set)
|
||||
end
|
||||
|
||||
@spec change_record_set(RecordSet.t(), map()) :: Ecto.Changeset.t()
|
||||
@spec change_record_set(RecordSet.t(), map()) :: Changeset.t()
|
||||
def change_record_set(%RecordSet{} = record_set, attrs \\ %{}) do
|
||||
RecordSet.changeset(record_set, attrs)
|
||||
end
|
||||
|
||||
@spec add_record_to_set(RecordSet.t(), String.t()) ::
|
||||
{:ok, RecordSet.t()} | {:error, Ecto.Changeset.t()}
|
||||
{:ok, RecordSet.t()} | {:error, Changeset.t()}
|
||||
def add_record_to_set(%RecordSet{} = record_set, record_id) do
|
||||
next_position =
|
||||
from(i in RecordSetItem,
|
||||
@@ -110,9 +111,9 @@ defmodule MusicLibrary.RecordSets do
|
||||
|
||||
%RecordSetItem{}
|
||||
|> RecordSetItem.changeset(%{position: next_position})
|
||||
|> Ecto.Changeset.put_change(:record_set_id, record_set.id)
|
||||
|> Ecto.Changeset.put_change(:record_id, record_id)
|
||||
|> Ecto.Changeset.unique_constraint([:record_set_id, :record_id])
|
||||
|> Changeset.put_change(:record_set_id, record_set.id)
|
||||
|> Changeset.put_change(:record_id, record_id)
|
||||
|> Changeset.unique_constraint([:record_set_id, :record_id])
|
||||
|> Repo.insert()
|
||||
|> case do
|
||||
{:ok, _item} -> {:ok, get_record_set!(record_set.id)}
|
||||
@@ -182,11 +183,11 @@ defmodule MusicLibrary.RecordSets do
|
||||
|
||||
Repo.transaction(fn ->
|
||||
item_a
|
||||
|> Ecto.Changeset.change(position: item_b.position)
|
||||
|> Changeset.change(position: item_b.position)
|
||||
|> Repo.update!()
|
||||
|
||||
item_b
|
||||
|> Ecto.Changeset.change(position: item_a.position)
|
||||
|> Changeset.change(position: item_a.position)
|
||||
|> Repo.update!()
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
defmodule MusicLibrary.Worker.FetchArtistInfo do
|
||||
use Oban.Worker, queue: :default, max_attempts: 3
|
||||
|
||||
alias MusicLibrary.Artists
|
||||
alias MusicLibrary.Records.Similarity
|
||||
|
||||
@impl Oban.Worker
|
||||
def perform(%Oban.Job{args: %{"id" => artist_id}}) do
|
||||
with {:ok, _artist_info} <- MusicLibrary.Artists.refresh_artist_info(artist_id),
|
||||
{:ok, _artist_info} <- MusicLibrary.Artists.refresh_wikipedia_data(artist_id),
|
||||
{:ok, _artist_info} <- MusicLibrary.Artists.refresh_image(artist_id),
|
||||
{:ok, _artist_info} <- MusicLibrary.Artists.refresh_lastfm_data(artist_id) do
|
||||
with {:ok, _artist_info} <- Artists.refresh_artist_info(artist_id),
|
||||
{:ok, _artist_info} <- Artists.refresh_wikipedia_data(artist_id),
|
||||
{:ok, _artist_info} <- Artists.refresh_image(artist_id),
|
||||
{:ok, _artist_info} <- Artists.refresh_lastfm_data(artist_id) do
|
||||
Similarity.regenerate_artist_embeddings(artist_id)
|
||||
else
|
||||
{:error, :no_english_wikipedia} -> {:cancel, :no_english_wikipedia}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
defmodule MusicLibrary.Worker.RecordRefreshMusicBrainzData do
|
||||
use Oban.Worker, queue: :music_brainz, max_attempts: 3
|
||||
|
||||
alias MusicLibrary.Records
|
||||
|
||||
@impl Oban.Worker
|
||||
def perform(%Oban.Job{args: %{"id" => record_id}}) do
|
||||
record = MusicLibrary.Records.get_record!(record_id)
|
||||
record = Records.get_record!(record_id)
|
||||
|
||||
with {:ok, updated_record} <- MusicLibrary.Records.refresh_musicbrainz_data(record) do
|
||||
MusicLibrary.Records.notify_update(updated_record)
|
||||
with {:ok, updated_record} <- Records.refresh_musicbrainz_data(record) do
|
||||
Records.notify_update(updated_record)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
defmodule MusicLibrary.Worker.RefreshCover do
|
||||
use Oban.Worker, queue: :heavy_writes, max_attempts: 3
|
||||
|
||||
alias MusicLibrary.Records
|
||||
|
||||
@impl Oban.Worker
|
||||
def perform(%Oban.Job{args: %{"id" => record_id}}) do
|
||||
record = MusicLibrary.Records.get_record!(record_id)
|
||||
record = Records.get_record!(record_id)
|
||||
|
||||
case MusicLibrary.Records.refresh_cover(record) do
|
||||
case Records.refresh_cover(record) do
|
||||
{:ok, updated_record} ->
|
||||
MusicLibrary.Records.notify_update(updated_record)
|
||||
Records.notify_update(updated_record)
|
||||
|
||||
{:error, :cover_not_available} ->
|
||||
{:cancel, :cover_not_available}
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule MusicLibraryWeb.Components.Chat do
|
||||
|
||||
alias MusicLibrary.Chats
|
||||
alias MusicLibraryWeb.Markdown
|
||||
alias Phoenix.LiveView
|
||||
|
||||
def open(id), do: Fluxon.open_dialog(id)
|
||||
|
||||
@@ -386,13 +387,13 @@ defmodule MusicLibraryWeb.Components.Chat do
|
||||
|
||||
Task.Supervisor.start_child(MusicLibrary.TaskSupervisor, fn ->
|
||||
case chat_module.stream_response(stream_messages, chat_context, fn chunk ->
|
||||
Phoenix.LiveView.send_update(parent_pid, __MODULE__,
|
||||
LiveView.send_update(parent_pid, __MODULE__,
|
||||
id: component_id,
|
||||
chunk: chunk
|
||||
)
|
||||
end) do
|
||||
:ok ->
|
||||
Phoenix.LiveView.send_update(parent_pid, __MODULE__,
|
||||
LiveView.send_update(parent_pid, __MODULE__,
|
||||
id: component_id,
|
||||
done: true
|
||||
)
|
||||
@@ -400,7 +401,7 @@ defmodule MusicLibraryWeb.Components.Chat do
|
||||
{:error, reason} ->
|
||||
Logger.error("Chat streaming error: #{reason}")
|
||||
|
||||
Phoenix.LiveView.send_update(parent_pid, __MODULE__,
|
||||
LiveView.send_update(parent_pid, __MODULE__,
|
||||
id: component_id,
|
||||
error: gettext("Something went wrong. Please try again.")
|
||||
)
|
||||
|
||||
+7
-5
@@ -3,6 +3,8 @@ defmodule OpenAI.API do
|
||||
Low-level HTTP client for the OpenAI API (chat completions, streaming responses, embeddings).
|
||||
"""
|
||||
|
||||
alias Req.Request
|
||||
|
||||
require Logger
|
||||
|
||||
@spec gpt(OpenAI.Completion.t(), OpenAI.Config.t()) :: {:ok, map()} | {:error, term()}
|
||||
@@ -52,9 +54,9 @@ defmodule OpenAI.API do
|
||||
temperature: temperature
|
||||
},
|
||||
into: fn {:data, data}, {req, resp} ->
|
||||
buffer = Req.Request.get_private(req, :sse_buffer, "")
|
||||
buffer = Request.get_private(req, :sse_buffer, "")
|
||||
{events, buffer} = ServerSentEvents.parse(buffer <> data)
|
||||
req = Req.Request.put_private(req, :sse_buffer, buffer)
|
||||
req = Request.put_private(req, :sse_buffer, buffer)
|
||||
|
||||
decode_events(events, cb, req, resp)
|
||||
end
|
||||
@@ -119,10 +121,10 @@ defmodule OpenAI.API do
|
||||
base_url: "https://api.openai.com",
|
||||
auth: {:bearer, config.api_key}
|
||||
)
|
||||
|> Req.Request.merge_options(config.req_options)
|
||||
|> Request.merge_options(config.req_options)
|
||||
|> Req.RateLimiter.attach(name: :open_ai, cooldown: config.api_cooldown)
|
||||
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Req.Request.append_response_steps(log_error: &log_error/1)
|
||||
|> Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Request.append_response_steps(log_error: &log_error/1)
|
||||
end
|
||||
|
||||
defp decode_responses_event(json, cb) do
|
||||
|
||||
+10
-8
@@ -20,6 +20,8 @@ defmodule Req.RateLimiter do
|
||||
Pass `:clock` in `attach/2` opts to override (useful in tests).
|
||||
"""
|
||||
|
||||
alias Req.Request
|
||||
|
||||
@table __MODULE__
|
||||
@default_clock Req.RateLimiter.SystemClock
|
||||
|
||||
@@ -44,25 +46,25 @@ defmodule Req.RateLimiter do
|
||||
* `:clock` - module implementing `Req.RateLimiter.Clock` (default: `Req.RateLimiter.SystemClock`)
|
||||
|
||||
"""
|
||||
@spec attach(Req.Request.t(), attach_opts()) :: Req.Request.t()
|
||||
@spec attach(Request.t(), attach_opts()) :: Request.t()
|
||||
def attach(request, opts) do
|
||||
name = Keyword.fetch!(opts, :name)
|
||||
cooldown = Keyword.fetch!(opts, :cooldown)
|
||||
clock = Keyword.get(opts, :clock, @default_clock)
|
||||
|
||||
request
|
||||
|> Req.Request.put_private(:rate_limiter_name, name)
|
||||
|> Req.Request.put_private(:rate_limiter_cooldown, cooldown)
|
||||
|> Req.Request.put_private(:rate_limiter_clock, clock)
|
||||
|> Req.Request.prepend_request_steps(rate_limiter: &throttle/1)
|
||||
|> Request.put_private(:rate_limiter_name, name)
|
||||
|> Request.put_private(:rate_limiter_cooldown, cooldown)
|
||||
|> Request.put_private(:rate_limiter_clock, clock)
|
||||
|> Request.prepend_request_steps(rate_limiter: &throttle/1)
|
||||
end
|
||||
|
||||
defp throttle(request) do
|
||||
cooldown = Req.Request.get_private(request, :rate_limiter_cooldown)
|
||||
cooldown = Request.get_private(request, :rate_limiter_cooldown)
|
||||
|
||||
if cooldown > 0 do
|
||||
name = Req.Request.get_private(request, :rate_limiter_name)
|
||||
clock = Req.Request.get_private(request, :rate_limiter_clock)
|
||||
name = Request.get_private(request, :rate_limiter_name)
|
||||
clock = Request.get_private(request, :rate_limiter_clock)
|
||||
now = clock.now()
|
||||
|
||||
case :ets.lookup(@table, name) do
|
||||
|
||||
@@ -3,6 +3,8 @@ defmodule Wikipedia.API do
|
||||
Interface to the Wikidata and Wikipedia APIs.
|
||||
"""
|
||||
|
||||
alias Req.Request
|
||||
|
||||
require Logger
|
||||
|
||||
@spec get_wikipedia_title(String.t(), Wikipedia.Config.t()) ::
|
||||
@@ -75,10 +77,10 @@ defmodule Wikipedia.API do
|
||||
max_retries: 1,
|
||||
user_agent: config.user_agent
|
||||
)
|
||||
|> Req.Request.merge_options(config.req_options)
|
||||
|> Request.merge_options(config.req_options)
|
||||
|> Req.RateLimiter.attach(name: :wikipedia, cooldown: config.api_cooldown)
|
||||
|> Req.Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Req.Request.append_response_steps(log_error: &log_error/1)
|
||||
|> Request.append_request_steps(log_attempt: &log_attempt/1)
|
||||
|> Request.append_response_steps(log_error: &log_error/1)
|
||||
end
|
||||
|
||||
defp get_request(request) do
|
||||
|
||||
@@ -3,6 +3,7 @@ defmodule MusicLibrary.Chats.ArtistChatTest do
|
||||
|
||||
alias MusicLibrary.Artists.{Artist, ArtistInfo}
|
||||
alias MusicLibrary.Chats.ArtistChat
|
||||
alias Plug.Conn
|
||||
|
||||
defp build_artist(attrs \\ %{}) do
|
||||
defaults = %{
|
||||
@@ -44,13 +45,13 @@ defmodule MusicLibrary.Chats.ArtistChatTest do
|
||||
|
||||
defp stub_and_capture_instructions(test_pid) do
|
||||
Req.Test.stub(OpenAI.API, fn conn ->
|
||||
{:ok, body, conn} = Plug.Conn.read_body(conn)
|
||||
{:ok, body, conn} = Conn.read_body(conn)
|
||||
request = JSON.decode!(body)
|
||||
send(test_pid, {:captured_instructions, request["instructions"]})
|
||||
|
||||
conn
|
||||
|> Plug.Conn.put_resp_content_type("text/event-stream")
|
||||
|> Plug.Conn.send_resp(200, completed_response())
|
||||
|> Conn.put_resp_content_type("text/event-stream")
|
||||
|> Conn.send_resp(200, completed_response())
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ defmodule MusicLibrary.Chats.CollectionChatTest do
|
||||
use ExUnit.Case
|
||||
|
||||
alias MusicLibrary.Chats.CollectionChat
|
||||
alias Plug.Conn
|
||||
|
||||
defp sse_event(type, data) do
|
||||
json = JSON.encode!(%{type: type, delta: data})
|
||||
@@ -15,13 +16,13 @@ defmodule MusicLibrary.Chats.CollectionChatTest do
|
||||
|
||||
defp stub_and_capture_instructions(test_pid) do
|
||||
Req.Test.stub(OpenAI.API, fn conn ->
|
||||
{:ok, body, conn} = Plug.Conn.read_body(conn)
|
||||
{:ok, body, conn} = Conn.read_body(conn)
|
||||
request = JSON.decode!(body)
|
||||
send(test_pid, {:captured_instructions, request["instructions"]})
|
||||
|
||||
conn
|
||||
|> Plug.Conn.put_resp_content_type("text/event-stream")
|
||||
|> Plug.Conn.send_resp(200, completed_response())
|
||||
|> Conn.put_resp_content_type("text/event-stream")
|
||||
|> Conn.send_resp(200, completed_response())
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule MusicLibrary.Chats.RecordChatTest do
|
||||
alias MusicLibrary.Artists.Artist
|
||||
alias MusicLibrary.Chats.RecordChat
|
||||
alias MusicLibrary.Records.Record
|
||||
alias Plug.Conn
|
||||
|
||||
defp build_record(attrs \\ %{}) do
|
||||
defaults = %{
|
||||
@@ -36,13 +37,13 @@ defmodule MusicLibrary.Chats.RecordChatTest do
|
||||
|
||||
defp stub_and_capture_instructions(test_pid) do
|
||||
Req.Test.stub(OpenAI.API, fn conn ->
|
||||
{:ok, body, conn} = Plug.Conn.read_body(conn)
|
||||
{:ok, body, conn} = Conn.read_body(conn)
|
||||
request = JSON.decode!(body)
|
||||
send(test_pid, {:captured_instructions, request["instructions"]})
|
||||
|
||||
conn
|
||||
|> Plug.Conn.put_resp_content_type("text/event-stream")
|
||||
|> Plug.Conn.send_resp(200, completed_response())
|
||||
|> Conn.put_resp_content_type("text/event-stream")
|
||||
|> Conn.send_resp(200, completed_response())
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ defmodule MusicLibraryWeb.Components.ChatTest do
|
||||
alias MusicBrainz.Fixtures.ReleaseGroup
|
||||
alias MusicLibrary.Chats
|
||||
alias MusicLibraryWeb.Components.Chat
|
||||
alias Req.Test
|
||||
|
||||
@component_id "record-chat"
|
||||
|
||||
@@ -16,7 +17,7 @@ defmodule MusicLibraryWeb.Components.ChatTest do
|
||||
# `OpenAI.API`. A default stub that returns an empty SSE stream prevents
|
||||
# Req.Test from raising inside the supervised Task process and keeps
|
||||
# test output noise-free. Individual tests can override this as needed.
|
||||
Req.Test.stub(OpenAI.API, fn conn ->
|
||||
Test.stub(OpenAI.API, fn conn ->
|
||||
conn
|
||||
|> Plug.Conn.put_resp_content_type("text/event-stream")
|
||||
|> Plug.Conn.send_resp(
|
||||
@@ -32,22 +33,22 @@ defmodule MusicLibraryWeb.Components.ChatTest do
|
||||
release_group = ReleaseGroup.release_group(:marbles)
|
||||
release = ReleaseFixtures.release(:marbles)
|
||||
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
cond do
|
||||
conn.host == "coverartarchive.org" ->
|
||||
Plug.Conn.send_resp(conn, 200, marbles_cover_data())
|
||||
|
||||
match?([_, _, "release-group", ^release_group_id], conn.path_info) ->
|
||||
Req.Test.json(conn, release_group)
|
||||
Test.json(conn, release_group)
|
||||
|
||||
match?([_, _, "release"], conn.path_info) ->
|
||||
Req.Test.json(conn, ReleaseGroup.release_group_releases(:marbles))
|
||||
Test.json(conn, ReleaseGroup.release_group_releases(:marbles))
|
||||
|
||||
match?([_, _, "release", _], conn.path_info) ->
|
||||
Req.Test.json(conn, release)
|
||||
Test.json(conn, release)
|
||||
|
||||
true ->
|
||||
Req.Test.json(conn, %{})
|
||||
Test.json(conn, %{})
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -164,7 +165,7 @@ defmodule MusicLibraryWeb.Components.ChatTest do
|
||||
test "streaming error propagates to the component as user-facing text", %{conn: conn} do
|
||||
record = setup_record()
|
||||
|
||||
Req.Test.stub(OpenAI.API, fn conn ->
|
||||
Test.stub(OpenAI.API, fn conn ->
|
||||
Plug.Conn.send_resp(conn, 500, JSON.encode!(%{"error" => "internal server error"}))
|
||||
end)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ defmodule MusicLibraryWeb.Components.ReleaseTest do
|
||||
|
||||
alias MusicBrainz.Fixtures.Release, as: ReleaseFixtures
|
||||
alias MusicLibrary.Secrets
|
||||
alias Req.Test
|
||||
|
||||
@finished_at ~U[2026-03-15 21:00:00Z]
|
||||
# `@sheet_form` scopes form-change events to the LiveComponent; button
|
||||
@@ -24,13 +25,13 @@ defmodule MusicLibraryWeb.Components.ReleaseTest do
|
||||
@sheet_form "#release-with-tracks-sheet-form"
|
||||
|
||||
defp stub_musicbrainz_release(_) do
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
case conn.request_path do
|
||||
"/ws/2/release/" <> _id ->
|
||||
Req.Test.json(conn, ReleaseFixtures.release_with_media(:marbles))
|
||||
Test.json(conn, ReleaseFixtures.release_with_media(:marbles))
|
||||
|
||||
_ ->
|
||||
Req.Test.json(conn, %{})
|
||||
Test.json(conn, %{})
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -40,11 +41,11 @@ defmodule MusicLibraryWeb.Components.ReleaseTest do
|
||||
defp capture_lastfm_scrobble(_) do
|
||||
test_pid = self()
|
||||
|
||||
Req.Test.stub(LastFm.API, fn conn ->
|
||||
Test.stub(LastFm.API, fn conn ->
|
||||
{:ok, body, conn} = Plug.Conn.read_body(conn)
|
||||
params = URI.decode_query(body)
|
||||
send(test_pid, {:lastfm_scrobble, params})
|
||||
Req.Test.json(conn, %{"scrobbles" => %{"@attr" => %{"accepted" => 1}}})
|
||||
Test.json(conn, %{"scrobbles" => %{"@attr" => %{"accepted" => 1}}})
|
||||
end)
|
||||
|
||||
:ok
|
||||
|
||||
@@ -8,6 +8,7 @@ defmodule MusicLibraryWeb.ArtistLive.ShowTest do
|
||||
alias MusicLibrary.Artists
|
||||
alias MusicLibrary.Assets
|
||||
alias MusicLibrary.Assets.Asset
|
||||
alias Req.Test
|
||||
|
||||
defp fill_collection(_config) do
|
||||
collection_record =
|
||||
@@ -34,13 +35,13 @@ defmodule MusicLibraryWeb.ArtistLive.ShowTest do
|
||||
conn: conn,
|
||||
artist_musicbrainz_id: artist_musicbrainz_id
|
||||
} do
|
||||
Req.Test.stub(LastFm.API, fn conn ->
|
||||
Test.stub(LastFm.API, fn conn ->
|
||||
case Map.get(conn.params, "method") do
|
||||
"artist.getInfo" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_info())
|
||||
Test.json(conn, Fixtures.Artist.get_info())
|
||||
|
||||
"artist.getSimilar" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -60,13 +61,13 @@ defmodule MusicLibraryWeb.ArtistLive.ShowTest do
|
||||
|> Ecto.Changeset.change(wikipedia_data: Wikipedia.Fixtures.article_summary())
|
||||
|> MusicLibrary.Repo.update!()
|
||||
|
||||
Req.Test.stub(LastFm.API, fn conn ->
|
||||
Test.stub(LastFm.API, fn conn ->
|
||||
case Map.get(conn.params, "method") do
|
||||
"artist.getInfo" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_info())
|
||||
Test.json(conn, Fixtures.Artist.get_info())
|
||||
|
||||
"artist.getSimilar" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -82,13 +83,13 @@ defmodule MusicLibraryWeb.ArtistLive.ShowTest do
|
||||
conn: conn,
|
||||
artist_musicbrainz_id: artist_musicbrainz_id
|
||||
} do
|
||||
Req.Test.stub(LastFm.API, fn conn ->
|
||||
Test.stub(LastFm.API, fn conn ->
|
||||
case Map.get(conn.params, "method") do
|
||||
"artist.getInfo" ->
|
||||
Req.Test.transport_error(conn, :timeout)
|
||||
Test.transport_error(conn, :timeout)
|
||||
|
||||
"artist.getSimilar" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -104,13 +105,13 @@ defmodule MusicLibraryWeb.ArtistLive.ShowTest do
|
||||
conn: conn,
|
||||
artist_musicbrainz_id: artist_musicbrainz_id
|
||||
} do
|
||||
Req.Test.stub(LastFm.API, fn conn ->
|
||||
Test.stub(LastFm.API, fn conn ->
|
||||
case Map.get(conn.params, "method") do
|
||||
"artist.getInfo" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_info())
|
||||
Test.json(conn, Fixtures.Artist.get_info())
|
||||
|
||||
"artist.getSimilar" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -136,13 +137,13 @@ defmodule MusicLibraryWeb.ArtistLive.ShowTest do
|
||||
other_collection_record =
|
||||
record_with_artist("Porcupine Tree", %{purchased_at: DateTime.utc_now()})
|
||||
|
||||
Req.Test.stub(LastFm.API, fn conn ->
|
||||
Test.stub(LastFm.API, fn conn ->
|
||||
case Map.get(conn.params, "method") do
|
||||
"artist.getInfo" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_info())
|
||||
Test.json(conn, Fixtures.Artist.get_info())
|
||||
|
||||
"artist.getSimilar" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -175,9 +176,9 @@ defmodule MusicLibraryWeb.ArtistLive.ShowTest do
|
||||
conn: conn,
|
||||
artist_musicbrainz_id: musicbrainz_id
|
||||
} do
|
||||
Req.Test.stub(BraveSearch.API, fn conn ->
|
||||
Test.stub(BraveSearch.API, fn conn ->
|
||||
assert conn.request_path == "/res/v1/images/search"
|
||||
Req.Test.json(conn, BraveSearch.Fixtures.search_images_response())
|
||||
Test.json(conn, BraveSearch.Fixtures.search_images_response())
|
||||
end)
|
||||
|
||||
{:ok, view, _html} = live(conn, ~p"/artists/#{musicbrainz_id}/edit")
|
||||
@@ -196,8 +197,8 @@ defmodule MusicLibraryWeb.ArtistLive.ShowTest do
|
||||
conn: conn,
|
||||
artist_musicbrainz_id: musicbrainz_id
|
||||
} do
|
||||
Req.Test.stub(BraveSearch.API, fn conn ->
|
||||
Req.Test.transport_error(conn, :timeout)
|
||||
Test.stub(BraveSearch.API, fn conn ->
|
||||
Test.transport_error(conn, :timeout)
|
||||
end)
|
||||
|
||||
{:ok, view, _html} = live(conn, ~p"/artists/#{musicbrainz_id}/edit")
|
||||
@@ -243,10 +244,10 @@ defmodule MusicLibraryWeb.ArtistLive.ShowTest do
|
||||
} do
|
||||
raven_binary = raven_cover_data()
|
||||
|
||||
Req.Test.stub(BraveSearch.API, fn conn ->
|
||||
Test.stub(BraveSearch.API, fn conn ->
|
||||
case conn.request_path do
|
||||
"/res/v1/images/search" ->
|
||||
Req.Test.json(conn, BraveSearch.Fixtures.search_images_response())
|
||||
Test.json(conn, BraveSearch.Fixtures.search_images_response())
|
||||
|
||||
_ ->
|
||||
Plug.Conn.send_resp(conn, 200, raven_binary)
|
||||
@@ -275,13 +276,13 @@ defmodule MusicLibraryWeb.ArtistLive.ShowTest do
|
||||
end
|
||||
|
||||
defp stub_last_fm(_config) do
|
||||
Req.Test.stub(LastFm.API, fn conn ->
|
||||
Test.stub(LastFm.API, fn conn ->
|
||||
case Map.get(conn.params, "method") do
|
||||
"artist.getInfo" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_info())
|
||||
Test.json(conn, Fixtures.Artist.get_info())
|
||||
|
||||
"artist.getSimilar" ->
|
||||
Req.Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
Test.json(conn, Fixtures.Artist.get_similar_artists())
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ defmodule MusicLibraryWeb.CollectionLive.IndexTest do
|
||||
alias MusicLibrary.Assets.{Image, Transform}
|
||||
alias MusicLibrary.Records.Record
|
||||
alias MusicLibrary.Worker.ImportFromMusicbrainzReleaseGroup
|
||||
alias Req.Test
|
||||
|
||||
# make it a multiple of 4 for easier calculations
|
||||
@default_records_page_size 4
|
||||
@@ -274,8 +275,8 @@ defmodule MusicLibraryWeb.CollectionLive.IndexTest do
|
||||
end
|
||||
|
||||
test "pre-fills the search query from import_query param", %{conn: conn} do
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Req.Test.json(conn, %{"release-groups" => [], "count" => 0})
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.json(conn, %{"release-groups" => [], "count" => 0})
|
||||
end)
|
||||
|
||||
conn
|
||||
@@ -495,10 +496,10 @@ defmodule MusicLibraryWeb.CollectionLive.IndexTest do
|
||||
end
|
||||
|
||||
defp stub_release_group_search do
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
case conn.path_info do
|
||||
[_ws, _version, "release-group"] ->
|
||||
Req.Test.json(conn, release_group_search_results())
|
||||
Test.json(conn, release_group_search_results())
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -511,16 +512,16 @@ defmodule MusicLibraryWeb.CollectionLive.IndexTest do
|
||||
release_group_releases = release_group_releases(:marbles)
|
||||
cover_data = marbles_cover_data()
|
||||
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
case conn.path_info do
|
||||
[_ws, _version, "release-group", ^first_id] ->
|
||||
Req.Test.json(conn, release_group)
|
||||
Test.json(conn, release_group)
|
||||
|
||||
[_ws, _version, "release-group"] ->
|
||||
Req.Test.json(conn, release_group_search_results())
|
||||
Test.json(conn, release_group_search_results())
|
||||
|
||||
[_ws, _version, "release"] ->
|
||||
Req.Test.json(conn, release_group_releases)
|
||||
Test.json(conn, release_group_releases)
|
||||
|
||||
[_release_group, ^first_id, "front"] ->
|
||||
Plug.Conn.send_resp(conn, 200, cover_data)
|
||||
@@ -560,21 +561,21 @@ defmodule MusicLibraryWeb.CollectionLive.IndexTest do
|
||||
|
||||
cover_data = marbles_cover_data()
|
||||
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
case conn.path_info do
|
||||
[_ws, _version, "release-group", ^release_group_id] ->
|
||||
Req.Test.json(conn, release_group)
|
||||
Test.json(conn, release_group)
|
||||
|
||||
[_ws, _version, "release", ^release_id] ->
|
||||
Req.Test.json(conn, release)
|
||||
Test.json(conn, release)
|
||||
|
||||
[_ws, _version, "release"] ->
|
||||
if conn.params["query"] do
|
||||
# barcode scan
|
||||
Req.Test.json(conn, releases)
|
||||
Test.json(conn, releases)
|
||||
else
|
||||
# Search by release group ID
|
||||
Req.Test.json(conn, release_group_releases)
|
||||
Test.json(conn, release_group_releases)
|
||||
end
|
||||
|
||||
[_release_group, ^release_group_id, "front"] ->
|
||||
|
||||
@@ -4,18 +4,19 @@ defmodule MusicLibraryWeb.ScrobbleLive.IndexTest do
|
||||
import Phoenix.LiveViewTest, only: [render: 1, render_submit: 1, render_click: 3, form: 3]
|
||||
|
||||
alias MusicBrainz.Fixtures.ReleaseGroup
|
||||
alias Req.Test
|
||||
|
||||
defp stub_search_results(_) do
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
case conn.request_path do
|
||||
"/ws/2/release-group" ->
|
||||
Req.Test.json(conn, ReleaseGroup.release_group_search_results())
|
||||
Test.json(conn, ReleaseGroup.release_group_search_results())
|
||||
|
||||
"/ws/2/release" ->
|
||||
Req.Test.json(conn, ReleaseGroup.release_group_releases(:marbles))
|
||||
Test.json(conn, ReleaseGroup.release_group_releases(:marbles))
|
||||
|
||||
_ ->
|
||||
Req.Test.json(conn, %{})
|
||||
Test.json(conn, %{})
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -23,13 +24,13 @@ defmodule MusicLibraryWeb.ScrobbleLive.IndexTest do
|
||||
end
|
||||
|
||||
defp stub_empty_search_results(_) do
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
case conn.request_path do
|
||||
"/ws/2/release-group" ->
|
||||
Req.Test.json(conn, %{"count" => 0, "release-groups" => []})
|
||||
Test.json(conn, %{"count" => 0, "release-groups" => []})
|
||||
|
||||
_ ->
|
||||
Req.Test.json(conn, %{})
|
||||
Test.json(conn, %{})
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
@@ -5,17 +5,18 @@ defmodule MusicLibraryWeb.ScrobbleLive.ShowTest do
|
||||
|
||||
alias MusicBrainz.Fixtures.Release, as: ReleaseFixtures
|
||||
alias MusicLibrary.Secrets
|
||||
alias Req.Test
|
||||
|
||||
@release_id ReleaseFixtures.release_id(:marbles)
|
||||
|
||||
defp stub_musicbrainz_release(_) do
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
case conn.request_path do
|
||||
"/ws/2/release/" <> _id ->
|
||||
Req.Test.json(conn, ReleaseFixtures.release_with_media(:marbles))
|
||||
Test.json(conn, ReleaseFixtures.release_with_media(:marbles))
|
||||
|
||||
_ ->
|
||||
Req.Test.json(conn, %{})
|
||||
Test.json(conn, %{})
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -23,7 +24,7 @@ defmodule MusicLibraryWeb.ScrobbleLive.ShowTest do
|
||||
end
|
||||
|
||||
defp stub_musicbrainz_release_error(_) do
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
Plug.Conn.send_resp(conn, 404, "Not Found")
|
||||
end)
|
||||
|
||||
@@ -31,16 +32,16 @@ defmodule MusicLibraryWeb.ScrobbleLive.ShowTest do
|
||||
end
|
||||
|
||||
defp stub_lastfm_scrobble(_) do
|
||||
Req.Test.stub(LastFm.API, fn conn ->
|
||||
Req.Test.json(conn, %{"scrobbles" => %{"@attr" => %{"accepted" => 1}}})
|
||||
Test.stub(LastFm.API, fn conn ->
|
||||
Test.json(conn, %{"scrobbles" => %{"@attr" => %{"accepted" => 1}}})
|
||||
end)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
defp stub_lastfm_scrobble_error(_) do
|
||||
Req.Test.stub(LastFm.API, fn conn ->
|
||||
Req.Test.json(conn, %{"error" => 11, "message" => "Service temporarily unavailable"})
|
||||
Test.stub(LastFm.API, fn conn ->
|
||||
Test.json(conn, %{"error" => 11, "message" => "Service temporarily unavailable"})
|
||||
end)
|
||||
|
||||
:ok
|
||||
|
||||
@@ -9,6 +9,7 @@ defmodule MusicLibraryWeb.WishlistLive.IndexTest do
|
||||
|
||||
alias MusicLibrary.Records.Record
|
||||
alias MusicLibrary.Worker.ImportFromMusicbrainzReleaseGroup
|
||||
alias Req.Test
|
||||
|
||||
defp fill_wishlist(_) do
|
||||
records = Enum.map(1..5, fn _ -> record(%{purchased_at: nil}) end)
|
||||
@@ -110,10 +111,10 @@ defmodule MusicLibraryWeb.WishlistLive.IndexTest do
|
||||
end
|
||||
|
||||
defp stub_release_group_search do
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
case conn.path_info do
|
||||
[_ws, _version, "release-group"] ->
|
||||
Req.Test.json(conn, release_group_search_results())
|
||||
Test.json(conn, release_group_search_results())
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -126,16 +127,16 @@ defmodule MusicLibraryWeb.WishlistLive.IndexTest do
|
||||
release_group_releases = release_group_releases(:marbles)
|
||||
cover_data = marbles_cover_data()
|
||||
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
case conn.path_info do
|
||||
[_ws, _version, "release-group", ^first_id] ->
|
||||
Req.Test.json(conn, release_group)
|
||||
Test.json(conn, release_group)
|
||||
|
||||
[_ws, _version, "release-group"] ->
|
||||
Req.Test.json(conn, release_group_search_results())
|
||||
Test.json(conn, release_group_search_results())
|
||||
|
||||
[_ws, _version, "release"] ->
|
||||
Req.Test.json(conn, release_group_releases)
|
||||
Test.json(conn, release_group_releases)
|
||||
|
||||
[_release_group, ^first_id, "front"] ->
|
||||
Plug.Conn.send_resp(conn, 200, cover_data)
|
||||
|
||||
@@ -10,6 +10,7 @@ defmodule MusicLibraryWeb.LiveHelpers.RecordActionsTest do
|
||||
alias MusicLibrary.Chats
|
||||
alias MusicLibrary.Records
|
||||
alias MusicLibrary.Records.Similarity
|
||||
alias Req.Test
|
||||
|
||||
# A MusicBrainz stub that returns valid fixture responses for every route
|
||||
# the Collection Show page touches during `handle_params` and via async
|
||||
@@ -20,23 +21,23 @@ defmodule MusicLibraryWeb.LiveHelpers.RecordActionsTest do
|
||||
release = ReleaseFixtures.release(:marbles)
|
||||
cover_data = Keyword.get(opts, :cover_data, marbles_cover_data())
|
||||
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
cond do
|
||||
# Cover art archive returns raw image bytes
|
||||
conn.host == "coverartarchive.org" ->
|
||||
Plug.Conn.send_resp(conn, 200, cover_data)
|
||||
|
||||
match?([_, _, "release-group", ^release_group_id], conn.path_info) ->
|
||||
Req.Test.json(conn, release_group)
|
||||
Test.json(conn, release_group)
|
||||
|
||||
match?([_, _, "release"], conn.path_info) ->
|
||||
Req.Test.json(conn, ReleaseGroup.release_group_releases(:marbles))
|
||||
Test.json(conn, ReleaseGroup.release_group_releases(:marbles))
|
||||
|
||||
match?([_, _, "release", _], conn.path_info) ->
|
||||
Req.Test.json(conn, release)
|
||||
Test.json(conn, release)
|
||||
|
||||
true ->
|
||||
Req.Test.json(conn, %{})
|
||||
Test.json(conn, %{})
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -58,13 +59,13 @@ defmodule MusicLibraryWeb.LiveHelpers.RecordActionsTest do
|
||||
release_group_id = record.musicbrainz_id
|
||||
|
||||
# Initial page load needs a valid response, then the refresh request fails.
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
case conn.path_info do
|
||||
[_, _, "release-group", ^release_group_id] ->
|
||||
Req.Test.transport_error(conn, :timeout)
|
||||
Test.transport_error(conn, :timeout)
|
||||
|
||||
_ ->
|
||||
Req.Test.json(conn, %{})
|
||||
Test.json(conn, %{})
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -94,16 +95,16 @@ defmodule MusicLibraryWeb.LiveHelpers.RecordActionsTest do
|
||||
release_group_id = record.musicbrainz_id
|
||||
release_group = ReleaseGroup.release_group(:marbles)
|
||||
|
||||
Req.Test.stub(MusicBrainz.API, fn conn ->
|
||||
Test.stub(MusicBrainz.API, fn conn ->
|
||||
cond do
|
||||
conn.host == "coverartarchive.org" ->
|
||||
Req.Test.transport_error(conn, :timeout)
|
||||
Test.transport_error(conn, :timeout)
|
||||
|
||||
match?([_, _, "release-group", ^release_group_id], conn.path_info) ->
|
||||
Req.Test.json(conn, release_group)
|
||||
Test.json(conn, release_group)
|
||||
|
||||
true ->
|
||||
Req.Test.json(conn, %{})
|
||||
Test.json(conn, %{})
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
defmodule MusicLibrary.Fixtures.Records do
|
||||
@moduledoc false
|
||||
|
||||
alias Discogs.Fixtures.Artist, as: DiscogsArtistFixture
|
||||
alias MusicBrainz.Fixtures.ReleaseGroup
|
||||
alias MusicLibrary.Assets
|
||||
alias MusicLibrary.Assets.Asset
|
||||
@@ -105,9 +106,9 @@ defmodule MusicLibrary.Fixtures.Records do
|
||||
|> Enum.into(%{
|
||||
id: musicbrainz_id,
|
||||
musicbrainz_data: MusicBrainz.Fixtures.Artist.get_artist(),
|
||||
discogs_data: Discogs.Fixtures.Artist.get_artist(),
|
||||
image_data: Discogs.Fixtures.Artist.image_data(),
|
||||
image_width: Discogs.Fixtures.Artist.image_width()
|
||||
discogs_data: DiscogsArtistFixture.get_artist(),
|
||||
image_data: DiscogsArtistFixture.image_data(),
|
||||
image_width: DiscogsArtistFixture.image_width()
|
||||
})
|
||||
|> MusicLibrary.Artists.create_artist_info()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user