feat(api): add genre list endpoint
- Add GENRE_LIST endpoint constant - Add GenreInfo model with id, name, color, slug, path - Add get_genres() method to client - Add get_genres Tauri command
This commit is contained in:
1 parent
b6c723d3df
commit
8e31717908
5 files changed
+71
-1
No files matched your search
@@ -413,6 +413,33 @@ impl QobuzClient {
|
||||
Ok(serde_json::from_value(albums.clone())?)
|
||||
}
|
||||
|
||||
/// Get list of genres
|
||||
pub async fn get_genres(&self, parent_id: Option<u64>) -> Result<Vec<GenreInfo>> {
|
||||
let url = endpoints::build_url(paths::GENRE_LIST);
|
||||
let mut query: Vec<(&str, String)> = vec![];
|
||||
|
||||
if let Some(pid) = parent_id {
|
||||
query.push(("parent_id", pid.to_string()));
|
||||
}
|
||||
|
||||
let response: Value = self
|
||||
.http
|
||||
.get(&url)
|
||||
.header("X-App-Id", self.app_id().await?)
|
||||
.query(&query)
|
||||
.send()
|
||||
.await?
|
||||
.json()
|
||||
.await?;
|
||||
|
||||
let genres = response
|
||||
.get("genres")
|
||||
.and_then(|g| g.get("items"))
|
||||
.ok_or_else(|| ApiError::ApiResponse("No genres in response".to_string()))?;
|
||||
|
||||
Ok(serde_json::from_value(genres.clone())?)
|
||||
}
|
||||
|
||||
/// Get track by ID
|
||||
pub async fn get_track(&self, track_id: u64) -> Result<Track> {
|
||||
let url = endpoints::build_url(paths::TRACK_GET);
|
||||
|
||||
@@ -40,6 +40,9 @@ pub mod paths {
|
||||
// Label
|
||||
pub const LABEL_GET: &str = "/label/get";
|
||||
|
||||
// Genre
|
||||
pub const GENRE_LIST: &str = "/genre/list";
|
||||
|
||||
// Catalog (combined search)
|
||||
pub const CATALOG_SEARCH: &str = "/catalog/search";
|
||||
}
|
||||
|
||||
@@ -289,13 +289,37 @@ pub struct LabelDetail {
|
||||
pub albums_count: Option<u32>,
|
||||
}
|
||||
|
||||
/// Genre model
|
||||
/// Genre model (basic, used in album responses)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Genre {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
/// Genre info with full details (from genre/list endpoint)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GenreInfo {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
#[serde(default)]
|
||||
pub color: Option<String>,
|
||||
#[serde(default)]
|
||||
pub slug: Option<String>,
|
||||
#[serde(default)]
|
||||
pub path: Option<Vec<u64>>,
|
||||
}
|
||||
|
||||
/// Genre list response from API
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GenreListResponse {
|
||||
pub genres: GenreListContainer,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GenreListContainer {
|
||||
pub items: Vec<GenreInfo>,
|
||||
}
|
||||
|
||||
/// Search results container
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SearchResults {
|
||||
|
||||
@@ -393,3 +393,18 @@ pub async fn get_label(
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
/// Get list of genres for filtering
|
||||
#[tauri::command]
|
||||
pub async fn get_genres(
|
||||
parent_id: Option<u64>,
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<Vec<crate::api::models::GenreInfo>, String> {
|
||||
log::info!("Command: get_genres parent_id={:?}", parent_id);
|
||||
|
||||
let client = state.client.lock().await;
|
||||
client
|
||||
.get_genres(parent_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
@@ -492,6 +492,7 @@ pub fn run() {
|
||||
commands::search_all,
|
||||
commands::get_album,
|
||||
commands::get_featured_albums,
|
||||
commands::get_genres,
|
||||
commands::get_track,
|
||||
commands::get_artist,
|
||||
commands::get_artist_detail,
|
||||
|
||||
Reference in new issue
Block a user