audio_state.rs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. use std::{
  2. sync::Arc,
  3. mem::drop,
  4. };
  5. use rand::seq::SliceRandom;
  6. use super::{
  7. song_queue::SongQueue,
  8. song::{
  9. Song,
  10. },
  11. song_searcher::{
  12. process_query,
  13. song_recommender,
  14. },
  15. subprocess::ffmpeg_pcm,
  16. };
  17. use crate::util::send_embed_http;
  18. use songbird::{Call, Event, EventContext, EventHandler as VoiceEventHandler, TrackEvent,
  19. input::{
  20. self,
  21. reader::Reader,
  22. },
  23. tracks::{
  24. TrackHandle,
  25. TrackCommand,
  26. }
  27. };
  28. use tokio::sync::Mutex;
  29. use serenity::{
  30. async_trait,
  31. prelude::{
  32. Mutex as SerenityMutex,
  33. },
  34. http::Http,
  35. client::Context,
  36. model::{
  37. id::ChannelId,
  38. channel::Message,
  39. },
  40. };
  41. pub struct AudioState{
  42. queue: SongQueue,
  43. handler: Arc<SerenityMutex<Call>>,
  44. current_song: Mutex<Option<Song>>,
  45. track_handle: Mutex<Option<TrackHandle>>,
  46. is_looping: Mutex<bool>,
  47. channel_id: Mutex<ChannelId>,
  48. http: Mutex<Arc<Http>>,
  49. }
  50. impl AudioState{
  51. pub fn new(handler: Arc<SerenityMutex<Call>>, ctx: &Context, msg: &Message) -> Arc<AudioState>{
  52. let audio_state = AudioState{
  53. queue: SongQueue::new(),
  54. handler,
  55. current_song: Mutex::new(None),
  56. track_handle: Mutex::new(None),
  57. is_looping: Mutex::new(false),
  58. channel_id: Mutex::new(msg.channel_id),
  59. http: Mutex::new(ctx.http.clone()),
  60. };
  61. let audio_state = Arc::new(audio_state);
  62. {
  63. let audio_state = audio_state.clone();
  64. tokio::spawn(async {
  65. AudioState::play_audio(audio_state).await;
  66. });
  67. }
  68. audio_state
  69. }
  70. pub async fn set_context(audio_state: Arc<AudioState>, ctx: &Context, msg: &Message){
  71. {
  72. let mut channel_id = audio_state.channel_id.lock().await;
  73. *channel_id = msg.channel_id;
  74. }
  75. {
  76. let mut http = audio_state.http.lock().await;
  77. *http = ctx.http.clone();
  78. }
  79. }
  80. async fn play_audio(audio_state: Arc<AudioState>){
  81. let is_looping = audio_state.is_looping.lock().await;
  82. let mut song = if *is_looping{
  83. let mut current_song = audio_state.current_song.lock().await;
  84. current_song.take().expect("logical error: expected current_song to be non-empty")
  85. }else{
  86. audio_state.queue.pop().await
  87. };
  88. drop(is_looping);
  89. let url = song.get_url().await;
  90. let source = ffmpeg_pcm(url).await;
  91. let source = match source {
  92. Ok(source) => source,
  93. Err(why) => {
  94. println!("Error in AudioState::play_audio: {}", why);
  95. return
  96. }
  97. };
  98. let reader = Reader::Extension(source);
  99. let source = input::Input::float_pcm(true, reader);
  100. let mut handler = audio_state.handler.lock().await;
  101. let handle = handler.play_source(source);
  102. if let Err(why) = handle.add_event(
  103. Event::Track(TrackEvent::End),
  104. SongEndNotifier{
  105. audio_state: audio_state.clone(),
  106. }
  107. ){
  108. panic!("Err AudioState::play_audio: {:?}", why);
  109. }
  110. {
  111. let text = song.get_string().await;
  112. let channel_id = audio_state.channel_id.lock().await;
  113. let http = audio_state.http.lock().await;
  114. send_embed_http(*channel_id, http.clone(), &format!(
  115. "Now playing:\n\n {}", text
  116. )).await;
  117. }
  118. let mut current_song = audio_state.current_song.lock().await;
  119. *current_song = Some(song);
  120. let mut track_handle = audio_state.track_handle.lock().await;
  121. *track_handle = Some(handle);
  122. }
  123. pub async fn add_audio(audio_state: Arc<AudioState>, query: &str, shuffle: bool){
  124. let mut songs = match process_query(query).await{
  125. Ok(songs) => songs,
  126. Err(why) => {
  127. println!("Error add_audio: {}", why);
  128. return;
  129. },
  130. };
  131. if shuffle {
  132. songs.shuffle(&mut rand::thread_rng());
  133. }
  134. audio_state.queue.push(songs).await;
  135. }
  136. pub async fn add_recommended_songs(audio_state: Arc<AudioState>, query: &str, amount: usize){
  137. let mut songs = match song_recommender(query, amount).await{
  138. Ok(songs) => songs,
  139. Err(why) => {
  140. println!("Error add_recommended_songs: {}", why);
  141. return;
  142. },
  143. };
  144. songs.shuffle(&mut rand::thread_rng());
  145. audio_state.queue.push(songs).await;
  146. }
  147. pub async fn extend_songs(audio_state: Arc<AudioState>, query: &str, extend_ratio: f64){
  148. let mut songs = match process_query(query).await{
  149. Ok(songs) => songs,
  150. Err(why) => {
  151. println!("Error extend_songs: {}", why);
  152. return;
  153. },
  154. };
  155. let recommended_songs = match song_recommender(query, (songs.len() as f64 * extend_ratio) as usize).await{
  156. Ok(songs) => songs,
  157. Err(why) => {
  158. println!("Error add_recommended_songs: {}", why);
  159. return;
  160. },
  161. };
  162. songs.extend(recommended_songs);
  163. songs.shuffle(&mut rand::thread_rng());
  164. audio_state.queue.push(songs).await;
  165. }
  166. pub async fn send_track_command(audio_state: Arc<AudioState>, cmd: TrackCommand) -> Result<(), String>{
  167. let track_handle = audio_state.track_handle.lock().await;
  168. match track_handle.as_ref() {
  169. Some(track_handle) => {
  170. match track_handle.send(cmd){
  171. Ok(()) => Ok(()),
  172. Err(why) => Err(format!("{:?}",why))
  173. }
  174. },
  175. None => Err("no song currently playing".to_string())
  176. }
  177. }
  178. pub async fn shuffle(audio_state: Arc<AudioState>) -> Result<(), String>{
  179. audio_state.queue.shuffle().await
  180. }
  181. pub async fn clear(audio_state: Arc<AudioState>) -> Result<(), String>{
  182. audio_state.queue.clear().await
  183. }
  184. // on success, returns a bool that specifies whether the queue is now being looped
  185. pub async fn change_looping(audio_state: Arc<AudioState>) -> Result<bool, String>{
  186. {
  187. let current_song = audio_state.current_song.lock().await;
  188. if current_song.is_none() {
  189. return Err("no song is playing".to_string());
  190. }
  191. }
  192. let mut is_looping = audio_state.is_looping.lock().await;
  193. *is_looping = !*is_looping;
  194. Ok(*is_looping)
  195. /*
  196. if looping{
  197. if *is_looping{
  198. Err("already looping".to_string())
  199. }else{
  200. *is_looping = true;
  201. Ok(())
  202. }
  203. }else{
  204. if !*is_looping{
  205. Err("not looping at the moment".to_string())
  206. }else{
  207. *is_looping = false;
  208. Ok(())
  209. }
  210. }*/
  211. }
  212. pub async fn cleanup(audio_state: Arc<AudioState>) {
  213. audio_state.queue.cleanup().await;
  214. }
  215. pub async fn get_string(audio_state: Arc<AudioState>) -> String {
  216. let current_song = audio_state.current_song.lock().await;
  217. let current_song = match &*current_song {
  218. Some(song) => song.get_string().await,
  219. None => "*Not playing*\n".to_string(),
  220. };
  221. format!("**Current Song:**\n{}\n\n**Queue:**\n{}", current_song, audio_state.queue.get_string().await)
  222. }
  223. }
  224. struct SongEndNotifier {
  225. audio_state: Arc<AudioState>,
  226. }
  227. #[async_trait]
  228. impl VoiceEventHandler for SongEndNotifier {
  229. async fn act(&self, _ctx: &EventContext<'_>) -> Option<Event> {
  230. AudioState::play_audio(self.audio_state.clone()).await;
  231. None
  232. }
  233. }