aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/by-name/mp/mpdpopm/src/storage
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/by-name/mp/mpdpopm/src/storage')
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/storage/mod.rs212
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(())
+ }
+}