async def hivivek(ctx): """Says hi vivek in the nearest voice channel""" try: await ctx.message.delete() ## now nav to parent group (if there is one, then first active voice channel) categoryid = ctx.channel.category_id category = ctx.guild.get_channel(categoryid) await ctx.send("@vivek hi") for channel in category.voice_channels: print('got channel', channel.name) voicething = await channel.connect() print('connected') tcardaudio = discord.PCMAudio(open("./hivivek/hivivek.wav", "rb")) print('setup sound') print('opus loaded') voicething.play(tcardaudio) print('playeded') while voicething.is_playing(): time.sleep(1) await voicething.disconnect() except Exception as e: print('hivivek exception',type(e),e)
async def change_channel(self): try: selection = self.channels.currentData() self.mute.setText("Mute") self.setEnabled(False) if selection is not None: not_connected = ( self.voice is None or self.voice is not None and not self.voice.is_connected() ) if not_connected: self.voice = await selection.connect(timeout=10) else: await self.voice.move_to(selection) not_playing = ( self.devices.currentData() is not None and not self.voice.is_playing() ) if not_playing: self.voice.play(discord.PCMAudio(self.stream)) else: if self.voice is not None: await self.voice.disconnect() except Exception: logging.exception("Error on change_channel") finally: self.setEnabled(True)
async def generate_source( self, message: discord.Message, user_preference: UserVoicePreference, english_dict: dict) -> Optional[discord.PCMAudio]: read_name = all( (True if self.least_user != message.author.id else False, self.guild_preference.read_name)) text = message.clean_content text = code_block_compiled.sub("", text) if read_name: if self.guild_preference.read_nick: text = message.author.display_name + "、" + text else: text = message.author.name + "、" + text text = self.escape_dictionary(text) sentences = english_compiled.findall(text) for sentence in sentences: if sentence.upper() in english_dict.keys(): text = text.replace(sentence, english_dict[sentence.upper()]) if len(text) > self.guild_preference.limit: text = text[:self.guild_preference.limit] + "、以下略" if not text: return None async with self.jtalk_lock: # async with self.voice_event_lock: self.jtalk.set_speed(user_preference.speed) self.jtalk.set_tone(user_preference.tone) self.jtalk.set_intone(user_preference.intone) self.jtalk.set_volume(user_preference.volume) r = await self.loop.run_in_executor(self.executor, partial(self.get_source, text)) self.least_user = message.author.id return discord.PCMAudio(r)
async def change_channel(self): try: s_name = self.sv.get() c_name = self.cv.get() if c_name != 'None': guild = discord.utils.find( lambda s: s.id == self.server_map[s_name].id, self.bot.guilds) channel = discord.utils.find( lambda c: c.id == self.channel_map[c_name].id, guild.channels) self.disable_ui() if self.voice is None or self.voice is not None and not self.voice.is_connected( ): self.voice = await channel.connect(timeout=10) else: await self.voice.move_to(channel) if self.dv.get() != 'None' and not self.voice.is_playing(): self.voice.play(discord.PCMAudio(self.stream)) else: if self.voice is not None: await self.voice.disconnect() self.voice = None except Exception: logging.exception('Error on change_channel') finally: self.enable_ui()
async def play_audio(stream, channel_id): voice_channel = bot.get_channel(channel_id) print(f'- Dispatch audio to \'{voice_channel}\'') last_song_cache[str(channel_id)] = io.BytesIO(stream.getvalue()) try: voice_client = await voice_channel.connect() except discord.ClientException: print(f'Cannot connect to channel {voice_channel}') return if voice_client.is_playing(): print(f'Channel {voice_channel} is busy') return else: buffer = discord.PCMAudio(stream) voice_client.play(buffer) # this loop can probably be removed by using the 'after=' kwarg # of play() that is called when it finishes. however, that seems # to be very hard to get to work with async functions while voice_client.is_playing(): await asyncio.sleep(1) await voice_client.disconnect()
async def change_channel(self): try: s_name = self.sv.get() c_name = self.cv.get() if (c_name != 'None'): guild = discord.utils.find( lambda s: s.id == self.server_map[s_name].id, self.bot.guilds) channel = discord.utils.find( lambda c: c.id == self.channel_map[c_name].id, guild.channels) if (self.voice is None): self.voice = await channel.connect() else: await self.voice.move_to(channel) if (self.dv.get() != 'None' and not self.voice.is_playing()): self.voice.play(discord.PCMAudio(self.stream)) else: if (self.voice is not None): await self.voice.disconnect() self.voice = None except: logging.exception('Error on change_channel')
async def stream_to(voice_client, url, ctx): resp = requests.get(url, stream=True) # Gather information about stream station_name = resp.headers.get("icy-name", "unknown station") genre = resp.headers.get("icy-genre") stream_fmt = resp.headers.get("Content-Type") bitrate = int(resp.headers.get("icy-br", 0)) samplerate = int(resp.headers.get("icy-sr", 0)) audio_info = resp.headers.get("ice-audio-info") metaint = int(resp.headers.get("icy-metaint", 0)) # Send information about stream desc = "" for category, value in zip( ["Genre", "Format", "Bitrate", "Samplerate", "Audio Info"], [genre, stream_fmt, bitrate, samplerate, audio_info]): if value: desc += f"{category}: {value}\n" embed = discord.Embed(title="Radio information:", description=desc, colour=ctx.author.colour.value or 0xff0) embed.set_author(name=f"Streaming from {station_name}", icon_url=voice_client.user.avatar_url) await ctx.send(embed=embed) converter = (ffmpeg.input(url, re=None, loglevel="quiet").output( "pipe:1", format="s16le", ar='48k').run_async(pipe_stdout=True)) voice_client.play(discord.PCMAudio(converter.stdout))
def play_empty(self): """Play blank audio to let Discord know we're still here""" if self.vclient: try: if self.vclient: self.vclient.volume = 0 self.vclient.play(discord.PCMAudio("\n".encode())) except discord.ClientException: pass
async def generate_default_source(self, text: str) -> discord.PCMAudio: async with self.voice_event_lock: self.jtalk.set_speed(1.0) self.jtalk.set_tone(0) self.jtalk.set_intone(1.0) self.jtalk.set_volume(-3.0) r = await self.loop.run_in_executor(self.executor, partial(self.get_source, text)) self.least_user = None return discord.PCMAudio(r)
async def tcard(ctx): """Raises a t-card in the current channel""" try: await ctx.message.delete() embedTcard = discord.Embed.from_dict({ }) embedTcard.set_image(url='http://geas.org.uk/wp-content/uploads/2020/08/tcard-1-e1597167776966.png') ## now nav to parent group (if there is one, then first active voice channel) categoryid = ctx.channel.category_id category = ctx.guild.get_channel(categoryid) ## try to find relevant role to @ rather than the @here cos on our server that gets the admins too, who are sick of it! atRole = None for role in category.changed_roles: if '@' in role.name: continue elif ' ' not in role.name: # make the wild assumption the relevant has a space in it continue elif not atRole or len(role.name)> len(atRole.name): # make the wild assuptiion that the role we want is the longest one, and has a space in it atRole = role if not atRole: atRole = '@here' else: atRole = atRole.mention await ctx.send("{} **T CARD T CARD T CARD T CARD**".format(atRole), embed=embedTcard) for channel in category.voice_channels: print('got channel', channel.name) voicething = await channel.connect() print('connected') tcardaudio = discord.PCMAudio(open("tcard.wav", "rb")) print('setup sound') print('opus loaded') voicething.play(tcardaudio) print('playeded') while voicething.is_playing(): time.sleep(1) await voicething.disconnect() except Exception as e: print('tcard exception',type(e),e)
async def speak_content_in_channel(self, member, content): if member.voice is None or member.voice.channel is None: return voice_channel = member.voice.channel voices_in_guild = [x for x in self.bot.voice_clients if x.guild == voice_channel.guild] if len(voices_in_guild) > 0: voice_client = voices_in_guild[0] if voice_client.channel != voice_channel: await voice_client.disconnect() voice_client = await voice_channel.connect() else: voice_client = await voice_channel.connect() old_guild_document = await self.tts_db.settings.find_one({"_id": member.guild.id}) if old_guild_document is None: old_guild_document = {"_id": member.guild.id, "speed": 1.0, "lang": "en", "tld": "com"} await self.bot.mongo.force_insert(self.tts_db.settings, old_guild_document) lang = old_guild_document.get("lang") speed = old_guild_document.get("speed") tld = old_guild_document.get("tld") with concurrent.futures.ProcessPoolExecutor() as pool: output = await self.bot.loop.run_in_executor(pool, partial(get_speak_file, content, lang, speed, tld)) if member.guild.id not in self.guild_queues: async with self.queue_change_lock: self.guild_queues[member.guild.id] = [] async with self.queue_change_lock: our_uid = self.uid self.uid += 1 self.guild_queues[member.guild.id].append(our_uid) while voice_client.is_playing(): await asyncio.sleep(0.05) while self.guild_queues[member.guild.id][0] != our_uid: await asyncio.sleep(0.05) try: voice_client.play(discord.PCMAudio(output)) except discord.errors.ClientException: pass while voice_client.is_playing(): await asyncio.sleep(0.05) self.guild_queues[member.guild.id].pop(0) return True
async def source(self, session): data = await fetch_voice_data( session=session, token=self.google_cloud_token, text=self.text, language_code=self.language, name=self.voice_setting.voice[self.language], rate=self.voice_setting.speed, pitch=self.voice_setting.pitch, ) return discord.PCMAudio(io.BytesIO(audioop.tostereo(data, 2, 1, 1)))
def change_device(self, options, dv): try: if dv.get() != 'None': if self.voice is not None: self.voice.stop() self.stream.change_device(options.get(dv.get())) self.voice.play(discord.PCMAudio(self.stream)) else: self.stream.change_device(options.get(dv.get())) except Exception: logging.exception('Error on change_device')
async def source(self, session): data = await fetch_voice_data( session=session, token=self.bot.google_cloud_token, text=self.text, language_code=LANGUAGES[self.language], name=convert_voice_name(LANGUAGES[self.language], self.voice_setting.voice[self.language]), rate=self.voice_setting.speed, pitch=self.voice_setting.pitch, ) source = discord.PCMAudio(io.BytesIO(audioop.tostereo(data, 2, 1, 1))) return discord.PCMVolumeTransformer(source, volume=0.4)
async def _play(self, song): if song.stream is None: song.fetch_buffer() await self._join_channel(song.channel) await asyncio.sleep(2) source = discord.PCMVolumeTransformer(discord.PCMAudio(song.stream)) source.volume = song.volume / 100 song.channel.guild.voice_client.play( source, after=lambda e: self.bot.log.error("Player error: %s" % e) if e else None, ) self.lastPlayed[song.channel.guild.id] = datetime.now()
async def create_source( self, attachment: discord.Attachment) -> discord.AudioSource: """ Attachmentからdiscord.PCMAudioを作成します。 :param attachment: 変換するアタッチメント :return: 出力するPCMAudio """ raw = await attachment.read() data = await self.to_pcm( raw, "mp3" if attachment.filename.endswith(".mp3") else "wav") return discord.PCMVolumeTransformer(discord.PCMAudio(data), volume=0.8)
async def _say(self, text: str, context: Union[commands.Context, SlashContext], voice_channel, language, text_to_speech_input=None): # Get text-to-speech data text_to_speech_bytes = await self._get_text_to_speech(text_to_speech_input, language=language) # Check if we got valid text-to-speech data if text_to_speech_bytes.getbuffer().nbytes <= 0: await context.send('There was a problem generating the text-to-speech!') return # Join the voice channel try: await self._guild_locks[context.guild].acquire() voice_client = await self._join_voice_channel(voice_channel) except InsufficientPermissionsException as e: self._guild_locks[context.guild].release() await context.send( f'I don\'t have permission to join your voice channel! Please grant me the following permissions: ' + ', '.join(f'`{x}`' for x in e.permissions) + '.') return # Temporary fix for (https://github.com/TychoTheTaco/Discord-Dictionary-Bot/issues/1) await asyncio.sleep(2.5) # Send text chat reply await context.send(text) # Create a callback to be invoked when the bot is finished playing audio def after(error): # A nested async function is used here to ensure that the bot leaves the voice channel before releasing the associated locks async def after_coroutine(error): if error is not None: logger.error(f'An error occurred while playing audio: {error}') # Update voice channel map self._voice_channels[voice_channel] -= 1 # Disconnect from the voice channel if we don't need it anymore if self._voice_channels[voice_channel] <= 0: await self._leave_voice_channel(voice_channel) self._guild_locks[context.guild].release() asyncio.run_coroutine_threadsafe(after_coroutine(error), self._bot.loop) # Speak voice_client.play(discord.PCMAudio(text_to_speech_bytes), after=after)
def change_device(self): try: selection = self.devices.currentData() self.mute.setText("Mute") if self.voice is not None: self.voice.stop() self.stream.change_device(selection) if self.voice.is_connected(): self.voice.play(discord.PCMAudio(self.stream)) else: self.stream.change_device(selection) except Exception: logging.exception("Error on change_device")
async def tts(self, message, stripped, server): # command: espeak --stdout "hello world" | ffmpeg -i pipe:0 out.ogg caller = message.author guild = message.guild if 'off' not in server.roles and not caller.guild_permissions.manage_guild: for role in caller.roles: if role.id in server.roles: break else: await channel.send( 'You aren\'t allowed to do this. Please tell a moderator to do `{}roles` to set up permissions' .format(server.prefix)) return if caller.voice is None: await channel.send('You aren\'t in a voice channel.') elif not caller.voice.channel.permissions_for(guild.me).connect: await channel.send('No permissions to connect to channel.') else: try: voice = await caller.voice.channel.connect() except discord.errors.ClientException: voice = [ v for v in self.voice_clients if v.channel.guild == guild ][0] if voice.channel != caller.voice.channel: await voice.disconnect() voice = await caller.voice.channel.connect() if voice.is_playing(): voice.stop() s = subprocess.Popen( ['pico2wave', '-w', 'stdout.wav', '"{}"'.format(stripped)], stdout=subprocess.PIPE) s2 = subprocess.Popen([ 'ffmpeg', '-i', '-', '-f', 's16le', '-ar', '48000', '-ac', '2', '-loglevel', 'warning', 'pipe:1' ], stdin=s.stdout, stdout=subprocess.PIPE) voice.play(discord.PCMAudio(s2.stdout))
async def connect(bot, stream, device_id, channel_id, token): try: print('Connecting...') await bot.wait_until_ready() print(f'Logged in as {bot.user.name}') channel = bot.get_channel(channel_id) stream.change_device(device_id) voice = await channel.connect() voice.play(discord.PCMAudio(stream)) print(f'Playing audio in {channel.name}') except Exception: logging.exception('Error on cli connect') sys.exit(1)
async def on_voice_state_update(member, old_state, new_state): # Don't send messages about ourself! if member.id == client.user.id: return # Has the user moved channel? new_channel = new_state.channel old_channel = old_state.channel if old_channel == new_channel: return # Check if the bot needs to change channel. guild = (old_channel and old_channel.guild) or (new_channel and new_channel.guild) assert (guild) await update_bot_channel(guild) if not guild.voice_client: return voice_client = guild.voice_client # Build a message based on the change. message = None lang = None if new_channel == voice_client.channel: lang, hello = get_synonym('Hello', member.display_name) message = f'{hello} {member.display_name}!' if member.display_name == 'James': message = message + ' I was so worried!' elif old_channel == voice_client.channel: lang, goodbye = get_synonym('Goodbye', member.display_name) message = f'{goodbye} {member.display_name}!' # Send the text-to-speech message, or queue it if the bot is already speaking. if message: stream = BytesIO(text_to_pcm(message, lang)) stream.seek( 64 ) # Hack: skip the first couple of frames to fix an audible pop... audio_stream = discord.PCMAudio(stream) if voice_client.is_playing(): message_queue.append(audio_stream) else: voice_client.play(audio_stream, after=partial(after_play_finished, guild))
async def connect(bot, device_id, channel_id): try: print("Connecting...") await bot.wait_until_ready() print(f"Logged in as {bot.user.name}") stream = sound.PCMStream() channel = bot.get_channel(channel_id) stream.change_device(device_id) voice = await channel.connect() voice.play(discord.PCMAudio(stream)) print(f"Playing audio in {channel.name}") except Exception: logging.exception("Error on cli connect") sys.exit(1)
async def loop(self): try: while not self.bot.is_closed(): req = await self.queue.get() if not await self.bot.firestore.spend_char( req.guild.id, len(req.text)): await self.text_channel.send( "申し訳ございません。今月の利用可能文字数を超えてしまいました。" "\nまだご利用になりたい場合は、公式サイトより文字数を購入してください。") await self.close(force=True) return await req.convert_username(self.before_user_id) data = await request_tts(self.bot.access_token, self.session, req) self.before_user_id = req.message.author.id while self.voice_client.is_playing(): await asyncio.sleep(0.5) await asyncio.sleep(0.2) source = discord.PCMAudio( io.BytesIO(audioop.tostereo(data, 2, 1, 1))) self.voice_client.play(source) except asyncio.exceptions.CancelledError: pass except audioop.error as e: import traceback traceback.print_exc() await self.bot.error(e) await self.text_channel.send('内部エラーが発生しました。再接続してください。') await self.close(force=True) except Exception as e: import traceback traceback.print_exc() await self.bot.error(e) await self.text_channel.send('内部エラーが発生しました。再接続してください。') await self.close(force=True)
async def on_voice_state_update(member, old_state, new_state): # Don't send messages about ourself or any other bots! if member.bot: return # Has the user moved channel? new_channel = new_state.channel old_channel = old_state.channel if old_channel == new_channel: return # Check if the bot needs to change channel. guild = (old_channel and old_channel.guild) or (new_channel and new_channel.guild) assert (guild) await update_bot_channel(guild) if not voice_client: return # Build a message based on the change. Treat 'afk' channel as if user disconnected. message = None lang = None if new_channel == voice_client.channel: lang, hello = get_synonym('Hello') message = f'{hello} {member.display_name}!' elif old_channel == voice_client.channel: lang, goodbye = get_synonym('Goodbye') message = f'{goodbye} {member.display_name}!' if member.display_name == 'James': message = message + ' we were so worried!' # Send the text-to-speech message, or queue it if the bot is already speaking. if message and voice_client: audio_stream = discord.PCMAudio(BytesIO(text_to_pcm(message))) if voice_client.is_playing(): message_queue.append(audio_stream) else: voice_client.play(audio_stream, after=after_play_finished)
async def on_voice_state_update(member, old_state, new_state): # Don't send messages about ourself or any other bots! if member.bot: return # Has the user moved channel? new_channel = new_state.channel old_channel = old_state.channel if old_channel == new_channel: return # Check if the bot should go to the new channel. guild = (old_channel and old_channel.guild) or (new_channel and new_channel.guild) assert (guild) await update_bot_channel(guild) # Build a message based on the change. Treat 'afk' channel as if user disconnected. now_in_channel = (new_channel and new_channel != guild.afk_channel) was_in_channel = (old_channel and old_channel != guild.afk_channel) message = None if now_in_channel: if was_in_channel: message = f'{member.display_name} {get_synonym("moved to")} {new_channel.name}.' else: message = f'{get_synonym("Hello")} {member.display_name}!' elif was_in_channel: message = f'{get_synonym("Goodbye")} {member.display_name}!' # Send the text-to-speech message, or queue it if the bot is already speaking. if message and voice_client: audio_stream = discord.PCMAudio(BytesIO(text_to_pcm(message))) if voice_client.is_playing(): message_queue.append(audio_stream) else: voice_client.play(audio_stream, after=after_play_finished)
async def plays(ctx, source): vc = bot.voice_clients[0] audio_src = discord.PCMAudio( 'C:\\Users\\Francois\\Music\\Downloaded by MediaHuman\\The Black Keys - Little Black Submarines.mp3' ) await vc.play(audio_src)
async def __do_play_wav(self, wav, voice_channel): return await self.__do_play_source(discord.PCMAudio(open(wav, "r+b")), voice_channel)
def __set_src__(self): self._file = open(self.path, "rb") self._src = discord.PCMVolumeTransformer(discord.PCMAudio(self._file), volume=self.default_vol)
async def play(self, ctx, song): ctx.voice_client.play(discord.PCMAudio(f'music/{song}')) await ctx.send(ctx.voice_client.is_playing())