Skip to content

Add some more commands. #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use output::Output;
use playlist::Playlist;
use plugin::Plugin;
use proto::*;
use search::{Query, Window};
use search::{Query, Window, Term};
use song::{Id, Song};
use stats::Stats;
use status::{ReplayGain, Status};
Expand Down Expand Up @@ -237,8 +237,8 @@ impl<S: Read + Write> Client<S> {
}

/// Append a song into a queue
pub fn push<P: AsRef<str>>(&mut self, path: P) -> Result<Id> {
self.run_command("addid", path.as_ref())
pub fn push<P: ToSongPath>(&mut self, path: P) -> Result<Id> {
self.run_command("addid", path)
.and_then(|_| self.read_field("Id"))
.and_then(|v| {
self.expect_ok()
Expand All @@ -247,8 +247,8 @@ impl<S: Read + Write> Client<S> {
}

/// Insert a song into a given position in a queue
pub fn insert<P: AsRef<str>>(&mut self, path: P, pos: usize) -> Result<usize> {
self.run_command("addid", (path.as_ref(), pos))
pub fn insert<P: ToSongPath>(&mut self, path: P, pos: usize) -> Result<usize> {
self.run_command("addid", (path, pos))
.and_then(|_| self.read_field("Id"))
.and_then(|v| {
self.expect_ok()
Expand Down Expand Up @@ -383,8 +383,8 @@ impl<S: Read + Write> Client<S> {
}

/// Add new songs to a playlist
pub fn pl_push<N: ToPlaylistName, P: AsRef<str>>(&mut self, name: N, path: P) -> Result<()> {
self.run_command("playlistadd", (name.to_name(), path.as_ref()))
pub fn pl_push<N: ToPlaylistName, P: ToSongPath>(&mut self, name: N, path: P) -> Result<()> {
self.run_command("playlistadd", (name.to_name(), path))
.and_then(|_| self.expect_ok())
}

Expand Down Expand Up @@ -427,7 +427,7 @@ impl<S: Read + Write> Client<S> {
// Database search {{{
// TODO: count tag needle [...] [group] [grouptag], find type what [...] [window start:end]
// TODO: search type what [...] [window start:end], searchadd type what [...]
// TODO: findadd type what [...], listallinfo [uri], listfiles [uri], lsinfo [uri]
// TODO: listallinfo [uri], listfiles [uri]
// TODO: list type [filtertype] [filterwhat] [...] [group] [grouptype] [...]
// TODO: searchaddpl name type what [...], readcomments

Expand Down Expand Up @@ -455,6 +455,26 @@ impl<S: Read + Write> Client<S> {
})
}

/// Lists unique tags values of the specified type for songs matching the given query.
// TODO: list type [filtertype] [filterwhat] [...] [group] [grouptype] [...]
// It isn't clear if or how `group` works
pub fn list(&mut self, term: &Term, query: &Query) -> Result<Vec<String>> {
self.run_command("list", (term, query))
.and_then(|_| self.read_pairs().map(|p| p.map(|p| p.1)).collect())
}

/// Find all songs in the db that match query and adds them to current playlist.
pub fn findadd(&mut self, query: &Query) -> Result<()> {
Copy link
Owner

@kstep kstep Jan 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought of joining up searchadd and findadd together into a single method, as the functionality of these commands are essentially the same, except for case-sensitivity, which can be passed either as a separate parameter, or as a field in Query object (debatable).

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On one hand, having something like that would make sense. On the other, keeping them separate makes it easier for somebody looking at MPD documentation to figure out what the corresponding method is. Given that most of the methods currently do match with the underlying MPD commands, I'd be inclined to at least have a lower-level interface that more closely mirrors the underlying protocol.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll merge it as is for now, but I think this point should be thought through more thoroughly.

self.run_command("findadd", query)
.and_then(|_| self.expect_ok())
}

/// Lists the contents of a directory.
pub fn lsinfo<P: ToSongPath>(&mut self, path: P) -> Result<Song> {
self.run_command("lsinfo", path)
.and_then(|_| self.read_struct())
}

// }}}

// Output methods {{{
Expand Down
32 changes: 32 additions & 0 deletions src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use error::Error;
use output::Output;
use playlist::Playlist;
use proto::ToArguments;
use song::{self, Id, Song};
use std::collections::BTreeMap;
use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
Expand Down Expand Up @@ -281,4 +282,35 @@ impl ToSongRange for song::Range {
self
}
}

// }}}

pub trait ToSongPath {
fn to_path(&self) -> &str;
}

impl ToSongPath for Song {
fn to_path(&self) -> &str {
&self.file
}
}

impl<'a, T: ToSongPath> ToSongPath for &'a T {
fn to_path(&self) -> &str {
(*self).to_path()
}
}

impl ToSongPath for AsRef<str> {
fn to_path(&self) -> &str {
self.as_ref()
}
}

impl<T: ToSongPath> ToArguments for T {
fn to_arguments<F, E>(&self, f: &mut F) -> Result<(), E>
where F: FnMut(&str) -> Result<(), E>
{
self.to_path().to_arguments(f)
}
}
10 changes: 9 additions & 1 deletion src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,19 @@ impl<'a> fmt::Display for Term<'a> {
}
}

impl<'a> ToArguments for &'a Term<'a> {
fn to_arguments<F, E>(&self, f: &mut F) -> StdResult<(), E>
where F: FnMut(&str) -> StdResult<(), E>
{
f(&self.to_string())
}
}

impl<'a> ToArguments for &'a Filter<'a> {
fn to_arguments<F, E>(&self, f: &mut F) -> StdResult<(), E>
where F: FnMut(&str) -> StdResult<(), E>
{
f(&self.typ.to_string())?;
(&self.typ).to_arguments(f)?;
f(&self.what)
}
}
Expand Down