Переглянути джерело

Progressive functionality based on enabled privileged intents

main
Rocketsoup 1 місяць тому
джерело
коміт
c1485f052e

+ 7
- 1
config.sample.py Переглянути файл

1
 # Copy this file to config.py and fill in "<REQUIRED>" values
1
 # Copy this file to config.py and fill in "<REQUIRED>" values
2
 CONFIG = {
2
 CONFIG = {
3
-	'__config_version': 4,
3
+	'__config_version': 5,
4
 
4
 
5
     # -----------------------------------------------------------------------
5
     # -----------------------------------------------------------------------
6
     # General
6
     # General
14
 	'max_members_per_message': 20,
14
 	'max_members_per_message': 20,
15
 	# Minimum seconds between warnings about the same member.
15
 	# Minimum seconds between warnings about the same member.
16
 	'squelch_warning_seconds': 300,
16
 	'squelch_warning_seconds': 300,
17
+	# Whether the Discord app has Message Content intent enabled. Enables more
18
+	# features but requires applying for access for bots serving 10k or more users.
19
+	'has_message_content_intent': False,
20
+	# Whether the Discord app has Server Members intent enabled. Enables more
21
+	# features but requires applying for access for bots serving 10k or more users.
22
+	'has_members_intent': False,
17
 
23
 
18
     # -----------------------------------------------------------------------
24
     # -----------------------------------------------------------------------
19
     # Emojis used for performing actions on flagged activities. The bot will
25
     # Emojis used for performing actions on flagged activities. The bot will

+ 1
- 1
main.py Переглянути файл

19
 from rocketbot.bot import start_bot  # noqa: E402
19
 from rocketbot.bot import start_bot  # noqa: E402
20
 from rocketbot.utils import bot_log  # noqa: E402
20
 from rocketbot.utils import bot_log  # noqa: E402
21
 
21
 
22
-CURRENT_CONFIG_VERSION = 4
22
+CURRENT_CONFIG_VERSION = 5
23
 if (CONFIG.get('__config_version') or 0) < CURRENT_CONFIG_VERSION:
23
 if (CONFIG.get('__config_version') or 0) < CURRENT_CONFIG_VERSION:
24
 	# If you're getting this error, it means something changed in config.py's
24
 	# If you're getting this error, it means something changed in config.py's
25
 	# format. Consult config.sample.py and compare it to your own config.py.
25
 	# format. Consult config.sample.py and compare it to your own config.py.

+ 25
- 13
rocketbot/bot.py Переглянути файл

83
 		return
83
 		return
84
 	bot_log(None, None, 'Creating bot...')
84
 	bot_log(None, None, 'Creating bot...')
85
 	intents = Intents.default()
85
 	intents = Intents.default()
86
-	intents.message_content = True
87
-	intents.members = True
86
+	# Set privileged intents. Must agree with configuration in Discord app.
87
+	intents.message_content = CONFIG.get('has_message_content_intent', False)
88
+	intents.members = CONFIG.get('has_members_intent', False)
88
 	intents.presences = False
89
 	intents.presences = False
89
 	rocketbot = Rocketbot(intents=intents)
90
 	rocketbot = Rocketbot(intents=intents)
90
 __create_bot()
91
 __create_bot()
111
 	await rocketbot.add_cog(ConfigCog(rocketbot))
112
 	await rocketbot.add_cog(ConfigCog(rocketbot))
112
 
113
 
113
 	# Optional
114
 	# Optional
114
-	await rocketbot.add_cog(AutoKickCog(rocketbot))
115
-	await rocketbot.add_cog(BangCommandCog(rocketbot))
116
-	await rocketbot.add_cog(CrossPostCog(rocketbot))
117
-	await rocketbot.add_cog(GamesCog(rocketbot))
118
-	await rocketbot.add_cog(HelpCog(rocketbot))
119
-	await rocketbot.add_cog(JoinRaidCog(rocketbot))
120
-	await rocketbot.add_cog(LoggingCog(rocketbot))
121
-	await rocketbot.add_cog(PatternCog(rocketbot))
122
-	await rocketbot.add_cog(URLSpamCog(rocketbot))
123
-	await rocketbot.add_cog(UsernamePatternCog(rocketbot))
124
-	await rocketbot.add_cog(VideoPreviewCog(rocketbot))
115
+	if AutoKickCog.supports_intents(rocketbot.intents):
116
+		await rocketbot.add_cog(AutoKickCog(rocketbot))
117
+	if BangCommandCog.supports_intents(rocketbot.intents):
118
+		await rocketbot.add_cog(BangCommandCog(rocketbot))
119
+	if CrossPostCog.supports_intents(rocketbot.intents):
120
+		await rocketbot.add_cog(CrossPostCog(rocketbot))
121
+	if GamesCog.supports_intents(rocketbot.intents):
122
+		await rocketbot.add_cog(GamesCog(rocketbot))
123
+	if HelpCog.supports_intents(rocketbot.intents):
124
+		await rocketbot.add_cog(HelpCog(rocketbot))
125
+	if JoinRaidCog.supports_intents(rocketbot.intents):
126
+		await rocketbot.add_cog(JoinRaidCog(rocketbot))
127
+	if LoggingCog.supports_intents(rocketbot.intents):
128
+		await rocketbot.add_cog(LoggingCog(rocketbot))
129
+	if PatternCog.supports_intents(rocketbot.intents):
130
+		await rocketbot.add_cog(PatternCog(rocketbot))
131
+	if URLSpamCog.supports_intents(rocketbot.intents):
132
+		await rocketbot.add_cog(URLSpamCog(rocketbot))
133
+	if UsernamePatternCog.supports_intents(rocketbot.intents):
134
+		await rocketbot.add_cog(UsernamePatternCog(rocketbot))
135
+	if VideoPreviewCog.supports_intents(rocketbot.intents):
136
+		await rocketbot.add_cog(VideoPreviewCog(rocketbot))
125
 
137
 
126
 	await rocketbot.start(CONFIG['client_token'], reconnect=True)
138
 	await rocketbot.start(CONFIG['client_token'], reconnect=True)
127
 	print('\nBot aborted')
139
 	print('\nBot aborted')

+ 5
- 1
rocketbot/cogs/autokickcog.py Переглянути файл

1
 from datetime import datetime, timedelta, timezone
1
 from datetime import datetime, timedelta, timezone
2
 
2
 
3
-from discord import Guild, Member, Status
3
+from discord import Guild, Intents, Member, Status
4
 from discord.ext import tasks
4
 from discord.ext import tasks
5
 from discord.ext.commands import Cog
5
 from discord.ext.commands import Cog
6
 from discord.ext.tasks import Loop
6
 from discord.ext.tasks import Loop
158
 			if val % 10 == 3:
158
 			if val % 10 == 3:
159
 				return f'{val}rd'
159
 				return f'{val}rd'
160
 		return f'{val}th'
160
 		return f'{val}th'
161
+
162
+	@classmethod
163
+	def supports_intents(cls, intents: Intents) -> bool:
164
+		return intents.members

+ 13
- 1
rocketbot/cogs/bangcommandcog.py Переглянути файл

1
 import re
1
 import re
2
 from typing import Optional, TypedDict
2
 from typing import Optional, TypedDict
3
 
3
 
4
-from discord import Guild, Interaction, Message, SelectOption, TextChannel, TextStyle
4
+from discord import (
5
+	Guild,
6
+	Intents,
7
+	Interaction,
8
+	Message,
9
+	SelectOption,
10
+	TextChannel,
11
+	TextStyle,
12
+)
5
 from discord.app_commands import Choice, Group, autocomplete
13
 from discord.app_commands import Choice, Group, autocomplete
6
 from discord.ext.commands import Cog
14
 from discord.ext.commands import Cog
7
 from discord.ui import Label, Modal, Select, TextInput
15
 from discord.ui import Label, Modal, Select, TextInput
270
 		match = re.match(r'^!((?:[a-z]+)(?:[_-][a-z]+)*)\b.*$', name)
278
 		match = re.match(r'^!((?:[a-z]+)(?:[_-][a-z]+)*)\b.*$', name)
271
 		return BangCommandCog._normalize_name(match.group(1)) if match else None
279
 		return BangCommandCog._normalize_name(match.group(1)) if match else None
272
 
280
 
281
+	@classmethod
282
+	def supports_intents(cls, intents: Intents) -> bool:
283
+		return intents.message_content
284
+
273
 class _EditModal(Modal, title='Edit Command'):
285
 class _EditModal(Modal, title='Edit Command'):
274
 	name_label = Label(
286
 	name_label = Label(
275
 		text='Command name',
287
 		text='Command name',

+ 7
- 0
rocketbot/cogs/basecog.py Переглянути файл

7
 import discord
7
 import discord
8
 from discord import (
8
 from discord import (
9
 	Guild,
9
 	Guild,
10
+	Intents,
10
 	Interaction,
11
 	Interaction,
11
 	Member,
12
 	Member,
12
 	Message,
13
 	Message,
302
 		Writes a message to the console. Intended for significant events only.
303
 		Writes a message to the console. Intended for significant events only.
303
 		"""
304
 		"""
304
 		bot_log(guild, cls, message)
305
 		bot_log(guild, cls, message)
306
+
307
+	# Meta
308
+
309
+	@classmethod
310
+	def supports_intents(cls, intents: Intents) -> bool:
311
+		return True

+ 11
- 7
rocketbot/cogs/crosspostcog.py Переглянути файл

141
 			self.__trace(f"User {message.author.name} exempt from crosspost checks")
141
 			self.__trace(f"User {message.author.name} exempt from crosspost checks")
142
 			return
142
 			return
143
 		def compute_message_hash(m: Message) -> int:
143
 		def compute_message_hash(m: Message) -> int:
144
-			to_hash = m.content
145
-			# URLs sometimes differ per spam message, so simplify them
146
-			url_regex = r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
147
-			to_hash = re.sub(url_regex, '<url>', to_hash)
148
-			# Add attachment metadata
149
-			for attachment in m.attachments:
150
-				to_hash += f'\n[[ATT: ct={attachment.content_type} s={attachment.size} w={attachment.width} h={attachment.height}]]'
144
+			if self.bot.intents.message_content:
145
+				to_hash = m.content
146
+				# URLs sometimes differ per spam message, so simplify them
147
+				url_regex = r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'
148
+				to_hash = re.sub(url_regex, '<url>', to_hash)
149
+				# Add attachment metadata
150
+				for attachment in m.attachments:
151
+					to_hash += f'\n[[ATT: ct={attachment.content_type} s={attachment.size} w={attachment.width} h={attachment.height}]]'
152
+			else:
153
+				# Without content, treat every message as unique
154
+				to_hash = str(m.id)
151
 			h = hash(to_hash)
155
 			h = hash(to_hash)
152
 			self.__trace(f"Hash for message #{m.id} by {m.author.name} is {h}\n\thash content: \"{to_hash}\"")
156
 			self.__trace(f"Hash for message #{m.id} by {m.author.name} is {h}\n\thash content: \"{to_hash}\"")
153
 			return h
157
 			return h

+ 5
- 1
rocketbot/cogs/joinraidcog.py Переглянути файл

5
 from datetime import datetime, timedelta
5
 from datetime import datetime, timedelta
6
 from typing import Optional
6
 from typing import Optional
7
 
7
 
8
-from discord import Guild, Member
8
+from discord import Guild, Intents, Member
9
 from discord.ext.commands import Cog
9
 from discord.ext.commands import Cog
10
 
10
 
11
 from config import CONFIG
11
 from config import CONFIG
189
 			did_kick=kick_count >= member_count,
189
 			did_kick=kick_count >= member_count,
190
 			did_ban=ban_count >= member_count,
190
 			did_ban=ban_count >= member_count,
191
 			user_count=member_count))
191
 			user_count=member_count))
192
+
193
+	@classmethod
194
+	def supports_intents(cls, intents: Intents) -> bool:
195
+		return intents.members

+ 18
- 0
rocketbot/cogs/logcog.py Переглянути файл

206
 		Called when a Member joins a Guild.
206
 		Called when a Member joins a Guild.
207
 
207
 
208
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_member_join
208
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_member_join
209
+
210
+		Requires Members privileged intent.
209
 		"""
211
 		"""
210
 		guild = member.guild
212
 		guild = member.guild
211
 		if not self.get_guild_setting(guild, self.SETTING_ENABLED):
213
 		if not self.get_guild_setting(guild, self.SETTING_ENABLED):
273
 		will not be called, you may use on_raw_member_remove() instead.
275
 		will not be called, you may use on_raw_member_remove() instead.
274
 
276
 
275
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_member_remove
277
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_member_remove
278
+
279
+		Requires Members privileged intent.
276
 		"""
280
 		"""
277
 		guild = member.guild
281
 		guild = member.guild
278
 		if not self.get_guild_setting(guild, self.SETTING_ENABLED):
282
 		if not self.get_guild_setting(guild, self.SETTING_ENABLED):
312
 		* flags
316
 		* flags
313
 
317
 
314
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_member_update
318
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_member_update
319
+
320
+		Requires Members privileged intent.
315
 		"""
321
 		"""
316
 		guild = after.guild
322
 		guild = after.guild
317
 		if not self.get_guild_setting(guild, self.SETTING_ENABLED):
323
 		if not self.get_guild_setting(guild, self.SETTING_ENABLED):
371
 		* discriminator
377
 		* discriminator
372
 
378
 
373
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_user_update
379
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_user_update
380
+
381
+		Requires Members privileged intent.
374
 		"""
382
 		"""
375
 		if hasattr(after, 'guild'):
383
 		if hasattr(after, 'guild'):
376
 			guild = after.guild
384
 			guild = after.guild
492
 		Called when a Message is created and sent.
500
 		Called when a Message is created and sent.
493
 
501
 
494
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_message
502
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_message
503
+
504
+		Content fields blank without MessageContent privileged intent.
495
 		"""
505
 		"""
496
 		# print(f"on_message:"
506
 		# print(f"on_message:"
497
 		# 	f"\n\tid: {message.id}"
507
 		# 	f"\n\tid: {message.id}"
523
 		* A call message has received an update to its participants or ending time.
533
 		* A call message has received an update to its participants or ending time.
524
 
534
 
525
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_message_edit
535
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_message_edit
536
+
537
+		Content fields blank without MessageContent privileged intent.
526
 		"""
538
 		"""
527
 		guild = after.guild
539
 		guild = after.guild
528
 		if not self.get_guild_setting(guild, self.SETTING_ENABLED):
540
 		if not self.get_guild_setting(guild, self.SETTING_ENABLED):
556
 		Discord embed server.
568
 		Discord embed server.
557
 
569
 
558
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_raw_message_edit
570
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_raw_message_edit
571
+
572
+		Content fields blank without MessageContent privileged intent.
559
 		"""
573
 		"""
560
 		if payload.cached_message:
574
 		if payload.cached_message:
561
 			return  # already handled by on_message_edit
575
 			return  # already handled by on_message_edit
663
 		RawMessageDeleteEvent.cached_message
677
 		RawMessageDeleteEvent.cached_message
664
 
678
 
665
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_raw_message_delete
679
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_raw_message_delete
680
+
681
+		Content fields blank without MessageContent privileged intent.
666
 		"""
682
 		"""
667
 		message = payload.cached_message
683
 		message = payload.cached_message
668
 		if message and message.author.id == self.bot.user.id:
684
 		if message and message.author.id == self.bot.user.id:
692
 		RawBulkMessageDeleteEvent.cached_messages
708
 		RawBulkMessageDeleteEvent.cached_messages
693
 
709
 
694
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_raw_bulk_message_delete
710
 		https://discordpy.readthedocs.io/en/stable/api.html#discord.on_raw_bulk_message_delete
711
+
712
+		Content fields blank without MessageContent privileged intent.
695
 		"""
713
 		"""
696
 		guild = self.bot.get_guild(payload.guild_id) or await self.bot.fetch_guild(payload.guild_id)
714
 		guild = self.bot.get_guild(payload.guild_id) or await self.bot.fetch_guild(payload.guild_id)
697
 		if not guild:
715
 		if not guild:

+ 5
- 1
rocketbot/cogs/patterncog.py Переглянути файл

6
 from datetime import datetime
6
 from datetime import datetime
7
 from typing import Optional
7
 from typing import Optional
8
 
8
 
9
-from discord import Guild, Interaction, Member, Message
9
+from discord import Guild, Intents, Interaction, Member, Message
10
 from discord import utils as discordutils
10
 from discord import utils as discordutils
11
 from discord.app_commands import Choice, Group, autocomplete
11
 from discord.app_commands import Choice, Group, autocomplete
12
 from discord.ext.commands import Cog
12
 from discord.ext.commands import Cog
435
 				f'updated to `{priority}`.',
435
 				f'updated to `{priority}`.',
436
 			ephemeral=True,
436
 			ephemeral=True,
437
 		)
437
 		)
