Merge branch 'master' into fifo_develop
This commit is contained in:
commit
bed6cf8bb7
@ -14,11 +14,13 @@ Cog Function
|
||||
| exclusiverole | **Alpha** | <details><summary>Prevent certain roles from getting any other roles</summary>Fully functional, but pretty simple</details> |
|
||||
| fifo | **Alpha** | <details><summary>Schedule commands to be run at certain times or intervals</summary>Just released, please report bugs as you find them. Only works for bot owner for now</details> |
|
||||
| fight | **Incomplete** | <details><summary>Organize bracket tournaments within discord</summary>Still in-progress, a massive project</details> |
|
||||
| firstmessage | **Release** | <details><summary>Simple cog to provide a jump link to the first message in a channel/summary>Just released, please report bugs as you find them.</details> |
|
||||
| flag | **Alpha** | <details><summary>Create temporary marks on users that expire after specified time</summary>Ported, will not import old data. Please report bugs</details> |
|
||||
| forcemention | **Alpha** | <details><summary>Mentions unmentionable roles</summary>Very simple cog, mention doesn't persist</details> |
|
||||
| hangman | **Beta** | <details><summary>Play a game of hangman</summary>Some visual glitches and needs more customization</details> |
|
||||
| howdoi | **Incomplete** | <details><summary>Ask coding questions and get results from StackExchange</summary>Not yet functional</details> |
|
||||
| infochannel | **Beta** | <details><summary>Create a channel to display server info</summary>Just released, please report bugs</details> |
|
||||
| infochannel | **Beta** | <details><summary>Create a channel to display server info</summary>Due to rate limits, this does not update as often as it once did</details> |
|
||||
| isitdown | **Beta** | <details><summary>Check if a website/url is down</summary>Just released, please report bugs</details> |
|
||||
| launchlib | **Beta** | <details><summary>Access rocket launch data</summary>Just released, please report bugs</details> |
|
||||
| leaver | **Beta** | <details><summary>Send a message in a channel when a user leaves the server</summary>Seems to be functional, please report any bugs or suggestions</details> |
|
||||
| lovecalculator | **Alpha** | <details><summary>Calculate the love between two users</summary>[Snap-Ons] Just updated to V3</details> |
|
||||
@ -38,7 +40,7 @@ Cog Function
|
||||
| unicode | **Alpha** | <details><summary>Encode and Decode unicode characters</summary>[Snap-Ons] Just updated to V3</details> |
|
||||
| werewolf | **Pre-Alpha** | <details><summary>Play the classic party game Werewolf within discord</summary>Another massive project currently being developed, will be fully customizable</details> |
|
||||
|
||||
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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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")
|
||||
|
@ -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 <Fox> Chatter
|
||||
```
|
||||
|
||||
#### Step 2: Install Requirements
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
"bobloy",
|
||||
"utilities",
|
||||
"tool",
|
||||
"tools",
|
||||
"roles",
|
||||
"schedule",
|
||||
"cron",
|
||||
|
5
firstmessage/__init__.py
Normal file
5
firstmessage/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
from .firstmessage import FirstMessage
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
bot.add_cog(FirstMessage(bot))
|
49
firstmessage/firstmessage.py
Normal file
49
firstmessage/firstmessage.py
Normal file
@ -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)
|
17
firstmessage/info.json
Normal file
17
firstmessage/info.json
Normal file
@ -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"
|
||||
]
|
||||
}
|
@ -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")
|
||||
|
@ -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
|
||||
|
5
isitdown/__init__.py
Normal file
5
isitdown/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
from .isitdown import IsItDown
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
bot.add_cog(IsItDown(bot))
|
17
isitdown/info.json
Normal file
17
isitdown/info.json
Normal file
@ -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"
|
||||
]
|
||||
}
|
58
isitdown/isitdown.py
Normal file
58
isitdown/isitdown.py
Normal file
@ -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
|
@ -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 = {}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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."
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user