Compare commits

..

52 Commits

Author SHA1 Message Date
WTMike24
0aaffbf5f0 Added quick and dirty escape to asterisks. 2022-03-02 22:03:27 -05:00
bobloy
771d1457e5 Bump to latest version of Chatterbot 2021-09-22 13:26:12 -04:00
bobloy
d191abf6bd Only update if it's enabled (not all keys) 2021-09-03 15:37:08 -04:00
bobloy
aba9840bcb Less verbose debug 2021-09-03 15:28:28 -04:00
bobloy
0064e6e9b5 More verbose debug mode 2021-09-03 15:15:56 -04:00
bobloy
955624ad1a Use greedy converter, no more commas 2021-08-24 16:38:10 -04:00
bobloy
a6e0646b85
Merge pull request #186 from ScaredDonut/master
Booster counter
2021-08-09 15:51:29 -04:00
bobloy
269266ce04
Merge pull request #189 from aleclol/master
[LoveCalculator] Move .get_text() to after None check
2021-08-09 15:48:33 -04:00
bobloy
db3ce30122 Add back embed description, now required by discord 2021-08-09 10:29:27 -04:00
bobloy
1e87eacf83 Add edited timestamp 2021-07-23 16:13:07 -04:00
bobloy
61fa006e33 QoL fixes 2021-07-16 09:26:06 -04:00
bobloy
4183607372 Add option for skipping bots 2021-07-15 16:05:39 -04:00
bobloy
2421c4e9bf Add sm and md to requirements 2021-07-15 15:09:41 -04:00
bobloy
b2e843e781 Invalid timestring instead of error 2021-07-15 14:57:33 -04:00
aleclol
a7ce815e14
Merge branch 'bobloy:master' into master 2021-07-11 19:42:12 -04:00
bobloy
1e535c2f3e
Merge pull request #193 from XargsUK/master
additional exit conditions to recyclingplant
2021-07-08 08:34:31 -04:00
bobloy
fd80819618 Merge branch 'master' into XargsUK_master 2021-07-08 08:33:53 -04:00
bobloy
a5ff888f4c black reformat 2021-07-08 08:33:29 -04:00
bobloy
3eb499bf0e black reformat 2021-07-08 08:30:21 -04:00
bobloy
698dafade4 Add chatter initialization 2021-07-08 08:29:18 -04:00
Brad Duncan
15ecf72c64 Update recyclingplant.py 2021-07-08 07:37:45 +01:00
Brad Duncan
1d514f80c6 adding no response exit condition
Previously, if no response was provided by the user, the function would continuously loop.

I've modified the timeout to 20 seconds. When there's no response, +! to timeoutcount variable. When there's been 3 timeouts, break.
2021-07-08 07:37:37 +01:00
bobloy
b752bfd153 Stop looking at DMs 2021-07-06 13:50:15 -04:00
bobloy
47269ba8f4 fix has_table, move age and minutes to trainset 2021-07-06 12:01:27 -04:00
bobloy
e0a361b952 remove en_core_web_sm as dependency 2021-07-06 10:52:25 -04:00
bobloy
2a18760a83
Merge pull request #191 from bobloy/chatter_fox
Use Bobloy's chatterbot for Chatter
2021-07-06 10:10:09 -04:00
bobloy
b26afdf2db Merge branch 'master' into chatter_fox
# Conflicts:
#	chatter/requirements.txt
2021-07-06 10:09:41 -04:00
bobloy
86cc1fa35a Don't specify pyaml 2021-07-05 14:14:40 -04:00
aleclol
b331238c1c
Move .get_text() to after None check 2021-07-03 22:11:42 -04:00
bobloy
6f0c88b1ac change default models, fix requirements 2021-07-01 17:19:29 -04:00
bobloy
c165313031 no reply errors in cache 2021-07-01 15:25:38 -04:00
bobloy
9c63c12656 Don't need requirements file 2021-06-30 17:29:31 -04:00
bobloy
a55ae8a511 Use Bobloy's chatterbot fork 2021-06-30 17:29:00 -04:00
Alexander Soloviev
1ffac638ed Update infochannel.py
more formatting fix, too much indentation on github for whatever reason but not on notepad
2021-05-26 04:46:12 -05:00
Alexander Soloviev
5b75002c88 Update infochannel.py
fixed formatting I think? too many spaces/indents on github for some reason
2021-05-26 04:44:22 -05:00
Alexander Soloviev
7c08a5de0c Update infochannel.py
added booster counter as requested on https://github.com/bobloy/Fox-V3/issues/185
2021-05-26 04:39:24 -05:00
bobloy
bc12aa866e Fix formatting 2021-05-25 10:13:36 -04:00
bobloy
dbafd6ffd7
Merge pull request #183 from aleclol/master
Fix error on `[p]lovecalculator` command
2021-05-24 10:40:19 -04:00
aleclol
52ca2f6a45
Update lovecalculator.py 2021-05-18 15:27:55 -04:00
bobloy
2937b6ac92 List of dicts 2021-05-03 13:58:35 -04:00
bobloy
dbf84c8b81
Merge pull request #180 from phenom4n4n/patch-1
[LoveCalculator] Patch AttributeError
2021-04-16 14:58:18 -04:00
PhenoM4n4n
2f21de6a97 lovecalc attributeerror 2021-04-15 17:39:49 -07:00
bobloy
ed6cc433c8 Remove pycountry 2021-04-15 11:38:36 -04:00
bobloy
e1a30359d8
Merge pull request #148 from BogdanWDK/master
Language Support Added
2021-04-15 11:15:13 -04:00
bobloy
506a79c6d6 Removing debugging print 2021-04-15 11:14:00 -04:00
bobloy
1ddcd98078 Implement languages 2021-04-15 11:12:47 -04:00
bobloy
7bd004c78e Merge branch 'master' into BogdanWDK_master 2021-04-15 10:50:45 -04:00
bobloy
184833421a
Merge pull request #178 from Kreusada/patch-1
[SCP] Remove double setup
2021-04-15 09:09:22 -04:00
Kreusada
f04ff6886b
[SCP] Remove double setup 2021-04-15 13:59:19 +01:00
bobloy
28edcc1fdd deliminate on space not newline 2021-04-14 09:44:28 -04:00
bobloy
10ed1f9b9f pagify lots of stolen emojis 2021-04-14 09:40:34 -04:00
BogdanWDK
960b66a5b8 Language Support Added
Supports Language as [p]tts <lang> <text>
2020-09-30 06:54:18 +01:00
20 changed files with 244 additions and 200 deletions

