Merge branch 'master' into ae7q-refactor

This commit is contained in:
Abigail Gold 2020-01-08 16:33:07 -05:00
commit f5a9b0b780
No known key found for this signature in database
GPG Key ID: CF88335E873C3FB4
21 changed files with 107 additions and 45 deletions

View File

@ -28,7 +28,7 @@ $ run.sh
## Copyright
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This program is released under the terms of the GNU General Public License,
version 2. See `COPYING` for full license text.

View File

@ -1,23 +1,19 @@
"""
Common tools for the bot.
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.
---
`colours`: Colours used by embeds.
`cat`: Category names for the HelpCommand.
"""
import collections
import json
import re
import traceback
from pathlib import Path
from datetime import datetime
from pathlib import Path
from types import SimpleNamespace
import discord
@ -26,7 +22,8 @@ import discord.ext.commands as commands
import data.options as opt
__all__ = ["colours", "cat", "emojis", "embed_factory", "error_embed_factory", "add_react", "check_if_owner"]
__all__ = ["colours", "cat", "emojis", "paths", "ImageMetadata", "ImagesGroup",
"embed_factory", "error_embed_factory", "add_react", "check_if_owner"]
# --- Common values ---
@ -94,6 +91,29 @@ class ImagesGroup(collections.abc.Mapping):
return str(self._images)
# --- Converters ---
class GlobalChannelConverter(commands.IDConverter):
"""Converter to get any bot-acessible channel by ID/mention (global), or name (in current guild only)."""
async def convert(self, ctx: commands.Context, argument: str):
bot = ctx.bot
guild = ctx.guild
match = self._get_id_match(argument) or re.match(r'<#([0-9]+)>$', argument)
result = None
if match is None:
# not a mention/ID
if guild:
result = discord.utils.get(guild.text_channels, name=argument)
else:
raise commands.BadArgument(f"""Channel named "{argument}" not found in this guild.""")
else:
channel_id = int(match.group(1))
result = bot.get_channel(channel_id)
if not isinstance(result, (discord.TextChannel, discord.abc.PrivateChannel)):
raise commands.BadArgument(f"""Channel "{argument}" not found.""")
return result
# --- Helper functions ---
def embed_factory(ctx: commands.Context) -> discord.Embed:

View File

@ -1,7 +1,7 @@
"""
ae7q extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.
@ -16,6 +16,7 @@ KC4USA: reserved, no call history, *but* has application history
import discord.ext.commands as commands
import aiohttp
from bs4 import BeautifulSoup
import common as cmn
@ -24,7 +25,7 @@ import common as cmn
class AE7QCog(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.session = bot.qrm.session
self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
@commands.group(name="ae7q", aliases=["ae"], category=cmn.cat.lookup)
async def _ae7q_lookup(self, ctx: commands.Context):

View File

@ -1,23 +1,25 @@
"""
Base extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.
"""
import random
import re
from collections import OrderedDict
import random
from typing import Union
import discord
import discord.ext.commands as commands
import info
import common as cmn
import data.options as opt
import common as cmn
class QrmHelpCommand(commands.HelpCommand):
@ -171,8 +173,13 @@ class BaseCog(commands.Cog):
@commands.command(name="echo", aliases=["e"], hidden=True)
@commands.check(cmn.check_if_owner)
async def _echo(self, ctx: commands.Context, channel: commands.TextChannelConverter, *, msg: str):
"""Send a message in a channel as qrm. Only works within a server or DM to server, not between servers."""
async def _echo(self, ctx: commands.Context,
channel: Union[cmn.GlobalChannelConverter, commands.UserConverter], *, msg: str):
"""Send a message in a channel as qrm. Accepts channel/user IDs/mentions.
Channel names are current-guild only.
Does not work with the ID of the bot user."""
if isinstance(channel, discord.ClientUser):
raise commands.BadArgument("Can't send to the bot user!")
await channel.send(msg)

View File

@ -1,7 +1,7 @@
"""
Fun extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.

View File

