From 60e014e667b878b1da04d34f598fb782a9b9465f Mon Sep 17 00:00:00 2001 From: scanash00 Date: Wed, 23 Jul 2025 01:47:46 -0800 Subject: [PATCH] feat: more componentv2 --- locales/en-US.json | 509 +++++++++++++++-------------- locales/es-ES.json | 558 ++++++++++++++++---------------- src/commands/fun/8ball.ts | 41 ++- src/commands/fun/cat.ts | 46 +-- src/commands/fun/dog.ts | 45 ++- src/events/interactionCreate.ts | 177 +++++++--- 6 files changed, 754 insertions(+), 622 deletions(-) diff --git a/locales/en-US.json b/locales/en-US.json index 75362a0..09c11ed 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -1,269 +1,268 @@ { - "cooldown": "Please wait {cooldown} second(s) before using this command again.", - "failedrequest": "An error occurred while processing your request. Please try again later.", - "unexpectederror": "An unexpected error occurred. Please try again later.", - "poweredby": "Powered by", - "providedby": "Data provided by", - "reddit": { - "from": "From r/{subreddit}" + "cooldown": "Please wait {cooldown} second(s) before using this command again.", + "failedrequest": "An error occurred while processing your request. Please try again later.", + "unexpectederror": "An unexpected error occurred. Please try again later.", + "poweredby": "Powered by", + "providedby": "Data provided by", + "reddit": { + "from": "From r/{subreddit}" + }, + "error": "Error!", + "common": { + "ogmessage": "Original Message", + "jumptomessage": "Jump to message", + "messagelink": "Message link" + }, + "commands": { + "8ball": { + "name": "8ball", + "description": "Ask the magic 8-ball a question", + "says": "The Magic 8-Ball says…", + "question": "Question", + "answer": "Answer", + "askagain": "Ask Again", + "responces": { + "itiscertain": "It is certain", + "itisdecidedlyso": "It is decidedly so", + "withoutadoubt": "Without a doubt", + "yesdefinitely": "Yes definitely", + "youmayrelyonit": "You may rely on it", + "asiseeityes": "As I see it, yes", + "mostlikely": "Most likely", + "outlookgood": "Outlook good", + "yes": "Yes", + "signspointtoyes": "Signs point to yes", + "replyhazytryagain": "Reply hazy, try again", + "askagainlater": "Ask again later", + "betternottellyounow": "Better not tell you now", + "cannotpredictnow": "Cannot predict now", + "concentrateandaskagain": "Concentrate and ask again", + "dontcountonit": "Don't count on it", + "myreplyisno": "My reply is no", + "mysourcessayno": "My sources say no", + "outlooknotsogood": "Outlook not so good", + "verydoubtful": "Very doubtful" + } }, - "error": "Error!", - "common": { - "ogmessage": "Original Message", - "jumptomessage": "Jump to message", - "messagelink": "Message link" + "cat": { + "name": "cat", + "description": "Get a random cat image!", + "randomcat": "Random cat", + "newcat": "New cat", + "error": "Sorry, I had trouble fetching a cat image. Please try again later!" }, - "commands": { - "8ball": { - "name": "8ball", - "description": "Ask the magic 8-ball a question", - "says": "The Magic 8-Ball says…", - "question": "Question", - "answer": "Answer", - "anotherfortune": "Ask again for another fortune!", - "spoken": "The magic 8-ball has spoken!", - "responces": { - "itiscertain": "It is certain", - "itisdecidedlyso": "It is decidedly so", - "withoutadoubt": "Without a doubt", - "yesdefinitely": "Yes definitely", - "youmayrelyonit": "You may rely on it", - "asiseeityes": "As I see it, yes", - "mostlikely": "Most likely", - "outlookgood": "Outlook good", - "yes": "Yes", - "signspointtoyes": "Signs point to yes", - "replyhazytryagain": "Reply hazy, try again", - "askagainlater": "Ask again later", - "betternottellyounow": "Better not tell you now", - "cannotpredictnow": "Cannot predict now", - "concentrateandaskagain": "Concentrate and ask again", - "dontcountonit": "Don't count on it", - "myreplyisno": "My reply is no", - "mysourcessayno": "My sources say no", - "outlooknotsogood": "Outlook not so good", - "verydoubtful": "Very doubtful" - } - }, - "cat": { - "name": "cat", - "description": "Get a random cat image!", - "randomcat": "Random cat", - "newcat": "New cat", - "error": "Sorry, I had trouble fetching a cat image. Please try again later!" - }, - "dog": { - "name": "dog", - "description": "Get a random dog image!", - "randomdog": "Random dog", - "newdog": "New dog", - "error": "Sorry, I had trouble fetching a dog image. Please try again later!" - }, - "wiki": { - "name": "wiki", - "description": "Search Wikipedia for a topic", - "pedia": "Wikipedia: {article}", - "error": "Sorry, I had trouble fetching the Wikipedia article. Please try again later!", - "nosummary": "No summary available", - "readmoreonwiki": "Read more" - }, - "weather": { - "name": "weather", - "description": "Get the current weather for a location", - "temperature": "Temperature", - "feelslike": "Feels like", - "default": "Weather", - "humidity": "Humidity", - "windspeed": "Wind speed", - "pressure": "Pressure", - "weatherin": "Weather in {location}", - "error": "Sorry, I had trouble fetching the weather. Please try again later!", - "nolocation": "Location not found. Please check the city name and try again.", - "apikeymissing": "OpenWeather API key is missing or invalid." - }, - "joke": { - "name": "joke", - "description": "Get a random joke!", - "waitingpunchline": "The punchline will appear in {seconds} seconds…", - "error": "Sorry, I had trouble fetching a joke. Please try again later!", - "type": { - "default": "{type} joke", - "general": "General", - "programming": "Programming", - "dad": "Dad" - } + "dog": { + "name": "dog", + "description": "Get a random dog image!", + "randomdog": "Random dog", + "newdog": "New dog", + "error": "Sorry, I had trouble fetching a dog image. Please try again later!" + }, + "wiki": { + "name": "wiki", + "description": "Search Wikipedia for a topic", + "pedia": "Wikipedia: {article}", + "error": "Sorry, I had trouble fetching the Wikipedia article. Please try again later!", + "nosummary": "No summary available", + "readmoreonwiki": "Read more" + }, + "weather": { + "name": "weather", + "description": "Get the current weather for a location", + "temperature": "Temperature", + "feelslike": "Feels like", + "default": "Weather", + "humidity": "Humidity", + "windspeed": "Wind speed", + "pressure": "Pressure", + "weatherin": "Weather in {location}", + "error": "Sorry, I had trouble fetching the weather. Please try again later!", + "nolocation": "Location not found. Please check the city name and try again.", + "apikeymissing": "OpenWeather API key is missing or invalid." + }, + "joke": { + "name": "joke", + "description": "Get a random joke!", + "waitingpunchline": "The punchline will appear in {seconds} seconds…", + "error": "Sorry, I had trouble fetching a joke. Please try again later!", + "type": { + "default": "{type} joke", + "general": "General", + "programming": "Programming", + "dad": "Dad" + } + }, + "help": { + "name": "help", + "description": "Show all available commands and their usage", + "embed": { + "title": "Aethel commands", + "description": "Here are all the available commands" + }, + "nooptions": "No options" + }, + "remind": { + "name": "remind", + "reminder": "Reminder!", + "remindyou": "You asked me to remind me about: {message}", + "timeelapsed": "Time elapsed", + "originaltime": "Original Time", + "errors": { + "base": "An error occurred while setting your reminder. Please try again later.", + "failedtosave": "Failed to save your reminder. Please try again later.", + "invalidformat": "Invalid time format! Use combinations like: 1h30m, 45m, or 2h", + "providevalidchars": "Please provide a valid message (1-1000 characters)", + "atleastoneminute": "Reminder time must be at least 1 minute!", + "notlongerthanaday": "Reminder time cannot be longer than 24 hours!" + }, + "modal": { + "setreminder": "Set reminder", + "whento": "When to remind you? (e.g., 10m, 1h, 2h30m)" + }, + "reminderset": "Reminder set", + "iwillremindyou": "I'll remind you about {message} in {time}", + "contextiwillremindyou": "I'll remind you about this message in {time}", + "time": "Time", + "willtrigger": "Will trigger", + "reminderid": "Reminder ID: {reminderId}" + }, + "whois": { + "name": "whois", + "description": "Look up WHOIS information for a domain or IP address", + "error": "Sorry, I had trouble fetching WHOIS data. Please try again later!", + "nodata": "No WHOIS data found for the specified domain or IP.", + "notvalid": "Please provide a valid domain name or IP address." + }, + "ai": { + "name": "ai", + "description": "Chat with an AI assistant", + "optioins": { + "prompt": { + "name": "prompt", + "description": "Your message to the ai" }, - "help": { - "name": "help", - "description": "Show all available commands and their usage", - "embed": { - "title": "Aethel commands", - "description": "Here are all the available commands" - }, - "nooptions": "No options" + "customapi": "Use your own API key?", + "reset": "Reset your ai chat history" + }, + "request": { + "inprogress": "You already have a request in progress. Please wait for it to complete." + }, + "reset": "Your AI chat history has been reset.", + "defaultapi": " Switched to default API. Your custom API key has been cleared and the default model will be used.", + "modal": { + "title": "Enter your API Credentials", + "apikey": "API Key", + "apikeyplaceholder": "To stop using your key: /ai use_custom_api false", + "apiurl": "API Url", + "apiurlplaceholder": "Your API Url", + "model": "Model", + "modelplaceholder": "Model name (eg. gpt-4)" + }, + "nopendingrequest": "No pending request found. Please try the command again.", + "apicredssaved": "API credentials saved. You can now use the `/ai` command without re-entering your credentials. To stop using your key, do `/ai use_custom_api false`", + "process": { + "dailylimit": "You've reached your daily limit of AI requests", + "noapikey": "Please set up your API key first" + }, + "errors": { + "failed": "Failed to process AI response", + "nores": "No response from AI", + "toolong": "Message is too long" + } + }, + "todo": { + "name": "todo", + "description": "Manage your to-do list", + "add": { + "name": "add", + "description": "Add a new to-do item" + }, + "done": { + "name": "done", + "description": "Mark a to-do as done" + }, + "list": { + "name": "list", + "description": "View your to-do list" + }, + "added": "✅ Added to-do: **{item}**", + "add_error": "❌ Failed to add your todo. Please try again later.", + "empty": "Your to-do list is empty! 🎉", + "list_title": "📝 Your To-Do List", + "checked": "✅ Marked to-do as done: **{item}**", + "notfound": "❌ That to-do was not found: **{item}**", + "done_error": "❌ Failed to mark your todo as done. Please try again later.", + "todo_title": "To-Do", + "done_title": "Done", + "none": "—" + }, + "cobalt": { + "name": "cobalt", + "description": "Download a video or audio from a given URL", + "options": { + "url": { + "name": "url", + "description": "The URL of the video to download" }, - "remind": { - "name": "remind", - "reminder": "Reminder!", - "remindyou": "You asked me to remind me about: {message}", - "timeelapsed": "Time elapsed", - "originaltime": "Original Time", - "errors": { - "base": "An error occurred while setting your reminder. Please try again later.", - "failedtosave": "Failed to save your reminder. Please try again later.", - "invalidformat": "Invalid time format! Use combinations like: 1h30m, 45m, or 2h", - "providevalidchars": "Please provide a valid message (1-1000 characters)", - "atleastoneminute": "Reminder time must be at least 1 minute!", - "notlongerthanaday": "Reminder time cannot be longer than 24 hours!" - }, - "modal": { - "setreminder": "Set reminder", - "whento": "When to remind you? (e.g., 10m, 1h, 2h30m)" - }, - "reminderset": "Reminder set", - "iwillremindyou": "I'll remind you about {message} in {time}", - "contextiwillremindyou": "I'll remind you about this message in {time}", - "time": "Time", - "willtrigger": "Will trigger", - "reminderid": "Reminder ID: {reminderId}" + "video_quality": { + "name": "video-quality", + "description": "The video quality to download" }, - "whois": { - "name": "whois", - "description": "Look up WHOIS information for a domain or IP address", - "error": "Sorry, I had trouble fetching WHOIS data. Please try again later!", - "nodata": "No WHOIS data found for the specified domain or IP.", - "notvalid": "Please provide a valid domain name or IP address." + "audio_only": { + "name": "audio-only", + "description": "Download audio only" }, - "ai": { - "name": "ai", - "description": "Chat with an AI assistant", - "optioins": { - "prompt": { - "name": "prompt", - "description": "Your message to the ai" - }, - "customapi": "Use your own API key?", - "reset": "Reset your ai chat history" - }, - "request": { - "inprogress": "You already have a request in progress. Please wait for it to complete." - }, - "reset": "Your AI chat history has been reset.", - "defaultapi": " Switched to default API. Your custom API key has been cleared and the default model will be used.", - "modal": { - "title": "Enter your API Credentials", - "apikey": "API Key", - "apikeyplaceholder": "To stop using your key: /ai use_custom_api false", - "apiurl": "API Url", - "apiurlplaceholder": "Your API Url", - "model": "Model", - "modelplaceholder": "Model name (eg. gpt-4)" - }, - "nopendingrequest": "No pending request found. Please try the command again.", - "apicredssaved": "API credentials saved. You can now use the `/ai` command without re-entering your credentials. To stop using your key, do `/ai use_custom_api false`", - "process": { - "dailylimit": "You've reached your daily limit of AI requests", - "noapikey": "Please set up your API key first" - }, - "errors": { - "failed": "Failed to process AI response", - "nores": "No response from AI", - "toolong": "Message is too long" - } + "mute_audio": { + "name": "mute-audio", + "description": "Mute audio" }, - "todo": { - "name": "todo", - "description": "Manage your to-do list", - "add": { - "name": "add", - "description": "Add a new to-do item" - }, - "done": { - "name": "done", - "description": "Mark a to-do as done" - }, - "list": { - "name": "list", - "description": "View your to-do list" - }, - "added": "✅ Added to-do: **{item}**", - "add_error": "❌ Failed to add your todo. Please try again later.", - "empty": "Your to-do list is empty! 🎉", - "list_title": "📝 Your To-Do List", - "checked": "✅ Marked to-do as done: **{item}**", - "notfound": "❌ That to-do was not found: **{item}**", - "done_error": "❌ Failed to mark your todo as done. Please try again later.", - "todo_title": "To-Do", - "done_title": "Done", - "none": "—" + "twitter_gif": { + "name": "twitter-gif", + "description": "Download as Twitter GIF" }, - "cobalt": { - "name": "cobalt", - "description": "Download a video or audio from a given URL", - "options": { - "url": { - "name": "url", - "description": "The URL of the video to download" - }, - "video_quality": { - "name": "video-quality", - "description": "The video quality to download" - }, - "audio_only": { - "name": "audio-only", - "description": "Download audio only" - }, - "mute_audio": { - "name": "mute-audio", - "description": "Mute audio" - }, - "twitter_gif": { - "name": "twitter-gif", - "description": "Download as Twitter GIF" - }, - "tiktok_original_audio": { - "name": "tiktok-original-audio", - "description": "Include TikTok original audio" - }, - "audio_format": { - "name": "audio-format", - "description": "Format for audio (requires audio-only to be true)" - } - }, - "button_label": "Download", - "success": "✅ **Download ready!**\n\n🔗 {url}\n📥 **Click the button below to download your file.**", - "error": "❌ **Error:** {error}", - "unknown_error": "An unknown error occurred.", - "rate_limit": "⏳ **Rate limit exceeded.** Please try again later.", - "unknown_response": "❓ **Unknown response from the API.** Please try again.", - "multiple_items": "📋 **Multiple items found for this URL.** Please provide a more specific URL.", - "local_processing_not_supported": "⚠️ **Local processing is not supported.** Please try a different URL or option." + "tiktok_original_audio": { + "name": "tiktok-original-audio", + "description": "Include TikTok original audio" }, - "time": { - "name": "time", - "description": "Get the current time for a timezone", - "option_timezone": { - "name": "timezone", - "description": "The timezone to check (e.g., Europe/Madrid)" - }, - "embed": { - "title_single": "Time in {city}, {country}", - "title_multi": "Time for {city}", - "time_format": "dddd, MMMM D, YYYY, h:mm A z", - "notfound": "City not found.", - "field_day_of_week": "Day of Week", - "field_time": "Time", - "field_date": "Date", - "footer": "Timezone: {timezone}", - "footer_multi": "Multiple cities found with similar names", - "author": "Current Time", - "multi_city_description": "Multiple cities found for '{city}':" - } + "audio_format": { + "name": "audio-format", + "description": "Format for audio (requires audio-only to be true)" } + }, + "button_label": "Download", + "success": "✅ **Download ready!**\n\n🔗 {url}\n📥 **Click the button below to download your file.**", + "error": "❌ **Error:** {error}", + "unknown_error": "An unknown error occurred.", + "rate_limit": "⏳ **Rate limit exceeded.** Please try again later.", + "unknown_response": "❓ **Unknown response from the API.** Please try again.", + "multiple_items": "📋 **Multiple items found for this URL.** Please provide a more specific URL.", + "local_processing_not_supported": "⚠️ **Local processing is not supported.** Please try a different URL or option." }, - "categories": { - "fun": "Fun", - "info": "Info", - "utilities": "Utilities" + "time": { + "name": "time", + "description": "Get the current time for a timezone", + "option_timezone": { + "name": "timezone", + "description": "The timezone to check (e.g., Europe/Madrid)" + }, + "embed": { + "title_single": "Time in {city}, {country}", + "title_multi": "Time for {city}", + "time_format": "dddd, MMMM D, YYYY, h:mm A z", + "notfound": "City not found.", + "field_day_of_week": "Day of Week", + "field_time": "Time", + "field_date": "Date", + "footer": "Timezone: {timezone}", + "footer_multi": "Multiple cities found with similar names", + "author": "Current Time", + "multi_city_description": "Multiple cities found for '{city}':" + } } + }, + "categories": { + "fun": "Fun", + "info": "Info", + "utilities": "Utilities" + } } diff --git a/locales/es-ES.json b/locales/es-ES.json index d52a4e3..63f4b33 100644 --- a/locales/es-ES.json +++ b/locales/es-ES.json @@ -1,292 +1,292 @@ { - "cooldown": "Por favor, espera {cooldown} segundo(s) antes de usar este comando de nuevo.", - "failedrequest": "Se produjo un error al procesar tu solicitud. Por favor, inténtalo de nuevo más tarde.", - "unexpectederror": "Se produjo un error inesperado. Por favor, inténtalo de nuevo más tarde.", - "poweredby": "Tecnología de", - "providedby": "Datos proporcionados por", - "reddit": { - "from": "De r/{subreddit}" + "cooldown": "Por favor, espera {cooldown} segundo(s) antes de usar este comando de nuevo.", + "failedrequest": "Se produjo un error al procesar tu solicitud. Por favor, inténtalo de nuevo más tarde.", + "unexpectederror": "Se produjo un error inesperado. Por favor, inténtalo de nuevo más tarde.", + "poweredby": "Tecnología de", + "providedby": "Datos proporcionados por", + "reddit": { + "from": "De r/{subreddit}" + }, + "error": "¡Error!", + "common": { + "ogmessage": "Mensaje original", + "jumptomessage": "Ir al mensaje", + "messagelink": "Enlace al mensaje" + }, + "commands": { + "8ball": { + "name": "8ball", + "description": "Haz una pregunta a la bola mágica 8", + "says": "La bola mágica 8 dice…", + "question": "Pregunta", + "answer": "Respuesta", + "anotherfortune": "¡Pregunta de nuevo para otra predicción!", + "spoken": "¡La bola mágica 8 ha hablado!", + "responces": { + "itiscertain": "Es seguro", + "itisdecidedlyso": "Definitivamente sí", + "withoutadoubt": "Sin duda", + "yesdefinitely": "Sí, definitivamente", + "youmayrelyonit": "Puedes confiar en ello", + "asiseeityes": "Por lo que veo, sí", + "mostlikely": "Lo más probable", + "outlookgood": "Pinta bien", + "yes": "Sí", + "signspointtoyes": "Las señales apuntan a que sí", + "replyhazytryagain": "Respuesta confusa, inténtalo de nuevo", + "askagainlater": "Pregunta de nuevo más tarde", + "betternottellyounow": "Mejor no decírtelo ahora", + "cannotpredictnow": "No puedo predecirlo ahora", + "concentrateandaskagain": "Concéntrate y pregunta de nuevo", + "dontcountonit": "No cuentes con ello", + "myreplyisno": "Mi respuesta es no", + "mysourcessayno": "Mis fuentes dicen que no", + "outlooknotsogood": "No pinta bien", + "verydoubtful": "Muy dudoso" + } }, - "error": "¡Error!", - "common": { - "ogmessage": "Mensaje original", - "jumptomessage": "Ir al mensaje", - "messagelink": "Enlace al mensaje" + "cat": { + "name": "gato", + "description": "¡Obtén una imagen aleatoria de un gato!", + "randomcat": "Gato aleatorio", + "newcat": "Nuevo gato", + "error": "Lo siento, tuve problemas para obtener una imagen de gato. ¡Por favor, inténtalo de nuevo más tarde!" }, - "commands": { - "8ball": { - "name": "8ball", - "description": "Haz una pregunta a la bola mágica 8", - "says": "La bola mágica 8 dice…", - "question": "Pregunta", - "answer": "Respuesta", - "anotherfortune": "¡Pregunta de nuevo para otra predicción!", - "spoken": "¡La bola mágica 8 ha hablado!", - "responces": { - "itiscertain": "Es seguro", - "itisdecidedlyso": "Definitivamente sí", - "withoutadoubt": "Sin duda", - "yesdefinitely": "Sí, definitivamente", - "youmayrelyonit": "Puedes confiar en ello", - "asiseeityes": "Por lo que veo, sí", - "mostlikely": "Lo más probable", - "outlookgood": "Pinta bien", - "yes": "Sí", - "signspointtoyes": "Las señales apuntan a que sí", - "replyhazytryagain": "Respuesta confusa, inténtalo de nuevo", - "askagainlater": "Pregunta de nuevo más tarde", - "betternottellyounow": "Mejor no decírtelo ahora", - "cannotpredictnow": "No puedo predecirlo ahora", - "concentrateandaskagain": "Concéntrate y pregunta de nuevo", - "dontcountonit": "No cuentes con ello", - "myreplyisno": "Mi respuesta es no", - "mysourcessayno": "Mis fuentes dicen que no", - "outlooknotsogood": "No pinta bien", - "verydoubtful": "Muy dudoso" - } - }, - "cat": { - "name": "gato", - "description": "¡Obtén una imagen aleatoria de un gato!", - "randomcat": "Gato aleatorio", - "newcat": "Nuevo gato", - "error": "Lo siento, tuve problemas para obtener una imagen de gato. ¡Por favor, inténtalo de nuevo más tarde!" - }, - "dog": { - "name": "perro", - "description": "¡Obtén una imagen aleatoria de un perro!", - "randomdog": "Perro aleatorio", - "newdog": "Nuevo perro", - "error": "Lo siento, tuve problemas para obtener una imagen de perro. ¡Por favor, inténtalo de nuevo más tarde!" - }, - "wiki": { - "name": "wiki", - "description": "Busca un tema en Wikipedia", - "pedia": "Wikipedia: {article}", - "error": "Lo siento, tuve problemas para obtener el artículo de Wikipedia. Por favor, inténtalo de nuevo más tarde!", - "nosummary": "No hay resumen disponible", - "readmoreonwiki": "Leer más" - }, - "weather": { - "name": "clima", - "description": "Obtén el clima actual de una ubicación", - "temperature": "Temperatura", - "feelslike": "Sensación térmica", - "default": "Clima", - "humidity": "Humedad", - "windspeed": "Velocidad del viento", - "pressure": "Presión", - "weatherin": "Clima en {location}", - "error": "Lo siento, tuve problemas para obtener el clima. ¡Por favor, inténtalo de nuevo más tarde!", - "nolocation": "Ubicación no encontrada. Por favor, revisa el nombre de la ciudad e inténtalo de nuevo.", - "apikeymissing": "La clave de API de OpenWeather falta o no es válida." - }, - "joke": { - "name": "chiste", - "description": "¡Obtén un chiste aleatorio!", - "waitingpunchline": "El remate aparecerá en {seconds} segundos…", - "error": "Lo siento, tuve problemas para obtener un chiste. ¡Por favor, inténtalo de nuevo más tarde!", - "type": { - "default": "Chiste de {type}", - "general": "General", - "programming": "Programación", - "dad": "Padre" - } + "dog": { + "name": "perro", + "description": "¡Obtén una imagen aleatoria de un perro!", + "randomdog": "Perro aleatorio", + "newdog": "Nuevo perro", + "error": "Lo siento, tuve problemas para obtener una imagen de perro. ¡Por favor, inténtalo de nuevo más tarde!" + }, + "wiki": { + "name": "wiki", + "description": "Busca un tema en Wikipedia", + "pedia": "Wikipedia: {article}", + "error": "Lo siento, tuve problemas para obtener el artículo de Wikipedia. Por favor, inténtalo de nuevo más tarde!", + "nosummary": "No hay resumen disponible", + "readmoreonwiki": "Leer más" + }, + "weather": { + "name": "clima", + "description": "Obtén el clima actual de una ubicación", + "temperature": "Temperatura", + "feelslike": "Sensación térmica", + "default": "Clima", + "humidity": "Humedad", + "windspeed": "Velocidad del viento", + "pressure": "Presión", + "weatherin": "Clima en {location}", + "error": "Lo siento, tuve problemas para obtener el clima. ¡Por favor, inténtalo de nuevo más tarde!", + "nolocation": "Ubicación no encontrada. Por favor, revisa el nombre de la ciudad e inténtalo de nuevo.", + "apikeymissing": "La clave de API de OpenWeather falta o no es válida." + }, + "joke": { + "name": "chiste", + "description": "¡Obtén un chiste aleatorio!", + "waitingpunchline": "El remate aparecerá en {seconds} segundos…", + "error": "Lo siento, tuve problemas para obtener un chiste. ¡Por favor, inténtalo de nuevo más tarde!", + "type": { + "default": "Chiste de {type}", + "general": "General", + "programming": "Programación", + "dad": "Padre" + } + }, + "help": { + "name": "ayuda", + "description": "Muestra todos los comandos disponibles y su uso", + "embed": { + "title": "Comandos de Aethel", + "description": "Aquí están todos los comandos disponibles" + }, + "nooptions": "Sin opciones" + }, + "remind": { + "name": "recordar", + "reminder": "¡Recordatorio!", + "remindyou": "Me pediste que te recordara sobre: {message}", + "timeelapsed": "Tiempo transcurrido", + "originaltime": "Hora original", + "errors": { + "base": "Se produjo un error al configurar tu recordatorio. Por favor, inténtalo de nuevo más tarde.", + "failedtosave": "No se pudo guardar tu recordatorio. Por favor, inténtalo de nuevo más tarde.", + "invalidformat": "¡Formato de tiempo no válido! Usa combinaciones como: 1h30m, 45m o 2h", + "providevalidchars": "Por favor, proporciona un mensaje válido (1-1000 caracteres)", + "atleastoneminute": "¡El recordatorio debe ser de al menos 1 minuto!", + "notlongerthanaday": "¡El recordatorio no puede ser mayor a 24 horas!" + }, + "modal": { + "setreminder": "Configurar recordatorio", + "whento": "¿Cuándo recordarte? (ej: 10m, 1h, 2h30m)" + }, + "reminderset": "Recordatorio configurado", + "iwillremindyou": "Te recordaré sobre {message} en {time}", + "contextiwillremindyou": "Te recordaré sobre este mensaje en {time}", + "time": "Tiempo", + "willtrigger": "Se activará", + "reminderid": "ID del recordatorio: {reminderId}" + }, + "whois": { + "name": "whois", + "description": "Busca información WHOIS de un dominio o dirección IP", + "error": "Lo siento, tuve problemas para obtener los datos WHOIS. ¡Por favor, inténtalo de nuevo más tarde!", + "nodata": "No se encontraron datos WHOIS para el dominio o IP especificado.", + "notvalid": "Por favor, proporciona un nombre de dominio o dirección IP válido." + }, + "ai": { + "name": "ai", + "description": "Chatea con un asistente de IA", + "optioins": { + "prompt": { + "name": "mensaje", + "description": "Tu mensaje para la IA" }, - "help": { - "name": "ayuda", - "description": "Muestra todos los comandos disponibles y su uso", - "embed": { - "title": "Comandos de Aethel", - "description": "Aquí están todos los comandos disponibles" - }, - "nooptions": "Sin opciones" + "customapi": "¿Usar tu propia clave API?", + "reset": "Restablecer tu historial de chat de IA" + }, + "request": { + "inprogress": "Ya tienes una solicitud en curso. Por favor, espera a que termine." + }, + "reset": "Tu historial de chat de IA ha sido restablecido.", + "defaultapi": " Cambiado a la API predeterminada. Tu clave API personalizada ha sido eliminada y se usará el modelo predeterminado.", + "modal": { + "title": "Introduce tus credenciales de API", + "apikey": "Clave API", + "apikeyplaceholder": "Para dejar de usar tu clave: /ai use_custom_api false", + "apiurl": "URL de la API", + "apiurlplaceholder": "Tu URL de API", + "model": "Modelo", + "modelplaceholder": "Nombre del modelo (ej. gpt-4)" + }, + "nopendingrequest": "No se encontró ninguna solicitud pendiente. Por favor, intenta el comando de nuevo.", + "apicredssaved": "Credenciales de API guardadas. Ahora puedes usar el comando `/ai` sin volver a ingresar tus credenciales. Para dejar de usar tu clave, usa `/ai use_custom_api false`", + "process": { + "dailylimit": "Has alcanzado tu límite diario de solicitudes de IA", + "noapikey": "Por favor, configura primero tu clave API" + }, + "errors": { + "failed": "No se pudo procesar la respuesta de la IA", + "nores": "Sin respuesta de la IA", + "toolong": "El mensaje es demasiado largo" + } + }, + "todo": { + "name": "todo", + "description": "Gestiona tu lista de tareas", + "add": { + "name": "add", + "description": "Añade una nueva tarea" + }, + "done": { + "name": "hecho", + "description": "Marca una tarea como hecha" + }, + "list": { + "name": "list", + "description": "Ver tu lista de tareas" + }, + "added": "✅ Tarea añadida: **{item}**", + "empty": "¡Tu lista de tareas está vacía! 🎉", + "list_title": "📝 Tu Lista de Tareas", + "checked": "✅ Tarea marcada como hecha: **{item}**", + "notfound": "No se encontró esa tarea: **{item}**", + "todo_title": "Tareas", + "done_title": "Hechas", + "none": "—", + "add_error": "❌ No se ha podido añadir su tarea. Inténtalo de nuevo más tarde.", + "done_error": "❌ No se ha podido marcar la tarea como realizada. Inténtalo de nuevo más tarde." + }, + "time": { + "embed": { + "footer_multi": "Se han encontrado varias ciudades con nombres similares", + "title_single": "Tiempo en {city}, {country}", + "title_multi": "Hora en {ciudad}", + "time_format": "dddd, MMMM D, YYYY, h:mm A z", + "notfound": "Ciudad no encontrada.", + "field_day_of_week": "Día de la semana", + "field_time": "Tiempo", + "field_date": "Fecha", + "footer": "Zona horaria: {timezone}", + "author": "Hora actual", + "multi_city_description": "Múltiples ciudades encontradas para “{city}”:" + }, + "name": "tiempo", + "description": "Obtener la hora actual de una zona horaria", + "option_timezone": { + "name": "zona horaria", + "description": "La zona horaria a comprobar (por ejemplo, Europa/Madrid)" + } + }, + "cobalt": { + "description": "Descarga un vídeo o audio de una URL determinada", + "options": { + "url": { + "name": "url", + "description": "La URL del vídeo que desea descargar" }, - "remind": { - "name": "recordar", - "reminder": "¡Recordatorio!", - "remindyou": "Me pediste que te recordara sobre: {message}", - "timeelapsed": "Tiempo transcurrido", - "originaltime": "Hora original", - "errors": { - "base": "Se produjo un error al configurar tu recordatorio. Por favor, inténtalo de nuevo más tarde.", - "failedtosave": "No se pudo guardar tu recordatorio. Por favor, inténtalo de nuevo más tarde.", - "invalidformat": "¡Formato de tiempo no válido! Usa combinaciones como: 1h30m, 45m o 2h", - "providevalidchars": "Por favor, proporciona un mensaje válido (1-1000 caracteres)", - "atleastoneminute": "¡El recordatorio debe ser de al menos 1 minuto!", - "notlongerthanaday": "¡El recordatorio no puede ser mayor a 24 horas!" - }, - "modal": { - "setreminder": "Configurar recordatorio", - "whento": "¿Cuándo recordarte? (ej: 10m, 1h, 2h30m)" - }, - "reminderset": "Recordatorio configurado", - "iwillremindyou": "Te recordaré sobre {message} en {time}", - "contextiwillremindyou": "Te recordaré sobre este mensaje en {time}", - "time": "Tiempo", - "willtrigger": "Se activará", - "reminderid": "ID del recordatorio: {reminderId}" + "video_quality": { + "name": "calidad de vídeo", + "description": "La calidad de vídeo para descargar" }, - "whois": { - "name": "whois", - "description": "Busca información WHOIS de un dominio o dirección IP", - "error": "Lo siento, tuve problemas para obtener los datos WHOIS. ¡Por favor, inténtalo de nuevo más tarde!", - "nodata": "No se encontraron datos WHOIS para el dominio o IP especificado.", - "notvalid": "Por favor, proporciona un nombre de dominio o dirección IP válido." + "audio_only": { + "name": "sólo-audio", + "description": "Descargar sólo sonido" }, - "ai": { - "name": "ai", - "description": "Chatea con un asistente de IA", - "optioins": { - "prompt": { - "name": "mensaje", - "description": "Tu mensaje para la IA" - }, - "customapi": "¿Usar tu propia clave API?", - "reset": "Restablecer tu historial de chat de IA" - }, - "request": { - "inprogress": "Ya tienes una solicitud en curso. Por favor, espera a que termine." - }, - "reset": "Tu historial de chat de IA ha sido restablecido.", - "defaultapi": " Cambiado a la API predeterminada. Tu clave API personalizada ha sido eliminada y se usará el modelo predeterminado.", - "modal": { - "title": "Introduce tus credenciales de API", - "apikey": "Clave API", - "apikeyplaceholder": "Para dejar de usar tu clave: /ai use_custom_api false", - "apiurl": "URL de la API", - "apiurlplaceholder": "Tu URL de API", - "model": "Modelo", - "modelplaceholder": "Nombre del modelo (ej. gpt-4)" - }, - "nopendingrequest": "No se encontró ninguna solicitud pendiente. Por favor, intenta el comando de nuevo.", - "apicredssaved": "Credenciales de API guardadas. Ahora puedes usar el comando `/ai` sin volver a ingresar tus credenciales. Para dejar de usar tu clave, usa `/ai use_custom_api false`", - "process": { - "dailylimit": "Has alcanzado tu límite diario de solicitudes de IA", - "noapikey": "Por favor, configura primero tu clave API" - }, - "errors": { - "failed": "No se pudo procesar la respuesta de la IA", - "nores": "Sin respuesta de la IA", - "toolong": "El mensaje es demasiado largo" - } + "mute_audio": { + "name": "silencia-sonido", + "description": "Silenciar sonido" }, - "todo": { - "name": "todo", - "description": "Gestiona tu lista de tareas", - "add": { - "name": "add", - "description": "Añade una nueva tarea" - }, - "done": { - "name": "hecho", - "description": "Marca una tarea como hecha" - }, - "list": { - "name": "list", - "description": "Ver tu lista de tareas" - }, - "added": "✅ Tarea añadida: **{item}**", - "empty": "¡Tu lista de tareas está vacía! 🎉", - "list_title": "📝 Tu Lista de Tareas", - "checked": "✅ Tarea marcada como hecha: **{item}**", - "notfound": "No se encontró esa tarea: **{item}**", - "todo_title": "Tareas", - "done_title": "Hechas", - "none": "—", - "add_error": "❌ No se ha podido añadir su tarea. Inténtalo de nuevo más tarde.", - "done_error": "❌ No se ha podido marcar la tarea como realizada. Inténtalo de nuevo más tarde." + "twitter_gif": { + "name": "gif-twitter", + "description": "Descargar como GIF de Twitter" }, - "time": { - "embed": { - "footer_multi": "Se han encontrado varias ciudades con nombres similares", - "title_single": "Tiempo en {city}, {country}", - "title_multi": "Hora en {ciudad}", - "time_format": "dddd, MMMM D, YYYY, h:mm A z", - "notfound": "Ciudad no encontrada.", - "field_day_of_week": "Día de la semana", - "field_time": "Tiempo", - "field_date": "Fecha", - "footer": "Zona horaria: {timezone}", - "author": "Hora actual", - "multi_city_description": "Múltiples ciudades encontradas para “{city}”:" - }, - "name": "tiempo", - "description": "Obtener la hora actual de una zona horaria", - "option_timezone": { - "name": "zona horaria", - "description": "La zona horaria a comprobar (por ejemplo, Europa/Madrid)" - } + "tiktok_original_audio": { + "description": "Incluye el sonido original de TikTok", + "name": "tiktok-sonido-original" }, - "cobalt": { - "description": "Descarga un vídeo o audio de una URL determinada", - "options": { - "url": { - "name": "url", - "description": "La URL del vídeo que desea descargar" - }, - "video_quality": { - "name": "calidad de vídeo", - "description": "La calidad de vídeo para descargar" - }, - "audio_only": { - "name": "sólo-audio", - "description": "Descargar sólo sonido" - }, - "mute_audio": { - "name": "silencia-sonido", - "description": "Silenciar sonido" - }, - "twitter_gif": { - "name": "gif-twitter", - "description": "Descargar como GIF de Twitter" - }, - "tiktok_original_audio": { - "description": "Incluye el sonido original de TikTok", - "name": "tiktok-sonido-original" - }, - "audio_format": { - "name": "formato-audio", - "description": "Formato para audio (requiere que only-audio sea verdadero)" - } - }, - "button_label": "Descargar", - "error": "❌ **Error:** {error}", - "unknown_error": "Se ha producido un error desconocido.", - "rate_limit": "⏳ **Límite de tarifa excedido.** Por favor, inténtelo de nuevo más tarde.", - "unknown_response": "❓ **Respuesta desconocida de la API.** Por favor, inténtelo de nuevo.", - "local_processing_not_supported": "⚠️ **El procesamiento local no está soportado.** Por favor, intente una URL u opción diferente.", - "name": "cobalt", - "multiple_items": "📋 **Múltiples elementos encontrados para esta URL.** Por favor, proporcione una URL más específica.", - "success": "✅ **¡Descarga lista!**\n\n🔗 {url}\n📥 **Haz clic en el botón de abajo para descargar tu archivo.**" + "audio_format": { + "name": "formato-audio", + "description": "Formato para audio (requiere que only-audio sea verdadero)" } - }, - "time": { - "name": "hora", - "description": "Obtén la hora actual de una ubicación", - "embed": { - "title_single": "Hora para {city}, {country}", - "title_multi": "Hora para {city}", - "time_format": "dddd, D [de] MMMM [de] YYYY, h:mm A z", - "notfound": "Ciudad no encontrada.", - "day_of_week": "Día de la semana: {day}", - "time": "Hora: {time}", - "date": "Fecha: {date}", - "bullet": "• {city}, {country}:\n{day_of_week}\n{time}\n{date}", - "footer": "Zona horaria: {timezone}", - "author": "Hora actual", - "multi_city_description": "Se encontraron varias ciudades para '{city}':", - "field_day_of_week": "**Día de la semana**", - "field_time": "**Hora**", - "field_date": "**Fecha**" - }, - "error": "Lo siento, tuve problemas para obtener la hora. ¡Por favor, inténtalo de nuevo más tarde!", - "nolocation": "Ubicación no encontrada. Por favor, revisa el nombre de la ciudad e inténtalo de nuevo.", - "apikeymissing": "La clave de API de OpenWeather falta o no es válida." - }, - "categories": { - "fun": "Diversión", - "info": "Información", - "utilities": "Utilidades" + }, + "button_label": "Descargar", + "error": "❌ **Error:** {error}", + "unknown_error": "Se ha producido un error desconocido.", + "rate_limit": "⏳ **Límite de tarifa excedido.** Por favor, inténtelo de nuevo más tarde.", + "unknown_response": "❓ **Respuesta desconocida de la API.** Por favor, inténtelo de nuevo.", + "local_processing_not_supported": "⚠️ **El procesamiento local no está soportado.** Por favor, intente una URL u opción diferente.", + "name": "cobalt", + "multiple_items": "📋 **Múltiples elementos encontrados para esta URL.** Por favor, proporcione una URL más específica.", + "success": "✅ **¡Descarga lista!**\n\n🔗 {url}\n📥 **Haz clic en el botón de abajo para descargar tu archivo.**" } + }, + "time": { + "name": "hora", + "description": "Obtén la hora actual de una ubicación", + "embed": { + "title_single": "Hora para {city}, {country}", + "title_multi": "Hora para {city}", + "time_format": "dddd, D [de] MMMM [de] YYYY, h:mm A z", + "notfound": "Ciudad no encontrada.", + "day_of_week": "Día de la semana: {day}", + "time": "Hora: {time}", + "date": "Fecha: {date}", + "bullet": "• {city}, {country}:\n{day_of_week}\n{time}\n{date}", + "footer": "Zona horaria: {timezone}", + "author": "Hora actual", + "multi_city_description": "Se encontraron varias ciudades para '{city}':", + "field_day_of_week": "**Día de la semana**", + "field_time": "**Hora**", + "field_date": "**Fecha**" + }, + "error": "Lo siento, tuve problemas para obtener la hora. ¡Por favor, inténtalo de nuevo más tarde!", + "nolocation": "Ubicación no encontrada. Por favor, revisa el nombre de la ciudad e inténtalo de nuevo.", + "apikeymissing": "La clave de API de OpenWeather falta o no es válida." + }, + "categories": { + "fun": "Diversión", + "info": "Información", + "utilities": "Utilidades" + } } diff --git a/src/commands/fun/8ball.ts b/src/commands/fun/8ball.ts index ef336f9..72f99b6 100644 --- a/src/commands/fun/8ball.ts +++ b/src/commands/fun/8ball.ts @@ -1,8 +1,11 @@ import { SlashCommandBuilder, - EmbedBuilder, ApplicationIntegrationType, InteractionContextType, + ContainerBuilder, + SectionBuilder, + ButtonStyle, + MessageFlags, } from 'discord.js'; import { validateCommandOptions, sanitizeInput } from '@/utils/validation'; import { SlashCommandProps } from '@/types/command'; @@ -99,7 +102,7 @@ export default { if (!validation.isValid) { return interaction.reply({ content: validation.message, - ephemeral: true, + flags: MessageFlags.Ephemeral, }); } @@ -112,24 +115,34 @@ export default { interaction, `question: "${question?.substring(0, 50)}${question && question.length > 50 ? '...' : ''}"` ); - const [title, questionLabel, answerLabel, footer] = await Promise.all([ + const [title, questionLabel, answerLabel, askAgainLabel] = await Promise.all([ await client.getLocaleText('commands.8ball.says', interaction.locale), await client.getLocaleText('commands.8ball.question', interaction.locale), await client.getLocaleText('commands.8ball.answer', interaction.locale), - await client.getLocaleText('commands.8ball.anotherfortune', interaction.locale), + await client.getLocaleText('commands.8ball.askagain', interaction.locale), ]); - const embed = new EmbedBuilder() - .setColor(0x3498db) - .setTitle(title) - .addFields( - { name: `🎱 ${questionLabel}`, value: question }, - { name: answerLabel, value: `**${translatedResponse}**` } - ) - .setFooter({ text: footer }) - .setTimestamp(); + const container = new ContainerBuilder().setAccentColor(0x8b5cf6).addSectionComponents( + new SectionBuilder() + .addTextDisplayComponents((textDisplay) => + textDisplay.setContent( + `# 🔮 ${title}\n\n> **${questionLabel}**\n> ${question}\n\n## ✨ ${answerLabel}\n### ${translatedResponse}` + ) + ) + .setButtonAccessory((button) => + button + .setLabel(`🎲 ${askAgainLabel}`) + .setStyle(ButtonStyle.Primary) + .setCustomId( + `8ball_reroll_${interaction.user.id}_${Date.now()}_${encodeURIComponent(question)}` + ) + ) + ); - await interaction.reply({ embeds: [embed] }); + await interaction.reply({ + components: [container], + flags: MessageFlags.IsComponentsV2, + }); } catch (error) { await errorHandler({ interaction, diff --git a/src/commands/fun/cat.ts b/src/commands/fun/cat.ts index c405228..6d41c63 100644 --- a/src/commands/fun/cat.ts +++ b/src/commands/fun/cat.ts @@ -1,11 +1,13 @@ import { SlashCommandBuilder, - ButtonBuilder, ButtonStyle, - ActionRowBuilder, - EmbedBuilder, ApplicationIntegrationType, InteractionContextType, + ContainerBuilder, + SectionBuilder, + MediaGalleryBuilder, + MediaGalleryItemBuilder, + MessageFlags, } from 'discord.js'; import fetch from '@/utils/dynamicFetch'; import { sanitizeInput } from '@/utils/validation'; @@ -77,28 +79,36 @@ export default { ? sanitizeInput(catData.title).slice(0, 245) + '...' : await client.getLocaleText('random.cat', interaction.locale); - const embed = new EmbedBuilder().setColor(0xfaa0a0).setTitle(title).setImage(catData.url); - - embed.setFooter({ - text: (await client.getLocaleText('poweredby', interaction.locale)) + ' pur.cat', - }); + const refreshLabel = await client.getLocaleText('commands.cat.newcat', interaction.locale); + let content = `# ${title}\n\n`; if (catData.subreddit) { const fromText = await client.getLocaleText('reddit.from', interaction.locale, { subreddit: catData.subreddit, }); - embed.setDescription(fromText); + content += `${fromText}`; } - const refreshLabel = await client.getLocaleText('commands.cat.newcat', interaction.locale); - const refreshButton = new ButtonBuilder() - .setCustomId('refresh_cat') - .setLabel(refreshLabel) - .setStyle(ButtonStyle.Danger) - .setEmoji('🐱'); - const row = new ActionRowBuilder().addComponents(refreshButton); + + const container = new ContainerBuilder() + .setAccentColor(0xfaa0a0) + .addMediaGalleryComponents( + new MediaGalleryBuilder().addItems(new MediaGalleryItemBuilder().setURL(catData.url)) + ) + .addSectionComponents( + new SectionBuilder() + .addTextDisplayComponents((textDisplay) => textDisplay.setContent(content)) + .setButtonAccessory((button) => + button + .setLabel(refreshLabel) + .setStyle(ButtonStyle.Danger) + .setEmoji({ name: '🐱' }) + .setCustomId('refresh_cat') + ) + ); + await interaction.editReply({ - embeds: [embed], - components: [row], + components: [container], + flags: MessageFlags.IsComponentsV2, }); } catch (error) { await errorHandler({ diff --git a/src/commands/fun/dog.ts b/src/commands/fun/dog.ts index 389e3c4..fc2234c 100644 --- a/src/commands/fun/dog.ts +++ b/src/commands/fun/dog.ts @@ -1,11 +1,13 @@ import { SlashCommandBuilder, - ButtonBuilder, ButtonStyle, - ActionRowBuilder, - EmbedBuilder, InteractionContextType, ApplicationIntegrationType, + ContainerBuilder, + SectionBuilder, + MediaGalleryBuilder, + MediaGalleryItemBuilder, + MessageFlags, } from 'discord.js'; import fetch from '@/utils/dynamicFetch'; import { sanitizeInput } from '@/utils/validation'; @@ -78,27 +80,36 @@ export default { ? sanitizeInput(dogData.title).slice(0, 245) + '...' : await client.getLocaleText('commands.dog.randomdog', interaction.locale); - const embed = new EmbedBuilder().setColor(0x8a2be2).setTitle(title).setImage(dogData.url); - embed.setFooter({ - text: (await client.getLocaleText('poweredby', interaction.locale)) + ' erm.dog', - }); + const refreshLabel = await client.getLocaleText('commands.dog.newdog', interaction.locale); + let content = `# ${title}\n\n`; if (dogData.subreddit) { const fromText = await client.getLocaleText('reddit.from', interaction.locale, { subreddit: dogData.subreddit, }); - embed.setDescription(fromText); + content += `${fromText}`; } - const refreshLabel = await client.getLocaleText('commands.dog.newdog', interaction.locale); - const refreshButton = new ButtonBuilder() - .setCustomId('refresh_dog') - .setLabel(refreshLabel) - .setStyle(ButtonStyle.Secondary) - .setEmoji('🐶'); - const row = new ActionRowBuilder().addComponents(refreshButton); + + const container = new ContainerBuilder() + .setAccentColor(0x8a2be2) + .addMediaGalleryComponents( + new MediaGalleryBuilder().addItems(new MediaGalleryItemBuilder().setURL(dogData.url)) + ) + .addSectionComponents( + new SectionBuilder() + .addTextDisplayComponents((textDisplay) => textDisplay.setContent(content)) + .setButtonAccessory((button) => + button + .setLabel(refreshLabel) + .setStyle(ButtonStyle.Secondary) + .setEmoji({ name: '🐶' }) + .setCustomId('refresh_dog') + ) + ); + await interaction.editReply({ - embeds: [embed], - components: [row], + components: [container], + flags: MessageFlags.IsComponentsV2, }); } catch (error) { await errorHandler({ diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts index cf3aa9d..0ddf265 100644 --- a/src/events/interactionCreate.ts +++ b/src/events/interactionCreate.ts @@ -6,11 +6,13 @@ import logger from '@/utils/logger'; import { sanitizeInput, getUnallowedWordCategory } from '@/utils/validation'; import { isUserBanned, incrementUserStrike } from '@/utils/userStrikes'; import { - ActionRowBuilder, - ButtonBuilder, ButtonStyle, ClientEvents, - EmbedBuilder, + ContainerBuilder, + SectionBuilder, + MessageFlags, + MediaGalleryBuilder, + MediaGalleryItemBuilder, } from 'discord.js'; type InteractionHandler = (...args: ClientEvents['interactionCreate']) => void; @@ -134,31 +136,36 @@ export default class InteractionCreateEvent { ? sanitizeInput(data.title).slice(0, 245) + '...' : await this.client.getLocaleText('random.cat', i.locale); - const embed = new EmbedBuilder() - .setColor(0xfaa0a0) - .setTitle(title) - .setImage(data.url); - - const footerText = - (await this.client.getLocaleText('poweredby', i.locale)) + ' pur.cat'; - embed.setFooter({ text: footerText }); + const refreshLabel = await this.client.getLocaleText('commands.cat.newcat', i.locale); + let content = `# ${title}\n\n`; if (data.subreddit) { const fromText = await this.client.getLocaleText('reddit.from', i.locale, { subreddit: data.subreddit, }); - embed.setDescription(fromText); + content += `${fromText}`; } - const refreshLabel = await this.client.getLocaleText('commands.cat.newcat', i.locale); - const refreshButton = new ButtonBuilder() - .setCustomId('refresh_cat') - .setLabel(refreshLabel) - .setStyle(ButtonStyle.Danger) - .setEmoji('🐱'); - const row = new ActionRowBuilder().addComponents(refreshButton); + + const container = new ContainerBuilder() + .setAccentColor(0xfaa0a0) + .addMediaGalleryComponents( + new MediaGalleryBuilder().addItems(new MediaGalleryItemBuilder().setURL(data.url)) + ) + .addSectionComponents( + new SectionBuilder() + .addTextDisplayComponents((textDisplay) => textDisplay.setContent(content)) + .setButtonAccessory((button) => + button + .setLabel(refreshLabel) + .setStyle(ButtonStyle.Danger) + .setEmoji({ name: '🐱' }) + .setCustomId('refresh_cat') + ) + ); + await i.update({ - embeds: [embed], - components: [row], + components: [container], + flags: MessageFlags.IsComponentsV2, }); } else { await i.update({ @@ -173,6 +180,91 @@ export default class InteractionCreateEvent { components: [], }); } + } else if (i.customId.startsWith('8ball_reroll_')) { + const customIdParts = i.customId.split('_'); + const originalUserId = customIdParts[2]; + + if (originalUserId !== i.user.id) { + return await i.reply({ + content: 'Only the person who used the command can reroll the 8ball!', + flags: MessageFlags.Ephemeral, + }); + } + + let question = 'What will happen?'; + + try { + const customIdParts = i.customId.split('_'); + if (customIdParts.length >= 5) { + const encodedQuestion = customIdParts.slice(4).join('_'); + question = decodeURIComponent(encodedQuestion); + } + } catch (error) { + console.log('Error extracting question:', error); + } + + const responses = [ + 'itiscertain', + 'itisdecidedlyso', + 'withoutadoubt', + 'yesdefinitely', + 'youmayrelyonit', + 'asiseeityes', + 'mostlikely', + 'outlookgood', + 'yes', + 'signspointtoyes', + 'replyhazytryagain', + 'askagainlater', + 'betternottellyounow', + 'cannotpredictnow', + 'concentrateandaskagain', + 'dontcountonit', + 'myreplyisno', + 'mysourcessayno', + 'outlooknotsogood', + 'verydoubtful', + ]; + + const randomResponse = responses[Math.floor(Math.random() * responses.length)]; + + const title = await this.client.getLocaleText('commands.8ball.says', i.locale); + const questionLabel = await this.client.getLocaleText( + 'commands.8ball.question', + i.locale + ); + const answerLabel = await this.client.getLocaleText('commands.8ball.answer', i.locale); + const askAgainLabel = await this.client.getLocaleText( + 'commands.8ball.askagain', + i.locale + ); + + const translatedResponse = await this.client.getLocaleText( + `commands.8ball.responces.${randomResponse}`, + i.locale + ); + + const container = new ContainerBuilder().setAccentColor(0x8b5cf6).addSectionComponents( + new SectionBuilder() + .addTextDisplayComponents((textDisplay) => + textDisplay.setContent( + `# 🔮 ${title}\n\n> **${questionLabel}**\n> ${question}\n\n## ✨ ${answerLabel}\n### ${translatedResponse}` + ) + ) + .setButtonAccessory((button) => + button + .setLabel(`🎱 ${askAgainLabel}`) + .setStyle(ButtonStyle.Primary) + .setCustomId( + `8ball_reroll_${i.user.id}_${Date.now()}_${encodeURIComponent(question)}` + ) + ) + ); + + await i.update({ + components: [container], + flags: MessageFlags.IsComponentsV2, + }); } else if (i.customId === 'refresh_dog') { try { const response = await fetch('https://api.erm.dog/random-dog', { @@ -206,31 +298,38 @@ export default class InteractionCreateEvent { ? sanitizeInput(data!.title).slice(0, 245) + '...' : await this.client.getLocaleText('commands.dog.randomdog', i.locale); - const embed = new EmbedBuilder() - .setColor(0x8a2be2) - .setTitle(title) - .setImage(data!.url); - - const footerText = - (await this.client.getLocaleText('poweredby', i.locale)) + ' erm.dog'; - embed.setFooter({ text: footerText }); + const refreshLabel = await this.client.getLocaleText('commands.dog.newdog', i.locale); + let content = `# ${title}\n\n`; if (data!.subreddit) { const fromText = await this.client.getLocaleText('reddit.from', i.locale, { subreddit: data!.subreddit, }); - embed.setDescription(fromText); + content += `${fromText}`; } - const refreshLabel = await this.client.getLocaleText('commands.dog.newdog', i.locale); - const refreshButton = new ButtonBuilder() - .setCustomId('refresh_dog') - .setLabel(refreshLabel) - .setStyle(ButtonStyle.Secondary) - .setEmoji('🐶'); - const row = new ActionRowBuilder().addComponents(refreshButton); + + const container = new ContainerBuilder() + .setAccentColor(0x8a2be2) + .addMediaGalleryComponents( + new MediaGalleryBuilder().addItems( + new MediaGalleryItemBuilder().setURL(data!.url) + ) + ) + .addSectionComponents( + new SectionBuilder() + .addTextDisplayComponents((textDisplay) => textDisplay.setContent(content)) + .setButtonAccessory((button) => + button + .setLabel(refreshLabel) + .setStyle(ButtonStyle.Secondary) + .setEmoji({ name: '🐶' }) + .setCustomId('refresh_dog') + ) + ); + await i.update({ - embeds: [embed], - components: [row], + components: [container], + flags: MessageFlags.IsComponentsV2, }); } else { await i.update({ -- 2.51.2