438
+
439
+	@classmethod
440
+	def supports_intents(cls, intents: Intents) -> bool:
441
+		return intents.message_content

+ 5
- 1
rocketbot/cogs/urlspamcog.py Переглянути файл

5
 from datetime import timedelta
5
 from datetime import timedelta
6
 from typing import Literal
6
 from typing import Literal
7
 
7
 
8
-from discord import Guild, Member, Message
8
+from discord import Guild, Intents, Member, Message
9
 from discord import utils as discordutils
9
 from discord import utils as discordutils
10
 from discord.ext.commands import Cog
10
 from discord.ext.commands import Cog
11
 from discord.utils import escape_markdown
11
 from discord.utils import escape_markdown
358
 	def __find_urls(cls, text: str) -> list[str]:
358
 	def __find_urls(cls, text: str) -> list[str]:
359
 		p = re.compile(r'https?://\S+')
359
 		p = re.compile(r'https?://\S+')
360
 		return re.findall(p, text)
360
 		return re.findall(p, text)
361
+
362
+	@classmethod
363
+	def supports_intents(cls, intents: Intents) -> bool:
364
+		return intents.message_content

+ 5
- 1
rocketbot/cogs/usernamecog.py Переглянути файл

3
 """
3
 """
4
 from typing import Optional
