diff options
| author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2026-01-25 17:08:18 +0100 |
|---|---|---|
| committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2026-01-25 17:08:18 +0100 |
| commit | a5d8629d99aef14f24517d2014879af6aa43cf71 (patch) | |
| tree | c21a6babcac121e142ed7bf62ecd65f43565bca2 /pkgs | |
| parent | modules/{mpdpopm,legacy/beets}: Move the mpd stat tracking to mpdpopm (diff) | |
| download | nixos-config-a5d8629d99aef14f24517d2014879af6aa43cf71.zip | |
modules/river/keymap: Provide access to rate songs, bad/good
Diffstat (limited to '')
| -rw-r--r-- | pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs | 267 | ||||
| -rw-r--r-- | pkgs/by-name/mp/mpdpopm/src/messages.rs | 1 |
2 files changed, 168 insertions, 100 deletions
diff --git a/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs b/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs index 4ffcd499..04760f18 100644 --- a/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs +++ b/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs @@ -79,7 +79,6 @@ pub enum Error { } impl fmt::Display for Error { - #[allow(unreachable_patterns)] // the _ arm is *currently* unreachable fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Error::NoSubCommand => write!(f, "No sub-command given"), @@ -122,7 +121,18 @@ async fn map_tracks(client: &mut Client, args: Option<Vec<String>>) -> Result<Ve let files = match args { Some(iter) => iter, None => { - let file = match client.status().await.map_err(|err| Error::Client { + let file = provide_file(client, None).await?; + vec![file] + } + }; + Ok(files) +} + +async fn provide_file(client: &mut Client, maybe_file: Option<String>) -> Result<String> { + let file = match maybe_file { + Some(file) => file, + None => { + match client.status().await.map_err(|err| Error::Client { source: err, back: Backtrace::new(), })? { @@ -137,11 +147,11 @@ async fn map_tracks(client: &mut Client, args: Option<Vec<String>>) -> Result<Ve PlayerStatus::Stopped => { return Err(Error::PlayerStopped); } - }; - vec![file] + } } }; - Ok(files) + + Ok(file) } /// Retrieve ratings for one or more tracks @@ -175,49 +185,74 @@ async fn get_ratings( } /// Rate a track -async fn set_rating( - client: &mut Client, - chan: &str, - rating: u8, - arg: Option<String>, -) -> Result<()> { - let cmd = match &arg { - Some(uri) => format!("rate {} \\\"{}\\\"", rating, uri), - None => format!("rate {}", rating), - }; - client - .send_message(chan, &cmd) +async fn set_rating(client: &mut Client, rating: u8, arg: Option<String>) -> Result<()> { + let is_current = arg.is_none(); + let file = provide_file(client, arg).await?; + + rating_count::set(client, &file, rating) .await - .map_err(|err| Error::Client { - source: err, + .map_err(|err| Error::Ratings { + source: Box::new(err), back: Backtrace::new(), })?; - match &arg { - Some(uri) => info!("Set the rating for \"{}\" to \"{}\".", uri, rating), - None => info!("Set the rating for the current song to \"{}\".", rating), + match is_current { + false => info!("Set the rating for \"{}\" to \"{}\".", file, rating), + true => info!("Set the rating for the current song to \"{}\".", rating), } Ok(()) } /// Rate a track by incrementing the current rating -async fn inc_rating(client: &mut Client, chan: &str, arg: Option<String>) -> Result<()> { - let cmd = match &arg { - Some(uri) => format!("inc-rate \\\"{}\\\"", uri), - None => "inc-rate ".to_owned(), - }; - client - .send_message(chan, &cmd) +async fn inc_rating(client: &mut Client, arg: Option<String>) -> Result<()> { + let is_current = arg.is_none(); + let file = provide_file(client, arg).await?; + + let now = rating_count::get(client, &file) .await - .map_err(|err| Error::Client { - source: err, + .map_err(|err| Error::Ratings { + source: Box::new(err), + back: Backtrace::new(), + })?; + + rating_count::set(client, &file, now.unwrap_or_default().saturating_add(1)) + .await + .map_err(|err| Error::Ratings { + source: Box::new(err), back: Backtrace::new(), })?; - match &arg { - Some(uri) => info!("Incremented the rating for \"{}\".", uri), - None => info!("Incremented the rating for the current song."), + match is_current { + false => info!("Incremented the rating for \"{}\".", file), + true => info!("Incremented the rating for the current song."), + } + + Ok(()) +} + +/// Rate a track by decrementing the current rating +async fn decr_rating(client: &mut Client, arg: Option<String>) -> Result<()> { + let is_current = arg.is_none(); + let file = provide_file(client, arg).await?; + + let now = rating_count::get(client, &file) + .await + .map_err(|err| Error::Ratings { + source: Box::new(err), + back: Backtrace::new(), + })?; + + rating_count::set(client, &file, now.unwrap_or_default().saturating_sub(1)) + .await + .map_err(|err| Error::Ratings { + source: Box::new(err), + back: Backtrace::new(), + })?; + + match is_current { + false => info!("Decremented the rating for \"{}\".", file), + true => info!("Decremented the rating for the current song."), } Ok(()) @@ -253,27 +288,20 @@ async fn get_play_counts( } /// Set the playcount for a track -async fn set_play_counts( - client: &mut Client, - chan: &str, - playcount: usize, - arg: Option<String>, -) -> Result<()> { - let cmd = match &arg { - Some(uri) => format!("setpc {} \\\"{}\\\"", playcount, uri), - None => format!("setpc {}", playcount), - }; - client - .send_message(chan, &cmd) +async fn set_play_counts(client: &mut Client, playcount: usize, arg: Option<String>) -> Result<()> { + let is_current = arg.is_none(); + let file = provide_file(client, arg).await?; + + play_count::set(client, &file, playcount) .await - .map_err(|err| Error::Client { - source: err, + .map_err(|err| Error::Playcounts { + source: Box::new(err), back: Backtrace::new(), })?; - match &arg { - Some(uri) => info!("Set the playcount for \"{}\" to \"{}\".", uri, playcount), - None => info!( + match is_current { + false => info!("Set the playcount for \"{}\" to \"{}\".", file, playcount), + true => info!( "Set the playcount for the current song to \"{}\".", playcount ), @@ -325,27 +353,20 @@ async fn get_last_playeds( } /// Set the playcount for a track -async fn set_last_playeds( - client: &mut Client, - chan: &str, - lastplayed: u64, - arg: Option<String>, -) -> Result<()> { - let cmd = match &arg { - Some(uri) => format!("setlp {} {}", lastplayed, uri), - None => format!("setlp {}", lastplayed), - }; - client - .send_message(chan, &cmd) +async fn set_last_playeds(client: &mut Client, lastplayed: u64, arg: Option<String>) -> Result<()> { + let is_current = arg.is_none(); + let file = provide_file(client, arg).await?; + + last_played::set(client, &file, lastplayed) .await - .map_err(|err| Error::Client { - source: err, + .map_err(|err| Error::Playcounts { + source: Box::new(err), back: Backtrace::new(), })?; - match &arg { - Some(uri) => info!("Set last played for \"{}\" to \"{}\".", uri, lastplayed), - None => info!( + match is_current { + false => info!("Set last played for \"{}\" to \"{}\".", file, lastplayed), + true => info!( "Set last played for the current song to \"{}\".", lastplayed ), @@ -426,7 +447,7 @@ struct Args { } #[derive(Subcommand)] -enum SubCommand { +enum RatingCommand { /// retrieve the rating for one or more tracks /// /// With no arguments, retrieve the rating of the current song & print it @@ -437,7 +458,7 @@ enum SubCommand { /// Ratings are expressed as an integer between 0 & 255, inclusive, with /// the convention that 0 denotes "un-rated". #[clap(verbatim_doc_comment)] - GetRating { + Get { /// Always show the song URI, even when there is only one track #[arg(short, long)] with_uri: bool, @@ -451,15 +472,25 @@ enum SubCommand { /// With a second argument, rate that song at the first argument. Ratings /// may be expressed a an integer between 0 & 255, inclusive. #[clap(verbatim_doc_comment)] - SetRating { rating: u8, track: Option<String> }, + Set { rating: u8, track: Option<String> }, /// increment the rating for one track /// /// With one argument, increment the rating of the current song. /// With a second argument, rate that song at the first argument. #[clap(verbatim_doc_comment)] - IncRating { track: Option<String> }, + Inc { track: Option<String> }, + + /// decrement the rating for one track + /// + /// With one argument, decrement the rating of the current song. + /// With a second argument, rate that song at the first argument. + #[clap(verbatim_doc_comment)] + Decr { track: Option<String> }, +} +#[derive(Subcommand)] +enum PlayCountCommand { /// retrieve the play count for one or more tracks /// /// With no arguments, retrieve the play count of the current song & print it @@ -467,7 +498,7 @@ enum SubCommand { /// on stdout. With multiple arguments, print their play counts on stdout, one /// per line, prefixed by the track name. #[clap(verbatim_doc_comment)] - GetPc { + Get { /// Always show the song URI, even when there is only one track #[arg(short, long)] with_uri: bool, @@ -480,11 +511,14 @@ enum SubCommand { /// With one argument, set the play count of the current song to that argument. With a /// second argument, set the play count for that song to the first. #[clap(verbatim_doc_comment)] - SetPc { + Set { play_count: usize, track: Option<String>, }, +} +#[derive(Subcommand)] +enum LastPlayedCommand { /// retrieve the last played timestamp for one or more tracks /// /// With no arguments, retrieve the last played timestamp of the current @@ -495,7 +529,7 @@ enum SubCommand { /// /// The last played timestamp is expressed in seconds since Unix epoch. #[clap(verbatim_doc_comment)] - GetLp { + Get { /// Always show the song URI, even when there is only one track #[arg(short, long)] with_uri: bool, @@ -509,14 +543,44 @@ enum SubCommand { /// arguments, set the last played time for the second argument to the first. /// The last played timestamp is expressed in seconds since Unix epoch. #[clap(verbatim_doc_comment)] - SetLp { + Set { last_played: u64, track: Option<String>, }, +} +#[derive(Subcommand)] +enum PlaylistsCommand { /// retrieve the list of stored playlists #[clap(verbatim_doc_comment)] - GetPlaylists {}, + Get {}, +} + +#[derive(Subcommand)] +enum SubCommand { + /// Change details about rating. + Rating { + #[command(subcommand)] + command: RatingCommand, + }, + + /// Change details about play count. + PlayCount { + #[command(subcommand)] + command: PlayCountCommand, + }, + + /// Change details about last played date. + LastPlayed { + #[command(subcommand)] + command: LastPlayedCommand, + }, + + /// Change details about generated playlists. + Playlists { + #[command(subcommand)] + command: PlaylistsCommand, + }, /// search case-sensitively for songs matching matching a filter and add them to the queue /// @@ -642,28 +706,33 @@ async fn main() -> Result<()> { }; match args.command { - SubCommand::GetRating { with_uri, tracks } => { - get_ratings(&mut client, tracks, with_uri).await - } - SubCommand::SetRating { rating, track } => { - set_rating(&mut client, &config.commands_chan, rating, track).await - } - SubCommand::IncRating { track } => { - inc_rating(&mut client, &config.commands_chan, track).await - } - SubCommand::GetPc { with_uri, tracks } => { - get_play_counts(&mut client, tracks, with_uri).await - } - SubCommand::SetPc { play_count, track } => { - set_play_counts(&mut client, &config.commands_chan, play_count, track).await - } - SubCommand::GetLp { with_uri, tracks } => { - get_last_playeds(&mut client, tracks, with_uri).await - } - SubCommand::SetLp { last_played, track } => { - set_last_playeds(&mut client, &config.commands_chan, last_played, track).await - } - SubCommand::GetPlaylists {} => get_playlists(&mut client).await, + SubCommand::Rating { command } => match command { + RatingCommand::Get { with_uri, tracks } => { + get_ratings(&mut client, tracks, with_uri).await + } + RatingCommand::Set { rating, track } => set_rating(&mut client, rating, track).await, + RatingCommand::Inc { track } => inc_rating(&mut client, track).await, + RatingCommand::Decr { track } => decr_rating(&mut client, track).await, + }, + SubCommand::PlayCount { command } => match command { + PlayCountCommand::Get { with_uri, tracks } => { + get_play_counts(&mut client, tracks, with_uri).await + } + PlayCountCommand::Set { play_count, track } => { + set_play_counts(&mut client, play_count, track).await + } + }, + SubCommand::LastPlayed { command } => match command { + LastPlayedCommand::Get { with_uri, tracks } => { + get_last_playeds(&mut client, tracks, with_uri).await + } + LastPlayedCommand::Set { last_played, track } => { + set_last_playeds(&mut client, last_played, track).await + } + }, + SubCommand::Playlists { command } => match command { + PlaylistsCommand::Get {} => get_playlists(&mut client).await, + }, SubCommand::Findadd { filter } => { findadd(&mut client, &config.commands_chan, &filter, true).await } diff --git a/pkgs/by-name/mp/mpdpopm/src/messages.rs b/pkgs/by-name/mp/mpdpopm/src/messages.rs index 85b24470..ae356f34 100644 --- a/pkgs/by-name/mp/mpdpopm/src/messages.rs +++ b/pkgs/by-name/mp/mpdpopm/src/messages.rs @@ -64,7 +64,6 @@ use std::collections::VecDeque; use std::convert::TryFrom; use std::path::PathBuf; -//////////////////////////////////////////////////////////////////////////////////////////////////// #[derive(Debug)] pub enum Error { |
