Compare commits

...

52 Commits

Author SHA1 Message Date
WTMike24 0aaffbf5f0 Added quick and dirty escape to asterisks.
3 years ago
bobloy 771d1457e5 Bump to latest version of Chatterbot
3 years ago
bobloy d191abf6bd Only update if it's enabled (not all keys)
3 years ago
bobloy aba9840bcb Less verbose debug
3 years ago
bobloy 0064e6e9b5 More verbose debug mode
3 years ago
bobloy 955624ad1a Use greedy converter, no more commas
3 years ago
bobloy a6e0646b85
Merge pull request #186 from ScaredDonut/master
4 years ago
bobloy 269266ce04
Merge pull request #189 from aleclol/master
4 years ago
bobloy db3ce30122 Add back embed description, now required by discord
4 years ago
bobloy 1e87eacf83 Add edited timestamp
4 years ago
bobloy 61fa006e33 QoL fixes
4 years ago
bobloy 4183607372 Add option for skipping bots
4 years ago
bobloy 2421c4e9bf Add sm and md to requirements
4 years ago
bobloy b2e843e781 Invalid timestring instead of error
4 years ago
aleclol a7ce815e14
Merge branch 'bobloy:master' into master
4 years ago
bobloy 1e535c2f3e
Merge pull request #193 from XargsUK/master
4 years ago
bobloy fd80819618 Merge branch 'master' into XargsUK_master
4 years ago
bobloy a5ff888f4c black reformat
4 years ago
bobloy 3eb499bf0e black reformat
4 years ago
bobloy 698dafade4 Add chatter initialization
4 years ago
Brad Duncan 15ecf72c64 Update recyclingplant.py
4 years ago
Brad Duncan 1d514f80c6 adding no response exit condition
4 years ago
bobloy b752bfd153 Stop looking at DMs
4 years ago
bobloy 47269ba8f4 fix has_table, move age and minutes to trainset
4 years ago
bobloy e0a361b952 remove en_core_web_sm as dependency
4 years ago
bobloy 2a18760a83
Merge pull request #191 from bobloy/chatter_fox
4 years ago
bobloy b26afdf2db Merge branch 'master' into chatter_fox
4 years ago
bobloy 86cc1fa35a Don't specify pyaml
4 years ago
aleclol b331238c1c
Move .get_text() to after None check
4 years ago
bobloy 6f0c88b1ac change default models, fix requirements
4 years ago
bobloy c165313031 no reply errors in cache
4 years ago
bobloy 9c63c12656 Don't need requirements file
4 years ago
bobloy a55ae8a511 Use Bobloy's chatterbot fork
4 years ago
Alexander Soloviev 1ffac638ed Update infochannel.py
4 years ago
Alexander Soloviev 5b75002c88 Update infochannel.py
4 years ago
Alexander Soloviev 7c08a5de0c Update infochannel.py
4 years ago
bobloy bc12aa866e Fix formatting
4 years ago
bobloy dbafd6ffd7
Merge pull request #183 from aleclol/master
4 years ago
aleclol 52ca2f6a45
Update lovecalculator.py
4 years ago
bobloy 2937b6ac92 List of dicts
4 years ago
bobloy dbf84c8b81
Merge pull request #180 from phenom4n4n/patch-1
4 years ago
PhenoM4n4n 2f21de6a97 lovecalc attributeerror
4 years ago
bobloy ed6cc433c8 Remove pycountry
4 years ago
bobloy e1a30359d8
Merge pull request #148 from BogdanWDK/master
4 years ago
bobloy 506a79c6d6 Removing debugging print
4 years ago
bobloy 1ddcd98078 Implement languages
4 years ago
bobloy 7bd004c78e Merge branch 'master' into BogdanWDK_master
4 years ago
bobloy 184833421a
Merge pull request #178 from Kreusada/patch-1
4 years ago
Kreusada f04ff6886b
[SCP] Remove double setup
4 years ago
bobloy 28edcc1fdd deliminate on space not newline
4 years ago
bobloy 10ed1f9b9f pagify lots of stolen emojis
4 years ago
BogdanWDK 960b66a5b8 Language Support Added
4 years ago

