i'm looking for advice on how to make a player loop process that takes The songs from my queue and automatically plays them. The ones that ive tried making are only possible if the bot is used in 1 server. ive got alot more than 1 server that my bot is in. Im just looking for some advice on where to start
my code right now.
import wavelink
import discord
import asyncio
import random
from discord.ext import commands
import humanize as h
class MusicQueue(asyncio.Queue):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._queue = []
self.index = 0
self.repeat_start = None
def reset(self):
while len(self._queue)-1 > self.index:
self._queue.pop()
self.repeat_start = None
#dont reset the index, keep the history
def hard_reset(self):
self._queue.clear()
self.index = 0
self.repeat_start = None
def shuffle(self):
if self.repeat_start is not None:
n = self.repeat_start
else:
n = self.index
shuffle = self._queue[n:]
random.shuffle(shuffle)
old = self._queue[:n]
self._queue = old + shuffle
def repeat(self):
if self.repeat_start is not None:
self.repeat_start = None
else:
self.repeat_start = self.index
def _get(self):
if self.repeat_start is not None:
if len(self._queue) == 1:
# it doesnt seem to like it when only one item is in the queue, so dont increase the index
return self._queue[0]
diff = self.index - self.repeat_start
self.index += 1
if len(self._queue) <= self.index:
self.index = self.repeat_start
return self._queue[diff]
else:
r = self._queue[self.index]
self.index += 1
return r
def putleft(self, item):
self._queue.insert(self.index+1, item)
def empty(self):
if self.repeat_start is not None:
if len(self._queue) <= self.index:
self.index = self.repeat_start
return len(self._queue) <= self.index
#property
def q(self):
return self._queue[self.index:]
#property
def history(self):
return self._queue[:self.index]
class music(commands.Cog):
def __init__(self, client):
self.client = client
self.queues = {}
if not hasattr(client, 'wavelink'):
self.client.wavelink : wavelink.Client = wavelink.Client(self.client)
self.client.loop.create_task(self.start_nodes())
async def start_nodes(self):
await self.client.wait_until_ready()
await self.client.wavelink.initiate_node(host='0.0.0.0',
port=2333,
rest_uri='http://0.0.0.0:2333',
password='youshallnotpass',
identifier='DRIZZI',
region='us_central')
def getQueue(self,ctx):
if not self.queues[ctx.guild.id]:
self.queues[ctx.guild.id] = MusicQueue()
queue = self.queues[ctx.guild.id]
return queue
#commands.command(name='connect')
async def connect_(self, ctx, *, channel: discord.VoiceChannel=None):
if not channel:
try:
channel = ctx.author.voice.channel
except AttributeError:
raise discord.DiscordException('No channel to join. Please either specify a valid channel or join one.')
player = self.client.wavelink.get_player(ctx.guild.id)
await ctx.send(f'Connecting to **`{channel.name}`**')
await player.connect(channel.id)
#commands.command()
async def play(self, ctx, *, query: str):
def convert_from_ms( milliseconds ):
seconds, milliseconds = divmod(milliseconds,1000)
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
seconds = seconds
return hours, minutes, seconds
queue : MusicQueue = self.getQueue(ctx)
tracks = await self.client.wavelink.get_tracks(f'ytsearch:{query}')
song : wavelink.Track = tracks[0]
if song.duration > 600000:
return await ctx.send("Song may not be more than 10 minutes")
if not tracks:
return await ctx.send('Could not find any songs with that query.')
player = self.client.wavelink.get_player(ctx.guild.id)
if not player.is_connected:
await ctx.invoke(self.connect_)
emb = discord.Embed(title = f'Added {str(song)} to the queue')
emb.set_thumbnail(url=song.thumb)
time=convert_from_ms(song.duration)
emb.add_field(name='Duration', value=f'{time[1]}:{time[2]}')
emb.add_field(name='Uploaded by', value=song.author)
await ctx.send(embed=emb)
await queue.put((song,player))
def setup(client):
client.add_cog(music(client))```
Related
I'm trying to make a blackjack command for my Discord Bot in python, I'm making small codes and little by little testing and improving, see below:
import discord
from discord.ext import commands
from discord import app_commands
import random, json, datetime
class bj(discord.ui.Button):
def __init__(self, game ,gamesum, player_cards):
super().__init__()
self.value = None
#discord.ui.button (label="Hit", style=discord.ButtonStyle.blurple)
async def confirm(self, button: discord.ui.Button, interaction: discord. Interaction):
self.value = True
self.stop()
value_1=["A", 1,2,3,4,5,6,7,8,9,10,"J","Q","K",]
nype_1=["♦️","♠️","♥️","♣️"]
card_value_3 = random.randint(0, len(value_1) - 1)
nype_card_3 = random.randint(0, len(nype_1) - 1)
card_3 = f"{card_value_3[card_value_3]} {card_value_3[nype_card_3]}"
await match.edit()
match.edit_field(name='Your hand', value=f"{player_cards} {card_value_3}{nype_card_3}")
if type(card_value_3)==str:
if value_card_3=="A":
value_letter_3=11
else:
value_letter_3=10
else:
value_letter_3=value_card_3
class client(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.synced = False
async def setup_hook(self) -> None:
self.add_view(DropdownView())
async def on_ready(self):
await aclient.change_presence(activity = discord.Streaming(name = "/news", url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"))
await self.wait_until_ready()
if not self.synced:
await tree.sync()
self.synced = True
print(f"We entered as {self.user}!")
print(f"That has the ID {self.user.id}")
client = client()
tree = app_commands.CommandTree(aclient)
#tree.command(name='blackjack', description='Play a game of blackjack')
async def blackjack(interaction: discord.Interaction, amount:int):
await open_account(interaction.user)
money = await add_money(interaction.user)
if amount>money[0]:
await interaction.response.send_message(f"You don't have all this amount {interaction.user.mention}.")
else:
if quantity<0:
await interaction.response.send_message(f"You must enter a positive value")
else:
value_1=["A",2,3,4,5,6,7,8,9,10,'J','Q',"K"]
nype_1=["♦️","♠️","♥️","♣️"]
value_card_a = random.randint(0, len(value_1) - 1)
nype_card_a = random.randint(0, len(nype_1) - 1)
letter_a = f"{value_1[value_card_a]}{nype_1[nype_letter_a]}"
b_card_value = random.randint(0, len(1_value) - 1)
nype_card_b = random.randint(0, len(nype_1) - 1)
letter_b = f"{value_1[value_card_b]}{nype_1[nype_letter_a]}"
player_cards = f"{card_a} {card_b}"
if type(value_card_a)==str:
if value_card_a=="A":
value_letter_a=11
else:
value_letter_a=10
else:
value_card_a=value_card_a
if type(value_card_b)==str:
if value_card_b=="A":
value_letter_b=11
else:
value_letter_b=10
else:
value_card_b=value_card_b
sum_of_game=value_card_a+value_card_b
await add_money(interaction.user, -1*amount)
if sum_of_game==21:
result='Blackjack'
titulo_resultado=f'You won ~~K~~ {1.5*amount}'
else:
result=sum_of_game
titulo_resultado=f'You invested ~~K~~ {amount} in this blackjack'
departure=discord.Embed(
description=f'{result_title}',
colour=discord.Color.random()
)
match.add_field(name='Your hand', value=f"{player_cards}\n{result}")
if result=='Blackjack':
await add_money(interaction.user, 1.5*amount)
await interaction.response.send_message(embed=game, view=bj(game ,gamesum, player_cards))
async def open_account(user):
users = await bank_data()
if str(user.id) in users:
return False
else:
users[str(user.id)] = {}
users[str(user.id)]['wallet'] = 0
users[str(user.id)]['bank']= 0
with open("money.json", "w") as f:
json.dump(users, f)
return true
async def bank_data():
with open("money.json", "r") as f:
users = json.load(f)
return users
async def add_money(user, change=0, mode = "wallet"):
users = await bank_data()
users[str(user.id)][mode] +=change
with open("money.json", "w") as f:
json.dump(users, f)
money = [users[str(user.id)]["wallet"], users[str(user.id)]["bank"]]
return money
aclient.run(Token)
But in await interaction.response.send_message(embed=match, view=bj(match ,game_sum, player_cards)) is reporting the error
2023-02-06 19:14:31 ERROR discord.app_commands.tree Ignoring exception in command 'blackjack'
Traceback (most recent call last):
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/app_commands/commands.py", line 862, in _do_call
return await self._callback(interaction, **params) # type: ignore
File "main.py", line 1155, in blackjack
await interaction.response.send_message(embed=partida, view=bj(partida ,soma_de_jogo, cartas_jogador))
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/interactions.py", line 754, in send_message
params = interaction_message_response_params(
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/webhook/async_.py", line 577, in interaction_message_response_params
data['components'] = view.to_components()
AttributeError: 'bj' object has no attribute 'to_components'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/app_commands/tree.py", line 1242, in _call
await command._invoke_with_namespace(interaction, namespace)
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/app_commands/commands.py", line 887, in _invoke_with_namespace
return await self._do_call(interaction, transformed_values)
File "/home/runner/Kllin/venv/lib/python3.10/site-packages/discord/app_commands/commands.py", line 880, in _do_call
raise CommandInvokeError(self, e) from e
discord.app_commands.errors.CommandInvokeError: Command 'blackjack' raised an exception: AttributeError: 'bj' object has no attribute 'to_components'
I tried to interpret the error, as I recently started programming, it didn't help much, I asked in ChatGPT, and it also didn't help much (the error didn't even change), so the artificial intelligence itself suggested that I come and ask here, I hope it helps me help(Oh, and sorry for not leaving everything organized and well separated, they said there was a lot of code and little information).
I've got a series of lengthy messages that make up the help function of my Discord bot, and I'd like to have them sent to a thread instead of the channel itself. However, when I try and call create_thread(), I get this error: AttributeError: 'TextChannel' object has no attribute 'create_thread'
Here's my code:
import discord
import os
import random
import time
client = discord.Client()
class initiative_card:
def __init__(self,name,command,image,emoji,color,card_type,copy,user_defined_name):
self.rgb = str(color).split(",")
self.raw_color = color
self.name = name
self.command = command
self.image = image
self.emoji = emoji
self.color = discord.Color.from_rgb(int(self.rgb[0]),int(self.rgb[1]),int(self.rgb[2]))
if (card_type == "Hero"):
self.is_hero = True
else:
self.is_hero = False
self.copy = copy
self.user_defined_name = user_defined_name
self.faceup = True
self.cardback_emoji = "<:initcardback:1069116117756432435>"
self.cardback_image = "https://cdn.discordapp.com/emojis/1069116117756432435.webp?size=96&quality=lossless"
def flip(self):
self.faceup = not self.faceup
global all_initiative_cards
global initiative_deck
global turn_index
def initialize_deck():
global all_initiative_cards
global initiative_deck
global turn_index
all_initiative_cards = []
# Read the cards file and create the initiative deck
with open('initiative_cards.txt') as f:
lines = f.readlines()
print('Found ' + str(len(lines)) + ' card entries in file')
valid_lines = 0
hero_card_count = 0
for i in lines:
words = i.split(" ")
if len(words) == 7:
all_initiative_cards.append(initiative_card(words[0],words[1],words[2],words[3],words[4],words[5],0,"undefined"))
valid_lines = valid_lines + 1
for i in all_initiative_cards:
if i.is_hero:
hero_card_count = hero_card_count + 1
print(str(valid_lines) + " valid entries found; created " + str(len(all_initiative_cards)) + " cards, of which " + str(hero_card_count) + " were hero cards.")
initiative_deck = []
turn_index = 0
return
#client.event
async def on_ready():
initialize_deck()
await client.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name='!inithelp'))
#client.event
async def on_message(message):
global all_initiative_cards
global initiative_deck
global turn_index
if message.author == client.user:
return
if message.content.startswith('!allcards'):
new_thread = await message.channel.create_thread(name="Initiative Card Reference", message="Initiative Card Reference", type=ChannelType.public_thread)
new_thread.add_user(message.author)
embed=discord.Embed(title="Initiative", description="Listing all cards available to add to the track.", color=0x8c8c8c)
embed.set_thumbnail(url='https://cdn.discordapp.com/emojis/756583300612751460.webp?size=96&quality=lossless')
for index, item in enumerate(all_initiative_cards):
if (not (index % 8)) and (index > 0):
await new_thread.send(embed=embed)
embed=discord.Embed(title="Spectaculars Initiative", description="Listing all cards available to add to the track.", color=0x8c8c8c)
embed.set_thumbnail(url='https://cdn.discordapp.com/emojis/756583300612751460.webp?size=96&quality=lossless')
embed.add_field(name=item.name, value="Card ID: " + item.command, inline=True)
embed.add_field(name="Card Image", value=item.emoji,inline=True)
embed.add_field(name='\n',value='\n')
await new_thread.send(embed=embed)
Discord.py seems to have a create_thread method for TextChannel. What am I not seeing here?
I've tried removing all of the arguments from message.channel.create_thread. I was expecting this to create a new thread with the help text in it in the channel in which the help request was sent.
I'm writing a Discord bot to play music
When trying to play a playlist, it throws the error 'Command raised an exception: KeyError: 'webpage_url'. What could be the problem?
It won't even load the first video
def __init__(self, ctx: commands.Context, source: discord.FFmpegPCMAudio, *, data: dict, volume: float = 0.5):
super().__init__(source, volume)
self.requester = ctx.author
self.channel = ctx.channel
self.data = data
self.title = data.get('title')
self.tags = data.get('tags')
self.url = data.get('webpage_url')
self.stream_url = data.get('url')
def __str__(self):
return '**{0.title}** by **{0.uploader}**'.format(self)
#classmethod
async def create_source(cls, ctx: commands.Context, search: str, *, loop: asyncio.BaseEventLoop = None):
loop = loop or asyncio.get_event_loop()
partial = functools.partial(cls.ytdl.extract_info, search, download=False, process=False)
data = await loop.run_in_executor(None, partial)
if data is None:
raise YTDLError('Couldn\'t find anything that matches `{}`'.format(search))
if 'entries' not in data:
process_info = data
else:
process_info = None
for entry in data['entries']:
if entry:
process_info = entry
break
if process_info is None:
raise YTDLError('Couldn\'t find anything that matches `{}`'.format(search))
webpage_url = process_info['webpage_url']
partial = functools.partial(cls.ytdl.extract_info, webpage_url, download=False)
processed_info = await loop.run_in_executor(None, partial)
if processed_info is None:
raise YTDLError('Couldn\'t fetch `{}`'.format(webpage_url))
if 'entries' not in processed_info:
info = processed_info
else:
info = None
while info is None:
try:
info = processed_info['entries'].pop(0)
except IndexError:
raise YTDLError('Couldn\'t retrieve any matches for `{}`'.format(webpage_url))
return cls(ctx, discord.FFmpegPCMAudio(info['url'], **cls.FFMPEG_OPTIONS), data=info)
i'm newbie. sorry for what might be a stupid question
Right now i'm just using datetime and have a loop check every minute if there is a 0, 15, 30, or 45 in the minute place. After a while the bot loses time and sends messages later than the specified time. Is there a way I could make this use unix/fix the desync? or would unix fix the desyncing?
import os
import discord
import random
import datetime
import asyncio
from discord.ext import commands, tasks
ecchi = []
time = datetime.datetime.now
class Hentai(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_ready(self):
if time().second != 0:
waittime = 62-time().second
await asyncio.sleep(waittime)
if self.time_check.current_loop == 0:
self.time_check.start()
else:
if self.time_check.current_loop == 0:
self.time_check.start()
# Fetches random image from "hentai" folder:
for filename in os.listdir('./assets/hentai'):
path = os.path.join('./assets/hentai', filename)
if os.path.isfile(path):
if os.path.getsize(path) > 8000000:
continue
if filename.endswith('.jpg'):
ecchi.append(filename)
elif filename.endswith('.png'):
ecchi.append(filename)
#commands.command(brief = "Automatically sends a random ecchi/hentai image every 15 minutes, or manually send one")
async def hentai(self, ctx):
random_image = random.choice(ecchi)
file = discord.File(f"./assets/hentai/{random_image}")
await ctx.send(file = file)
# Automatic 15 minute loop
#tasks.loop(minutes=15)
async def send_hentai(self):
channels = (12345678901234567890, 12345678901234567890)
for channel_id in channels:
channel = self.bot.get_channel(channel_id)
random_image = random.choice(ecchi)
file = discord.File(f"./assets/hentai/{random_image}")
await channel.send(file = file)
#tasks.loop(minutes=1)
async def time_check(self):
if time().minute == 0:
if self.send_hentai.current_loop == 0:
self.send_hentai.start()
self.time_check.stop()
if time().minute == 15:
if self.send_hentai.current_loop == 0:
self.send_hentai.start()
self.time_check.stop()
if time().minute == 30:
if self.send_hentai.current_loop == 0:
self.send_hentai.start()
self.time_check.stop()
if time().minute == 45:
if self.send_hentai.current_loop == 0:
self.send_hentai.start()
self.time_check.stop()
def setup(bot):
bot.add_cog(Hentai(bot))
import os
import discord
import random
import datetime
import asyncio
from discord.ext import commands, tasks
ecchi = []
def UtcNow():
now = datetime.datetime.utcnow()
return (now - datetime.datetime(1970, 1, 1)).total_seconds()
class Hentai(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_ready(self):
time = UtcNow()
if time != 0:
waittime = 60-time
await asyncio.sleep(waittime)
if self.time_check.current_loop == 0:
self.time_check.start()
else:
if self.time_check.current_loop == 0:
self.time_check.start()
# Fetches random image from "hentai" folder:
for filename in os.listdir('./assets/hentai'):
path = os.path.join('./assets/hentai', filename)
if os.path.isfile(path):
if os.path.getsize(path) > 8000000:
continue
if filename.endswith('.jpg'):
ecchi.append(filename)
elif filename.endswith('.png'):
ecchi.append(filename)
#commands.command(brief = "Automatically sends a random ecchi/hentai image every 15 minutes, or manually send one (Possibly against TOS)")
async def hentai(self, ctx):
random_image = random.choice(ecchi)
file = discord.File(f"./assets/hentai/{random_image}")
await ctx.send(file = file)
# Automatic 15 minute loop
currentloop = 0
#tasks.loop(seconds=5)
async def time_check(self):
if self.currentloop > 0:
self.currentloop -= 1
time = UtcNow()
if ((int(time/60)%15) == 0 and self.currentloop == 0):
self.currentloop = 12
channels = (751890144977748068, 854619663475277824)
for channel_id in channels:
channel = self.bot.get_channel(channel_id)
random_image = random.choice(ecchi)
file = discord.File(f"./assets/hentai/{random_image}")
await channel.send(file = file)
def setup(bot):
bot.add_cog(Hentai(bot))
I'm making discord bot with python. I was making leveling system using database (https://account.mongodb.com/) and I got this syntax error: pymongo.errors.ConfigurationError: A DNS label is empty. Please help me.
main.py:
import os
import discord
import datetime
import levelsys
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='$', intents=intents)
cogs = [levelsys]
for i in range(len(cogs)):
cogs[i].setup(bot)
# Setting permissions that a user should have to execute this command.
print('Server Running')
bot.run(os.getenv('token'))
levelsys.py:
import discord
from discord.ext import commands
from pymongo import MongoClient
import urllib.parse
bot_channel = 798127930295058442
talk_channels = [690995360834912327]
level = ['new', 'old_new', 'Master Oogway']
levelnum = [5, 15, 30]
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='$', intents=intents)
cluster = MongoClient("mongodb+srv://Myself:" + urllib.parse.quote("stackoverflow") + "#cluster0.4h226.mongodb.n...")
leveling = cluster["discord"]["leveling"]
class levelsys(commands.Cog):
def __init__(self, bot):
self.bot = bot
#commands.Cog.listener()
async def on_ready(self):
print('ready!')
#commands.Cog.listener()
async def on_message(self, message):
if message.channel.id in talk_channels:
stats = leveling.find_one({"id": message.author.id})
if not message.author.bot:
if stats is None:
newuser = {"id": message.auhor.id, "xp": 100}
leveling.insert_one(newuser)
else:
xp = stats["xp"] + 5
leveling.update_one({"id": message.author.id}, {"set":{"xp":xp}})
lvl = 0
while True:
if xp < ((50*(lvl**2))+(50*(lvl-1))):
break
lvl += 1
xp -= ((50*(lvl**2))+(50*(lvl-1)))
if xp == 0:
await message.channel.send(f"Well done {message.author.mention}: you advanced to **level: {lvl}**!")
for i in range(len(level)):
if lvl == levelnum[1]:
await message.author.add_roles(discord.utils.get(message.author.guild.roles, name=level[i]))
embed = discord.Embed(
description= f"{message.author.mention} you have gotten role **{level[i]}**!!!"
)
embed.set_thumbnail(url=message.author.avatar_url)
await message.channel.send(embed=embed)
#commands.command()
async def rank(self, ctx):
if ctx.channel.id == bot_channel:
stats = leveling.find_one({"id": ctx.author.id})
if stats is None:
embed = discord.Embed(description="You need to write more messages to get the rank!")
await ctx.channel.send(embed=embed)
else:
xp = stats["xp"]
lvl = 0
rank = 0
while True:
if xp < ((50*(lvl**2))+(50*lvl)):
break
lvl += 1
xp -= ((50*((lvl-1)**2))+(50*(lvl-1)))
boxes = int((xp/(200*((1/2)*lvl)))*20)
rankings = leveling.find().sort("xp",-1)
for x in rankings:
rank += 1
if stats["id"] == x["id"]:
break
embed = discord.Embed(title="{}'s level stats".format(ctx.author.name))
embed.add_field(name="Name", value=ctx.author.mention, inline=True)
embed.add_field(name="Xp", value=f"{xp}/{int(200*((1/2)*lvl))}", inline=True)
embed.add_field(name="Rank", value=f"{rank}/{ctx.guild.member_count}", inline=True)
embed.add_field(name="Level Bar", value=boxes*":blue_square:"+ (20-boxes)* ":white_large_square:", inline=False)
embed.set_thumbnail(url=ctx.author.avatar_url)
await ctx.channel.send(embed=embed)
#commands.command()
async def leaderboard(self, ctx):
if (ctx.channel.id == bot_channel):
rankings = leveling.find().sort("xp",-1)
i=1
embed = discord.Embed(title="Rankings:")
for x in rankings:
try:
temp = ctx.quild.get_member(x["id"])
tempxp = x["xp"]
embed.add_field(name=f"{i}: {temp.name}", value=f"Total XP: {tempxp}", inline= False)
i+=1
except:
pass
if i == 11:
break
await ctx.channel.send(embed=embed)
def setup(bot):
bot.add_cog(levelsys(bot))
error:
pymongo.errors.ConfigurationError: A DNS label is empty.
Please help me a little and tell me if there are other errors I need to fix. Thank you very much!
At a guess your issue is with the connection string; mongodb in "SRV" mode uses DNS to determine the replicaset / shard details.