Added connected devices. Improved logging. UI fixes
This commit is contained in:
+93
-19
@@ -22,7 +22,10 @@ pub struct LoginResponse {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[allow(dead_code, reason = "rendered by the profile view in a later milestone")]
|
||||
#[allow(
|
||||
dead_code,
|
||||
reason = "rendered by the profile view in a later milestone"
|
||||
)]
|
||||
pub struct MeStats {
|
||||
pub liked_tracks: i64,
|
||||
pub playlists: i64,
|
||||
@@ -31,7 +34,10 @@ pub struct MeStats {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[allow(dead_code, reason = "rendered by the profile view in a later milestone")]
|
||||
#[allow(
|
||||
dead_code,
|
||||
reason = "rendered by the profile view in a later milestone"
|
||||
)]
|
||||
pub struct MeResponse {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
@@ -55,28 +61,37 @@ pub struct ArtistCard {
|
||||
pub track_count: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ArtistRef {
|
||||
#[allow(dead_code, reason = "navigation to artists from track rows later")]
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
/// Serialize keeps every field the backend sent us, so device-sync payloads
|
||||
/// (play_from_index, queue_add) carry full track objects like the web does.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TrackItem {
|
||||
#[allow(dead_code, reason = "playback engine consumes this in milestone 3")]
|
||||
pub id: i64,
|
||||
pub title: String,
|
||||
/// Absent in the artist-appearance variant of track payloads.
|
||||
#[serde(default)]
|
||||
pub track_number: Option<i32>,
|
||||
pub duration_seconds: f64,
|
||||
#[serde(default)]
|
||||
pub artists: Vec<ArtistRef>,
|
||||
#[serde(default)]
|
||||
pub featured_artists: Vec<ArtistRef>,
|
||||
#[allow(dead_code, reason = "jump-to-release navigation later")]
|
||||
#[serde(default)]
|
||||
pub release_id: i64,
|
||||
#[serde(default)]
|
||||
pub release_title: String,
|
||||
#[allow(dead_code, reason = "shown in queue/now-playing later")]
|
||||
pub release_year: Option<i32>,
|
||||
/// Server-relative path to `/api/player/stream/{id}`.
|
||||
#[serde(default)]
|
||||
pub stream_url: String,
|
||||
#[allow(dead_code, reason = "now-playing artwork in milestone 3")]
|
||||
pub cover_url: Option<String>,
|
||||
@@ -103,21 +118,6 @@ impl TrackItem {
|
||||
format!("{}:{:02}", total / 60, total % 60)
|
||||
}
|
||||
|
||||
/// Compact "FLAC 929k 24.3MB" suffix for track rows.
|
||||
pub fn tech_label_short(&self) -> String {
|
||||
let mut parts = Vec::new();
|
||||
if let Some(format) = &self.audio_format {
|
||||
parts.push(format.to_uppercase());
|
||||
}
|
||||
if let Some(bitrate) = self.audio_bitrate {
|
||||
parts.push(format!("{bitrate}k"));
|
||||
}
|
||||
if let Some(bytes) = self.file_size_bytes {
|
||||
parts.push(format!("{:.1}MB", bytes as f64 / 1_048_576.0));
|
||||
}
|
||||
parts.join(" ")
|
||||
}
|
||||
|
||||
/// Full tech line for the status bar, including the sample rate.
|
||||
pub fn tech_label_full(&self) -> String {
|
||||
let mut parts = Vec::new();
|
||||
@@ -157,6 +157,10 @@ pub struct ArtistDetail {
|
||||
pub total_play_count: i64,
|
||||
pub top_tracks: Vec<TrackItem>,
|
||||
pub releases: Vec<ReleaseCard>,
|
||||
/// Tracks where this artist is featured (the only content for artists
|
||||
/// without own releases).
|
||||
#[serde(default)]
|
||||
pub featured_tracks: Vec<TrackItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@@ -208,6 +212,76 @@ pub struct LikesResponse {
|
||||
pub track_ids: Vec<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct DeviceDto {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub kind: String,
|
||||
#[allow(dead_code, reason = "server-side flag; we compare ids directly")]
|
||||
pub is_current: bool,
|
||||
pub is_active: bool,
|
||||
#[allow(dead_code, reason = "freshness display later")]
|
||||
pub last_seen_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DeviceCommandDto {
|
||||
#[allow(dead_code, reason = "commands are applied in poll order")]
|
||||
pub id: Option<String>,
|
||||
pub command: String,
|
||||
#[serde(default)]
|
||||
pub payload: serde_json::Value,
|
||||
}
|
||||
|
||||
/// Mirrors the backend's PlayerDevicePlaybackStateDto; tracks stay raw JSON
|
||||
/// so unknown fields survive the round trip between clients.
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct DevicePlaybackState {
|
||||
#[serde(default)]
|
||||
pub track: Option<serde_json::Value>,
|
||||
#[serde(default)]
|
||||
pub tracks: Vec<serde_json::Value>,
|
||||
#[serde(default)]
|
||||
pub index: i32,
|
||||
#[serde(default)]
|
||||
pub position_seconds: f64,
|
||||
#[serde(default)]
|
||||
pub duration_seconds: f64,
|
||||
#[serde(default)]
|
||||
pub paused: bool,
|
||||
#[serde(default)]
|
||||
pub shuffle: bool,
|
||||
#[serde(default = "default_repeat_mode")]
|
||||
pub repeat_mode: String,
|
||||
#[serde(default = "default_volume")]
|
||||
pub volume: f64,
|
||||
#[serde(default)]
|
||||
pub updated_at_ms: i64,
|
||||
}
|
||||
|
||||
fn default_repeat_mode() -> String {
|
||||
"off".to_string()
|
||||
}
|
||||
|
||||
fn default_volume() -> f64 {
|
||||
1.0
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DevicePollResponse {
|
||||
#[allow(dead_code, reason = "echo of our own id")]
|
||||
pub device_id: String,
|
||||
pub active_device_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub devices: Vec<DeviceDto>,
|
||||
#[serde(default)]
|
||||
pub commands: Vec<DeviceCommandDto>,
|
||||
#[serde(default)]
|
||||
#[allow(dead_code, reason = "Jam control is out of scope for the TUI v1")]
|
||||
pub current_jam_id: Option<String>,
|
||||
pub playback_state: Option<DevicePlaybackState>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct SearchResults {
|
||||
pub artists: Vec<ArtistCard>,
|
||||
|
||||
Reference in New Issue
Block a user