audio.rs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. use super::audio_state::AudioState;
  2. use super::song::Song;
  3. use lazy_static::lazy_static;
  4. use serenity::{
  5. client::Context,
  6. framework::standard::{
  7. macros::{command, group},
  8. Args, CommandResult,
  9. },
  10. model::{channel::Message, id::GuildId},
  11. };
  12. use songbird::tracks::TrackCommand;
  13. use std::{collections::HashMap, sync::Arc};
  14. use tokio::sync::Mutex;
  15. use crate::util::{message_react, send_embed};
  16. #[group]
  17. #[commands(
  18. join,
  19. disconnect,
  20. play,
  21. skip,
  22. pause,
  23. resume,
  24. change_loop,
  25. volume,
  26. shuffle,
  27. clear,
  28. queue
  29. )]
  30. struct Audio;
  31. lazy_static! {
  32. static ref AUDIO_STATES: Mutex<HashMap<GuildId, Arc<Mutex<AudioState>>>> = Mutex::new(HashMap::new());
  33. }
  34. async fn get_audio_state(ctx: &Context, msg: &Message) -> Option<Arc<Mutex<AudioState>>> {
  35. let guild = msg.guild(&ctx.cache).await.unwrap();
  36. let guild_id = guild.id;
  37. let mut audio_states = AUDIO_STATES.lock().await;
  38. let manager = songbird::get(ctx).await.unwrap();
  39. let channel_id = guild
  40. .voice_states
  41. .get(&msg.author.id)
  42. .and_then(|voice_state| voice_state.channel_id);
  43. let channel_id = match channel_id {
  44. Some(channel_id) => channel_id,
  45. None => {
  46. send_embed(ctx, msg, "Error: please be in a voice channel").await;
  47. return None;
  48. }
  49. };
  50. if let Some(call_locked) = manager.get(guild_id) {
  51. let call = call_locked.lock().await;
  52. if call.current_channel().is_none() {
  53. drop(call);
  54. match manager.remove(guild_id).await {
  55. Ok(_) => {}
  56. Err(err) => {
  57. println!("Error leaving call: {:?}", err);
  58. return None;
  59. }
  60. }
  61. audio_states.remove(&guild_id);
  62. }
  63. }
  64. let call_lock = match manager.get(guild_id) {
  65. Some(call) => call,
  66. None => {
  67. audio_states.remove(&guild_id);
  68. match manager.join(guild_id, channel_id).await {
  69. (call, Ok(_)) => call,
  70. (_, Err(err)) => {
  71. println!("Error joining call: {:?}", err);
  72. return None;
  73. }
  74. }
  75. }
  76. };
  77. let mut call = call_lock.lock().await;
  78. if call.current_channel() != Some(channel_id.into()) {
  79. if let Err(err) = call.join(channel_id.into()).await {
  80. println!("Error joining call: {:?}", err);
  81. }
  82. }
  83. match audio_states.get(&guild_id) {
  84. Some(state) => {
  85. let state = state.clone();
  86. AudioState::set_context(state.clone(), ctx, msg).await;
  87. Some(state)
  88. }
  89. None => {
  90. let audio_state = AudioState::new(manager.get(guild_id).unwrap(), ctx, msg);
  91. audio_states.insert(guild_id, audio_state.clone());
  92. Some(audio_state)
  93. }
  94. }
  95. }
  96. async fn remove_audio_state(ctx: &Context, msg: &Message) -> Result<(), String> {
  97. let guild = msg.guild(&ctx.cache).await.unwrap();
  98. let guild_id = guild.id;
  99. let mut audio_states = AUDIO_STATES.lock().await;
  100. let manager = songbird::get(ctx).await.unwrap();
  101. if let Err(_) = manager.remove(guild_id).await {
  102. return Err("Could not leave channel".to_string());
  103. }
  104. if audio_states.remove(&guild_id).is_some() {
  105. Ok(())
  106. } else {
  107. Err("bot is not currently active".to_string())
  108. }
  109. }
  110. #[command]
  111. async fn join(ctx: &Context, msg: &Message) -> CommandResult {
  112. let audio_state = get_audio_state(ctx, msg).await;
  113. if audio_state.is_some() {
  114. message_react(ctx, msg, "🥳").await;
  115. }
  116. Ok(())
  117. }
  118. #[command]
  119. #[aliases("leave")]
  120. async fn disconnect(ctx: &Context, msg: &Message) -> CommandResult {
  121. match remove_audio_state(ctx, msg).await {
  122. Ok(()) => message_react(ctx, msg, "👋").await,
  123. Err(why) => send_embed(ctx, msg, &format!("Error: {}", why)).await,
  124. };
  125. Ok(())
  126. }
  127. #[command]
  128. async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
  129. let query = args.rest().to_string();
  130. message_react(ctx, msg, "🎶").await;
  131. let audio_state = get_audio_state(ctx, msg).await;
  132. let audio_state = match audio_state {
  133. Some(audio_state) => audio_state,
  134. None => return Ok(()),
  135. };
  136. let song = {
  137. let ctx = ctx.clone();
  138. let msg = msg.clone();
  139. tokio::spawn(async move {
  140. let song = Song::from_query(msg.author.clone(), query).await;
  141. match song {
  142. Ok(song) => {
  143. message_react(&ctx, &msg, "✅").await;
  144. Some(song)
  145. }
  146. Err(why) => {
  147. message_react(&ctx, &msg, "❎").await;
  148. send_embed(&ctx, &msg, &format!("Error: {}", why)).await;
  149. None
  150. }
  151. }
  152. })
  153. };
  154. AudioState::add_audio(audio_state, song).await;
  155. Ok(())
  156. }
  157. #[command]
  158. async fn skip(ctx: &Context, msg: &Message) -> CommandResult {
  159. let audio_state = get_audio_state(ctx, msg).await;
  160. let audio_state = match audio_state {
  161. Some(audio_state) => audio_state,
  162. None => return Ok(()),
  163. };
  164. if let Err(why) = AudioState::send_track_command(audio_state, TrackCommand::Stop).await {
  165. send_embed(ctx, msg, &format!("Error: {}", why)).await;
  166. } else {
  167. message_react(ctx, msg, "↪").await;
  168. };
  169. Ok(())
  170. }
  171. #[command]
  172. async fn pause(ctx: &Context, msg: &Message) -> CommandResult {
  173. let audio_state = get_audio_state(ctx, msg).await;
  174. let audio_state = match audio_state {
  175. Some(audio_state) => audio_state,
  176. None => return Ok(()),
  177. };
  178. if let Err(why) = AudioState::send_track_command(audio_state, TrackCommand::Pause).await {
  179. send_embed(ctx, msg, &format!("Error: {}", why)).await;
  180. } else {
  181. message_react(ctx, msg, "⏸").await;
  182. };
  183. Ok(())
  184. }
  185. #[command]
  186. async fn resume(ctx: &Context, msg: &Message) -> CommandResult {
  187. let audio_state = get_audio_state(ctx, msg).await;
  188. let audio_state = match audio_state {
  189. Some(audio_state) => audio_state,
  190. None => return Ok(()),
  191. };
  192. if let Err(why) = AudioState::send_track_command(audio_state, TrackCommand::Play).await {
  193. send_embed(ctx, msg, &format!("Error: {}", why)).await;
  194. } else {
  195. message_react(ctx, msg, "▶").await;
  196. };
  197. Ok(())
  198. }
  199. #[command]
  200. async fn shuffle(ctx: &Context, msg: &Message) -> CommandResult {
  201. let audio_state = get_audio_state(ctx, msg).await;
  202. let audio_state = match audio_state {
  203. Some(audio_state) => audio_state,
  204. None => return Ok(()),
  205. };
  206. if let Err(why) = AudioState::shuffle(audio_state).await {
  207. send_embed(ctx, msg, &format!("Error: {}", why)).await;
  208. } else {
  209. message_react(ctx, msg, "🔀").await;
  210. };
  211. Ok(())
  212. }
  213. #[command]
  214. async fn clear(ctx: &Context, msg: &Message) -> CommandResult {
  215. let audio_state = get_audio_state(ctx, msg).await;
  216. let audio_state = match audio_state {
  217. Some(audio_state) => audio_state,
  218. None => return Ok(()),
  219. };
  220. if let Err(why) = AudioState::clear(audio_state.clone()).await {
  221. send_embed(ctx, msg, &format!("Error: {}", why)).await;
  222. } else {
  223. message_react(ctx, msg, "🗑").await;
  224. };
  225. Ok(())
  226. }
  227. #[command]
  228. #[aliases("loop")]
  229. async fn change_loop(ctx: &Context, msg: &Message) -> CommandResult {
  230. let audio_state = get_audio_state(ctx, msg).await;
  231. let audio_state = match audio_state {
  232. Some(audio_state) => audio_state,
  233. None => return Ok(()),
  234. };
  235. match AudioState::change_looping(audio_state).await {
  236. Ok(true) => message_react(ctx, msg, "🔄").await,
  237. Ok(false) => message_react(ctx, msg, "➡").await,
  238. Err(why) => send_embed(ctx, msg, &format!("Error: {}", why)).await,
  239. };
  240. Ok(())
  241. }
  242. #[command]
  243. #[aliases("vol")]
  244. async fn volume(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
  245. let audio_state = get_audio_state(ctx, msg).await;
  246. let audio_state = match audio_state {
  247. Some(audio_state) => audio_state,
  248. None => return Ok(()),
  249. };
  250. let volume: u8 = args.rest().parse()?;
  251. match AudioState::set_volume(audio_state, volume.into()).await {
  252. Ok(()) => message_react(ctx, msg, "🎶").await,
  253. Err(why) => send_embed(ctx, msg, &format!("Error: {}", why)).await,
  254. };
  255. Ok(())
  256. }
  257. #[command]
  258. async fn queue(ctx: &Context, msg: &Message) -> CommandResult {
  259. let audio_state = get_audio_state(ctx, msg).await;
  260. let audio_state = match audio_state {
  261. Some(audio_state) => audio_state,
  262. None => return Ok(()),
  263. };
  264. send_embed(ctx, msg, &AudioState::get_string(audio_state).await).await;
  265. Ok(())
  266. }