Improve some vc stuff and implement quote tts

This commit is contained in:
2021-10-07 12:24:05 +02:00
parent 1d05d5ca22
commit 2b48a566a5
2 changed files with 72 additions and 21 deletions

51
bot.py
View File

@@ -15,7 +15,8 @@ from dotenv import load_dotenv
from lib.config import config, config_load, config_save, config_get, config_set, config_get_descriptions, \ from lib.config import config, config_load, config_save, config_get, config_set, config_get_descriptions, \
config_set_raw, config_meta config_set_raw, config_meta
from lib.utils import async_filter, find_category, find_role_case_insensitive, link_channel from lib.utils import async_filter, find_category, find_role_case_insensitive, link_channel, connect_and_play, \
text_to_speech
VERSION = "1.0.2" VERSION = "1.0.2"
@@ -105,10 +106,9 @@ async def on_message(message: discord.Message):
voice: discord.VoiceState = loeh.voice voice: discord.VoiceState = loeh.voice
try: try:
voice_channel: discord.VoiceChannel = voice.channel voice_channel: discord.VoiceChannel = voice.channel
voice_protocol: discord.VoiceProtocol = await voice_channel.connect() source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(source=OCH_LOEH_SOUND))
if type(voice_protocol) is discord.VoiceClient: voice_protocol = await connect_and_play(voice_channel, source=source)
source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(source=OCH_LOEH_SOUND))
voice_protocol.play(source)
await loeh.edit(mute=True) await loeh.edit(mute=True)
sleeper = asyncio.sleep(config_get('och-timeout', message.guild.id)) sleeper = asyncio.sleep(config_get('och-timeout', message.guild.id))
@@ -118,7 +118,7 @@ async def on_message(message: discord.Message):
if message is not None: if message is not None:
await message.edit(content="~~Zu Befehl!~~\nEs sei ihm verziehen.") await message.edit(content="~~Zu Befehl!~~\nEs sei ihm verziehen.")
if type(voice_protocol) is discord.VoiceClient: if type(voice_protocol) is discord.VoiceClient:
await voice_protocol.disconnect() await voice_protocol.disconnect(force=True)
except (asyncio.TimeoutError, discord.Forbidden, discord.HTTPException, discord.ClientException): except (asyncio.TimeoutError, discord.Forbidden, discord.HTTPException, discord.ClientException):
await message.channel.send('Failed to complete your command, Sir') await message.channel.send('Failed to complete your command, Sir')
return return
@@ -145,15 +145,8 @@ async def on_message(message: discord.Message):
matches.append(member) matches.append(member)
if matches and voice is not None: if matches and voice is not None:
voice_protocol: discord.VoiceProtocol = await voice.connect() source, destroy_tts = await text_to_speech(message.content)
if type(voice_protocol) is discord.VoiceClient: voice_protocol: Optional[discord.VoiceProtocol] = await connect_and_play(voice, source)
tts = gtts.gTTS(message.content, lang='de')
os.makedirs('temp', exist_ok=True)
tts.save('temp/och.mp3')
source = discord.PCMVolumeTransformer(
discord.FFmpegPCMAudio(source='temp/och.mp3', before_options='-v quiet')
)
voice_protocol.play(source)
async def _mute(m: discord.Member): async def _mute(m: discord.Member):
await m.edit(mute=True) await m.edit(mute=True)
@@ -173,11 +166,11 @@ async def on_message(message: discord.Message):
if message is not None: if message is not None:
waiter = message.edit(content='~~Auf gehts!~~\nGeschafft!') waiter = message.edit(content='~~Auf gehts!~~\nGeschafft!')
if type(voice_protocol) is discord.VoiceClient: if type(voice_protocol) is discord.VoiceClient:
await voice_protocol.disconnect() await voice_protocol.disconnect(force=True)
if waiter is not None: if waiter is not None:
await waiter await waiter
os.remove('temp/och.mp3') destroy_tts()
else: else:
await message.channel.send('404: No users found!') await message.channel.send('404: No users found!')
elif config_get('inf19x-insiders-enable', message.guild.id): elif config_get('inf19x-insiders-enable', message.guild.id):
@@ -766,11 +759,17 @@ def get_quotes(guild_id: int) -> Dict[str, List[str]]:
description="The author to filter by", description="The author to filter by",
option_type=str, option_type=str,
required=False required=False
),
create_option(
name="tts",
description="Text to speech to voice chat",
option_type=SlashCommandOptionType.BOOLEAN,
required=False
) )
], ],
guild_ids=slash_guild_ids guild_ids=slash_guild_ids
) )
async def quote_random_slash(ctx: SlashContext, author: Optional[str] = None): async def quote_random_slash(ctx: SlashContext, author: Optional[str] = None, tts: bool = False):
if not await check_slash_context(ctx, False): if not await check_slash_context(ctx, False):
return return
@@ -789,8 +788,20 @@ async def quote_random_slash(ctx: SlashContext, author: Optional[str] = None):
return return
author_quotes = quotes[author] author_quotes = quotes[author]
quote = '\n'.join(map(lambda line: '> ' + line, random.choice(author_quotes).splitlines())) quote = random.choice(author_quotes)
await ctx.send(quote + '\n *~' + author + '*') text = '\n'.join(map(lambda line: '> ' + line, quote.splitlines()))
await ctx.send(text + '\n *~' + author + '*')
if tts:
voice: discord.VoiceState = ctx.author.voice
if voice.channel is not None:
async def after_play(e: discord.DiscordException, vp: discord.VoiceProtocol):
await vp.disconnect(force=True)
source, tts_destroyer = text_to_speech(quote)
await connect_and_play(voice.channel, source, after_play=after_play)
tts_destroyer()
@slash.subcommand( @slash.subcommand(

View File

@@ -1,6 +1,11 @@
import asyncio
import os
import random
import string
from collections import AsyncIterable from collections import AsyncIterable
from typing import Callable, AsyncGenerator, Optional from typing import Callable, AsyncGenerator, Optional, Any, Coroutine
import discord import discord
import gtts
async def async_filter(fun: Callable, iterable: AsyncIterable) -> AsyncGenerator: async def async_filter(fun: Callable, iterable: AsyncIterable) -> AsyncGenerator:
@@ -29,3 +34,38 @@ def link_channel(channel: discord.abc.GuildChannel, italic: bool = False) -> str
return '[*' + channel.name + '*](https://discord.com/channels/' + str(channel.guild.id) + '/' + str( return '[*' + channel.name + '*](https://discord.com/channels/' + str(channel.guild.id) + '/' + str(
channel.id) + ')' channel.id) + ')'
return '[' + channel.name + '](https://discord.com/channels/' + str(channel.guild.id) + '/' + str(channel.id) + ')' return '[' + channel.name + '](https://discord.com/channels/' + str(channel.guild.id) + '/' + str(channel.id) + ')'
def text_to_speech(text: str, lang: str = "de") -> (discord.AudioSource, Callable[[], None]):
tts = gtts.gTTS(text, lang=lang)
os.makedirs('temp', exist_ok=True)
file_name = 'temp/' + ''.join(random.choice(string.ascii_lowercase) for i in range(12)) + '.mp3'
tts.save(file_name)
source = discord.PCMVolumeTransformer(
discord.FFmpegPCMAudio(source=file_name, before_options='-v quiet')
)
def destroy():
os.remove(file_name)
return source, destroy
async def connect_and_play(
channel: discord.VoiceChannel, source: discord.AudioSource,
after_play: Optional[Callable[[discord.DiscordException, discord.VoiceProtocol], Coroutine[Any, Any, Any]]] = None
) -> Optional[discord.VoiceProtocol]:
# noinspection PyTypeChecker
client: discord.VoiceClient = await channel.connect()
after_callback: Optional[Callable[[discord.DiscordException], Any]]
if after_play is None:
after_callback = None
else:
def callback(exc: discord.DiscordException) -> Any:
loop = asyncio.get_event_loop()
return loop.run_until_complete(after_play(exc, client))
after_callback = callback
client.play(source, after=after_callback)
return client