diff --git a/Cargo.lock b/Cargo.lock
index a8af51c..73bd94f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1418,7 +1418,7 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "furumusic"
-version = "0.4.3"
+version = "0.4.4"
dependencies = [
"anyhow",
"async-trait",
diff --git a/Cargo.toml b/Cargo.toml
index f71dc2c..4040cb2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "furumusic"
-version = "0.4.4"
+version = "0.4.5"
edition = "2024"
description = "Reusable web-app boilerplate: auth, OIDC/SSO, admin panel, user management, i18n, PostgreSQL"
diff --git a/src/i18n/phrases.rs b/src/i18n/phrases.rs
index da4bee1..1805e88 100644
--- a/src/i18n/phrases.rs
+++ b/src/i18n/phrases.rs
@@ -373,6 +373,7 @@ translations! {
player_repeat: "Repeat" , "Повтор";
player_volume: "Volume" , "Громкость";
player_appears_on: "Appears on" , "Участвует в";
+ player_top_tracks: "Popular tracks" , "Популярные треки";
player_albums: "Albums" , "Альбомы";
player_eps: "EPs" , "EP";
player_singles: "Singles" , "Синглы";
diff --git a/src/player/mod.rs b/src/player/mod.rs
index 0349c4f..caa756b 100644
--- a/src/player/mod.rs
+++ b/src/player/mod.rs
@@ -3201,40 +3201,44 @@ async fn artist_detail_handler(
.collect();
let top_tracks = sqlx::query_as::<_, PlaylistTrackRow>(
- r#"SELECT t.id, t.title::text as title, t.track_number, t.disc_number,
- t.duration_seconds, t.cover_file_id,
- r.cover_file_id as release_cover_file_id,
- r.id as release_id,
- r.title::text as release_title,
- r.year as release_year,
- COALESCE(mf.uploader_name, 'UFO')::text AS uploader_name,
- mf.audio_format,
- mf.audio_bitrate,
- mf.audio_sample_rate,
- mf.audio_bit_depth,
- mf.file_size_bytes,
- t.lastfm_listeners,
- t.lastfm_playcount,
- t.lastfm_rating,
- t.lastfm_updated_at
- FROM furumusic__track t
- JOIN furumusic__release r ON r.id = t.release_id
- LEFT JOIN furumusic__media_file mf ON mf.id = t.audio_file_id
- WHERE t.is_hidden = false
- AND r.is_hidden = false
- AND EXISTS (
- SELECT 1
- FROM furumusic__track_artist ta
- WHERE ta.track_id = t.id
- AND ta.artist_id = $1
- AND ta.role <> 'featuring'
- )
- ORDER BY COALESCE(t.lastfm_rating, 0) DESC,
- COALESCE(t.lastfm_playcount, 0) DESC,
- COALESCE(t.lastfm_listeners, 0) DESC,
- r.year DESC NULLS LAST,
- t.track_number NULLS LAST,
- t.id
+ r#"SELECT * FROM (
+ SELECT DISTINCT ON (lower(t.title::text))
+ t.id, t.title::text as title, t.track_number, t.disc_number,
+ t.duration_seconds, t.cover_file_id,
+ r.cover_file_id as release_cover_file_id,
+ r.id as release_id,
+ r.title::text as release_title,
+ r.year as release_year,
+ COALESCE(mf.uploader_name, 'UFO')::text AS uploader_name,
+ mf.audio_format,
+ mf.audio_bitrate,
+ mf.audio_sample_rate,
+ mf.audio_bit_depth,
+ mf.file_size_bytes,
+ t.lastfm_listeners,
+ t.lastfm_playcount,
+ t.lastfm_rating,
+ t.lastfm_updated_at
+ FROM furumusic__track t
+ JOIN furumusic__release r ON r.id = t.release_id
+ LEFT JOIN furumusic__media_file mf ON mf.id = t.audio_file_id
+ WHERE t.is_hidden = false
+ AND r.is_hidden = false
+ AND EXISTS (
+ SELECT 1
+ FROM furumusic__track_artist ta
+ WHERE ta.track_id = t.id
+ AND ta.artist_id = $1
+ AND ta.role <> 'featuring'
+ )
+ ORDER BY lower(t.title::text), COALESCE(t.lastfm_rating, 0) DESC
+ ) deduped
+ ORDER BY COALESCE(lastfm_rating, 0) DESC,
+ COALESCE(lastfm_playcount, 0) DESC,
+ COALESCE(lastfm_listeners, 0) DESC,
+ release_year DESC NULLS LAST,
+ track_number NULLS LAST,
+ id
LIMIT 50"#,
)
.bind(artist_id)
diff --git a/templates/player/shell.html b/templates/player/shell.html
index 6f6d72e..a3b5d27 100644
--- a/templates/player/shell.html
+++ b/templates/player/shell.html
@@ -620,6 +620,83 @@
+
+
+ {{ t.player_top_tracks }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+