BOORU TAG AUTOCOMPLETE

This commit is contained in:
Ashley Graves 2024-10-10 14:48:59 +02:00
parent 19fef30ff1
commit 8d7357e4da
4 changed files with 92 additions and 41 deletions

View file

@ -8,8 +8,8 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@himeka/booru": "github:asadahimeka/booru-search",
"@imgproxy/imgproxy-node": "^1.0.6", "@imgproxy/imgproxy-node": "^1.0.6",
"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",

View file

@ -8,12 +8,12 @@ importers:
.: .:
dependencies: dependencies:
'@himeka/booru':
specifier: github:asadahimeka/booru-search
version: https://codeload.github.com/asadahimeka/booru-search/tar.gz/9599c1c7e2ab8467ac6b0ce7d5300c621e4b00b9
'@imgproxy/imgproxy-node': '@imgproxy/imgproxy-node':
specifier: ^1.0.6 specifier: ^1.0.6
version: 1.0.6 version: 1.0.6
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
@ -60,6 +60,11 @@ packages:
resolution: {integrity: sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==} resolution: {integrity: sha512-PZ+vLpxGCRtmr2RMkqh8Zp+BenUaJqlS6xhgWKEZcgC/vfHLEzpHtKkB0sl3nZWpwtcKk6YWy+pU3okL2I97FA==}
engines: {node: '>=16.11.0'} engines: {node: '>=16.11.0'}
'@himeka/booru@https://codeload.github.com/asadahimeka/booru-search/tar.gz/9599c1c7e2ab8467ac6b0ce7d5300c621e4b00b9':
resolution: {tarball: https://codeload.github.com/asadahimeka/booru-search/tar.gz/9599c1c7e2ab8467ac6b0ce7d5300c621e4b00b9}
version: 2.7.7
engines: {node: '>=10.0.0'}
'@imgproxy/imgproxy-js-core@1.0.8': '@imgproxy/imgproxy-js-core@1.0.8':
resolution: {integrity: sha512-3oBneumj7b/YCeyLteKyKaidQSrDhEHnZMiVBHO0Hshju/YSplbzSeACZGwai7LyD3YMMpsK/kLIodXU6wbtMw==} resolution: {integrity: sha512-3oBneumj7b/YCeyLteKyKaidQSrDhEHnZMiVBHO0Hshju/YSplbzSeACZGwai7LyD3YMMpsK/kLIodXU6wbtMw==}
@ -105,10 +110,6 @@ 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'}
@ -141,8 +142,8 @@ 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: fast-xml-parser@4.4.0:
resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==} resolution: {integrity: sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==}
hasBin: true hasBin: true
form-data-encoder@1.7.2: form-data-encoder@1.7.2:
@ -165,6 +166,9 @@ packages:
humanize-ms@1.2.1: humanize-ms@1.2.1:
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
isomorphic-unfetch@3.1.0:
resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==}
lodash.snakecase@4.1.1: lodash.snakecase@4.1.1:
resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==}
@ -225,6 +229,9 @@ packages:
resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==} resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==}
engines: {node: '>=18.17'} engines: {node: '>=18.17'}
unfetch@4.2.0:
resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==}
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'}
@ -296,6 +303,13 @@ snapshots:
- bufferutil - bufferutil
- utf-8-validate - utf-8-validate
'@himeka/booru@https://codeload.github.com/asadahimeka/booru-search/tar.gz/9599c1c7e2ab8467ac6b0ce7d5300c621e4b00b9':
dependencies:
fast-xml-parser: 4.4.0
isomorphic-unfetch: 3.1.0
transitivePeerDependencies:
- encoding
'@imgproxy/imgproxy-js-core@1.0.8': {} '@imgproxy/imgproxy-js-core@1.0.8': {}
'@imgproxy/imgproxy-node@1.0.6': '@imgproxy/imgproxy-node@1.0.6':
@ -340,11 +354,6 @@ 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
@ -381,7 +390,7 @@ snapshots:
fast-deep-equal@3.1.3: {} fast-deep-equal@3.1.3: {}
fast-xml-parser@4.5.0: fast-xml-parser@4.4.0:
dependencies: dependencies:
strnum: 1.0.5 strnum: 1.0.5
@ -416,6 +425,13 @@ snapshots:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
isomorphic-unfetch@3.1.0:
dependencies:
node-fetch: 2.7.0
unfetch: 4.2.0
transitivePeerDependencies:
- encoding
lodash.snakecase@4.1.1: {} lodash.snakecase@4.1.1: {}
lodash@4.17.21: {} lodash@4.17.21: {}
@ -454,6 +470,8 @@ snapshots:
undici@6.19.8: {} undici@6.19.8: {}
unfetch@4.2.0: {}
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: {}

