@ -1,15 +1,18 @@
import asyncio
import discord
import discord
from redbot . core import Config , checks , commands
from redbot . core import Config , checks , commands
from redbot . core . bot import Red
from redbot . core . bot import Red
from redbot . core . commands import Cog
from redbot . core . commands import Cog
# Cog: Any = getattr(commands, "Cog", object)
# Cog: Any = getattr(commands, "Cog", object)
# listener = getattr(commands.Cog, "listener", None) # Trusty + Sinbad
# listener = getattr(commands.Cog, "listener", None) # Trusty + Sinbad
# if listener is None:
# if listener is None:
# def listener(name=None):
# def listener(name=None):
# return lambda x: x
# return lambda x: x
RATE_LIMIT_DELAY = 60 * 10 # If you're willing to risk rate limiting, you can decrease the delay
class InfoChannel ( Cog ) :
class InfoChannel ( Cog ) :
"""
"""
@ -19,6 +22,7 @@ class InfoChannel(Cog):
"""
"""
def __init__ ( self , bot : Red ) :
def __init__ ( self , bot : Red ) :
super ( ) . __init__ ( )
self . bot = bot
self . bot = bot
self . config = Config . get_conf (
self . config = Config . get_conf (
self , identifier = 731101021116710497110110101108 , force_registration = True
self , identifier = 731101021116710497110110101108 , force_registration = True
@ -35,6 +39,8 @@ class InfoChannel(Cog):
self . config . register_guild ( * * default_guild )
self . config . register_guild ( * * default_guild )
self . _critical_section_wooah_ = 0
@commands.command ( )
@commands.command ( )
@checks.admin ( )
@checks.admin ( )
async def infochannel ( self , ctx : commands . Context ) :
async def infochannel ( self , ctx : commands . Context ) :
@ -70,9 +76,13 @@ class InfoChannel(Cog):
return
return
if channel is None :
if channel is None :
try :
await self . make_infochannel ( guild )
await self . make_infochannel ( guild )
except discord . Forbidden :
await ctx . send ( " Failure: Missing permission to create voice channel " )
return
else :
else :
await self . delete_infochannel ( guild , channel )
await self . delete_ all_ infochannels ( guild )
if not await ctx . tick ( ) :
if not await ctx . tick ( ) :
await ctx . send ( " Done! " )
await ctx . send ( " Done! " )
@ -83,6 +93,8 @@ class InfoChannel(Cog):
"""
"""
Toggle different types of infochannels
Toggle different types of infochannels
"""
"""
if not ctx . invoked_subcommand :
pass
@infochannelset.command ( name = " botcount " )
@infochannelset.command ( name = " botcount " )
async def _infochannelset_botcount ( self , ctx : commands . Context , enabled : bool = None ) :
async def _infochannelset_botcount ( self , ctx : commands . Context , enabled : bool = None ) :
@ -92,7 +104,10 @@ class InfoChannel(Cog):
guild = ctx . guild
guild = ctx . guild
if enabled is None :
if enabled is None :
enabled = not await self . config . guild ( guild ) . bot_count ( )
enabled = not await self . config . guild ( guild ) . bot_count ( )
await self . config . guild ( guild ) . bot_count . set ( enabled )
await self . config . guild ( guild ) . bot_count . set ( enabled )
await self . make_infochannel ( ctx . guild )
if enabled :
if enabled :
await ctx . send ( " InfoChannel for bot count has been enabled. " )
await ctx . send ( " InfoChannel for bot count has been enabled. " )
else :
else :
@ -106,7 +121,10 @@ class InfoChannel(Cog):
guild = ctx . guild
guild = ctx . guild
if enabled is None :
if enabled is None :
enabled = not await self . config . guild ( guild ) . online_count ( )
enabled = not await self . config . guild ( guild ) . online_count ( )
await self . config . guild ( guild ) . online_count . set ( enabled )
await self . config . guild ( guild ) . online_count . set ( enabled )
await self . make_infochannel ( ctx . guild )
if enabled :
if enabled :
await ctx . send ( " InfoChannel for online user count has been enabled. " )
await ctx . send ( " InfoChannel for online user count has been enabled. " )
else :
else :
@ -120,25 +138,49 @@ class InfoChannel(Cog):
guild . me : discord . PermissionOverwrite ( manage_channels = True , connect = True ) ,
guild . me : discord . PermissionOverwrite ( manage_channels = True , connect = True ) ,
}
}
# Remove the old info channel first
channel_id = await self . config . guild ( guild ) . channel_id ( )
if channel_id is not None :
channel : discord . VoiceChannel = guild . get_channel ( channel_id )
if channel :
await channel . delete ( reason = " InfoChannel delete " )
# Then create the new one
channel = await guild . create_voice_channel (
channel = await guild . create_voice_channel (
" Placeholder " , reason = " InfoChannel make " , overwrites = overwrites
" Total Humans: " , reason = " InfoChannel make " , overwrites = overwrites
)
)
await self . config . guild ( guild ) . channel_id . set ( channel . id )
await self . config . guild ( guild ) . channel_id . set ( channel . id )
if botcount :
if botcount :
# Remove the old bot channel first
botchannel_id = await self . config . guild ( guild ) . botchannel_id ( )
if channel_id is not None :
botchannel : discord . VoiceChannel = guild . get_channel ( botchannel_id )
if botchannel :
await botchannel . delete ( reason = " InfoChannel delete " )
# Then create the new one
botchannel = await guild . create_voice_channel (
botchannel = await guild . create_voice_channel (
" Placeholder " , reason = " InfoChannel botcount " , overwrites = overwrites
" Bots: " , reason = " InfoChannel botcount " , overwrites = overwrites
)
)
await self . config . guild ( guild ) . botchannel_id . set ( botchannel . id )
await self . config . guild ( guild ) . botchannel_id . set ( botchannel . id )
if onlinecount :
if onlinecount :
# Remove the old online channel first
onlinechannel_id = await self . config . guild ( guild ) . onlinechannel_id ( )
if channel_id is not None :
onlinechannel : discord . VoiceChannel = guild . get_channel ( onlinechannel_id )
if onlinechannel :
await onlinechannel . delete ( reason = " InfoChannel delete " )
# Then create the new one
onlinechannel = await guild . create_voice_channel (
onlinechannel = await guild . create_voice_channel (
" Placeholder " , reason = " InfoChannel onlinecount " , overwrites = overwrites
" Online: " , reason = " InfoChannel onlinecount " , overwrites = overwrites
)
)
await self . config . guild ( guild ) . onlinechannel_id . set ( onlinechannel . id )
await self . config . guild ( guild ) . onlinechannel_id . set ( onlinechannel . id )
await self . update_infochannel ( guild )
await self . update_infochannel ( guild )
async def delete_infochannel ( self , guild : discord . Guild , channel : discord . VoiceChannel ) :
async def delete_ all_ infochannels ( self , guild : discord . Guild ) :
guild_data = await self . config . guild ( guild ) . all ( )
guild_data = await self . config . guild ( guild ) . all ( )
botchannel_id = guild_data [ " botchannel_id " ]
botchannel_id = guild_data [ " botchannel_id " ]
onlinechannel_id = guild_data [ " onlinechannel_id " ]
onlinechannel_id = guild_data [ " onlinechannel_id " ]
@ -151,6 +193,7 @@ class InfoChannel(Cog):
await botchannel . delete ( reason = " InfoChannel delete " )
await botchannel . delete ( reason = " InfoChannel delete " )
if onlinechannel_id is not None :
if onlinechannel_id is not None :
await onlinechannel . delete ( reason = " InfoChannel delete " )
await onlinechannel . delete ( reason = " InfoChannel delete " )
await self . config . guild ( guild ) . clear ( )
await self . config . guild ( guild ) . clear ( )
async def update_infochannel ( self , guild : discord . Guild ) :
async def update_infochannel ( self , guild : discord . Guild ) :
@ -162,23 +205,23 @@ class InfoChannel(Cog):
# bots = lambda x: x.bot
# bots = lambda x: x.bot
# def bots(x): return x.bot
# def bots(x): return x.bot
num = len ( [ m for m in guild . members if m . bot ] )
bot_ num = len ( [ m for m in guild . members if m . bot ] )
bot_msg = f " Bots: { num } "
# bot_msg = f"Bots: {num} "
# Gets count of online users
# Gets count of online users
members = guild . member_count
members = guild . member_count
offline = len ( list ( filter ( lambda m : m . status is discord . Status . offline , guild . members ) ) )
offline = len ( list ( filter ( lambda m : m . status is discord . Status . offline , guild . members ) ) )
num = members - offline
online_ num = members - offline
online_msg = f " Online: { num } "
# online_msg = f"Online: {num} "
# Gets count of actual users
# Gets count of actual users
total = lambda x : not x . bot
total = lambda x : not x . bot
num = len ( [ m for m in guild . members if total ( m ) ] )
human_ num = len ( [ m for m in guild . members if total ( m ) ] )
human_msg = f " Total Humans: { num } "
# human_msg = f"Total Humans: {num} "
channel_id = guild_data [ " channel_id " ]
channel_id = guild_data [ " channel_id " ]
if channel_id is None :
if channel_id is None :
return
return False
botchannel_id = guild_data [ " botchannel_id " ]
botchannel_id = guild_data [ " botchannel_id " ]
onlinechannel_id = guild_data [ " onlinechannel_id " ]
onlinechannel_id = guild_data [ " onlinechannel_id " ]
@ -188,28 +231,53 @@ class InfoChannel(Cog):
onlinechannel : discord . VoiceChannel = guild . get_channel ( onlinechannel_id )
onlinechannel : discord . VoiceChannel = guild . get_channel ( onlinechannel_id )
if guild_data [ " member_count " ] :
if guild_data [ " member_count " ] :
name = " {} " . format ( human_msg )
name = f " { channel . name . split ( ' : ' ) [ 0 ] } : { human_num } "
await channel . edit ( reason = " InfoChannel update " , name = name )
await channel . edit ( reason = " InfoChannel update " , name = name )
if botcount :
if botcount :
name = " {} " . format ( bot_msg )
name = f" { botchannel . name . split ( ' : ' ) [ 0 ] } : { bot_num } "
await botchannel . edit ( reason = " InfoChannel update " , name = name )
await botchannel . edit ( reason = " InfoChannel update " , name = name )
if onlinecount :
if onlinecount :
name = " {} " . format ( online_msg )
name = f" { onlinechannel . name . split ( ' : ' ) [ 0 ] } : { online_num } "
await onlinechannel . edit ( reason = " InfoChannel update " , name = name )
await onlinechannel . edit ( reason = " InfoChannel update " , name = name )
async def update_infochannel_with_cooldown ( self , guild ) :
""" My attempt at preventing rate limits, lets see how it goes """
if self . _critical_section_wooah_ :
if self . _critical_section_wooah_ == 2 :
print ( " Already pending, skipping " )
return # Another one is already pending, don't queue more than one
print ( " Queuing another update " )
self . _critical_section_wooah_ = 2
while self . _critical_section_wooah_ :
await asyncio . sleep (
RATE_LIMIT_DELAY / / 4
) # Max delay ends up as 1.25 * RATE_LIMIT_DELAY
print ( " Issuing queued update " )
return await self . update_infochannel_with_cooldown ( guild )
print ( " Entering critical " )
self . _critical_section_wooah_ = 1
await self . update_infochannel ( guild )
await asyncio . sleep ( RATE_LIMIT_DELAY )
self . _critical_section_wooah_ = 0
print ( " Exiting critical " )
@Cog.listener ( )
@Cog.listener ( )
async def on_member_join ( self , member : discord . Member ) :
async def on_member_join ( self , member : discord . Member ) :
await self . update_infochannel ( member . guild )
await self . update_infochannel _with_cooldown ( member . guild )
@Cog.listener ( )
@Cog.listener ( )
async def on_member_remove ( self , member : discord . Member ) :
async def on_member_remove ( self , member : discord . Member ) :
await self . update_infochannel ( member . guild )
await self . update_infochannel _with_cooldown ( member . guild )
@Cog.listener ( )
@Cog.listener ( )
async def on_member_update ( self , before : discord . Member , after : discord . Member ) :
async def on_member_update ( self , before : discord . Member , after : discord . Member ) :
onlinecount = await self . config . guild ( after . guild ) . online_count ( )
onlinecount = await self . config . guild ( after . guild ) . online_count ( )
if onlinecount :
if onlinecount :
if before . status != after . status :
if before . status != after . status :
await self . update_infochannel ( after . guild )
await self . update_infochannel _with_cooldown ( after . guild )