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): | ||||
| @ -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,6 +307,10 @@ class FIFO(commands.Cog): | ||||
|                 out += f"{task_name}: {task_data}\n" | ||||
| 
 | ||||
|             if 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,7 +286,7 @@ 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""" | ||||
|  | ||||
							
								
								
									
										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) | ||||
|         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
	 bobloy
						bobloy