@ -3,6 +3,7 @@ import logging
import re
import discord
from discord.ext.commands import RoleConverter, Greedy, CommandError, ArgumentParsingError
from discord.ext.commands.view import StringView
from redbot.core import Config, checks, commands
from redbot.core.bot import Red
@ -13,15 +14,38 @@ log = logging.getLogger("red.fox_v3.ccrole")
async def _get_roles_from_content(ctx, content):
content_list = content.split(",")
# greedy = Greedy[RoleConverter]
view = StringView(content)
rc = RoleConverter()
# "Borrowed" from discord.ext.commands.Command._transform_greedy_pos
result = []
while not view.eof:
# for use with a manual undo
previous = view.index
view.skip_ws()
try:
role_list = [
discord.utils.get(ctx.guild.roles, name=role.strip(" ")).id for role in content_list
]
except (discord.HTTPException, AttributeError): # None.id is attribute error
return None
argument = view.get_quoted_word()
value = await rc.convert(ctx, argument)
except (CommandError, ArgumentParsingError):
view.index = previous
break
else:
return role_list
result.append(value)
return [r.id for r in result]
# Old method
# content_list = content.split(",")
# try:
# role_list = [
# discord.utils.get(ctx.guild.roles, name=role.strip(" ")).id for role in content_list
# ]
# except (discord.HTTPException, AttributeError): # None.id is attribute error
# return None
# else:
# return role_list
class CCRole(commands.Cog):
@ -84,7 +108,7 @@ class CCRole(commands.Cog):
# Roles to add
await ctx.send(
"What roles should it add? (Must be **comma separated**)\n"
"What roles should it add?\n"
"Say `None` to skip adding roles"
)
@ -106,7 +130,7 @@ class CCRole(commands.Cog):
# Roles to remove
await ctx.send(
"What roles should it remove? (Must be comma separated)\n"
"What roles should it remove?\n"
"Say `None` to skip removing roles"
)
try:
@ -124,7 +148,7 @@ class CCRole(commands.Cog):
# Roles to use
await ctx.send(
"What roles are allowed to use this command? (Must be comma separated)\n"
"What roles are allowed to use this command?\n"
"Say `None` to allow all roles"
)

@ -74,77 +74,35 @@ If you get an error at this step, stop and skip to one of the manual methods bel
#### Step 2: Install additional dependencies
Assuming the previous commands had no error, you can now use `pipinstall` to add the remaining dependencies.
Here you need to decide which training models you want to have available to you.
NOTE: This method is not the intended use case for `pipinstall` and may stop working in the future.
Shutdown the bot and run any number of these in the console:
```
[p]pipinstall --no-deps chatterbot>=1.1
```
#### Step 3: Load the cog and get started
```
[p]load chatter
```
python -m spacy download en_core_web_sm # ~15 MB
### Windows - Manually
#### Step 1: Built-in Downloader
python -m spacy download en_core_web_md # ~50 MB
You need to get a copy of the requirements.txt provided with chatter, I recommend this method.
python -m spacy download en_core_web_lg # ~750 MB (CPU Optimized)
```
[p]repo add Fox https://github.com/bobloy/Fox-V3
python -m spacy download en_core_web_trf # ~500 MB (GPU Optimized)
```
#### Step 2: Install Requirements
Make sure you have your virtual environment that you installed Red on activated before starting this step. See the Red Docs for details on how.
In a terminal running as an admin, navigate to the directory containing this repo.
I've used my install directory as an example.
```
cd C:\Users\Bobloy\AppData\Local\Red-DiscordBot\Red-DiscordBot\data\bobbot\cogs\RepoManager\repos\Fox\chatter
pip install -r requirements.txt
pip install --no-deps "chatterbot>=1.1"
```
#### Step 3: Load Chatter
#### Step 3: Load the cog and get started
```
[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
```
### Linux - Manually
#### Step 1: Built-in Downloader
```
[p]repo add Fox https://github.com/bobloy/Fox-V3
[p]cog install Fox chatter
```
#### Step 2: Install Requirements
In your console with your virtual environment activated:
```
pip install --no-deps "chatterbot>=1.1"
```
### Step 3: Load Chatter
### Windows - Manually
Deprecated
```
[p]load chatter
```
### Linux - Manually
Deprecated
# Configuration
Chatter works out the the box without any training by learning as it goes,
Chatter works out the box without any training by learning as it goes,
but will have very poor and repetitive responses at first.
Initial training is recommended to speed up its learning.

