diff --git a/tuxbot/cogs/Linux/__init__.py b/tuxbot/cogs/Linux/__init__.py new file mode 100644 index 0000000..e4f5d05 --- /dev/null +++ b/tuxbot/cogs/Linux/__init__.py @@ -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)) diff --git a/tuxbot/cogs/Linux/config.py b/tuxbot/cogs/Linux/config.py new file mode 100644 index 0000000..78d774c --- /dev/null +++ b/tuxbot/cogs/Linux/config.py @@ -0,0 +1,12 @@ +from typing import Dict + +from structured_config import Structure + +HAS_MODELS = False + + +class LinuxConfig(Structure): + pass + + +extra: Dict[str, Dict] = {} diff --git a/tuxbot/cogs/Linux/functions/__init__.py b/tuxbot/cogs/Linux/functions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tuxbot/cogs/Linux/functions/cnf.py b/tuxbot/cogs/Linux/functions/cnf.py new file mode 100644 index 0000000..fc2c20c --- /dev/null +++ b/tuxbot/cogs/Linux/functions/cnf.py @@ -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, + } diff --git a/tuxbot/cogs/Linux/functions/exceptions.py b/tuxbot/cogs/Linux/functions/exceptions.py new file mode 100644 index 0000000..64d969d --- /dev/null +++ b/tuxbot/cogs/Linux/functions/exceptions.py @@ -0,0 +1,9 @@ +from discord.ext import commands + + +class LinuxException(commands.BadArgument): + pass + + +class CNFException(LinuxException): + pass diff --git a/tuxbot/cogs/Linux/functions/utils.py b/tuxbot/cogs/Linux/functions/utils.py new file mode 100644 index 0000000..ad86680 --- /dev/null +++ b/tuxbot/cogs/Linux/functions/utils.py @@ -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() diff --git a/tuxbot/cogs/Linux/linux.py b/tuxbot/cogs/Linux/linux.py new file mode 100644 index 0000000..6ca695c --- /dev/null +++ b/tuxbot/cogs/Linux/linux.py @@ -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)) diff --git a/tuxbot/cogs/Linux/locales/en-US.po b/tuxbot/cogs/Linux/locales/en-US.po new file mode 100644 index 0000000..b1789f5 --- /dev/null +++ b/tuxbot/cogs/Linux/locales/en-US.po @@ -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" diff --git a/tuxbot/cogs/Linux/locales/fr-FR.po b/tuxbot/cogs/Linux/locales/fr-FR.po new file mode 100644 index 0000000..2968853 --- /dev/null +++ b/tuxbot/cogs/Linux/locales/fr-FR.po @@ -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" diff --git a/tuxbot/cogs/Linux/locales/messages.pot b/tuxbot/cogs/Linux/locales/messages.pot new file mode 100644 index 0000000..691ff10 --- /dev/null +++ b/tuxbot/cogs/Linux/locales/messages.pot @@ -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 , 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 \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + diff --git a/tuxbot/cogs/Linux/models/__init__.py b/tuxbot/cogs/Linux/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tuxbot/core/bot.py b/tuxbot/core/bot.py index fd48168..b8aa209 100644 --- a/tuxbot/core/bot.py +++ b/tuxbot/core/bot.py @@ -42,6 +42,7 @@ packages: Tuple = ( "tuxbot.cogs.Polls", "tuxbot.cogs.Custom", "tuxbot.cogs.Network", + "tuxbot.cogs.Linux", )