diff options
Diffstat (limited to 'pkgs/by-name/mp/mpdpopm/src/storage/mod.rs')
| -rw-r--r-- | pkgs/by-name/mp/mpdpopm/src/storage/mod.rs | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/pkgs/by-name/mp/mpdpopm/src/storage/mod.rs b/pkgs/by-name/mp/mpdpopm/src/storage/mod.rs new file mode 100644 index 00000000..29cfe144 --- /dev/null +++ b/pkgs/by-name/mp/mpdpopm/src/storage/mod.rs @@ -0,0 +1,212 @@ +use std::path::PathBuf; + +use backtrace::Backtrace; + +#[derive(Debug)] +pub enum Error { + PlayerStopped, + BadPath { + pth: PathBuf, + }, + SystemTime { + source: std::time::SystemTimeError, + back: Backtrace, + }, + Client { + source: crate::clients::Error, + back: Backtrace, + }, + Rating { + source: crate::ratings::Error, + back: Backtrace, + }, +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Error::PlayerStopped => write!(f, "The MPD player is stopped"), + Error::BadPath { pth } => write!(f, "Bad path: {:?}", pth), + Error::SystemTime { source, back: _ } => { + write!(f, "Couldn't get system time: {}", source) + } + Error::Client { source, back: _ } => write!(f, "Client error: {}", source), + Error::Rating { source, back: _ } => write!(f, "Rating error: {}", source), + } + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match &self { + Error::SystemTime { source, back: _ } => Some(source), + Error::Client { source, back: _ } => Some(source), + _ => None, + } + } +} + +type Result<T> = std::result::Result<T, Error>; + +pub mod play_count { + use backtrace::Backtrace; + + use crate::clients::Client; + + use super::{Error, Result}; + + pub const STICKER: &str = "unwoundstack.com:playcount"; + + /// Retrieve the play count for a track + pub async fn get(client: &mut Client, file: &str) -> Result<Option<usize>> { + match client + .get_sticker::<usize>(file, STICKER) + .await + .map_err(|err| Error::Client { + source: err, + back: Backtrace::new(), + })? { + Some(n) => Ok(Some(n)), + None => Ok(None), + } + } + + /// Set the play count for a track-- this will run the associated command, if any + pub async fn set(client: &mut Client, file: &str, play_count: usize) -> Result<()> { + client + .set_sticker(file, STICKER, &format!("{}", play_count)) + .await + .map_err(|err| Error::Client { + source: err, + back: Backtrace::new(), + })?; + + Ok(()) + } + + #[cfg(test)] + mod pc_lp_tests { + use super::*; + use crate::{clients::test_mock::Mock, storage::play_count}; + + /// "Smoke" tests for play counts & last played times + #[tokio::test] + async fn pc_smoke() { + let mock = Box::new(Mock::new(&[ + ("sticker get song a pc", "sticker: pc=11\nOK\n"), + ( + "sticker get song a pc", + "ACK [50@0] {sticker} no such sticker\n", + ), + ("sticker get song a pc", "splat!"), + ])); + let mut cli = Client::new(mock).unwrap(); + + assert_eq!(play_count::get(&mut cli, "a").await.unwrap().unwrap(), 11); + let val = play_count::get(&mut cli, "a").await.unwrap(); + assert!(val.is_none()); + play_count::get(&mut cli, "a").await.unwrap_err(); + } + } +} + +pub mod skipped { + use backtrace::Backtrace; + + use crate::clients::Client; + + use super::{Error, Result}; + + const STICKER: &str = "unwoundstack.com:skipped_count"; + + /// Retrieve the skip count for a track + pub async fn get(client: &mut Client, file: &str) -> Result<Option<usize>> { + match client + .get_sticker::<usize>(file, STICKER) + .await + .map_err(|err| Error::Client { + source: err, + back: Backtrace::new(), + })? { + Some(n) => Ok(Some(n)), + None => Ok(None), + } + } + + /// Set the skip count for a track + pub async fn set(client: &mut Client, file: &str, skip_count: usize) -> Result<()> { + client + .set_sticker(file, STICKER, &format!("{}", skip_count)) + .await + .map_err(|err| Error::Client { + source: err, + back: Backtrace::new(), + }) + } +} + +pub mod last_played { + use backtrace::Backtrace; + + use crate::clients::Client; + + use super::{Error, Result}; + + pub const STICKER: &str = "unwoundstack.com:lastplayed"; + + /// Retrieve the last played timestamp for a track (seconds since Unix epoch) + pub async fn get(client: &mut Client, file: &str) -> Result<Option<u64>> { + client + .get_sticker::<u64>(file, STICKER) + .await + .map_err(|err| Error::Client { + source: err, + back: Backtrace::new(), + }) + } + + /// Set the last played for a track + pub async fn set(client: &mut Client, file: &str, last_played: u64) -> Result<()> { + client + .set_sticker(file, STICKER, &format!("{}", last_played)) + .await + .map_err(|err| Error::Client { + source: err, + back: Backtrace::new(), + })?; + Ok(()) + } +} + +pub mod rating_count { + use backtrace::Backtrace; + + use crate::clients::Client; + + use super::{Error, Result}; + + pub const STICKER: &str = "unwoundstack.com:ratings_count"; + + /// Retrieve the rating count for a track + pub async fn get(client: &mut Client, file: &str) -> Result<Option<u8>> { + client + .get_sticker::<u8>(file, STICKER) + .await + .map_err(|err| Error::Client { + source: err, + back: Backtrace::new(), + }) + } + + /// Set the rating count for a track + pub async fn set(client: &mut Client, file: &str, rating_count: u8) -> Result<()> { + client + .set_sticker(file, STICKER, &format!("{}", rating_count)) + .await + .map_err(|err| Error::Client { + source: err, + back: Backtrace::new(), + })?; + Ok(()) + } +} |