@ -1,8 +1,10 @@
from .chat import Chatter
def setup(bot):
bot.add_cog(Chatter(bot))
async def setup(bot):
cog = Chatter(bot)
await cog.initialize()
bot.add_cog(cog)
# __all__ = (

@ -19,6 +19,7 @@ from redbot.core.utils.predicates import MessagePredicate
from chatter.trainers import MovieTrainer, TwitterCorpusTrainer, UbuntuCorpusTrainer2
chatterbot_log = logging.getLogger("red.fox_v3.chatterbot")
log = logging.getLogger("red.fox_v3.chatter")
@ -29,6 +30,12 @@ def my_local_get_prefix(prefixes, content):
return None
class ENG_TRF:
ISO_639_1 = "en_core_web_trf"
ISO_639 = "eng"
ENGLISH_NAME = "English"
class ENG_LG:
ISO_639_1 = "en_core_web_lg"
ISO_639 = "eng"
@ -52,12 +59,15 @@ class Chatter(Cog):
This cog trains a chatbot that will talk like members of your Guild
"""
models = [ENG_SM, ENG_MD, ENG_LG, ENG_TRF]
algos = [SpacySimilarity, JaccardSimilarity, LevenshteinDistance]
def __init__(self, bot):
super().__init__()
self.bot = bot
self.config = Config.get_conf(self, identifier=6710497116116101114)
default_global = {"learning": True}
default_guild = {
default_global = {"learning": True, "model_number": 0, "algo_number": 0, "threshold": 0.90}
self.default_guild = {
"whitelist": None,
"days": 1,
"convo_delta": 15,
@ -70,16 +80,16 @@ class Chatter(Cog):
# TODO: Move training_model and similarity_algo to config
# TODO: Add an option to see current settings
self.tagger_language = ENG_MD
self.tagger_language = ENG_SM
self.similarity_algo = SpacySimilarity
self.similarity_threshold = 0.90
self.chatbot = self._create_chatbot()
self.chatbot = None
# self.chatbot.set_trainer(ListTrainer)
# self.trainer = ListTrainer(self.chatbot)
self.config.register_global(**default_global)
self.config.register_guild(**default_guild)
self.config.register_guild(**self.default_guild)
self.loop = asyncio.get_event_loop()
@ -92,6 +102,18 @@ class Chatter(Cog):
"""Nothing to delete"""
return
async def initialize(self):
all_config = dict(self.config.defaults["GLOBAL"])
all_config.update(await self.config.all())
model_number = all_config["model_number"]
algo_number = all_config["algo_number"]
threshold = all_config["threshold"]
self.tagger_language = self.models[model_number]
self.similarity_algo = self.algos[algo_number]
self.similarity_threshold = threshold
self.chatbot = self._create_chatbot()
def _create_chatbot(self):
return ChatBot(
@ -104,7 +126,7 @@ class Chatter(Cog):
logic_adapters=["chatterbot.logic.BestMatch"],
maximum_similarity_threshold=self.similarity_threshold,
tagger_language=self.tagger_language,
logger=log,
logger=chatterbot_log,
)
async def _get_conversation(self, ctx, in_channels: List[discord.TextChannel]):
@ -328,15 +350,12 @@ class Chatter(Cog):
self, ctx: commands.Context, algo_number: int, threshold: float = None
):
"""
Switch the active logic algorithm to one of the three. Default after reload is Spacy
Switch the active logic algorithm to one of the three. Default is Spacy
0: Spacy
1: Jaccard
2: Levenshtein
"""
algos = [SpacySimilarity, JaccardSimilarity, LevenshteinDistance]
if algo_number < 0 or algo_number > 2:
await ctx.send_help()
return
@ -349,8 +368,11 @@ class Chatter(Cog):
return
else:
self.similarity_threshold = threshold
await self.config.threshold.set(self.similarity_threshold)
self.similarity_algo = self.algos[algo_number]
await self.config.algo_number.set(algo_number)
self.similarity_algo = algos[algo_number]
async with ctx.typing():
self.chatbot = self._create_chatbot()
@ -360,20 +382,18 @@ class Chatter(Cog):
@chatter.command(name="model")
async def chatter_model(self, ctx: commands.Context, model_number: int):
"""
Switch the active model to one of the three. Default after reload is Medium
Switch the active model to one of the three. Default is Small
0: Small
1: Medium
1: Medium (Requires additional setup)
2: Large (Requires additional setup)
3. Accurate (Requires additional setup)
"""
models = [ENG_SM, ENG_MD, ENG_LG]
if model_number < 0 or model_number > 2:
if model_number < 0 or model_number > 3:
await ctx.send_help()
return
if model_number == 2:
if model_number >= 0:
await ctx.maybe_send_embed(
"Additional requirements needed. See guide before continuing.\n" "Continue?"
)
@ -386,7 +406,8 @@ class Chatter(Cog):
if not pred.result:
return
self.tagger_language = models[model_number]
self.tagger_language = self.models[model_number]
await self.config.model_number.set(model_number)
async with ctx.typing():
self.chatbot = self._create_chatbot()
@ -395,7 +416,13 @@ class Chatter(Cog):
)
@commands.is_owner()
@chatter.command(name="minutes")
@chatter.group(name="trainset")
async def chatter_trainset(self, ctx: commands.Context):
"""Commands for configuring training"""
pass
@commands.is_owner()
@chatter_trainset.command(name="minutes")
async def minutes(self, ctx: commands.Context, minutes: int):
"""
Sets the number of minutes the bot will consider a break in a conversation during training
@ -411,7 +438,7 @@ class Chatter(Cog):
await ctx.tick()
@commands.is_owner()
@chatter.command(name="age")
@chatter_trainset.command(name="age")
async def age(self, ctx: commands.Context, days: int):
"""
Sets the number of days to look back
@ -630,7 +657,7 @@ class Chatter(Cog):
guild: discord.Guild = getattr(message, "guild", None)
if await self.bot.cog_disabled_in_guild(self, guild):
if guild is None or await self.bot.cog_disabled_in_guild(self, guild):
return
ctx: commands.Context = await self.bot.get_context(message)
@ -705,7 +732,9 @@ class Chatter(Cog):
)
replying = None
if self._guild_cache[guild.id]["reply"]:
if (
"reply" not in self._guild_cache[guild.id] and self.default_guild["reply"]
) or self._guild_cache[guild.id]["reply"]:
if message != ctx.channel.last_message:
replying = message

@ -7,18 +7,10 @@
"hidden": false,
"install_msg": "Thank you for installing Chatter! Please make sure you check the install instructions at https://github.com/bobloy/Fox-V3/blob/master/chatter/README.md\nAfter that, get started ith `[p]load chatter` and `[p]help Chatter`",
"requirements": [
"git+git://github.com/gunthercox/chatterbot-corpus@master#egg=chatterbot_corpus",
"mathparse>=0.1,<0.2",
"nltk>=3.2,<4.0",
"pint>=0.8.1",
"python-dateutil>=2.8,<2.9",
"pyyaml>=5.3,<5.4",
"sqlalchemy>=1.3,<1.4",
"pytz",
"https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-2.3.1/en_core_web_sm-2.3.1.tar.gz#egg=en_core_web_sm",
"https://github.com/explosion/spacy-models/releases/download/en_core_web_md-2.3.1/en_core_web_md-2.3.1.tar.gz#egg=en_core_web_md",
"spacy>=2.3,<2.4",
"kaggle"
"git+git://github.com/bobloy/ChatterBot@fox#egg=ChatterBot>=1.1.0.dev4",
"kaggle",
"https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.1.0/en_core_web_sm-3.1.0.tar.gz#egg=en_core_web_sm",
"https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.1.0/en_core_web_md-3.1.0.tar.gz#egg=en_core_web_md"
],
"short": "Local Chatbot run on machine learning",
"end_user_data_statement": "This cog only stores anonymous conversations data; no End User Data is stored.",

@ -1,12 +0,0 @@
git+git://github.com/gunthercox/chatterbot-corpus@master#egg=chatterbot_corpus
mathparse>=0.1,<0.2
nltk>=3.2,<4.0
pint>=0.8.1
python-dateutil>=2.8,<2.9
pyyaml>=5.3,<5.4
sqlalchemy>=1.3,<1.4
pytz
spacy>=2.3,<2.4
https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-2.3.1/en_core_web_sm-2.3.1.tar.gz#egg=en_core_web_sm
https://github.com/explosion/spacy-models/releases/download/en_core_web_md-2.3.1/en_core_web_md-2.3.1.tar.gz#egg=en_core_web_md
# https://github.com/explosion/spacy-models/releases/download/en_core_web_lg-2.3.1/en_core_web_lg-2.3.1.tar.gz#egg=en_core_web_lg

@ -5,7 +5,7 @@ class MyDumbSQLStorageAdapter(SQLStorageAdapter):
def __init__(self, **kwargs):
super(SQLStorageAdapter, self).__init__(**kwargs)
from sqlalchemy import create_engine
from sqlalchemy import create_engine, inspect
from sqlalchemy.orm import sessionmaker
self.database_uri = kwargs.get("database_uri", False)
@ -18,9 +18,7 @@ class MyDumbSQLStorageAdapter(SQLStorageAdapter):
if not self.database_uri:
self.database_uri = "sqlite:///db.sqlite3"
self.engine = create_engine(
self.database_uri, convert_unicode=True, connect_args={"check_same_thread": False}
)
self.engine = create_engine(self.database_uri, connect_args={"check_same_thread": False})
if self.database_uri.startswith("sqlite://"):
from sqlalchemy.engine import Engine
@ -31,7 +29,7 @@ class MyDumbSQLStorageAdapter(SQLStorageAdapter):
dbapi_connection.execute("PRAGMA journal_mode=WAL")
dbapi_connection.execute("PRAGMA synchronous=NORMAL")
if not self.engine.dialect.has_table(self.engine, "Statement"):
if not inspect(self.engine).has_table("Statement"):
self.create_database()
self.Session = sessionmaker(bind=self.engine, expire_on_commit=True)

@ -1,5 +1,6 @@
import asyncio
import json
import logging
import os
import pathlib
from abc import ABC
@ -13,6 +14,8 @@ from redbot.core import Config, commands
from redbot.core.bot import Red
from redbot.core.data_manager import bundled_data_path, cog_data_path
log = logging.getLogger("red.fox_v3.conquest")
class Conquest(commands.Cog):
"""
@ -53,14 +56,20 @@ class Conquest(commands.Cog):
self.current_map = await self.config.current_map()
if self.current_map:
await self.current_map_load()
if not await self.current_map_load():
await self.config.current_map.clear()
async def current_map_load(self):
map_data_path = self.asset_path / self.current_map / "data.json"
if not map_data_path.exists():
log.warning(f"{map_data_path} does not exist. Clearing current map")
return False
with map_data_path.open() as mapdata:
self.map_data: dict = json.load(mapdata)
self.ext = self.map_data["extension"]
self.ext_format = "JPEG" if self.ext.upper() == "JPG" else self.ext.upper()
return True
@commands.group()
async def conquest(self, ctx: commands.Context):

