|
@@ -1,18 +1,24 @@
|
|
|
extern crate argparse;
|
|
|
extern crate bytes;
|
|
|
extern crate futures;
|
|
|
+extern crate mpd;
|
|
|
extern crate mumble_protocol;
|
|
|
extern crate opus;
|
|
|
|
|
|
+mod commands;
|
|
|
+mod util;
|
|
|
+
|
|
|
use argparse::ArgumentParser;
|
|
|
use argparse::Store;
|
|
|
use argparse::StoreTrue;
|
|
|
use bytes::Bytes;
|
|
|
+use commands::parse_command;
|
|
|
use futures::channel::oneshot;
|
|
|
use futures::join;
|
|
|
use futures::stream::SplitSink;
|
|
|
use futures::SinkExt;
|
|
|
use futures::StreamExt;
|
|
|
+use mpd::Client;
|
|
|
use mumble_protocol::control::msgs;
|
|
|
use mumble_protocol::control::ClientControlCodec;
|
|
|
use mumble_protocol::control::ControlPacket;
|
|
@@ -23,6 +29,7 @@ use mumble_protocol::voice::VoicePacketPayload;
|
|
|
use mumble_protocol::Clientbound;
|
|
|
use mumble_protocol::Serverbound;
|
|
|
use opus::Encoder;
|
|
|
+use std::collections::BTreeMap;
|
|
|
use std::convert::Into;
|
|
|
use std::convert::TryInto;
|
|
|
use std::fs::File;
|
|
@@ -38,6 +45,7 @@ use tokio::sync::mpsc;
|
|
|
use tokio_tls::TlsConnector;
|
|
|
use tokio_util::codec::Decoder;
|
|
|
use tokio_util::udp::UdpFramed;
|
|
|
+use util::display_song;
|
|
|
|
|
|
struct AudioSettings {
|
|
|
fifo_path: String,
|
|
@@ -49,6 +57,7 @@ async fn connect(
|
|
|
server_host: String,
|
|
|
user_name: String,
|
|
|
accept_invalid_cert: bool,
|
|
|
+ mpd_addr: String,
|
|
|
crypt_state_sender: oneshot::Sender<ClientCryptState>,
|
|
|
) {
|
|
|
// Wrap crypt_state_sender in Option, so we can call it only once
|
|
@@ -82,6 +91,9 @@ async fn connect(
|
|
|
msg.set_opus(true);
|
|
|
sink.send(msg.into()).await.unwrap();
|
|
|
|
|
|
+ // Connect to MPD
|
|
|
+ let mut conn = Client::connect(mpd_addr).unwrap();
|
|
|
+
|
|
|
println!("Logging in..");
|
|
|
let mut crypt_state = None;
|
|
|
|
|
@@ -105,6 +117,8 @@ async fn connect(
|
|
|
}
|
|
|
});
|
|
|
|
|
|
+ let mut paged_results = BTreeMap::new();
|
|
|
+
|
|
|
while let Some(i) = rx.recv().await {
|
|
|
match i {
|
|
|
Some(packet) => match packet.unwrap() {
|
|
@@ -115,10 +129,17 @@ async fn connect(
|
|
|
msg.get_message()
|
|
|
);
|
|
|
// Send reply back to server
|
|
|
- let mut response = msgs::TextMessage::new();
|
|
|
- response.mut_session().push(msg.get_actor());
|
|
|
- response.set_message(msg.take_message());
|
|
|
- sink.send(response.into()).await.unwrap();
|
|
|
+ if let Some(reply) = parse_command(
|
|
|
+ &mut conn,
|
|
|
+ &mut paged_results,
|
|
|
+ msg.get_actor(),
|
|
|
+ &msg.take_message(),
|
|
|
+ ) {
|
|
|
+ let mut response = msgs::TextMessage::new();
|
|
|
+ response.mut_session().push(msg.get_actor());
|
|
|
+ response.set_message(reply);
|
|
|
+ sink.send(response.into()).await.unwrap();
|
|
|
+ }
|
|
|
}
|
|
|
ControlPacket::CryptSetup(msg) => {
|
|
|
// Wait until we're fully connected before initiating UDP voice
|
|
@@ -150,6 +171,17 @@ async fn connect(
|
|
|
_ => {}
|
|
|
},
|
|
|
None => {
|
|
|
+ // Update status
|
|
|
+ let status = conn
|
|
|
+ .currentsong()
|
|
|
+ .ok()
|
|
|
+ .flatten()
|
|
|
+ .map(|s| display_song(&s))
|
|
|
+ .flatten()
|
|
|
+ .unwrap_or("".to_string());
|
|
|
+ let mut response = msgs::UserState::new();
|
|
|
+ response.set_comment(status);
|
|
|
+ sink.send(response.into()).await.unwrap();
|
|
|
sink.send(msgs::Ping::new().into()).await.unwrap();
|
|
|
}
|
|
|
}
|
|
@@ -291,6 +323,7 @@ async fn main() {
|
|
|
let mut accept_invalid_cert = false;
|
|
|
let mut bitrate = 96_000i32;
|
|
|
let mut fifo_path = "".to_string();
|
|
|
+ let mut mpd_addr = "127.0.0.1:6600".to_string();
|
|
|
{
|
|
|
let mut ap = ArgumentParser::new();
|
|
|
ap.set_description("Mumble bot for streaming music from MPD");
|
|
@@ -315,6 +348,11 @@ async fn main() {
|
|
|
.required();
|
|
|
ap.refer(&mut bitrate)
|
|
|
.add_option(&["--bitrate"], Store, "Opus encoder bitrate (bits/s)");
|
|
|
+ ap.refer(&mut mpd_addr).add_option(
|
|
|
+ &["--mpd-addr"],
|
|
|
+ Store,
|
|
|
+ "MPD TCP control socket address",
|
|
|
+ );
|
|
|
ap.parse_args_or_exit();
|
|
|
}
|
|
|
let server_addr = (server_host.as_ref(), server_port)
|
|
@@ -334,6 +372,7 @@ async fn main() {
|
|
|
server_host,
|
|
|
user_name,
|
|
|
accept_invalid_cert,
|
|
|
+ mpd_addr,
|
|
|
crypt_state_sender,
|
|
|
),
|
|
|
handle_udp(
|