aboutsummaryrefslogtreecommitdiffstats
path: root/cogs/tts.py
diff options
context:
space:
mode:
authorsalmonik <raisersoft@proton.me>2026-02-04 16:19:22 +0100
committersalmonik <raisersoft@proton.me>2026-02-04 16:19:22 +0100
commit72abc43db8f732743c65d6f6a820369ab8665766 (patch)
tree094fafdb0baf2e06a02045b1b2c0be88931a379a /cogs/tts.py
parentrefactor music (diff)
downloadsenator-sperma-72abc43db8f732743c65d6f6a820369ab8665766.tar.gz
senator-sperma-72abc43db8f732743c65d6f6a820369ab8665766.zip
more asynchronous work and other minor improvements
Diffstat (limited to 'cogs/tts.py')
-rw-r--r--cogs/tts.py138
1 files changed, 80 insertions, 58 deletions
diff --git a/cogs/tts.py b/cogs/tts.py
index 3c2f9ce..158006c 100644
--- a/cogs/tts.py
+++ b/cogs/tts.py
@@ -6,7 +6,7 @@
6import os 6import os
7import json 7import json
8import discord 8import discord
9import tempfile 9import aiofiles
10import logging 10import logging
11from discord.ext import commands 11from discord.ext import commands
12from gtts import gTTS 12from gtts import gTTS
@@ -18,80 +18,102 @@ class TTS(commands.Cog):
18 def __init__(self, bot): 18 def __init__(self, bot):
19 self.bot = bot 19 self.bot = bot
20 20
21 async def _load_settings(self):
22 """Load volume settings from settings.json"""
23 volume = 1.0
24 if os.path.exists('settings.json'):
25 try:
26 async with aiofiles.open('settings.json') as f:
27 data = json.load(f)
28 volume = data.get('volume', 1.0)
29 except (json.JSONDecodeError, KeyError) as e:
30 logger.error(f"Error loading settings: {e}")
31 return volume
32
33 async def _handle_file_output(self, ctx, temp_path, text):
34 """Handle TTS file output"""
35 try:
36 await ctx.respond(file=discord.File(temp_path, filename='tts.mp3'))
37 logger.info(f"Sent TTS for text: {text}")
38 except Exception as e:
39 logger.error(f"Error sending file: {e}")
40 await ctx.respond("eror :c", ephemeral=True)
41
42 async def _get_or_connect_voice_client(self, channel):
43 """Get existing voice client or connect to new channel"""
44 voice_client = discord.utils.get(self.bot.voice_clients, guild=channel.guild)
45
46 if not voice_client or not voice_client.is_connected():
47 voice_client = await channel.connect()
48 elif voice_client.channel != channel:
49 await voice_client.move_to(channel)
50
51 return voice_client
52
53 async def _handle_voice_output(self, ctx, temp_path, text, volume):
54 """Handle TTS voice channel output"""
55 await ctx.respond(content="\u200b", ephemeral=True)
56 await ctx.interaction.delete_original_response()
57
58 # Check if the user is in a voice channel
59 if not (ctx.author.voice and ctx.author.voice.channel):
60 logger.info("User is not in a voice channel")
61 return
62
63 channel = ctx.author.voice.channel
64 try:
65 voice_client = await self._get_or_connect_voice_client(channel)
66
67 # Play the TTS audio with volume adjustment
68 audio_source = discord.FFmpegPCMAudio(
69 temp_path,
70 options=f'-filter:a "volume={volume}"'
71 )
72 voice_client.play(audio_source)
73 logger.info(f"Playing TTS: {text}")
74
75 # Wait for the audio to finish playing
76 while voice_client.is_playing():
77 await asyncio.sleep(0.1)
78
79 except Exception as e:
80 logger.error(f"Error in voice channel handling: {e}")
81 await ctx.respond("eror :c", ephemeral=True)
82
83 async def _cleanup_temp_file(self, temp_path):
84 """Clean up temporary file"""
85 try:
86 if temp_path and os.path.exists(temp_path):
87 os.unlink(temp_path)
88 except Exception as e:
89 logger.error(f"Error cleaning up temp file {temp_path}: {e}")
90
21 @commands.slash_command(name="tts", description="Generuje TTS dla danego tekstu") 91 @commands.slash_command(name="tts", description="Generuje TTS dla danego tekstu")
22 async def tts(self, ctx, 92 async def tts(self, ctx,
23 text: str = discord.Option(str, "Tekst do przeczytania", required=True), 93 text: str = discord.Option(str, "Tekst do przeczytania", required=True),
24 output: str = discord.Option(str, "Wybierz sposób odtwarzania", choices=["file", "vc"], default="vc") 94 output: str = discord.Option(str, "Wybierz sposób odtwarzania", choices=["file", "vc"], default="vc")
25 ): 95 ):
26 await ctx.defer() 96 await ctx.defer()
27 # Create a temporary file for TTS output
28 with tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) as temp_file:
29 temp_path = temp_file.name
30 97
98 async with NamedTemporaryFile(suffix=".mp3", delete=False) as temp_file:
99 temp_path = temp_file.name
100
31 try: 101 try:
32 # Generate and save TTS to temp file 102 # Generate and save TTS to temp file
33 tts = gTTS(text=text, lang='pl') 103 tts = gTTS(text=text, lang='pl')
34 tts.save(temp_path) 104 tts.save(temp_path)
35 105
36 # Load settings if available 106 # Load settings
37 volume = 1.0 # Default volume 107 volume = await self._load_settings()
38 if os.path.exists('settings.json'):
39 try:
40 with open('settings.json') as f:
41 data = json.load(f)
42 volume = data.get('volume', 1.0)
43 except (json.JSONDecodeError, KeyError) as e:
44 logger.error(f"Error loading settings: {e}")
45 108
109 # Handle output based on user choice
46 if output == "file": 110 if output == "file":
47 try: 111 await self._handle_file_output(ctx, temp_path, text)
48 await ctx.respond(file=discord.File(temp_path, filename='tts.mp3'))
49 logger.info(f"Sent TTS for text: {text}")
50 except Exception as e:
51 logger.error(f"Error sending file: {e}")
52 await ctx.respond("eror :c", ephemeral=True)
53
54 elif output == "vc": 112 elif output == "vc":
55 await ctx.respond(content="\u200b", ephemeral=True) 113 await self._handle_voice_output(ctx, temp_path, text, volume)
56 await ctx.interaction.delete_original_response()
57
58 # Check if the user is in a voice channel
59 if not (ctx.author.voice and ctx.author.voice.channel):
60 logger.info("User is not in a voice channel")
61 return
62
63 channel = ctx.author.voice.channel
64 try:
65 # Connect to the voice channel if not already connected
66 voice_client = discord.utils.get(self.bot.voice_clients, guild=channel.guild)
67 if not voice_client or not voice_client.is_connected():
68 voice_client = await channel.connect()
69 elif voice_client.channel != channel:
70 await voice_client.move_to(channel)
71
72 # Play the TTS audio with volume adjustment
73 audio_source = discord.FFmpegPCMAudio(
74 temp_path,
75 options=f'-filter:a "volume={volume}"'
76 )
77 voice_client.play(audio_source)
78 logger.info(f"Playing TTS: {text}")
79
80 # Wait for the audio to finish playing
81 while voice_client.is_playing():
82 await asyncio.sleep(0.1)
83
84 except Exception as e:
85 logger.error(f"Error in voice channel handling: {e}")
86 await ctx.respond("eror :c", ephemeral=True)
87 114
88 finally: 115 finally:
89 # Clean up the temporary file 116 await self._cleanup_temp_file(temp_path)
90 try:
91 if temp_path and os.path.exists(temp_path):
92 os.unlink(temp_path)
93 except Exception as e:
94 logger.error(f"Error cleaning up temp file {temp_path}: {e}")
95 117
96def setup(bot): 118def setup(bot):
97 bot.add_cog(TTS(bot)) \ No newline at end of file 119 bot.add_cog(TTS(bot)) \ No newline at end of file