Files
Mace-AIO-Discord-Bot---With…/bot/cogs/commands/j2c.py

725 lines
35 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ╔══════════════════════════════════════════════════════════════════╗
# ║ ║
# ║ +-+-+-+-+-+-+-+-+ ║
# ║ |H|e|x|a|H|o|s|t| ║
# ║ +-+-+-+-+-+-+-+-+ ║
# ║ ║
# ║ © 2026 HexaHost — All Rights Reserved ║
# ║ ║
# ║ discord ── https://discord.gg/hexahost ║
# ║ github ── https://github.com/theoneandonlymace ║
# ║ ║
# ╚══════════════════════════════════════════════════════════════════╝
import discord
from discord.ext import commands
from discord import ui, SelectOption
from discord.ui import LayoutView, TextDisplay, Separator, ActionRow
import aiosqlite
import asyncio
from typing import Dict, List, Optional
from utils.cv2 import CV2, build_container
class JoinToCreate(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.private_channels: Dict[int, Dict] = {}
self.category_name = "J2C"
self.setup_data: Dict[int, Dict] = {}
self.db_path = "j2c_data.db"
self.blocked_users: Dict[int, List[int]] = {} # {vc_id: [user_ids]}
self.creating_vc = set()
async def init_db(self):
async with aiosqlite.connect(self.db_path) as db:
await db.execute("""
CREATE TABLE IF NOT EXISTS guild_setup (
guild_id INTEGER PRIMARY KEY,
join_channel_id INTEGER,
control_channel_id INTEGER,
control_message_id INTEGER,
category_id INTEGER
)
""")
try:
await db.execute("ALTER TABLE guild_setup ADD COLUMN category_id INTEGER")
except aiosqlite.OperationalError:
pass
await db.execute("""
CREATE TABLE IF NOT EXISTS private_channels (
vc_id INTEGER PRIMARY KEY,
guild_id INTEGER,
owner_id INTEGER,
member_limit INTEGER DEFAULT 2,
region TEXT DEFAULT '',
is_locked BOOLEAN DEFAULT FALSE,
has_waiting_room BOOLEAN DEFAULT FALSE,
has_thread BOOLEAN DEFAULT FALSE
)
""")
await db.execute("""
CREATE TABLE IF NOT EXISTS blocked_users (
vc_id INTEGER,
user_id INTEGER,
PRIMARY KEY (vc_id, user_id)
)
""")
await db.commit()
async def load_data(self):
async with aiosqlite.connect(self.db_path) as db:
# Load guild setups
async with db.execute("SELECT guild_id, join_channel_id, control_channel_id, control_message_id, category_id FROM guild_setup") as cursor:
async for row in cursor:
guild_id, join_channel_id, control_channel_id, control_message_id, category_id = row
self.setup_data[guild_id] = {
"join_channel_id": join_channel_id,
"control_channel_id": control_channel_id,
"control_message_id": control_message_id,
"category_id": category_id
}
# Load private channels
async with db.execute("SELECT * FROM private_channels") as cursor:
async for row in cursor:
vc_id, guild_id, owner_id, member_limit, region, is_locked, has_waiting_room, has_thread = row
self.private_channels[vc_id] = {
"owner": owner_id,
"limit": member_limit,
"region": region,
"is_locked": bool(is_locked),
"has_waiting_room": bool(has_waiting_room),
"has_thread": bool(has_thread),
"guild_id": guild_id
}
# Load blocked users
async with db.execute("SELECT * FROM blocked_users") as cursor:
async for row in cursor:
vc_id, user_id = row
if vc_id not in self.blocked_users:
self.blocked_users[vc_id] = []
self.blocked_users[vc_id].append(user_id)
async def save_guild_setup(self, guild_id: int, data: Dict):
async with aiosqlite.connect(self.db_path) as db:
await db.execute("""
INSERT OR REPLACE INTO guild_setup (guild_id, join_channel_id, control_channel_id, control_message_id, category_id)
VALUES (?, ?, ?, ?, ?)
""", (guild_id, data["join_channel_id"], data["control_channel_id"], data["control_message_id"], data.get("category_id")))
await db.commit()
async def save_private_channel(self, vc_id: int, guild_id: int, data: Dict):
try:
if vc_id not in self.private_channels:
self.private_channels[vc_id] = data
async with aiosqlite.connect(self.db_path) as db:
await db.execute("""
INSERT OR REPLACE INTO private_channels
(vc_id, guild_id, owner_id, member_limit, region, is_locked, has_waiting_room, has_thread)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""", (
vc_id, guild_id,
data["owner"],
data.get("limit", 2),
data.get("region", ""),
data.get("is_locked", False),
data.get("has_waiting_room", False),
data.get("has_thread", False)
))
await db.commit()
except Exception as e:
print(f"Error saving private channel: {e}")
async def delete_private_channel(self, vc_id: int):
async with aiosqlite.connect(self.db_path) as db:
await db.execute("DELETE FROM private_channels WHERE vc_id = ?", (vc_id,))
await db.execute("DELETE FROM blocked_users WHERE vc_id = ?", (vc_id,))
await db.commit()
async def delete_guild_setup(self, guild_id: int):
async with aiosqlite.connect(self.db_path) as db:
await db.execute("DELETE FROM guild_setup WHERE guild_id = ?", (guild_id,))
await db.execute("DELETE FROM private_channels WHERE guild_id = ?", (guild_id,))
await db.execute("DELETE FROM blocked_users WHERE vc_id IN (SELECT vc_id FROM private_channels WHERE guild_id = ?)", (guild_id,))
await db.commit()
async def block_user(self, vc_id: int, user_id: int):
async with aiosqlite.connect(self.db_path) as db:
await db.execute("INSERT OR IGNORE INTO blocked_users (vc_id, user_id) VALUES (?, ?)", (vc_id, user_id))
await db.commit()
if vc_id not in self.blocked_users:
self.blocked_users[vc_id] = []
if user_id not in self.blocked_users[vc_id]:
self.blocked_users[vc_id].append(user_id)
async def unblock_user(self, vc_id: int, user_id: int):
async with aiosqlite.connect(self.db_path) as db:
await db.execute("DELETE FROM blocked_users WHERE vc_id = ? AND user_id = ?", (vc_id, user_id))
await db.commit()
if vc_id in self.blocked_users and user_id in self.blocked_users[vc_id]:
self.blocked_users[vc_id].remove(user_id)
@commands.Cog.listener()
async def on_ready(self):
await self.init_db()
await self.load_data()
for guild_id, data in self.setup_data.items():
guild = self.bot.get_guild(guild_id)
if guild:
try:
control_channel = guild.get_channel(data["control_channel_id"])
if control_channel:
msg = None
if data["control_message_id"]:
try:
msg = await control_channel.fetch_message(data["control_message_id"])
except:
pass
if msg:
view = ControlPanelView(self, guild)
await msg.edit(view=view, embed=None, content=None)
else:
view = ControlPanelView(self, guild)
msg = await control_channel.send(view=view)
self.setup_data[guild_id]["control_message_id"] = msg.id
await self.save_guild_setup(guild_id, self.setup_data[guild_id])
except Exception as e:
print(f"Error in J2C on_ready: {e}")
continue
@commands.hybrid_command(name='j2csetup')
@commands.has_permissions(administrator=True)
async def setup_private_channels(self, ctx):
if ctx.guild.id in self.setup_data:
await ctx.send(view=CV2("❌ Error", "J2C system is already setup in this server!"))
return
category = discord.utils.get(ctx.guild.categories, name=self.category_name)
if not category:
category = await ctx.guild.create_category(self.category_name)
join_channel = await ctx.guild.create_voice_channel(
" Join to Create",
category=category,
reason="J2C System Setup"
)
control_channel = await ctx.guild.create_text_channel(
"ctrl-panel",
category=category,
reason="J2C System Setup"
)
view = ControlPanelView(self, ctx.guild)
control_message = await control_channel.send(view=view)
self.setup_data[ctx.guild.id] = {
"join_channel_id": join_channel.id,
"control_channel_id": control_channel.id,
"control_message_id": control_message.id
}
await self.save_guild_setup(ctx.guild.id, self.setup_data[ctx.guild.id])
await ctx.send(view=CV2("✅ Success", f"J2C system setup complete! Join {join_channel.mention} to create a private VC."))
@commands.hybrid_command(name='j2creset')
@commands.has_permissions(administrator=True)
async def reset_private_channels(self, ctx):
if ctx.guild.id not in self.setup_data:
await ctx.send(view=CV2("❌ Error", "J2C system is not setup in this server!"))
return
category = discord.utils.get(ctx.guild.categories, name=self.category_name)
if category:
for channel in category.channels:
try:
await channel.delete(reason="J2C System Reset")
except:
continue
if category:
try:
await category.delete(reason="J2C System Reset")
except:
pass
vc_ids = [vc_id for vc_id, data in self.private_channels.items()
if data.get("guild_id") == ctx.guild.id]
for vc_id in vc_ids:
del self.private_channels[vc_id]
del self.setup_data[ctx.guild.id]
await self.delete_guild_setup(ctx.guild.id)
await ctx.send(view=CV2("✅ Success", "J2C system has been completely reset in this server!"))
@commands.Cog.listener()
async def on_voice_state_update(self, member, before, after):
if member.guild.id not in self.setup_data:
return
guild_data = self.setup_data[member.guild.id]
# User joined the join channel
if after.channel and after.channel.id == guild_data["join_channel_id"]:
if member.id in self.creating_vc:
return
self.creating_vc.add(member.id)
try:
category_id = guild_data.get("category_id")
category = None
if category_id:
try:
category = member.guild.get_channel(int(category_id))
except:
pass
# Fallback 1: Use the parent category of the join channel
if not category and after.channel.category:
category = after.channel.category
# Fallback 2: J2C category by name
if not category:
category = discord.utils.get(member.guild.categories, name=self.category_name)
vc = await member.guild.create_voice_channel(
f"{member.name}'s VC",
category=category,
reason="Private VC Creation",
user_limit=2
)
await member.move_to(vc)
self.private_channels[vc.id] = {
"owner": member.id,
"limit": 2,
"region": "",
"is_locked": False,
"has_waiting_room": False,
"has_thread": False,
"guild_id": member.guild.id
}
await self.save_private_channel(vc.id, member.guild.id, self.private_channels[vc.id])
await self.update_control_panel(member.guild)
finally:
self.creating_vc.discard(member.id)
# User left a private channel
if before.channel and before.channel.id in self.private_channels:
# Check if user was blocked
if (before.channel.id in self.blocked_users and
member.id in self.blocked_users[before.channel.id]):
await member.move_to(None)
return
# Check if channel is empty
if len(before.channel.members) == 0:
try:
await before.channel.delete()
except:
pass
if before.channel.id in self.private_channels:
del self.private_channels[before.channel.id]
await self.delete_private_channel(before.channel.id)
await self.update_control_panel(member.guild)
async def update_control_panel(self, guild: discord.Guild):
if guild.id not in self.setup_data:
return
guild_data = self.setup_data[guild.id]
control_channel = guild.get_channel(guild_data["control_channel_id"])
if not control_channel or not guild_data["control_message_id"]:
return
try:
control_message = await control_channel.fetch_message(guild_data["control_message_id"])
view = ControlPanelView(self, guild)
await control_message.edit(view=view, embed=None, content=None)
except:
pass
class ControlPanelView(LayoutView):
def __init__(self, cog, guild):
super().__init__(timeout=None)
self.cog = cog
desc = ("Join the 'Join to Create VC' voice channel to create your own private voice channel.\n\n"
"Use the buttons below to manage your private VC.")
active_vcs = []
for vc_id, data in self.cog.private_channels.items():
if guild.get_channel(vc_id):
owner = guild.get_member(data["owner"])
if owner:
status = []
if data["is_locked"]:
status.append("🔒 Locked")
if data["has_thread"]:
status.append("💬 Thread")
vc_info = f"<#{vc_id}> (👑 {owner.mention})"
if status:
vc_info += f" [{' '.join(status)}]"
active_vcs.append(vc_info)
if active_vcs:
desc += "\n\n**Active Private VCs**\n" + "\n".join(active_vcs)
container = build_container(
TextDisplay("**J2C System**"),
Separator(visible=True),
TextDisplay(desc)
)
self.add_item(container)
b_limit = ui.Button(label="LIMIT", style=discord.ButtonStyle.blurple, custom_id="j2c:limit", emoji="")
b_limit.callback = self.set_limit
b_privacy = ui.Button(label="PRIVACY", style=discord.ButtonStyle.blurple, custom_id="j2c:privacy", emoji="🔒")
b_privacy.callback = self.toggle_privacy
b_thread = ui.Button(label="THREAD", style=discord.ButtonStyle.blurple, custom_id="j2c:thread", emoji="💬")
b_thread.callback = self.create_thread
b_untrust = ui.Button(label="UNTRUST", style=discord.ButtonStyle.green, custom_id="j2c:untrust", emoji="")
b_untrust.callback = self.untrust
b_invite = ui.Button(label="INVITE", style=discord.ButtonStyle.green, custom_id="j2c:invite", emoji="✉️")
b_invite.callback = self.invite_user
b_kick = ui.Button(label="KICK", style=discord.ButtonStyle.green, custom_id="j2c:kick", emoji="👢")
b_kick.callback = self.kick_user
b_region = ui.Button(label="REGION", style=discord.ButtonStyle.green, custom_id="j2c:region", emoji="🌍")
b_region.callback = self.set_region
b_unblock = ui.Button(label="UNBLOCK", style=discord.ButtonStyle.red, custom_id="j2c:unblock", emoji="🔓")
b_unblock.callback = self.unblock
b_claim = ui.Button(label="CLAIM", style=discord.ButtonStyle.red, custom_id="j2c:claim", emoji="")
b_claim.callback = self.claim
b_transfer = ui.Button(label="TRANSFER", style=discord.ButtonStyle.red, custom_id="j2c:transfer", emoji="🔄")
b_transfer.callback = self.transfer
b_delete = ui.Button(label="DELETE", style=discord.ButtonStyle.red, custom_id="j2c:delete", emoji="🗑️")
b_delete.callback = self.delete_vc
b_block = ui.Button(label="BLOCK", style=discord.ButtonStyle.danger, custom_id="j2c:block", emoji="🚫")
b_block.callback = self.block
self.add_item(ActionRow(b_limit, b_privacy, b_thread))
self.add_item(ActionRow(b_untrust, b_invite, b_kick, b_region))
self.add_item(ActionRow(b_unblock, b_claim, b_transfer, b_delete))
self.add_item(ActionRow(b_block))
async def get_owned_vc(self, interaction: discord.Interaction) -> Optional[discord.VoiceChannel]:
for vc_id, data in self.cog.private_channels.items():
if data["owner"] == interaction.user.id:
vc = interaction.guild.get_channel(vc_id)
if vc:
return vc
return None
async def set_limit(self, interaction: discord.Interaction):
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.response.send_message("You don't own any private VC!", ephemeral=True)
return
modal = SetLimitModal(vc)
await interaction.response.send_modal(modal)
async def toggle_privacy(self, interaction: discord.Interaction):
await interaction.response.defer(ephemeral=True)
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.followup.send("You don't own any private VC!", ephemeral=True)
return
is_locked = not self.cog.private_channels[vc.id]["is_locked"]
await vc.set_permissions(interaction.guild.default_role, connect=not is_locked)
self.cog.private_channels[vc.id]["is_locked"] = is_locked
await self.cog.save_private_channel(vc.id, interaction.guild.id, self.cog.private_channels[vc.id])
await interaction.followup.send(f"VC is now {'🔒 locked' if is_locked else '🔓 unlocked'}!", ephemeral=True)
await self.cog.update_control_panel(interaction.guild)
async def create_thread(self, interaction: discord.Interaction):
await interaction.response.defer(ephemeral=True)
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.followup.send("You don't own any private VC!", ephemeral=True)
return
has_thread = not self.cog.private_channels[vc.id]["has_thread"]
self.cog.private_channels[vc.id]["has_thread"] = has_thread
await self.cog.save_private_channel(vc.id, interaction.guild.id, self.cog.private_channels[vc.id])
if has_thread:
thread = await interaction.channel.create_thread(name=f"{vc.name} Discussion", auto_archive_duration=60)
await interaction.followup.send(f"Created thread: {thread.mention}", ephemeral=True)
else:
await interaction.followup.send("Thread feature disabled for your VC", ephemeral=True)
await self.cog.update_control_panel(interaction.guild)
async def untrust(self, interaction: discord.Interaction):
await interaction.response.defer(ephemeral=True)
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.followup.send("You don't own any private VC!", ephemeral=True)
return
await interaction.followup.send("Untrust feature would be implemented here", ephemeral=True)
async def invite_user(self, interaction: discord.Interaction):
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.response.send_message("You don't own any private VC!", ephemeral=True)
return
options = []
for member in interaction.guild.members:
if (member not in vc.members and not member.bot and member != interaction.user):
options.append(SelectOption(label=member.name, value=str(member.id)))
if not options:
await interaction.response.send_message("No members available to invite!", ephemeral=True)
return
dropdown = UserSelectDropdown(options, "Select members to invite", self.invite_selected)
view = ui.View()
view.add_item(dropdown)
await interaction.response.send_message("Select members to invite:", view=view, ephemeral=True)
async def invite_selected(self, interaction: discord.Interaction, selected: List[str]):
await interaction.response.defer(ephemeral=True)
vc = await self.get_owned_vc(interaction)
if not vc: return
for user_id in selected:
member = interaction.guild.get_member(int(user_id))
if member:
try: await member.send(f"You've been invited to join {vc.mention} by {interaction.user.mention}!")
except: pass
await interaction.followup.send("Invites sent!", ephemeral=True)
async def kick_user(self, interaction: discord.Interaction):
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.response.send_message("You don't own any private VC!", ephemeral=True)
return
options = []
for member in vc.members:
if member.id != interaction.user.id:
options.append(SelectOption(label=member.name, value=str(member.id)))
if not options:
await interaction.response.send_message("No users to kick in your VC!", ephemeral=True)
return
dropdown = UserSelectDropdown(options, "Select members to kick", self.kick_selected)
view = ui.View()
view.add_item(dropdown)
await interaction.response.send_message("Select members to kick:", view=view, ephemeral=True)
async def kick_selected(self, interaction: discord.Interaction, selected: List[str]):
await interaction.response.defer(ephemeral=True)
vc = await self.get_owned_vc(interaction)
if not vc: return
for user_id in selected:
member = interaction.guild.get_member(int(user_id))
if member and member in vc.members:
try: await member.move_to(None)
except: pass
await interaction.followup.send("Selected members kicked!", ephemeral=True)
async def set_region(self, interaction: discord.Interaction):
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.response.send_message("You don't own any private VC!", ephemeral=True)
return
regions = [
SelectOption(label="Automatic", value="auto"), SelectOption(label="US West", value="us-west"),
SelectOption(label="US East", value="us-east"), SelectOption(label="Europe", value="europe"),
SelectOption(label="Singapore", value="singapore"), SelectOption(label="Japan", value="japan"),
SelectOption(label="Brazil", value="brazil"), SelectOption(label="Australia", value="australia")
]
dropdown = RegionSelectDropdown(regions, vc)
view = ui.View()
view.add_item(dropdown)
await interaction.response.send_message("Select a region:", view=view, ephemeral=True)
async def unblock(self, interaction: discord.Interaction):
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.response.send_message("You don't own any private VC!", ephemeral=True)
return
if vc.id not in self.cog.blocked_users or not self.cog.blocked_users[vc.id]:
await interaction.response.send_message("No blocked users!", ephemeral=True)
return
options = []
for user_id in self.cog.blocked_users[vc.id]:
member = interaction.guild.get_member(user_id)
if member:
options.append(SelectOption(label=member.name, value=str(user_id)))
dropdown = UserSelectDropdown(options, "Select users to unblock", self.unblock_selected)
view = ui.View()
view.add_item(dropdown)
await interaction.response.send_message("Select users to unblock:", view=view, ephemeral=True)
async def unblock_selected(self, interaction: discord.Interaction, selected: List[str]):
await interaction.response.defer(ephemeral=True)
vc = await self.get_owned_vc(interaction)
if not vc: return
for user_id in selected:
await self.cog.unblock_user(vc.id, int(user_id))
await interaction.followup.send("Selected users unblocked!", ephemeral=True)
await self.cog.update_control_panel(interaction.guild)
async def claim(self, interaction: discord.Interaction):
available_vcs = []
for vc_id, data in self.cog.private_channels.items():
if data["guild_id"] == interaction.guild.id:
vc = interaction.guild.get_channel(vc_id)
if vc:
owner = interaction.guild.get_member(data["owner"])
if not owner or owner not in vc.members:
available_vcs.append((vc, data))
if not available_vcs:
await interaction.response.send_message("No VCs available to claim!", ephemeral=True)
return
options = []
for vc, data in available_vcs:
owner_mention = f"<{data['owner']}>" if data['owner'] else "Unknown"
options.append(SelectOption(label=f"{vc.name} (prev: {owner_mention})", value=str(vc.id)))
dropdown = VCSelectDropdown(options, "Select VC to claim", self.claim_selected)
view = ui.View()
view.add_item(dropdown)
await interaction.response.send_message("Select VC to claim:", view=view, ephemeral=True)
async def claim_selected(self, interaction: discord.Interaction, selected: List[str]):
await interaction.response.defer(ephemeral=True)
vc_id = int(selected[0])
vc = interaction.guild.get_channel(vc_id)
if not vc:
await interaction.followup.send("VC no longer exists!", ephemeral=True)
return
self.cog.private_channels[vc.id]["owner"] = interaction.user.id
await self.cog.save_private_channel(vc.id, interaction.guild.id, self.cog.private_channels[vc.id])
await interaction.followup.send(f"You've claimed {vc.mention}!", ephemeral=True)
await self.cog.update_control_panel(interaction.guild)
async def transfer(self, interaction: discord.Interaction):
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.response.send_message("You don't own any private VC!", ephemeral=True)
return
options = []
for member in vc.members:
if member.id != interaction.user.id:
options.append(SelectOption(label=member.name, value=str(member.id)))
if not options:
await interaction.response.send_message("No users to transfer to in your VC!", ephemeral=True)
return
dropdown = UserSelectDropdown(options, "Select new owner", self.transfer_selected)
view = ui.View()
view.add_item(dropdown)
await interaction.response.send_message("Select new owner:", view=view, ephemeral=True)
async def transfer_selected(self, interaction: discord.Interaction, selected: List[str]):
await interaction.response.defer(ephemeral=True)
vc = await self.get_owned_vc(interaction)
if not vc: return
new_owner_id = int(selected[0])
new_owner = interaction.guild.get_member(new_owner_id)
if not new_owner:
await interaction.followup.send("User not found!", ephemeral=True)
return
self.cog.private_channels[vc.id]["owner"] = new_owner_id
await self.cog.save_private_channel(vc.id, interaction.guild.id, self.cog.private_channels[vc.id])
await interaction.followup.send(f"Transferred ownership of {vc.mention} to {new_owner.mention}!", ephemeral=True)
await self.cog.update_control_panel(interaction.guild)
async def delete_vc(self, interaction: discord.Interaction):
await interaction.response.defer(ephemeral=True)
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.followup.send("You don't own any private VC!", ephemeral=True)
return
for member in vc.members:
try: await member.move_to(None)
except: pass
await vc.delete()
if vc.id in self.cog.private_channels:
del self.cog.private_channels[vc.id]
await self.cog.delete_private_channel(vc.id)
await interaction.followup.send("Your private VC has been deleted!", ephemeral=True)
await self.cog.update_control_panel(interaction.guild)
async def block(self, interaction: discord.Interaction):
vc = await self.get_owned_vc(interaction)
if not vc:
await interaction.response.send_message("You don't own any private VC!", ephemeral=True)
return
options = []
for member in interaction.guild.members:
if (member not in vc.members and not member.bot and member != interaction.user):
options.append(SelectOption(label=member.name, value=str(member.id)))
if not options:
await interaction.response.send_message("No members available to block!", ephemeral=True)
return
dropdown = UserSelectDropdown(options, "Select members to block", self.block_selected)
view = ui.View()
view.add_item(dropdown)
await interaction.response.send_message("Select members to block:", view=view, ephemeral=True)
async def block_selected(self, interaction: discord.Interaction, selected: List[str]):
await interaction.response.defer(ephemeral=True)
vc = await self.get_owned_vc(interaction)
if not vc: return
for user_id in selected:
await self.cog.block_user(vc.id, int(user_id))
await interaction.followup.send("Selected members blocked from joining!", ephemeral=True)
await self.cog.update_control_panel(interaction.guild)
class UserSelectDropdown(ui.Select):
def __init__(self, options: List[SelectOption], placeholder: str, callback):
super().__init__(placeholder=placeholder, options=options, min_values=1, max_values=len(options))
self.callback_func = callback
async def callback(self, interaction: discord.Interaction):
await self.callback_func(interaction, self.values)
class RegionSelectDropdown(ui.Select):
def __init__(self, options: List[SelectOption], vc: discord.VoiceChannel):
super().__init__(placeholder="Select a region", options=options)
self.vc = vc
async def callback(self, interaction: discord.Interaction):
region = self.values[0]
try:
await self.vc.edit(rtc_region=region if region != "auto" else None)
await interaction.response.send_message(f"Region set to {self.values[0]}!", ephemeral=True)
except Exception as e:
await interaction.response.send_message(f"Failed to set region: {e}", ephemeral=True)
class VCSelectDropdown(ui.Select):
def __init__(self, options: List[SelectOption], placeholder: str, callback):
super().__init__(placeholder=placeholder, options=options, min_values=1, max_values=1)
self.callback_func = callback
async def callback(self, interaction: discord.Interaction):
await self.callback_func(interaction, self.values)
class SetLimitModal(ui.Modal, title="Set VC User Limit"):
def __init__(self, vc: discord.VoiceChannel):
super().__init__()
self.vc = vc
self.limit = ui.TextInput(
label="User Limit (0 for no limit)",
placeholder="Enter a number between 0 and 99",
default=str(vc.user_limit) if vc.user_limit else "0",
max_length=2
)
self.add_item(self.limit)
async def on_submit(self, interaction: discord.Interaction):
try:
limit = int(self.limit.value)
if limit < 0 or limit > 99:
raise ValueError
await self.vc.edit(user_limit=limit if limit != 0 else None)
cog = interaction.client.get_cog("JoinToCreate")
if cog and self.vc.id in cog.private_channels:
cog.private_channels[self.vc.id]["limit"] = limit
await cog.save_private_channel(self.vc.id, interaction.guild.id, cog.private_channels[self.vc.id])
await interaction.response.send_message(f"User limit set to {limit if limit != 0 else 'no limit'}!", ephemeral=True)
await cog.update_control_panel(interaction.guild)
except:
await interaction.response.send_message("Invalid limit! Please enter a number between 0 and 99.", ephemeral=True)
async def setup(bot):
await bot.add_cog(JoinToCreate(bot))