booru
This commit is contained in:
parent
2f09b99d0b
commit
2eaadf2208
9 changed files with 224 additions and 31 deletions
|
@ -8,6 +8,7 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"booru": "^2.6.8",
|
||||||
"discord.js": "^14.16.3",
|
"discord.js": "^14.16.3",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"groq-sdk": "^0.7.0"
|
"groq-sdk": "^0.7.0"
|
||||||
|
|
|
@ -8,6 +8,9 @@ importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
booru:
|
||||||
|
specifier: ^2.6.8
|
||||||
|
version: 2.6.8
|
||||||
discord.js:
|
discord.js:
|
||||||
specifier: ^14.16.3
|
specifier: ^14.16.3
|
||||||
version: 14.16.3
|
version: 14.16.3
|
||||||
|
@ -17,9 +20,6 @@ importers:
|
||||||
groq-sdk:
|
groq-sdk:
|
||||||
specifier: ^0.7.0
|
specifier: ^0.7.0
|
||||||
version: 0.7.0
|
version: 0.7.0
|
||||||
uwuifier:
|
|
||||||
specifier: ^4.2.2
|
|
||||||
version: 4.2.2
|
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
@ -90,6 +90,10 @@ packages:
|
||||||
asynckit@0.4.0:
|
asynckit@0.4.0:
|
||||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
|
|
||||||
|
booru@2.6.8:
|
||||||
|
resolution: {integrity: sha512-/MN9Q5Yd3jBvOXgG05SLsdbGHFUWx6yoLYKU0xIoTWDsNlliUqM8Aj581pBujqFhg4E/Pi9cHdpMRN/FqustUA==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
combined-stream@1.0.8:
|
||||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
@ -122,6 +126,10 @@ packages:
|
||||||
fast-deep-equal@3.1.3:
|
fast-deep-equal@3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
|
|
||||||
|
fast-xml-parser@4.5.0:
|
||||||
|
resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
form-data-encoder@1.7.2:
|
form-data-encoder@1.7.2:
|
||||||
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
|
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
|
||||||
|
|
||||||
|
@ -172,6 +180,9 @@ packages:
|
||||||
encoding:
|
encoding:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
strnum@1.0.5:
|
||||||
|
resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
|
||||||
|
|
||||||
tr46@0.0.3:
|
tr46@0.0.3:
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||||
|
|
||||||
|
@ -191,9 +202,6 @@ packages:
|
||||||
resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==}
|
resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==}
|
||||||
engines: {node: '>=18.17'}
|
engines: {node: '>=18.17'}
|
||||||
|
|
||||||
uwuifier@4.2.2:
|
|
||||||
resolution: {integrity: sha512-Fhtj3Yg3rrDTEs+L1fqkgM3VYGJrP4U9GY+4fPdw08T5kzOB8NSosZnZfa5Zhv1Hh7NCpH5G6t1DIZyM1wPK1w==}
|
|
||||||
|
|
||||||
web-streams-polyfill@4.0.0-beta.3:
|
web-streams-polyfill@4.0.0-beta.3:
|
||||||
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
@ -303,6 +311,11 @@ snapshots:
|
||||||
|
|
||||||
asynckit@0.4.0: {}
|
asynckit@0.4.0: {}
|
||||||
|
|
||||||
|
booru@2.6.8:
|
||||||
|
dependencies:
|
||||||
|
fast-xml-parser: 4.5.0
|
||||||
|
undici: 6.19.8
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
combined-stream@1.0.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream: 1.0.0
|
delayed-stream: 1.0.0
|
||||||
|
@ -339,6 +352,10 @@ snapshots:
|
||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
|
fast-xml-parser@4.5.0:
|
||||||
|
dependencies:
|
||||||
|
strnum: 1.0.5
|
||||||
|
|
||||||
form-data-encoder@1.7.2: {}
|
form-data-encoder@1.7.2: {}
|
||||||
|
|
||||||
form-data@4.0.0:
|
form-data@4.0.0:
|
||||||
|
@ -388,6 +405,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url: 5.0.0
|
whatwg-url: 5.0.0
|
||||||
|
|
||||||
|
strnum@1.0.5: {}
|
||||||
|
|
||||||
tr46@0.0.3: {}
|
tr46@0.0.3: {}
|
||||||
|
|
||||||
ts-mixer@6.0.4: {}
|
ts-mixer@6.0.4: {}
|
||||||
|
@ -400,8 +419,6 @@ snapshots:
|
||||||
|
|
||||||
undici@6.19.8: {}
|
undici@6.19.8: {}
|
||||||
|
|
||||||
uwuifier@4.2.2: {}
|
|
||||||
|
|
||||||
web-streams-polyfill@4.0.0-beta.3: {}
|
web-streams-polyfill@4.0.0-beta.3: {}
|
||||||
|
|
||||||
webidl-conversions@3.0.1: {}
|
webidl-conversions@3.0.1: {}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType, AttachmentBuilder, EmbedBuilder } = require('discord.js');
|
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType, AttachmentBuilder, EmbedBuilder } = require("discord.js");
|
||||||
|
|
||||||
const data = new ContextMenuCommandBuilder()
|
const data = new ContextMenuCommandBuilder()
|
||||||
.setName('Describe Image(s)')
|
.setName("Describe Image(s)")
|
||||||
.setType(ApplicationCommandType.Message)
|
.setType(ApplicationCommandType.Message)
|
||||||
.setContexts([
|
.setContexts([
|
||||||
InteractionContextType.Guild,
|
InteractionContextType.Guild,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require('discord.js');
|
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
|
||||||
|
|
||||||
const data = new ContextMenuCommandBuilder()
|
const data = new ContextMenuCommandBuilder()
|
||||||
.setName('Summarize')
|
.setName("Summarize")
|
||||||
.setType(ApplicationCommandType.Message)
|
.setType(ApplicationCommandType.Message)
|
||||||
.setContexts([
|
.setContexts([
|
||||||
InteractionContextType.Guild,
|
InteractionContextType.Guild,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const { InteractionContextType, ApplicationIntegrationType, SlashCommandBuilder, EmbedBuilder } = require('discord.js');
|
const { InteractionContextType, ApplicationIntegrationType, SlashCommandBuilder, EmbedBuilder } = require("discord.js");
|
||||||
|
|
||||||
const data = new SlashCommandBuilder()
|
const data = new SlashCommandBuilder()
|
||||||
.setName('prompt')
|
.setName("prompt")
|
||||||
.setDescription("Prompt an AI model with data")
|
.setDescription("Prompt an AI model with data")
|
||||||
.addStringOption(builder =>
|
.addStringOption(builder =>
|
||||||
builder //
|
builder //
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require('discord.js');
|
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
|
||||||
|
|
||||||
const data = new ContextMenuCommandBuilder()
|
const data = new ContextMenuCommandBuilder()
|
||||||
.setName('Query AI')
|
.setName("Query AI")
|
||||||
.setType(ApplicationCommandType.Message)
|
.setType(ApplicationCommandType.Message)
|
||||||
.setContexts([
|
.setContexts([
|
||||||
InteractionContextType.Guild,
|
InteractionContextType.Guild,
|
||||||
|
|
175
src/commands/fun/gelbooru.js
Normal file
175
src/commands/fun/gelbooru.js
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
const { InteractionContextType, ApplicationIntegrationType, SlashCommandBuilder, EmbedBuilder, escapeMarkdown, bold } = require("discord.js");
|
||||||
|
const { basename, extname } = require("node:path");
|
||||||
|
const Booru = require('booru');
|
||||||
|
|
||||||
|
const boorus = [];
|
||||||
|
for (const site of Object.keys(Booru.sites)) {
|
||||||
|
boorus.push({
|
||||||
|
name: site,
|
||||||
|
value: site
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultBooru = "gelbooru.com";
|
||||||
|
|
||||||
|
const data = new SlashCommandBuilder()
|
||||||
|
.setName("booru")
|
||||||
|
.setDescription("Select a random image from any booru")
|
||||||
|
.addStringOption(builder =>
|
||||||
|
builder //
|
||||||
|
.setName("tags")
|
||||||
|
.setRequired(true)
|
||||||
|
.setDescription("Tags to search for")
|
||||||
|
)
|
||||||
|
.addStringOption(builder =>
|
||||||
|
builder //
|
||||||
|
.setName("booru")
|
||||||
|
.setRequired(false)
|
||||||
|
.setDescription("Booru board to search (default: gelbooru)")
|
||||||
|
.addChoices(boorus)
|
||||||
|
)
|
||||||
|
.setContexts([
|
||||||
|
InteractionContextType.Guild,
|
||||||
|
InteractionContextType.BotDM,
|
||||||
|
InteractionContextType.PrivateChannel
|
||||||
|
])
|
||||||
|
.setIntegrationTypes([
|
||||||
|
ApplicationIntegrationType.GuildInstall,
|
||||||
|
ApplicationIntegrationType.UserInstall
|
||||||
|
]);
|
||||||
|
|
||||||
|
function isEmbeddableFileType(ext) {
|
||||||
|
return ['.jpg', '.jpeg', '.png', '.gif'].includes(ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
function notEmpty(str) {
|
||||||
|
return str.trim() !== ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const regexCutTags = /[\S\s]{1,75}[^,]{0,25}/;
|
||||||
|
function formatTags(tags) {
|
||||||
|
const tagString = tags.join(', ')
|
||||||
|
|
||||||
|
if (tagString.length < 100) {
|
||||||
|
return tagString
|
||||||
|
}
|
||||||
|
|
||||||
|
const tagCutMatch = tagString.match(regexCutTags) ?? []
|
||||||
|
return `${escapeMarkdown(tagCutMatch[0] ?? '')}...`
|
||||||
|
}
|
||||||
|
|
||||||
|
const ratingEmojis = {
|
||||||
|
s: '<:rating_safe:1293819920978804829>',
|
||||||
|
g: '<:rating_general:1293819929199513610>',
|
||||||
|
q: '<:rating_questionable:1293819907099725925>',
|
||||||
|
e: '<:rating_explicit:1293819893795389491>',
|
||||||
|
u: '<:rating_unknown:1293819936845594665>',
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatRating(rating) {
|
||||||
|
return ratingEmojis[rating] ?? rating.toUpperCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatScore(score) {
|
||||||
|
if (score > 0) {
|
||||||
|
return `<:green_arrow_up:1293819944399667222> ${score}`
|
||||||
|
} else if (score < 0) {
|
||||||
|
return `<:red_arrow_down:1293819951764869181> ${score}`
|
||||||
|
} else {
|
||||||
|
return `<:yellow_tilde:1293819958643396608> ${score}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNSFWPost(post) {
|
||||||
|
return !['s', 'g'].includes(post.rating)
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(time) {
|
||||||
|
return `${(Number(time) / 1e6).toFixed(2)}ms`
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data,
|
||||||
|
async execute(interaction) {
|
||||||
|
const tags = interaction.options.getString("tags").split(" ");
|
||||||
|
const booru = interaction.options.getString("booru") ?? defaultBooru;
|
||||||
|
|
||||||
|
await interaction.deferReply();
|
||||||
|
console.log(booru, tags);
|
||||||
|
|
||||||
|
const startTime = process.hrtime.bigint();
|
||||||
|
|
||||||
|
var post = null;
|
||||||
|
while (post == null) {
|
||||||
|
var newPost = (await Booru.search(booru, tags, { limit: 1, random: true }))[0];
|
||||||
|
if (newPost == null) {
|
||||||
|
await interaction.followUp("Could not find any post matching tags.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isNSFWPost(newPost)) continue;
|
||||||
|
post = newPost;
|
||||||
|
}
|
||||||
|
|
||||||
|
const endTime = process.hrtime.bigint();
|
||||||
|
const timeTaken = endTime - startTime;
|
||||||
|
|
||||||
|
const ext = extname((post['data']).file_name ?? post.fileUrl ?? '').toLowerCase();
|
||||||
|
|
||||||
|
const leadingDescription = [
|
||||||
|
`**Score:** ${formatScore(post.score)}`,
|
||||||
|
`**Rating:** ${formatRating(post.rating)}`,
|
||||||
|
`[File URL](${post.fileUrl})`,
|
||||||
|
`\`${ext}\``,
|
||||||
|
].join(' | ')
|
||||||
|
|
||||||
|
const description = [leadingDescription, `**Tags:** ${formatTags(post.tags)}`]
|
||||||
|
.filter(notEmpty)
|
||||||
|
.join('\n')
|
||||||
|
|
||||||
|
const footerText = [
|
||||||
|
post.booru.domain,
|
||||||
|
post.id,
|
||||||
|
timeTaken ? formatTime(timeTaken) : '',
|
||||||
|
].filter(notEmpty).join(' · ')
|
||||||
|
|
||||||
|
|
||||||
|
if (isEmbeddableFileType(ext)) {
|
||||||
|
const embed = new EmbedBuilder()
|
||||||
|
.setColor("#cba6f7")
|
||||||
|
.setTitle(`Post #${post.id}`)
|
||||||
|
.setURL(post.postView)
|
||||||
|
//.setDescription(description)
|
||||||
|
.setFields([{
|
||||||
|
name: "Score",
|
||||||
|
value: formatScore(post.score),
|
||||||
|
inline: true
|
||||||
|
}, {
|
||||||
|
name: "Rating",
|
||||||
|
value: formatRating(post.rating),
|
||||||
|
inline: true
|
||||||
|
}, {
|
||||||
|
name: "File",
|
||||||
|
value: `[${basename(post.fileUrl)}](${post.fileUrl})`,
|
||||||
|
inline: true
|
||||||
|
}, {
|
||||||
|
name: "Tags",
|
||||||
|
value: formatTags(post.tags),
|
||||||
|
inline: false
|
||||||
|
}])
|
||||||
|
.setImage(post.fileUrl)
|
||||||
|
.setFooter({
|
||||||
|
text: footerText,
|
||||||
|
iconURL: `https://${post.booru.domain}/favicon.ico`,
|
||||||
|
})
|
||||||
|
|
||||||
|
await interaction.followUp({ embeds: [embed] });
|
||||||
|
} else {
|
||||||
|
await interaction.followUp(
|
||||||
|
'>>> ' + bold(`[Post #${post.id}](<${post.postView}>)`) + "\n" +
|
||||||
|
description + "\n" +
|
||||||
|
footerText
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,7 +1,7 @@
|
||||||
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType, AttachmentBuilder } = require('discord.js');
|
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType, AttachmentBuilder } = require("discord.js");
|
||||||
|
|
||||||
const data = new ContextMenuCommandBuilder()
|
const data = new ContextMenuCommandBuilder()
|
||||||
.setName('Message Information')
|
.setName("Message Information")
|
||||||
.setType(ApplicationCommandType.Message)
|
.setType(ApplicationCommandType.Message)
|
||||||
.setContexts([
|
.setContexts([
|
||||||
InteractionContextType.Guild,
|
InteractionContextType.Guild,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require('discord.js');
|
const { ContextMenuCommandBuilder, ApplicationCommandType, InteractionContextType, ApplicationIntegrationType } = require("discord.js");
|
||||||
|
|
||||||
const data = new ContextMenuCommandBuilder()
|
const data = new ContextMenuCommandBuilder()
|
||||||
.setName('User Information')
|
.setName("User Information")
|
||||||
.setType(ApplicationCommandType.User)
|
.setType(ApplicationCommandType.User)
|
||||||
.setContexts([
|
.setContexts([
|
||||||
InteractionContextType.Guild,
|
InteractionContextType.Guild,
|
||||||
|
|
Loading…
Reference in a new issue