def skipto(skip_val): if YoutubeHelper.music_thread is not None: if YoutubeHelper.queue_instance.is_empty(): GM.gui.quick_gui( "The youtube queue is empty, so I can't skip tracks.", text_type='header', box_align='left') return if skip_val > YoutubeHelper.queue_instance.size() - 1: GM.gui.quick_gui( f"You can't skip beyond the length of the current queue.", text_type='header', box_align='left') return if skip_val < 1: next() return GM.gui.quick_gui(f"Skipping to track {skip_val} in the queue.", text_type='header', box_align='left') for i in range(skip_val): YoutubeHelper.queue_instance.pop() GM.logger.info("The youtube audio queue skipped tracks.") utils.clear_directory(utils.get_temporary_img_dir()) stop_audio() download_next() play_audio() return
def download_image_stream(img_url): utils.clear_directory(utils.get_temporary_img_dir()) img_ext = img_url.rsplit('.', 1)[1] with open(f"{utils.get_temporary_img_dir()}image.{img_ext}", 'wb') as img_file: resp = requests.get(img_url, stream=True) for block in resp.iter_content(1024): if not block: break img_file.write(block) debug_print(f"Downloaded image from: {img_url}")
def download_image_requests(img_url): utils.clear_directory(utils.get_temporary_img_dir()) img_ext = img_url.rsplit('.', 1)[1] s = requests.Session() r = s.get(img_url, headers={'User-Agent': 'Mozilla/5.0'}) if r.status_code == 200: with open(f"image.{img_ext}", 'wb') as f: r.raw.decode_content = True shutil.copyfileobj(r.raw, f) debug_print(f"Downloaded image from: {img_url}") else: debug_print(f"403 Error! - {img_url}")
def download_specific(index): queue_list = list(YoutubeHelper.queue_instance.queue_storage) youtube_url = None if len(queue_list) > 0: youtube_url = queue_list[index]['main_url'] else: return if os.path.isfile(utils.get_temporary_img_dir() + f"{queue_list[index]['img_id']}.jpg"): return try: with youtube_dl.YoutubeDL(YoutubeHelper.ydl_opts) as ydl: ydl.extract_info(youtube_url, download=True) except youtube_dl.utils.DownloadError: return return
def exit(self): GM.gui.quick_gui( f"{utils.get_bot_name()} is being shutdown.", text_type='header', box_align='left', ignore_whisper=True, ) for plugin in self.bot_plugins.values(): plugin.quit() utils.clear_directory(utils.get_temporary_img_dir()) reg_print("Cleared temporary directories.") if self.web_thr: from helpers.web_handler import stop_web stop_web() self.web_thr.join() reg_print("JJMumbleBot Web Interface was disconnected.") GM.logger.info("JJMumbleBot Web Interface was disconnected.") self.exit_flag = True
def download_next(): queue_list = list(YoutubeHelper.queue_instance.queue_storage) # print(queue_list) youtube_url = None if len(queue_list) > 0: youtube_url = queue_list[-1]['main_url'] else: return if os.path.isfile(utils.get_temporary_img_dir() + f"{queue_list[-1]['img_id']}.jpg"): # print("Thumbnail exists...skipping") return try: with youtube_dl.YoutubeDL(YoutubeHelper.ydl_opts) as ydl: ydl.extract_info(youtube_url, download=True) #if video['duration'] >= YoutubeHelper.max_track_duration or video['duration'] <= 0.1: # debug_print("Video length exceeds limit...skipping.") # YoutubeHelper.queue_instance.pop() except youtube_dl.utils.DownloadError: return return
def next(): if YoutubeHelper.music_thread is not None: if YoutubeHelper.queue_instance.is_empty(): GM.gui.quick_gui( "The youtube queue is empty, so I can't go to the next song.", text_type='header', box_align='left') return GM.gui.quick_gui("Going to next available track.", text_type='header', box_align='left') GM.logger.info( "The youtube audio queue moved to the next available track.") try: utils.remove_file( f"{YoutubeHelper.current_song_info['img_id']}.jpg", utils.get_temporary_img_dir()) except FileNotFoundError: pass stop_audio() download_next() play_audio() return return
def play_audio(): GM.mumble.sound_output.clear_buffer() time.sleep(0.1) YoutubeHelper.current_song_info = YoutubeHelper.queue_instance.pop() if YoutubeHelper.current_song_info is None: stop_audio() return if YoutubeHelper.current_song_info['img_id'] is None: return YoutubeHelper.current_song = YoutubeHelper.current_song_info.get( 'main_url') stripped_url = BeautifulSoup(YoutubeHelper.current_song, features='html.parser').get_text() uri = stripped_url command = utils.get_vlc_dir() thr = None if not YoutubeHelper.queue_instance.is_empty(): thr = threading.Thread(target=download_next) thr.start() #if YoutubeHelper.music_thread: # YoutubeHelper.music_thread.terminate() # YoutubeHelper.music_thread.kill() # YoutubeHelper.music_thread = None #if YoutubeHelper.music_thread is None: YoutubeHelper.music_thread = sp.Popen([command, uri] + [ '-I', 'dummy', '--quiet', '--one-instance', '--no-repeat', '--sout', '#transcode{acodec=s16le, channels=2, ' 'samplerate=24000, ab=192, threads=8}:std{access=file, ' 'mux=wav, dst=-}', 'vlc://quit' ], stdout=sp.PIPE, bufsize=480) # YoutubeHelper.music_thread.wait() YoutubeHelper.is_playing = True utils.unmute() GM.gui.quick_gui_img( f"{utils.get_temporary_img_dir()}", f"{YoutubeHelper.current_song_info['img_id']}", caption=f"Now playing: {YoutubeHelper.current_song_info['main_title']}", format=True, img_size=32768) while not YoutubeHelper.exit_flag and GM.mumble.isAlive(): while GM.mumble.sound_output.get_buffer_size( ) > 0.5 and not YoutubeHelper.exit_flag: time.sleep(0.01) if YoutubeHelper.music_thread: raw_music = YoutubeHelper.music_thread.stdout.read(480) if raw_music and YoutubeHelper.music_thread and YoutubeHelper.is_playing: GM.mumble.sound_output.add_sound( audioop.mul(raw_music, 2, YoutubeHelper.volume)) else: if not YoutubeHelper.autoplay: YoutubeHelper.is_playing = False if thr: thr.join() try: utils.remove_file( f"{YoutubeHelper.current_song_info['img_id']}.jpg", utils.get_temporary_img_dir()) if YoutubeHelper.queue_instance.size() < 1: utils.clear_directory( utils.get_temporary_img_dir()) except (FileNotFoundError, TypeError): pass download_next() return else: YoutubeHelper.is_playing = False if thr: thr.join() try: utils.remove_file( f"{YoutubeHelper.current_song_info['img_id']}.jpg", utils.get_temporary_img_dir()) if YoutubeHelper.queue_instance.size() < 1: utils.clear_directory( utils.get_temporary_img_dir()) except (FileNotFoundError, TypeError): pass download_next() play_audio() return else: return return
def clear_queue(): YoutubeHelper.queue_instance.clear() if not YoutubeHelper.is_playing: utils.clear_directory(utils.get_temporary_img_dir())
def process_command(self, text): message = text.message.strip() message_parse = message[1:].split(' ', 1) all_messages = message[1:].split() command = message_parse[0] if command == "song": if not pv.plugin_privilege_checker(text, command, self.priv_path): return if YH.current_song_info is not None: GM.gui.quick_gui_img(f"{utils.get_temporary_img_dir()}", f"{YH.current_song_info['img_id']}", caption=f"Now playing: {YH.current_song_info['main_title']}", format=True, img_size=32768) GM.logger.info("Displayed current song in the youtube plugin.") else: GM.gui.quick_gui( f"{utils.get_bot_name()} is not playing anything right now.", text_type='header', box_align='left') return elif command == "autoplay": if not pv.plugin_privilege_checker(text, command, self.priv_path): return if YH.autoplay: YH.autoplay = False; GM.gui.quick_gui( "Autoplay has been disabled.", text_type='header', box_align='left') GM.logger.info("Autoplay has been disabled in the youtube plugin.") else: YH.autoplay = True GM.gui.quick_gui( "Autoplay has been enabled.", text_type='header', box_align='left') GM.logger.info("Autoplay has been enabled in the youtube plugin.") return elif command == "shuffle": if not pv.plugin_privilege_checker(text, command, self.priv_path): return if YH.music_thread is not None: if not YH.queue_instance.is_empty(): YH.queue_instance.shuffle() YM.download_next() GM.gui.quick_gui( "The youtube queue has been shuffled.", text_type='header', box_align='left') GM.logger.info("The youtube audio queue was shuffled.") return elif command == "next": if not pv.plugin_privilege_checker(text, command, self.priv_path): return YM.next() return elif command == "remove": if not pv.plugin_privilege_checker(text, command, self.priv_path): return if YH.music_thread is not None: if YH.queue_instance.is_empty(): GM.gui.quick_gui( "The youtube queue is empty, so I can't remove tracks.", text_type='header', box_align='left') return rem_val = int(message[1:].split(' ', 1)[1]) if rem_val > YH.queue_instance.size() - 1 or rem_val < 0: GM.gui.quick_gui( f"You can't remove tracks beyond the length of the current queue.", text_type='header', box_align='left') return removed_item = YH.queue_instance.remove(rem_val) GM.gui.quick_gui( f"Removed track: [{rem_val}]-{removed_item['main_title']} from the queue.", text_type='header', box_align='left') GM.logger.info(f"Removed track #{rem_val} from the youtube audio queue.") return elif command == "skipto": if not pv.plugin_privilege_checker(text, command, self.priv_path): return skip_val = int(message[1:].split(' ', 1)[1]) YM.skipto(skip_val) GM.logger.info(f"The youtube audio queue skipped to track #{skip_val}.") return elif command == "stop": if not pv.plugin_privilege_checker(text, command, self.priv_path): return if YH.music_thread is not None: GM.gui.quick_gui( "Stopping youtube audio thread.", text_type='header', box_align='left') YH.queue_instance.clear() YM.stop_audio() utils.clear_directory(utils.get_temporary_img_dir()) YH.queue_instance = qh.QueueHandler(YH.max_queue_size) GM.logger.info("The youtube audio thread was stopped.") return return elif command == "clear": if not pv.plugin_privilege_checker(text, command, self.priv_path): return reg_print("Clearing youtube queue.") YM.clear_queue() GM.gui.quick_gui( "Cleared youtube queue.", text_type='header', box_align='left') GM.logger.info("The youtube queue was cleared.") return elif command == "max_duration": if not pv.plugin_privilege_checker(text, command, self.priv_path): return try: new_max = int(message[1:].split(' ', 1)[1]) YM.set_max_track_duration(new_max) GM.gui.quick_gui( f"Set youtube track max duration to {YH.max_track_duration}", text_type='header', box_align='left') GM.logger.info(f"The youtube track max duration was set to {YH.max_track_duration}.") except IndexError: GM.gui.quick_gui( f"Current youtube track max duration: {YH.max_track_duration}", text_type='header', box_align='left') return elif command == "volume": if not pv.plugin_privilege_checker(text, command, self.priv_path): return try: vol = float(message[1:].split(' ', 1)[1]) except IndexError: GM.gui.quick_gui( f"Current youtube volume: {YH.volume}", text_type='header', box_align='left') return if vol > 1: GM.gui.quick_gui( "Invalid Volume Input: [0-1]", text_type='header', box_align='left') return if vol < 0: GM.gui.quick_gui( "Invalid Volume Input: [0-1]", text_type='header', box_align='left') return YH.volume = vol GM.gui.quick_gui( f"Set volume to {YH.volume}", text_type='header', box_align='left') GM.logger.info(f"The youtube audio volume was changed to {YH.volume}.") return elif command == "youtube": if not pv.plugin_privilege_checker(text, command, self.priv_path): return try: search_term = message_parse[1] except IndexError: return YH.all_searches = YM.get_search_results(search_term) search_results = YM.get_choices(YH.all_searches) GM.gui.quick_gui( f"{search_results}\nWhich one would you like to play?", text_type='header', box_align='left', text_align='left') GM.logger.info("Displayed youtube search results.") YH.can_play = True return elif command == "queue": if not pv.plugin_privilege_checker(text, command, self.priv_path): return queue_results = YM.get_queue() if queue_results is not None: cur_text = "" for i, item in enumerate(queue_results): cur_text += f"{item}" if i % 50 == 0 and i != 0: GM.gui.quick_gui( f"{cur_text}", text_type='header', box_align='left', text_align='left') cur_text = "" if cur_text != "": GM.gui.quick_gui( f"{cur_text}", text_type='header', box_align='left', text_align='left') GM.logger.info("Displayed current youtube queue.") return else: GM.gui.quick_gui( "The youtube queue is empty.", text_type='header', box_align='left') return elif command == "playlist": if not pv.plugin_privilege_checker(text, command, self.priv_path): return if len(message_parse) == 2: stripped_url = BeautifulSoup(message_parse[1], features='html.parser').get_text() if "youtube.com" in stripped_url or "youtu.be" in stripped_url: if YH.queue_instance.is_full(): GM.gui.quick_gui( "The youtube queue is full!", text_type='header', box_align='left') return all_song_data = YM.download_playlist(stripped_url) if all_song_data is None: return self.sound_board_plugin.clear_audio_thread() for i, song_data in enumerate(all_song_data): YH.queue_instance.insert(song_data) GM.gui.quick_gui( f"Playlist generated: {stripped_url}", text_type='header', box_align='left') GM.logger.info(f"Generated playlist: {stripped_url}") if not YH.is_playing: YM.download_next() YM.play_audio() return else: GM.gui.quick_gui( "The given link was not identified as a youtube video link!", text_type='header', box_align='left') return elif command == "linkfront": if not pv.plugin_privilege_checker(text, command, self.priv_path): return if len(message_parse) == 2: stripped_url = BeautifulSoup(message_parse[1], features='html.parser').get_text() if "youtube.com" in stripped_url or "youtu.be" in stripped_url: if YH.queue_instance.is_full(): GM.gui.quick_gui( "The youtube queue is full!", text_type='header', box_align='left') return song_data = YM.download_song_name(stripped_url) if song_data is None: GM.gui.quick_gui( "ERROR: The chosen stream was either too long or a live stream.", text_type='header', box_align='left') return song_data['main_url'] = stripped_url self.sound_board_plugin.clear_audio_thread() YH.queue_instance.insert_priority(song_data) GM.gui.quick_gui( f"Added to front of queue: {stripped_url}", text_type='header', box_align='left') GM.logger.info("Direct link added to the front of the youtube queue.") if not YH.is_playing: YM.download_next() YM.play_audio() return else: GM.gui.quick_gui( "The given link was not identified as a youtube video link!", text_type='header', box_align='left') return elif command == "link": if not pv.plugin_privilege_checker(text, command, self.priv_path): return if len(message_parse) == 2: stripped_url = BeautifulSoup(message_parse[1], features='html.parser').get_text() if "youtube.com" in stripped_url or "youtu.be" in stripped_url: if YH.queue_instance.is_full(): GM.gui.quick_gui( "The youtube queue is full!", text_type='header', box_align='left') return song_data = YM.download_song_name(stripped_url) if song_data is None: GM.gui.quick_gui( "ERROR: The chosen stream was either too long or a live stream.", text_type='header', box_align='left') return song_data['main_url'] = stripped_url self.sound_board_plugin.clear_audio_thread() YH.queue_instance.insert(song_data) GM.gui.quick_gui( f"Added to queue: {stripped_url}", text_type='header', box_align='left') GM.logger.info("Direct link added to youtube queue.") if not YH.is_playing: YM.download_next() YM.play_audio() return else: GM.gui.quick_gui( "The given link was not identified as a youtube video link!", text_type='header', box_align='left') return elif command == "play": if not pv.plugin_privilege_checker(text, command, self.priv_path): return if YH.can_play: if YH.queue_instance.is_full(): GM.gui.quick_gui( "The youtube queue is full!", text_type='header', box_align='left') return self.sound_board_plugin.clear_audio_thread() if len(all_messages) == 1: song_data = YM.download_song_name( "https://www.youtube.com" + YH.all_searches[0]['href']) if song_data is None: GM.gui.quick_gui( f"The chosen video is too long. The maximum video length is {(YH.max_track_duration/60)} minutes", text_type='header', box_align='left') return song_data['main_url'] = "https://www.youtube.com" + YH.all_searches[0]['href'] GM.gui.quick_gui( f"Automatically chosen: {YH.all_searches[0]['title']}", text_type='header', box_align='left') YH.can_play = False YH.queue_instance.insert(song_data) if not YH.is_playing: YM.download_next() YM.play_audio() elif len(all_messages) == 2: if 9 >= int(all_messages[1]) >= 0: song_data = YM.download_song_name( "https://www.youtube.com" + YH.all_searches[int(all_messages[1])]['href']) if song_data is None: utils.echo(utils.get_my_channel(), f"The chosen video is too long. The maximum video length is {(YH.max_track_duration/60)} minutes") return song_data['main_url'] = "https://www.youtube.com" + YH.all_searches[int(all_messages[1])]['href'] GM.gui.quick_gui( f"You've chosen: {YH.all_searches[int(all_messages[1])]['title']}", text_type='header', box_align='left') YH.can_play = False else: GM.gui.quick_gui( "Invalid choice! Valid Range [0-9]", text_type='header', box_align='left') YH.can_play = False return YH.queue_instance.insert(song_data) if not YH.is_playing: YM.download_next() YM.play_audio() elif len(all_messages) == 3: if 9 >= int(all_messages[1]) >= 0: song_data = YM.download_song_name( "https://www.youtube.com" + YH.all_searches[int(all_messages[1])]['href']) if song_data is None: GM.gui.quick_gui( f"The chosen video is too long. The maximum video length is {(YH.max_track_duration/60)} minutes", text_type='header', box_align='left') return song_data['main_url'] = "https://www.youtube.com" + YH.all_searches[int(all_messages[1])]['href'] GM.gui.quick_gui( f"You've chosen: {YH.all_searches[int(all_messages[1])]['title']}", text_type='header', box_align='left') YH.can_play = False else: GM.gui.quick_gui( "Invalid choice! Valid Range [0-9]", text_type='header', box_align='left') YH.can_play = False return count = int(all_messages[2]) for i in range(count): YH.queue_instance.insert(song_data) if not YH.is_playing: YM.download_next() YM.play_audio() return elif command == "replay": if not pv.plugin_privilege_checker(text, command, self.priv_path): return if YH.music_thread is not None: if YH.current_song is not None and YH.current_song_info is not None: YH.queue_instance.insert_priority(YH.current_song_info) YM.stop_audio() YM.download_next() YM.play_audio() else: GM.gui.quick_gui( "There is no track available to replay.", text_type='header', box_align='left') return return
def process_command(self, text): message = text.message.strip() message_parse = message[1:].split(' ', 1) command = message_parse[0] if command == "post": if not pv.plugin_privilege_checker(text, command, self.priv_path): return img_url = message_parse[1] # Download image img_url = ''.join( BeautifulSoup(img_url, 'html.parser').findAll(text=True)) IH.download_image_stream(img_url) # Format image time.sleep(1) img_ext = img_url.rsplit('.', 1)[1] formatted_string = IH.format_image("image", img_ext, utils.get_temporary_img_dir()) reg_print("Posting an image to the mumble channel chat.") # Display image with PGUI system GM.gui.quick_gui_img( f"{utils.get_temporary_img_dir()}", formatted_string, bgcolor=GM.cfg['Plugin_Settings']['Images_FrameColor'], cellspacing=GM.cfg['Plugin_Settings']['Images_FrameSize'], format=False) GM.logger.info( f"Posted an image to the mumble channel chat from: {message_parse[1]}." ) return elif command == "img": if not pv.plugin_privilege_checker(text, command, self.priv_path): return parameter = message_parse[1] if not os.path.isfile(utils.get_permanent_media_dir() + f"images/{parameter}.jpg"): GM.gui.quick_gui("The image does not exist.", text_type='header', box_align='left') return False # Format image img_data = parameter.rsplit('.', 1) formatted_string = IH.format_image( img_data[0], "jpg", utils.get_permanent_media_dir() + "images/") reg_print("Posting an image to the mumble channel chat.") # Display image with PGUI system GM.gui.quick_gui_img( f"{utils.get_permanent_media_dir()}images/", formatted_string, bgcolor=GM.cfg['Plugin_Settings']['Images_FrameColor'], cellspacing=GM.cfg['Plugin_Settings']['Images_FrameSize'], format=False) GM.logger.info( "Posted an image to the mumble channel chat from local files.") return elif command == "imglist": if not pv.plugin_privilege_checker(text, command, self.priv_path): return file_counter = 0 gather_list = [] internal_list = [] for file_item in os.listdir(utils.get_permanent_media_dir() + "images/"): if file_item.endswith(".jpg"): gather_list.append(f"{file_item}") file_counter += 1 gather_list.sort(key=str.lower) for i, item in enumerate(gather_list): internal_list.append( f"<br><font color='{GM.cfg['PGUI_Settings']['IndexTextColor']}'>[{i}]</font> - [{item}]" ) cur_text = f"<font color='{GM.cfg['PGUI_Settings']['HeaderTextColor']}'>Local Image Files:</font>" if len(internal_list) == 0: cur_text += "<br>There are no local image files available." GM.gui.quick_gui(cur_text, text_type='header', box_align='left', user=GM.mumble.users[text.actor]['name']) GM.logger.info("Displayed a list of all local image files.") return for i, item in enumerate(internal_list): cur_text += item if i % 50 == 0 and i != 0: GM.gui.quick_gui(cur_text, text_type='header', box_align='left', text_align='left', user=GM.mumble.users[text.actor]['name']) cur_text = "" if cur_text != "": GM.gui.quick_gui(cur_text, text_type='header', box_align='left', text_align='left', user=GM.mumble.users[text.actor]['name']) GM.logger.info("Displayed a list of all local image files.") return elif command == "imglist_echo": if not pv.plugin_privilege_checker(text, command, self.priv_path): return file_counter = 0 gather_list = [] internal_list = [] for file_item in os.listdir(utils.get_permanent_media_dir() + "images/"): if file_item.endswith(".jpg"): gather_list.append(f"{file_item}") file_counter += 1 gather_list.sort(key=str.lower) for i, item in enumerate(gather_list): internal_list.append( f"<br><font color='{GM.cfg['PGUI_Settings']['IndexTextColor']}'>[{i}]</font> - [{item}]" ) cur_text = f"<font color='{GM.cfg['PGUI_Settings']['HeaderTextColor']}'>Local Image Files:</font>" if len(internal_list) == 0: cur_text += "<br>There are no local image files available." GM.gui.quick_gui(cur_text, text_type='header', box_align='left') GM.logger.info("Displayed a list of all local image files.") return for i, item in enumerate(internal_list): cur_text += item if i % 50 == 0 and i != 0: GM.gui.quick_gui(cur_text, text_type='header', box_align='left', text_align='left') cur_text = "" if cur_text != "": GM.gui.quick_gui(cur_text, text_type='header', box_align='left', text_align='left') GM.logger.info("Displayed a list of all local image files.") return