@ -1,7 +1,7 @@
"""
Grid extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.

View File

@ -1,7 +1,7 @@
"""
Ham extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.

View File

@ -1,7 +1,7 @@
"""
Image extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.
@ -9,6 +9,8 @@ General Public License, version 2.
import io
import aiohttp
import discord
import discord.ext.commands as commands
@ -20,7 +22,7 @@ class ImageCog(commands.Cog):
self.bot = bot
self.bandcharts = cmn.ImagesGroup(cmn.paths.bandcharts / "meta.json")
self.maps = cmn.ImagesGroup(cmn.paths.maps / "meta.json")
self.session = bot.qrm.session
self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
@commands.command(name="bandplan", aliases=['plan', 'bands'], category=cmn.cat.ref)
async def _bandplan(self, ctx: commands.Context, region: str = ''):

View File

@ -1,7 +1,7 @@
"""
Lookup extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.

View File

@ -1,7 +1,7 @@
"""
Morse Code extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.

View File

@ -1,7 +1,7 @@
"""
QRZ extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.
@ -21,7 +21,7 @@ import data.keys as keys
class QRZCog(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.session = bot.qrm.session
self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
self._qrz_session_init.start()
@commands.command(name="call", aliases=["qrz"], category=cmn.cat.lookup)

View File

@ -1,7 +1,7 @@
"""
Study extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.
@ -10,6 +10,8 @@ General Public License, version 2.
import random
import json
import aiohttp
import discord.ext.commands as commands
import common as cmn
@ -20,7 +22,7 @@ class StudyCog(commands.Cog):
self.bot = bot
self.lastq = dict()
self.source = 'Data courtesy of [HamStudy.org](https://hamstudy.org/)'
self.session = bot.qrm.session
self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
@commands.command(name="hamstudy", aliases=['rq', 'randomquestion', 'randomq'], category=cmn.cat.study)
async def _random_question(self, ctx: commands.Context, level: str = None):

View File

@ -1,7 +1,7 @@
"""
Weather extension for qrm
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.
@ -10,6 +10,8 @@ General Public License, version 2.
import io
import re
import aiohttp
import discord
import discord.ext.commands as commands
@ -21,7 +23,7 @@ class WeatherCog(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.session = bot.qrm.session
self.session = aiohttp.ClientSession(connector=bot.qrm.connector)
@commands.command(name="bandconditions", aliases=['cond', 'condx', 'conditions'], category=cmn.cat.weather)
async def _band_conditions(self, ctx: commands.Context):

View File

@ -1,7 +1,7 @@
"""
Static info about the bot.
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.

31
main.py
View File

@ -2,7 +2,7 @@
"""
qrm, a bot for Discord
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.
@ -11,17 +11,19 @@ General Public License, version 2.
import sys
import traceback
import asyncio
from datetime import time, datetime
import random
from types import SimpleNamespace
import pytz
import aiohttp
import discord
from discord.ext import commands, tasks
import utils.connector as conn
import common as cmn
import info
import data.options as opt
import data.keys as keys
@ -38,13 +40,21 @@ debug_mode = opt.debug # Separate assignement in-case we define an override (te
# --- Bot setup ---
# Loop/aiohttp stuff
loop = asyncio.get_event_loop()
connector = loop.run_until_complete(conn.new_connector())
bot = commands.Bot(command_prefix=opt.prefix,
description=info.description,
help_command=commands.MinimalHelpCommand())
help_command=commands.MinimalHelpCommand(),
loop=loop,
connector=connector)
# Simple way to access bot-wide stuff in extensions.
bot.qrm = SimpleNamespace()
bot.qrm.session = aiohttp.ClientSession(headers={'User-Agent': f'discord-qrm2/{info.release}'})
# Let's store stuff here.
bot.qrm.connector = connector
bot.qrm.debug_mode = debug_mode
@ -54,7 +64,6 @@ bot.qrm.debug_mode = debug_mode
@commands.check(cmn.check_if_owner)
async def _restart_bot(ctx: commands.Context):
"""Restarts the bot."""
await bot.qrm.session.close()
global exit_code
await cmn.add_react(ctx.message, cmn.emojis.check_mark)
print(f"[**] Restarting! Requested by {ctx.author}.")
@ -66,7 +75,6 @@ async def _restart_bot(ctx: commands.Context):
@commands.check(cmn.check_if_owner)
async def _shutdown_bot(ctx: commands.Context):
"""Shuts down the bot."""
await bot.qrm.session.close()
global exit_code
await cmn.add_react(ctx.message, cmn.emojis.check_mark)
print(f"[**] Shutting down! Requested by {ctx.author}.")
@ -74,7 +82,7 @@ async def _shutdown_bot(ctx: commands.Context):
await bot.logout()
@bot.group(name="extctl", hidden=True)
@bot.group(name="extctl", aliases=["ex"], hidden=True)
@commands.check(cmn.check_if_owner)
async def _extctl(ctx: commands.Context):
"""Extension control commands.
@ -84,7 +92,7 @@ async def _extctl(ctx: commands.Context):
await ctx.invoke(cmd)
@_extctl.command(name="list")
@_extctl.command(name="list", aliases=["ls"])
async def _extctl_list(ctx: commands.Context):
"""Lists Extensions."""
embed = cmn.embed_factory(ctx)
@ -93,7 +101,7 @@ async def _extctl_list(ctx: commands.Context):
await ctx.send(embed=embed)
@_extctl.command(name="load")
@_extctl.command(name="load", aliases=["ld"])
async def _extctl_load(ctx: commands.Context, extension: str):
try:
bot.load_extension(ext_dir + "." + extension)
@ -103,7 +111,7 @@ async def _extctl_load(ctx: commands.Context, extension: str):
await ctx.send(embed=embed)
@_extctl.command(name="reload", aliases=["relaod"])
@_extctl.command(name="reload", aliases=["rl", "r", "relaod"])
async def _extctl_reload(ctx: commands.Context, extension: str):
if ctx.invoked_with == "relaod":
pika = bot.get_emoji(opt.pika)
@ -117,7 +125,7 @@ async def _extctl_reload(ctx: commands.Context, extension: str):
await ctx.send(embed=embed)
@_extctl.command(name="unload")
@_extctl.command(name="unload", aliases=["ul"])
async def _extctl_unload(ctx: commands.Context, extension: str):
try:
bot.unload_extension(ext_dir + "." + extension)
@ -246,6 +254,7 @@ except ConnectionResetError as ex:
raise
raise SystemExit("ConnectionResetError: {}".format(ex))
# --- Exit ---
# Codes for the wrapper shell script:
# 0 - Clean exit, don't restart

View File

@ -1,7 +1,7 @@
"""
Information about callsigns for the vanity prefixes command in hamcog.
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrmbot and is released under the terms of the GNU
General Public License, version 2.

View File

@ -1,7 +1,7 @@
"""
A listing of morse code symbols
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrmbot and is released under the terms of the GNU
General Public License, version 2.

View File

@ -1,7 +1,7 @@
"""
A listing of NATO Phonetics
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrmbot and is released under the terms of the GNU
General Public License, version 2.

View File

@ -1,7 +1,7 @@
"""
A listing of Q Codes
---
Copyright (C) 2019 Abigail Gold, 0x5c
Copyright (C) 2019-2020 Abigail Gold, 0x5c
This file is part of discord-qrmbot and is released under the terms of the GNU
General Public License, version 2.

3
utils/__init__.py Normal file
View File

@ -0,0 +1,3 @@
"""
Various utilities for the bot.
"""

16
utils/connector.py Normal file
View File

@ -0,0 +1,16 @@
"""
Wrapper to handle aiohttp connector creation.
---
Copyright (C) 2020 Abigail Gold, 0x5c
This file is part of discord-qrm2 and is released under the terms of the GNU
General Public License, version 2.
"""
import aiohttp
async def new_connector(*args, **kwargs) -> aiohttp.TCPConnector:
"""*Yes, it's just a coro to instantiate a class.*"""
return aiohttp.TCPConnector(*args, **kwargs)