1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
from datetime import datetime
from typing import Union
import discord
from discord.ext import commands
class WrappedMessageConverter(commands.MessageConverter):
"""A converter that handles embed-suppressed links like <http://example.com>."""
async def convert(self, ctx: commands.Context, argument: str) -> discord.Message:
"""Wrap the commands.MessageConverter to handle <> delimited message links."""
# It's possible to wrap a message in [<>] as well, and it's supported because its easy
if argument.startswith("[") and argument.endswith("]"):
argument = argument[1:-1]
if argument.startswith("<") and argument.endswith(">"):
argument = argument[1:-1]
return await super().convert(ctx, argument)
class CoordinateConverter(commands.Converter):
"""Converter for Coordinates."""
@staticmethod
async def convert(ctx: commands.Context, coordinate: str) -> tuple[int, int]:
"""Take in a coordinate string and turn it into an (x, y) tuple."""
if len(coordinate) not in (2, 3):
raise commands.BadArgument("Invalid co-ordinate provided.")
coordinate = coordinate.lower()
if coordinate[0].isalpha():
digit = coordinate[1:]
letter = coordinate[0]
else:
digit = coordinate[:-1]
letter = coordinate[-1]
if not digit.isdecimal():
raise commands.BadArgument
x = ord(letter) - ord("a")
y = int(digit) - 1
if (not 0 <= x <= 9) or (not 0 <= y <= 9):
raise commands.BadArgument
return x, y
SourceType = Union[commands.Command, commands.Cog]
class SourceConverter(commands.Converter):
"""Convert an argument into a command or cog."""
@staticmethod
async def convert(ctx: commands.Context, argument: str) -> SourceType:
"""Convert argument into source object."""
cog = ctx.bot.get_cog(argument)
if cog:
return cog
cmd = ctx.bot.get_command(argument)
if cmd:
return cmd
raise commands.BadArgument(
f"Unable to convert `{argument}` to valid command or Cog."
)
class DateConverter(commands.Converter):
"""Parse SOL or earth date (in format YYYY-MM-DD) into `int` or `datetime`. When invalid input, raise error."""
@staticmethod
async def convert(ctx: commands.Context, argument: str) -> Union[int, datetime]:
"""Parse date (SOL or earth) into `datetime` or `int`. When invalid value, raise error."""
if argument.isdecimal():
return int(argument)
try:
date = datetime.strptime(argument, "%Y-%m-%d")
except ValueError:
raise commands.BadArgument(
f"Can't convert `{argument}` to `datetime` in format `YYYY-MM-DD` or `int` in SOL."
)
return date
class Subreddit(commands.Converter):
"""Forces a string to begin with "r/" and checks if it's a valid subreddit."""
@staticmethod
async def convert(ctx: commands.Context, sub: str) -> str:
"""
Force sub to begin with "r/" and check if it's a valid subreddit.
If sub is a valid subreddit, return it prepended with "r/"
"""
sub = sub.lower()
if not sub.startswith("r/"):
sub = f"r/{sub}"
resp = await ctx.bot.http_session.get(
"https://www.reddit.com/subreddits/search.json",
params={"q": sub}
)
json = await resp.json()
if not json["data"]["children"]:
raise commands.BadArgument(
f"The subreddit `{sub}` either doesn't exist, or it has no posts."
)
return sub
|