# ╔══════════════════════════════════════════════════════════════════╗ # ║ ║ # ║ +-+-+-+-+-+-+-+-+ ║ # ║ |H|e|x|a|H|o|s|t| ║ # ║ +-+-+-+-+-+-+-+-+ ║ # ║ ║ # ║ © 2026 HexaHost — All Rights Reserved ║ # ║ ║ # ║ discord ── https://discord.gg/hexahost ║ # ║ github ── https://github.com/theoneandonlymace ║ # ║ ║ # ╚══════════════════════════════════════════════════════════════════╝ from utils.db_paths import db_path import discord from utils.emoji import ARROWRED from discord.ext import commands import aiosqlite from utils.cv2 import CV2 INVITE_DB = db_path("invite.db") EMOJI_INVITE = ARROWRED from utils.config import BotName class Tracking(commands.Cog): def __init__(self, bot): self.bot = bot self.invites = {} async def ensure_tables(self, guild_id): async with aiosqlite.connect(INVITE_DB) as db: await db.execute(f''' CREATE TABLE IF NOT EXISTS invites_{guild_id} ( user_id INTEGER PRIMARY KEY, total INTEGER DEFAULT 0, fake INTEGER DEFAULT 0, left INTEGER DEFAULT 0, rejoin INTEGER DEFAULT 0 ) ''') await db.execute(''' CREATE TABLE IF NOT EXISTS logging ( guild_id INTEGER PRIMARY KEY, channel_id INTEGER ) ''') await db.commit() @commands.Cog.listener() async def on_ready(self): import asyncio async def fetch_invites(guild): try: self.invites[guild.id] = await guild.invites() except discord.Forbidden: pass except Exception: pass await asyncio.gather(*(fetch_invites(guild) for guild in self.bot.guilds)) @commands.Cog.listener() async def on_invite_create(self, invite): try: self.invites[invite.guild.id] = await invite.guild.invites() except discord.Forbidden: pass @commands.Cog.listener() async def on_invite_delete(self, invite): try: self.invites[invite.guild.id] = await invite.guild.invites() except discord.Forbidden: pass @commands.Cog.listener() async def on_member_join(self, member): guild = member.guild await self.ensure_tables(guild.id) invites_before = self.invites.get(guild.id, []) try: invites_after = await guild.invites() except discord.Forbidden: invites_after = [] inviter = None for invite in invites_after: for old_invite in invites_before: if invite.code == old_invite.code and invite.uses > old_invite.uses: inviter = invite.inviter break if inviter: break self.invites[guild.id] = invites_after async with aiosqlite.connect(INVITE_DB) as db: if inviter: # Check if user has been in DB before (Rejoin) async with db.execute(f"SELECT user_id FROM invites_{guild.id} WHERE user_id = ?", (member.id,)) as cursor: user_row = await cursor.fetchone() if user_row: await db.execute(f"UPDATE invites_{guild.id} SET rejoin = rejoin + 1 WHERE user_id = ?", (inviter.id,)) else: await db.execute(f"INSERT OR IGNORE INTO invites_{guild.id} (user_id) VALUES (?)", (inviter.id,)) await db.execute(f"UPDATE invites_{guild.id} SET total = total + 1 WHERE user_id = ?", (inviter.id,)) await db.commit() async with db.execute("SELECT channel_id FROM logging WHERE guild_id = ?", (guild.id,)) as cursor: log_row = await cursor.fetchone() log_channel = guild.get_channel(log_row[0]) if log_row else None if log_channel: total = await self.get_total_invites(guild.id, inviter.id) if inviter else 0 msg = ( f"{member.mention} has joined {guild.name}, invited by " f"{inviter.name if inviter else 'Unknown'}, who now has {total} invites." ) await log_channel.send(view=CV2("📥 Member Joined", msg)) @commands.Cog.listener() async def on_member_remove(self, member): guild = member.guild await self.ensure_tables(guild.id) async with aiosqlite.connect(INVITE_DB) as db: await db.execute(f"UPDATE invites_{guild.id} SET left = left + 1 WHERE user_id = ?", (member.id,)) await db.commit() async def get_total_invites(self, guild_id, user_id): async with aiosqlite.connect(INVITE_DB) as db: async with db.execute(f"SELECT total FROM invites_{guild_id} WHERE user_id = ?", (user_id,)) as cursor: row = await cursor.fetchone() return row[0] if row else 0 @commands.hybrid_command(aliases=["inv"]) async def invites(self, ctx, member: discord.Member = None): member = member or ctx.author await self.ensure_tables(ctx.guild.id) async with aiosqlite.connect(INVITE_DB) as db: async with db.execute(f"SELECT total, fake, left, rejoin FROM invites_{ctx.guild.id} WHERE user_id = ?", (member.id,)) as cursor: row = await cursor.fetchone() if row: total, fake, left, rejoin = row real = total - fake - left - rejoin else: total = fake = left = rejoin = real = 0 desc = ( f"{EMOJI_INVITE} **› {member.mention} has `{total}` invites**\n\n" f"**Real:** `{real}`\n" f"**Fake:** `{fake}`\n" f"**Left:** `{left}`\n" f"**Rejoins:** `{rejoin}`\n\n" f"{EMOJI_INVITE} **Get {BotName} Premium Lifetime [Join Support Here](https://discord.gg/hexahost)**" ) await ctx.send(view=CV2(f"Invite Log - {member.name}", desc)) @commands.hybrid_command(aliases=["addinvs"]) @commands.has_permissions(administrator=True) async def addinvites(self, ctx, member: discord.Member, amount: int): await self.ensure_tables(ctx.guild.id) async with aiosqlite.connect(INVITE_DB) as db: await db.execute(f"INSERT OR IGNORE INTO invites_{ctx.guild.id} (user_id) VALUES (?)", (member.id,)) await db.execute(f"UPDATE invites_{ctx.guild.id} SET total = total + ? WHERE user_id = ?", (amount, member.id)) await db.commit() await ctx.send(view=CV2("✅ Success", f"Added **{amount}** invites to {member.mention}.")) @commands.hybrid_command(aliases=["setinvs"]) @commands.has_permissions(administrator=True) async def setinvites(self, ctx, member: discord.Member, amount: int): await self.ensure_tables(ctx.guild.id) async with aiosqlite.connect(INVITE_DB) as db: await db.execute(f"INSERT OR REPLACE INTO invites_{ctx.guild.id} (user_id, total) VALUES (?, ?)", (member.id, amount)) await db.commit() await ctx.send(view=CV2("✅ Success", f"Set invites of {member.mention} to **{amount}**.")) @commands.hybrid_command(aliases=["resetinvs"]) @commands.has_permissions(administrator=True) async def resetinvites(self, ctx, member: discord.Member): await self.ensure_tables(ctx.guild.id) async with aiosqlite.connect(INVITE_DB) as db: await db.execute(f"DELETE FROM invites_{ctx.guild.id} WHERE user_id = ?", (member.id,)) await db.commit() await ctx.send(view=CV2("✅ Success", f"Reset invites of {member.mention}.")) @commands.hybrid_command(aliases=["invlb"]) async def invitesleaderboard(self, ctx): await self.ensure_tables(ctx.guild.id) async with aiosqlite.connect(INVITE_DB) as db: async with db.execute(f"SELECT user_id, total FROM invites_{ctx.guild.id} ORDER BY total DESC LIMIT 10") as cursor: data = await cursor.fetchall() if not data: await ctx.send(view=CV2("❌ Error", "No invites found.")) return leaderboard = "" for idx, (user_id, total) in enumerate(data, start=1): user = ctx.guild.get_member(user_id) name = user.name if user else f"Left User ({user_id})" leaderboard += f"#{idx} {name} — {total} invites\n" await ctx.send(view=CV2("📊 Invite Leaderboard", leaderboard)) @commands.hybrid_command(aliases=["invlog"]) @commands.has_permissions(administrator=True) async def invitelogging(self, ctx, channel: discord.TextChannel): await self.ensure_tables(ctx.guild.id) async with aiosqlite.connect(INVITE_DB) as db: await db.execute("INSERT OR REPLACE INTO logging (guild_id, channel_id) VALUES (?, ?)", (ctx.guild.id, channel.id)) await db.commit() await ctx.send(view=CV2("✅ Success", f"Invite logs will now be sent to {channel.mention}")) async def setup(bot): await bot.add_cog(Tracking(bot))