4
 from typing import Optional
5
 
5
 
6
-from discord import Guild, Interaction, Member
6
+from discord import Guild, Intents, Interaction, Member
7
 from discord.app_commands import Group
7
 from discord.app_commands import Group
8
 from discord.ext.commands import Cog
8
 from discord.ext.commands import Cog
9
 
9
 
239
 			context.ignored_by = reacted_by
239
 			context.ignored_by = reacted_by
240
 			self.log(context.member.guild, f'Warning ignored by {reacted_by.name}')
240
 			self.log(context.member.guild, f'Warning ignored by {reacted_by.name}')
241
 			await bot_message.set_reactions(context.reactions())
241
 			await bot_message.set_reactions(context.reactions())
242
+
243
+	@classmethod
244
+	def supports_intents(cls, intents: Intents) -> bool:
245
+		return intents.members

+ 5
- 1
rocketbot/cogs/videopreviewcog.py Переглянути файл

4
 import subprocess
4
 import subprocess
5
 from datetime import timedelta
5
 from datetime import timedelta
6
 
6
 
7
-from discord import Message
7
+from discord import Intents, Message
8
 from discord.ext.commands import Cog
8
 from discord.ext.commands import Cog
9
 
9
 
10
 from rocketbot.cogs.basecog import BaseCog
10
 from rocketbot.cogs.basecog import BaseCog
219
 			content,
219
 			content,
220
 			mention_author=False
220
 			mention_author=False
221
 		)
221
 		)
222
+
223
+	@classmethod
224
+	def supports_intents(cls, intents: Intents) -> bool:
225
+		return intents.message_content

Завантаження…
Відмінити
Зберегти