main.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. extern crate discord;
  2. use std::env;
  3. use discord::{Discord, State};
  4. use discord::model::Event;
  5. // A simple DJ bot example.
  6. // Use by issuing the command "!dj <youtube-link>" in PM or a visible text channel.
  7. // The bot will join the voice channel of the person issuing the command.
  8. // "!dj stop" will stop playing, and "!dj quit" will quit the voice channel.
  9. // The bot will quit any voice channel it is the last user in.
  10. pub fn main() {
  11. // Log in to Discord using a bot token from the environment
  12. let discord = Discord::from_bot_token(
  13. &env::var("DISCORD_TOKEN").expect("Expected token"),
  14. ).expect("login failed");
  15. // establish websocket and voice connection
  16. let (mut connection, ready) = discord.connect().expect("connect failed");
  17. println!("[Ready] {} is serving {} servers", ready.user.username, ready.servers.len());
  18. let mut state = State::new(ready);
  19. connection.sync_calls(&state.all_private_channels());
  20. // receive events forever
  21. loop {
  22. let event = match connection.recv_event() {
  23. Ok(event) => event,
  24. Err(err) => {
  25. println!("[Warning] Receive error: {:?}", err);
  26. if let discord::Error::WebSocket(..) = err {
  27. // Handle the websocket connection being dropped
  28. let (new_connection, ready) = discord.connect().expect("connect failed");
  29. connection = new_connection;
  30. state = State::new(ready);
  31. println!("[Ready] Reconnected successfully.");
  32. }
  33. if let discord::Error::Closed(..) = err {
  34. break
  35. }
  36. continue
  37. },
  38. };
  39. state.update(&event);
  40. match event {
  41. Event::MessageCreate(message) => {
  42. // safeguard: stop if the message is from us
  43. if message.author.id == state.user().id {
  44. continue
  45. }
  46. // reply to a command if there was one
  47. let mut split = message.content.split(' ');
  48. let first_word = split.next().unwrap_or("");
  49. let argument = split.next().unwrap_or("");
  50. let prefix = "!";
  51. if first_word.starts_with(prefix) {
  52. let vchan = state.find_voice_user(message.author.id);
  53. let command: String = first_word.chars().skip(prefix.chars().count()).collect();
  54. match command.as_ref() {
  55. "stop" => {
  56. vchan.map(|(sid, _)| connection.voice(sid).stop());
  57. },
  58. "quit" => {
  59. vchan.map(|(sid, _)| connection.drop_voice(sid));
  60. },
  61. "play" => {
  62. let output = if let Some((server_id, channel_id)) = vchan {
  63. match discord::voice::open_ytdl_stream(argument) {
  64. Ok(stream) => {
  65. let voice = connection.voice(server_id);
  66. voice.set_deaf(true);
  67. voice.connect(channel_id);
  68. voice.play(stream);
  69. String::new()
  70. },
  71. Err(error) => format!("Error: {}", error),
  72. }
  73. } else {
  74. "You must be in a voice channel to DJ".to_owned()
  75. };
  76. if !output.is_empty() {
  77. warn(discord.send_message(message.channel_id, &output, "", false));
  78. }
  79. },
  80. _ => {
  81. }
  82. }
  83. }
  84. }
  85. Event::VoiceStateUpdate(server_id, _) => {
  86. // If someone moves/hangs up, and we are in a voice channel,
  87. if let Some(cur_channel) = connection.voice(server_id).current_channel() {
  88. // and our current voice channel is empty, disconnect from voice
  89. match server_id {
  90. Some(server_id) => if let Some(srv) = state.servers().iter().find(|srv| srv.id == server_id) {
  91. if srv.voice_states.iter().filter(|vs| vs.channel_id == Some(cur_channel)).count() <= 1 {
  92. connection.voice(Some(server_id)).disconnect();
  93. }
  94. },
  95. None => if let Some(call) = state.calls().get(&cur_channel) {
  96. if call.voice_states.len() <= 1 {
  97. connection.voice(server_id).disconnect();
  98. }
  99. }
  100. }
  101. }
  102. }
  103. _ => {}, // discard other events
  104. }
  105. }
  106. }
  107. fn warn<T, E: ::std::fmt::Debug>(result: Result<T, E>) {
  108. match result {
  109. Ok(_) => {},
  110. Err(err) => println!("[Warning] {:?}", err)
  111. }
  112. }