feat(commands:cnf|Linux): add new Command Not Found scrapper (Known issue: cache resolve on none results)
This commit is contained in:
parent
fcc23d87df
commit
88f60690dd
12 changed files with 247 additions and 0 deletions
19
tuxbot/cogs/Linux/__init__.py
Normal file
19
tuxbot/cogs/Linux/__init__.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
from collections import namedtuple
|
||||
|
||||
from tuxbot.core.bot import Tux
|
||||
from .linux import Linux
|
||||
from .config import LinuxConfig, HAS_MODELS
|
||||
|
||||
VersionInfo = namedtuple("VersionInfo", "major minor micro release_level")
|
||||
version_info = VersionInfo(major=1, minor=0, micro=0, release_level="alpha")
|
||||
|
||||
__version__ = "v{}.{}.{}-{}".format(
|
||||
version_info.major,
|
||||
version_info.minor,
|
||||
version_info.micro,
|
||||
version_info.release_level,
|
||||
).replace("\n", "")
|
||||
|
||||
|
||||
def setup(bot: Tux):
|
||||
bot.add_cog(Linux(bot))
|
12
tuxbot/cogs/Linux/config.py
Normal file
12
tuxbot/cogs/Linux/config.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from typing import Dict
|
||||
|
||||
from structured_config import Structure
|
||||
|
||||
HAS_MODELS = False
|
||||
|
||||
|
||||
class LinuxConfig(Structure):
|
||||
pass
|
||||
|
||||
|
||||
extra: Dict[str, Dict] = {}
|
0
tuxbot/cogs/Linux/functions/__init__.py
Normal file
0
tuxbot/cogs/Linux/functions/__init__.py
Normal file
77
tuxbot/cogs/Linux/functions/cnf.py
Normal file
77
tuxbot/cogs/Linux/functions/cnf.py
Normal file
|
@ -0,0 +1,77 @@
|
|||
import asyncio
|
||||
|
||||
import aiohttp
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from tuxbot.cogs.Linux.functions.exceptions import CNFException
|
||||
|
||||
|
||||
def _(x):
|
||||
return x
|
||||
|
||||
|
||||
class CNF:
|
||||
_url = "https://command-not-found.com/{}"
|
||||
_content: BeautifulSoup
|
||||
|
||||
command: str
|
||||
|
||||
description: str = ""
|
||||
meta: dict = {}
|
||||
distro: dict = {}
|
||||
|
||||
def __init__(self, command: str):
|
||||
self.command = command
|
||||
|
||||
# =========================================================================
|
||||
# =========================================================================
|
||||
|
||||
async def fetch(self):
|
||||
try:
|
||||
async with aiohttp.ClientSession() as cs:
|
||||
async with cs.get(self._url.format(self.command)) as s:
|
||||
if s.status == 200:
|
||||
self._content = BeautifulSoup(
|
||||
await s.text(), "html.parser"
|
||||
)
|
||||
return self.parse()
|
||||
|
||||
except (aiohttp.ClientError, asyncio.exceptions.TimeoutError):
|
||||
pass
|
||||
|
||||
raise CNFException(_("Something went wrong ..."))
|
||||
|
||||
def parse(self):
|
||||
info = self._content.find("div", class_="row-command-info")
|
||||
distro = self._content.find_all("div", class_="command-install")
|
||||
|
||||
try:
|
||||
self.description = info.find("p", class_="my-0").text.strip()
|
||||
except AttributeError:
|
||||
self.description = "N/A"
|
||||
|
||||
try:
|
||||
for m in info.find("ul", class_="list-group").find_all("li"):
|
||||
row = m.text.strip().split("\n")
|
||||
|
||||
self.meta[row[0].lower()[:-1]] = row[1]
|
||||
except AttributeError:
|
||||
self.meta = {}
|
||||
|
||||
try:
|
||||
del distro[0] # unused row
|
||||
|
||||
for d in distro:
|
||||
self.distro[
|
||||
d.find("dt").text.strip().split("\n")[-1].strip()
|
||||
] = d.find("code").text
|
||||
except (AttributeError, IndexError):
|
||||
self.distro = {}
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"command": self.command,
|
||||
"description": self.description,
|
||||
"meta": self.meta,
|
||||
"distro": self.distro,
|
||||
}
|
9
tuxbot/cogs/Linux/functions/exceptions.py
Normal file
9
tuxbot/cogs/Linux/functions/exceptions.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from discord.ext import commands
|
||||
|
||||
|
||||
class LinuxException(commands.BadArgument):
|
||||
pass
|
||||
|
||||
|
||||
class CNFException(LinuxException):
|
||||
pass
|
17
tuxbot/cogs/Linux/functions/utils.py
Normal file
17
tuxbot/cogs/Linux/functions/utils.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
from aiocache import cached, Cache
|
||||
from aiocache.serializers import PickleSerializer
|
||||
|
||||
from tuxbot.cogs.Linux.functions.cnf import CNF
|
||||
|
||||
|
||||
@cached(
|
||||
ttl=24 * 3600,
|
||||
serializer=PickleSerializer(),
|
||||
cache=Cache.MEMORY,
|
||||
namespace="linux",
|
||||
)
|
||||
async def get_from_cnf(command: str) -> dict:
|
||||
cnf = CNF(command)
|
||||
await cnf.fetch()
|
||||
|
||||
return cnf.to_dict()
|
56
tuxbot/cogs/Linux/linux.py
Normal file
56
tuxbot/cogs/Linux/linux.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
import logging
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
from tuxbot.cogs.Linux.functions.utils import get_from_cnf
|
||||
from tuxbot.core.utils.functions.extra import command_extra, ContextPlus
|
||||
from tuxbot.core.bot import Tux
|
||||
from tuxbot.core.i18n import (
|
||||
Translator,
|
||||
)
|
||||
|
||||
log = logging.getLogger("tuxbot.cogs.Linux")
|
||||
_ = Translator("Linux", __file__)
|
||||
|
||||
|
||||
class Linux(commands.Cog):
|
||||
def __init__(self, bot: Tux):
|
||||
self.bot = bot
|
||||
|
||||
async def cog_before_invoke(self, ctx: ContextPlus):
|
||||
await ctx.trigger_typing()
|
||||
|
||||
# =========================================================================
|
||||
# =========================================================================
|
||||
|
||||
@command_extra(name="cnf")
|
||||
async def _cnf(self, ctx: ContextPlus, command: str):
|
||||
cnf = await get_from_cnf(command)
|
||||
|
||||
if cnf["distro"]:
|
||||
e = discord.Embed(title=f"{cnf['description']} ({cnf['command']})")
|
||||
|
||||
description = (
|
||||
"__Maintainer:__ {maintainer}\n"
|
||||
"__Homepage:__ [{homepage}]({homepage})\n"
|
||||
"__Section:__ {section}".format(
|
||||
maintainer=cnf["meta"].get("maintainer", "N/A"),
|
||||
homepage=cnf["meta"].get("homepage", "N/A"),
|
||||
section=cnf["meta"].get("section", "N/A"),
|
||||
)
|
||||
)
|
||||
|
||||
e.description = description
|
||||
|
||||
e.set_footer(
|
||||
text="Powered by https://command-not-found.com/ "
|
||||
"and with his authorization"
|
||||
)
|
||||
|
||||
for k, v in cnf["distro"].items():
|
||||
e.add_field(name=f"**__{k}__**", value=f"```{v}```")
|
||||
|
||||
return await ctx.send(embed=e)
|
||||
|
||||
await ctx.send(_("No result found", ctx, self.bot.config))
|
18
tuxbot/cogs/Linux/locales/en-US.po
Normal file
18
tuxbot/cogs/Linux/locales/en-US.po
Normal file
|
@ -0,0 +1,18 @@
|
|||
# English translations for Tuxbot-bot package.
|
||||
# Copyright (C) 2020 THE Tuxbot-bot'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the Tuxbot-bot package.
|
||||
# Automatically generated, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Tuxbot-bot\n"
|
||||
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
|
||||
"POT-Creation-Date: 2021-01-25 14:36+0100\n"
|
||||
"PO-Revision-Date: 2020-06-10 00:38+0200\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: en_US\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
19
tuxbot/cogs/Linux/locales/fr-FR.po
Normal file
19
tuxbot/cogs/Linux/locales/fr-FR.po
Normal file
|
@ -0,0 +1,19 @@
|
|||
# French translations for Tuxbot-bot package
|
||||
# Traductions françaises du paquet Tuxbot-bot.
|
||||
# Copyright (C) 2020 THE Tuxbot-bot'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the Tuxbot-bot package.
|
||||
# Automatically generated, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Tuxbot-bot\n"
|
||||
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
|
||||
"POT-Creation-Date: 2021-01-25 14:36+0100\n"
|
||||
"PO-Revision-Date: 2020-06-10 00:38+0200\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
19
tuxbot/cogs/Linux/locales/messages.pot
Normal file
19
tuxbot/cogs/Linux/locales/messages.pot
Normal file
|
@ -0,0 +1,19 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the Tuxbot-bot package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Tuxbot-bot\n"
|
||||
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
|
||||
"POT-Creation-Date: 2021-03-01 14:59+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
0
tuxbot/cogs/Linux/models/__init__.py
Normal file
0
tuxbot/cogs/Linux/models/__init__.py
Normal file
|
@ -42,6 +42,7 @@ packages: Tuple = (
|
|||
"tuxbot.cogs.Polls",
|
||||
"tuxbot.cogs.Custom",
|
||||
"tuxbot.cogs.Network",
|
||||
"tuxbot.cogs.Linux",
|
||||
)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue