feat: add Essentials [Genre] section to For You tab

Add v2_reco_get_top_genres command that queries the user's most-played
genres from reco_events. Frontend loads top genre and fetches
ideal-discography featured albums filtered by that genre.
This commit is contained in:
vicrodh committed 2026-03-10 00:05:25 -06:00
1 parent ff109e5c64
commit 9780948ca8
4 files changed
+149 -1

No files matched your search

+22
View File
@@ -4437,6 +4437,28 @@ pub async fn v2_reco_get_forgotten_favorites(
.await
}
/// Get user's top genres by play count
#[tauri::command]
pub async fn v2_reco_get_top_genres(
limit: Option<u32>,
reco_state: State<'_, RecoState>,
) -> Result<Vec<TopGenre>, String> {
let guard = reco_state.db.lock().await;
let db = guard.as_ref().ok_or("No active session")?;
let genres = db.get_top_genre_ids(limit.unwrap_or(5))?;
Ok(genres
.into_iter()
.map(|(id, name)| TopGenre { id, name })
.collect())
}
#[derive(Debug, Clone, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TopGenre {
pub id: u64,
pub name: String,
}
#[derive(Debug, Clone, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct V2LibraryCacheStats {
+1
View File
@@ -1387,6 +1387,7 @@ pub fn run() {
commands_v2::v2_reco_get_home_resolved,
commands_v2::v2_get_album_suggestions,
commands_v2::v2_reco_get_forgotten_favorites,
commands_v2::v2_reco_get_top_genres,
commands_v2::v2_library_get_cache_stats,
commands_v2::v2_library_get_stats,
commands_v2::v2_library_get_albums,
+30
View File
@@ -425,6 +425,36 @@ impl RecoStoreDb {
Ok(albums)
}
/// Get the user's most-played genres by event count
pub fn get_top_genre_ids(&self, limit: u32) -> Result<Vec<(u64, String)>, String> {
let mut stmt = self
.conn
.prepare(
r#"
SELECT e.genre_id, COALESCE(m.genre_name, ''), COUNT(*) AS play_count
FROM reco_events e
LEFT JOIN reco_album_meta m ON e.album_id = m.album_id
WHERE e.genre_id IS NOT NULL AND e.genre_id > 0
GROUP BY e.genre_id
ORDER BY play_count DESC
LIMIT ?
"#,
)
.map_err(|e| format!("Failed to prepare top genres query: {}", e))?;
let rows = stmt
.query_map(params![limit], |row| {
Ok((row.get::<_, u64>(0)?, row.get::<_, String>(1)?))
})
.map_err(|e| format!("Failed to query top genres: {}", e))?;
let mut genres = Vec::new();
for row in rows {
genres.push(row.map_err(|e| format!("Failed to read genre row: {}", e))?);
}
Ok(genres)
}
pub fn get_favorite_track_ids(&self, limit: u32) -> Result<Vec<u64>, String> {
let mut stmt = self
.conn