@@ -10,7 +10,7 @@ defmodule MusicLibrary.ListeningStats do
|
|||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
alias LastFm.Track
|
alias LastFm.Track
|
||||||
alias MusicLibrary.{Artists, Collection, Records.ArtistRecord, Repo, Wishlist}
|
alias MusicLibrary.{Artists, Collection, Records.ArtistRecord, Records.Record, Repo, Wishlist}
|
||||||
|
|
||||||
@pagination Application.compile_env!(:music_library, :pagination)
|
@pagination Application.compile_env!(:music_library, :pagination)
|
||||||
|
|
||||||
@@ -247,6 +247,42 @@ defmodule MusicLibrary.ListeningStats do
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec get_last_listened_track(Record.t()) :: Track.t() | nil
|
||||||
|
def get_last_listened_track(record) do
|
||||||
|
q =
|
||||||
|
from t in scrobbles_for_record_query(record),
|
||||||
|
order_by: [desc: t.scrobbled_at_uts],
|
||||||
|
limit: 1
|
||||||
|
|
||||||
|
Repo.one(q)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec play_count(Record.t()) :: non_neg_integer()
|
||||||
|
def play_count(record) do
|
||||||
|
record
|
||||||
|
|> scrobbles_for_record_query()
|
||||||
|
|> Repo.aggregate(:count)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp scrobbles_for_record_query(record) do
|
||||||
|
record_id = record.id
|
||||||
|
|
||||||
|
q =
|
||||||
|
from r in fragment("records, json_each(records.release_ids)"),
|
||||||
|
where: fragment("records.id = ?", ^record_id),
|
||||||
|
select: r.value
|
||||||
|
|
||||||
|
release_ids = Repo.all(q)
|
||||||
|
main_artist_name = Record.main_artist(record).name
|
||||||
|
record_title = record.title
|
||||||
|
|
||||||
|
from t in Track,
|
||||||
|
where: fragment("? ->> '$.musicbrainz_id'", t.album) in ^release_ids,
|
||||||
|
or_where:
|
||||||
|
fragment("? ->> '$.title'", t.album) == ^record_title and
|
||||||
|
fragment("? ->> '$.name'", t.artist) == ^main_artist_name
|
||||||
|
end
|
||||||
|
|
||||||
defp polyfill_artist(artist, musicbrainz_id) do
|
defp polyfill_artist(artist, musicbrainz_id) do
|
||||||
if is_nil(artist.musicbrainz_id) or artist.musicbrainz_id == "" do
|
if is_nil(artist.musicbrainz_id) or artist.musicbrainz_id == "" do
|
||||||
%{artist | musicbrainz_id: musicbrainz_id}
|
%{artist | musicbrainz_id: musicbrainz_id}
|
||||||
|
|||||||
@@ -278,42 +278,6 @@ defmodule MusicLibrary.Records do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec get_last_listened_track(Record.t()) :: LastFm.Track.t() | nil
|
|
||||||
def get_last_listened_track(record) do
|
|
||||||
q =
|
|
||||||
from t in scrobbles_for_record_query(record),
|
|
||||||
order_by: [desc: t.scrobbled_at_uts],
|
|
||||||
limit: 1
|
|
||||||
|
|
||||||
Repo.one(q)
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec play_count(Record.t()) :: non_neg_integer()
|
|
||||||
def play_count(record) do
|
|
||||||
record
|
|
||||||
|> scrobbles_for_record_query()
|
|
||||||
|> Repo.aggregate(:count)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp scrobbles_for_record_query(record) do
|
|
||||||
record_id = record.id
|
|
||||||
|
|
||||||
q =
|
|
||||||
from r in fragment("records, json_each(records.release_ids)"),
|
|
||||||
where: fragment("records.id = ?", ^record_id),
|
|
||||||
select: r.value
|
|
||||||
|
|
||||||
release_ids = Repo.all(q)
|
|
||||||
main_artist_name = Record.main_artist(record).name
|
|
||||||
record_title = record.title
|
|
||||||
|
|
||||||
from t in LastFm.Track,
|
|
||||||
where: fragment("? ->> '$.musicbrainz_id'", t.album) in ^release_ids,
|
|
||||||
or_where:
|
|
||||||
fragment("? ->> '$.title'", t.album) == ^record_title and
|
|
||||||
fragment("? ->> '$.name'", t.artist) == ^main_artist_name
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec refresh_cover(Record.t()) :: {:ok, Record.t()} | {:error, term()}
|
@spec refresh_cover(Record.t()) :: {:ok, Record.t()} | {:error, term()}
|
||||||
def refresh_cover(record) do
|
def refresh_cover(record) do
|
||||||
with {:ok, cover_data} <- MusicBrainz.get_cover_art({:url, record.cover_url}),
|
with {:ok, cover_data} <- MusicBrainz.get_cover_art({:url, record.cover_url}),
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ defmodule MusicLibraryWeb.CollectionLive.Show do
|
|||||||
similar_records: 1
|
similar_records: 1
|
||||||
]
|
]
|
||||||
|
|
||||||
alias MusicLibrary.{Records, RecordSets, ScrobbleActivity}
|
alias MusicLibrary.{ListeningStats, Records, RecordSets, ScrobbleActivity}
|
||||||
alias MusicLibrary.Records.Similarity
|
alias MusicLibrary.Records.Similarity
|
||||||
alias MusicLibraryWeb.ErrorMessages
|
alias MusicLibraryWeb.ErrorMessages
|
||||||
alias Phoenix.LiveView.JS
|
alias Phoenix.LiveView.JS
|
||||||
@@ -346,8 +346,8 @@ defmodule MusicLibraryWeb.CollectionLive.Show do
|
|||||||
@impl true
|
@impl true
|
||||||
def handle_params(%{"id" => id}, _, socket) do
|
def handle_params(%{"id" => id}, _, socket) do
|
||||||
record = Records.get_record!(id)
|
record = Records.get_record!(id)
|
||||||
last_listened_track = Records.get_last_listened_track(record)
|
last_listened_track = ListeningStats.get_last_listened_track(record)
|
||||||
play_count = Records.play_count(record) || 0
|
play_count = ListeningStats.play_count(record) || 0
|
||||||
|
|
||||||
socket =
|
socket =
|
||||||
if record.selected_release_id do
|
if record.selected_release_id do
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ defmodule MusicLibrary.ListeningStatsTest do
|
|||||||
import MusicLibrary.ArtistInfoFixtures
|
import MusicLibrary.ArtistInfoFixtures
|
||||||
import MusicLibrary.ScrobbledTracksFixtures
|
import MusicLibrary.ScrobbledTracksFixtures
|
||||||
|
|
||||||
|
alias MusicLibrary.Fixtures.Records, as: RecordsFixtures
|
||||||
alias MusicLibrary.ListeningStats
|
alias MusicLibrary.ListeningStats
|
||||||
|
alias MusicLibrary.Records.Record
|
||||||
|
|
||||||
describe "scrobble_count/0" do
|
describe "scrobble_count/0" do
|
||||||
test "returns correct count" do
|
test "returns correct count" do
|
||||||
@@ -94,6 +96,65 @@ defmodule MusicLibrary.ListeningStatsTest do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "get_last_listened_track/1" do
|
||||||
|
test "returns the most recent scrobbled track for a record" do
|
||||||
|
record = RecordsFixtures.record()
|
||||||
|
main_artist = Record.main_artist(record)
|
||||||
|
now = System.system_time(:second)
|
||||||
|
|
||||||
|
_older =
|
||||||
|
track_fixture(%{
|
||||||
|
artist_name: main_artist.name,
|
||||||
|
album_title: record.title,
|
||||||
|
title: "Older Track",
|
||||||
|
scrobbled_at_uts: now - 200
|
||||||
|
})
|
||||||
|
|
||||||
|
track_fixture(%{
|
||||||
|
artist_name: main_artist.name,
|
||||||
|
album_title: record.title,
|
||||||
|
title: "Newer Track",
|
||||||
|
scrobbled_at_uts: now - 100
|
||||||
|
})
|
||||||
|
|
||||||
|
result = ListeningStats.get_last_listened_track(record)
|
||||||
|
|
||||||
|
assert result.title == "Newer Track"
|
||||||
|
assert result.scrobbled_at_uts == now - 100
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns nil when no scrobbles exist for the record" do
|
||||||
|
record = RecordsFixtures.record()
|
||||||
|
|
||||||
|
assert ListeningStats.get_last_listened_track(record) == nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "play_count/1" do
|
||||||
|
test "returns the correct scrobble count for a record" do
|
||||||
|
record = RecordsFixtures.record()
|
||||||
|
main_artist = Record.main_artist(record)
|
||||||
|
now = System.system_time(:second)
|
||||||
|
|
||||||
|
for i <- 1..3 do
|
||||||
|
track_fixture(%{
|
||||||
|
artist_name: main_artist.name,
|
||||||
|
album_title: record.title,
|
||||||
|
title: "Track #{i}",
|
||||||
|
scrobbled_at_uts: now - i * 100
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
assert ListeningStats.play_count(record) == 3
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns 0 when no scrobbles exist for the record" do
|
||||||
|
record = RecordsFixtures.record()
|
||||||
|
|
||||||
|
assert ListeningStats.play_count(record) == 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "get_top_artists_by_days/2" do
|
describe "get_top_artists_by_days/2" do
|
||||||
test "counts tracks with missing artist_infos records within date range" do
|
test "counts tracks with missing artist_infos records within date range" do
|
||||||
artist_info =
|
artist_info =
|
||||||
|
|||||||
Reference in New Issue
Block a user