From 68edb163378e6424e376ca946ae269036f0f69b9 Mon Sep 17 00:00:00 2001 From: nexy7574 Date: Mon, 29 Apr 2024 01:29:48 +0100 Subject: [PATCH] Add more config options And also document those config options better --- config.example.toml | 44 +++++++++++++++++++++++++++++-- src/cogs/auto_responder.py | 53 ++++++++++++++++++++++++++++++++++---- src/cogs/ollama.py | 2 -- src/cogs/quote_quota.py | 2 +- src/cogs/screenshot.py | 2 +- src/cogs/ytdl.py | 18 +++++++++---- src/conf.py | 2 -- src/main.py | 8 ++++++ 8 files changed, 113 insertions(+), 18 deletions(-) diff --git a/config.example.toml b/config.example.toml index 307deca..45efb89 100644 --- a/config.example.toml +++ b/config.example.toml @@ -1,6 +1,10 @@ +# Example config file for Jimmy v2. +# This file is populated mostly with the default values set in src/conf.py. [jimmy] token = "token" # the bot token -debug_guilds = [994710566612500550] # server IDs to create slash commands in. Set to null for all guilds. +debug_guilds = [994710566612500550] # server IDs to create slash commands in. Omit for all guilds. +disabled_commands = ["i do not exist"] # A list of full command names to disable (e.g. " bool: + return self.config["transcoding"].get("enabled", True) + + @property + def allow_hevc_to_h264(self) -> bool: + return self.transcoding_enabled and self.config["transcoding"].get("hevc", True) + + @property + def allow_on_demand_transcoding(self) -> bool: + return self.transcoding_enabled and self.config["transcoding"].get("on_demand", True) + + def overpowered(self, guild: discord.Guild | None) -> bool: + if not guild: + self.log.debug("Not overpowered, in DM") + return False # in a DM + enable_offline = self.config.get("overrule_offline_superiors", False) + for _id in self.config.get("overpowered_by", []): + member = guild.get_member(_id) + if member: + if member.status != discord.Status.offline or enable_offline is False: + self.log.debug("Overpowered by %s (%s)", member, member.status) + return True + self.log.debug("No overpowered.") + return False @staticmethod @typing.overload @@ -71,7 +108,6 @@ class AutoResponder(commands.Cog): if new: _ = asyncio.create_task(update.add_reaction(new)) last_reaction = new - self.log.info("Waiting for transcode lock to release") async with self.transcode_lock: cog: FFMeta = self.bot.get_cog("FFMeta") @@ -195,6 +231,9 @@ class AutoResponder(commands.Cog): *domains: str, additional: Iterable[str] = None ) -> None: + if self.allow_hevc_to_h264 is False: + self.log.debug("hevc_to_h264 is disabled, not engaging.") + return additional = additional or [] links = self.extract_links(message.content, *domains) + list(additional) if links: @@ -259,6 +298,9 @@ class AutoResponder(commands.Cog): async def copy_ncfe_docs(self, message: discord.Message, links: list[ParseResult]) -> None: files = [] + if self.config.get("download_pdfs", True) is False: + self.log.debug("Download PDFs is disabled in config, disengaging.") + return self.log.info("Preparing to download: %s", ", ".join(map(ParseResult.geturl, links))) async with aiohttp.ClientSession() as session: for link in set(links): @@ -291,10 +333,10 @@ class AutoResponder(commands.Cog): @commands.Cog.listener("on_message") async def auto_responder(self, message: discord.Message): - if message.author == self.bot.user: + if message.author == self.bot.user or self.overpowered(message.guild): return - # Check for HEVC truth social links and convert into h264 + # Check for HEVC links and convert into h264 if message.channel.name == "spam" and message.author != self.bot.user: await self.transcode_hevc_to_h264(message) @@ -304,7 +346,7 @@ class AutoResponder(commands.Cog): @commands.Cog.listener("on_reaction_add") async def on_reaction_add(self, reaction: discord.Reaction, user: discord.User): - if user == self.bot.user: + if user == self.bot.user or self.overpowered(reaction.message.guild): return if reaction.message.author != self.bot.user: @@ -313,7 +355,8 @@ class AutoResponder(commands.Cog): extra = [] if reaction.message.attachments: extra = [attachment.url for attachment in reaction.message.attachments] - await self.transcode_hevc_to_h264(reaction.message, additional=extra) + if self.allow_on_demand_transcoding: + await self.transcode_hevc_to_h264(reaction.message, additional=extra) @commands.Cog.listener("on_raw_reaction_add") async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): diff --git a/src/cogs/ollama.py b/src/cogs/ollama.py index d45eceb..d7f144c 100644 --- a/src/cogs/ollama.py +++ b/src/cogs/ollama.py @@ -1,6 +1,5 @@ import asyncio import base64 -import contextlib import io import json import logging @@ -12,7 +11,6 @@ from fnmatch import fnmatch import aiohttp import discord -import httpx import redis from discord import Interaction from discord.ext import commands diff --git a/src/cogs/quote_quota.py b/src/cogs/quote_quota.py index 9f59eaf..89784ab 100644 --- a/src/cogs/quote_quota.py +++ b/src/cogs/quote_quota.py @@ -3,7 +3,7 @@ import io import logging import re from datetime import datetime, timedelta -from typing import Annotated, Callable, Iterable +from typing import Annotated, Callable import discord import matplotlib.pyplot as plt diff --git a/src/cogs/screenshot.py b/src/cogs/screenshot.py index 7d4fccc..8d1affd 100644 --- a/src/cogs/screenshot.py +++ b/src/cogs/screenshot.py @@ -215,7 +215,7 @@ class ScreenshotCog(commands.Cog): f"Cleanup time: {seconds(start_cleanup, end_cleanup)}s\n" f"Total time: {seconds(start_init, end_cleanup)}s\n" f"Screenshot size: {screenshot_size_mb}MB\n" - f"Resolution: {resolution}" + f"Resolution: {resolution}\n" f"Used proxy: {use_proxy}", colour=discord.Colour.dark_theme(), timestamp=discord.utils.utcnow(), diff --git a/src/cogs/ytdl.py b/src/cogs/ytdl.py index 77fb8e0..23d23c9 100644 --- a/src/cogs/ytdl.py +++ b/src/cogs/ytdl.py @@ -23,9 +23,9 @@ class YTDLCog(commands.Cog): self.log = logging.getLogger("jimmy.cogs.ytdl") self.common_formats = { "144p": "17", # mp4 (h264+aac) v - "240p": "133+139", + "240p": "bv[width==240]+ba[ext=webm]/bv[width==240]+ba[ext=m4a]/bv[width==240]+ba", "360p": "18", - "480p": "135+139", + "480p": "bv[width==480]+ba[ext=webm]/bv[width==480]+ba[ext=m4a]/bv[width==480]+ba", "720p": "22", "1080p": "bv[width==1080]+ba[ext=webm]/bv[width==1080]+ba[ext=m4a]/bv[width==1080]+ba", "1440p": "bv[width==1440]+ba[ext=webm]/bv[width==1440]+ba[ext=m4a]/bv[width==1440]+ba", @@ -102,9 +102,13 @@ class YTDLCog(commands.Cog): :return: The created hash key """ snip = snip or "*" - await self._init_db() + _hash = hashlib.md5(f"{webpage_url}:{format_id}:{snip}".encode()).hexdigest() + try: + await self._init_db() + except Exception as e: + logging.error("Failed to initialise ytdl database: %s", e, exc_info=True) + return async with aiosqlite.connect("./data/ytdl.db") as db: - _hash = hashlib.md5(f"{webpage_url}:{format_id}:{snip}".encode()).hexdigest() self.log.debug( "Saving %r (%r:%r:%r) with message %d>%d, index %d", _hash, @@ -137,7 +141,11 @@ class YTDLCog(commands.Cog): :param snip: The start and end time to snip the video. e.g. 00:00:00-00:10:00 :return: the URL, if found and valid. """ - await self._init_db() + try: + await self._init_db() + except Exception as e: + logging.error("Failed to initialise ytdl database: %s", e, exc_info=True) + return async with aiosqlite.connect("./data/ytdl.db") as db: _hash = hashlib.md5(f"{webpage_url}:{format_id}:{snip}".encode()).hexdigest() self.log.debug( diff --git a/src/conf.py b/src/conf.py index 2a5e7fd..1518de7 100644 --- a/src/conf.py +++ b/src/conf.py @@ -28,10 +28,8 @@ try: CONFIG.setdefault("logging", {}) CONFIG.setdefault("jimmy", {}) CONFIG.setdefault("ollama", {}) - CONFIG.setdefault("rss", {"meta": {"channel": None}}) CONFIG.setdefault("screenshot", {}) CONFIG.setdefault("quote_a", {"channel": None}) - CONFIG.setdefault("server", {"host": "0.0.0.0", "port": 8080, "channel": 1032974266527907901}) CONFIG.setdefault("redis", {"host": "redis", "port": 6379, "decode_responses": True}) except FileNotFoundError: cwd = Path.cwd() diff --git a/src/main.py b/src/main.py index bd57890..5d16fba 100644 --- a/src/main.py +++ b/src/main.py @@ -179,6 +179,14 @@ async def delete_message(ctx: discord.ApplicationContext, message: discord.Messa await ctx.delete(delay=15) +@bot.check_once +async def check_is_enabled(ctx: commands.Context | discord.ApplicationContext) -> bool: + disabled = CONFIG["jimmy"].get("disabled_commands", []) + if ctx.command.qualified_name in disabled: + raise commands.DisabledCommand("%s is disabled via this instance's configuration file.") + return True + + if not CONFIG["jimmy"].get("token"): log.critical("No token specified in config.toml. Exiting. (hint: set jimmy.token in config.toml)") sys.exit(1)