.
This commit is contained in:
		
							parent
							
								
									5368d21be4
								
							
						
					
					
						commit
						7222239774
					
				
							
								
								
									
										3
									
								
								bot.py
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								bot.py
									
									
									
									
									
								
							@ -136,6 +136,9 @@ modules_path = pathlib.Path(__file__).parent / 'modules'
 | 
			
		||||
extensions = []
 | 
			
		||||
for folder in modules_path.iterdir():
 | 
			
		||||
    if folder.is_dir():
 | 
			
		||||
        # skip non-cog helpers under modules/common
 | 
			
		||||
        if folder.name == 'common':
 | 
			
		||||
            continue
 | 
			
		||||
        for file in folder.glob('*.py'):
 | 
			
		||||
            if file.name == '__init__.py':
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
@ -572,10 +572,23 @@ async def setup(bot):
 | 
			
		||||
    cog = PirateReportCog(bot)
 | 
			
		||||
    await bot.add_cog(cog)
 | 
			
		||||
 | 
			
		||||
    # Register commands either globally or to a specific guild if configured
 | 
			
		||||
    home_gid = cfg(bot).int('home_guild_id', 0)
 | 
			
		||||
    guild_obj = discord.Object(id=home_gid) if home_gid else None
 | 
			
		||||
 | 
			
		||||
    def _rm(name: str):
 | 
			
		||||
        try:
 | 
			
		||||
            bot.tree.remove_command(name, guild=guild_obj)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            try:
 | 
			
		||||
                bot.tree.remove_command(name, guild=None)
 | 
			
		||||
            except Exception:
 | 
			
		||||
                pass
 | 
			
		||||
 | 
			
		||||
    # make re-loads idempotent
 | 
			
		||||
    for name in ("report", "edit_pirate", "encounter"):
 | 
			
		||||
        _rm(name)
 | 
			
		||||
 | 
			
		||||
    if home_gid:
 | 
			
		||||
        guild_obj = discord.Object(id=home_gid)
 | 
			
		||||
        bot.tree.add_command(cog.report, guild=guild_obj)
 | 
			
		||||
        bot.tree.add_command(cog.edit_pirate, guild=guild_obj)
 | 
			
		||||
        bot.tree.add_command(cog.encounter, guild=guild_obj)
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,8 @@
 | 
			
		||||
import asyncio
 | 
			
		||||
import discord
 | 
			
		||||
from discord.ext import commands
 | 
			
		||||
from mod_perms import require_mod_ctx  # ctx-aware mod gate
 | 
			
		||||
from mod_perms import require_mod_ctx
 | 
			
		||||
from modules.common.settings import cfg as _cfg
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PiratesListCog(commands.Cog):
 | 
			
		||||
@ -16,29 +17,17 @@ class PiratesListCog(commands.Cog):
 | 
			
		||||
    Posts are chunked to stay <2000 chars and previous posts are deleted on refresh.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, bot):
 | 
			
		||||
    def __init__(self, bot: commands.Bot):
 | 
			
		||||
        self.bot = bot
 | 
			
		||||
        cfg = bot.config["DEFAULT"]
 | 
			
		||||
        self.list_channel_id = int(cfg["pirates_list_channel_id"])
 | 
			
		||||
        try:
 | 
			
		||||
            self.group_threshold = int(cfg.get("threat_group_threshold", "3"))
 | 
			
		||||
        except Exception:
 | 
			
		||||
            self.group_threshold = 3
 | 
			
		||||
        try:
 | 
			
		||||
            self.min_samples = int(cfg.get("threat_min_samples_for_stats", "3"))
 | 
			
		||||
        except Exception:
 | 
			
		||||
            self.min_samples = 3
 | 
			
		||||
 | 
			
		||||
        c = _cfg(bot)
 | 
			
		||||
        self.list_channel_id = c.int("pirates_list_channel_id")
 | 
			
		||||
        self.group_threshold = c.int("threat_group_threshold", 3)
 | 
			
		||||
        self.min_samples = c.int("threat_min_samples_for_stats", 3)
 | 
			
		||||
 | 
			
		||||
        # serialize refreshes per guild
 | 
			
		||||
        self._locks = {}
 | 
			
		||||
        self._no_mentions = discord.AllowedMentions.none()
 | 
			
		||||
 | 
			
		||||
        def _lock_for(self, guild_id: int):
 | 
			
		||||
            import asyncio
 | 
			
		||||
            self._locks.setdefault(guild_id, asyncio.Lock())
 | 
			
		||||
            return self._locks[guild_id]
 | 
			
		||||
 | 
			
		||||
        # send settings: never ping on posted content
 | 
			
		||||
        self._locks: dict[int, asyncio.Lock] = {}
 | 
			
		||||
        # never ping on posted content
 | 
			
		||||
        self._no_mentions = discord.AllowedMentions.none()
 | 
			
		||||
 | 
			
		||||
    # ----------------- utils -----------------
 | 
			
		||||
