mirror of
https://github.com/polyjitter/searchbot-discord.git
synced 2024-08-14 22:46:55 +00:00
New get_webhook and logging features
This commit is contained in:
parent
7ae19ef8a6
commit
a824c068e7
4 changed files with 254 additions and 100 deletions
|
@ -19,6 +19,8 @@ class Search(commands.Cog):
|
|||
|
||||
# Main Stuff
|
||||
self.bot = bot
|
||||
self.info = bot.logging.info
|
||||
self.warn = bot.logging.warn
|
||||
self.request = bot.request
|
||||
self.instances = bot.instances
|
||||
self.emoji = "\U0001F50D"
|
||||
|
@ -57,7 +59,6 @@ class Search(commands.Cog):
|
|||
with open('searxes.txt') as f:
|
||||
self.instances = f.read().split('\n')
|
||||
instance = random.sample(self.instances, k=1)[0]
|
||||
print(f"Attempting to use {instance}")
|
||||
|
||||
# Error Template
|
||||
error_msg = (
|
||||
|
@ -81,9 +82,6 @@ class Search(commands.Cog):
|
|||
# Figure out engines for different categories to get decent results.
|
||||
if category == 'videos':
|
||||
call += '&engines=bing+videos,google+videos'
|
||||
|
||||
print(call)
|
||||
|
||||
# Make said API call
|
||||
try:
|
||||
async with self.request.get(call) as resp:
|
||||
|
@ -121,17 +119,21 @@ class Search(commands.Cog):
|
|||
# Instance Info
|
||||
msg += f"\n\n_Results retrieved from instance `{instance}`._"
|
||||
|
||||
return msg
|
||||
|
||||
# Reached if error with returned results
|
||||
except (KeyError, IndexError) as e:
|
||||
# Logging
|
||||
print(f"{e} with instance {instance}, trying again.")
|
||||
self.warn(
|
||||
f"A user encountered a(n) `{e}` with <{instance}> when searching for `{query}`. "
|
||||
"Consider removing it or looking into it.",
|
||||
name="Failed Instance"
|
||||
)
|
||||
|
||||
self.instances.remove(instance) # Weed the instance out
|
||||
# Recurse until good response
|
||||
return await self._search_logic(query, is_nsfw)
|
||||
|
||||
return msg
|
||||
|
||||
async def _instance_check(self, instance, info):
|
||||
"""Checks the quality of an instance."""
|
||||
|
||||
|
@ -172,84 +174,94 @@ class Search(commands.Cog):
|
|||
async def search(self, ctx, *, query: str):
|
||||
"""Search online for general results."""
|
||||
|
||||
# Logging
|
||||
print(f"\n\nNEW CALL: {ctx.author} from {ctx.guild}.\n")
|
||||
|
||||
# Handling
|
||||
async with ctx.typing():
|
||||
msg = await self._search_logic(query, ctx.channel.is_nsfw())
|
||||
await self.info(
|
||||
content=f"**{ctx.author}** searched for `{query}` in \"{ctx.guild}\" and got this:"
|
||||
f"\n\n{msg}",
|
||||
name="Search Results"
|
||||
)
|
||||
await ctx.send(msg)
|
||||
|
||||
@commands.command(aliases=['video'])
|
||||
async def videos(self, ctx, *, query: str):
|
||||
"""Search online for videos."""
|
||||
|
||||
# Logging
|
||||
print(f"\n\nNEW VIDEO CALL: {ctx.author} from {ctx.guild}.\n")
|
||||
|
||||
# Handling
|
||||
async with ctx.typing():
|
||||
msg = await self._search_logic(query, ctx.channel.is_nsfw(), 'videos')
|
||||
await self.info(
|
||||
content=f"**{ctx.author}** searched for `{query}` videos in \"{ctx.guild}\" and got this:"
|
||||
f"\n\n{msg}",
|
||||
name="Search Results"
|
||||
)
|
||||
await ctx.send(msg)
|
||||
|
||||
@commands.command()
|
||||
async def music(self, ctx, *, query: str):
|
||||
"""Search online for music."""
|
||||
|
||||
# Logging
|
||||
print(f"\n\nNEW MUSIC CALL: {ctx.author} from {ctx.guild}.\n")
|
||||
|
||||
# Handling
|
||||
async with ctx.typing():
|
||||
msg = await self._search_logic(query, ctx.channel.is_nsfw(), 'music')
|
||||
await self.info(
|
||||
content=f"**{ctx.author}** searched for `{query}` music in \"{ctx.guild}\" and got this:"
|
||||
f"\n\n{msg}",
|
||||
name="Search Results"
|
||||
)
|
||||
await ctx.send(msg)
|
||||
|
||||
@commands.command(aliases=['file'])
|
||||
async def files(self, ctx, *, query: str):
|
||||
"""Search online for files."""
|
||||
|
||||
# Logging
|
||||
print(f"\n\nNEW FILES CALL: {ctx.author} from {ctx.guild}.\n")
|
||||
|
||||
# Handling
|
||||
async with ctx.typing():
|
||||
msg = await self._search_logic(query, ctx.channel.is_nsfw(), 'files')
|
||||
await self.info(
|
||||
content=f"**{ctx.author}** searched for `{query}` files in \"{ctx.guild}\" and got this:"
|
||||
f"\n\n{msg}",
|
||||
name="Search Results"
|
||||
)
|
||||
await ctx.send(msg)
|
||||
|
||||
@commands.command(aliases=['image'])
|
||||
async def images(self, ctx, *, query: str):
|
||||
"""Search online for images."""
|
||||
|
||||
# Logging
|
||||
print(f"\n\nNEW IMAGES CALL: {ctx.author} from {ctx.guild}.\n")
|
||||
|
||||
# Handling
|
||||
async with ctx.typing():
|
||||
msg = await self._search_logic(query, ctx.channel.is_nsfw(), 'images')
|
||||
await self.info(
|
||||
content=f"**{ctx.author}** searched for `{query}` images in \"{ctx.guild}\" and got this:"
|
||||
f"\n\n{msg}",
|
||||
name="Search Results"
|
||||
)
|
||||
await ctx.send(msg)
|
||||
|
||||
@commands.command()
|
||||
async def it(self, ctx, *, query: str):
|
||||
"""Search online for IT-related information."""
|
||||
|
||||
# Logging
|
||||
print(f"\n\nNEW IT CALL: {ctx.author} from {ctx.guild}.\n")
|
||||
|
||||
# Handling
|
||||
async with ctx.typing():
|
||||
msg = await self._search_logic(query, ctx.channel.is_nsfw(), 'it')
|
||||
await self.info(
|
||||
content=f"**{ctx.author}** searched for `{query}` IT in \"{ctx.guild}\" and got this:"
|
||||
f"\n\n{msg}",
|
||||
name="Search Results"
|
||||
)
|
||||
await ctx.send(msg)
|
||||
|
||||
@commands.command(aliases=['map'])
|
||||
async def maps(self, ctx, *, query: str):
|
||||
"""Search online for map information."""
|
||||
|
||||
# Logging
|
||||
print(f"\n\nNEW MAP CALL: {ctx.author} from {ctx.guild}.\n")
|
||||
|
||||
# Handling
|
||||
async with ctx.typing():
|
||||
msg = await self._search_logic(query, ctx.channel.is_nsfw(), 'map')
|
||||
await self.info(
|
||||
content=f"**{ctx.author}** searched for `{query}` maps in \"{ctx.guild}\" and got this:"
|
||||
f"\n\n{msg}",
|
||||
name="Search Results"
|
||||
)
|
||||
await ctx.send(msg)
|
||||
|
||||
@commands.command()
|
||||
|
@ -287,9 +299,7 @@ class Search(commands.Cog):
|
|||
|
||||
if isinstance(error, commands.CommandNotFound) or \
|
||||
isinstance(error, commands.CheckFailure):
|
||||
# Logging
|
||||
print(f"\n\nNEW CALL: {ctx.author} from {ctx.guild}.\n")
|
||||
|
||||
|
||||
# Handling
|
||||
async with ctx.typing():
|
||||
# Prepares term
|
||||
|
@ -297,6 +307,15 @@ class Search(commands.Cog):
|
|||
term = term.lstrip(' ')
|
||||
# Does search
|
||||
msg = await self._search_logic(term, ctx.channel.is_nsfw())
|
||||
|
||||
# Logging
|
||||
await self.info(
|
||||
content=f"**{ctx.author}** searched for `{term}` in \"{ctx.guild}\" and got this:"
|
||||
f"\n\n{msg}",
|
||||
name="Search Results"
|
||||
)
|
||||
|
||||
|
||||
# Sends result
|
||||
await ctx.send(msg)
|
||||
|
||||
|
|
181
extensions/utils/logging.py
Normal file
181
extensions/utils/logging.py
Normal file
|
@ -0,0 +1,181 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# tacibot logging util
|
||||
# Provides utils for logging via webhooks.
|
||||
|
||||
'''Online File'''
|
||||
|
||||
import discord
|
||||
from discord.ext.commands import Context
|
||||
import traceback
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Logging():
|
||||
"""Provides logging utilities for bots."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.request = bot.request
|
||||
self.online = bot.online
|
||||
self.maintenance = bot.maintenance
|
||||
|
||||
# Sets info hook first
|
||||
self.info_hook = self.online.get_webhook(
|
||||
bot.config['INFO_HOOK'] if bot.config['INFO_HOOK']
|
||||
else None
|
||||
)
|
||||
|
||||
# Sets other hooks or defaults them
|
||||
if self.info_hook:
|
||||
self.warn_hook = self.online.get_webhook(
|
||||
bot.config['WARN_HOOK'] if bot.config['WARN_HOOK']
|
||||
else self.info_hook
|
||||
)
|
||||
self.error_hook = self.online.get_webhook(
|
||||
bot.config['ERROR_HOOK'] if bot.config['ERROR_HOOK']
|
||||
else self.info_hook
|
||||
)
|
||||
self.debug_hook = self.online.get_webhook(
|
||||
bot.config['DEBUG_HOOK'] if bot.config['DEBUG_HOOK']
|
||||
else self.info_hook
|
||||
)
|
||||
|
||||
# If no hooks, nothing is there
|
||||
else:
|
||||
self.warn_hook = self.error_hook = self.debug_hook = None
|
||||
|
||||
async def _create_error_embed(self, error: Exception, ctx: Context):
|
||||
"""Creates a new basic error embed."""
|
||||
|
||||
# Prerequisites
|
||||
formatted_tb = traceback.format_tb(error.__traceback__)
|
||||
formatted_tb = ''.join(formatted_tb)
|
||||
original_exc = traceback.format_exception(
|
||||
type(error), error, error.__traceback__)
|
||||
print(original_exc)
|
||||
|
||||
# Hastebins Traceback
|
||||
try:
|
||||
url = await self.online.hastebin(
|
||||
''.join(original_exc))
|
||||
except Exception as e:
|
||||
url = None
|
||||
print(e)
|
||||
|
||||
# Embed Building
|
||||
error_embed = discord.Embed(
|
||||
title=(
|
||||
f"{type(error).__name__} "
|
||||
f"{'(Click for Hastebin)' if url else ''}"
|
||||
),
|
||||
url=url if url else None,
|
||||
color=0xFF0000
|
||||
)
|
||||
|
||||
# Formats Traceback
|
||||
trace_content = (
|
||||
"```py\n\nTraceback (most recent call last):"
|
||||
"\n{}{}: {}```").format(
|
||||
formatted_tb,
|
||||
type(error).__name__,
|
||||
error)
|
||||
|
||||
# Adds Traceback
|
||||
error_embed.add_field(
|
||||
name=(
|
||||
f"`{type(error).__name__}` in "
|
||||
f"command `{ctx.command.qualified_name}`"
|
||||
),
|
||||
value=(trace_content[:1018] + '...```')
|
||||
if len(trace_content) > 1024
|
||||
else trace_content
|
||||
)
|
||||
|
||||
# Provides completed embed
|
||||
return error_embed
|
||||
|
||||
async def info(self, content: str,
|
||||
embed: Optional[discord.Embed] = None,
|
||||
name: Optional[str] = None):
|
||||
"""Logs info and sends it to the appropriate places."""
|
||||
|
||||
if self.info_hook:
|
||||
return await self.info_hook.send(
|
||||
content=content,
|
||||
username=f"{self.bot.user.name} - {name if name else 'unknown'}",
|
||||
avatar_url=str(self.bot.user.avatar_url),
|
||||
embed=embed
|
||||
)
|
||||
else:
|
||||
return
|
||||
|
||||
async def warn(self, content: str,
|
||||
embed: Optional[discord.Embed] = None,
|
||||
name: Optional[str] = None):
|
||||
"""Logs warnings and sends them to the appropriate places."""
|
||||
|
||||
if self.warn_hook:
|
||||
return await self.warn_hook.send(
|
||||
content=content,
|
||||
username=f"{self.bot.user.name} - {name if name else 'unknown'}",
|
||||
avatar_url=str(self.bot.user.avatar_url),
|
||||
embed=embed
|
||||
)
|
||||
else:
|
||||
return
|
||||
|
||||
async def error(self, error: Exception, ctx: Context, name: Optional[str]):
|
||||
"""Logs errors and sends them to the appropriate places."""
|
||||
|
||||
# Prerequisites
|
||||
error_embed = await self._create_error_embed(error, ctx)
|
||||
|
||||
# Log and say so
|
||||
if self.error_hook:
|
||||
|
||||
# Log
|
||||
fallback = (
|
||||
f"**{ctx.author}** encountered a(n) "
|
||||
f"`{type(error).__name__}` when attempting to use "
|
||||
f"`{ctx.command}`."
|
||||
)
|
||||
await self.error_hook.send(
|
||||
content=fallback,
|
||||
username=f"{self.bot.user.name} - {name if name else 'unknown'}",
|
||||
avatar_url=str(self.bot.user.avatar_url),
|
||||
embed=error_embed
|
||||
)
|
||||
|
||||
# Say so
|
||||
is_reported = "has been automatically reported, but"
|
||||
|
||||
# Say hasn't been logged
|
||||
else:
|
||||
is_reported = "has not been automatically reported, so"
|
||||
|
||||
# Added reported info and return
|
||||
error_embed.description = (
|
||||
f"This is (probably) a bug. This {is_reported} "
|
||||
f"please give **{self.bot.appinfo.owner}** a heads-up in DMs."
|
||||
)
|
||||
return error_embed
|
||||
|
||||
async def debug(self, content: str,
|
||||
embed: Optional[discord.Embed] = None,
|
||||
name: Optional[str] = None):
|
||||
"""Logs warnings and sends them to the appropriate places."""
|
||||
|
||||
if self.debug_hook and self.maintenance:
|
||||
return await self.debug_hook.send(
|
||||
content=content,
|
||||
username=f"{self.bot.user.name} - {name if name else 'unknown'}",
|
||||
avatar_url=str(self.bot.user.avatar_url),
|
||||
embed=embed
|
||||
)
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.logging = Logging(bot)
|
|
@ -5,7 +5,12 @@
|
|||
|
||||
'''Online File'''
|
||||
|
||||
import discord
|
||||
|
||||
|
||||
class Online():
|
||||
"""Provides various online utilities for your bot."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.request = bot.request
|
||||
|
@ -18,11 +23,16 @@ class Online():
|
|||
async with self.request.post(url=url, data=data) as haste_response:
|
||||
haste_key = (await haste_response.json())['key']
|
||||
haste_url = f"http://hastebin.com/{haste_key}"
|
||||
# data = {'sprunge': ''}
|
||||
# data['sprunge'] = string
|
||||
# haste_url = await self.aioclient.post(url='http://sprunge.us',
|
||||
# data=data)
|
||||
return haste_url
|
||||
|
||||
def get_webhook(self, url: str):
|
||||
"""Easily gets a webhook from a url."""
|
||||
|
||||
return discord.Webhook.from_url(
|
||||
url,
|
||||
adapter=discord.AsyncWebhookAdapter(self.request)
|
||||
)
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.online = Online(bot)
|
||||
|
|
66
main.py
66
main.py
|
@ -14,18 +14,15 @@ import json
|
|||
import os
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import logging
|
||||
import random
|
||||
|
||||
|
||||
class Bot(commands.Bot):
|
||||
"""Custom Bot Class that subclasses the commands.ext one"""
|
||||
|
||||
def __init__(self, **options):
|
||||
"""Initializes the main parts of the bot."""
|
||||
|
||||
# Logging
|
||||
print('Initializing...\n')
|
||||
|
||||
# Initializes parent class
|
||||
super().__init__(self._get_prefix_new, **options)
|
||||
|
||||
|
@ -43,8 +40,6 @@ class Bot(commands.Bot):
|
|||
with open('searxes.txt') as f:
|
||||
self.instances = f.read().split('\n')
|
||||
|
||||
# Logging
|
||||
|
||||
def _init_extensions(self):
|
||||
"""Initializes extensions."""
|
||||
|
||||
|
@ -163,73 +158,22 @@ async def on_command_error(ctx, error):
|
|||
|
||||
# Lets other cogs handle CommandNotFound.
|
||||
# Change this if you want command not found handling
|
||||
if isinstance(error, commands.CommandNotFound):
|
||||
if isinstance(error, commands.CommandNotFound)or isinstance(error, commands.CheckFailure):
|
||||
return
|
||||
|
||||
# Provides a very pretty embed if something's actually a dev's fault.
|
||||
elif isinstance(error, commands.CommandInvokeError):
|
||||
|
||||
# Prerequisites
|
||||
original_error = error.original
|
||||
traceback_orig = traceback.format_tb(original_error.__traceback__)
|
||||
traceback_orig = ''.join(traceback_orig)
|
||||
appinfo = await bot.application_info()
|
||||
original_exc = traceback.format_exception(
|
||||
type(original_error), original_error, original_error.__traceback__)
|
||||
print(original_exc)
|
||||
|
||||
# Main Message
|
||||
embed_fallback = f"**An error occured: {type(original_error).__name__}. Please contact {appinfo.owner}.**"
|
||||
|
||||
# Hastebins Traceback
|
||||
try:
|
||||
url = await bot.online.hastebin(
|
||||
''.join(original_exc))
|
||||
except Exception as e:
|
||||
url = None
|
||||
print(e)
|
||||
|
||||
# Embed Building
|
||||
error_embed = discord.Embed(
|
||||
title=(
|
||||
f"{type(original_error).__name__} "
|
||||
f"{'(Click for Hastebin)' if url else ''}"
|
||||
),
|
||||
url=url if url else None,
|
||||
color=0xFF0000,
|
||||
description=( # TODO Change if has logging
|
||||
"This is (probably) a bug. This has not been automatically "
|
||||
f"reported, so please give **{appinfo.owner}** a heads-up in DMs.")
|
||||
)
|
||||
|
||||
# Formats Traceback
|
||||
trace_content = (
|
||||
"```py\n\nTraceback (most recent call last):"
|
||||
"\n{}{}: {}```").format(
|
||||
traceback_orig,
|
||||
type(original_error).__name__,
|
||||
original_error)
|
||||
|
||||
# Adds Traceback
|
||||
error_embed.add_field(
|
||||
name=(
|
||||
f"`{type(original_error).__name__}` in "
|
||||
f"command `{ctx.command.qualified_name}`"
|
||||
),
|
||||
value=(trace_content[:1018] + '...```')
|
||||
if len(trace_content) > 1024
|
||||
else trace_content
|
||||
)
|
||||
embed_fallback = f"**An error occured: {type(error).__name__}. Please contact {bot.appinfo.owner}.**"
|
||||
error_embed = await bot.logging.error(error, ctx, ctx.command.cog.__name__)
|
||||
|
||||
# Sending
|
||||
await ctx.send(embed_fallback, embed=error_embed)
|
||||
|
||||
# If anything else goes wrong, just go ahead and send it in chat.
|
||||
else:
|
||||
original_error = error
|
||||
original_exc = traceback.format_exception(
|
||||
type(original_error), original_error, original_error.__traceback__)
|
||||
print(''.join(original_exc))
|
||||
await bot.logging.error(error, ctx, ctx.command.cog.__name__)
|
||||
await ctx.send(error)
|
||||
# NOTE Bot Entry Point
|
||||
# Starts the bot
|
||||
|
|
Loading…
Reference in a new issue