diff --git a/.gitignore b/.gitignore
index ee64372..9ec1673 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
.idea/
*.pyc
+venv/
+v-data/
+database.sqlite3
diff --git a/README.md b/README.md
index 0bb7fc2..7c516ae 100644
--- a/README.md
+++ b/README.md
@@ -3,21 +3,25 @@
Cog Function
| Name | Status | Description (Click to see full status)
-| --- | --- | --- |
+| --- | --- | --- |
+| announcedaily | **Alpha** | Send daily announcements to all servers at a specified times
Commissioned release, so suggestions will not be accepted |
| ccrole | **Beta** | Create custom commands that also assign roles
May have some bugs, please create an issue if you find any |
| chatter | **Alpha** | Chat-bot trained to talk like your guild
Missing some key features, but currently functional |
| coglint | **Alpha** | Error check code in python syntax posted to discord
Works, but probably needs more turning to work for cogs |
| fight | **Incomplete** | Organize bracket tournaments within discord
Still in-progress, a massive project |
-| flag | **Incomplete** | Create temporary marks on users that expire after specified time
Not yet ported to v3 |
+| 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 | **Alpha** | Play a game of hangman
Some visual glitches and needs more customization |
-| howdoi | **Incomplete** | Create temporary marks on users that expire after specified time
Not yet ported to v3 |
-| leaver | **Incomplete** | Send a message in a channel when a user leaves the server
Not yet ported to v3 |
+| howdoi | **Incomplete** | Ask coding questions and get results from StackExchange
Not yet functional |
+| leaver | **Alpha** | Send a message in a channel when a user leaves the server
Just released, please report bugs |
| lseen | **Alpha** | Track when a member was last online
Alpha release, please report bugs |
| reactrestrict | **Alpha** | Removes reactions by role per channel
A bit clunky, but functional |
| sayurl | **Alpha** | Convert any URL into text and post to discord
No error checking and pretty spammy |
| secrethitler | **Incomplete** | Play the Secret Hitler game
Concept, no work done yet |
| stealemoji | **Alpha** | Steals any custom emoji it sees in a reaction
Some planned upgrades for server generation |
| timerole | **Alpha** | Add roles to members after specified time on the server
Upgraded from V2, please report any bugs |
+| tts | **Alpha** | Send a Text-to-Speech message as an uploaded mp3
Alpha release, please report any bugs |
+| qrinvite | **Alpha** | Create a QR code invite for the server
Alpha release, please report any bugs |
| werewolf | **Alpha** | Play the classic party game Werewolf within discord
Another massive project currently being developed, will be fully customizable |
diff --git a/announcedaily/__init__.py b/announcedaily/__init__.py
new file mode 100644
index 0000000..8cc69d5
--- /dev/null
+++ b/announcedaily/__init__.py
@@ -0,0 +1,9 @@
+from redbot.core.bot import Red
+
+from .announcedaily import AnnounceDaily
+
+
+def setup(bot: Red):
+ daily = AnnounceDaily(bot)
+ bot.add_cog(daily)
+ bot.loop.create_task(daily.check_day())
diff --git a/announcedaily/announcedaily.py b/announcedaily/announcedaily.py
new file mode 100644
index 0000000..17a1bd7
--- /dev/null
+++ b/announcedaily/announcedaily.py
@@ -0,0 +1,250 @@
+import asyncio
+import random
+from datetime import datetime, timedelta
+
+import discord
+from redbot.core import Config, checks, commands
+from redbot.core.bot import Red
+from redbot.core.data_manager import cog_data_path
+from redbot.core.utils.chat_formatting import pagify, box
+
+DEFAULT_MESSAGES = [
+ # "Example message. Uncomment and overwrite to use",
+ # "Example message 2. Each message is in quotes and separated by a comma"
+]
+
+
+class AnnounceDaily:
+ """
+ Send daily announcements
+ """
+
+ def __init__(self, bot: Red):
+ self.bot = bot
+ self.path = str(cog_data_path(self)).replace('\\', '/')
+
+ self.image_path = self.path + "/"
+
+ self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
+ default_global = {
+ 'messages': [],
+ 'images': [],
+ 'time': {'hour': 0, 'minute': 0, 'second': 0}
+ }
+ default_guild = {
+ "channelid": None
+ }
+
+ self.config.register_global(**default_global)
+ self.config.register_guild(**default_guild)
+
+ async def _get_msgs(self):
+ return DEFAULT_MESSAGES + await self.config.messages()
+
+ @commands.group(name="announcedaily", aliases=['annd'])
+ @checks.mod_or_permissions(administrator=True)
+ @commands.guild_only()
+ async def _ad(self, ctx: commands.Context):
+ """
+ Base command for managing AnnounceDaily settings
+
+ Do `[p]help annd ` for more details
+ """
+ if ctx.invoked_subcommand is None:
+ pass
+
+ @commands.command()
+ @checks.guildowner()
+ @commands.guild_only()
+ async def runannounce(self, ctx: commands.Context):
+ """Manually run the daily announcement"""
+
+ await self.send_announcements()
+ await ctx.send("Success")
+
+ @_ad.command()
+ async def setchannel(self, ctx: commands.Context, channel: discord.TextChannel = None):
+ """
+ Set the announcement channel for this server
+
+ Don't pass a channel to clear this server of receiving announcements
+ """
+ if channel is not None:
+ await self.config.guild(ctx.guild).channelid.set(channel.id)
+ await ctx.send("Announcement channel has been set to {}".format(channel.mention))
+ else:
+ await self.config.guild(ctx.guild).channelid.set(None)
+ await ctx.send("Announcement channel has been cleared")
+
+ @_ad.command()
+ async def addmsg(self, ctx: commands.Context, *, msg):
+ """
+ Add a message to the pool of announcement messages
+ """
+ async with self.config.messages() as msgs:
+ msgs.append(msg)
+
+ await ctx.send("Message successfully added!")
+
+ @_ad.command()
+ async def addimg(self, ctx: commands.Context, filename=None):
+ """
+ Add an image to the pool of announcement images
+
+ You must attach an image while executing this command
+ """
+ if ctx.message.attachments:
+ att_ = ctx.message.attachments[0]
+ try:
+ h = att_.height
+ except AttributeError:
+ await ctx.send("You must attach an image, no other file will be accepted")
+ return
+
+ if filename is None:
+ filename = att_.filename
+
+ try:
+ # with open(self.image_path + filename, 'w') as f:
+ # await att_.save(f)
+ await att_.save(self.image_path + filename)
+ except discord.NotFound:
+ await ctx.send("Did you delete the message? Cause I couldn't download the attachment")
+ except discord.HTTPException:
+ await ctx.send("Failed to download the attachment, please try again")
+ else:
+ async with self.config.images() as images:
+ if filename in images:
+ await ctx.send("Image {} has been overwritten!".format(filename))
+ else:
+ images.append(filename)
+ await ctx.send("Image {} has been added!".format(filename))
+ else:
+ await ctx.send("You must attach an image when sending this command")
+
+ @_ad.command()
+ async def listmsg(self, ctx: commands.Context):
+ """
+ List all registered announcement messages
+ """
+ messages = await self.config.messages()
+ for page in pagify("\n".join("{} - {}".format(key, image) for key, image in enumerate(messages))):
+ await ctx.send(box(page))
+ await ctx.send("Done!")
+
+ @_ad.command()
+ async def listimg(self, ctx: commands.Context):
+ """
+ List all registered announcement immages
+ """
+ images = await self.config.images()
+ for page in pagify("\n".join(images)):
+ await ctx.send(box(page))
+ await ctx.send("Done!")
+
+ @_ad.command()
+ async def delmsg(self, ctx: commands.Context, index: int):
+ """
+ Remove a message from the announcement pool
+
+ Must provide the index of the message, which can be found by using `[p]annd listmsg`
+ """
+ async with self.config.messages() as messages:
+ try:
+ out = messages.pop(index)
+ except IndexError:
+ await ctx.send("Invalid index, check valid indexes with `listmsg` command")
+ return
+
+ await ctx.send("The following message was removed:\n```{}```".format(out))
+
+ @_ad.command()
+ async def delimg(self, ctx: commands.Context, filename: str):
+ """
+ Remove an image from the announcement pool
+
+ Does not delete the file from the disk, so you may have to clean it up occasionally
+ """
+ async with self.config.images() as images:
+ if filename not in images:
+ await ctx.send("This file doesn't exist")
+ else:
+ images.remove(filename)
+ await ctx.send("Successfully removed {}".format(filename))
+
+ @_ad.command()
+ async def settime(self, ctx: commands.Context, minutes_from_now: int):
+ """
+ Set the daily announcement time
+
+ It will first announce at the time you provided, then it will repeat every 24 hours
+ """
+ ann_time = datetime.now() + timedelta(minutes=minutes_from_now)
+
+ h = ann_time.hour
+ m = ann_time.minute
+ s = ann_time.second
+ await self.config.time.set({'hour': h, 'minute': m, 'second': s})
+
+ await ctx.send("Announcements time has been set to {}::{}::{} every day\n"
+ "**Changes will apply after next scheduled announcement or reload**".format(h, m, s))
+
+ async def send_announcements(self):
+ messages = await self._get_msgs()
+ images = await self.config.images()
+
+ total = len(messages) + len(images)
+ if total < 1:
+ return
+
+ x = random.randint(0, total - 1)
+
+ if x >= len(messages):
+ x -= len(messages)
+ choice = images[x]
+ choice = open(self.image_path + choice, 'rb')
+ is_image = True
+ else:
+ choice = messages[x]
+ is_image = False
+
+ for guild in self.bot.guilds:
+ channel = await self.config.guild(guild).channelid()
+ if channel is None:
+ continue
+ channel = guild.get_channel(channel)
+ if channel is None:
+ continue
+
+ if is_image:
+ await channel.send(file=discord.File(choice))
+ else:
+ await channel.send(choice)
+
+ async def check_day(self):
+ while self is self.bot.get_cog("AnnounceDaily"):
+ tomorrow = datetime.now() + timedelta(days=1)
+ time = await self.config.time()
+ h, m, s = time['hour'], time['minute'], time['second']
+ midnight = datetime(year=tomorrow.year, month=tomorrow.month,
+ day=tomorrow.day, hour=h, minute=m, second=s)
+
+ print("Sleeping for {} seconds".format((midnight - datetime.now()).seconds))
+ await asyncio.sleep((midnight - datetime.now()).seconds)
+
+ if self is not self.bot.get_cog("AnnounceDaily"):
+ print("Announce canceled, cog has been lost")
+ return
+
+ await self.send_announcements()
+
+ await asyncio.sleep(3)
+
+# [p]setchannel #channelname - Set the announcement channel per server
+# [p]addmsg - Adds a msg to the pool
+# [p]addimg http://imgurl.com/image.jpg - Adds an image to the pool
+# [p]listmsg - Lists all messages in the pool
+# [p]listimg - Unsure about this one, but would probably just post all the images
+# [p]delmsg - Remove msg from pool
+# [p]delimg - Remove image from pool
+# [p]settime - S
diff --git a/announcedaily/info..json b/announcedaily/info..json
new file mode 100644
index 0000000..c2e9ce6
--- /dev/null
+++ b/announcedaily/info..json
@@ -0,0 +1,18 @@
+{
+ "author": [
+ "Bobloy"
+ ],
+ "bot_version": [
+ 3,
+ 0,
+ 0
+ ],
+ "description": "Send daily announcements to all servers at a specified times",
+ "hidden": true,
+ "install_msg": "Thank you for installing AnnounceDaily! Get started with `[p]help AnnounceDaily`",
+ "requirements": [],
+ "short": "Send daily announcements",
+ "tags": [
+ "bobloy"
+ ]
+}
\ No newline at end of file
diff --git a/ccrole/ccrole.py b/ccrole/ccrole.py
index d8c17f6..a92ef2d 100644
--- a/ccrole/ccrole.py
+++ b/ccrole/ccrole.py
@@ -2,7 +2,6 @@ import asyncio
import re
import discord
-
from redbot.core import Config, checks
from redbot.core import commands
from redbot.core.utils.chat_formatting import pagify, box
@@ -30,7 +29,7 @@ class CCRole:
Highly customizable custom commands with role management."""
if not ctx.invoked_subcommand:
- await ctx.send_help()
+ pass
@ccrole.command(name="add")
@checks.mod_or_permissions(administrator=True)
@@ -106,7 +105,7 @@ class CCRole:
return
# Selfrole
- await ctx.send('Is this a targeted command?(yes/no)\nNo will make this a selfrole command')
+ await ctx.send('Is this a targeted command?(yes//no)\nNo will make this a selfrole command')
try:
answer = await self.bot.wait_for('message', timeout=120, check=check)
@@ -191,7 +190,7 @@ class CCRole:
"""Shows custom commands list"""
guild = ctx.guild
cmd_list = await self.config.guild(guild).cmdlist()
- cmd_list = {k: v for k,v in cmd_list.items() if v}
+ cmd_list = {k: v for k, v in cmd_list.items() if v}
if not cmd_list:
await ctx.send(
"There are no custom commands in this server. Use `{}ccrole add` to start adding some.".format(
diff --git a/ccrole/info.json b/ccrole/info.json
index 73a1f79..addc00f 100644
--- a/ccrole/info.json
+++ b/ccrole/info.json
@@ -1,10 +1,22 @@
{
- "author" : ["Bobloy"],
- "bot_version" : [3,0,0],
- "description" : "[Incomplete] Creates custom commands to adjust roles and send custom messages",
- "hidden" : false,
- "install_msg" : "Thank you for installing Custom Commands w/ Roles.",
- "requirements" : [],
- "short" : "[Incomplete] Creates commands that adjust roles",
- "tags" : ["fox", "bobloy", "utility", "tools", "roles"]
+ "author": [
+ "Bobloy"
+ ],
+ "bot_version": [
+ 3,
+ 0,
+ 0
+ ],
+ "description": "[Incomplete] Creates custom commands to adjust roles and send custom messages",
+ "hidden": false,
+ "install_msg": "Thank you for installing Custom Commands w/ Roles.",
+ "requirements": [],
+ "short": "[Incomplete] Creates commands that adjust roles",
+ "tags": [
+ "fox",
+ "bobloy",
+ "utility",
+ "tools",
+ "roles"
+ ]
}
\ No newline at end of file
diff --git a/chatter/chat.py b/chatter/chat.py
index dce136f..0cbd9c4 100644
--- a/chatter/chat.py
+++ b/chatter/chat.py
@@ -1,16 +1,18 @@
import asyncio
+import pathlib
from datetime import datetime, timedelta
import discord
-
from redbot.core import Config
from redbot.core import commands
+from redbot.core.data_manager import cog_data_path
from chatter.chatterbot import ChatBot
+from chatter.chatterbot.comparisons import levenshtein_distance
+from chatter.chatterbot.response_selection import get_first_response
from chatter.chatterbot.trainers import ListTrainer
-
class Chatter:
"""
This cog trains a chatbot that will talk like members of your Guild
@@ -24,11 +26,23 @@ class Chatter:
"whitelist": None,
"days": 1
}
+ path: pathlib.Path = cog_data_path(self)
+ data_path = path / ("database.sqlite3")
self.chatbot = ChatBot(
"ChatterBot",
storage_adapter='chatter.chatterbot.storage.SQLStorageAdapter',
- database='./database.sqlite3'
+ database=str(data_path),
+ statement_comparison_function=levenshtein_distance,
+ response_selection_method=get_first_response,
+ logic_adapters=[
+ 'chatter.chatterbot.logic.BestMatch',
+ {
+ 'import_path': 'chatter.chatterbot.logic.LowConfidenceAdapter',
+ 'threshold': 0.65,
+ 'default_response': ':thinking:'
+ }
+ ]
)
self.chatbot.set_trainer(ListTrainer)
@@ -43,21 +57,42 @@ class Chatter:
Currently takes a stupid long time
Returns a list of text
"""
- out = []
+ out = [[]]
after = datetime.today() - timedelta(days=(await self.config.guild(ctx.guild).days()))
+ def new_message(msg, sent, out_in):
+ if sent is None:
+ return False
+
+ if len(out_in) < 2:
+ return False
+
+ return msg.created_at - sent >= timedelta(hours=3) # This should be configurable perhaps
+
for channel in ctx.guild.text_channels:
if in_channel:
channel = in_channel
await ctx.send("Gathering {}".format(channel.mention))
user = None
+ i = 0
+ send_time = None
try:
+
async for message in channel.history(limit=None, reverse=True, after=after):
+ # if message.author.bot: # Skip bot messages
+ # continue
+ if new_message(message, send_time, out[i]):
+ out.append([])
+ i += 1
+ user = None
+ else:
+ send_time = message.created_at + timedelta(seconds=1)
if user == message.author:
- out[-1] += "\n" + message.clean_content
+ out[i][-1] += "\n" + message.clean_content
else:
user = message.author
- out.append(message.clean_content)
+ out[i].append(message.clean_content)
+
except discord.Forbidden:
pass
except discord.HTTPException:
@@ -70,18 +105,19 @@ class Chatter:
def _train(self, data):
try:
- self.chatbot.train(data)
+ for convo in data:
+ self.chatbot.train(convo)
except:
return False
return True
- @commands.group()
+ @commands.group(invoke_without_command=False)
async def chatter(self, ctx: commands.Context):
"""
Base command for this cog. Check help for the commands list.
"""
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
@chatter.command()
async def age(self, ctx: commands.Context, days: int):
@@ -99,7 +135,8 @@ class Chatter:
Backup your training data to a json for later use
"""
await ctx.send("Backing up data, this may take a while")
- future = await self.loop.run_in_executor(None, self.chatbot.trainer.export_for_training, './{}.json'.format(backupname))
+ future = await self.loop.run_in_executor(None, self.chatbot.trainer.export_for_training,
+ './{}.json'.format(backupname))
if future:
await ctx.send("Backup successful!")
@@ -134,17 +171,21 @@ class Chatter:
else:
await ctx.send("Error occurred :(")
- async def on_message(self, message):
+ async def on_message(self, message: discord.Message):
"""
Credit to https://github.com/Twentysix26/26-Cogs/blob/master/cleverbot/cleverbot.py
for on_message recognition of @bot
"""
author = message.author
- channel = message.channel
+ try:
+ guild: discord.Guild = message.guild
+ except AttributeError: # Not a guild message
+ return
+ channel: discord.TextChannel = message.channel
- if message.author.id != self.bot.user.id:
- to_strip = "@" + author.guild.me.display_name + " "
+ if author.id != self.bot.user.id:
+ to_strip = "@" + guild.me.display_name + " "
text = message.clean_content
if not text.startswith(to_strip):
return
@@ -152,7 +193,7 @@ class Chatter:
async with channel.typing():
future = await self.loop.run_in_executor(None, self.chatbot.get_response, text)
- if future:
+ if future and str(future):
await channel.send(str(future))
else:
await channel.send(':thinking:')
diff --git a/chatter/chatterbot/chatterbot.py b/chatter/chatterbot/chatterbot.py
index c7a92cb..08576c3 100644
--- a/chatter/chatterbot/chatterbot.py
+++ b/chatter/chatterbot/chatterbot.py
@@ -2,10 +2,7 @@ from __future__ import unicode_literals
import logging
-from . import utils
-from .input import InputAdapter
-from .output import OutputAdapter
-from .storage import StorageAdapter
+from chatter.chatterbot import utils
class ChatBot(object):
@@ -14,7 +11,7 @@ class ChatBot(object):
"""
def __init__(self, name, **kwargs):
- from .logic import MultiLogicAdapter
+ from chatter.chatterbot.logic import MultiLogicAdapter
self.name = name
kwargs['name'] = name
@@ -33,9 +30,9 @@ class ChatBot(object):
output_adapter = kwargs.get('output_adapter', 'chatter.chatterbot.output.OutputAdapter')
# Check that each adapter is a valid subclass of it's respective parent
- utils.validate_adapter_class(storage_adapter, StorageAdapter)
- utils.validate_adapter_class(input_adapter, InputAdapter)
- utils.validate_adapter_class(output_adapter, OutputAdapter)
+ # utils.validate_adapter_class(storage_adapter, StorageAdapter)
+ # utils.validate_adapter_class(input_adapter, InputAdapter)
+ # utils.validate_adapter_class(output_adapter, OutputAdapter)
self.logic = MultiLogicAdapter(**kwargs)
self.storage = utils.initialize_class(storage_adapter, **kwargs)
@@ -139,7 +136,7 @@ class ChatBot(object):
"""
Learn that the statement provided is a valid response.
"""
- from .conversation import Response
+ from chatter.chatterbot.conversation import Response
if previous_statement:
statement.add_response(
diff --git a/chatter/chatterbot/comparisons.py b/chatter/chatterbot/comparisons.py
index 59efa95..5e253a0 100644
--- a/chatter/chatterbot/comparisons.py
+++ b/chatter/chatterbot/comparisons.py
@@ -92,7 +92,7 @@ class SynsetDistance(Comparator):
"""
Download required NLTK corpora if they have not already been downloaded.
"""
- from .utils import nltk_download_corpus
+ from chatter.chatterbot.utils import nltk_download_corpus
nltk_download_corpus('corpora/wordnet')
@@ -100,7 +100,7 @@ class SynsetDistance(Comparator):
"""
Download required NLTK corpora if they have not already been downloaded.
"""
- from .utils import nltk_download_corpus
+ from chatter.chatterbot.utils import nltk_download_corpus
nltk_download_corpus('tokenizers/punkt')
@@ -108,7 +108,7 @@ class SynsetDistance(Comparator):
"""
Download required NLTK corpora if they have not already been downloaded.
"""
- from .utils import nltk_download_corpus
+ from chatter.chatterbot.utils import nltk_download_corpus
nltk_download_corpus('corpora/stopwords')
@@ -177,7 +177,7 @@ class SentimentComparison(Comparator):
Download the NLTK vader lexicon for sentiment analysis
that is required for this algorithm to run.
"""
- from .utils import nltk_download_corpus
+ from chatter.chatterbot.utils import nltk_download_corpus
nltk_download_corpus('sentiment/vader_lexicon')
@@ -252,7 +252,7 @@ class JaccardSimilarity(Comparator):
Download the NLTK wordnet corpora that is required for this algorithm
to run only if the corpora has not already been downloaded.
"""
- from .utils import nltk_download_corpus
+ from chatter.chatterbot.utils import nltk_download_corpus
nltk_download_corpus('corpora/wordnet')
diff --git a/chatter/chatterbot/logic/__init__.py b/chatter/chatterbot/logic/__init__.py
index 1930556..8a6cc97 100644
--- a/chatter/chatterbot/logic/__init__.py
+++ b/chatter/chatterbot/logic/__init__.py
@@ -1,5 +1,5 @@
-from .best_match import BestMatch
from .logic_adapter import LogicAdapter
+from .best_match import BestMatch
from .low_confidence import LowConfidenceAdapter
from .mathematical_evaluation import MathematicalEvaluation
from .multi_adapter import MultiLogicAdapter
diff --git a/chatter/chatterbot/logic/best_match.py b/chatter/chatterbot/logic/best_match.py
index 5c48121..f19fc99 100644
--- a/chatter/chatterbot/logic/best_match.py
+++ b/chatter/chatterbot/logic/best_match.py
@@ -1,6 +1,6 @@
from __future__ import unicode_literals
-from .logic_adapter import LogicAdapter
+from chatter.chatterbot.logic import LogicAdapter
class BestMatch(LogicAdapter):
diff --git a/chatter/chatterbot/logic/low_confidence.py b/chatter/chatterbot/logic/low_confidence.py
index 585cf20..2d33bba 100644
--- a/chatter/chatterbot/logic/low_confidence.py
+++ b/chatter/chatterbot/logic/low_confidence.py
@@ -1,7 +1,7 @@
from __future__ import unicode_literals
from chatter.chatterbot.conversation import Statement
-from .best_match import BestMatch
+from chatter.chatterbot.logic import BestMatch
class LowConfidenceAdapter(BestMatch):
diff --git a/chatter/chatterbot/logic/multi_adapter.py b/chatter/chatterbot/logic/multi_adapter.py
index 6cfe30f..5ae79f4 100644
--- a/chatter/chatterbot/logic/multi_adapter.py
+++ b/chatter/chatterbot/logic/multi_adapter.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
from collections import Counter
from chatter.chatterbot import utils
-from .logic_adapter import LogicAdapter
+from chatter.chatterbot.logic import LogicAdapter
class MultiLogicAdapter(LogicAdapter):
diff --git a/chatter/chatterbot/logic/no_knowledge_adapter.py b/chatter/chatterbot/logic/no_knowledge_adapter.py
index 55208b4..848b23e 100644
--- a/chatter/chatterbot/logic/no_knowledge_adapter.py
+++ b/chatter/chatterbot/logic/no_knowledge_adapter.py
@@ -1,6 +1,6 @@
from __future__ import unicode_literals
-from .logic_adapter import LogicAdapter
+from chatter.chatterbot.logic import LogicAdapter
class NoKnowledgeAdapter(LogicAdapter):
diff --git a/chatter/chatterbot/logic/specific_response.py b/chatter/chatterbot/logic/specific_response.py
index 101dd3b..ef7a630 100644
--- a/chatter/chatterbot/logic/specific_response.py
+++ b/chatter/chatterbot/logic/specific_response.py
@@ -1,6 +1,6 @@
from __future__ import unicode_literals
-from .logic_adapter import LogicAdapter
+from chatter.chatterbot.logic import LogicAdapter
class SpecificResponseAdapter(LogicAdapter):
diff --git a/chatter/chatterbot/logic/time_adapter.py b/chatter/chatterbot/logic/time_adapter.py
index 72902e2..d4bbd15 100644
--- a/chatter/chatterbot/logic/time_adapter.py
+++ b/chatter/chatterbot/logic/time_adapter.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
from datetime import datetime
-from .logic_adapter import LogicAdapter
+from chatter.chatterbot.logic import LogicAdapter
class TimeLogicAdapter(LogicAdapter):
diff --git a/chatter/chatterbot/output/__init__.py b/chatter/chatterbot/output/__init__.py
index 80abe4f..52c3534 100644
--- a/chatter/chatterbot/output/__init__.py
+++ b/chatter/chatterbot/output/__init__.py
@@ -1,8 +1,8 @@
+from .output_adapter import OutputAdapter
from .gitter import Gitter
from .hipchat import HipChat
from .mailgun import Mailgun
from .microsoft import Microsoft
-from .output_adapter import OutputAdapter
from .terminal import TerminalAdapter
__all__ = (
diff --git a/chatter/chatterbot/output/gitter.py b/chatter/chatterbot/output/gitter.py
index ba01fa8..664d341 100644
--- a/chatter/chatterbot/output/gitter.py
+++ b/chatter/chatterbot/output/gitter.py
@@ -1,6 +1,6 @@
from __future__ import unicode_literals
-from .output_adapter import OutputAdapter
+from chatter.chatterbot.output import OutputAdapter
class Gitter(OutputAdapter):
diff --git a/chatter/chatterbot/output/hipchat.py b/chatter/chatterbot/output/hipchat.py
index 2546092..20029fa 100644
--- a/chatter/chatterbot/output/hipchat.py
+++ b/chatter/chatterbot/output/hipchat.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
import json
-from .output_adapter import OutputAdapter
+from chatter.chatterbot.output import OutputAdapter
class HipChat(OutputAdapter):
diff --git a/chatter/chatterbot/output/mailgun.py b/chatter/chatterbot/output/mailgun.py
index 71a9a7a..d022a51 100644
--- a/chatter/chatterbot/output/mailgun.py
+++ b/chatter/chatterbot/output/mailgun.py
@@ -1,6 +1,6 @@
from __future__ import unicode_literals
-from .output_adapter import OutputAdapter
+from chatter.chatterbot.output import OutputAdapter
class Mailgun(OutputAdapter):
diff --git a/chatter/chatterbot/output/microsoft.py b/chatter/chatterbot/output/microsoft.py
index 816fc97..4f2426a 100644
--- a/chatter/chatterbot/output/microsoft.py
+++ b/chatter/chatterbot/output/microsoft.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
import json
-from .output_adapter import OutputAdapter
+from chatter.chatterbot.output import OutputAdapter
class Microsoft(OutputAdapter):
diff --git a/chatter/chatterbot/output/terminal.py b/chatter/chatterbot/output/terminal.py
index 8ab63e1..005d0ae 100644
--- a/chatter/chatterbot/output/terminal.py
+++ b/chatter/chatterbot/output/terminal.py
@@ -1,6 +1,6 @@
from __future__ import unicode_literals
-from .output_adapter import OutputAdapter
+from chatter.chatterbot.output import OutputAdapter
class TerminalAdapter(OutputAdapter):
diff --git a/chatter/chatterbot/storage/storage_adapter.py b/chatter/chatterbot/storage/storage_adapter.py
index 046ae63..cf1f45b 100644
--- a/chatter/chatterbot/storage/storage_adapter.py
+++ b/chatter/chatterbot/storage/storage_adapter.py
@@ -158,7 +158,9 @@ class StorageAdapter(object):
class EmptyDatabaseException(Exception):
def __init__(self,
- value='The database currently contains no entries. At least one entry is expected. You may need to train your chat bot to populate your database.'):
+ value='The database currently contains no entries. '
+ 'At least one entry is expected. '
+ 'You may need to train your chat bot to populate your database.'):
self.value = value
def __str__(self):
diff --git a/chatter/chatterbot/trainers.py b/chatter/chatterbot/trainers.py
index 042019e..f3a4165 100644
--- a/chatter/chatterbot/trainers.py
+++ b/chatter/chatterbot/trainers.py
@@ -2,8 +2,8 @@ import logging
import os
import sys
-from . import utils
-from .conversation import Statement, Response
+from chatter.chatterbot import utils
+from chatter.chatterbot.conversation import Statement, Response
class Trainer(object):
@@ -127,7 +127,7 @@ class ChatterBotCorpusTrainer(Trainer):
def __init__(self, storage, **kwargs):
super(ChatterBotCorpusTrainer, self).__init__(storage, **kwargs)
- from .corpus import Corpus
+ from chatter.chatterbot.corpus import Corpus
self.corpus = Corpus()
diff --git a/chatter/chatterbot/utils.py b/chatter/chatterbot/utils.py
index e18549e..9785bd4 100644
--- a/chatter/chatterbot/utils.py
+++ b/chatter/chatterbot/utils.py
@@ -46,7 +46,7 @@ def validate_adapter_class(validate_class, adapter_class):
:raises: Adapter.InvalidAdapterTypeException
"""
- from .adapters import Adapter
+ from chatter.chatterbot.adapters import Adapter
# If a dictionary was passed in, check if it has an import_path attribute
if isinstance(validate_class, dict):
diff --git a/coglint/coglint.py b/coglint/coglint.py
index 10861c7..0c3d045 100644
--- a/coglint/coglint.py
+++ b/coglint/coglint.py
@@ -1,11 +1,8 @@
import discord
-
-from redbot.core import Config, checks
-
-from redbot.core.bot import Red
-
from pylint import epylint as lint
+from redbot.core import Config
from redbot.core import commands
+from redbot.core.bot import Red
from redbot.core.data_manager import cog_data_path
diff --git a/fight/fight.py b/fight/fight.py
index b050de8..efba2ed 100644
--- a/fight/fight.py
+++ b/fight/fight.py
@@ -1,10 +1,11 @@
+import asyncio
import os
import math
# from typing import Union
import discord
-
+from redbot.core import commands
from redbot.core.utils.chat_formatting import pagify
from redbot.core.utils.chat_formatting import box
@@ -102,7 +103,7 @@ class Fight:
await ctx.send("Current tournament ID: " + await self._activefight(ctx))
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
# await ctx.send("I can do stuff!")
@fight.command(name="join")
@@ -198,10 +199,10 @@ class Fight:
async def fadmin(self, ctx):
"""Admin command for managing the current tournament"""
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
@fadmin.command(name="score")
- async def fadmin_score(self, ctx, mID, score1, score2):
+ async def fadmin_score(self, ctx: commands.Context, mID, score1, score2):
"""Set's the score for matchID and clears disputes"""
currFight = await self._getcurrentfight(ctx)
tID = await self._activefight(ctx)
@@ -213,11 +214,11 @@ class Fight:
await ctx.send("Tournament currently not accepting new players")
return
- if await self._infight(ctx, tID, user.id):
+ if await self._infight(ctx, tID, ctx.user.id):
await ctx.send("You are already in this tournament!")
return
- currFight["PLAYERS"].append(user.id)
+ currFight["PLAYERS"].append(ctx.user.id)
await self._save_fight(ctx, tID, currFight)
@@ -256,7 +257,7 @@ class Fight:
# self.save_data()
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
# await ctx.send("I can do stuff!")
@fightset.command(name="emoji")
@@ -548,7 +549,7 @@ class Fight:
async def fightset_guild(self, ctx):
"""Adjust guild wide settings"""
if ctx.invoked_subcommand is None or isinstance(ctx.invoked_subcommand, commands.Group):
- await ctx.send_help()
+ pass
@fightset_guild.command(name="selfreport")
async def fightset_guild_selfreport(self, ctx):
@@ -711,11 +712,13 @@ class Fight:
async def _embed_tourney(self, ctx, tID):
"""Prints a pretty embed of the tournament"""
- await ctx.send("_placeholder Todo")
+ #_placeholder Todo
+ pass
async def _comparescores(self):
"""Checks user submitted scores for inconsistancies"""
- await ctx.send("_comparescores Todo")
+ # _comparescores Todo
+ pass
async def _parseuser(self, guild: discord.Guild, tID, userid):
"""Finds user in the tournament"""
@@ -821,8 +824,8 @@ class Fight:
"""Reports a win for member in match"""
theT = await self._getfight(guild, tID)
- if member.id not in theT["PLAYERS"]: # Shouldn't happen
- return False
+ # if member.id not in theT["PLAYERS"]: # Shouldn't happen
+ # return False
if theT["RULES"]["TYPE"] == 0:
return await self._rr_report_dispute(guild, tID, mID)
@@ -833,13 +836,16 @@ class Fight:
# **********************Single Elimination***************************
async def _elim_setup(self, tID):
- await ctx.send("Elim setup todo")
+ # ToDo Elim setup
+ pass
async def _elim_start(self, tID):
- await ctx.send("Elim start todo")
+ # ToDo Elim start
+ pass
async def _elim_update(self, matchID):
- await ctx.send("Elim update todo")
+ # ToDo Elim update
+ pass
# **********************Round-Robin**********************************
diff --git a/fight/info.json b/fight/info.json
index 8805dad..fabe8ca 100644
--- a/fight/info.json
+++ b/fight/info.json
@@ -2,7 +2,7 @@
"author" : ["Bobloy"],
"bot_version" : [3,0,0],
"description" : "[Incomplete] Cog to organize tournaments within Discord",
- "hidden" : false,
+ "hidden" : true,
"install_msg" : "Thank you for installing Fight. Run with [p]fight or [p]fightset",
"requirements" : [],
"short" : "[Incomplete] Cog to organize tournaments",
diff --git a/flag/__init__.py b/flag/__init__.py
new file mode 100644
index 0000000..0184952
--- /dev/null
+++ b/flag/__init__.py
@@ -0,0 +1,5 @@
+from .flag import Flag
+
+
+def setup(bot):
+ bot.add_cog(Flag(bot))
diff --git a/flag/flag.py b/flag/flag.py
new file mode 100644
index 0000000..1ececf4
--- /dev/null
+++ b/flag/flag.py
@@ -0,0 +1,184 @@
+from datetime import date, timedelta
+
+import discord
+from redbot.core import Config, checks, commands
+from redbot.core.bot import Red
+from redbot.core.utils.chat_formatting import pagify
+
+
+class Flag:
+ """
+ Set expiring flags on members
+ """
+
+ def __init__(self, bot: Red):
+ self.bot = bot
+ self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
+ default_global = {}
+ default_guild = {
+ "days": 31,
+ "dm": True,
+ "flags": {}
+ }
+
+ self.config.register_global(**default_global)
+ self.config.register_guild(**default_guild)
+
+ @checks.is_owner()
+ @commands.command()
+ async def clearallflag(self, ctx: commands.Context):
+ """Clears all flags for all members in this server"""
+
+ await self.config.guild(ctx.guild).flags.clear()
+ await ctx.send("Done")
+
+ @checks.mod_or_permissions(manage_roles=True)
+ @commands.guild_only()
+ @commands.group()
+ async def flagset(self, ctx: commands.Context):
+ """
+ My custom cog
+
+ Extra information goes here
+ """
+ if ctx.invoked_subcommand is None:
+ pass
+
+ @flagset.command(name="expire")
+ async def flagset_expire(self, ctx: commands.Context, days: int):
+ """
+ Set the number of days for flags to expire after for server
+ """
+ await self.config.guild(ctx.guild).days.set(days)
+ await ctx.send("Number of days for new flags to expire is now {} days".format(days))
+
+ @flagset.command(name="dm")
+ async def flagset_dm(self, ctx: commands.Context):
+ """Toggles DM-ing the flags"""
+
+ dm = await self.config.guild(ctx.guild).dm()
+ await self.config.guild(ctx.guild).dm.set(not dm)
+
+ await ctx.send("DM-ing members when they get a flag is now set to **{}**".format(not dm))
+
+ @staticmethod
+ def _flag_template():
+ return {
+ 'reason': "",
+ 'expireyear': 0,
+ 'expiremonth': 0,
+ 'expireday': 0
+ }
+
+ # ************************Flag command group start************************
+ @checks.mod_or_permissions(manage_roles=True)
+ @commands.command()
+ async def flag(self, ctx: commands.Context, member: discord.Member, *, reason):
+ """Flag a member"""
+ guild = ctx.guild
+ await self._check_flags(guild)
+ # clashroyale = self.bot.get_cog('clashroyale')
+ # if clashroyale is None:
+ # await ctx.send("Requires clashroyale cog installed")
+ # return
+
+ flag = self._flag_template()
+ expiredate = date.today()
+ expiredate += timedelta(days=await self.config.guild(guild).days())
+
+ flag['reason'] = reason
+ flag['expireyear'] = expiredate.year
+ flag['expiremonth'] = expiredate.month
+ flag['expireday'] = expiredate.day
+
+ # flags = await self.config.guild(guild).flags.get_raw(str(member.id), default=[])
+ # flags.append(flag)
+ # await self.config.guild(guild).flags.set_raw(str(member.id), value=flags)
+
+ async with self.config.guild(guild).flags() as flags:
+ flags[str(member.id)].append(flag)
+
+ outembed = await self._list_flags(member)
+
+ if outembed:
+ await ctx.send(embed=outembed)
+ if await self.config.guild(guild).dm():
+ await member.send(embed=outembed)
+ else:
+ await ctx.send("This member has no flags.. somehow..")
+
+ @checks.mod_or_permissions(manage_roles=True)
+ @commands.command(pass_context=True, no_pm=True, aliases=['flagclear'])
+ async def clearflag(self, ctx: commands.Context, member: discord.Member):
+ """Clears flags for a member"""
+ guild = ctx.guild
+ await self._check_flags(guild)
+
+ await self.config.guild(guild).flags.set_raw(str(member.id), value=[])
+
+ await ctx.send("Success!")
+
+ @commands.command(pass_context=True, no_pm=True, aliases=['flaglist'])
+ async def listflag(self, ctx: commands.Context, member: discord.Member):
+ """Lists flags for a member"""
+ server = ctx.guild
+ await self._check_flags(server)
+
+ outembed = await self._list_flags(member)
+
+ if outembed:
+ await ctx.send(embed=outembed)
+ else:
+ await ctx.send("This member has no flags!")
+
+ @commands.command(pass_context=True, no_pm=True, aliases=['flagall'])
+ async def allflag(self, ctx: commands.Context):
+ """Lists all flags for the server"""
+ guild = ctx.guild
+ await self._check_flags(guild)
+ out = "All flags for {}\n".format(ctx.guild.name)
+
+ flags = await self.config.guild(guild).flags()
+ flag_d = {}
+ for memberid, flag_data in flags.items():
+ if len(flag_data) > 0:
+ member = guild.get_member(int(memberid))
+ flag_d[member.display_name + member.discriminator] = len(flag_data)
+
+ for display_name, flag_count in sorted(flag_d.items()):
+ out += "{} - **{}** flags".format(display_name, flag_count)
+
+ for page in pagify(out):
+ await ctx.send(page)
+
+ async def _list_flags(self, member: discord.Member):
+ """Returns a pretty embed of flags on a member"""
+ flags = await self.config.guild(member.guild).flags.get_raw(str(member.id), default=[])
+
+ embed = discord.Embed(title="Flags for " + member.display_name,
+ description="User has {} active flags".format(len(flags)), color=0x804040)
+ for flag in flags:
+ embed.add_field(name="Reason: " + flag['reason'],
+ value="Expires on " + str(date(flag['expireyear'], flag['expiremonth'], flag['expireday'])),
+ inline=True)
+
+ embed.set_thumbnail(url=member.avatar_url)
+
+ return embed
+
+ async def _check_flags(self, guild: discord.Guild):
+ """Updates and removes expired flags"""
+ flag_data = await self.config.guild(guild).flags()
+ flag_d = {}
+ for memberid, flags in flag_data.items():
+ # for member in guild.members:
+ # flags = await self.config.guild(guild).flags.get_raw(str(member.id), default=[])
+ x = 0
+ while x < len(flags):
+ flag = flags[x]
+ if date.today() >= date(flag['expireyear'], flag['expiremonth'], flag['expireday']):
+ del flags[x]
+ else:
+ x += 1
+
+ await self.config.guild(guild).flags.set_raw(memberid, value=flags)
diff --git a/flag/info..json b/flag/info..json
new file mode 100644
index 0000000..b5908b9
--- /dev/null
+++ b/flag/info..json
@@ -0,0 +1,23 @@
+{
+ "author": [
+ "Bobloy"
+ ],
+ "bot_version": [
+ 3,
+ 0,
+ 0
+ ],
+ "description": "Add expiring flags on members to track warnings or incidents",
+ "hidden": true,
+ "install_msg": "Thank you for installing Flag! Get started with `[p]help Flag`",
+ "requirements": [],
+ "short": "Add expiring flags to members",
+ "tags": [
+ "bobloy",
+ "warning",
+ "warn",
+ "temp",
+ "tools",
+ "warning"
+ ]
+}
\ No newline at end of file
diff --git a/forcemention/__init__.py b/forcemention/__init__.py
new file mode 100644
index 0000000..a2a8ee7
--- /dev/null
+++ b/forcemention/__init__.py
@@ -0,0 +1,5 @@
+from .forcemention import ForceMention
+
+
+def setup(bot):
+ bot.add_cog(ForceMention(bot))
diff --git a/forcemention/forcemention.py b/forcemention/forcemention.py
new file mode 100644
index 0000000..8086d7d
--- /dev/null
+++ b/forcemention/forcemention.py
@@ -0,0 +1,38 @@
+from discord.utils import get
+
+from redbot.core import Config, checks, commands
+
+from redbot.core.bot import Red
+
+
+class ForceMention:
+ """
+ Mention the unmentionables
+ """
+
+ def __init__(self, bot: Red):
+ self.bot = bot
+ self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
+ default_global = {}
+ default_guild = {}
+
+ self.config.register_global(**default_global)
+ self.config.register_guild(**default_guild)
+
+ @checks.admin_or_permissions(manage_roles=True)
+ @commands.command()
+ async def forcemention(self, ctx: commands.Context, role: str, *, message=''):
+ """
+ Mentions that role, regardless if it's unmentionable
+ """
+ role_obj = get(ctx.guild.roles, name=role)
+ if role_obj is None:
+ await ctx.maybe_send_embed("Couldn't find role named {}".format(role))
+ return
+
+ if not role_obj.mentionable:
+ await role_obj.edit(mentionable=True)
+ await ctx.send("{}\n{}".format(role_obj.mention, message))
+ await role_obj.edit(mentionable=False)
+ else:
+ await ctx.send("{}\n{}".format(role_obj.mention, message))
diff --git a/forcemention/info..json b/forcemention/info..json
new file mode 100644
index 0000000..46810ae
--- /dev/null
+++ b/forcemention/info..json
@@ -0,0 +1,19 @@
+{
+ "author": [
+ "Bobloy"
+ ],
+ "bot_version": [
+ 3,
+ 0,
+ 0
+ ],
+ "description": "Mentions roles that are unmentionable",
+ "hidden": false,
+ "install_msg": "Thank you for installing ForceMention! Get started with `[p]forcemention`",
+ "requirements": [],
+ "short": "Mention unmentionables",
+ "tags": [
+ "bobloy",
+ "utils"
+ ]
+}
\ No newline at end of file
diff --git a/hangman/hangman.py b/hangman/hangman.py
index 6e5dba6..7002e8f 100644
--- a/hangman/hangman.py
+++ b/hangman/hangman.py
@@ -127,7 +127,7 @@ class Hangman:
@checks.mod_or_permissions(administrator=True)
async def hangset(self, ctx):
"""Adjust hangman settings"""
- if not ctx.invoked_subcommand:
+ if ctx.invoked_subcommand is None:
pass
@hangset.command(pass_context=True)
diff --git a/howdoi/howdoi.py b/howdoi/howdoi.py
index 019c014..17fc623 100644
--- a/howdoi/howdoi.py
+++ b/howdoi/howdoi.py
@@ -33,7 +33,7 @@ class Howdoi:
"""Adjust howdoi settings
Settings are reset on reload"""
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
@howdoiset.command(pass_context=True, name="answers")
async def howdoiset_answers(self, ctx, num_answers: int=1):
diff --git a/info.json b/info.json
index 713f4e5..4d8e5e1 100644
--- a/info.json
+++ b/info.json
@@ -1,7 +1,7 @@
{
"AUTHOR": "Bobloy",
- "INSTALL_MSG": "Thank you for installing Fox-Cogs by Bobloy",
- "NAME": "Fox-Cogs",
+ "INSTALL_MSG": "Thank you for installing Fox-V3 by Bobloy",
+ "NAME": "Fox-V3",
"SHORT": "Cogs by Bobloy",
"DESCRIPTION": "Cogs for RED Discord Bot by Bobloy"
}
\ No newline at end of file
diff --git a/leaver/__init__.py b/leaver/__init__.py
new file mode 100644
index 0000000..ed6689b
--- /dev/null
+++ b/leaver/__init__.py
@@ -0,0 +1,5 @@
+from .leaver import Leaver
+
+
+def setup(bot):
+ bot.add_cog(Leaver(bot))
diff --git a/leaver/info.json b/leaver/info.json
index a1a44c3..08bef6f 100644
--- a/leaver/info.json
+++ b/leaver/info.json
@@ -1,9 +1,20 @@
{
- "AUTHOR": "Bobloy",
- "INSTALL_MSG": "Thank you for installing leaver",
- "NAME": "Leaver",
- "SHORT": "Sends message on leave",
- "DESCRIPTION": "Keeps track of when people leave the server, and posts a message notifying",
- "TAGS": ["fox", "bobloy", "utilities", "tools", "tool"],
- "HIDDEN": false
+ "author": [
+ "Bobloy"
+ ],
+ "bot_version": [
+ 3,
+ 0,
+ 0
+ ],
+ "description": "Keeps track of when people leave the server, and posts a message notifying",
+ "hidden": false,
+ "install_msg": "Thank you for installing Leaver. Get started with `[p]help Leaver`",
+ "requirements": [],
+ "short": "Send message on leave",
+ "tags": [
+ "bobloy",
+ "utils",
+ "tools"
+ ]
}
\ No newline at end of file
diff --git a/leaver/leaver.py b/leaver/leaver.py
index 2aff2ac..a9b4a6e 100644
--- a/leaver/leaver.py
+++ b/leaver/leaver.py
@@ -1,78 +1,42 @@
import discord
-import os
-from datetime import datetime
-
-from .utils.dataIO import dataIO
-from .utils import checks
+from redbot.core import Config, checks, commands
+from redbot.core.commands import Context
class Leaver:
- """Creates a goodbye message when people leave"""
+ """
+ Creates a goodbye message when people leave
+ """
def __init__(self, bot):
self.bot = bot
- self.path = "data/Fox-Cogs/leaver"
- self.file_path = "data/Fox-Cogs/leaver/leaver.json"
- self.the_data = dataIO.load_json(self.file_path)
+ self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
+ default_guild = {
+ "channel": ''
+ }
- def save_data(self):
- """Saves the json"""
- dataIO.save_json(self.file_path, self.the_data)
+ self.config.register_guild(**default_guild)
- @commands.group(aliases=['setleaver'], pass_context=True, no_pm=True)
+ @commands.group(aliases=['setleaver'])
@checks.mod_or_permissions(administrator=True)
async def leaverset(self, ctx):
"""Adjust leaver settings"""
-
- server = ctx.message.server
- if server.id not in self.the_data:
- self.the_data[server.id] = {}
- self.save_data()
-
-
if ctx.invoked_subcommand is None:
- await self.bot.send_cmd_help(ctx)
+ pass
- @leaverset.command(pass_context=True, no_pm=True)
- async def channel(self, ctx):
- server = ctx.message.server
- if 'CHANNEL' not in self.the_data[server.id]:
- self.the_data[server.id]['CHANNEL'] = ''
-
+ @leaverset.command()
+ async def channel(self, ctx: Context):
+ guild = ctx.guild
+ await self.config.guild(guild).channel.set(ctx.channel.id)
+ await ctx.send("Channel set to " + ctx.channel.name)
- self.the_data[server.id]['CHANNEL'] = ctx.message.channel.id
- self.save_data()
- await self.bot.say("Channel set to "+ctx.message.channel.name)
+ async def on_member_remove(self, member: discord.Member):
+ guild = member.guild
+ channel = await self.config.guild(guild).channel()
- async def when_leave(self, member):
- server = member.server
- if server.id in self.the_data:
- await self.bot.send_message(server.get_channel(self.the_data[server.id]['CHANNEL']),
- str(member) + "(*" + str(member.nick) +"*) has left the server!")
+ if channel != '':
+ channel = guild.get_channel(channel)
+ await channel.send(str(member) + "(*" + str(member.nick) + "*) has left the server!")
else:
- await self.bot.send_message(server.default_channel.id, str(member) + " (*" + str(member.nick) +"*) has left the server!")
-
-
-def check_folders():
- if not os.path.exists("data/Fox-Cogs"):
- print("Creating data/Fox-Cogs folder...")
- os.makedirs("data/Fox-Cogs")
-
- if not os.path.exists("data/Fox-Cogs/leaver"):
- print("Creating data/Fox-Cogs/leaver folder...")
- os.makedirs("data/Fox-Cogs/leaver")
-
-
-def check_files():
- if not dataIO.is_valid_json("data/Fox-Cogs/leaver/leaver.json"):
- dataIO.save_json("data/Fox-Cogs/leaver/leaver.json", {})
-
-
-def setup(bot):
- check_folders()
- check_files()
- q = Leaver(bot)
- bot.add_listener(q.when_leave, "on_member_remove")
- bot.add_cog(q)
-
\ No newline at end of file
+ pass
diff --git a/lseen/info..json b/lseen/info..json
new file mode 100644
index 0000000..9f69325
--- /dev/null
+++ b/lseen/info..json
@@ -0,0 +1,20 @@
+{
+ "author": [
+ "Bobloy"
+ ],
+ "bot_version": [
+ 3,
+ 0,
+ 0
+ ],
+ "description": "Keep track of when users were last seen online",
+ "hidden": true,
+ "install_msg": "Thank you for installing LastSeen. Get started with `[p]help LastSeen`",
+ "requirements": [],
+ "short": "Last seen tracker",
+ "tags": [
+ "bobloy",
+ "utils",
+ "tools"
+ ]
+}
\ No newline at end of file
diff --git a/lseen/lseen.py b/lseen/lseen.py
index 43c56ea..7693385 100644
--- a/lseen/lseen.py
+++ b/lseen/lseen.py
@@ -10,7 +10,7 @@ from redbot.core import commands
class LastSeen:
"""
- V3 Cog Template
+ Report when a user was last seen online
"""
online_status = discord.Status.online
@@ -41,7 +41,7 @@ class LastSeen:
async def lset(self, ctx: commands.Context):
"""Change settings for lseen"""
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
@lset.command(name="toggle")
async def lset_toggle(self, ctx: commands.Context):
@@ -58,8 +58,6 @@ class LastSeen:
async def lseen(self, ctx: commands.Context, member: discord.Member):
"""
Just says the time the user was last seen
-
- :param member:
"""
if member.status != self.offline_status:
diff --git a/nudity/__init__.py b/nudity/__init__.py
new file mode 100644
index 0000000..7d32df6
--- /dev/null
+++ b/nudity/__init__.py
@@ -0,0 +1,5 @@
+from .nudity import Nudity
+
+
+def setup(bot):
+ bot.add_cog(Nudity(bot))
diff --git a/nudity/info..json b/nudity/info..json
new file mode 100644
index 0000000..4384930
--- /dev/null
+++ b/nudity/info..json
@@ -0,0 +1,20 @@
+{
+ "author": [
+ "Bobloy"
+ ],
+ "bot_version": [
+ 3,
+ 0,
+ 0
+ ],
+ "description": "Keep track of when users were last seen online",
+ "hidden": true,
+ "install_msg": "Thank you for installing LastSeen. Get started with `[p]help LastSeen`",
+ "requirements": ["nudepy"],
+ "short": "Last seen tracker",
+ "tags": [
+ "bobloy",
+ "utils",
+ "tools"
+ ]
+}
\ No newline at end of file
diff --git a/nudity/nudity.py b/nudity/nudity.py
new file mode 100644
index 0000000..be30ee4
--- /dev/null
+++ b/nudity/nudity.py
@@ -0,0 +1,45 @@
+from datetime import datetime
+
+import discord
+import nude
+from nude import Nude
+from redbot.core import Config
+from redbot.core import commands
+from redbot.core.bot import Red
+
+
+class Nudity:
+ """
+ V3 Cog Template
+ """
+
+ online_status = discord.Status.online
+
+ offline_status = discord.Status.offline
+
+ def __init__(self, bot: Red):
+ self.bot = bot
+ self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
+
+ default_guild = {
+ "enabled": False
+ }
+
+ self.config.register_guild(**default_guild)
+
+ @commands.command(aliases=['togglenudity'], name='nudity')
+ async def nudity(self, ctx: commands.Context):
+ """Toggle nude-checking on or off"""
+ is_on = await self.config.guild(ctx.guild).enabled()
+ await self.config.guild(ctx.guild).enabled.set(not is_on)
+ await ctx.send("Nude checking is now set to {}".format(not is_on))
+
+ async def on_message(self, message: discord.Message):
+ is_on = await self.config.guild(message.guild).enabled()
+ if not is_on:
+ return
+
+ if not message.attachments:
+ return
+
+
diff --git a/qrinvite/__init__.py b/qrinvite/__init__.py
new file mode 100644
index 0000000..a91023a
--- /dev/null
+++ b/qrinvite/__init__.py
@@ -0,0 +1,5 @@
+from .qrinvite import QRInvite
+
+
+def setup(bot):
+ bot.add_cog(QRInvite(bot))
diff --git a/qrinvite/info..json b/qrinvite/info..json
new file mode 100644
index 0000000..3015652
--- /dev/null
+++ b/qrinvite/info..json
@@ -0,0 +1,23 @@
+{
+ "author": [
+ "Bobloy"
+ ],
+ "bot_version": [
+ 3,
+ 0,
+ 0
+ ],
+ "description": "Create a QR code invite for the server",
+ "hidden": true,
+ "install_msg": "Thank you for installing QRInvite! Get started with `[p]help QRInvite`",
+ "requirements": [
+ "MyQR"
+ ],
+ "short": "Create a QR code invite",
+ "tags": [
+ "bobloy",
+ "tools",
+ "qr",
+ "code"
+ ]
+}
\ No newline at end of file
diff --git a/qrinvite/qrinvite.py b/qrinvite/qrinvite.py
new file mode 100644
index 0000000..4180bb4
--- /dev/null
+++ b/qrinvite/qrinvite.py
@@ -0,0 +1,81 @@
+import pathlib
+
+import aiohttp
+import discord
+from PIL import Image
+
+from redbot.core import Config, checks, commands
+
+from redbot.core.bot import Red
+
+from MyQR import myqr
+from redbot.core.data_manager import cog_data_path
+
+
+class QRInvite:
+ """
+ V3 Cog Template
+ """
+
+ def __init__(self, bot: Red):
+ self.bot = bot
+ self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
+ default_global = {}
+ default_guild = {}
+
+ self.config.register_global(**default_global)
+ self.config.register_guild(**default_guild)
+
+ @commands.command()
+ async def qrinvite(self, ctx: commands.Context, invite: str=None, colorized: bool=False, image_url: str=None):
+ """
+ Create a custom QR code invite for this server
+ """
+ if invite is None:
+ try:
+ invite = await ctx.channel.create_invite()
+ except discord.Forbidden:
+ try:
+ invite = await ctx.channel.invites()
+ invite = invite[0]
+ except discord.Forbidden:
+ await ctx.send("No permission to get an invite, please provide one")
+ return
+ invite = invite.code
+
+ if image_url is None:
+ image_url = ctx.guild.icon_url
+
+ extension = pathlib.Path(image_url).parts[-1].replace('.','?').split('?')[1]
+
+ path: pathlib.Path = cog_data_path(self)
+ image_path = path / (ctx.guild.icon+"."+extension)
+ async with aiohttp.ClientSession() as session:
+ async with session.get(image_url) as response:
+ image = await response.read()
+
+ with image_path.open("wb") as file:
+ file.write(image)
+
+ if extension == "webp":
+ new_path = convert_png(str(image_path))
+ else:
+ new_path = str(image_path)
+
+ myqr.run(invite,picture=new_path,save_name=ctx.guild.icon+"_qrcode.png",
+ save_dir=str(cog_data_path(self)),colorized=colorized,)
+
+ png_path: pathlib.Path = path / (ctx.guild.icon+"_qrcode.png")
+ with png_path.open("rb") as png_fp:
+ await ctx.send(file=discord.File(png_fp.read(), "qrcode.png"))
+
+def convert_png(path):
+ im = Image.open(path)
+ im.load()
+ alpha = im.split()[-1]
+ im = im.convert('RGB').convert('P', palette=Image.ADAPTIVE, colors=255)
+ mask = Image.eval(alpha, lambda a: 255 if a <=128 else 0)
+ im.paste(255, mask)
+ newPath = path.replace(".webp",".png")
+ im.save(newPath, transparency=255)
+ return newPath
\ No newline at end of file
diff --git a/reactrestrict/reactrestrict.py b/reactrestrict/reactrestrict.py
index 87b50a3..f1bb2c3 100644
--- a/reactrestrict/reactrestrict.py
+++ b/reactrestrict/reactrestrict.py
@@ -1,12 +1,9 @@
-import asyncio
from typing import List, Union
import discord
-
-
from redbot.core import Config
-from redbot.core.bot import Red
from redbot.core import commands
+from redbot.core.bot import Red
class ReactRestrictCombo:
@@ -16,8 +13,8 @@ class ReactRestrictCombo:
def __eq__(self, other: "ReactRestrictCombo"):
return (
- self.message_id == other.message_id and
- self.role_id == other.role_id
+ self.message_id == other.message_id and
+ self.role_id == other.role_id
)
def to_json(self):
@@ -83,7 +80,7 @@ class ReactRestrict:
"""
# is_custom = True
# if isinstance(emoji, str):
- # is_custom = False
+ # is_custom = False
combo = ReactRestrictCombo(message_id, role.id)
@@ -95,10 +92,10 @@ class ReactRestrict:
async def remove_react(self, message_id: int, role: discord.Role):
"""
- Removes a given reaction.
+ Removes a given reaction
- :param int message_id:
- :param str or int emoji:
+ :param message_id:
+ :param role:
:return:
"""
current_combos = await self.combo_list()
@@ -109,14 +106,13 @@ class ReactRestrict:
if to_keep != current_combos:
await self.set_combo_list(to_keep)
- async def has_reactrestrict_combo(self, message_id: int)\
+ async def has_reactrestrict_combo(self, message_id: int) \
-> (bool, List[ReactRestrictCombo]):
"""
- Determines if there is an existing role combo for a given message
+ Determines if there is an existing role combo for a given message
and emoji ID.
- :param int message_id:
- :param str or int emoji:
+ :param message_id:
:return:
"""
if not await self.is_registered(message_id):
@@ -169,8 +165,8 @@ class ReactRestrict:
raise LookupError("No role found.")
return role
-
- async def _get_message_from_channel(self, channel_id: int, message_id: int)\
+
+ async def _get_message_from_channel(self, channel_id: int, message_id: int) \
-> Union[discord.Message, None]:
"""
Tries to find a message by ID in the current guild context.
@@ -180,12 +176,12 @@ class ReactRestrict:
return await channel.get_message(message_id)
except discord.NotFound:
pass
- except AttributeError: # VoiceChannel object has no attribute 'get_message'
+ except AttributeError: # VoiceChannel object has no attribute 'get_message'
pass
return None
-
- async def _get_message(self, ctx: commands.Context, message_id: int)\
+
+ async def _get_message(self, ctx: commands.Context, message_id: int) \
-> Union[discord.Message, None]:
"""
Tries to find a message by ID in the current guild context.
@@ -199,12 +195,10 @@ class ReactRestrict:
return await channel.get_message(message_id)
except discord.NotFound:
pass
- except AttributeError: # VoiceChannel object has no attribute 'get_message'
+ except AttributeError: # VoiceChannel object has no attribute 'get_message'
pass
except discord.Forbidden: # No access to channel, skip
pass
-
-
return None
@@ -214,7 +208,7 @@ class ReactRestrict:
Base command for this cog. Check help for the commands list.
"""
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
@reactrestrict.command()
async def add(self, ctx: commands.Context, message_id: int, *, role: discord.Role):
@@ -228,18 +222,18 @@ class ReactRestrict:
return
# try:
- # emoji, actual_emoji = await self._wait_for_emoji(ctx)
+ # emoji, actual_emoji = await self._wait_for_emoji(ctx)
# except asyncio.TimeoutError:
- # await ctx.send("You didn't respond in time, please redo this command.")
- # return
-
+ # await ctx.send("You didn't respond in time, please redo this command.")
+ # return
+ #
# try:
- # await message.add_reaction(actual_emoji)
+ # await message.add_reaction(actual_emoji)
# except discord.HTTPException:
- # await ctx.send("I can't add that emoji because I'm not in the guild that"
- # " owns it.")
- # return
-
+ # await ctx.send("I can't add that emoji because I'm not in the guild that"
+ # " owns it.")
+ # return
+ #
# noinspection PyTypeChecker
await self.add_reactrestrict(message_id, role)
@@ -251,10 +245,10 @@ class ReactRestrict:
Removes role associated with a given reaction.
"""
# try:
- # emoji, actual_emoji = await self._wait_for_emoji(ctx)
+ # emoji, actual_emoji = await self._wait_for_emoji(ctx)
# except asyncio.TimeoutError:
- # await ctx.send("You didn't respond in time, please redo this command.")
- # return
+ # await ctx.send("You didn't respond in time, please redo this command.")
+ # return
# noinspection PyTypeChecker
await self.remove_react(message_id, role)
@@ -298,50 +292,50 @@ class ReactRestrict:
for apprrole in roles:
if apprrole in member.roles:
return
-
+
message = await self._get_message_from_channel(channel_id, message_id)
await message.remove_reaction(emoji, member)
-
- # try:
- # await member.add_roles(*roles)
- # except discord.Forbidden:
- # pass
+ # try:
+ # await member.add_roles(*roles)
+ # except discord.Forbidden:
+ # pass
+ #
# async def on_raw_reaction_remove(self, emoji: discord.PartialReactionEmoji,
- # message_id: int, channel_id: int, user_id: int):
- # """
- # 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
-
- # has_reactrestrict, combos = await self.has_reactrestrict_combo(message_id, emoji_id)
-
- # if not has_reactrestrict:
- # return
-
- # try:
- # member = self._get_member(channel_id, user_id)
- # except LookupError:
- # return
-
- # if member.bot:
- # return
-
- # try:
- # roles = [self._get_role(member.guild, c.role_id) for c in combos]
- # except LookupError:
- # return
-
- # try:
- # await member.remove_roles(*roles)
- # except discord.Forbidden:
- # pass
+ # message_id: int, channel_id: int, user_id: int):
+ # """
+ # 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
+ #
+ # has_reactrestrict, combos = await self.has_reactrestrict_combo(message_id, emoji_id)
+ #
+ # if not has_reactrestrict:
+ # return
+ #
+ # try:
+ # member = self._get_member(channel_id, user_id)
+ # except LookupError:
+ # return
+ #
+ # if member.bot:
+ # return
+ #
+ # try:
+ # roles = [self._get_role(member.guild, c.role_id) for c in combos]
+ # except LookupError:
+ # return
+ #
+ # try:
+ # await member.remove_roles(*roles)
+ # except discord.Forbidden:
+ # pass
diff --git a/sayurl/sayurl.py b/sayurl/sayurl.py
index c536b41..04499cd 100644
--- a/sayurl/sayurl.py
+++ b/sayurl/sayurl.py
@@ -1,7 +1,7 @@
import aiohttp
import html2text
-from redbot.core import Config
+from redbot.core import Config, commands
from redbot.core.bot import Red
from redbot.core.utils.chat_formatting import pagify
@@ -32,8 +32,7 @@ class SayUrl:
"""
Converts a URL to something readable
- :param url:
- :return:
+ Works better on smaller websites
"""
h = html2text.HTML2Text()
diff --git a/secrethitler/secrethitler.py b/secrethitler/secrethitler.py
index edee4d0..2f9360b 100644
--- a/secrethitler/secrethitler.py
+++ b/secrethitler/secrethitler.py
@@ -3,7 +3,7 @@ import asyncio
import discord
-from redbot.core import Config
+from redbot.core import Config, commands
from datetime import datetime, timedelta
@@ -33,7 +33,7 @@ class Werewolf:
Base command for this cog. Check help for the commands list.
"""
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
@ww.command()
async def new(self, ctx, game_code):
diff --git a/stealemoji/stealemoji.py b/stealemoji/stealemoji.py
index a55d2c9..05dd961 100644
--- a/stealemoji/stealemoji.py
+++ b/stealemoji/stealemoji.py
@@ -45,7 +45,7 @@ class StealEmoji:
Base command for this cog. Check help for the commands list.
"""
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
@stealemoji.command(name="collect")
async def se_collect(self, ctx):
@@ -58,7 +58,7 @@ class StealEmoji:
async def se_bank(self, ctx):
"""Add current server as emoji bank"""
await ctx.send("This will upload custom emojis to this server\n"
- "Are you sure you want to make the current server an emoji bank? (y/n)")
+ "Are you sure you want to make the current server an emoji bank? (y//n)")
def check(m):
return m.content.upper() in ["Y", "YES", "N", "NO"] and m.channel == ctx.channel and m.author == ctx.author
diff --git a/timerole/timerole.py b/timerole/timerole.py
index fb2fff2..25a7c1b 100644
--- a/timerole/timerole.py
+++ b/timerole/timerole.py
@@ -37,7 +37,7 @@ class Timerole:
async def timerole(self, ctx):
"""Adjust timerole settings"""
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
@timerole.command()
async def addrole(self, ctx: commands.Context, role: discord.Role, days: int, *requiredroles: discord.Role):
diff --git a/tts/__init__.py b/tts/__init__.py
new file mode 100644
index 0000000..47959b8
--- /dev/null
+++ b/tts/__init__.py
@@ -0,0 +1,5 @@
+from .tts import TTS
+
+
+def setup(bot):
+ bot.add_cog(TTS(bot))
diff --git a/tts/info..json b/tts/info..json
new file mode 100644
index 0000000..babe7fc
--- /dev/null
+++ b/tts/info..json
@@ -0,0 +1,22 @@
+{
+ "author": [
+ "Bobloy"
+ ],
+ "bot_version": [
+ 3,
+ 0,
+ 0
+ ],
+ "description": "Send Text2Speech messages as an uploaded mp3",
+ "hidden": true,
+ "install_msg": "Thank you for installing TTS. Get started with `[p]tts`",
+ "requirements": [
+ "gTTS"
+ ],
+ "short": "Send TTS messages as uploaded mp3",
+ "tags": [
+ "bobloy",
+ "utils",
+ "audio"
+ ]
+}
\ No newline at end of file
diff --git a/tts/tts.py b/tts/tts.py
new file mode 100644
index 0000000..dcae0be
--- /dev/null
+++ b/tts/tts.py
@@ -0,0 +1,34 @@
+import io
+
+import discord
+from gtts import gTTS
+from redbot.core import Config, commands
+from redbot.core.bot import Red
+
+
+class TTS:
+ """
+ V3 Cog Template
+ """
+
+ def __init__(self, bot: Red):
+ self.bot = bot
+
+ self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
+ default_global = {}
+ default_guild = {}
+
+ self.config.register_global(**default_global)
+ self.config.register_guild(**default_guild)
+
+ @commands.command(aliases=["t2s", "text2"])
+ async def tts(self, ctx: commands.Context, *, text: str):
+ """
+ My custom cog
+
+ Extra information goes here
+ """
+ mp3_fp = io.BytesIO()
+ tts = gTTS(text, 'en')
+ tts.write_to_fp(mp3_fp)
+ await ctx.send(file=discord.File(mp3_fp.getvalue(), "text.mp3"))
diff --git a/werewolf/builder.py b/werewolf/builder.py
index 28b22ea..48e7e71 100644
--- a/werewolf/builder.py
+++ b/werewolf/builder.py
@@ -120,8 +120,6 @@ async def parse_code(code, game):
digits += 1
continue
-
-
try:
idx = int(built)
except ValueError:
@@ -146,7 +144,6 @@ async def parse_code(code, game):
built = ""
-
return decode
diff --git a/werewolf/player.py b/werewolf/player.py
index d1f9359..c84d87f 100644
--- a/werewolf/player.py
+++ b/werewolf/player.py
@@ -30,4 +30,4 @@ class Player:
try:
await self.member.send(message) # Lets do embeds later
except discord.Forbidden:
- await self.role.game.village_channel.send("Couldn't DM {}, uh oh".format(self.mention))
\ No newline at end of file
+ await self.role.game.village_channel.send("Couldn't DM {}, uh oh".format(self.mention))
diff --git a/werewolf/roles/seer.py b/werewolf/roles/seer.py
index b005b9a..5c58250 100644
--- a/werewolf/roles/seer.py
+++ b/werewolf/roles/seer.py
@@ -16,7 +16,6 @@ class Seer(Role):
description = "A mystic in search of answers in a chaotic town.\n" \
"Calls upon the cosmos to discern those of Lycan blood"
-
def __init__(self, game):
super().__init__(game)
# self.game = game
diff --git a/werewolf/werewolf.py b/werewolf/werewolf.py
index e312312..59c18c6 100644
--- a/werewolf/werewolf.py
+++ b/werewolf/werewolf.py
@@ -53,7 +53,7 @@ class Werewolf:
Base command to adjust settings. Check help for command list.
"""
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
@commands.guild_only()
@wwset.command(name="list")
@@ -136,7 +136,7 @@ class Werewolf:
Base command for this cog. Check help for the commands list.
"""
if ctx.invoked_subcommand is None:
- await ctx.send_help()
+ pass
@commands.guild_only()
@ww.command(name="new")