diff --git a/README.md b/README.md
index 3a9ab8f..ec76ead 100644
--- a/README.md
+++ b/README.md
@@ -14,11 +14,13 @@ Cog Function
| exclusiverole | **Alpha** | Prevent certain roles from getting any other roles
Fully functional, but pretty simple |
| fifo | **Alpha** | Schedule commands to be run at certain times or intervals
Just released, please report bugs as you find them. Only works for bot owner for now |
| fight | **Incomplete** | Organize bracket tournaments within discord
Still in-progress, a massive project |
+| firstmessage | **Release** | Simple cog to provide a jump link to the first message in a channel/summary>Just released, please report bugs as you find them.
|
| flag | **Alpha** | Create temporary marks on users that expire after specified time
Ported, will not import old data. Please report bugs |
| forcemention | **Alpha** | Mentions unmentionable roles
Very simple cog, mention doesn't persist |
| hangman | **Beta** | Play a game of hangman
Some visual glitches and needs more customization |
| howdoi | **Incomplete** | Ask coding questions and get results from StackExchange
Not yet functional |
-| infochannel | **Beta** | Create a channel to display server info
Just released, please report bugs |
+| infochannel | **Beta** | Create a channel to display server info
Due to rate limits, this does not update as often as it once did |
+| isitdown | **Beta** | Check if a website/url is down
Just released, please report bugs |
| launchlib | **Beta** | Access rocket launch data
Just released, please report bugs |
| leaver | **Beta** | Send a message in a channel when a user leaves the server
Seems to be functional, please report any bugs or suggestions |
| lovecalculator | **Alpha** | Calculate the love between two users
[Snap-Ons] Just updated to V3 |
@@ -38,7 +40,7 @@ Cog Function
| unicode | **Alpha** | Encode and Decode unicode characters
[Snap-Ons] Just updated to V3 |
| werewolf | **Pre-Alpha** | Play the classic party game Werewolf within discord
Another massive project currently being developed, will be fully customizable |
-Check out my V2 cogs at [Fox-Cogs v2](https://github.com/bobloy/Fox-Cogs)
+Check out *Deprecated* my V2 cogs at [Fox-Cogs v2](https://github.com/bobloy/Fox-Cogs)
# Installation
### Recommended - Built-in Downloader
diff --git a/audiotrivia/audiosession.py b/audiotrivia/audiosession.py
index 780d4b9..1bdff02 100644
--- a/audiotrivia/audiosession.py
+++ b/audiotrivia/audiosession.py
@@ -1,8 +1,13 @@
"""Module to manage audio trivia sessions."""
import asyncio
+import logging
import lavalink
+from lavalink.enums import LoadType
from redbot.cogs.trivia import TriviaSession
+from redbot.core.utils.chat_formatting import bold
+
+log = logging.getLogger("red.fox_v3.audiotrivia.audiosession")
class AudioSession(TriviaSession):
@@ -23,9 +28,9 @@ class AudioSession(TriviaSession):
async def run(self):
"""Run the audio trivia session.
- In order for the trivia session to be stopped correctly, this should
- only be called internally by `TriviaSession.start`.
- """
+ In order for the trivia session to be stopped correctly, this should
+ only be called internally by `TriviaSession.start`.
+ """
await self._send_startup_msg()
max_score = self.settings["max_score"]
delay = self.settings["delay"]
@@ -36,8 +41,9 @@ class AudioSession(TriviaSession):
self.count += 1
await self.player.stop()
- msg = "**Question number {}!**\n\nName this audio!".format(self.count)
- await self.ctx.send(msg)
+ msg = bold(f"Question number {self.count}!") + "\n\nName this audio!"
+ await self.ctx.maybe_send_embed(msg)
+ log.debug(f"Audio question: {question}")
# print("Audio question: {}".format(question))
# await self.ctx.invoke(self.audio.play(ctx=self.ctx, query=question))
@@ -45,18 +51,28 @@ class AudioSession(TriviaSession):
# await self.ctx.invoke(self.player.play, query=question)
query = question.strip("<>")
- tracks = await self.player.get_tracks(query)
- seconds = tracks[0].length / 1000
+ load_result = await self.player.load_tracks(query)
+ log.debug(f"{load_result.load_type=}")
+ if load_result.has_error or load_result.load_type != LoadType.TRACK_LOADED:
+ await self.ctx.maybe_send_embed(f"Track has error, skipping. See logs for details")
+ log.info(f"Track has error: {load_result.exception_message}")
+ continue # Skip tracks with error
+ tracks = load_result.tracks
+
+ track = tracks[0]
+ seconds = track.length / 1000
if self.settings["repeat"] and seconds < delay:
+ # Append it until it's longer than the delay
tot_length = seconds + 0
while tot_length < delay:
- self.player.add(self.ctx.author, tracks[0])
+ self.player.add(self.ctx.author, track)
tot_length += seconds
else:
- self.player.add(self.ctx.author, tracks[0])
+ self.player.add(self.ctx.author, track)
if not self.player.current:
+ log.debug("Pressing play")
await self.player.play()
continue_ = await self.wait_for_answer(answers, delay, timeout)
diff --git a/audiotrivia/audiotrivia.py b/audiotrivia/audiotrivia.py
index c0c88fd..0bab980 100644
--- a/audiotrivia/audiotrivia.py
+++ b/audiotrivia/audiotrivia.py
@@ -1,4 +1,5 @@
import datetime
+import logging
import pathlib
from typing import List
@@ -15,7 +16,7 @@ from redbot.core.utils.chat_formatting import box
from .audiosession import AudioSession
-# from redbot.cogs.audio.utils import userlimit
+log = logging.getLogger("red.fox_v3.audiotrivia")
class AudioTrivia(Trivia):
@@ -83,24 +84,24 @@ class AudioTrivia(Trivia):
self.audio: Audio = self.bot.get_cog("Audio")
if self.audio is None:
- await ctx.send("Audio is not loaded. Load it and try again")
+ await ctx.maybe_send_embed("Audio is not loaded. Load it and try again")
return
categories = [c.lower() for c in categories]
session = self._get_trivia_session(ctx.channel)
if session is not None:
- await ctx.send("There is already an ongoing trivia session in this channel.")
+ await ctx.maybe_send_embed("There is already an ongoing trivia session in this channel.")
return
status = await self.audio.config.status()
notify = await self.audio.config.guild(ctx.guild).notify()
if status:
- await ctx.send(
+ await ctx.maybe_send_embed(
f"It is recommended to disable audio status with `{ctx.prefix}audioset status`"
)
if notify:
- await ctx.send(
+ await ctx.maybe_send_embed(
f"It is recommended to disable audio notify with `{ctx.prefix}audioset notify`"
)
@@ -109,12 +110,12 @@ class AudioTrivia(Trivia):
if not ctx.author.voice.channel.permissions_for(
ctx.me
).connect or self.audio.is_vc_full(ctx.author.voice.channel):
- return await ctx.send("I don't have permission to connect to your channel.")
+ return await ctx.maybe_send_embed("I don't have permission to connect to your channel.")
await lavalink.connect(ctx.author.voice.channel)
lavaplayer = lavalink.get_player(ctx.guild.id)
lavaplayer.store("connect", datetime.datetime.utcnow())
except AttributeError:
- return await ctx.send("Connect to a voice channel first.")
+ return await ctx.maybe_send_embed("Connect to a voice channel first.")
lavaplayer = lavalink.get_player(ctx.guild.id)
lavaplayer.store("channel", ctx.channel.id) # What's this for? I dunno
@@ -122,7 +123,7 @@ class AudioTrivia(Trivia):
await self.audio.set_player_settings(ctx)
if not ctx.author.voice or ctx.author.voice.channel != lavaplayer.channel:
- return await ctx.send(
+ return await ctx.maybe_send_embed(
"You must be in the voice channel to use the audiotrivia command."
)
@@ -134,13 +135,13 @@ class AudioTrivia(Trivia):
try:
dict_ = self.get_audio_list(category)
except FileNotFoundError:
- await ctx.send(
+ await ctx.maybe_send_embed(
"Invalid category `{0}`. See `{1}audiotrivia list`"
" for a list of trivia categories."
"".format(category, ctx.prefix)
)
except InvalidListError:
- await ctx.send(
+ await ctx.maybe_send_embed(
"There was an error parsing the trivia list for"
" the `{}` category. It may be formatted"
" incorrectly.".format(category)
@@ -151,7 +152,7 @@ class AudioTrivia(Trivia):
continue
return
if not trivia_dict:
- await ctx.send(
+ await ctx.maybe_send_embed(
"The trivia list was parsed successfully, however it appears to be empty!"
)
return
@@ -166,7 +167,10 @@ class AudioTrivia(Trivia):
# Delay in audiosettings overwrites delay in settings
combined_settings = {**settings, **audiosettings}
session = AudioSession.start(
- ctx=ctx, question_list=trivia_dict, settings=combined_settings, player=lavaplayer,
+ ctx=ctx,
+ question_list=trivia_dict,
+ settings=combined_settings,
+ player=lavaplayer,
)
self.trivia_sessions.append(session)
LOG.debug("New audio trivia session; #%s in %d", ctx.channel, ctx.guild.id)
diff --git a/audiotrivia/data/lists/games.yaml b/audiotrivia/data/lists/games.yaml
index c3a9078..4de795a 100644
--- a/audiotrivia/data/lists/games.yaml
+++ b/audiotrivia/data/lists/games.yaml
@@ -1,13 +1,13 @@
AUTHOR: Plab
-https://www.youtube.com/watch?v=--bWm9hhoZo:
+https://www.youtube.com/watch?v=f9O2Rjn1azc:
- Transistor
-https://www.youtube.com/watch?v=-4nCbgayZNE:
+https://www.youtube.com/watch?v=PgUhYFkVdSY:
- Dark Cloud 2
- Dark Cloud II
-https://www.youtube.com/watch?v=-64NlME4lJU:
+https://www.youtube.com/watch?v=1T1RZttyMwU:
- Mega Man 7
- Mega Man VII
-https://www.youtube.com/watch?v=-AesqnudNuw:
+https://www.youtube.com/watch?v=AdDbbzuq1vY:
- Mega Man 9
- Mega Man IX
https://www.youtube.com/watch?v=-BmGDtP2t7M:
diff --git a/ccrole/ccrole.py b/ccrole/ccrole.py
index 190050d..eb654b1 100644
--- a/ccrole/ccrole.py
+++ b/ccrole/ccrole.py
@@ -7,6 +7,7 @@ from discord.ext.commands.view import StringView
from redbot.core import Config, checks, commands
from redbot.core.bot import Red
from redbot.core.utils.chat_formatting import box, pagify
+from redbot.core.utils.mod import get_audit_reason
log = logging.getLogger("red.fox_v3.ccrole")
@@ -358,23 +359,24 @@ class CCRole(commands.Cog):
else:
target = message.author
+ reason = get_audit_reason(message.author)
+
if cmd["aroles"]:
arole_list = [
discord.utils.get(message.guild.roles, id=roleid) for roleid in cmd["aroles"]
]
try:
- await target.add_roles(*arole_list)
+ await target.add_roles(*arole_list, reason=reason)
except discord.Forbidden:
log.exception(f"Permission error: Unable to add roles")
await ctx.send("Permission error: Unable to add roles")
- await asyncio.sleep(1)
if cmd["rroles"]:
rrole_list = [
discord.utils.get(message.guild.roles, id=roleid) for roleid in cmd["rroles"]
]
try:
- await target.remove_roles(*rrole_list)
+ await target.remove_roles(*rrole_list, reason=reason)
except discord.Forbidden:
log.exception(f"Permission error: Unable to remove roles")
await ctx.send("Permission error: Unable to remove roles")
diff --git a/chatter/README.md b/chatter/README.md
index e8c03d6..8ef6734 100644
--- a/chatter/README.md
+++ b/chatter/README.md
@@ -29,7 +29,7 @@ Chatter by default uses spaCy's `en_core_web_md` training model, which is ~50 MB
Chatter can potential use spaCy's `en_core_web_lg` training model, which is ~800 MB
-Chatter uses as sqlite database that can potentially take up a large amount os disk space,
+Chatter uses as sqlite database that can potentially take up a large amount of disk space,
depending on how much training Chatter has done.
The sqlite database can be safely deleted at any time. Deletion will only erase training data.
@@ -50,7 +50,9 @@ Linux is a bit easier, but only tested on Debian and Ubuntu.
## Windows Prerequisites
-Install these on your windows machine before attempting the installation
+**Requires 64 Bit Python to continue on Windows.**
+
+Install these on your windows machine before attempting the installation:
[Visual Studio C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
@@ -83,6 +85,7 @@ pip install --no-deps "chatterbot>=1.1"
#### Step 3: Load Chatter
```
+[p]repo add Fox https://github.com/bobloy/Fox-V3 # If you didn't already do this in step 1
[p]cog install Fox chatter
[p]load chatter
```
@@ -92,7 +95,7 @@ pip install --no-deps "chatterbot>=1.1"
#### Step 1: Built-in Downloader
```
-[p]cog install Chatter
+[p]cog install Chatter
```
#### Step 2: Install Requirements
diff --git a/chatter/chat.py b/chatter/chat.py
index a81e669..ad8e37b 100644
--- a/chatter/chat.py
+++ b/chatter/chat.py
@@ -463,7 +463,7 @@ class Chatter(Cog):
# Thank you Cog-Creators
channel: discord.TextChannel = message.channel
- if channel.id == await self.config.guild(guild).chatchannel():
+ if guild is not None and channel.id == await self.config.guild(guild).chatchannel():
pass # good to go
else:
when_mentionables = commands.when_mentioned(self.bot, message)
diff --git a/fifo/fifo.py b/fifo/fifo.py
index 91991b0..30346d7 100644
--- a/fifo/fifo.py
+++ b/fifo/fifo.py
@@ -10,6 +10,7 @@ from apscheduler.schedulers.base import STATE_PAUSED, STATE_RUNNING
from redbot.core import Config, checks, commands
from redbot.core.bot import Red
from redbot.core.commands import TimedeltaConverter
+from redbot.core.utils.chat_formatting import pagify
from .datetime_cron_converters import CronConverter, DatetimeConverter, TimezoneConverter
from .task import Task
@@ -306,7 +307,11 @@ class FIFO(commands.Cog):
out += f"{task_name}: {task_data}\n"
if out:
- await ctx.maybe_send_embed(out)
+ if len(out) > 2000:
+ for page in pagify(out):
+ await ctx.maybe_send_embed(page)
+ else:
+ await ctx.maybe_send_embed(out)
else:
await ctx.maybe_send_embed("No tasks to list")
diff --git a/fifo/info.json b/fifo/info.json
index c9a80dd..dda63ce 100644
--- a/fifo/info.json
+++ b/fifo/info.json
@@ -16,6 +16,7 @@
"bobloy",
"utilities",
"tool",
+ "tools",
"roles",
"schedule",
"cron",
diff --git a/firstmessage/__init__.py b/firstmessage/__init__.py
new file mode 100644
index 0000000..4dab2ed
--- /dev/null
+++ b/firstmessage/__init__.py
@@ -0,0 +1,5 @@
+from .firstmessage import FirstMessage
+
+
+async def setup(bot):
+ bot.add_cog(FirstMessage(bot))
diff --git a/firstmessage/firstmessage.py b/firstmessage/firstmessage.py
new file mode 100644
index 0000000..f13bd60
--- /dev/null
+++ b/firstmessage/firstmessage.py
@@ -0,0 +1,49 @@
+import logging
+
+import discord
+from redbot.core import Config, commands
+from redbot.core.bot import Red
+
+log = logging.getLogger("red.fox_v3.firstmessage")
+
+
+class FirstMessage(commands.Cog):
+ """
+ Provides a link to the first message in the provided channel
+ """
+
+ def __init__(self, bot: Red):
+ super().__init__()
+ self.bot = bot
+ self.config = Config.get_conf(
+ self, identifier=701051141151167710111511597103101, force_registration=True
+ )
+
+ default_guild = {}
+
+ self.config.register_guild(**default_guild)
+
+ async def red_delete_data_for_user(self, **kwargs):
+ """Nothing to delete"""
+ return
+
+ @commands.command()
+ async def firstmessage(self, ctx: commands.Context, channel: discord.TextChannel = None):
+ """
+ Provide a link to the first message in current or provided channel.
+ """
+ if channel is None:
+ channel = ctx.channel
+ try:
+ message: discord.Message = (
+ await channel.history(limit=1, oldest_first=True).flatten()
+ )[0]
+ except (discord.Forbidden, discord.HTTPException):
+ log.exception(f"Unable to read message history for {channel.id=}")
+ await ctx.maybe_send_embed("Unable to read message history for that channel")
+ return
+
+ em = discord.Embed(description=f"[First Message in {channel.mention}]({message.jump_url})")
+ em.set_author(name=message.author.display_name, icon_url=message.author.avatar_url)
+
+ await ctx.send(embed=em)
diff --git a/firstmessage/info.json b/firstmessage/info.json
new file mode 100644
index 0000000..f656d32
--- /dev/null
+++ b/firstmessage/info.json
@@ -0,0 +1,17 @@
+{
+ "author": [
+ "Bobloy"
+ ],
+ "min_bot_version": "3.4.0",
+ "description": "Simple cog to jump to the first message of a channel easily",
+ "hidden": false,
+ "install_msg": "Thank you for installing FirstMessage.\nGet started with `[p]load firstmessage`, then `[p]help FirstMessage`",
+ "short": "Simple cog to jump to first message of a channel",
+ "end_user_data_statement": "This cog does not store any End User Data",
+ "tags": [
+ "bobloy",
+ "utilities",
+ "tool",
+ "tools"
+ ]
+}
\ No newline at end of file
diff --git a/hangman/__init__.py b/hangman/__init__.py
index dbc62e7..35012c4 100644
--- a/hangman/__init__.py
+++ b/hangman/__init__.py
@@ -6,4 +6,3 @@ def setup(bot):
n = Hangman(bot)
data_manager.bundled_data_path(n)
bot.add_cog(n)
- bot.add_listener(n.on_react, "on_reaction_add")
diff --git a/hangman/hangman.py b/hangman/hangman.py
index c7d005d..2b6ab07 100644
--- a/hangman/hangman.py
+++ b/hangman/hangman.py
@@ -50,27 +50,27 @@ class Hangman(Cog):
theface = await self.config.guild(guild).theface()
self.hanglist[guild] = (
""">
- \_________
+ \\_________
|/
|
|
|
|
|
- |\___
+ |\\___
""",
""">
- \_________
+ \\_________
|/ |
|
|
|
|
|
- |\___
+ |\\___
H""",
""">
- \_________
+ \\_________
|/ |
| """
+ theface
@@ -79,10 +79,10 @@ class Hangman(Cog):
|
|
|
- |\___
+ |\\___
HA""",
""">
- \________
+ \\________
|/ |
| """
+ theface
@@ -91,10 +91,10 @@ class Hangman(Cog):
| |
|
|
- |\___
+ |\\___
HAN""",
""">
- \_________
+ \\_________
|/ |
| """
+ theface
@@ -103,43 +103,43 @@ class Hangman(Cog):
| |
|
|
- |\___
+ |\\___
HANG""",
""">
- \_________
+ \\_________
|/ |
| """
+ theface
+ """
- | /|\
+ | /|\\
| |
|
|
- |\___
+ |\\___
HANGM""",
""">
- \________
+ \\________
|/ |
| """
+ theface
+ """
- | /|\
+ | /|\\
| |
| /
|
- |\___
+ |\\___
HANGMA""",
""">
- \________
+ \\________
|/ |
| """
+ theface
+ """
- | /|\
+ | /|\\
| |
- | / \
+ | / \\
|
- |\___
+ |\\___
HANGMAN""",
)
@@ -255,7 +255,7 @@ class Hangman(Cog):
elif i in self.the_data[guild]["guesses"] or i not in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
out_str += "__" + i + "__ "
else:
- out_str += "**\_** "
+ out_str += "**\\_** "
self.winbool[guild] = False
return out_str
@@ -286,10 +286,10 @@ class Hangman(Cog):
await self._reprintgame(message)
- @commands.Cog.listener()
+ @commands.Cog.listener("on_reaction_add")
async def on_react(self, reaction, user: Union[discord.User, discord.Member]):
- """ Thanks to flapjack reactpoll for guidelines
- https://github.com/flapjax/FlapJack-Cogs/blob/master/reactpoll/reactpoll.py"""
+ """Thanks to flapjack reactpoll for guidelines
+ https://github.com/flapjax/FlapJack-Cogs/blob/master/reactpoll/reactpoll.py"""
guild: discord.Guild = getattr(user, "guild", None)
if guild is None:
return
diff --git a/isitdown/__init__.py b/isitdown/__init__.py
new file mode 100644
index 0000000..fdebc2a
--- /dev/null
+++ b/isitdown/__init__.py
@@ -0,0 +1,5 @@
+from .isitdown import IsItDown
+
+
+async def setup(bot):
+ bot.add_cog(IsItDown(bot))
diff --git a/isitdown/info.json b/isitdown/info.json
new file mode 100644
index 0000000..d321732
--- /dev/null
+++ b/isitdown/info.json
@@ -0,0 +1,17 @@
+{
+ "author": [
+ "Bobloy"
+ ],
+ "min_bot_version": "3.4.0",
+ "description": "Check if a website/url is down using the https://isitdown.site/ api",
+ "hidden": false,
+ "install_msg": "Thank you for installing IsItDown.\nGet started with `[p]load isitdown`, then `[p]help IsItDown`",
+ "short": "Check if a website/url is down",
+ "end_user_data_statement": "This cog does not store any End User Data",
+ "tags": [
+ "bobloy",
+ "utilities",
+ "tool",
+ "tools"
+ ]
+}
\ No newline at end of file
diff --git a/isitdown/isitdown.py b/isitdown/isitdown.py
new file mode 100644
index 0000000..f786928
--- /dev/null
+++ b/isitdown/isitdown.py
@@ -0,0 +1,58 @@
+import logging
+import re
+
+import aiohttp
+from redbot.core import Config, commands
+from redbot.core.bot import Red
+
+log = logging.getLogger("red.fox_v3.isitdown")
+
+
+class IsItDown(commands.Cog):
+ """
+ Cog Description
+
+ Less important information about the cog
+ """
+
+ def __init__(self, bot: Red):
+ super().__init__()
+ self.bot = bot
+ self.config = Config.get_conf(self, identifier=0, force_registration=True)
+
+ default_guild = {"iids": []} # List of tuple pairs (channel_id, website)
+
+ self.config.register_guild(**default_guild)
+
+ async def red_delete_data_for_user(self, **kwargs):
+ """Nothing to delete"""
+ return
+
+ @commands.command(alias=["iid"])
+ async def isitdown(self, ctx: commands.Context, url_to_check):
+ """
+ Check if the provided url is down
+
+ Alias: iid
+ """
+ try:
+ resp = await self._check_if_down(url_to_check)
+ except AssertionError:
+ await ctx.maybe_send_embed("Invalid URL provided. Make sure not to include `http://`")
+ return
+
+ if resp["isitdown"]:
+ await ctx.maybe_send_embed(f"{url_to_check} is DOWN!")
+ else:
+ await ctx.maybe_send_embed(f"{url_to_check} is UP!")
+
+ async def _check_if_down(self, url_to_check):
+ url = re.compile(r"https?://(www\.)?")
+ url.sub("", url_to_check).strip().strip("/")
+
+ url = f"https://isitdown.site/api/v3/{url}"
+ async with aiohttp.ClientSession() as session:
+ async with session.get(url) as response:
+ assert response.status == 200
+ resp = await response.json()
+ return resp
diff --git a/launchlib/launchlib.py b/launchlib/launchlib.py
index e34a23d..ae870fd 100644
--- a/launchlib/launchlib.py
+++ b/launchlib/launchlib.py
@@ -22,7 +22,9 @@ class LaunchLib(commands.Cog):
def __init__(self, bot: Red):
super().__init__()
self.bot = bot
- self.config = Config.get_conf(self, identifier=0, force_registration=True)
+ self.config = Config.get_conf(
+ self, identifier=7697117110991047610598, force_registration=True
+ )
default_guild = {}
diff --git a/lseen/lseen.py b/lseen/lseen.py
index a451f57..3348b65 100644
--- a/lseen/lseen.py
+++ b/lseen/lseen.py
@@ -75,9 +75,7 @@ class LastSeen(Cog):
else:
last_seen = await self.config.member(member).seen()
if last_seen is None:
- await ctx.maybe_send_embed(
- embed=discord.Embed(description="I've never seen this user")
- )
+ await ctx.maybe_send_embed("I've never seen this user")
return
last_seen = self.get_date_time(last_seen)
diff --git a/planttycoon/planttycoon.py b/planttycoon/planttycoon.py
index 61e5e06..665fc9a 100644
--- a/planttycoon/planttycoon.py
+++ b/planttycoon/planttycoon.py
@@ -360,7 +360,9 @@ class PlantTycoon(commands.Cog):
``{0}prune``: Prune your plant.\n"""
em = discord.Embed(
- title=title, description=description.format(prefix), color=discord.Color.green(),
+ title=title,
+ description=description.format(prefix),
+ color=discord.Color.green(),
)
em.set_thumbnail(url="https://image.prntscr.com/image/AW7GuFIBSeyEgkR2W3SeiQ.png")
em.set_footer(
@@ -525,7 +527,8 @@ class PlantTycoon(commands.Cog):
if t:
em = discord.Embed(
- title="Plant statistics of {}".format(plant["name"]), color=discord.Color.green(),
+ title="Plant statistics of {}".format(plant["name"]),
+ color=discord.Color.green(),
)
em.set_thumbnail(url=plant["image"])
em.add_field(name="**Name**", value=plant["name"])
@@ -583,7 +586,8 @@ class PlantTycoon(commands.Cog):
author = ctx.author
if product is None:
em = discord.Embed(
- title="All gardening supplies that you can buy:", color=discord.Color.green(),
+ title="All gardening supplies that you can buy:",
+ color=discord.Color.green(),
)
for pd in self.products:
em.add_field(
@@ -616,8 +620,11 @@ class PlantTycoon(commands.Cog):
await gardener.save_gardener()
message = "You bought {}.".format(product.lower())
else:
- message = "You don't have enough Thneeds. You have {}, but need {}.".format(
- gardener.points, self.products[product.lower()]["cost"] * amount,
+ message = (
+ "You don't have enough Thneeds. You have {}, but need {}.".format(
+ gardener.points,
+ self.products[product.lower()]["cost"] * amount,
+ )
)
else:
message = "I don't have this product."
diff --git a/reactrestrict/reactrestrict.py b/reactrestrict/reactrestrict.py
index 4030538..79c3c1c 100644
--- a/reactrestrict/reactrestrict.py
+++ b/reactrestrict/reactrestrict.py
@@ -1,3 +1,4 @@
+import logging
from typing import List, Union
import discord
@@ -5,6 +6,8 @@ from redbot.core import Config, commands
from redbot.core.bot import Red
from redbot.core.commands import Cog
+log = logging.getLogger("red.fox_v3.reactrestrict")
+
class ReactRestrictCombo:
def __init__(self, message_id, role_id):
@@ -131,10 +134,12 @@ class ReactRestrict(Cog):
If no such channel or member can be found.
"""
channel = self.bot.get_channel(channel_id)
+ if channel is None:
+ raise LookupError("no channel found.")
try:
member = channel.guild.get_member(user_id)
except AttributeError as e:
- raise LookupError("No channel found.") from e
+ raise LookupError("No member found.") from e
if member is None:
raise LookupError("No member found.")
@@ -168,7 +173,7 @@ class ReactRestrict(Cog):
"""
channel = self.bot.get_channel(channel_id)
try:
- return await channel.get_message(message_id)
+ return await channel.fetch_message(message_id)
except discord.NotFound:
pass
except AttributeError: # VoiceChannel object has no attribute 'get_message'
@@ -186,9 +191,11 @@ class ReactRestrict(Cog):
:param message_id:
:return:
"""
- for channel in ctx.guild.channels:
+
+ guild: discord.Guild = ctx.guild
+ for channel in guild.text_channels:
try:
- return await channel.get_message(message_id)
+ return await channel.fetch_message(message_id)
except discord.NotFound:
pass
except AttributeError: # VoiceChannel object has no attribute 'get_message'
@@ -232,7 +239,7 @@ class ReactRestrict(Cog):
# noinspection PyTypeChecker
await self.add_reactrestrict(message_id, role)
- await ctx.maybe_send_embed("Message|Role combo added.")
+ await ctx.maybe_send_embed("Message|Role restriction added.")
@reactrestrict.command()
async def remove(self, ctx: commands.Context, message_id: int, role: discord.Role):
@@ -248,37 +255,38 @@ class ReactRestrict(Cog):
# noinspection PyTypeChecker
await self.remove_react(message_id, role)
- await ctx.send("Reaction removed.")
+ await ctx.send("React restriction removed.")
@commands.Cog.listener()
- async def on_raw_reaction_add(
- self, emoji: discord.PartialEmoji, message_id: int, channel_id: int, user_id: int
- ):
+ async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent):
"""
Event handler for long term reaction watching.
-
- :param discord.PartialReactionEmoji emoji:
- :param int message_id:
- :param int channel_id:
- :param int user_id:
- :return:
"""
- if emoji.is_custom_emoji():
- emoji_id = emoji.id
- else:
- emoji_id = emoji.name
+
+ emoji = payload.emoji
+ message_id = payload.message_id
+ channel_id = payload.channel_id
+ user_id = payload.user_id
+
+ # if emoji.is_custom_emoji():
+ # emoji_id = emoji.id
+ # else:
+ # emoji_id = emoji.name
has_reactrestrict, combos = await self.has_reactrestrict_combo(message_id)
if not has_reactrestrict:
+ log.debug("Message not react restricted")
return
try:
member = self._get_member(channel_id, user_id)
except LookupError:
+ log.exception("Unable to get member from guild")
return
if member.bot:
+ log.debug("Won't remove reactions added by bots")
return
if await self.bot.cog_disabled_in_guild(self, member.guild):
@@ -287,14 +295,19 @@ class ReactRestrict(Cog):
try:
roles = [self._get_role(member.guild, c.role_id) for c in combos]
except LookupError:
+ log.exception("Couldn't get approved roles from combos")
return
for apprrole in roles:
if apprrole in member.roles:
+ log.debug("Has approved role")
return
message = await self._get_message_from_channel(channel_id, message_id)
- await message.remove_reaction(emoji, member)
+ try:
+ await message.remove_reaction(emoji, member)
+ except (discord.Forbidden, discord.NotFound, discord.HTTPException):
+ log.exception("Unable to remove reaction")
# try:
# await member.add_roles(*roles)