@ -1,7 +1,7 @@
{
"maps": [
"simple_blank_map",
"test",
"test2"
"simple",
"ck2",
"HoI"
]
}

@ -441,6 +441,7 @@ class FIFO(commands.Cog):
self.scheduler.print_jobs(out=cp)
out = cp.string
out=out.replace("*","\*")
if out:
if len(out) > 2000:

@ -90,6 +90,7 @@ things_for_fakemessage_to_steal = [
"content",
"nonce",
"reference",
"_edited_timestamp" # New 7/23/21
]
things_fakemessage_sets_by_default = {
@ -142,7 +143,7 @@ class FakeMessage(discord.Message):
self._update(
{
"mention_roles": self.raw_role_mentions,
"mentions": self.raw_mentions,
"mentions": [{"id": _id} for _id in self.raw_mentions],
}
)

@ -28,9 +28,12 @@ async def get_channel_counts(category, guild):
online_num = members - offline_num
# Gets count of actual users
human_num = members - bot_num
# count amount of premium subs/nitro subs.
boosters = guild.premium_subscription_count
return {
"members": members,
"humans": human_num,
"boosters": boosters,
"bots": bot_num,
"roles": roles_num,
"channels": channels_num,
@ -58,6 +61,7 @@ class InfoChannel(Cog):
self.default_channel_names = {
"members": "Members: {count}",
"humans": "Humans: {count}",
"boosters": "Boosters: {count}",
"bots": "Bots: {count}",
"roles": "Roles: {count}",
"channels": "Channels: {count}",
@ -170,6 +174,7 @@ class InfoChannel(Cog):
Valid Types are:
- `members`: Total members on the server
- `humans`: Total members that aren't bots
- `boosters`: Total amount of boosters
- `bots`: Total bots
- `roles`: Total number of roles
- `channels`: Total number of channels excluding infochannels,
@ -224,6 +229,7 @@ class InfoChannel(Cog):
Valid Types are:
- `members`: Total members on the server
- `humans`: Total members that aren't bots
- `boosters`: Total amount of boosters
- `bots`: Total bots
- `roles`: Total number of roles
- `channels`: Total number of channels excluding infochannels
@ -441,6 +447,7 @@ class InfoChannel(Cog):
guild,
members=True,
humans=True,
boosters=True,
bots=True,
roles=True,
channels=True,
@ -497,14 +504,16 @@ class InfoChannel(Cog):
guild_data = await self.config.guild(guild).all()
to_update = (
kwargs.keys() & guild_data["enabled_channels"].keys()
kwargs.keys() & [key for key, value in guild_data["enabled_channels"].items() if value]
) # Value in kwargs doesn't matter
log.debug(f"{to_update=}")
if to_update or extra_roles:
log.debug(f"{to_update=}\n"
f"{extra_roles=}")
category = guild.get_channel(guild_data["category_id"])
if category is None:
log.debug('Channel category is missing, updating must be off')
return # Nothing to update, must be off
channel_data = await get_channel_counts(category, guild)

@ -40,16 +40,20 @@ class LoveCalculator(Cog):
log.debug(f"{resp=}")
soup_object = BeautifulSoup(resp, "html.parser")
description = soup_object.find("div", class_="result__score").get_text()
description = soup_object.find("div", class_="result__score")
if description is None:
description = "Dr. Love is busy right now"
else:
description = description.strip()
description = description.get_text().strip()
result_image = soup_object.find("img", class_="result__image").get("src")
result_text = soup_object.find("div", class_="result-text").get_text()
result_text = soup_object.find("div", class_="result-text")
if result_text is None:
result_text = f"{x} and {y} aren't compatible 😔"
else:
result_text = result_text.get_text()
result_text = " ".join(result_text.split())
try:

@ -77,11 +77,13 @@ class LastSeen(Cog):
return
last_seen = self.get_date_time(last_seen)
# embed = discord.Embed(
# description="{} was last seen at this date and time".format(member.display_name),
# timestamp=last_seen)
embed = discord.Embed(
description="{} was last seen at this date and time".format(member.display_name),
timestamp=last_seen,
color=await self.bot.get_embed_color(ctx),
)
embed = discord.Embed(timestamp=last_seen, color=await self.bot.get_embed_color(ctx))
# embed = discord.Embed(timestamp=last_seen, color=await self.bot.get_embed_color(ctx))
await ctx.send(embed=embed)
@commands.Cog.listener()

@ -32,6 +32,7 @@ class RecyclingPlant(Cog):
x = 0
reward = 0
timeoutcount = 0
await ctx.send(
"{0} has signed up for a shift at the Recycling Plant! Type ``exit`` to terminate it early.".format(
ctx.author.display_name
@ -53,14 +54,25 @@ class RecyclingPlant(Cog):
return m.author == ctx.author and m.channel == ctx.channel
try:
answer = await self.bot.wait_for("message", timeout=120, check=check)
answer = await self.bot.wait_for("message", timeout=20, check=check)
except asyncio.TimeoutError:
answer = None
if answer is None:
if timeoutcount == 2:
await ctx.send(
"``{}`` fell down the conveyor belt to be sorted again!".format(used["object"])
"{} slacked off at work, so they were sacked with no pay.".format(
ctx.author.display_name
)
)
break
else:
await ctx.send(
"{} is slacking, and if they carry on not working, they'll be fired.".format(
ctx.author.display_name
)
)
timeoutcount += 1
elif answer.content.lower().strip() == used["action"]:
await ctx.send(
"Congratulations! You put ``{}`` down the correct chute! (**+50**)".format(

@ -177,7 +177,3 @@ class SCP(Cog):
msg = "http://www.scp-wiki.net/log-of-unexplained-locations"
await ctx.maybe_send_embed(msg)
def setup(bot):
bot.add_cog(SCP(bot))

@ -6,6 +6,7 @@ import discord
from redbot.core import Config, checks, commands
from redbot.core.bot import Red
from redbot.core.commands import Cog
from redbot.core.utils.chat_formatting import pagify
log = logging.getLogger("red.fox_v3.stealemoji")
# Replaced with discord.Asset.read()
@ -99,7 +100,8 @@ class StealEmoji(Cog):
await ctx.maybe_send_embed("No stolen emojis yet")
return
await ctx.maybe_send_embed(emoj)
for page in pagify(emoj, delims=[" "]):
await ctx.maybe_send_embed(page)
@checks.is_owner()
@stealemoji.command(name="notify")

@ -37,7 +37,7 @@ class Timerole(Cog):
self.bot = bot
self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
default_global = {}
default_guild = {"announce": None, "reapply": True, "roles": {}}
default_guild = {"announce": None, "reapply": True, "roles": {}, "skipbots": True}
default_rolemember = {"had_role": False, "check_again_time": None}
self.config.register_global(**default_global)
@ -92,6 +92,9 @@ class Timerole(Cog):
await ctx.maybe_send_embed("Error: Invalid time string.")
return
if parsed_time is None:
return await ctx.maybe_send_embed("Error: Invalid time string.")
days = parsed_time.days
hours = parsed_time.seconds // 60 // 60
@ -151,6 +154,14 @@ class Timerole(Cog):
await self.config.guild(guild).reapply.set(not current_setting)
await ctx.maybe_send_embed(f"Reapplying roles is now set to: {not current_setting}")
@timerole.command()
async def skipbots(self, ctx: commands.Context):
"""Toggle skipping bots when adding/removing roles. Defaults to True"""
guild = ctx.guild
current_setting = await self.config.guild(guild).skipbots()
await self.config.guild(guild).skipbots.set(not current_setting)
await ctx.maybe_send_embed(f"Skipping bots is now set to: {not current_setting}")
@timerole.command()
async def delrole(self, ctx: commands.Context, role: discord.Role):
"""Deletes a role from being added/removed after specified time"""
@ -199,6 +210,7 @@ class Timerole(Cog):
remove_results = ""
reapply = all_guilds[guild_id]["reapply"]
role_dict = all_guilds[guild_id]["roles"]
skipbots = all_guilds[guild_id]["skipbots"]
if not any(role_dict.values()): # No roles
log.debug(f"No roles are configured for guild: {guild}")
@ -208,6 +220,10 @@ class Timerole(Cog):
# log.debug(f"{all_mr=}")
async for member in AsyncIter(guild.members, steps=10):
if member.bot and skipbots:
continue
addlist = []
removelist = []
@ -295,9 +311,12 @@ class Timerole(Cog):
log.exception("Failed Adding Roles")
add_results += f"{member.display_name} : **(Failed Adding Roles)**\n"
else:
add_results += " \n".join(
add_results += (
" \n".join(
f"{member.display_name} : {role.name}" for role in add_roles
)
+ "\n"
)
for role_id in addlist:
await self.config.custom(
"RoleMember", role_id, member.id
@ -310,9 +329,12 @@ class Timerole(Cog):
log.exception("Failed Removing Roles")
remove_results += f"{member.display_name} : **(Failed Removing Roles)**\n"
else:
remove_results += " \n".join(
remove_results += (
" \n".join(
f"{member.display_name} : {role.name}" for role in remove_roles
)
+ "\n"
)
for role_id in removelist:
await self.config.custom(
"RoleMember", role_id, member.id

@ -1,11 +1,35 @@
import io
import logging
from typing import Optional, TYPE_CHECKING
import discord
from discord.ext.commands import BadArgument, Converter
from gtts import gTTS
from gtts.lang import _fallback_deprecated_lang, tts_langs
from redbot.core import Config, commands
from redbot.core.bot import Red
from redbot.core.commands import Cog
log = logging.getLogger("red.fox_v3.tts")
if TYPE_CHECKING:
ISO639Converter = str
else:
class ISO639Converter(Converter):
async def convert(self, ctx, argument) -> str:
lang = _fallback_deprecated_lang(argument)
try:
langs = tts_langs()
if lang not in langs:
raise BadArgument("Language not supported: %s" % lang)
except RuntimeError as e:
log.debug(str(e), exc_info=True)
log.warning(str(e))
return lang
class TTS(Cog):
"""
@ -18,7 +42,7 @@ class TTS(Cog):
self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
default_global = {}
default_guild = {}
default_guild = {"language": "en"}
self.config.register_global(**default_global)
self.config.register_guild(**default_guild)
@ -27,13 +51,29 @@ class TTS(Cog):
"""Nothing to delete"""
return
@commands.mod()
@commands.command()
async def ttslang(self, ctx: commands.Context, lang: ISO639Converter):
"""
Sets the default language for TTS in this guild.
Default is `en` for English
"""
await self.config.guild(ctx.guild).language.set(lang)
await ctx.send(f"Default tts language set to {lang}")
@commands.command(aliases=["t2s", "text2"])
async def tts(self, ctx: commands.Context, *, text: str):
async def tts(
self, ctx: commands.Context, lang: Optional[ISO639Converter] = None, *, text: str
):
"""
Send Text to speech messages as an mp3
"""
if lang is None:
lang = await self.config.guild(ctx.guild).language()
mp3_fp = io.BytesIO()
tts = gTTS(text, lang="en")
tts = gTTS(text, lang=lang)
tts.write_to_fp(mp3_fp)
mp3_fp.seek(0)
await ctx.send(file=discord.File(mp3_fp, "text.mp3"))

Loading…
Cancel
Save