From a641cae640b31ada70a8248a28d2d9c00e229337 Mon Sep 17 00:00:00 2001 From: Seaswimmer Date: Tue, 28 May 2024 20:20:21 -0400 Subject: [PATCH] feat(seautils): add `[p]rfc` command --- poetry.lock | 34 +++++++++++++++++++++++++++++++++- pyproject.toml | 1 + seautils/info.json | 3 ++- seautils/seautils.py | 31 +++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/poetry.lock b/poetry.lock index 50be601..d30b1f7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -228,6 +228,27 @@ files = [ [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] +html5lib = ["html5lib"] +lxml = ["lxml"] + [[package]] name = "brotli" version = "1.1.0" @@ -2111,6 +2132,17 @@ files = [ {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, ] +[[package]] +name = "soupsieve" +version = "2.5" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.8" +files = [ + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, +] + [[package]] name = "tinycss2" version = "1.2.1" @@ -2451,4 +2483,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.12" -content-hash = "0ac382e0399d9c23c5f89a0ffeb3aae056dc8b28e864b22f815c0e3eb34175bd" +content-hash = "55119c37c690ab197058ad091cb31bdf7c1c51ae62947e0026f4cddb423093d3" diff --git a/pyproject.toml b/pyproject.toml index 245364d..a2afb43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ websockets = "^12.0" pillow = "^10.3.0" numpy = "^1.26.4" colorthief = "^0.2.1" +beautifulsoup4 = "^4.12.3" [tool.poetry.group.dev] optional = true diff --git a/seautils/info.json b/seautils/info.json index f331eac..8e93f9d 100644 --- a/seautils/info.json +++ b/seautils/info.json @@ -8,5 +8,6 @@ "hidden": true, "disabled": false, "min_bot_version": "3.5.0", - "min_python_version": [3, 8, 0] + "min_python_version": [3, 8, 0], + "requirements": ["beautifulsoup4"] } diff --git a/seautils/seautils.py b/seautils/seautils.py index da87b3a..389ea71 100644 --- a/seautils/seautils.py +++ b/seautils/seautils.py @@ -12,7 +12,9 @@ from asyncio.subprocess import Process from functools import partial, partialmethod from typing import Any +import aiohttp import yaml +from bs4 import BeautifulSoup from discord import Color, Embed, app_commands from discord.utils import CachedSlotProperty, cached_property from redbot.core import commands @@ -185,3 +187,32 @@ class SeaUtils(commands.Cog): await ctx.send(content= warning + cf.box(text=ns_stdout.decode())) except (FileNotFoundError): await ctx.maybe_send_embed(message=cf.error("Neither `dig` nor `nslookup` are installed on the system. Unable to resolve DNS query.")) + + async def get_results(self, ctx: commands.Context, soup: BeautifulSoup) -> list: + pre_tags = soup.find_all('pre') + content = [] + for pre_tag in pre_tags: + if await ctx.embed_requested(): + embed = Embed( + title="RFC Document", + description=pre_tag.text, + color=await ctx.embed_color() + ) + content.append(embed) + else: + content.append(pre_tag.text) + return content + + @commands.command() + async def rfc(self, ctx: commands.Context, number: int) -> None: + """Retrieve the text of an RFC document.""" + url = f"https://www.rfc-editor.org/rfc/rfc{number}.html" + async with aiohttp.ClientSession() as session: + async with session.get(url=url) as response: + if response.status == 200: + html = await response.text() + soup = BeautifulSoup(html, 'html.parser') + content = await self.get_results(ctx, soup) + await SimpleMenu(pages=content, disable_after_timeout=True, timeout=300).start(ctx) + else: + await ctx.maybe_send_embed(content=cf.error(f"An error occurred while fetching RFC {number}. Status code: {response.status}."))