View File

@ -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"
)

View File

@ -74,12 +74,18 @@ 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
python -m spacy download en_core_web_sm # ~15 MB
python -m spacy download en_core_web_md # ~50 MB
python -m spacy download en_core_web_lg # ~750 MB (CPU Optimized)
python -m spacy download en_core_web_trf # ~500 MB (GPU Optimized)
```
#### Step 3: Load the cog and get started
@ -89,62 +95,14 @@ NOTE: This method is not the intended use case for `pipinstall` and may stop wor
```
### Windows - Manually
#### Step 1: Built-in Downloader
You need to get a copy of the requirements.txt provided with chatter, I recommend this method.
```
[p]repo add Fox https://github.com/bobloy/Fox-V3
```
#### 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
```
[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
```
Deprecated
### 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
```
[p]load chatter
```
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.

View File

@ -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__ = (

View File

@ -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

View File

@ -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.",

View File

@ -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

View File

@ -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)

View File

@ -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):

View File

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

View File

@ -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:

View File

@ -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],
}
)

View File

@ -1,17 +1,13 @@
import logging
from datetime import date, timedelta
from typing import Literal, Optional
from typing import Literal
import discord
from redbot.cogs.mutes import Mutes
from redbot.core import Config, checks, commands
from redbot.core.bot import Red
from redbot.core.commands import Cog
from redbot.core.utils import AsyncIter
from redbot.core.utils.chat_formatting import pagify
log = logging.getLogger("red.fox_v3.flag")
class Flag(Cog):
"""
@ -23,7 +19,7 @@ class Flag(Cog):
self.bot = bot
self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True)
default_global = {}
default_guild = {"days": 31, "dm": True, "flags": {}, "mutethreshold": 0}
default_guild = {"days": 31, "dm": True, "flags": {}}
self.config.register_global(**default_global)
self.config.register_guild(**default_guild)
@ -82,29 +78,6 @@ class Flag(Cog):
"DM-ing members when they get a flag is now set to **{}**".format(not dm)
)
@checks.admin_or_permissions(manage_guild=True)
@flagset.command(name="mute")
async def flagset_mute(self, ctx: commands.Context, count: int):
"""
Sets the threshold for flags to mute the user.
Only works when the core mute cog is configured properly.
Set to zero to disable.
"""
if count < 0:
await ctx.send_help()
return
await self.config.guild(ctx.guild).mutethreshold.set(count)
if count:
await ctx.maybe_send_embed(
"Will now attempt to mute people after **{}** flags".format(count)
)
else:
await ctx.maybe_send_embed("Muting disabled.")
@staticmethod
def _flag_template():
return {"reason": "", "expireyear": 0, "expiremonth": 0, "expireday": 0}
@ -118,8 +91,7 @@ class Flag(Cog):
await self._check_flags(guild)
flag = self._flag_template()
mute_days = await self.config.guild(guild).days()
expire_date = date.today() + timedelta(mute_days)
expire_date = date.today() + timedelta(days=await self.config.guild(guild).days())
flag["reason"] = reason
flag["expireyear"] = expire_date.year
@ -134,12 +106,6 @@ class Flag(Cog):
if str(member.id) not in flags:
flags[str(member.id)] = []
flags[str(member.id)].append(flag)
flag_count = len(flags[str(member.id)])
mute_threshold = await self.config.guild(guild).mutethreshold()
if 0 < mute_threshold <= flag_count:
able_to_mute = await self._attempt_mute(ctx, member, mute_days)
log.debug(f"Mute attempt: {able_to_mute}")
outembed = await self._list_flags(member)
@ -200,17 +166,6 @@ class Flag(Cog):
for page in pagify(out):
await ctx.send(page)
async def _attempt_mute(self, ctx, member: discord.Member, days):
mutes: Optional[Mutes] = self.bot.get_cog("Mutes")
if mutes is None:
log.info("Mutes cog not loaded, cannot mute")
return False
return await mutes.mute(ctx, member, f'{days} days [Flag] Exceeded mute threshold')
# return await mutes.mute_user(
# member.guild, author, member, until, "[Flag] Exceeded mute threshold"
# )
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=[])

View File

@ -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)

View File

@ -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:

View File

@ -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()

View File

@ -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(

View File

@ -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))

View File

@ -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")

View File

@ -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

View File

@ -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"))