diff --git a/lib/last_fm.ex b/lib/last_fm.ex index 907f74ae..1d4d6bce 100644 --- a/lib/last_fm.ex +++ b/lib/last_fm.ex @@ -1,5 +1,6 @@ defmodule LastFm do - alias LastFm.{API, Feed, Refresh, Scrobble} + alias LastFm.{API, Feed, Refresh, Scrobble, Track, Worker} + alias MusicLibrary.{BackgroundRepo, Repo} def get_scrobbled_tracks, do: Feed.all_tracks() @@ -7,9 +8,21 @@ defmodule LastFm do def refresh_scrobbled_tracks, do: Refresh.refresh() - def get_tracks(to_uts) do + def get_tracks(opts) do last_fm_config = last_fm_config() - API.get_recent_tracks(to_uts, last_fm_config) + API.get_recent_tracks(opts, last_fm_config) + end + + def lowest_scrobbled_at_uts do + Repo.aggregate(Track, :min, :scrobbled_at_uts) + end + + def backfill_scrobbled_tracks do + to_uts = lowest_scrobbled_at_uts() + + %{"to_uts" => to_uts} + |> Worker.BackfillScrobbledTracks.new() + |> BackgroundRepo.insert() end def get_artist_info(musicbrainz_id, name) do diff --git a/lib/last_fm/api.ex b/lib/last_fm/api.ex index c92aee1a..b426dfdb 100644 --- a/lib/last_fm/api.ex +++ b/lib/last_fm/api.ex @@ -51,11 +51,14 @@ defmodule LastFm.API do |> post_request() end - def get_recent_tracks(to_uts \\ nil, config) do + def get_recent_tracks(opts \\ [], config) do + to_uts = Keyword.get(opts, :to_uts) + limit = Keyword.get(opts, :limit, 50) + params = config |> base_params() - |> Keyword.merge(method: "user.getrecenttracks", limit: 50) + |> Keyword.merge(method: "user.getrecenttracks", limit: limit) params = if to_uts, do: Keyword.put(params, :to, to_uts), else: params diff --git a/lib/last_fm/import.ex b/lib/last_fm/import.ex index a5b7ede1..f65ab0b1 100644 --- a/lib/last_fm/import.ex +++ b/lib/last_fm/import.ex @@ -10,8 +10,8 @@ defmodule LastFm.Import do :last_fm_data ] - def batch(uts_to) do - with {:ok, tracks} <- LastFm.get_tracks(uts_to) do + def batch(opts) do + with {:ok, tracks} <- LastFm.get_tracks(opts) do track_params = tracks |> Enum.map(fn t -> Map.take(t, @insertable_fields) end) diff --git a/lib/last_fm/worker/backfill_scrobbled_tracks.ex b/lib/last_fm/worker/backfill_scrobbled_tracks.ex new file mode 100644 index 00000000..1c463164 --- /dev/null +++ b/lib/last_fm/worker/backfill_scrobbled_tracks.ex @@ -0,0 +1,29 @@ +defmodule LastFm.Worker.BackfillScrobbledTracks do + use Oban.Worker, queue: :heavy_writes, max_attempts: 3 + + alias MusicLibrary.BackgroundRepo + + @backfill_delay 5 + @batch_size 100 + + @impl Oban.Worker + def perform(%{args: %{"to_uts" => to_uts}}) do + # importing is an all or nothing operation, which means that we can + # use the returning count to determine if we reached the end of the backfilling + # process. + case LastFm.Import.batch(to_uts: to_uts, limit: @batch_size) do + {@batch_size, nil} -> + next_to_uts = LastFm.lowest_scrobbled_at_uts() + + %{"to_uts" => next_to_uts} + |> new(schedule_in: @backfill_delay) + |> BackgroundRepo.insert() + + {other_count, nil} when is_integer(other_count) -> + :ok + + error -> + error + end + end +end