2022-02-21 07:10:57 +00:00
|
|
|
import urlextract
|
|
|
|
import hikari
|
|
|
|
import lightbulb
|
|
|
|
import pysaucenao
|
|
|
|
|
|
|
|
from tools import components, scraper
|
|
|
|
|
|
|
|
|
2022-02-21 20:53:53 +00:00
|
|
|
plugin = lightbulb.Plugin("booru")
|
2022-02-21 07:10:57 +00:00
|
|
|
extractor = urlextract.URLExtract()
|
|
|
|
|
|
|
|
|
|
|
|
@plugin.command
|
2023-03-07 02:38:21 +00:00
|
|
|
@lightbulb.option(
|
|
|
|
"ephemeral",
|
|
|
|
"Respond ephemerally (only visible to invoker) or in current channel",
|
|
|
|
type=hikari.OptionType.BOOLEAN,
|
|
|
|
default=True,
|
|
|
|
)
|
|
|
|
@lightbulb.option("attachment", "Attachment to reverse", type=hikari.OptionType.ATTACHMENT, default=None)
|
|
|
|
@lightbulb.option("url", "URL(s) to reverse, separated by space", default=None)
|
|
|
|
@lightbulb.command("reverse", "Reverse image search using SauceNAO & Kheina")
|
2022-02-21 07:10:57 +00:00
|
|
|
@lightbulb.implements(lightbulb.SlashCommand, lightbulb.MessageCommand)
|
|
|
|
async def reverse(context):
|
|
|
|
match context:
|
|
|
|
case lightbulb.SlashContext():
|
2023-03-07 02:38:21 +00:00
|
|
|
urls = extractor.find_urls(
|
|
|
|
f"{context.options.url} {context.options.attachment.url if context.options.attachment else None}",
|
|
|
|
only_unique=True,
|
|
|
|
with_schema_only=True,
|
|
|
|
)
|
2022-02-21 07:10:57 +00:00
|
|
|
|
|
|
|
if not urls:
|
2023-03-07 02:38:21 +00:00
|
|
|
await context.respond("***Invalid URL(s)***", flags=hikari.MessageFlag.EPHEMERAL)
|
2022-02-21 07:10:57 +00:00
|
|
|
return
|
|
|
|
|
2023-03-07 02:38:21 +00:00
|
|
|
await _reverse(context, urls, ephemeral=context.options.ephemeral)
|
2022-02-21 07:10:57 +00:00
|
|
|
case lightbulb.MessageContext():
|
2022-02-21 20:53:53 +00:00
|
|
|
urls = extractor.find_urls(context.options.target.content or "", only_unique=True, with_schema_only=True)
|
2022-02-21 07:10:57 +00:00
|
|
|
urls += [attachment.url for attachment in context.options.target.attachments if attachment.url not in urls]
|
|
|
|
|
|
|
|
if not urls:
|
2023-03-07 02:38:21 +00:00
|
|
|
await context.respond("***No images found***", flags=hikari.MessageFlag.EPHEMERAL)
|
2022-02-21 07:10:57 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
selector = None
|
|
|
|
|
|
|
|
if len(urls) > 1:
|
|
|
|
selector = components.Selector(
|
2023-03-07 02:39:11 +00:00
|
|
|
pages=[f"**Select images to search: `{urls.index(url) + 1}/{len(urls)}`**\n{url}" for url in urls],
|
2022-02-21 19:41:01 +00:00
|
|
|
buttons=[components.Back(), components.Forward(), components.Select(), components.Confirm()],
|
2022-02-21 20:53:53 +00:00
|
|
|
urls=urls,
|
2022-02-21 19:41:01 +00:00
|
|
|
)
|
2022-02-21 07:10:57 +00:00
|
|
|
|
|
|
|
await selector.send(context.interaction, ephemeral=True)
|
|
|
|
await selector.wait()
|
|
|
|
|
|
|
|
if selector.timed_out:
|
2022-03-04 05:57:35 +00:00
|
|
|
await context.interaction.edit_initial_response("***Timed out***", components=None)
|
2022-02-21 07:10:57 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
urls = selector.selected
|
|
|
|
|
|
|
|
await _reverse(context, urls, selector=selector)
|
|
|
|
|
2022-02-21 20:53:53 +00:00
|
|
|
|
2022-03-04 05:59:46 +00:00
|
|
|
# Listener for reverse exceptions
|
2022-02-21 07:10:57 +00:00
|
|
|
@reverse.set_error_handler()
|
|
|
|
async def on_reverse_error(event):
|
|
|
|
error = None
|
|
|
|
|
|
|
|
match event.exception.__cause__:
|
|
|
|
case pysaucenao.ShortLimitReachedException():
|
2022-03-04 05:57:35 +00:00
|
|
|
error = "***API limit reached. Please try again in a minute***"
|
2022-02-21 07:10:57 +00:00
|
|
|
case pysaucenao.DailyLimitReachedException():
|
2022-03-04 05:57:35 +00:00
|
|
|
error = "***Daily API limit reached. Please try again tomorrow***"
|
2022-02-21 07:10:57 +00:00
|
|
|
case pysaucenao.FileSizeLimitException() as url:
|
2022-03-04 05:57:35 +00:00
|
|
|
error = f"***Image file size too large***\n{url}"
|
2022-02-21 07:10:57 +00:00
|
|
|
case pysaucenao.ImageSizeException() as url:
|
2022-03-04 05:57:35 +00:00
|
|
|
error = f"***Image resolution too small***\n{url}"
|
2022-02-21 07:10:57 +00:00
|
|
|
case pysaucenao.InvalidImageException() as url:
|
2022-03-04 05:57:35 +00:00
|
|
|
error = f"***Invalid image***\n{url}"
|
2022-02-21 07:10:57 +00:00
|
|
|
case pysaucenao.UnknownStatusCodeException():
|
2022-03-04 05:57:35 +00:00
|
|
|
error = "***An unknown SauceNAO error has occurred. The service may be down***"
|
2022-02-21 07:10:57 +00:00
|
|
|
|
|
|
|
if error:
|
2022-02-21 19:38:38 +00:00
|
|
|
try:
|
2022-03-04 06:03:46 +00:00
|
|
|
await event.context.respond(error, flags=hikari.MessageFlag.EPHEMERAL)
|
2022-02-21 19:38:38 +00:00
|
|
|
except:
|
|
|
|
await event.context.interaction.edit_initial_response(error, components=None)
|
|
|
|
|
2022-02-21 07:10:57 +00:00
|
|
|
return True
|
|
|
|
|
2022-02-21 20:53:53 +00:00
|
|
|
|
2022-03-04 05:59:46 +00:00
|
|
|
# Reverse images and respond
|
2023-03-07 02:38:21 +00:00
|
|
|
async def _reverse(context, urls, *, selector=None, ephemeral=True):
|
2022-02-21 07:10:57 +00:00
|
|
|
if not selector:
|
2023-03-07 02:38:21 +00:00
|
|
|
await context.respond(
|
|
|
|
hikari.ResponseType.DEFERRED_MESSAGE_CREATE,
|
|
|
|
flags=hikari.MessageFlag.EPHEMERAL if ephemeral else hikari.MessageFlag.NONE,
|
|
|
|
)
|
2022-02-21 07:10:57 +00:00
|
|
|
|
|
|
|
matches = await scraper.reverse(urls)
|
|
|
|
|
|
|
|
if not matches:
|
|
|
|
if selector:
|
2022-03-04 05:57:35 +00:00
|
|
|
await context.interaction.edit_initial_response("***No matches found***", components=None)
|
2022-02-21 07:10:57 +00:00
|
|
|
else:
|
2023-03-07 02:38:21 +00:00
|
|
|
await context.respond("***No matches found***", flags=hikari.MessageFlag.EPHEMERAL)
|
2022-02-21 07:10:57 +00:00
|
|
|
return
|
|
|
|
|
2022-02-21 20:53:53 +00:00
|
|
|
pages = [
|
|
|
|
(
|
|
|
|
hikari.Embed(
|
2022-02-22 23:22:50 +00:00
|
|
|
title=match["artist"],
|
|
|
|
url=match["url"],
|
|
|
|
color=context.get_guild().get_my_member().get_top_role().color if context.get_guild() else "#1a1a1a",
|
2022-02-21 20:53:53 +00:00
|
|
|
)
|
2022-02-23 23:47:12 +00:00
|
|
|
.set_author(name=f"{match['similarity']}% Match")
|
2022-02-21 20:53:53 +00:00
|
|
|
.set_image(match["thumbnail"])
|
|
|
|
.set_footer(match["source"])
|
|
|
|
)
|
|
|
|
if match
|
2022-03-04 05:57:35 +00:00
|
|
|
else f"***No match found***\n{urls[index]}"
|
2022-02-21 20:53:53 +00:00
|
|
|
for index, match in enumerate(matches)
|
|
|
|
]
|
2022-02-21 07:10:57 +00:00
|
|
|
|
|
|
|
if len(pages) > 1:
|
2022-03-04 06:03:14 +00:00
|
|
|
selector = components.Selector(
|
|
|
|
pages=pages,
|
|
|
|
buttons=[components.Back(), components.Forward()],
|
|
|
|
timeout=600,
|
|
|
|
)
|
2022-02-21 07:10:57 +00:00
|
|
|
|
|
|
|
await selector.send_edit(context.interaction)
|
|
|
|
else:
|
|
|
|
if selector:
|
2022-03-07 04:19:22 +00:00
|
|
|
if isinstance(pages[0], hikari.Embed):
|
|
|
|
await context.interaction.edit_initial_response(content=None, embed=pages[0], components=None)
|
|
|
|
else:
|
|
|
|
await context.interaction.edit_initial_response(pages[0], components=None)
|
2022-02-21 07:10:57 +00:00
|
|
|
else:
|
2023-03-07 02:38:21 +00:00
|
|
|
await context.respond(
|
|
|
|
pages[0], flags=hikari.MessageFlag.EPHEMERAL if ephemeral else hikari.MessageFlag.NONE
|
|
|
|
)
|
2022-02-21 07:10:57 +00:00
|
|
|
|
2022-02-21 20:53:53 +00:00
|
|
|
|
2022-02-21 07:10:57 +00:00
|
|
|
def load(bot):
|
|
|
|
bot.add_plugin(plugin)
|
2022-02-21 20:53:53 +00:00
|
|
|
|
|
|
|
|
2022-02-21 07:10:57 +00:00
|
|
|
def unload(bot):
|
|
|
|
bot.remove_plugin(plugin)
|