Use stored scrobbled tracks

This commit is contained in:
Claudio Ortolina
2025-05-31 21:36:05 +01:00
parent 32956ca593
commit 1703f1cf70
5 changed files with 39 additions and 46 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ defmodule LastFm do
alias LastFm.{API, Feed, Refresh, Scrobble, Track, Worker}
alias MusicLibrary.{BackgroundRepo, Repo}
def get_scrobbled_tracks, do: Feed.all_tracks()
def get_scrobbled_tracks, do: Feed.all_tracks(100)
def subscribe_to_feed, do: Feed.subscribe()
+29 -19
View File
@@ -8,34 +8,44 @@ defmodule LastFm.Feed do
to one track at a time, and the timestamp has second-level precision.
"""
@spec create_table!() :: :ok | no_return
def create_table! do
__MODULE__ = :ets.new(__MODULE__, [:ordered_set, :named_table, :public])
:ok
end
import Ecto.Query
@insertable_fields [
:musicbrainz_id,
:title,
:artist,
:album,
:cover_url,
:scrobbled_at_uts,
:scrobbled_at_label,
:last_fm_data
]
@spec update([LastFm.Track.t()]) :: :ok | no_return
def update(tracks) do
data = Enum.map(tracks, fn t -> {t.scrobbled_at_uts, t} end)
track_params =
tracks
|> Enum.map(fn t -> Map.take(t, @insertable_fields) end)
|> Enum.map(&Map.to_list/1)
:ets.delete_all_objects(__MODULE__)
:ets.insert(__MODULE__, data)
# HACK: if two tracks happen to have the exact same scrobbled_at_uts,
# we move it by a sec.
MusicLibrary.Repo.insert_all(LastFm.Track, track_params,
on_conflict: :nothing,
conflict_target: [:scrobbled_at_uts, :title]
)
Phoenix.PubSub.broadcast(LastFm.PubSub, "feed:update", %{tracks: tracks})
end
@spec all_tracks() :: [LastFm.Track.t()]
def all_tracks do
m = [
{
{:_, :_},
[],
[{:element, 2, :"$_"}]
}
]
@spec all_tracks(non_neg_integer()) :: [LastFm.Track.t()]
def all_tracks(limit) do
q =
from t in LastFm.Track,
order_by: {:desc, t.scrobbled_at_uts},
limit: ^limit
# reversing to get tracks in DESC order
:ets.select_reverse(__MODULE__, m)
MusicLibrary.Repo.all(q)
end
@spec subscribe() :: :ok
+1 -22
View File
@@ -1,28 +1,7 @@
defmodule LastFm.Import do
@insertable_fields [
:musicbrainz_id,
:title,
:artist,
:album,
:cover_url,
:scrobbled_at_uts,
:scrobbled_at_label,
:last_fm_data
]
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)
|> Enum.map(&Map.to_list/1)
# HACK: if two tracks happen to have the exact same scrobbled_at_uts,
# we move it by a sec.
MusicLibrary.Repo.insert_all(LastFm.Track, track_params,
on_conflict: :nothing,
conflict_target: [:scrobbled_at_uts, :title]
)
LastFm.Feed.update(tracks)
end
end
end
-2
View File
@@ -7,8 +7,6 @@ defmodule LastFm.Supervisor do
@impl true
def init(config) do
:ok = LastFm.Feed.create_table!()
children = [
{Phoenix.PubSub, name: LastFm.PubSub},
{LastFm.Refresh, config}
+8 -2
View File
@@ -1,5 +1,5 @@
defmodule LastFm.FeedTest do
use ExUnit.Case, async: true
use MusicLibrary.DataCase
alias LastFm.{Album, Artist, Feed, Track}
@@ -46,7 +46,13 @@ defmodule LastFm.FeedTest do
test "it returns tracks in descending order of scrobble" do
:ok = Feed.update([@track_two, @track_one])
assert [@track_two, @track_one] == Feed.all_tracks()
track_two_scrobbled_at_uts = @track_two.scrobbled_at_uts
track_one_scrobbled_at_uts = @track_one.scrobbled_at_uts
assert [
%{scrobbled_at_uts: ^track_two_scrobbled_at_uts},
%{scrobbled_at_uts: ^track_one_scrobbled_at_uts}
] = Feed.all_tracks(10)
end
end
end