@@ -42,25 +42,27 @@ def __init__(self, bot: Tux) -> None:
4242
4343 self .xp_cooldown = CONFIG .XP_CONFIG .XP_COOLDOWN
4444 self .levels_exponent = CONFIG .XP_CONFIG .LEVELS_EXPONENT
45-
45+
4646 # The xp_roles and max_level are now handled per server
4747 self .enable_xp_cap = CONFIG .XP_CONFIG .ENABLE_XP_CAP
48-
48+
4949 def get_max_level (self , guild_id : int ) -> int :
5050 """
5151 Get the maximum configured level for a guild.
52-
52+
5353 Parameters
5454 ----------
5555 guild_id : int
5656 The guild ID
57-
57+
5858 Returns
5959 -------
6060 int
6161 The maximum level configured for the guild, or 0 if no levels are configured
6262 """
63- if guild_id in CONFIG .XP_CONFIG .XP_ROLES and (guild_roles := CONFIG .XP_CONFIG .XP_ROLES [guild_id ]):
63+ if guild_id in CONFIG .XP_CONFIG .XP_ROLES and (
64+ guild_roles := CONFIG .XP_CONFIG .XP_ROLES [guild_id ]
65+ ):
6466 return max (item ["level" ] for item in guild_roles )
6567 return 0
6668
@@ -75,15 +77,15 @@ async def xp_listener(self, message: discord.Message) -> None:
7577 The message object.
7678 """
7779 try :
78- # Skip XP processing during maintenance mode
79- if getattr (self .bot , "maintenance_mode" , False ):
80+ # Skip XP processing for bots, DMs, maintenance mode, or blacklisted channels
81+ is_maintenance = getattr (self .bot , "maintenance_mode" , False )
82+ if message .author .bot or not message .guild or is_maintenance :
8083 return
8184
82- if message .author .bot or not message .guild :
83- return
84-
85- # Check if this channel is in the blacklist for this guild
86- guild_blacklist = CONFIG .XP_CONFIG .XP_BLACKLIST_CHANNELS .get (message .guild .id , [])
85+ guild_blacklist = CONFIG .XP_CONFIG .XP_BLACKLIST_CHANNELS .get (
86+ message .guild .id ,
87+ [],
88+ )
8789 if message .channel .id in guild_blacklist :
8890 return
8991
@@ -111,7 +113,10 @@ async def xp_listener(self, message: discord.Message) -> None:
111113 last_message_time = (
112114 user_level_data .last_message if user_level_data else None
113115 )
114- if last_message_time and self .is_on_cooldown (last_message_time , message .guild .id ):
116+ if last_message_time and self .is_on_cooldown (
117+ last_message_time ,
118+ message .guild .id ,
119+ ):
115120 return
116121
117122 # Process XP gain with the already fetched data
@@ -141,8 +146,11 @@ async def process_xp_gain(
141146 current_level = user_level_data .level if user_level_data else 0
142147
143148 # Get the server-specific exponent or use default (0 is default key)
144- server_exponent = self .levels_exponent .get (guild .id , self .levels_exponent .get (0 , 2.0 ))
145-
149+ server_exponent = self .levels_exponent .get (
150+ guild .id ,
151+ self .levels_exponent .get (0 , 2.0 ),
152+ )
153+
146154 # Recalculate what level the current XP should be (in case exponent changed)
147155 # This ensures level is always correct based on current XP and exponent
148156 expected_level_from_xp = self .calculate_level (current_xp , guild .id )
@@ -159,10 +167,13 @@ async def process_xp_gain(
159167 xp_increment = self .calculate_xp_increment (member , guild .id )
160168 new_xp = current_xp + xp_increment
161169 new_level = self .calculate_level (new_xp , guild .id )
162-
170+
163171 # Log if there's a suspicious level jump (more than 5 levels from expected)
164172 if new_level > expected_level_from_xp + 5 :
165- server_exponent = self .levels_exponent .get (guild .id , self .levels_exponent .get (0 , 2.0 ))
173+ server_exponent = self .levels_exponent .get (
174+ guild .id ,
175+ self .levels_exponent .get (0 , 2.0 ),
176+ )
166177 logger .warning (
167178 f"Suspicious level jump detected for { member .name } ({ member .id } ): "
168179 f"Level { expected_level_from_xp } -> { new_level } (XP: { current_xp :.2f} -> { new_xp :.2f} , "
@@ -190,7 +201,11 @@ async def process_xp_gain(
190201 )
191202 await self .handle_level_up (member , guild , new_level )
192203
193- def is_on_cooldown (self , last_message_time : datetime .datetime , guild_id : int = 0 ) -> bool :
204+ def is_on_cooldown (
205+ self ,
206+ last_message_time : datetime .datetime ,
207+ guild_id : int = 0 ,
208+ ) -> bool :
194209 """
195210 Check if the member is on cooldown.
196211
@@ -284,19 +299,26 @@ async def update_roles(
284299
285300 role_ids = {role ["role_id" ] for role in guild_roles }
286301 roles_to_remove = [
287- r for r in guild_member .roles
288- if r .id in role_ids and r != highest_role
302+ r for r in guild_member .roles if r .id in role_ids and r != highest_role
289303 ]
290304
291305 if roles_to_remove :
292306 await guild_member .remove_roles (* roles_to_remove )
293307
294308 if highest_role or roles_to_remove :
295- assigned_text = f"Assigned { highest_role .name } " if highest_role else "No role assigned"
296- removed_text = f", Removed: { ', ' .join (r .name for r in roles_to_remove )} " if roles_to_remove else ""
309+ assigned_text = (
310+ f"Assigned { highest_role .name } "
311+ if highest_role
312+ else "No role assigned"
313+ )
314+ removed_text = (
315+ f", Removed: { ', ' .join (r .name for r in roles_to_remove )} "
316+ if roles_to_remove
317+ else ""
318+ )
297319 logger .debug (
298320 f"Updated roles for { guild_member } in { g } : "
299- f"{ assigned_text } { removed_text } "
321+ f"{ assigned_text } { removed_text } " ,
300322 )
301323
302324 @staticmethod
@@ -336,7 +358,11 @@ def calculate_xp_for_level(self, level: int, guild_id: int = 0) -> float:
336358 exponent = self .levels_exponent .get (guild_id , self .levels_exponent .get (0 , 2.0 ))
337359 return 500 * (level / 5 ) ** exponent
338360
339- def calculate_xp_increment (self , member : discord .Member , guild_id : int = 0 ) -> float :
361+ def calculate_xp_increment (
362+ self ,
363+ member : discord .Member ,
364+ guild_id : int = 0 ,
365+ ) -> float :
340366 """
341367 Calculate the XP increment for a member.
342368
@@ -359,7 +385,7 @@ def calculate_xp_increment(self, member: discord.Member, guild_id: int = 0) -> f
359385 role ["role_id" ]: role ["multiplier" ]
360386 for role in CONFIG .XP_CONFIG .XP_MULTIPLIERS [guild_id ]
361387 }
362-
388+
363389 return max (
364390 (guild_multipliers .get (role .id , 1 ) for role in member .roles ),
365391 default = 1 ,
@@ -383,15 +409,17 @@ def calculate_level(self, xp: float, guild_id: int = 0) -> int:
383409 """
384410 # Ensure XP is non-negative to prevent complex number errors
385411 xp = max (0.0 , xp )
386-
412+
387413 # Get server-specific exponent or use default
388414 exponent = self .levels_exponent .get (guild_id , self .levels_exponent .get (0 , 2.0 ))
389-
415+
390416 # Guard against division by zero
391417 if exponent == 0 :
392- logger .error (f"levels_exponent for guild { guild_id } cannot be 0, using default value of 2" )
418+ logger .error (
419+ f"levels_exponent for guild { guild_id } cannot be 0, using default value of 2" ,
420+ )
393421 exponent = 2.0
394-
422+
395423 return int ((xp / 500 ) ** (1 / exponent ) * 5 )
396424
397425 # *NOTE* Do not move this function to utils.py, as this results in a circular import.
@@ -458,7 +486,12 @@ def generate_progress_bar(
458486
459487 return f"`{ bar } ` { current_value } /{ target_value } "
460488
461- def get_level_progress (self , xp : float , level : int , guild_id : int = 0 ) -> tuple [int , int ]:
489+ def get_level_progress (
490+ self ,
491+ xp : float ,
492+ level : int ,
493+ guild_id : int = 0 ,
494+ ) -> tuple [int , int ]:
462495 """
463496 Get the progress towards the next level.
464497
0 commit comments