View file

@ -1,8 +1,9 @@
const { InteractionContextType, ApplicationIntegrationType, SlashCommandBuilder, EmbedBuilder, escapeMarkdown, bold } = require("discord.js"); const { InteractionContextType, ApplicationIntegrationType, SlashCommandBuilder, EmbedBuilder, escapeMarkdown, bold } = require("discord.js");
const { stringify } = require("node:querystring");
const { readFileSync } = require("node:fs"); const { readFileSync } = require("node:fs");
const { extname } = require("node:path");
const { decode } = require("html-entities"); const { decode } = require("html-entities");
const Booru = require('booru'); const { extname } = require("node:path");
const Booru = require('@himeka/booru');
const boorus = []; const boorus = [];
for (const site of Object.keys(Booru.sites)) { for (const site of Object.keys(Booru.sites)) {
@ -22,14 +23,15 @@ const data = new SlashCommandBuilder()
.setName("tags") .setName("tags")
.setRequired(false) .setRequired(false)
.setDescription("Tags to search for") .setDescription("Tags to search for")
.setAutocomplete(true)
) )
.addStringOption(builder => /*.addStringOption(builder =>
builder // builder //
.setName("booru") .setName("booru")
.setRequired(false) .setRequired(false)
.setDescription("Booru board to search (default: gelbooru)") .setDescription("Booru board to search (default: gelbooru)")
.addChoices(boorus) .addChoices(boorus)
) )*/
.addBooleanOption(builder => .addBooleanOption(builder =>
builder // builder //
.setName("nsfw") .setName("nsfw")
@ -169,4 +171,29 @@ module.exports = {
); );
} }
}, },
async autocomplete(interaction) {
const focusedValue = interaction.options.getFocused();
const tags = focusedValue.split(" ");
var queryString = stringify({
"page": "dapi",
"json": "1",
"s": "tag",
"q": "index",
"orderby": "count",
"name_pattern": tags[tags.length - 1] + "%"
});
const results = await (await fetch(`https://gelbooru.com/index.php?${queryString}`)).json();
const choices = [];
for (const tag of results.tag) {
if (tag.name == "") continue;
choices.push(tag.name);
}
if (choices.length == 0) {
await interaction.respond();
return;
}
await interaction.respond(
choices.slice(0, 25).map(choice => ({ name: (tags.length > 1 ? tags.slice(0, tags.length - 1).join(" ") + " " : '') + choice, value: choice })),
);
},
}; };

View file

@ -1,4 +1,4 @@
const { REST, Routes, Client, Collection, GatewayIntentBits, Events, Partials } = require("discord.js"); const { REST, Routes, Client, Collection, GatewayIntentBits, Events, Partials, InteractionType } = require("discord.js");
const { default: Groq } = require("groq-sdk"); const { default: Groq } = require("groq-sdk");
const path = require("node:path"); const path = require("node:path");
const fs = require("node:fs"); const fs = require("node:fs");
@ -36,14 +36,19 @@ for (const folder of commandFolders) {
} }
client.on(Events.InteractionCreate, async interaction => { client.on(Events.InteractionCreate, async interaction => {
if (interaction.commandName == undefined) return;
const command = interaction.client.commands.get(interaction.commandName); const command = interaction.client.commands.get(interaction.commandName);
if (!command) { if (!command) {
console.error(`No command matching ${interaction.commandName} was found.`); console.error(`No command matching ${interaction.commandName} was found.`);
return; return;
} }
if (interaction.isAutocomplete()) {
try {
await command.autocomplete(interaction);
} catch (error) {
console.error(error);
}
} else if (interaction.isCommand()) {
var options = ""; var options = "";
for (const option of interaction.options.data) { for (const option of interaction.options.data) {
options += option.name + ":" + option.value options += option.name + ":" + option.value
@ -66,6 +71,7 @@ client.on(Events.InteractionCreate, async interaction => {
await interaction.reply(data); await interaction.reply(data);
} }
} }
}
}); });
client.once(Events.ClientReady, async () => { client.once(Events.ClientReady, async () => {