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:
4 files changed
+149
-1
No files matched your search
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user