I want to make that when the description of the embed exceeds the word limit it continues in another separate embed but that the previous embed ends with 3 dots (...) eliminating a small part of the message and following it in the other embed, at the moment this is the code I have:
#commands.command(aliases=["pj"])
async def personaje(self, ctx, personaje=None, member: discord.Member=None):
if personaje is None:
await ctx.send(":x: Debes proporcionar la id del personaje que quieres visualizar")
else:
if member is None:
member = ctx.author
if os.path.exists("json/Roleplay/Personajes/{member}/{idpersonaje}.json".format(member=member.id, idpersonaje=personaje)):
with open("json/Roleplay/Personajes/{member}/{idpersonaje}.json".format(member=member.id, idpersonaje=personaje), 'r') as f:
data = json.load(f)
Nombre = data["Nombre"]
Historia = data["Historia"]
color = data["Color"]
personalizado = data["Personalizado"]
text = ""
text = "".join(f"\n**{key}:** {value}" for key, value in personalizado.items())
color = int(color, 16)
timestamp = datetime.datetime.now()
prueba = f"**{Nombre} {text}\n\n**Historia:**\n {Historia}"
if len(prueba) < 2000:
embed=discord.Embed(description=prueba, color=color)
embed.set_author(name=ctx.author, icon_url=ctx.author.avatar_url)
embed.timestamp = timestamp
await ctx.send(embed=embed)
else:
embed=discord.Embed(description=prueba[:-3] + "...", color=color)
embed.set_author(name=ctx.author, icon_url=ctx.author.avatar_url)
embed.timestamp = timestamp
await ctx.send(embed=embed)
else:
await ctx.send(":x: Este personaje no existe")
return
Example of what I want to do (obviously with a longer text that exceeds 2000 words):
https://imgur.com/zytqLKm
Best method is making a function to split the data every n char.
Making fields with name of empty line might be better then using new embed.
Keep in mind don't split at 2000 exactly because you have ...
def split_length(data: str, n: int):
'''Splits the data given at each given n'''
out_data = []
for i in range(0, len(data), n):
out_data.append(data[i:i+n])
return out_data
#bot.command()
async def longtext(ctx):
embed = discord.Embed(title='Example of long text split')
long_text = 'qwerty'
field_values = split_length(data=long_text, n=2)
for value in field_values:
# "\u200b" is just an empty line
embed.add_field(name="\u200b", value=f"{value} ...", inline=True)
await ctx.send(embed=embed)
I'm trying to run a timer function in a function that edit an embed while leaving the initial function running, but I can't find how to do that... Here's my code:
#bot.command(aliases = ['pc'])
async def pour_combien(ctx, lim, reverse, *gage):
async def timer(time, msg_to_edit):
while time >= 0:
await asyncio.sleep(1)
embed.set_footer(text=f"• {time} secondes restantes...\n\n\u270B Pour accepter \u274c Pour annuler (seulement pour le créateur)")
time -= 1
await msg_to_edit.edit(embed=embed)
time = 30.0
embed = discord.Embed([.......])
embed.set_footer(text=f"• {time} secondes restantes...\n\n\u270B Pour accepter \u274c Pour annuler (seulement pour le créateur)")
demande = await ctx.send(embed= embed)
await demande.add_reaction("\u270B")
await demande.add_reaction("\u274c")
await timer(time, demande)
while True:
try:
reaction, user = await bot.wait_for('reaction_add', timeout=time, check=lambda reaction, user: reaction.emoji in [u'\u270B',u'\u274c'])
except asyncio.TimeoutError:
return
else:
if reaction.emoji == u'\u270B':
if user != ctx.author:
player2 = user
break
else:
if user == ctx.author:
return
So I would like to run await timer(time, demande) and While True: [...] at the same time, I don't know if it's possible.
You can use threading to run them at the same time.
import threading
threading.Thread(target=timer, args=[time, msg_to_edit]).start()
You can use threading, but why do that in an asynchronous environment. We can simply use asyncio for that.
async def wait_for_reaction_add():
#while loop here
# inside command
await asyncio.gather(timer(time, demande), wait_for_reaction_add()
asyncio.gather runs both the coroutines concurrently
References:
asyncio
asyncio.gather
list(song_queue) = []
FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
YDL_OPTIONS = {'format': 'bestaudio', 'noplaylist':'True'}
def search(arg):
try: requests.get("".join(arg))
except: arg = " ".join(arg)
else: arg = "".join(arg)
with youtube_dl.YoutubeDL(YDL_OPTIONS ) as ydl:
info = ydl.extract_info(f"ytsearch:{arg}", download=False)['entries'][0]
return {'source': info['formats'][0]['url'], 'title': info['title']}
def play_next(ctx):
voice = get(client.voice_clients, guild=ctx.guild)
if len(song_queue) > 1:
del song_queue[0]
voice.play(discord.FFmpegPCMAudio(song_queue[0][source], **FFMPEG_OPTIONS), after=lambda e: play_next(ctx))
voice.is_playing()
#client.command()
async def play(ctx, *arg):
channel = ctx.message.author.voice.channel
if channel:
voice = get(client.voice_clients, guild=ctx.guild)
song = search(arg)
song_queue.append(song)
if voice and voice.is_connected():
await voice.move_to(channel)
else:
voice = await channel.connect()
if not voice.is_playing():
voice.play(discord.FFmpegPCMAudio(song[0]['source'], **FFMPEG_OPTIONS), after=lambda e: play_next(ctx))
voice.is_playing()
else:
await ctx.send("Added to queue")
else:
await ctx.send("You're not connected to any channel!")
this code doesn't play the music and the song queue and idk how to fix it to help me please
I need it so that it can play music and preferably not have the queue ANd i need it so that it can
I have code for my music bot that will play the video using the title of the song. It also has a working queue feature. Try copy-pasting this code into your cog, and it should work for you without any issues.
import discord
from discord.ext import commands
import random
import asyncio
import itertools
import sys
import traceback
from async_timeout import timeout
from functools import partial
import youtube_dl
from youtube_dl import YoutubeDL
# Suppress noise about console usage from errors
youtube_dl.utils.bug_reports_message = lambda: ''
ytdlopts = {
'format': 'bestaudio/best',
'outtmpl': 'downloads/%(extractor)s-%(id)s-%(title)s.%(ext)s',
'restrictfilenames': True,
'noplaylist': True,
'nocheckcertificate': True,
'ignoreerrors': False,
'logtostderr': False,
'quiet': True,
'no_warnings': True,
'default_search': 'auto',
'source_address': '0.0.0.0' # ipv6 addresses cause issues sometimes
}
ffmpegopts = {
'before_options': '-nostdin',
'options': '-vn'
}
ytdl = YoutubeDL(ytdlopts)
class VoiceConnectionError(commands.CommandError):
"""Custom Exception class for connection errors."""
class InvalidVoiceChannel(VoiceConnectionError):
"""Exception for cases of invalid Voice Channels."""
class YTDLSource(discord.PCMVolumeTransformer):
def __init__(self, source, *, data, requester):
super().__init__(source)
self.requester = requester
self.title = data.get('title')
self.web_url = data.get('webpage_url')
self.duration = data.get('duration')
# YTDL info dicts (data) have other useful information you might want
# https://github.com/rg3/youtube-dl/blob/master/README.md
def __getitem__(self, item: str):
"""Allows us to access attributes similar to a dict.
This is only useful when you are NOT downloading.
"""
return self.__getattribute__(item)
#classmethod
async def create_source(cls, ctx, search: str, *, loop, download=False):
loop = loop or asyncio.get_event_loop()
to_run = partial(ytdl.extract_info, url=search, download=download)
data = await loop.run_in_executor(None, to_run)
if 'entries' in data:
# take first item from a playlist
data = data['entries'][0]
embed = discord.Embed(title="", description=f"Queued [{data['title']}]({data['webpage_url']}) [{ctx.author.mention}]", color=discord.Color.green())
await ctx.send(embed=embed)
if download:
source = ytdl.prepare_filename(data)
else:
return {'webpage_url': data['webpage_url'], 'requester': ctx.author, 'title': data['title']}
return cls(discord.FFmpegPCMAudio(source), data=data, requester=ctx.author)
#classmethod
async def regather_stream(cls, data, *, loop):
"""Used for preparing a stream, instead of downloading.
Since Youtube Streaming links expire."""
loop = loop or asyncio.get_event_loop()
requester = data['requester']
to_run = partial(ytdl.extract_info, url=data['webpage_url'], download=False)
data = await loop.run_in_executor(None, to_run)
return cls(discord.FFmpegPCMAudio(data['url']), data=data, requester=requester)
class MusicPlayer:
"""A class which is assigned to each guild using the bot for Music.
This class implements a queue and loop, which allows for different guilds to listen to different playlists
simultaneously.
When the bot disconnects from the Voice it's instance will be destroyed.
"""
__slots__ = ('bot', '_guild', '_channel', '_cog', 'queue', 'next', 'current', 'np', 'volume')
def __init__(self, ctx):
self.bot = ctx.bot
self._guild = ctx.guild
self._channel = ctx.channel
self._cog = ctx.cog
self.queue = asyncio.Queue()
self.next = asyncio.Event()
self.np = None # Now playing message
self.volume = .5
self.current = None
ctx.bot.loop.create_task(self.player_loop())
async def player_loop(self):
"""Our main player loop."""
await self.bot.wait_until_ready()
while not self.bot.is_closed():
self.next.clear()
try:
# Wait for the next song. If we timeout cancel the player and disconnect...
async with timeout(300): # 5 minutes...
source = await self.queue.get()
except asyncio.TimeoutError:
return self.destroy(self._guild)
if not isinstance(source, YTDLSource):
# Source was probably a stream (not downloaded)
# So we should regather to prevent stream expiration
try:
source = await YTDLSource.regather_stream(source, loop=self.bot.loop)
except Exception as e:
await self._channel.send(f'There was an error processing your song.\n'
f'```css\n[{e}]\n```')
continue
source.volume = self.volume
self.current = source
self._guild.voice_client.play(source, after=lambda _: self.bot.loop.call_soon_threadsafe(self.next.set))
embed = discord.Embed(title="Now playing", description=f"[{source.title}]({source.web_url}) [{source.requester.mention}]", color=discord.Color.green())
self.np = await self._channel.send(embed=embed)
await self.next.wait()
# Make sure the FFmpeg process is cleaned up.
source.cleanup()
self.current = None
def destroy(self, guild):
"""Disconnect and cleanup the player."""
return self.bot.loop.create_task(self._cog.cleanup(guild))
class Music(commands.Cog):
"""Music related commands."""
__slots__ = ('bot', 'players')
def __init__(self, bot):
self.bot = bot
self.players = {}
async def cleanup(self, guild):
try:
await guild.voice_client.disconnect()
except AttributeError:
pass
try:
del self.players[guild.id]
except KeyError:
pass
async def __local_check(self, ctx):
"""A local check which applies to all commands in this cog."""
if not ctx.guild:
raise commands.NoPrivateMessage
return True
async def __error(self, ctx, error):
"""A local error handler for all errors arising from commands in this cog."""
if isinstance(error, commands.NoPrivateMessage):
try:
return await ctx.send('This command can not be used in Private Messages.')
except discord.HTTPException:
pass
elif isinstance(error, InvalidVoiceChannel):
await ctx.send('Error connecting to Voice Channel. '
'Please make sure you are in a valid channel or provide me with one')
print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)
def get_player(self, ctx):
"""Retrieve the guild player, or generate one."""
try:
player = self.players[ctx.guild.id]
except KeyError:
player = MusicPlayer(ctx)
self.players[ctx.guild.id] = player
return player
#commands.command(name='join', aliases=['connect', 'j'], description="connects to voice")
async def connect_(self, ctx, *, channel: discord.VoiceChannel=None):
"""Connect to voice.
Parameters
------------
channel: discord.VoiceChannel [Optional]
The channel to connect to. If a channel is not specified, an attempt to join the voice channel you are in
will be made.
This command also handles moving the bot to different channels.
"""
if not channel:
try:
channel = ctx.author.voice.channel
except AttributeError:
embed = discord.Embed(title="", description="No channel to join. Please call `,join` from a voice channel.", color=discord.Color.green())
await ctx.send(embed=embed)
raise InvalidVoiceChannel('No channel to join. Please either specify a valid channel or join one.')
vc = ctx.voice_client
if vc:
if vc.channel.id == channel.id:
return
try:
await vc.move_to(channel)
except asyncio.TimeoutError:
raise VoiceConnectionError(f'Moving to channel: <{channel}> timed out.')
else:
try:
await channel.connect()
except asyncio.TimeoutError:
raise VoiceConnectionError(f'Connecting to channel: <{channel}> timed out.')
if (random.randint(0, 1) == 0):
await ctx.message.add_reaction('👍')
await ctx.send(f'**Joined `{channel}`**')
#commands.command(name='play', aliases=['sing','p'], description="streams music")
async def play_(self, ctx, *, search: str):
"""Request a song and add it to the queue.
This command attempts to join a valid voice channel if the bot is not already in one.
Uses YTDL to automatically search and retrieve a song.
Parameters
------------
search: str [Required]
The song to search and retrieve using YTDL. This could be a simple search, an ID or URL.
"""
await ctx.trigger_typing()
vc = ctx.voice_client
if not vc:
await ctx.invoke(self.connect_)
player = self.get_player(ctx)
# If download is False, source will be a dict which will be used later to regather the stream.
# If download is True, source will be a discord.FFmpegPCMAudio with a VolumeTransformer.
source = await YTDLSource.create_source(ctx, search, loop=self.bot.loop, download=False)
await player.queue.put(source)
#commands.command(name='pause', description="pauses music")
async def pause_(self, ctx):
"""Pause the currently playing song."""
vc = ctx.voice_client
if not vc or not vc.is_playing():
embed = discord.Embed(title="", description="I am currently not playing anything", color=discord.Color.green())
return await ctx.send(embed=embed)
elif vc.is_paused():
return
vc.pause()
await ctx.send("Paused ⏸️")
#commands.command(name='resume', description="resumes music")
async def resume_(self, ctx):
"""Resume the currently paused song."""
vc = ctx.voice_client
if not vc or not vc.is_connected():
embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=discord.Color.green())
return await ctx.send(embed=embed)
elif not vc.is_paused():
return
vc.resume()
await ctx.send("Resuming ⏯️")
#commands.command(name='skip', description="skips to next song in queue")
async def skip_(self, ctx):
"""Skip the song."""
vc = ctx.voice_client
if not vc or not vc.is_connected():
embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=discord.Color.green())
return await ctx.send(embed=embed)
if vc.is_paused():
pass
elif not vc.is_playing():
return
vc.stop()
#commands.command(name='remove', aliases=['rm', 'rem'], description="removes specified song from queue")
async def remove_(self, ctx, pos : int=None):
"""Removes specified song from queue"""
vc = ctx.voice_client
if not vc or not vc.is_connected():
embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=discord.Color.green())
return await ctx.send(embed=embed)
player = self.get_player(ctx)
if pos == None:
player.queue._queue.pop()
else:
try:
s = player.queue._queue[pos-1]
del player.queue._queue[pos-1]
embed = discord.Embed(title="", description=f"Removed [{s['title']}]({s['webpage_url']}) [{s['requester'].mention}]", color=discord.Color.green())
await ctx.send(embed=embed)
except:
embed = discord.Embed(title="", description=f'Could not find a track for "{pos}"', color=discord.Color.green())
await ctx.send(embed=embed)
#commands.command(name='clear', aliases=['clr', 'cl', 'cr'], description="clears entire queue")
async def clear_(self, ctx):
"""Deletes entire queue of upcoming songs."""
vc = ctx.voice_client
if not vc or not vc.is_connected():
embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=discord.Color.green())
return await ctx.send(embed=embed)
player = self.get_player(ctx)
player.queue._queue.clear()
await ctx.send('**Cleared**')
#commands.command(name='queue', aliases=['q', 'playlist', 'que'], description="shows the queue")
async def queue_info(self, ctx):
"""Retrieve a basic queue of upcoming songs."""
vc = ctx.voice_client
if not vc or not vc.is_connected():
embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=discord.Color.green())
return await ctx.send(embed=embed)
player = self.get_player(ctx)
if player.queue.empty():
embed = discord.Embed(title="", description="queue is empty", color=discord.Color.green())
return await ctx.send(embed=embed)
seconds = vc.source.duration % (24 * 3600)
hour = seconds // 3600
seconds %= 3600
minutes = seconds // 60
seconds %= 60
if hour > 0:
duration = "%dh %02dm %02ds" % (hour, minutes, seconds)
else:
duration = "%02dm %02ds" % (minutes, seconds)
# Grabs the songs in the queue...
upcoming = list(itertools.islice(player.queue._queue, 0, int(len(player.queue._queue))))
fmt = '\n'.join(f"`{(upcoming.index(_)) + 1}.` [{_['title']}]({_['webpage_url']}) | ` {duration} Requested by: {_['requester']}`\n" for _ in upcoming)
fmt = f"\n__Now Playing__:\n[{vc.source.title}]({vc.source.web_url}) | ` {duration} Requested by: {vc.source.requester}`\n\n__Up Next:__\n" + fmt + f"\n**{len(upcoming)} songs in queue**"
embed = discord.Embed(title=f'Queue for {ctx.guild.name}', description=fmt, color=discord.Color.green())
embed.set_footer(text=f"{ctx.author.display_name}", icon_url=ctx.author.avatar_url)
await ctx.send(embed=embed)
#commands.command(name='leave', aliases=["stop", "dc", "disconnect", "bye"], description="stops music and disconnects from voice")
async def leave_(self, ctx):
"""Stop the currently playing song and destroy the player.
!Warning!
This will destroy the player assigned to your guild, also deleting any queued songs and settings.
"""
vc = ctx.voice_client
if not vc or not vc.is_connected():
embed = discord.Embed(title="", description="I'm not connected to a voice channel", color=discord.Color.green())
return await ctx.send(embed=embed)
if (random.randint(0, 1) == 0):
await ctx.message.add_reaction('👋')
await ctx.send('**Successfully disconnected**')
await self.cleanup(ctx.guild)
def setup(bot):
bot.add_cog(Music(bot))
I am trying to do the level system and I succeeded by following a tutorial.
But when I restart my bot it makes me start leveling again by creating new data on the json not removing the old ones and after 2 hours of different attempts I don't know how to solve.
EDIT: I decided to update the code by removing the functions and see how it went. Although I notice an improvement, it sometimes resets the data to hell and I don't understand why.
Code:
#with functions
import discord
import random
from discord import client
from discord.ext import commands
import json
from discord.utils import get
from random import choice
client = commands.Bot(command_prefix='°')
users = {}
#client.event
async def on_ready():
print('Bot online')
global users
try:
with open('ranking.json') as f:
users = json.load(f)
except FileNotFoundError:
print("Impossibile caricare ranking.json")
users = {}
#client.event
async def on_message(message):
if message.author == client.user:
return
xp = random.randrange(5, 10)
await update_data(users, message.author)
await add_experience(users, message.author, xp)
await level_up(users, message.author, message)
_save()
await client.process_commands(message)
async def update_data(users, user):
if user.id not in users:
print("pass")
users[user.id] = {}
users[user.id]["experience"] = 0
users[user.id]["level"] = 0
async def add_experience(users, user, xp):
users[user.id]["experience"] += xp
async def level_up(users, user, message):
experience = users[user.id]["experience"]
lvl_start = users[user.id]["level"]
lvl_end = int(experience ** (1/4))
print(lvl_start)
print(lvl_end)
if lvl_start < lvl_end:
await message.channel.send(f"{user.mention} è salito al livello {lvl_end}")
users[user.id]["level"] = lvl_end
def _save():
with open('ranking.json', 'w+') as f:
json.dump(users, f)
#without functions
import discord
import random
from discord import client
from discord.ext import commands
import json
from discord.utils import get
from random import choice
client = commands.Bot(command_prefix='°')
users = {}
#client.event
async def on_ready():
print('Bot online')
global users
try:
with open('ranking.json') as f:
users = json.load(f)
except FileNotFoundError:
print("Impossibile caricare ranking.json")
users = {}
#client.event
async def on_message(message):
id_user = str(message.author.id)
if message.author == client.user:
return
xp = random.randrange(5, 10)
if id_user not in users:
print(message.author.name)
users[id_user] = {}
users[id_user]["experience"] = 0
users[id_user]["level"] = 0
users[id_user]["experience"] += xp
experience = users[id_user]["experience"]
lvl_start = users[id_user]["level"]
lvl_end = int(experience ** (1 / 4))
if lvl_start < lvl_end:
await message.channel.send(f"{message.author.mention} è salito al livello {lvl_end}")
users[id_user]["level"] = lvl_end
_save()
await client.process_commands(message)
def _save():
with open('ranking.json', 'w+') as f:
json.dump(users, f)
ranking.json
{"488826524791734275": {"experience": 56, "level": 2}, "488826524791734275": {"experience": 32, "level": 2}}
As you can see from the json my user id is repeated two times and from the screen my messages where I restarted the bot during execution.
Is it possible to be able to rank every 30 seconds? i have no idea how to do it.
JSON keys can't be INT so change user.id to str(user.id)
In theory, the code should have sent a msg to all the servers that have set there channel! Altho it seems not to be working. I think its because I can't get the channel_id even tho I have done it in sqlite. Here is the code:
#client.event
async def on_ready():
print("The client is online!")
db = sqlite3.connect('entry.sqlite')
cursor = db.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS main(
guild_id TEXT,
channel_id,
user_id
)
''')
#client.command()
async def ping(ctx):
embed = discord.Embed(
title = "Pong!",
description = f"Your ping is {client.latency}ms !", color=0xf9c900)
await ctx.send(embed=embed)
#client.command()
async def public(ctx, channel:discord.TextChannel, winners: int, time: int, link:str, *, prize:str):
db = sqlite3.connect('entry.sqlite')
cursor = db.cursor()
channel_id = cursor.execute(f"SELECT channel_id FROM main WHERE guild_id = {ctx.guild.id}")
result = cursor.fetchone()
if result is None:
return
else:
for guild in client.guilds:
for channel in channel_id:
try:
embed = discord.Embed(
title = f"**Giving Away {prize}**",
description = f"React with 🎉 to enter! \n **{winners}** winner \n \n 🎊 Must be in **{link}** to enter!", color=0xf9c900)
msg = await ctx.send(embed=embed)
asyncio.sleep(1)
await msg.add_reaction('🎉')
asyncio.sleep(time)
except Exception:
continue
else:
break
#client.command()
async def setchannel(ctx, channel:discord.TextChannel):
if ctx.message.author.guild_permissions.manage_messages:
db = sqlite3.connect('entry.sqlite')
cursor = db.cursor()
cursor.execute(f"SELECT channel_id FROM main WHERE guild_id = {ctx.guild.id}")
result = cursor.fetchone()
if result is None:
sql = ("INSERT INTO main(guild_id, channel_id) VALUES(?,?)")
val = (ctx.guild.id, channel.id)
embed = discord.Embed(description=f":white_check_mark: succesfully added the giveaway channel {channel.mention}!",color=0x00ced1)
await ctx.send(embed=embed)
elif result is not None:
sql = ("UPDATE main SET channel_id = ? WHERE guild_id = ?")
val = (channel.id, ctx.guild.id)
embed = discord.Embed(description=f":white_check_mark: succesfully updated the giveaway channel {channel.mention}!",color=0x00ced1)
await ctx.send(embed=embed)
cursor.execute(sql, val)
db.commit()
cursor.close()
db.close()
The part I am trying to figure out is this part:
#client.command()
async def public(ctx, channel:discord.TextChannel, winners: int, time: int, link:str, *, prize:str):
db = sqlite3.connect('entry.sqlite')
cursor = db.cursor()
channel_id = cursor.execute(f"SELECT channel_id FROM main WHERE guild_id = {ctx.guild.id}")
result = cursor.fetchone()
if result is None:
return
else:
for guild in client.guilds:
for channel in channel_id:
try:
embed = discord.Embed(
title = f"**Giving Away {prize}**",
description = f"React with 🎉 to enter! \n **{winners}** winner \n \n 🎊 Must be in **{link}** to enter!", color=0xf9c900)
msg = await ctx.send(embed=embed)
asyncio.sleep(1)
await msg.add_reaction('🎉')
asyncio.sleep(time)
except Exception:
continue
else:
break
This part is suppose to send a message to the ones that have set there channel! But it isn't working and its not sending me any errors!
First of all, your SQL "SELECT channel_id FROM main WHERE guild_id = {ctx.guild.id}" is going to retrieve the channel_id for the guild that you ran the public command in.
Then, you get one row of data using cursor.fetchone(), but in your loop you are attempting to loop over channel_id, which is not the data you want, so I doubt your for loop is even running.