# HG changeset patch # User Paper # Date 1775333071 14400 # Node ID 594c0f9d7972a9016fdb542b4e18e3adb44be0f4 # Parent a5ee18c79a0484f0c7f6f20dd6577f06b19c9118 errr diff -r a5ee18c79a04 -r 594c0f9d7972 src/beefweb.rs --- a/src/beefweb.rs Sat Apr 04 12:34:46 2026 -0400 +++ b/src/beefweb.rs Sat Apr 04 16:04:31 2026 -0400 @@ -18,6 +18,9 @@ * . */ +/* Fuck off, I don't care. */ +#![allow(nonstandard_style)] + #[derive(serde::Serialize, serde::Deserialize, Debug)] pub struct PlayerInfo { pub name: String, @@ -71,15 +74,66 @@ } #[derive(serde::Serialize, serde::Deserialize, Debug)] +pub enum PlaybackState { + #[serde(rename = "stopped")] + STOPPED, + #[serde(rename = "playing")] + PLAYING, + #[serde(rename = "paused")] + PAUSED, +} + +/* fb2k playback order */ +#[derive(Debug)] +pub enum PlaybackOrder { + DEFAULT, + REPEAT_PLAYLIST, + REPEAT_TRACK, + RANDOM, + SHUFFLE_TRACKS, + SHUFFLE_ALBUMS, + SHUFFLE_FOLDERS, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug)] +#[serde(tag = "type")] +pub enum Options { + #[serde(rename = "enum")] + Enumeration { + #[serde(rename = "enumNames")] + enum_names: Vec, + id: String, + name: String, + value: i64, + }, + #[serde(rename = "bool")] + Boolean { + id: String, + name: String, + value: bool, + }, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug)] pub struct Player { pub info: PlayerInfo, #[serde(rename = "activeItem")] pub active_item: ActiveItemInfo, /* XXX actually an enum */ #[serde(rename = "playbackState")] - pub playback_state: String, + pub playback_state: PlaybackState, pub volume: VolumeInfo, pub permissions: ApiPermissions, + + options: Option>, + + /* these two fields are deprecated, + * replaced with "options" array */ + #[serde(skip_serializing_if = "Option::is_none")] + playbackMode: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + playbackModes: Option>, } /* {"player": {struct Player}} */ @@ -158,6 +212,76 @@ .player); } + fn playback_order_lookup(playback_order: &str) -> Option + { + return match playback_order { + "Default" => return Some(PlaybackOrder::DEFAULT), + "Repeat (playlist)" => return Some(PlaybackOrder::REPEAT_PLAYLIST), + "Repeat (track)" => return Some(PlaybackOrder::REPEAT_TRACK), + "Random" => return Some(PlaybackOrder::RANDOM), + "Shuffle (tracks)" => return Some(PlaybackOrder::SHUFFLE_TRACKS), + "Shuffle (albums)" => return Some(PlaybackOrder::SHUFFLE_ALBUMS), + "Shuffle (folders)" => return Some(PlaybackOrder::SHUFFLE_FOLDERS), + _ => None, + }; + } + + fn playback_order_cruft(v: &Vec, s: i64) -> Option + { + let x = v.get(s as usize); + + match x { + Some(y) => return Self::playback_order_lookup(y), + _ => (), + }; + + return None; + } + + pub async fn playback_order(&self) -> Result + { + let p = self.player().await?; + + match p.options { + Some(x) => { + for i in x { + match i { + Options::Enumeration { enum_names: e, id: id, name: _, value: v } => { + match id.as_str() { + "playbackOrder" => { + match Self::playback_order_cruft(&e, v) { + Some(z) => return Ok(z), + _ => (), + }; + }, + _ => (), + }; + }, + _ => (), + }; + } + }, + _ => (), + } + + match p.playbackModes { + Some(x) => { + match p.playbackMode { + Some(y) => { + match Self::playback_order_cruft(&x, y) { + Some(v) => return Ok(v), + _ => (), + } + }, + _ => (), + }; + } + _ => (), + } + + return Err(anyhow::anyhow!("Unknown or invalid playback order?")); + } + pub async fn volume(&self) -> Result { return Ok(self.player().await?.volume); @@ -237,14 +361,29 @@ { return self.set_player(&SetPlayer { volume: None, - relative_volume: Some(position), + relative_volume: None, muted: None, - position: None, + position: Some(position), relative_position: None, options: None, }).await; } +/* TODO -- finish this; need to link between string and enum + + pub async fn set_playback_order(&self, ) -> Result<(), anyhow::Error> + { + let p = self.set_player(&SetPlayer { + volume: None, + relative_volume: None, + muted: None, + position: None, + relative_position: None, + options: + }) + } +*/ + pub async fn playlist_items(&self, playlist_id: &str, offset: i64, count: i64, columns: Vec<&str>) -> Result { return Ok(self.client diff -r a5ee18c79a04 -r 594c0f9d7972 src/player.rs --- a/src/player.rs Sat Apr 04 12:34:46 2026 -0400 +++ b/src/player.rs Sat Apr 04 16:04:31 2026 -0400 @@ -23,7 +23,7 @@ use zbus::fdo; use zbus::Result; use std::collections::HashMap; -use std::io::Write; +//use std::io::Write; use std::cell::RefCell; /* teehee */ @@ -237,34 +237,35 @@ _ => (), }; - return match p.unwrap().playback_state.as_str() { - "playing" => Ok(mpris_server::PlaybackStatus::Playing), - "stopped" => Ok(mpris_server::PlaybackStatus::Stopped), - "paused" => Ok(mpris_server::PlaybackStatus::Paused), - _ => Err(fdo::Error::Failed("deez nuts".to_string())), + return match p.unwrap().playback_state { + beefweb::PlaybackState::PLAYING => Ok(mpris_server::PlaybackStatus::Playing), + beefweb::PlaybackState::STOPPED => Ok(mpris_server::PlaybackStatus::Stopped), + beefweb::PlaybackState::PAUSED => Ok(mpris_server::PlaybackStatus::Paused), }; } async fn loop_status(&self) -> fdo::Result { + /* TODO -- we can do this w/ self.bw.playback_order() */ return Ok(mpris_server::LoopStatus::None); } async fn set_loop_status(&self, loop_status: mpris_server::LoopStatus) -> Result<()> { + /* TODO -- implement self.bw.set_playback_order() */ return Ok(()); } async fn shuffle(&self) -> fdo::Result { - /* TODO */ + /* TODO -- we can do this w/ self.bw.playback_order() */ println!("Shuffle"); return Ok(false); } async fn set_shuffle(&self, shuffle: bool) -> Result<()> { - /* TODO */ + /* TODO -- implement self.bw.set_playback_order() */ println!("SetShuffle({shuffle})"); return Ok(()); } @@ -315,11 +316,33 @@ async fn volume(&self) -> fdo::Result { - return Ok(mpris_server::Volume::default()); + let vr = self.bw.volume().await; + + match vr { + Err(_) => return Err(fdo::Error::Failed("uhoh".to_string())), + _ => (), + } + + let v = vr.unwrap(); + + /* dB -> linear */ + return Ok(match v.r#type { + beefweb::VolumeType::DB => 10.0_f64.powf(v.value / 20.0), + beefweb::VolumeType::LINEAR => v.value, + beefweb::VolumeType::UPDOWN => /* ??? */ v.value, + }); } async fn set_volume(&self, volume: mpris_server::Volume) -> Result<()> { + /* linear -> dB */ + let v = 20.0 * volume.log10(); + + match self.bw.set_volume(v).await { + Err(_) => return Err(zbus::Error::Failure("uhoh".to_string())), + _ => (), + } + return Ok(()); }