@ -119,30 +108,19 @@ class PiratesListCog(commands.Cog):
 | 
			
		||||
 | 
			
		||||
    async def refresh_list(self, guild: discord.Guild):
 | 
			
		||||
        """Edit list messages in place; only send extra messages when we need more chunks (new pirates)."""
 | 
			
		||||
        # ---- serialize per guild ----
 | 
			
		||||
        lock = getattr(self, "_locks", {}).get(guild.id)
 | 
			
		||||
        if lock is None:
 | 
			
		||||
            # tiny fallback if you didn't add _lock_for()
 | 
			
		||||
            import asyncio as _asyncio
 | 
			
		||||
            if not hasattr(self, "_locks"):
 | 
			
		||||
                self._locks = {}
 | 
			
		||||
            self._locks[guild.id] = _asyncio.Lock()
 | 
			
		||||
            lock = self._locks[guild.id]
 | 
			
		||||
 | 
			
		||||
        async with lock:
 | 
			
		||||
        async with self._lock_for(guild.id):
 | 
			
		||||
            channel = guild.get_channel(self.list_channel_id)
 | 
			
		||||
            if not channel:
 | 
			
		||||
                print("[pirates_list] list channel not found:", self.list_channel_id)
 | 
			
		||||
                return
 | 
			
		||||
 | 
			
		||||
            dm = self.bot.data_manager
 | 
			
		||||
            allow = getattr(self, "_no_mentions", discord.AllowedMentions.none())
 | 
			
		||||
            allow = self._no_mentions
 | 
			
		||||
 | 
			
		||||
            # ---- load & prune existing posts for this guild/channel ----
 | 
			
		||||
            records = [r for r in dm.get("pirates_list_posts")
 | 
			
		||||
                       if r.get("guild_id") == guild.id and r.get("channel_id") == self.list_channel_id]
 | 
			
		||||
 | 
			
		||||
            # fetch messages (drop any that vanished)
 | 
			
		||||
            msgs, kept_records = [], []
 | 
			
		||||
            for r in records:
 | 
			
		||||
                try:
 | 
			
		||||
@ -150,11 +128,8 @@ class PiratesListCog(commands.Cog):
 | 
			
		||||
                    msgs.append(m)
 | 
			
		||||
                    kept_records.append(r)
 | 
			
		||||
                except Exception:
 | 
			
		||||
                    # prune dead record
 | 
			
		||||
                    dm.remove("pirates_list_posts", lambda x, mid=r["message_id"]: x.get("message_id") == mid)
 | 
			
		||||
 | 
			
		||||
            records = kept_records  # only live ones, in stored order
 | 
			
		||||
 | 
			
		||||
            # ---- build fresh, sorted contents ----
 | 
			
		||||
            pirates = sorted(
 | 
			
		||||
                dm.get("pirates"),
 | 
			
		||||
@ -168,13 +143,11 @@ class PiratesListCog(commands.Cog):
 | 
			
		||||
            if not pirates:
 | 
			
		||||
                placeholder = "_No verified pirates yet._"
 | 
			
		||||
                if msgs:
 | 
			
		||||
                    # edit first, delete the rest
 | 
			
		||||
                    if msgs[0].content != placeholder:
 | 
			
		||||
                        try:
 | 
			
		||||
                            await msgs[0].edit(content=placeholder, allowed_mentions=allow)
 | 
			
		||||
                        except Exception as e:
 | 
			
		||||
                            print("[pirates_list] edit placeholder failed:", repr(e))
 | 
			
		||||
                    # remove extra posts/records
 | 
			
		||||
                    for extra in msgs[1:]:
 | 
			
		||||
                        try:
 | 
			
		||||
                            await extra.delete()
 | 
			
		||||
@ -214,7 +187,7 @@ class PiratesListCog(commands.Cog):
 | 
			
		||||
                    except Exception as e:
 | 
			
		||||
                        print("[pirates_list] edit block failed:", repr(e))
 | 
			
		||||
 | 
			
		||||
            # ---- if we need *more* messages (usually after adding a pirate), send them ----
 | 
			
		||||
            # ---- send additional messages if needed ----
 | 
			
		||||
            if len(chunks) > len(msgs):
 | 
			
		||||
                for i in range(len(msgs), len(chunks)):
 | 
			
		||||
                    try:
 | 
			
		||||
@ -227,7 +200,7 @@ class PiratesListCog(commands.Cog):
 | 
			
		||||
                    except Exception as e:
 | 
			
		||||
                        print("[pirates_list] send block failed:", repr(e))
 | 
			
		||||
 | 
			
		||||
            # ---- if we need fewer messages (e.g., pirate removed), delete extras ----
 | 
			
		||||
            # ---- delete extras if fewer chunks now ----
 | 
			
		||||
            elif len(chunks) < len(msgs):
 | 
			
		||||
                extras = msgs[len(chunks):]
 | 
			
		||||
                for m in extras:
 | 
			
		||||
@ -252,5 +225,5 @@ class PiratesListCog(commands.Cog):
 | 
			
		||||
        await ctx.reply("Pirates list refreshed.", ephemeral=is_slash)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def setup(bot):
 | 
			
		||||
async def setup(bot: commands.Bot):
 | 
			
		||||
    await bot.add_cog(PiratesListCog(bot))
 | 
			
		||||
 | 
			
		||||
@ -561,7 +561,7 @@ class _StartView(discord.ui.View):
 | 
			
		||||
class SpicePayCog(commands.Cog):
 | 
			
		||||
    def __init__(self, bot):
 | 
			
		||||
        self.bot = bot
 | 
			
		||||
        self-sessions: Dict[tuple, Dict] = {}
 | 
			
		||||
        self.sessions: Dict[tuple, Dict] = {}
 | 
			
		||||
 | 
			
		||||
        r = cfg(bot)
 | 
			
		||||
        def _f(key, default):
 | 
			
		||||
 | 
			
		||||
@ -443,7 +443,7 @@ class UserCardsCog(commands.Cog):
 | 
			
		||||
        await self._log(member.guild, f"📝 User joined: {member.mention} (ID: {member.id})")
 | 
			
		||||
        await self.refresh_card(member)
 | 
			
		||||
 | 
			
		||||
    @commands.Cog.listener())
 | 
			
		||||
    @commands.Cog.listener()
 | 
			
		||||
    async def on_member_update(self, before: discord.Member, after: discord.Member):
 | 
			
		||||
        if before.nick != after.nick or before.roles != after.roles:
 | 
			
		||||
            await self.refresh_card(after)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user