mirror of
https://github.com/SrIzan10/vinci.git
synced 2026-06-06 09:17:02 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 045c89a6cb | |||
| 8dcd2de683 | |||
| e3c63632a1 | |||
| a6df2e4f31 | |||
| 502811ca9f | |||
| 58dd540ea9 | |||
| 589f53c65c | |||
| 66594ce8bd | |||
| effbe7d9c5 |
7
.devcontainer/devcontainer.json
Normal file
7
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"image": "mcr.microsoft.com/devcontainers/universal:2",
|
||||
"runArgs": ["--device=/dev/net/tun"],
|
||||
"features": {
|
||||
"ghcr.io/tailscale/codespace/tailscale": {}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
node_modules
|
||||
images
|
||||
.env*
|
||||
dist
|
||||
node_modules/
|
||||
json.sqlite
|
||||
dist/
|
||||
*giveaway*
|
||||
.sern
|
||||
/generated/generated/prisma
|
||||
prisma/vinci.db
|
||||
!.env.example
|
||||
33
.env.example
33
.env.example
@@ -1,8 +1,27 @@
|
||||
# THIS IS OUTDATED
|
||||
DISCORD_TOKEN=
|
||||
PREFIX=
|
||||
# Database (before rewrites)
|
||||
MONGODB=
|
||||
# API keys
|
||||
CATAPI=
|
||||
DOGAPI=
|
||||
TWITTER=
|
||||
# request makesweet creator for this
|
||||
MAKESWEET=
|
||||
GENIUS=
|
||||
SPOTIFY_CLIENT=
|
||||
SPOTIFY_SECRET=
|
||||
CF_AI_TOKEN=
|
||||
CF_AI_ACC=
|
||||
# Guild configs
|
||||
GUILDID=
|
||||
SUGGESTIONS_CHANNEL=
|
||||
MODLOGS_CHANNEL=
|
||||
JOINSANDLEAVES_CHANNEL=
|
||||
SOCIALS_CHANNEL=
|
||||
GIVEAWAYS_CHANNEL=
|
||||
MCFORM_CHANNEL=
|
||||
CHATGPT_CHANNEL=
|
||||
T_CHANNEL=
|
||||
|
||||
TOKEN=token
|
||||
PREFIX=v!
|
||||
MONGODB=mongodb://
|
||||
HYPIXEL_API=API_KEY
|
||||
YOURLS_KEY=YOURLS_SIGNATURE
|
||||
YOUTUBE_API=
|
||||
NODE_ENV=development
|
||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,6 +1,11 @@
|
||||
.env
|
||||
.env.dev
|
||||
.env*
|
||||
node_modules/
|
||||
json.sqlite
|
||||
dist/
|
||||
*giveaway*
|
||||
*giveaway*
|
||||
.sern
|
||||
/generated/generated/prisma
|
||||
src/utils/db/dict.db
|
||||
prisma/vinci.db
|
||||
!.env.example
|
||||
.codex
|
||||
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
65
.idea/codeStyles/Project.xml
generated
65
.idea/codeStyles/Project.xml
generated
@@ -1,65 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||
<option name="HTML_QUOTE_STYLE" value="Single" />
|
||||
<option name="HTML_ENFORCE_QUOTES" value="true" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</JSCodeStyleSettings>
|
||||
<TypeScriptCodeStyleSettings version="0">
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</TypeScriptCodeStyleSettings>
|
||||
<VueCodeStyleSettings>
|
||||
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
|
||||
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
|
||||
</VueCodeStyleSettings>
|
||||
<codeStyleSettings language="HTML">
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="TypeScript">
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Vue">
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
7
.idea/discord.xml
generated
7
.idea/discord.xml
generated
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
<option name="description" value="" />
|
||||
</component>
|
||||
</project>
|
||||
10
.idea/inspectionProfiles/Project_Default.xml
generated
10
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,10 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
6
.idea/misc.xml
generated
6
.idea/misc.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/vinci.iml" filepath="$PROJECT_DIR$/.idea/vinci.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/vinci.iml
generated
9
.idea/vinci.iml
generated
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"tabWidth": 2,
|
||||
"useTabs": true,
|
||||
"singleQuote": true
|
||||
"useTabs": false,
|
||||
"printWidth": 100,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"semi": true
|
||||
}
|
||||
124
.sern/ambient.d.ts
vendored
124
.sern/ambient.d.ts
vendored
@@ -1,124 +0,0 @@
|
||||
declare var __DEV__: boolean
|
||||
declare var __PROD__: boolean
|
||||
declare var __VERSION__: string
|
||||
declare namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
SHELL:string
|
||||
SESSION_MANAGER:string
|
||||
COLORTERM:string
|
||||
XDG_CONFIG_DIRS:string
|
||||
XDG_SESSION_PATH:string
|
||||
COREPACK_ENABLE_DOWNLOAD_PROMPT:string
|
||||
NVM_INC:string
|
||||
XDG_MENU_PREFIX:string
|
||||
TERM_PROGRAM_VERSION:string
|
||||
ICEAUTHORITY:string
|
||||
NODE_OPTIONS:string
|
||||
LC_ADDRESS:string
|
||||
LC_NAME:string
|
||||
MEMORY_PRESSURE_WRITE:string
|
||||
DESKTOP_SESSION:string
|
||||
LC_MONETARY:string
|
||||
GTK_RC_FILES:string
|
||||
NO_AT_BRIDGE:string
|
||||
EDITOR:string
|
||||
XDG_SEAT:string
|
||||
PWD:string
|
||||
LOGNAME:string
|
||||
XDG_SESSION_DESKTOP:string
|
||||
XDG_SESSION_TYPE:string
|
||||
SYSTEMD_EXEC_PID:string
|
||||
_:string
|
||||
XAUTHORITY:string
|
||||
VSCODE_GIT_ASKPASS_NODE:string
|
||||
MOTD_SHOWN:string
|
||||
GTK2_RC_FILES:string
|
||||
HOME:string
|
||||
COREPACK_ROOT:string
|
||||
LANG:string
|
||||
LC_PAPER:string
|
||||
XDG_CURRENT_DESKTOP:string
|
||||
npm_package_version:string
|
||||
MEMORY_PRESSURE_WATCH:string
|
||||
STARSHIP_SHELL:string
|
||||
WAYLAND_DISPLAY:string
|
||||
GIT_ASKPASS:string
|
||||
XDG_SEAT_PATH:string
|
||||
INVOCATION_ID:string
|
||||
MANAGERPID:string
|
||||
INIT_CWD:string
|
||||
CHROME_DESKTOP:string
|
||||
STARSHIP_SESSION_KEY:string
|
||||
KDE_SESSION_UID:string
|
||||
NVM_DIR:string
|
||||
VSCODE_GIT_ASKPASS_EXTRA_ARGS:string
|
||||
XKB_DEFAULT_LAYOUT:string
|
||||
XDG_ACTIVATION_TOKEN:string
|
||||
XDG_SESSION_CLASS:string
|
||||
LC_IDENTIFICATION:string
|
||||
TERM:string
|
||||
npm_package_name:string
|
||||
PROJECT_CWD:string
|
||||
USER:string
|
||||
VSCODE_GIT_IPC_HANDLE:string
|
||||
QT_WAYLAND_RECONNECT:string
|
||||
KDE_SESSION_VERSION:string
|
||||
PAM_KWALLET5_LOGIN:string
|
||||
DISPLAY:string
|
||||
npm_lifecycle_event:string
|
||||
SHLVL:string
|
||||
NVM_CD_FLAGS:string
|
||||
LC_TELEPHONE:string
|
||||
LC_MEASUREMENT:string
|
||||
XDG_VTNR:string
|
||||
XDG_SESSION_ID:string
|
||||
npm_config_user_agent:string
|
||||
npm_execpath:string
|
||||
XDG_RUNTIME_DIR:string
|
||||
DEBUGINFOD_URLS:string
|
||||
npm_package_json:string
|
||||
LC_TIME:string
|
||||
BUN_INSTALL:string
|
||||
BERRY_BIN_FOLDER:string
|
||||
XKB_DEFAULT_VARIANT:string
|
||||
VSCODE_GIT_ASKPASS_MAIN:string
|
||||
QT_AUTO_SCREEN_SCALE_FACTOR:string
|
||||
JOURNAL_STREAM:string
|
||||
XDG_DATA_DIRS:string
|
||||
KDE_FULL_SESSION:string
|
||||
GDK_BACKEND:string
|
||||
BROWSER:string
|
||||
PATH:string
|
||||
ORIGINAL_XDG_CURRENT_DESKTOP:string
|
||||
DBUS_SESSION_BUS_ADDRESS:string
|
||||
KDE_APPLICATIONS_AS_SCOPE:string
|
||||
MAIL:string
|
||||
NVM_BIN:string
|
||||
npm_node_execpath:string
|
||||
LC_NUMERIC:string
|
||||
OLDPWD:string
|
||||
TERM_PROGRAM:string
|
||||
TOKEN:string
|
||||
PREFIX:string
|
||||
MONGODB:string
|
||||
YOURLS_KEY:string
|
||||
CATAPI:string
|
||||
DOGAPI:string
|
||||
TWITTER:string
|
||||
MAKESWEET:string
|
||||
GENIUS:string
|
||||
SPOTIFY_CLIENT:string
|
||||
SPOTIFY_SECRET:string
|
||||
CF_AI_TOKEN:string
|
||||
CF_AI_ACC:string
|
||||
GUILDID:string
|
||||
SUGGESTIONS_CHANNEL:string
|
||||
MODLOGS_CHANNEL:string
|
||||
JOINSANDLEAVES_CHANNEL:string
|
||||
SOCIALS_CHANNEL:string
|
||||
BIRTHDAYS_CHANNEL:string
|
||||
MCFORM_CHANNEL:string
|
||||
CHATGPT_CHANNEL:string
|
||||
T_CHANNEL:string
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node16",
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"target": "esnext",
|
||||
"rootDirs": [
|
||||
"./generated",
|
||||
"../src"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./ambient.d.ts",
|
||||
"../src"
|
||||
]
|
||||
}
|
||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -1,3 +1,7 @@
|
||||
{
|
||||
"dotenv.enableAutocloaking": false
|
||||
"dotenv.enableAutocloaking": false,
|
||||
"editor.tabSize": 2,
|
||||
"editor.detectIndentation": false,
|
||||
"editor.insertSpaces": true,
|
||||
"editor.rulers": [100]
|
||||
}
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
nodeLinker: node-modules
|
||||
50
Dockerfile
50
Dockerfile
@@ -1,31 +1,39 @@
|
||||
FROM node:lts
|
||||
|
||||
# Build stage
|
||||
FROM node:lts-alpine AS build
|
||||
|
||||
FROM oven/bun:alpine AS base
|
||||
WORKDIR /app
|
||||
RUN bun add -g @sern/cli
|
||||
|
||||
RUN apk add --no-cache --virtual .gyp python3 make g++
|
||||
# Install dependencies
|
||||
FROM base AS deps
|
||||
COPY package.json bun.lock ./
|
||||
RUN bun install --frozen-lockfile --ignore-scripts
|
||||
|
||||
# Build the application
|
||||
FROM base AS build
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
RUN corepack enable yarn
|
||||
RUN yarn
|
||||
|
||||
RUN yarn build
|
||||
|
||||
# Final stage
|
||||
FROM node:lts-alpine AS final
|
||||
RUN bun prisma generate
|
||||
RUN bun run build
|
||||
|
||||
# Production image
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=build /app/dist ./dist
|
||||
COPY --from=build /app/src ./src
|
||||
COPY --from=build /app/.sern ./.sern
|
||||
COPY --from=build /app/assets ./assets
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
COPY --from=build /app/package.json ./package.json
|
||||
RUN apk add --no-cache ffmpeg msttcorefonts-installer fontconfig && \
|
||||
ENV NODE_ENV=production
|
||||
|
||||
# Install system dependencies
|
||||
RUN apk add --no-cache ffmpeg fontconfig ttf-opensans msttcorefonts-installer && \
|
||||
update-ms-fonts && \
|
||||
fc-cache -f
|
||||
|
||||
CMD ["node", "dist/index.js"]
|
||||
RUN mkdir -p ./src/utils/db && \
|
||||
wget -O ./src/utils/db/dict.db https://github.com/SrIzan10/vinci/releases/download/dict-1/dict.db
|
||||
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
COPY --from=build /app/dist ./dist
|
||||
COPY --from=build /app/assets ./assets
|
||||
COPY --from=build /app/images ./images
|
||||
COPY --from=build /app/.sern ./.sern
|
||||
COPY --from=build /app/package.json ./package.json
|
||||
COPY --from=build /app/prisma ./prisma
|
||||
|
||||
CMD ["sh", "-c", "bun run db:migrate && bun dist/index.js"]
|
||||
|
||||
62
README.md
62
README.md
@@ -1,30 +1,46 @@
|
||||
vinci bot
|
||||
# vinci v2
|
||||
|
||||
# little shoutout
|
||||
this discord bot has been made with [sern handler](https://sern.dev) and MAN I LOVE THIS HANDLER.
|
||||
Vinci v2 is a rewrite of my first JS project, a discord bot for [my favorite book series](https://maraturing.com) server. It aims to improve the code quality of the primary codebase, full of bugs and spaghetti code.
|
||||
|
||||
the maintainers helped me out from day one of the bot (and also teached me a lotta js along the way)
|
||||
It is written, as always, under the [sern](https://sern.dev) framework.
|
||||
|
||||
so tysm for everything, and I hope I can continue making new bots with this <3
|
||||
It is 85% done, with hardest commands implemented.
|
||||
|
||||
(also, fellow programmer, consider using it please)
|
||||
This is a bot submission for [Converge](https://converge.hackclub.com) and [Summer of Making](https://summer.hackclub.com).
|
||||
|
||||
# badges yes sir
|
||||
[](https://www.codefactor.io/repository/github/srizan10/vinci) [](https://wakatime.com/badge/user/4ad16edf-eadc-48d9-b010-26f275fe0be6/project/120bd895-55e3-42fe-894b-bd974f6f7312)
|
||||
## New features
|
||||
- More fun games
|
||||
- Modern typescript and discord.js
|
||||
- SQLite + Prisma instead of MongoDB + Mongoose
|
||||
- Less API queries and more performance by using local datasets (like the Spanish dictionary)
|
||||
|
||||
# warning and stuff
|
||||
# Available commands
|
||||
- `/rolemenu` - Role selection menu (owner only)
|
||||
- `/sugerencias` - Send a suggestion to the channel with upvote/downvote buttons
|
||||
- `/mcform` - Submit a form to join a Minecraft server
|
||||
- `/ip` - Get information about the Minecraft server IP
|
||||
- `/acortar` - Shorten a URL
|
||||
- `/wikipedia` - Search Wikipedia (Spanish/English)
|
||||
- `/8ball` - Ask the magic 8-ball a question
|
||||
- `/a` - Autogenerated "A" text with user autocomplete
|
||||
- `/chiste` - Get a random joke from a local dataset
|
||||
- `/google` - The most useless Google search command
|
||||
- `/hangman` - Play a game of hangman
|
||||
- `/makesweet` - Generate a heart locket image
|
||||
- `/megamind` - Generate a Megamind meme with custom text
|
||||
- `/palabra` - Returns a random Spanish word. That is it.
|
||||
- `/rps` - Play rock paper scissors against someone
|
||||
### Other stuff
|
||||
- Bonzify - Text-to-speech with Bonzi Buddy voice
|
||||
- Cursivify - Italicize message text
|
||||
- Image classification - Classify images using Cloudflare AI
|
||||
- AI chat - Chat with AI on a channel
|
||||
|
||||
this bot has been entirely coded by me, with absolutely no youtube tutorials.
|
||||
the code is here for transparency purposes and it's not made to be hosted by third parties.
|
||||
|
||||
# heres a roadmap (REALLY OUTDATED)
|
||||
|
||||
- ~~form to apply for the minecraft server~~ DONE!
|
||||
- ~~moderation commands~~ DONE!
|
||||
- ~~welcome to users~~ DONE!
|
||||
- modmail
|
||||
- ~~socials notification system~~ DONE!
|
||||
- chatbot using IBM's AI (thanks @gosevil for the idea)
|
||||
- ~~joke command~~
|
||||
|
||||
10 stars! tysm!
|
||||
## Development setup
|
||||
1. Clone the repository
|
||||
2. Run `bun install`
|
||||
3. Install the sern cli: `npm install -g @sern/cli`
|
||||
4. Create a copy of `.env.example` and rename it to `.env`
|
||||
5. Fill in the file
|
||||
6. Run `bunx prisma migrate dev` to set up the database
|
||||
7. Run `bun dev`
|
||||
55
TODO.md
Normal file
55
TODO.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Slash Commands
|
||||
|
||||
## Fun Commands
|
||||
- [ ] /animal - Animal pictures with voting system (cat, dog, capybara, fox, raccoon)
|
||||
- [x] /chiste - Joke command fetching from API
|
||||
- [x] /rps - Rock Paper Scissors game
|
||||
- [x] /8ball - Magic 8-ball responses
|
||||
- [x] /megamind - Megamind meme generator with canvas
|
||||
- [x] /makesweet - Heart locket image generator
|
||||
- [x] /a - Custom command with user autocomplete
|
||||
|
||||
## Miscellaneous Commands
|
||||
- [x] /rolemenu - Role selection menu (owner only)
|
||||
- [ ] /creditos - Bot credits and acknowledgments
|
||||
- [x] ~~/infinitecraft - InfiniteCraft recipe solver~~
|
||||
- [ ] /letra - Song lyrics search via Genius API
|
||||
- [x] /google - Google search results
|
||||
- [x] /sugerencias - Suggestion system with upvote/downvote
|
||||
- [x] /wikipedia - Wikipedia search (Spanish/English)
|
||||
- [ ] /faq - FAQ system with Minecraft questions
|
||||
- [ ] ~~/afk - AFK status management~~
|
||||
- [x] /acortar - URL shortener
|
||||
|
||||
## Minecraft Commands
|
||||
- [x] /ip - Minecraft server IP information
|
||||
- [x] /mcform - Minecraft form submission
|
||||
|
||||
# Button Handlers
|
||||
- [x] suggestions-yes - Upvote button handler
|
||||
- [x] suggestions-no - Downvote button handler
|
||||
- [x] suggestions-yes-who - Show upvoters
|
||||
- [x] suggestions-no-who - Show downvoters
|
||||
|
||||
# Context Menu Commands
|
||||
- [x] bonzify - Text-to-speech with Bonzi Buddy voice
|
||||
- [x] cursivify - Italicize message text
|
||||
- [x] image-classification - Cloudflare AI image classification
|
||||
|
||||
# Message driven functions
|
||||
- [x] AI chat
|
||||
|
||||
# Utility Systems to Rewrite
|
||||
- [x] Resolver - Role/user resolution utility
|
||||
- [x] Wikipedia utility - Wikipedia search helper
|
||||
|
||||
# Background Services
|
||||
- [x] ~YouTube notifications system~ using rss instead
|
||||
- [x] Birthday checker service
|
||||
- [x] Activity status rotation
|
||||
|
||||
# Database
|
||||
- [x] Migration to sqlite
|
||||
|
||||
# Other
|
||||
- [ ] Figure out fonts
|
||||
1
assets/chistes.json
Normal file
1
assets/chistes.json
Normal file
File diff suppressed because one or more lines are too long
584
bun.lock
Normal file
584
bun.lock
Normal file
@@ -0,0 +1,584 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 0,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "ts-example",
|
||||
"dependencies": {
|
||||
"@napi-rs/canvas": "^0.1.72",
|
||||
"@prisma/client": "^6.10.1",
|
||||
"@sern/handler": "^4.2.4",
|
||||
"@sern/publisher": "1.1.2",
|
||||
"discord.js": "^14.21.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"execa": "^9.6.0",
|
||||
"mongodb": "^6.17.0",
|
||||
"node-html-parser": "^7.0.1",
|
||||
"openai": "^5.10.2",
|
||||
"rockpaperscissors-checker": "^1.2.0",
|
||||
"sharp": "^0.34.2",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sern/cli": "^1.4.0",
|
||||
"@types/bun": "^1.2.18",
|
||||
"@types/mongodb": "^4.0.7",
|
||||
"@types/node": "^17.0.25",
|
||||
"prisma": "^6.10.1",
|
||||
"typescript": "^5.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@discordjs/builders": ["@discordjs/builders@1.11.2", "", { "dependencies": { "@discordjs/formatters": "^0.6.1", "@discordjs/util": "^1.1.1", "@sapphire/shapeshift": "^4.0.0", "discord-api-types": "^0.38.1", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" } }, "sha512-F1WTABdd8/R9D1icJzajC4IuLyyS8f3rTOz66JsSI3pKvpCAtsMBweu8cyNYsIyvcrKAVn9EPK+Psoymq+XC0A=="],
|
||||
|
||||
"@discordjs/collection": ["@discordjs/collection@1.5.3", "", {}, "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="],
|
||||
|
||||
"@discordjs/formatters": ["@discordjs/formatters@0.6.1", "", { "dependencies": { "discord-api-types": "^0.38.1" } }, "sha512-5cnX+tASiPCqCWtFcFslxBVUaCetB0thvM/JyavhbXInP1HJIEU+Qv/zMrnuwSsX3yWH2lVXNJZeDK3EiP4HHg=="],
|
||||
|
||||
"@discordjs/rest": ["@discordjs/rest@2.5.1", "", { "dependencies": { "@discordjs/collection": "^2.1.1", "@discordjs/util": "^1.1.1", "@sapphire/async-queue": "^1.5.3", "@sapphire/snowflake": "^3.5.3", "@vladfrangu/async_event_emitter": "^2.4.6", "discord-api-types": "^0.38.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-Tg9840IneBcbrAjcGaQzHUJWFNq1MMWZjTdjJ0WS/89IffaNKc++iOvffucPxQTF/gviO9+9r8kEPea1X5J2Dw=="],
|
||||
|
||||
"@discordjs/util": ["@discordjs/util@1.1.1", "", {}, "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g=="],
|
||||
|
||||
"@discordjs/ws": ["@discordjs/ws@1.2.3", "", { "dependencies": { "@discordjs/collection": "^2.1.0", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.0", "@sapphire/async-queue": "^1.5.2", "@types/ws": "^8.5.10", "@vladfrangu/async_event_emitter": "^2.2.4", "discord-api-types": "^0.38.1", "tslib": "^2.6.2", "ws": "^8.17.0" } }, "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw=="],
|
||||
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||
|
||||
"@esbuild-kit/cjs-loader": ["@esbuild-kit/cjs-loader@2.4.4", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.2.3", "get-tsconfig": "^4.7.0" } }, "sha512-NfsJX4PdzhwSkfJukczyUiZGc7zNNWZcEAyqeISpDnn0PTfzMJR1aR8xAIPskBejIxBJbIgCCMzbaYa9SXepIg=="],
|
||||
|
||||
"@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
|
||||
|
||||
"@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.19.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.19.12", "", { "os": "android", "cpu": "arm" }, "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.19.12", "", { "os": "android", "cpu": "arm64" }, "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.19.12", "", { "os": "android", "cpu": "x64" }, "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.19.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.19.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.19.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.19.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.19.12", "", { "os": "linux", "cpu": "arm" }, "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.19.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.19.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.19.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.19.12", "", { "os": "linux", "cpu": "none" }, "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.19.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.19.12", "", { "os": "linux", "cpu": "x64" }, "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.19.12", "", { "os": "none", "cpu": "x64" }, "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.19.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.19.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.19.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.19.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.19.12", "", { "os": "win32", "cpu": "x64" }, "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA=="],
|
||||
|
||||
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.1.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg=="],
|
||||
|
||||
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.1.0" }, "os": "darwin", "cpu": "x64" }, "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g=="],
|
||||
|
||||
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.1.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA=="],
|
||||
|
||||
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.1.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ=="],
|
||||
|
||||
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.1.0", "", { "os": "linux", "cpu": "arm" }, "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA=="],
|
||||
|
||||
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.1.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew=="],
|
||||
|
||||
"@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.1.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ=="],
|
||||
|
||||
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.1.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA=="],
|
||||
|
||||
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q=="],
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.1.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w=="],
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A=="],
|
||||
|
||||
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.1.0" }, "os": "linux", "cpu": "arm" }, "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ=="],
|
||||
|
||||
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q=="],
|
||||
|
||||
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.1.0" }, "os": "linux", "cpu": "s390x" }, "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw=="],
|
||||
|
||||
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ=="],
|
||||
|
||||
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA=="],
|
||||
|
||||
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA=="],
|
||||
|
||||
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.2", "", { "dependencies": { "@emnapi/runtime": "^1.4.3" }, "cpu": "none" }, "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ=="],
|
||||
|
||||
"@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ=="],
|
||||
|
||||
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw=="],
|
||||
|
||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw=="],
|
||||
|
||||
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
|
||||
|
||||
"@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.3.0", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-zlayKCsIjYb7/IdfqxorK5+xUMyi4vOKcFy10wKJYc63NSdKI8mNME+uJqfatkPmOSMMUiojrL58IePKBm3gvQ=="],
|
||||
|
||||
"@napi-rs/canvas": ["@napi-rs/canvas@0.1.72", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.72", "@napi-rs/canvas-darwin-arm64": "0.1.72", "@napi-rs/canvas-darwin-x64": "0.1.72", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.72", "@napi-rs/canvas-linux-arm64-gnu": "0.1.72", "@napi-rs/canvas-linux-arm64-musl": "0.1.72", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.72", "@napi-rs/canvas-linux-x64-gnu": "0.1.72", "@napi-rs/canvas-linux-x64-musl": "0.1.72", "@napi-rs/canvas-win32-x64-msvc": "0.1.72" } }, "sha512-ypTJ/DXzsJbTU3o7qXFlWmZGgEbh42JWQl7v5/i+DJz/HURELcSnq9ler9e1ukqma70JzmCQcIseiE/Xs6sczw=="],
|
||||
|
||||
"@napi-rs/canvas-android-arm64": ["@napi-rs/canvas-android-arm64@0.1.72", "", { "os": "android", "cpu": "arm64" }, "sha512-OW99TDJEdfOhpJWQ7SXFsQi1BXd6UFuWM8AoQvJ0SQMHWY/iwuopmb1UqGV6Df9aM/SWxvCWBN/onjeCM8KVKQ=="],
|
||||
|
||||
"@napi-rs/canvas-darwin-arm64": ["@napi-rs/canvas-darwin-arm64@0.1.72", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gB8Pn/4GdS+B6P4HYuNqPGx8iQJ16Go1D6e5hIxfUbA/efupVGZ7e3OMGWGCUgF0vgbEPEF31sPzhcad4mdR5g=="],
|
||||
|
||||
"@napi-rs/canvas-darwin-x64": ["@napi-rs/canvas-darwin-x64@0.1.72", "", { "os": "darwin", "cpu": "x64" }, "sha512-x1zKtWVSnf+yLETHdSDAFJ1w6bctS/V2NP0wskTTBKkC+c/AmI2Dl+ZMIW11gF6rilBibrIzBeXJKPzV0GMWGA=="],
|
||||
|
||||
"@napi-rs/canvas-linux-arm-gnueabihf": ["@napi-rs/canvas-linux-arm-gnueabihf@0.1.72", "", { "os": "linux", "cpu": "arm" }, "sha512-Ef6HMF+TBS+lqBNpcUj2D17ODJrbgevXaVPtr2nQFCao5IvoEhVMdmVwWk5YiI+GcgbAkg5AF3LiU47RoSY5yg=="],
|
||||
|
||||
"@napi-rs/canvas-linux-arm64-gnu": ["@napi-rs/canvas-linux-arm64-gnu@0.1.72", "", { "os": "linux", "cpu": "arm64" }, "sha512-i1tWu+Li1Z6G4t+ckT38JwuB/cAAREV6H8VD3dip2yTYU+qnLz6kG4i+whm+SEQb1e4vk3xA1lKnjYx3jlOy8g=="],
|
||||
|
||||
"@napi-rs/canvas-linux-arm64-musl": ["@napi-rs/canvas-linux-arm64-musl@0.1.72", "", { "os": "linux", "cpu": "arm64" }, "sha512-Mu+2hHZAT9SdrjiRtCxMD/Unac8vqVxF/p+Tvjb5sN1NZkLGu+l7WIfrug8aeX150OwrYgAvsR4mhrm0BZvLxg=="],
|
||||
|
||||
"@napi-rs/canvas-linux-riscv64-gnu": ["@napi-rs/canvas-linux-riscv64-gnu@0.1.72", "", { "os": "linux", "cpu": "none" }, "sha512-xBPG/ImL58I4Ep6VM+sCrpwl8rE/8e7Dt9U7zzggNvYHrWD13vIF3q5L2/N9VxdBMh1pee6dBC/VcaXLYccZNQ=="],
|
||||
|
||||
"@napi-rs/canvas-linux-x64-gnu": ["@napi-rs/canvas-linux-x64-gnu@0.1.72", "", { "os": "linux", "cpu": "x64" }, "sha512-jkC8L+QovHpzQrw+Jm1IUqxgLV5QB1hJ1cR8iYzxNRd0TOF7YfxLaIGxvd/ReRi9r48JT6PL7z2IGT7TqK8T4w=="],
|
||||
|
||||
"@napi-rs/canvas-linux-x64-musl": ["@napi-rs/canvas-linux-x64-musl@0.1.72", "", { "os": "linux", "cpu": "x64" }, "sha512-PwPdPmHgJYnTMUr8Gff80eRVdpGjwrxueIqw+7v4aeFxbQjmQ+paa2xaGedFtkvdS2Dn5z8a0mVlrlbSfec+1Q=="],
|
||||
|
||||
"@napi-rs/canvas-win32-x64-msvc": ["@napi-rs/canvas-win32-x64-msvc@0.1.72", "", { "os": "win32", "cpu": "x64" }, "sha512-hZhXJZZ/2ZjkAoOtyGUs3Mx6jA4o9ESbc5bk+NKYO6thZRvRNA7rqvT9WF9pZK0xcRK5EyWRymv8fCzqmSVEzg=="],
|
||||
|
||||
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
||||
|
||||
"@prisma/client": ["@prisma/client@6.10.1", "", { "peerDependencies": { "prisma": "*", "typescript": ">=5.1.0" }, "optionalPeers": ["prisma", "typescript"] }, "sha512-Re4pMlcUsQsUTAYMK7EJ4Bw2kg3WfZAAlr8GjORJaK4VOP6LxRQUQ1TuLnxcF42XqGkWQ36q5CQF1yVadANQ6w=="],
|
||||
|
||||
"@prisma/config": ["@prisma/config@6.10.1", "", { "dependencies": { "jiti": "2.4.2" } }, "sha512-kz4/bnqrOrzWo8KzYguN0cden4CzLJJ+2VSpKtF8utHS3l1JS0Lhv6BLwpOX6X9yNreTbZQZwewb+/BMPDCIYQ=="],
|
||||
|
||||
"@prisma/debug": ["@prisma/debug@6.10.1", "", {}, "sha512-k2YT53cWxv9OLjW4zSYTZ6Z7j0gPfCzcr2Mj99qsuvlxr8WAKSZ2NcSR0zLf/mP4oxnYG842IMj3utTgcd7CaA=="],
|
||||
|
||||
"@prisma/engines": ["@prisma/engines@6.10.1", "", { "dependencies": { "@prisma/debug": "6.10.1", "@prisma/engines-version": "6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c", "@prisma/fetch-engine": "6.10.1", "@prisma/get-platform": "6.10.1" } }, "sha512-Q07P5rS2iPwk2IQr/rUQJ42tHjpPyFcbiH7PXZlV81Ryr9NYIgdxcUrwgVOWVm5T7ap02C0dNd1dpnNcSWig8A=="],
|
||||
|
||||
"@prisma/engines-version": ["@prisma/engines-version@6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c", "", {}, "sha512-ZJFTsEqapiTYVzXya6TUKYDFnSWCNegfUiG5ik9fleQva5Sk3DNyyUi7X1+0ZxWFHwHDr6BZV5Vm+iwP+LlciA=="],
|
||||
|
||||
"@prisma/fetch-engine": ["@prisma/fetch-engine@6.10.1", "", { "dependencies": { "@prisma/debug": "6.10.1", "@prisma/engines-version": "6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c", "@prisma/get-platform": "6.10.1" } }, "sha512-clmbG/Jgmrc/n6Y77QcBmAUlq9LrwI9Dbgy4pq5jeEARBpRCWJDJ7PWW1P8p0LfFU0i5fsyO7FqRzRB8mkdS4g=="],
|
||||
|
||||
"@prisma/get-platform": ["@prisma/get-platform@6.10.1", "", { "dependencies": { "@prisma/debug": "6.10.1" } }, "sha512-4CY5ndKylcsce9Mv+VWp5obbR2/86SHOLVV053pwIkhVtT9C9A83yqiqI/5kJM9T1v1u1qco/bYjDKycmei9HA=="],
|
||||
|
||||
"@sapphire/async-queue": ["@sapphire/async-queue@1.5.5", "", {}, "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="],
|
||||
|
||||
"@sapphire/shapeshift": ["@sapphire/shapeshift@4.0.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" } }, "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg=="],
|
||||
|
||||
"@sapphire/snowflake": ["@sapphire/snowflake@3.5.3", "", {}, "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ=="],
|
||||
|
||||
"@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],
|
||||
|
||||
"@sern/cli": ["@sern/cli@1.4.0", "", { "dependencies": { "@esbuild-kit/cjs-loader": "^2.4.2", "@esbuild-kit/esm-loader": "^2.5.5", "colorette": "2.0.20", "commander": "11.0.0", "dotenv": "^16.3.1", "esbuild": "^0.19.1", "execa": "7.2.0", "find-up": "6.3.0", "glob": "^10.3.3", "ora": "6.3.1", "prompts": "2.4.2", "undici": "5.23.0" }, "bin": { "sern": "dist/index.js" } }, "sha512-IePGYYJvIVwNtnukblYxE2X7hiFivLa/p4UVaMi0XLpZ+Fa3BAdsSiBKRzLtBYWl8J2Se9StLSFwBYQW7ik+/Q=="],
|
||||
|
||||
"@sern/handler": ["@sern/handler@4.2.4", "", { "dependencies": { "@sern/ioc": "^1.1.2", "callsites": "^3.1.0", "cron": "^3.1.7", "deepmerge": "^4.3.1" } }, "sha512-8qnYSwH2x5zhp7YidtDxQZFaQrwYn+YITk4kWrvqOx6b9PVDKtdzkjXd4e7dnI0tdmGuVwJGk6eRl/RnGUVDqw=="],
|
||||
|
||||
"@sern/ioc": ["@sern/ioc@1.1.2", "", {}, "sha512-n84w7n5hB1dl8N6dfSbeYIo0QYORMS1bpG/P7J7GoMNTu8c28EYVZ8uGs3Md9GB09UseOKn3mfv1QBDtRsbb1g=="],
|
||||
|
||||
"@sern/publisher": ["@sern/publisher@1.1.2", "", {}, "sha512-1zh99JZykKUhqHhE75ZXfiLsBtf1WI+NnDCojv8UlpnGBEyzO8xyI1X7PNf6cPKRs4W9XqY3PqTJ+hrqzIsMkg=="],
|
||||
|
||||
"@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="],
|
||||
|
||||
"@types/luxon": ["@types/luxon@3.4.2", "", {}, "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA=="],
|
||||
|
||||
"@types/mongodb": ["@types/mongodb@4.0.7", "", { "dependencies": { "mongodb": "*" } }, "sha512-lPUYPpzA43baXqnd36cZ9xxorprybxXDzteVKCPAdp14ppHtFJHnXYvNpmBvtMUTb5fKXVv6sVbzo1LHkWhJlw=="],
|
||||
|
||||
"@types/node": ["@types/node@17.0.45", "", {}, "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="],
|
||||
|
||||
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
|
||||
|
||||
"@types/webidl-conversions": ["@types/webidl-conversions@7.0.3", "", {}, "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="],
|
||||
|
||||
"@types/whatwg-url": ["@types/whatwg-url@11.0.5", "", { "dependencies": { "@types/webidl-conversions": "*" } }, "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ=="],
|
||||
|
||||
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
|
||||
|
||||
"@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.6", "", {}, "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||
|
||||
"bl": ["bl@5.1.0", "", { "dependencies": { "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ=="],
|
||||
|
||||
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||
|
||||
"bson": ["bson@6.10.4", "", {}, "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng=="],
|
||||
|
||||
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
|
||||
|
||||
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="],
|
||||
|
||||
"busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="],
|
||||
|
||||
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
|
||||
|
||||
"chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
|
||||
|
||||
"cli-cursor": ["cli-cursor@4.0.0", "", { "dependencies": { "restore-cursor": "^4.0.0" } }, "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg=="],
|
||||
|
||||
"cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="],
|
||||
|
||||
"clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="],
|
||||
|
||||
"color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
|
||||
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
|
||||
|
||||
"colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="],
|
||||
|
||||
"commander": ["commander@11.0.0", "", {}, "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ=="],
|
||||
|
||||
"cron": ["cron@3.5.0", "", { "dependencies": { "@types/luxon": "~3.4.0", "luxon": "~3.5.0" } }, "sha512-0eYZqCnapmxYcV06uktql93wNWdlTmmBFP2iYz+JPVcQqlyFYcn1lFuIk4R54pkOmE7mcldTAPZv6X5XA4Q46A=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="],
|
||||
|
||||
"css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="],
|
||||
|
||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||
|
||||
"deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
|
||||
|
||||
"defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="],
|
||||
|
||||
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
||||
|
||||
"discord-api-types": ["discord-api-types@0.38.13", "", {}, "sha512-FELWJRgLVQuR7Az8RhdEZE0k6QNjSW9PCUcU1iyP2Gke8HrJmnMceSS9pD93UM64s3tvZzJPajpPLjWZJylf4g=="],
|
||||
|
||||
"discord.js": ["discord.js@14.21.0", "", { "dependencies": { "@discordjs/builders": "^1.11.2", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.1", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.1", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.1", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-U5w41cEmcnSfwKYlLv5RJjB8Joa+QJyRwIJz5i/eg+v2Qvv6EYpCRhN9I2Rlf0900LuqSDg8edakUATrDZQncQ=="],
|
||||
|
||||
"dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
|
||||
|
||||
"domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
|
||||
|
||||
"domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
|
||||
|
||||
"domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
|
||||
|
||||
"dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
|
||||
|
||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
||||
|
||||
"entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
||||
|
||||
"esbuild": ["esbuild@0.19.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.19.12", "@esbuild/android-arm": "0.19.12", "@esbuild/android-arm64": "0.19.12", "@esbuild/android-x64": "0.19.12", "@esbuild/darwin-arm64": "0.19.12", "@esbuild/darwin-x64": "0.19.12", "@esbuild/freebsd-arm64": "0.19.12", "@esbuild/freebsd-x64": "0.19.12", "@esbuild/linux-arm": "0.19.12", "@esbuild/linux-arm64": "0.19.12", "@esbuild/linux-ia32": "0.19.12", "@esbuild/linux-loong64": "0.19.12", "@esbuild/linux-mips64el": "0.19.12", "@esbuild/linux-ppc64": "0.19.12", "@esbuild/linux-riscv64": "0.19.12", "@esbuild/linux-s390x": "0.19.12", "@esbuild/linux-x64": "0.19.12", "@esbuild/netbsd-x64": "0.19.12", "@esbuild/openbsd-x64": "0.19.12", "@esbuild/sunos-x64": "0.19.12", "@esbuild/win32-arm64": "0.19.12", "@esbuild/win32-ia32": "0.19.12", "@esbuild/win32-x64": "0.19.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="],
|
||||
|
||||
"execa": ["execa@9.6.0", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"figures": ["figures@6.1.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="],
|
||||
|
||||
"find-up": ["find-up@6.3.0", "", { "dependencies": { "locate-path": "^7.1.0", "path-exists": "^5.0.0" } }, "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw=="],
|
||||
|
||||
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
||||
|
||||
"get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
|
||||
|
||||
"get-tsconfig": ["get-tsconfig@4.10.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ=="],
|
||||
|
||||
"glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="],
|
||||
|
||||
"he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="],
|
||||
|
||||
"human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="],
|
||||
|
||||
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
||||
|
||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
||||
|
||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||
|
||||
"is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="],
|
||||
|
||||
"is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
|
||||
|
||||
"is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="],
|
||||
|
||||
"is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
|
||||
|
||||
"jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
|
||||
|
||||
"kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
||||
|
||||
"locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="],
|
||||
|
||||
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||
|
||||
"lodash.snakecase": ["lodash.snakecase@4.1.1", "", {}, "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="],
|
||||
|
||||
"log-symbols": ["log-symbols@5.1.0", "", { "dependencies": { "chalk": "^5.0.0", "is-unicode-supported": "^1.1.0" } }, "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA=="],
|
||||
|
||||
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
|
||||
"luxon": ["luxon@3.5.0", "", {}, "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ=="],
|
||||
|
||||
"magic-bytes.js": ["magic-bytes.js@1.12.1", "", {}, "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA=="],
|
||||
|
||||
"memory-pager": ["memory-pager@1.5.0", "", {}, "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="],
|
||||
|
||||
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
|
||||
|
||||
"mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
|
||||
|
||||
"minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||
|
||||
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||
|
||||
"mongodb": ["mongodb@6.17.0", "", { "dependencies": { "@mongodb-js/saslprep": "^1.1.9", "bson": "^6.10.4", "mongodb-connection-string-url": "^3.0.0" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.188.0", "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", "mongodb-client-encryption": ">=6.0.0 <7", "snappy": "^7.2.2", "socks": "^2.7.1" }, "optionalPeers": ["@aws-sdk/credential-providers", "@mongodb-js/zstd", "gcp-metadata", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-neerUzg/8U26cgruLysKEjJvoNSXhyID3RvzvdcpsIi2COYM3FS3o9nlH7fxFtefTb942dX3W9i37oPfCVj4wA=="],
|
||||
|
||||
"mongodb-connection-string-url": ["mongodb-connection-string-url@3.0.2", "", { "dependencies": { "@types/whatwg-url": "^11.0.2", "whatwg-url": "^14.1.0 || ^13.0.0" } }, "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA=="],
|
||||
|
||||
"node-html-parser": ["node-html-parser@7.0.1", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-KGtmPY2kS0thCWGK0VuPyOS+pBKhhe8gXztzA2ilAOhbUbxa9homF1bOyKvhGzMLXUoRds9IOmr/v5lr/lqNmA=="],
|
||||
|
||||
"npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="],
|
||||
|
||||
"nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
|
||||
|
||||
"onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
|
||||
|
||||
"openai": ["openai@5.10.2", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-n+vi74LzHtvlKcDPn9aApgELGiu5CwhaLG40zxLTlFQdoSJCLACORIPC2uVQ3JEYAbqapM+XyRKFy2Thej7bIw=="],
|
||||
|
||||
"ora": ["ora@6.3.1", "", { "dependencies": { "chalk": "^5.0.0", "cli-cursor": "^4.0.0", "cli-spinners": "^2.6.1", "is-interactive": "^2.0.0", "is-unicode-supported": "^1.1.0", "log-symbols": "^5.1.0", "stdin-discarder": "^0.1.0", "strip-ansi": "^7.0.1", "wcwidth": "^1.0.1" } }, "sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ=="],
|
||||
|
||||
"p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="],
|
||||
|
||||
"p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="],
|
||||
|
||||
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
|
||||
|
||||
"parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="],
|
||||
|
||||
"path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
||||
|
||||
"pretty-ms": ["pretty-ms@9.2.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg=="],
|
||||
|
||||
"prisma": ["prisma@6.10.1", "", { "dependencies": { "@prisma/config": "6.10.1", "@prisma/engines": "6.10.1" }, "peerDependencies": { "typescript": ">=5.1.0" }, "optionalPeers": ["typescript"], "bin": { "prisma": "build/index.js" } }, "sha512-khhlC/G49E4+uyA3T3H5PRBut486HD2bDqE2+rvkU0pwk9IAqGFacLFUyIx9Uw+W2eCtf6XGwsp+/strUwMNPw=="],
|
||||
|
||||
"prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
|
||||
|
||||
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
|
||||
|
||||
"restore-cursor": ["restore-cursor@4.0.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg=="],
|
||||
|
||||
"rockpaperscissors-checker": ["rockpaperscissors-checker@1.2.0", "", {}, "sha512-JfndRzDvMo1st+iK9dKZIEToFDouc+53+whmVFs+zyBOp0zv/sMNY9hUZI5J7ulygmW1fI6QmvRyXmfpN9Sh8Q=="],
|
||||
|
||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||
|
||||
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||
|
||||
"sharp": ["sharp@0.34.2", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", "@img/sharp-libvips-linux-arm64": "1.1.0", "@img/sharp-libvips-linux-ppc64": "1.1.0", "@img/sharp-libvips-linux-s390x": "1.1.0", "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", "@img/sharp-linux-x64": "0.34.2", "@img/sharp-linuxmusl-arm64": "0.34.2", "@img/sharp-linuxmusl-x64": "0.34.2", "@img/sharp-wasm32": "0.34.2", "@img/sharp-win32-arm64": "0.34.2", "@img/sharp-win32-ia32": "0.34.2", "@img/sharp-win32-x64": "0.34.2" } }, "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||
|
||||
"simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
|
||||
|
||||
"sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
|
||||
|
||||
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
|
||||
|
||||
"sparse-bitfield": ["sparse-bitfield@3.0.3", "", { "dependencies": { "memory-pager": "^1.0.2" } }, "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ=="],
|
||||
|
||||
"stdin-discarder": ["stdin-discarder@0.1.0", "", { "dependencies": { "bl": "^5.0.0" } }, "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ=="],
|
||||
|
||||
"streamsearch": ["streamsearch@1.1.0", "", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="],
|
||||
|
||||
"string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
||||
|
||||
"string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
|
||||
|
||||
"strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="],
|
||||
|
||||
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="],
|
||||
|
||||
"tr46": ["tr46@5.1.1", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw=="],
|
||||
|
||||
"ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||
|
||||
"undici": ["undici@5.23.0", "", { "dependencies": { "busboy": "^1.6.0" } }, "sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg=="],
|
||||
|
||||
"unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
|
||||
|
||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||
|
||||
"wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="],
|
||||
|
||||
"webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
|
||||
|
||||
"whatwg-url": ["whatwg-url@14.2.0", "", { "dependencies": { "tr46": "^5.1.0", "webidl-conversions": "^7.0.0" } }, "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
||||
|
||||
"wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||
|
||||
"yocto-queue": ["yocto-queue@1.2.1", "", {}, "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg=="],
|
||||
|
||||
"yoctocolors": ["yoctocolors@2.1.1", "", {}, "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ=="],
|
||||
|
||||
"@discordjs/rest/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
|
||||
|
||||
"@discordjs/rest/undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="],
|
||||
|
||||
"@discordjs/ws/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
|
||||
|
||||
"@sern/cli/execa": ["execa@7.2.0", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^4.3.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" } }, "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA=="],
|
||||
|
||||
"discord.js/undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="],
|
||||
|
||||
"figures/is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
|
||||
|
||||
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
||||
|
||||
"restore-cursor/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||
|
||||
"string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
|
||||
|
||||
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
|
||||
|
||||
"@sern/cli/execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
|
||||
|
||||
"@sern/cli/execa/human-signals": ["human-signals@4.3.1", "", {}, "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ=="],
|
||||
|
||||
"@sern/cli/execa/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="],
|
||||
|
||||
"@sern/cli/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
|
||||
|
||||
"@sern/cli/execa/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
||||
|
||||
"@sern/cli/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
|
||||
|
||||
"restore-cursor/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"@sern/cli/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
||||
}
|
||||
}
|
||||
12
dependencies.d.ts
vendored
12
dependencies.d.ts
vendored
@@ -1,12 +0,0 @@
|
||||
import { SernEmitter, Logging, CoreModuleStore, ModuleManager, ErrorHandling, CoreDependencies, Singleton } from '@sern/handler'
|
||||
import { Client } from 'discord.js'
|
||||
import Spotify from 'spotify-api.js'
|
||||
|
||||
declare global {
|
||||
interface Dependencies extends CoreDependencies {
|
||||
'@sern/client': Singleton<Client>
|
||||
'spotify-api-client': Singleton<Spotify.Client>
|
||||
}
|
||||
}
|
||||
|
||||
export {}
|
||||
116
package.json
116
package.json
@@ -1,76 +1,44 @@
|
||||
{
|
||||
"name": "vinci",
|
||||
"version": "1.1.0",
|
||||
"description": "Vinci Discord Bot for Mara Turing",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"dev": "sern build && node ./dist/index.js --dev",
|
||||
"prod": "tsc-watch -p \"./tsconfig.json\" --onSuccess \"node ./dist/index.js\"",
|
||||
"compile": "tsc --build",
|
||||
"build": "sern build",
|
||||
"web": "node webserver.js",
|
||||
"watch": "tsc --watch",
|
||||
"start": "node dist/index.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/SrIzan10/vinci.git"
|
||||
},
|
||||
"imports": {
|
||||
"#plugins": [
|
||||
"./dist/plugins/index.js"
|
||||
]
|
||||
},
|
||||
"keywords": [
|
||||
"discord-bot"
|
||||
],
|
||||
"type": "module",
|
||||
"author": "Sr Izan",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/SrIzan10/vinci/issues"
|
||||
},
|
||||
"homepage": "https://github.com/SrIzan10/vinci#readme",
|
||||
"dependencies": {
|
||||
"@ai-zen/node-fetch-event-source": "^2.1.4",
|
||||
"@consumet/extensions": "^1.7.0",
|
||||
"@discordjs/opus": "^0.9.0",
|
||||
"@discordjs/voice": "^0.15.0",
|
||||
"@microsoft/fetch-event-source": "^2.0.1",
|
||||
"@napi-rs/canvas": "^0.1.52",
|
||||
"@sern/handler": "^4.0.2",
|
||||
"@sern/publisher": "^1.1.2",
|
||||
"axios": "^1.6.8",
|
||||
"dayjs": "^1.11.6",
|
||||
"discord-tictactoe": "^4.0.0",
|
||||
"discord.js": "^14.16.2",
|
||||
"dotenv": "^16.0.1",
|
||||
"execa": "^6.1.0",
|
||||
"express": "^4.18.1",
|
||||
"extended-eventsource": "^1.4.6",
|
||||
"form-data": "^4.0.0",
|
||||
"genius-lyrics": "^4.4.3",
|
||||
"googlethis": "^1.8.0",
|
||||
"got": "^12.5.3",
|
||||
"libsodium-wrappers": "^0.7.10",
|
||||
"mongoose": "^6.11.3",
|
||||
"node-fetch": "^3.3.1",
|
||||
"pretty-seconds-spanish": "^2.1.1",
|
||||
"rockpaperscissors-checker": "^1.2.0",
|
||||
"set-interval-async": "^3.0.2",
|
||||
"sharp": "^0.33.3",
|
||||
"spotify-api.js": "^9.2.5",
|
||||
"stringify-safe": "^1.0.3",
|
||||
"systeminformation": "^5.21.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sern/cli": "^1.3.3",
|
||||
"@types/express": "^4.17.14",
|
||||
"@types/node": "^20.12.7",
|
||||
"ts-node": "10.9.1",
|
||||
"tsc-watch": "^5.0.3",
|
||||
"typescript": "^5.6.2"
|
||||
},
|
||||
"packageManager": "yarn@4.1.1"
|
||||
"name": "ts-example",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "sern build",
|
||||
"start": "bun run --inspect .",
|
||||
"db:migrate": "prisma migrate deploy",
|
||||
"install": "sern build",
|
||||
"commands:publish": "sern commands publish",
|
||||
"dev": "sern build -w --watch-command \"bun start\"",
|
||||
"db:mongo": "bun run src/utils/db/migrateMongo.ts"
|
||||
},
|
||||
"keywords": [
|
||||
"typescript",
|
||||
"sern",
|
||||
"discord.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"@napi-rs/canvas": "^0.1.72",
|
||||
"@prisma/client": "^6.10.1",
|
||||
"@sern/handler": "^4.2.4",
|
||||
"@sern/publisher": "1.1.2",
|
||||
"discord.js": "^14.21.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"execa": "^9.6.0",
|
||||
"mongodb": "^6.17.0",
|
||||
"node-html-parser": "^7.0.1",
|
||||
"openai": "^5.10.2",
|
||||
"rockpaperscissors-checker": "^1.2.0",
|
||||
"sharp": "^0.34.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sern/cli": "^1.4.0",
|
||||
"@types/bun": "^1.2.18",
|
||||
"@types/mongodb": "^4.0.7",
|
||||
"@types/node": "^17.0.25",
|
||||
"prisma": "^6.10.1",
|
||||
"typescript": "^5.0"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "ai_chats" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"messageid" TEXT NOT NULL,
|
||||
"threadid" TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "AIMessage" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"role" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"aiChatId" INTEGER NOT NULL,
|
||||
CONSTRAINT "AIMessage_aiChatId_fkey" FOREIGN KEY ("aiChatId") REFERENCES "ai_chats" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
19
prisma/migrations/20250628135845_fix_caps/migration.sql
Normal file
19
prisma/migrations/20250628135845_fix_caps/migration.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `AIMessage` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- DropTable
|
||||
PRAGMA foreign_keys=off;
|
||||
DROP TABLE "AIMessage";
|
||||
PRAGMA foreign_keys=on;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "AiMessage" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"role" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"aiChatId" INTEGER NOT NULL,
|
||||
CONSTRAINT "AiMessage_aiChatId_fkey" FOREIGN KEY ("aiChatId") REFERENCES "ai_chats" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `ai_chats` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- DropTable
|
||||
PRAGMA foreign_keys=off;
|
||||
DROP TABLE "ai_chats";
|
||||
PRAGMA foreign_keys=on;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "AiChat" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"messageid" TEXT NOT NULL,
|
||||
"threadid" TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_AiMessage" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"role" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"aiChatId" INTEGER NOT NULL,
|
||||
CONSTRAINT "AiMessage_aiChatId_fkey" FOREIGN KEY ("aiChatId") REFERENCES "AiChat" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_AiMessage" ("aiChatId", "content", "id", "role") SELECT "aiChatId", "content", "id", "role" FROM "AiMessage";
|
||||
DROP TABLE "AiMessage";
|
||||
ALTER TABLE "new_AiMessage" RENAME TO "AiMessage";
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
10
prisma/migrations/20250628140420_afk/migration.sql
Normal file
10
prisma/migrations/20250628140420_afk/migration.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Afk" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"userId" TEXT NOT NULL,
|
||||
"reason" TEXT NOT NULL,
|
||||
"expiresAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Afk_userId_key" ON "Afk"("userId");
|
||||
12
prisma/migrations/20250628140820_unique_chat/migration.sql
Normal file
12
prisma/migrations/20250628140820_unique_chat/migration.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[messageid]` on the table `AiChat` will be added. If there are existing duplicate values, this will fail.
|
||||
- A unique constraint covering the columns `[threadid]` on the table `AiChat` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "AiChat_messageid_key" ON "AiChat"("messageid");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "AiChat_threadid_key" ON "AiChat"("threadid");
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `expiresAt` on the `Afk` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Afk" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"userId" TEXT NOT NULL,
|
||||
"reason" TEXT NOT NULL
|
||||
);
|
||||
INSERT INTO "new_Afk" ("id", "reason", "userId") SELECT "id", "reason", "userId" FROM "Afk";
|
||||
DROP TABLE "Afk";
|
||||
ALTER TABLE "new_Afk" RENAME TO "Afk";
|
||||
CREATE UNIQUE INDEX "Afk_userId_key" ON "Afk"("userId");
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
10
prisma/migrations/20250628153216_birthday/migration.sql
Normal file
10
prisma/migrations/20250628153216_birthday/migration.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Birthday" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"userId" TEXT NOT NULL,
|
||||
"date" TEXT NOT NULL,
|
||||
"sent" BOOLEAN NOT NULL DEFAULT false
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Birthday_userId_key" ON "Birthday"("userId");
|
||||
12
prisma/migrations/20250628162223_suggestions/migration.sql
Normal file
12
prisma/migrations/20250628162223_suggestions/migration.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Suggestion" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"userId" TEXT NOT NULL,
|
||||
"msgId" TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Suggestion_userId_key" ON "Suggestion"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Suggestion_msgId_key" ON "Suggestion"("msgId");
|
||||
22
prisma/migrations/20250628162355_up_or_down/migration.sql
Normal file
22
prisma/migrations/20250628162355_up_or_down/migration.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `upDown` to the `Suggestion` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Suggestion" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"userId" TEXT NOT NULL,
|
||||
"msgId" TEXT NOT NULL,
|
||||
"upDown" INTEGER NOT NULL
|
||||
);
|
||||
INSERT INTO "new_Suggestion" ("id", "msgId", "userId") SELECT "id", "msgId", "userId" FROM "Suggestion";
|
||||
DROP TABLE "Suggestion";
|
||||
ALTER TABLE "new_Suggestion" RENAME TO "Suggestion";
|
||||
CREATE UNIQUE INDEX "Suggestion_userId_key" ON "Suggestion"("userId");
|
||||
CREATE UNIQUE INDEX "Suggestion_msgId_key" ON "Suggestion"("msgId");
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- DropIndex
|
||||
DROP INDEX "Suggestion_userId_key";
|
||||
2
prisma/migrations/20250628163113_aaaa/migration.sql
Normal file
2
prisma/migrations/20250628163113_aaaa/migration.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- DropIndex
|
||||
DROP INDEX "Suggestion_msgId_key";
|
||||
3
prisma/migrations/migration_lock.toml
Normal file
3
prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "sqlite"
|
||||
52
prisma/schema.prisma
Normal file
52
prisma/schema.prisma
Normal file
@@ -0,0 +1,52 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "debian-openssl-3.0.x"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = "file:./vinci.db"
|
||||
}
|
||||
|
||||
model AiChat {
|
||||
id Int @id @default(autoincrement())
|
||||
messageid String @unique
|
||||
threadid String @unique
|
||||
messages AiMessage[]
|
||||
}
|
||||
|
||||
model AiMessage {
|
||||
id Int @id @default(autoincrement())
|
||||
role String
|
||||
content String
|
||||
|
||||
aiChatId Int
|
||||
aiChat AiChat @relation(fields: [aiChatId], references: [id])
|
||||
}
|
||||
|
||||
model Afk {
|
||||
id Int @id @default(autoincrement())
|
||||
userId String @unique
|
||||
reason String
|
||||
}
|
||||
|
||||
model Birthday {
|
||||
id Int @id @default(autoincrement())
|
||||
userId String @unique
|
||||
date String
|
||||
sent Boolean @default(false)
|
||||
}
|
||||
|
||||
model Suggestion {
|
||||
id Int @id @default(autoincrement())
|
||||
userId String
|
||||
msgId String
|
||||
upDown Int
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { Resolver } from '../../utils/resolver.js';
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import { PublishConfig } from '@sern/publisher';
|
||||
import { ActionRowBuilder, ApplicationCommandOptionType, ChannelType, Collection, EmbedBuilder, PermissionFlagsBits, Role, StringSelectMenuBuilder, TextChannel } from "discord.js";
|
||||
|
||||
import { ownerOnly } from "#plugins";
|
||||
import { ActionRowBuilder, ApplicationCommandOptionType, ChannelType, ChatInputCommandInteraction, Collection, EmbedBuilder, Role, StringSelectMenuBuilder, TextChannel } from "discord.js";
|
||||
import { Resolver } from "../../util/resolver.js";
|
||||
export const config: PublishConfig = {
|
||||
defaultMemberPermissions: PermissionFlagsBits.Administrator,
|
||||
}
|
||||
|
||||
export default commandModule({
|
||||
name: 'rolemenu',
|
||||
type: CommandType.Slash,
|
||||
plugins: [ownerOnly()],
|
||||
plugins: [],
|
||||
description: 'ADMIN: Spawnea un menú de roles',
|
||||
//alias : [],
|
||||
options: [
|
||||
@@ -34,7 +37,6 @@ export default commandModule({
|
||||
execute: async (ctx) => {
|
||||
const channel = ctx.options.getChannel("channel", true) as unknown as TextChannel;
|
||||
if (!channel.isSendable()) return ctx.reply("Channel is not sendable");
|
||||
// @ts-ignore it should still be a correct interaction
|
||||
const role = new Resolver(ctx.options.getString("role", true), ctx.interaction)
|
||||
.roles;
|
||||
const message = ctx.options.getString("message", true);
|
||||
@@ -85,4 +87,4 @@ function createMenu(channel: TextChannel, role: Collection<string, Role>) {
|
||||
);
|
||||
const row = new ActionRowBuilder<StringSelectMenuBuilder>().setComponents(menu);
|
||||
return row;
|
||||
};
|
||||
};
|
||||
61
src/commands/contextMenu/bonzify.ts
Normal file
61
src/commands/contextMenu/bonzify.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { AttachmentBuilder } from 'discord.js';
|
||||
import { Readable } from 'node:stream';
|
||||
import fs from 'fs';
|
||||
import { execa } from 'execa';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.CtxMsg,
|
||||
plugins: [],
|
||||
execute: async (ctx) => {
|
||||
await ctx.deferReply({ withResponse: true });
|
||||
|
||||
const text = ctx.targetMessage.content;
|
||||
const encodedText = encodeURIComponent(text);
|
||||
const url = `https://www.tetyys.com/SAPI4/SAPI4?text=${encodedText}&voice=Adult%20Male%20%232%2C%20American%20English%20(TruVoice)&pitch=140&speed=157`;
|
||||
|
||||
const request = await fetch(url).then((res) => res.arrayBuffer());
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
|
||||
const randomnumber = randomString(5);
|
||||
const randomnumber_wav = `bonzi-wav-${randomnumber}.wav`;
|
||||
const randomnumber_mp3 = `bonzi-mp3-${randomnumber}.mp3`;
|
||||
fs.writeFileSync(`./src/utils/bonzi_temp/${randomnumber_wav}`, new Uint8Array(request));
|
||||
const command = execa(
|
||||
'ffmpeg',
|
||||
[
|
||||
'-i',
|
||||
`./src/utils/bonzi_temp/${randomnumber_wav}`,
|
||||
'-vn',
|
||||
`./src/utils/bonzi_temp/${randomnumber_mp3}`,
|
||||
],
|
||||
{ shell: true }
|
||||
);
|
||||
await new Promise((resolve) => {
|
||||
command.on('close', resolve);
|
||||
});
|
||||
|
||||
const stream = new Readable();
|
||||
stream._read = () => {};
|
||||
stream.push(
|
||||
Buffer.from(new Uint8Array(fs.readFileSync(`./src/utils/bonzi_temp/${randomnumber_mp3}`)))
|
||||
);
|
||||
stream.push(null);
|
||||
|
||||
const attachment = new AttachmentBuilder(stream, { name: 'bonzied.mp3' });
|
||||
fs.unlinkSync(`./src/utils/bonzi_temp/${randomnumber_mp3}`);
|
||||
fs.unlinkSync(`./src/utils/bonzi_temp/${randomnumber_wav}`);
|
||||
|
||||
await ctx.editReply({ files: [attachment] });
|
||||
},
|
||||
});
|
||||
|
||||
function randomString(length: number): string {
|
||||
let result = '';
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
60
src/commands/contextMenu/image-classification.ts
Normal file
60
src/commands/contextMenu/image-classification.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { AttachmentBuilder, codeBlock } from 'discord.js';
|
||||
import { createCanvas, loadImage } from '@napi-rs/canvas';
|
||||
import sharp from 'sharp';
|
||||
|
||||
export default commandModule({
|
||||
name: 'Clasifica una imagen',
|
||||
type: CommandType.CtxMsg,
|
||||
plugins: [],
|
||||
execute: async (ctx) => {
|
||||
await ctx.deferReply();
|
||||
|
||||
if (ctx.targetMessage.attachments.size === 0)
|
||||
return ctx.editReply('No hay ninguna imagen para clasificar!');
|
||||
const image = ctx.targetMessage.attachments.first()!;
|
||||
if (!image.contentType!.startsWith('image/') && image.contentType !== 'image/gif')
|
||||
return ctx.editReply('El archivo no es una imagen!');
|
||||
|
||||
const imageBuffer = await fetch(image.url).then(async (res) => await res.arrayBuffer());
|
||||
const compressed = sharp(imageBuffer)
|
||||
.webp({ quality: 70 });
|
||||
const imageUint8Array = new Uint8Array(await compressed.toBuffer());
|
||||
|
||||
const request = await fetch(
|
||||
`https://api.cloudflare.com/client/v4/accounts/${process.env.CF_AI_ACC}/ai/run/@cf/facebook/detr-resnet-50`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.CF_AI_TOKEN}`,
|
||||
'Content-Type': 'application/octet-stream',
|
||||
},
|
||||
body: imageUint8Array,
|
||||
}
|
||||
).then(async (res) => await res.json());
|
||||
if (request.errors.length > 0) {
|
||||
return ctx.editReply(`Hubo un error! ${codeBlock(JSON.stringify(request.errors))}`);
|
||||
}
|
||||
|
||||
// all canvas stuff, this was fun to make
|
||||
const imgMetadata = await compressed.metadata();
|
||||
const canvas = createCanvas(imgMetadata.width!, imgMetadata.height!);
|
||||
const ctxCanvas = canvas.getContext('2d');
|
||||
const img = await loadImage(image.url);
|
||||
ctxCanvas.drawImage(img, 0, 0, imgMetadata.width!, imgMetadata.height!);
|
||||
ctxCanvas.font = '30px sans-serif';
|
||||
ctxCanvas.fillStyle = 'red';
|
||||
ctxCanvas.strokeStyle = 'red';
|
||||
ctxCanvas.lineWidth = 3;
|
||||
for (const result of request.result) {
|
||||
if (result.score < 0.5) continue;
|
||||
const box = result.box;
|
||||
ctxCanvas.strokeRect(box.xmin, box.ymin, box.xmax - box.xmin, box.ymax - box.ymin);
|
||||
ctxCanvas.fillText(result.label, box.xmin, box.ymin - 5);
|
||||
}
|
||||
const canvasBuffer = canvas.toBuffer('image/png');
|
||||
const attachment = new AttachmentBuilder(canvasBuffer, { name: 'generatedImage.png' });
|
||||
|
||||
await ctx.editReply({ files: [attachment] });
|
||||
},
|
||||
});
|
||||
@@ -1,30 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import { ApplicationCommandOptionType } from "discord.js";
|
||||
|
||||
export default commandModule({
|
||||
name: '8ball',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Preguntale a la 8-ball cosas.',
|
||||
//alias : [],
|
||||
options: [{
|
||||
name: "pregunta",
|
||||
description: "Escribe lo que le quieres preguntar.",
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true
|
||||
}],
|
||||
execute: async (ctx) => {
|
||||
// yes, the question argument is never used. There is no reason to use it.
|
||||
var eightballwords = [
|
||||
'Probablemente',
|
||||
'Sí',
|
||||
'No',
|
||||
'Dudable',
|
||||
'Como lo veo, todo indica a que sí',
|
||||
'A lo mejor',
|
||||
'No cuentes con ello',
|
||||
'Buena suerte'
|
||||
]
|
||||
await ctx.reply({content: `La bola tiene respuesta: ${eightballwords[Math.floor(Math.random() * eightballwords.length)]}.`, ephemeral: true})
|
||||
},
|
||||
});
|
||||
@@ -1,93 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import {
|
||||
ApplicationCommandOptionType,
|
||||
AttachmentBuilder,
|
||||
EmbedBuilder,
|
||||
} from 'discord.js';
|
||||
const choices = [
|
||||
'XaviXE',
|
||||
'Paula',
|
||||
'William',
|
||||
'Espejito2500',
|
||||
'Wheelook',
|
||||
'MarioCabrera',
|
||||
'Paticama',
|
||||
'Vinci',
|
||||
'SrIzan',
|
||||
'ItsAdrian',
|
||||
'ByHGT',
|
||||
'Irene',
|
||||
'Boniato64',
|
||||
'Tormentarosa',
|
||||
'H',
|
||||
'SpRaY',
|
||||
];
|
||||
|
||||
export default commandModule({
|
||||
name: 'a',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'A',
|
||||
options: [
|
||||
{
|
||||
name: 'usuario',
|
||||
description: 'Usuario que debería aparecer',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
autocomplete: true,
|
||||
command: {
|
||||
onEvent: [],
|
||||
async execute(ctx) {
|
||||
const focusedValue = ctx.options.getFocused();
|
||||
const filtered = choices.filter((choice) =>
|
||||
choice.startsWith(focusedValue)
|
||||
);
|
||||
await ctx.respond(
|
||||
filtered.map((choice) => ({ name: choice, value: choice }))
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
const option = ctx.interaction.options.getString('usuario');
|
||||
if (!option) {
|
||||
const imagesArray = [
|
||||
'./images/a/XaviXE.png',
|
||||
'./images/a/Paula.png',
|
||||
'./images/a/William.png',
|
||||
'./images/a/Espejito2500.png',
|
||||
'./images/a/Wheelook.png',
|
||||
'./images/a/MarioCabrera.png',
|
||||
'./images/a/Paticama.png',
|
||||
'./images/a/Vinci.png',
|
||||
'./images/a/SrIzan.png',
|
||||
'./images/a/ItsAdrian.png',
|
||||
'./images/a/ByHGT.png',
|
||||
'./images/a/Irene.png',
|
||||
'./images/a/Boniato64.png',
|
||||
'./images/a/Tormentarosa.png',
|
||||
'./images/a/H.png',
|
||||
'./images/a/SpRaY.png',
|
||||
];
|
||||
const images =
|
||||
imagesArray[Math.floor(Math.random() * imagesArray.length)];
|
||||
|
||||
await ctx.reply({ content: 'A', files: [images] });
|
||||
} else {
|
||||
if (choices.indexOf(option) > -1) {
|
||||
const attachmentbuilder = new AttachmentBuilder(
|
||||
`./images/a/${option}.png`
|
||||
);
|
||||
await ctx.reply({ content: 'A', files: [attachmentbuilder] });
|
||||
} else {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle('A no encontrado!')
|
||||
.setDescription(
|
||||
`Qué raro, no se ha encontrado ese /a...\nPorqué no pruebas a poner uno del autocompletado?`
|
||||
)
|
||||
.setColor('Red');
|
||||
await ctx.reply({ embeds: [embed], ephemeral: true });
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,183 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import axios from "axios";
|
||||
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonStyle, ComponentType, EmbedBuilder } from "discord.js";
|
||||
|
||||
export default commandModule({
|
||||
name: 'animal',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Enseña un animal',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'gato',
|
||||
description: 'Enseña un gato',
|
||||
type: ApplicationCommandOptionType.Subcommand
|
||||
},
|
||||
{
|
||||
name: 'capybara',
|
||||
description: 'Enseña un capybara',
|
||||
type: ApplicationCommandOptionType.Subcommand
|
||||
},
|
||||
{
|
||||
name: 'zorro',
|
||||
description: 'Enseña un zorro',
|
||||
type: ApplicationCommandOptionType.Subcommand
|
||||
},
|
||||
{
|
||||
name: 'perro',
|
||||
description: 'what the dog doin',
|
||||
type: ApplicationCommandOptionType.Subcommand
|
||||
},
|
||||
{
|
||||
name: 'mapache',
|
||||
description: 'Enseña un mapache',
|
||||
type: ApplicationCommandOptionType.Subcommand
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
switch (ctx.options.getSubcommand()) {
|
||||
case 'gato': {
|
||||
const request = await axios.get(`https://api.thecatapi.com/v1/images/search?api_key=${process.env.CATAPI}`).then(res => res.data)
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setColor("Random")
|
||||
.setImage(request[0].url)
|
||||
.setFooter({text: `ID: ${request[0].id}`})
|
||||
.setTitle('Gato')
|
||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId("cat-upvote")
|
||||
.setEmoji("⬆️")
|
||||
.setStyle(ButtonStyle.Success),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("cat-downvote")
|
||||
.setEmoji("⬇️")
|
||||
.setStyle(ButtonStyle.Danger),
|
||||
)
|
||||
const rowdisabled = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId("cat-upvote")
|
||||
.setEmoji("⬆️")
|
||||
.setStyle(ButtonStyle.Success)
|
||||
.setDisabled(true),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("cat-downvote")
|
||||
.setEmoji("⬇️")
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
.setDisabled(true),
|
||||
)
|
||||
const message = await ctx.reply({embeds: [embed], components: [row]})
|
||||
const collector = message.createMessageComponentCollector({time: 30000, componentType: ComponentType.Button})
|
||||
collector.on('collect', async (i) => {
|
||||
await i.deferReply({ephemeral: true})
|
||||
if (i.customId === "cat-upvote") {
|
||||
await axios.post(`https://api.thecatapi.com/v1/votes?api_key=${process.env.CATAPI}`, {
|
||||
"image_id": request[0].id,
|
||||
"sub_id": i.user.id,
|
||||
"value": 1
|
||||
})
|
||||
i.editReply({content: "Has votado positivamente al gato con ID " + "`" + request[0].id + "`"})
|
||||
}
|
||||
if (i.customId === "cat-downvote") {
|
||||
await axios.post(`https://api.thecatapi.com/v1/votes?api_key=${process.env.CATAPI}`, {
|
||||
"image_id": request[0].id,
|
||||
"sub_id": i.user.id,
|
||||
"value": -1
|
||||
})
|
||||
i.editReply({content: `Has votado negativamente al gato con ID \`${request[0].id}\``})
|
||||
}
|
||||
})
|
||||
collector.on('end', async (i) => {
|
||||
await message.edit({components: [rowdisabled]})
|
||||
})
|
||||
}
|
||||
case 'capybara': {
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setTitle('Capybara')
|
||||
.setColor('Random')
|
||||
.setImage('https://api.capy.lol/v1/capybara');
|
||||
await ctx.interaction.reply({embeds: [embed]})
|
||||
}
|
||||
case 'zorro': {
|
||||
const request = await axios('https://randomfox.ca/floof/').then(res => res.data)
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setTitle('Zorro')
|
||||
.setColor('Random')
|
||||
.setImage(request.image)
|
||||
await ctx.interaction.reply({embeds: [embed]})
|
||||
}
|
||||
case 'perro': {
|
||||
const request = await axios.get(`https://api.thedogapi.com/v1/images/search?api_key=${process.env.DOGAPI}`).then(res => res.data)
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setColor("Random")
|
||||
.setImage(request[0].url)
|
||||
.setFooter({text: `ID: ${request[0].id}`})
|
||||
.setTitle('Perro')
|
||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId("dog-upvote")
|
||||
.setEmoji("⬆️")
|
||||
.setStyle(ButtonStyle.Success),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("dog-downvote")
|
||||
.setEmoji("⬇️")
|
||||
.setStyle(ButtonStyle.Danger),
|
||||
)
|
||||
const rowdisabled = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId("dog-upvote")
|
||||
.setEmoji("⬆️")
|
||||
.setStyle(ButtonStyle.Success)
|
||||
.setDisabled(true),
|
||||
new ButtonBuilder()
|
||||
.setCustomId("dog-downvote")
|
||||
.setEmoji("⬇️")
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
.setDisabled(true),
|
||||
)
|
||||
const message = await ctx.reply({embeds: [embed], components: [row]})
|
||||
const collector = message.createMessageComponentCollector({time: 30000, componentType: ComponentType.Button})
|
||||
collector.on('collect', async (i) => {
|
||||
await i.deferReply({ephemeral: true})
|
||||
if (i.customId === "dog-upvote") {
|
||||
await axios.post(`https://api.thedogapi.com/v1/votes?api_key=${process.env.DOGAPI}`, {
|
||||
"image_id": request[0].id,
|
||||
"sub_id": i.user.id,
|
||||
"value": 1
|
||||
})
|
||||
i.editReply({content: "Has votado positivamente al gato con ID " + "`" + request[0].id + "`"})
|
||||
}
|
||||
if (i.customId === "dog-downvote") {
|
||||
await axios.post(`https://api.thedogapi.com/v1/votes?api_key=${process.env.DOGAPI}`, {
|
||||
"image_id": request[0].id,
|
||||
"sub_id": i.user.id,
|
||||
"value": -1
|
||||
})
|
||||
i.editReply({content: "Has votado negativamente al gato con ID " + "`" + request[0].id + "`"})
|
||||
}
|
||||
})
|
||||
collector.on('end', async () => {
|
||||
await message.edit({components: [rowdisabled]})
|
||||
})
|
||||
}
|
||||
case 'mapache': {
|
||||
const request = await axios('https://some-random-api.com/animal/raccoon').then(res => res.data)
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setTitle('Mapache')
|
||||
.setDescription(`Fun fact: ${request.fact}`)
|
||||
.setColor('Random')
|
||||
.setImage(request.image)
|
||||
await ctx.interaction.reply({embeds: [embed]})
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,168 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { publish } from '#plugins';
|
||||
import { ANIME } from '@consumet/extensions';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ApplicationCommandOptionType,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
ComponentType,
|
||||
EmbedBuilder,
|
||||
} from 'discord.js';
|
||||
/*
|
||||
|
||||
import { ownerOnly } from "#plugins"
|
||||
*/
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'busca cosas en gogoanime',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'buscar',
|
||||
description: 'Busca un anime',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: [
|
||||
{
|
||||
name: 'palabra-clave',
|
||||
description: 'La palabra clave',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'capitulo',
|
||||
description: 'Mira los links de directo de cualquier capítulo (con su ID)',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: [
|
||||
{
|
||||
name: 'id-serie',
|
||||
description: 'El ID de la serie (búscalo primero)',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'id-capitulo',
|
||||
description: 'El ID del capítulo (usa el autocompletado)',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
command: {
|
||||
onEvent: [],
|
||||
execute: async (autocomplete) => {
|
||||
try {
|
||||
const focusedOption = autocomplete.options.getFocused();
|
||||
const gogoanime = new ANIME.Gogoanime();
|
||||
const serieOption = autocomplete.options.getString('id-serie', true)
|
||||
const fetch = await gogoanime.fetchAnimeInfo(serieOption)
|
||||
let choices = fetch.episodes!.filter((choice) => choice.number.toString().startsWith(focusedOption))
|
||||
choices = choices.slice(0, 25)
|
||||
await autocomplete.respond(
|
||||
choices.map((choice) => ({
|
||||
name: choice.number.toString(),
|
||||
value: choice.id.toString(),
|
||||
}))
|
||||
)
|
||||
} catch {
|
||||
await autocomplete.respond([{name: 'Algo malo ha ocurrido! Asegúrate que hayas puesto el ID correctamente', value: 'error'}])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'info',
|
||||
description: 'INGLÉS: Consigue información sobre alguna serie con su ID.',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: [
|
||||
{
|
||||
name: 'id',
|
||||
description: 'El nombre de la serie',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
execute: async (ctx, options) => {
|
||||
const gogoanime = new ANIME.Gogoanime();
|
||||
const doubleslashregex = new RegExp('(?<!:)\/\/+')
|
||||
switch (ctx.options.getSubcommand()) {
|
||||
case 'buscar': {
|
||||
await ctx.interaction.deferReply()
|
||||
const option = ctx.options.getString('palabra-clave', true);
|
||||
const search = await gogoanime.search(option);
|
||||
const editedarray = await Promise.all(
|
||||
search.results
|
||||
.map((results) => {
|
||||
return `[${results.title}](<${results.url!.replace(doubleslashregex, '/')}>)`;
|
||||
})
|
||||
.slice(0, 5)
|
||||
);
|
||||
const editedarrayids = await Promise.all(
|
||||
search.results
|
||||
.map((results) => {
|
||||
return `[${results.id}](<${results.url!.replace(doubleslashregex, '/')}>)`;
|
||||
})
|
||||
.slice(0, 5)
|
||||
);
|
||||
const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('gogoanime-search-toid')
|
||||
.setLabel('Cambiar a ID')
|
||||
.setStyle(ButtonStyle.Secondary)
|
||||
);
|
||||
if (editedarray.length === 0) return await ctx.interaction.editReply({content: 'No se ha encontrado nada con ese resultado de búsqueda, prueba a ser más general o concreto idk'})
|
||||
const message = await ctx.interaction.editReply({
|
||||
content: `Resultados de la búsqueda \`${option}\`:\n${editedarray.join('\n')}`,
|
||||
components: [button],
|
||||
});
|
||||
const collector = message.createMessageComponentCollector({max: 1, componentType: ComponentType.Button, time: 30000})
|
||||
collector.on('collect', async (i) => {
|
||||
if (i.customId !== 'gogoanime-search-toid') return;
|
||||
await ctx.interaction.editReply({
|
||||
content: `Resultados de la búsqueda \`${option}\` (modo ID):\n${editedarrayids.join('\n')}`,
|
||||
components: []
|
||||
})
|
||||
await i.deferUpdate()
|
||||
})
|
||||
} break;
|
||||
case 'capitulo': {
|
||||
const selepisode = ctx.options.getString('id-capitulo', true)
|
||||
try {
|
||||
const search = await gogoanime.fetchEpisodeServers(selepisode)
|
||||
const arrayed = await Promise.all(search.map((server) => `[${server.name}](<${server.url!.replace(doubleslashregex, '/')}>)`))
|
||||
await ctx.reply({content: `Todos los servidores de \`${selepisode}\` (Vinci no se hace cargo de los enlaces):\n${arrayed.join('\n')}`})
|
||||
} catch {
|
||||
await ctx.reply({content: 'Ha ocurrido un error! Asegúrate que hayas seleccionado bien un capítulo.'})
|
||||
}
|
||||
} break;
|
||||
case 'info': {
|
||||
try {
|
||||
const option = ctx.options.getString('id', true)
|
||||
const info = await gogoanime.fetchAnimeInfo(option)
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor('Random')
|
||||
.setTitle(`${info.title}`)
|
||||
.setURL(info.url!.replace(doubleslashregex, '/'))
|
||||
.setThumbnail(info.image!)
|
||||
.setFields(
|
||||
{name: 'Géneros', value: `${info.genres!.join(', ')}`},
|
||||
{name: 'Fecha de salida', value: `${info.releaseDate!}`, inline: true},
|
||||
{name: 'Capítulos totales', value: `${info.totalEpisodes!}`, inline: true},
|
||||
{name: '\u200B', value: '\u200B', inline: true},
|
||||
{name: 'Tipo', value: `${info.type!}`, inline: true},
|
||||
)
|
||||
|
||||
await ctx.reply({embeds: [embed]})
|
||||
} catch {
|
||||
await ctx.reply({content: 'Algo malo ha ocurrido, asegúrate que hayas escrito el ID correctamente\nTip: Usa el comando de buscar y conviértelos a ID.'})
|
||||
}
|
||||
} break;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import axios from "axios";
|
||||
|
||||
|
||||
export default commandModule({
|
||||
name: 'chiste',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Enseña un chiste en inglés.',
|
||||
execute: async (ctx) => {
|
||||
const jokeJSON = await axios(
|
||||
'https://v2.jokeapi.dev/joke/Programming,Miscellaneous,Spooky,Christmas?blacklistFlags=nsfw,religious,racist,sexist,explicit'
|
||||
).then((res) => res.data);
|
||||
ctx.reply({content: `${jokeJSON.joke || jokeJSON.setup}\n${jokeJSON.delivery || ""}`})
|
||||
}})
|
||||
@@ -1,164 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { publish } from '#plugins';
|
||||
import FormData from 'form-data';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ApplicationCommandOptionType,
|
||||
AttachmentBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
} from 'discord.js';
|
||||
import axios from 'axios';
|
||||
import https from 'node:https'
|
||||
/*
|
||||
|
||||
import { ownerOnly } from "#plugins"
|
||||
*/
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
//alias : [],
|
||||
description: 'no one will read this (i hope)',
|
||||
options: [
|
||||
{
|
||||
name: 'heartlocket',
|
||||
description: 'El corazón con una imagen que todos conocemos',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: [
|
||||
{
|
||||
name: 'imagen',
|
||||
description: 'Imagen (jpg o png)',
|
||||
type: ApplicationCommandOptionType.Attachment,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'texto',
|
||||
description: 'El texto que poner',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
await ctx.interaction.deferReply();
|
||||
switch (ctx.options.getSubcommand()) {
|
||||
case 'heartlocket':
|
||||
{
|
||||
try {
|
||||
// get all options
|
||||
const text = ctx.options.getString('texto', true);
|
||||
const image = ctx.options.getAttachment('imagen', true);
|
||||
|
||||
// check file extension of attachment
|
||||
if (
|
||||
!image.contentType!.includes('image/png') &&
|
||||
!image.contentType!.includes('image/jpeg')
|
||||
)
|
||||
return await ctx.interaction.editReply({
|
||||
content:
|
||||
'Tienes que usar una imagen con extensión `.png` o `.jpg`!',
|
||||
});
|
||||
|
||||
// save in a const the content type
|
||||
let fileExtension: string;
|
||||
if (image.contentType!.includes('image/png')) {
|
||||
fileExtension = 'png';
|
||||
} else if (image.contentType!.includes('image/jpeg')) {
|
||||
fileExtension = 'jpg';
|
||||
} else {
|
||||
fileExtension =
|
||||
'this shouldnt be seen, but typescript is sometimes an idiot and it needs an else so it doesnt cry';
|
||||
}
|
||||
|
||||
// upload to tmpfiles so it can be then uploaded to
|
||||
const formDataTemp = new FormData();
|
||||
const imageBinaryTemp = await axios
|
||||
.get(image.url, { responseType: 'arraybuffer' })
|
||||
.then((res) => res.data);
|
||||
const bufferTemp = Buffer.from(imageBinaryTemp, 'binary');
|
||||
formDataTemp.append('file', bufferTemp, `image.${fileExtension}`);
|
||||
const tempupload = await axios
|
||||
.post(
|
||||
`https://tmpfiles.org/api/v1/upload`,
|
||||
formDataTemp,
|
||||
)
|
||||
.then((res) => res.data);
|
||||
|
||||
// compress the image
|
||||
const compress = await axios.get(`https://api.resmush.it/ws.php?img=${(tempupload.data.url as string).replace('https://tmpfiles.org/', 'https://tmpfiles.org/dl/')}&qlty=80`, {
|
||||
httpsAgent: new https.Agent({ rejectUnauthorized: false })
|
||||
}).then(res => res.data)
|
||||
|
||||
// convert image to a binary so it can be sent to the MakeSweet API.
|
||||
const formData = new FormData();
|
||||
const imageBinary = await axios
|
||||
.get((compress.dest as string).replace(/\\\//g, '/'), { responseType: 'arraybuffer' })
|
||||
.then((res) => res.data);
|
||||
const buffer = Buffer.from(imageBinary, 'binary');
|
||||
formData.append('images[]', buffer, `image.${fileExtension}`);
|
||||
|
||||
// make the request to the actual API, but first check if there's text.
|
||||
let request: any;
|
||||
if (text) {
|
||||
request = await axios
|
||||
.post(
|
||||
`https://api.makesweet.com/make/heart-locket?text=${text}`,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
Authorization: process.env.MAKESWEET!,
|
||||
},
|
||||
responseType: 'arraybuffer',
|
||||
httpsAgent: new https.Agent({ rejectUnauthorized: false })
|
||||
}
|
||||
)
|
||||
.then((res) => res.data);
|
||||
} else {
|
||||
request = await axios
|
||||
.post(`https://api.makesweet.com/make/heart-locket`, formData, {
|
||||
headers: {
|
||||
Authorization: process.env.MAKESWEET!,
|
||||
},
|
||||
responseType: 'arraybuffer',
|
||||
httpsAgent: new https.Agent({ rejectUnauthorized: false })
|
||||
})
|
||||
.then((res) => res.data);
|
||||
}
|
||||
|
||||
// make an attachment with the data that the MakeSweet API returned
|
||||
const attachment = new AttachmentBuilder(request, {
|
||||
name: 'makesweet.gif',
|
||||
});
|
||||
|
||||
// finally, send the message
|
||||
const message = await ctx.interaction.editReply({
|
||||
content: 'Tu GIF está listo! 🎉',
|
||||
files: [attachment],
|
||||
});
|
||||
|
||||
// make an image link button
|
||||
const button = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel('Enlace al GIF')
|
||||
.setEmoji('📲')
|
||||
.setURL(`https://api.srizan.dev/misc/download?url=${message.attachments.first()!.url}&type=gif`)
|
||||
.setStyle(ButtonStyle.Link)
|
||||
);
|
||||
await ctx.interaction.editReply({
|
||||
content: 'Tu GIF está listo! 🎉',
|
||||
files: [attachment],
|
||||
components: [button]
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
await ctx.interaction.editReply({
|
||||
content: `ERROR: He intentado comprimir la imagen, pero no ha sido suficiente. Intenta usar una imagen menos pesada (1mb o menos)\nSi no es eso, probablemente ha ocurrido un error del que no tengo conocimiento.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,59 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
|
||||
import { ownerOnly } from "#plugins";
|
||||
import Canvas from '@napi-rs/canvas';
|
||||
import { ApplicationCommandOptionType, AttachmentBuilder } from 'discord.js';
|
||||
/*
|
||||
|
||||
import { ownerOnly } from "#plugins"
|
||||
*/
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
// , '928018226330337280'
|
||||
description: 'Añade a una imagen de megamind "No ...?"',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'texto',
|
||||
description: 'El texto SIN "No" ni "?".',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
const option = ctx.options.getString('texto', true)
|
||||
|
||||
await ctx.reply({content: 'Cargando...'})
|
||||
|
||||
const before = performance.now()
|
||||
|
||||
const canvas = Canvas.createCanvas(535, 540)
|
||||
const context = canvas.getContext('2d')
|
||||
|
||||
const background = await Canvas.loadImage('./images/megamind/megamind.png')
|
||||
context.drawImage(background, 0, 0, canvas.width, canvas.height)
|
||||
|
||||
const text = `No ${option}?`
|
||||
let fontsize = 60
|
||||
do {
|
||||
fontsize--;
|
||||
context.font = fontsize + "px Impact";
|
||||
} while (context.measureText(text).width > canvas.width)
|
||||
context.fillStyle = 'white'
|
||||
context.textAlign = 'center'
|
||||
context.textBaseline = 'middle'
|
||||
context.fillText(text, canvas.width / 2, canvas.height - 510)
|
||||
|
||||
const encode = await canvas.encode('png')
|
||||
|
||||
const after = performance.now()
|
||||
|
||||
const attachment = new AttachmentBuilder(encode, { name: 'megamind.png' });
|
||||
await ctx.interaction.editReply({
|
||||
content: `Aquí está tu megamind:\nLa generación de imagen ha tardado \`${(after - before).toFixed(2)}ms\`.`,
|
||||
files: [attachment]
|
||||
})
|
||||
},
|
||||
});
|
||||
@@ -1,113 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonStyle, ComponentType, EmbedBuilder, GuildMember } from "discord.js";
|
||||
|
||||
import rockpaperscissors from "rockpaperscissors-checker";
|
||||
|
||||
export default commandModule({
|
||||
name: 'rps',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Juega piedra papel tijeras con los panas',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'usuario',
|
||||
description: 'El usuario con el que enfrentarse',
|
||||
type: ApplicationCommandOptionType.User,
|
||||
required: true
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
// also the code is mine, I didn't steal from anyone
|
||||
let player1: number, player2: number, winner, bothResponded: boolean
|
||||
const option = ctx.options.getMember('usuario') as unknown as GuildMember
|
||||
if (ctx.user.id === option.id) {
|
||||
return await ctx.reply({content: `no puedes jugar contigo mismo 💀`, ephemeral: true})
|
||||
} else if (option.user.bot) {
|
||||
return await ctx.reply({content: `no puedes seleccionar a un bot.`, ephemeral: true})
|
||||
}
|
||||
const waitingEmbed = new EmbedBuilder()
|
||||
.setColor('Red')
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setTitle(`Piedra, papel o tijera? <:PauseChamp:1030169623070519388>`)
|
||||
.setDescription(`Esperando a que ambos jugadores eligan...\nJugador 1: ${ctx.user}\nJugador 2: ${option}`)
|
||||
.setFooter({text: `Hay un máximo de 30 segundos para elegir.`})
|
||||
const winEmbed = new EmbedBuilder()
|
||||
.setColor('Green')
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setFooter({text: `Gracias por jugar!`})
|
||||
const tieEmbed = new EmbedBuilder()
|
||||
.setColor('Yellow')
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setTitle(`Ha habido un empate <:Sadge:1015764348385382451>`)
|
||||
.setDescription(`Qué sadge, ha habido un empate...`)
|
||||
.setFooter({text: `Volvemos a intentarlo?`})
|
||||
const timeUpEmbed = new EmbedBuilder()
|
||||
.setColor('Red')
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setTitle(`Se acabó!`)
|
||||
.setDescription(`Uno de los dos jugadores no han respondido en los 30 segundos, así que se acabó la partida!`)
|
||||
.setFooter({text: `Volvemos a intentarlo?`})
|
||||
const buttons = ["Piedra", "Papel", "Tijera"].map(choice => {
|
||||
return new ButtonBuilder()
|
||||
.setLabel(choice)
|
||||
.setCustomId(`rps-${choice.toLowerCase()}`)
|
||||
.setStyle(ButtonStyle.Secondary)
|
||||
})
|
||||
const row = new ActionRowBuilder<ButtonBuilder>();
|
||||
const message = await ctx.interaction.reply({content: `${option}, te han retado a Piedra Papel o Tijera!`, embeds: [waitingEmbed], fetchReply: true, components: [row.setComponents(buttons)]})
|
||||
const collector = message.createMessageComponentCollector({time: 30_000, componentType: ComponentType.Button, filter: (i) => [ctx.user.id, option.id].includes(i.user.id),})
|
||||
collector.on('collect', async (i) => {
|
||||
await i.deferReply({ephemeral: true})
|
||||
if (i.customId === "rps-piedra") {
|
||||
if (i.user.id === ctx.user.id) {
|
||||
player1 = 1
|
||||
await i.editReply({content: `Se ha respondido **piedra** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
|
||||
} else if (i.user.id === option.id) {
|
||||
player2 = 1
|
||||
await i.editReply({content: `Se ha respondido **piedra** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
|
||||
}
|
||||
} else if (i.customId === "rps-papel") {
|
||||
if (i.user.id === ctx.user.id) {
|
||||
player1 = 2
|
||||
await i.editReply({content: `Se ha respondido **papel** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
|
||||
} else if (i.user.id === option.id) {
|
||||
player2 = 2
|
||||
await i.editReply({content: `Se ha respondido **papel** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
|
||||
}
|
||||
} else if (i.customId === "rps-tijera") {
|
||||
if (i.user.id === ctx.user.id) {
|
||||
player1 = 3
|
||||
await i.editReply({content: `Se ha respondido **tijera** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
|
||||
} else if (i.user.id === option.id) {
|
||||
player2 = 3
|
||||
await i.editReply({content: `Se ha respondido **tijera** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`})
|
||||
}
|
||||
}
|
||||
if (player1 && player2) {
|
||||
const checker = rockpaperscissors(player1, player2)
|
||||
bothResponded = true
|
||||
if (checker === "player1") {
|
||||
winner = ctx.user.username
|
||||
const setDescription = winEmbed.setDescription(`Tenemos resultados!\n**${winner}** ha ganado.`).setTitle(`Ha ganado ${winner}! <:Pog:1030169609178976346>`)
|
||||
await message.edit({embeds: [setDescription], components: [], content: ``})
|
||||
message.react('<:Pog:1030169609178976346>')
|
||||
} else if (checker === "player2") {
|
||||
winner = option.user.username
|
||||
const setDescription = winEmbed.setDescription(`Tenemos resultados!\n**${winner}** ha ganado.`).setTitle(`Ha ganado ${winner}! <:Pog:1030169609178976346>`)
|
||||
await message.edit({embeds: [setDescription], components: [], content: ``})
|
||||
message.react('<:Pog:1030169609178976346>')
|
||||
} else if (checker === "tie") {
|
||||
await message.edit({embeds: [tieEmbed], components: [], content: ``})
|
||||
}
|
||||
}
|
||||
})
|
||||
collector.on('ignore', async (i) => {
|
||||
await i.reply({content: 'No estás jugando!', ephemeral: true})
|
||||
})
|
||||
collector.on('end', async () => {
|
||||
if (bothResponded) return;
|
||||
await message.edit({embeds: [timeUpEmbed], components: [], content: ``})
|
||||
})
|
||||
},
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
import TicTacToe from 'discord-tictactoe';
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
|
||||
import { ApplicationCommandOptionType } from "discord.js";
|
||||
const game = new TicTacToe({language: 'en'})
|
||||
|
||||
export default commandModule({
|
||||
name: 'tictactoe',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'tres en raya',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: "opponent",
|
||||
description: "opponent",
|
||||
type: ApplicationCommandOptionType.User
|
||||
}
|
||||
],
|
||||
execute: async (ctx, options) => {
|
||||
ctx.reply({ content: 'comando desactivado temporalmente :(', ephemeral: true })
|
||||
// game.handleInteraction(ctx.interaction as ChatInputCommandInteraction)
|
||||
},
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { AttachmentBuilder } from 'discord.js';
|
||||
import { publish } from '#plugins';
|
||||
import { Readable } from 'node:stream'
|
||||
import { random } from '../../util/randomstring.js';
|
||||
import fs from 'fs';
|
||||
import { execa } from 'execa';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.CtxMsg,
|
||||
plugins: [],
|
||||
execute: async (ctx) => {
|
||||
await ctx.deferReply({ fetchReply: true })
|
||||
|
||||
const text = ctx.targetMessage.content;
|
||||
const encodedText = encodeURIComponent(text);
|
||||
const url = `https://www.tetyys.com/SAPI4/SAPI4?text=${encodedText}&voice=Adult%20Male%20%232%2C%20American%20English%20(TruVoice)&pitch=140&speed=157`;
|
||||
|
||||
const request = await fetch(url).then(res => res.arrayBuffer())
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
|
||||
const randomnumber = random(5)
|
||||
const randomnumber_wav = `bonzi-wav-${randomnumber}.wav`
|
||||
const randomnumber_mp3 = `bonzi-mp3-${randomnumber}.mp3`
|
||||
fs.writeFileSync(`./src/util/bonzi_temp/${randomnumber_wav}`, new Uint8Array(request))
|
||||
const command = execa('ffmpeg', [
|
||||
'-i', `./src/util/bonzi_temp/${randomnumber_wav}`,
|
||||
'-vn',
|
||||
`./src/util/bonzi_temp/${randomnumber_mp3}`
|
||||
], { shell: true })
|
||||
await new Promise((resolve) => {
|
||||
command.on('close', resolve)
|
||||
})
|
||||
|
||||
const stream = new Readable();
|
||||
stream._read = () => {};
|
||||
stream.push(Buffer.from(new Uint8Array(fs.readFileSync(`./src/util/bonzi_temp/${randomnumber_mp3}`))));
|
||||
stream.push(null)
|
||||
|
||||
const attachment = new AttachmentBuilder(stream, { name: 'bonzied.mp3' })
|
||||
fs.unlinkSync(`./src/util/bonzi_temp/${randomnumber_mp3}`)
|
||||
fs.unlinkSync(`./src/util/bonzi_temp/${randomnumber_wav}`)
|
||||
|
||||
await ctx.editReply({ files: [attachment] })
|
||||
},
|
||||
});
|
||||
@@ -1,21 +1,26 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Button,
|
||||
execute: async (ctx) => {
|
||||
await ctx.deferReply({ ephemeral: true })
|
||||
const getUserID = await ctx.client.users.fetch((ctx.message.embeds[0].footer!.text).replace('Discord ID: ', ''))
|
||||
|
||||
await getUserID.send({
|
||||
content: `Tu solicitud de entrada al servidor ha sido aceptada correctamente!\nYa puedes entrar al servidor con la IP \`minecraft.maraturing.com\``
|
||||
}).catch(async () => {
|
||||
await ctx.editReply({
|
||||
content: `No se ha podido enviar un DM a ${getUserID} <:Sadge:1015764348385382451>`,
|
||||
})
|
||||
}).then(async () => {
|
||||
await ctx.editReply({
|
||||
content: `Se ha podido enviar un DM a ${getUserID} correctamente! <:Pog:1030169609178976346>`
|
||||
})
|
||||
})
|
||||
},
|
||||
});
|
||||
type: CommandType.Button,
|
||||
execute: async (ctx) => {
|
||||
await ctx.deferReply({ ephemeral: true });
|
||||
const getUserID = await ctx.client.users.fetch(
|
||||
ctx.message.embeds[0].footer!.text.replace('Discord ID: ', '')
|
||||
);
|
||||
|
||||
await getUserID
|
||||
.send({
|
||||
content: `Tu solicitud de entrada al servidor ha sido aceptada correctamente!\nYa puedes entrar al servidor con la IP \`minecraft.maraturing.com\``,
|
||||
})
|
||||
.catch(async () => {
|
||||
await ctx.editReply({
|
||||
content: `No se ha podido enviar un DM a ${getUserID} <:Sadge:1015764348385382451>`,
|
||||
});
|
||||
})
|
||||
.then(async () => {
|
||||
await ctx.editReply({
|
||||
content: `Se ha podido enviar un DM a ${getUserID} correctamente! <:Pog:1030169609178976346>`,
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import axios from 'axios';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
@@ -8,7 +7,6 @@ import {
|
||||
} from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
name: 'mcform-main',
|
||||
type: CommandType.Modal,
|
||||
plugins: [],
|
||||
description: 'Envia el formulario para entrar al servidor.',
|
||||
@@ -23,13 +21,12 @@ export default commandModule({
|
||||
});
|
||||
} else {
|
||||
try {
|
||||
const request = await axios
|
||||
.get(`https://api.mojang.com/users/profiles/minecraft/${value}`, {
|
||||
validateStatus: function (status) {
|
||||
return status === 200 || status === 400;
|
||||
},
|
||||
})
|
||||
.then((res) => res.data);
|
||||
const request = await fetch(`https://mcprofile.io/api/v1/java/username/${value}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}).then((res) => res.json());
|
||||
await modal.reply({
|
||||
content:
|
||||
'Enviado!\nSé paciente ya que el bot no es automático.',
|
||||
@@ -43,7 +40,7 @@ export default commandModule({
|
||||
.setColor('Green')
|
||||
.setTitle('Nueva solicitud de entrada al servidor!')
|
||||
.setDescription(
|
||||
`Su nombre de usuario en Minecraft es: \`${value}\`\nSu UUID: \`${request.id}\``
|
||||
`Su nombre de usuario en Minecraft es: \`${value}\`\nSu UUID: \`${request.uuid}\``
|
||||
)
|
||||
.setFooter({ text: `Discord ID: ${modal.user.id}` });
|
||||
const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
@@ -1,35 +0,0 @@
|
||||
import { commandModule, CommandType } from "@sern/handler";
|
||||
import type { APISelectMenuComponent, GuildMember } from "discord.js";
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.StringSelect,
|
||||
name: 'role-menu',
|
||||
async execute(interaction) {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
|
||||
const roles = interaction.values;
|
||||
|
||||
const menuRoles: string[] = (
|
||||
interaction.message.components[0].components[0]
|
||||
.data as Readonly<APISelectMenuComponent>
|
||||
// @ts-ignore
|
||||
).options.map((o: { label: string; value: string }) => o.value);
|
||||
|
||||
const member = interaction.member! as unknown as GuildMember;
|
||||
if (!member) return;
|
||||
|
||||
let content = `Los roles han sido actualizados. Te he dado estos:\n${roles
|
||||
.map((r) => `<@&${r}>`)
|
||||
.join("\n")}`;
|
||||
if (roles.length === 0) content = "Se han actualizado los roles a ninguno o no se han seleccionado roles...";
|
||||
|
||||
const existing = member.roles.cache
|
||||
.filter((r) => r.id !== interaction.guildId)
|
||||
.map((r) => r.id)
|
||||
.filter((r) => !menuRoles.includes(r));
|
||||
|
||||
await member.roles.set(roles.concat(existing)).catch(() => null);
|
||||
|
||||
await interaction.editReply(content);
|
||||
},
|
||||
});
|
||||
@@ -1,75 +1,85 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from 'discord.js';
|
||||
import {
|
||||
ThreadAutoArchiveDuration,
|
||||
} from 'discord.js';
|
||||
import { ThreadAutoArchiveDuration } from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Modal,
|
||||
async execute(modal) {
|
||||
const value = modal.fields.getTextInputValue('sugerenciasInput');
|
||||
function onlySpaces(str: string) {
|
||||
return str.trim().length === 0;
|
||||
}
|
||||
if (onlySpaces(value) === true)
|
||||
return await modal.reply({
|
||||
content: 'Buen intento enviando un mensaje vacío >:D',
|
||||
ephemeral: true,
|
||||
});
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor('Random')
|
||||
.setTitle('Sugerencia')
|
||||
.setAuthor({
|
||||
name: `${modal.user.username}`,
|
||||
iconURL: `${modal.user.displayAvatarURL()}`,
|
||||
})
|
||||
.setDescription(value);
|
||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-yes')
|
||||
.setEmoji('✅')
|
||||
.setLabel('0')
|
||||
.setStyle(ButtonStyle.Success),
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-no')
|
||||
.setEmoji('❎')
|
||||
.setLabel('0')
|
||||
.setStyle(ButtonStyle.Danger),
|
||||
)
|
||||
const row2 = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-yes-who')
|
||||
.setEmoji('✅')
|
||||
.setLabel('Quién')
|
||||
.setStyle(ButtonStyle.Secondary),
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-no-who')
|
||||
.setEmoji('❎')
|
||||
.setLabel('Quién')
|
||||
.setStyle(ButtonStyle.Secondary),
|
||||
)
|
||||
|
||||
const guild = await modal.client.guilds.fetch(process.env.GUILDID!);
|
||||
const channel = await guild.channels.fetch(process.env.SUGGESTIONS_CHANNEL!);
|
||||
if (!channel || !channel.isTextBased()) {
|
||||
return await modal.reply({
|
||||
content: 'ERROR: Canal de sugerencias no encontrado.',
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
type: CommandType.Modal,
|
||||
async execute(modal) {
|
||||
const value = modal.fields.getTextInputValue('sugerenciasInput');
|
||||
|
||||
const msg = await channel.send({ embeds: [embed], components: [row, row2] });
|
||||
msg.startThread({
|
||||
name: `Sugerencia de ${modal.user.username}`,
|
||||
autoArchiveDuration: ThreadAutoArchiveDuration.ThreeDays,
|
||||
reason: 'AUTOMATIZADO: Hilo para discutir sobre la sugerencia.',
|
||||
});
|
||||
modal.reply({
|
||||
content:
|
||||
'¡Enviado!\nRECUERDA QUE NO ESTÁ PERMITIDO ENVIAR MENSAJES VACÍOS.',
|
||||
ephemeral: true,
|
||||
});
|
||||
},
|
||||
if (onlySpaces(value) === true) {
|
||||
return await modal.reply({
|
||||
content: 'Buen intento enviando un mensaje vacío >:D',
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor('Random')
|
||||
.setTitle('Sugerencia')
|
||||
.setAuthor({
|
||||
name: `${modal.user.username}`,
|
||||
iconURL: `${modal.user.displayAvatarURL()}`,
|
||||
})
|
||||
.setDescription(value);
|
||||
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-yes')
|
||||
.setEmoji('✅')
|
||||
.setLabel('0')
|
||||
.setStyle(ButtonStyle.Success),
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-no')
|
||||
.setEmoji('❎')
|
||||
.setLabel('0')
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
);
|
||||
const row2 = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-yes-who')
|
||||
.setEmoji('✅')
|
||||
.setLabel('Quién')
|
||||
.setStyle(ButtonStyle.Secondary),
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-no-who')
|
||||
.setEmoji('❎')
|
||||
.setLabel('Quién')
|
||||
.setStyle(ButtonStyle.Secondary)
|
||||
);
|
||||
|
||||
const guild = await modal.client.guilds.fetch(process.env.GUILDID!);
|
||||
const channel = await guild.channels.fetch(process.env.SUGGESTIONS_CHANNEL!);
|
||||
if (!channel || !channel.isTextBased()) {
|
||||
return await modal.reply({
|
||||
content: 'ERROR: Canal de sugerencias no encontrado.',
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
const msg = await channel.send({ embeds: [embed], components: [row, row2] });
|
||||
msg.startThread({
|
||||
name: `Sugerencia de ${modal.user.username}`,
|
||||
autoArchiveDuration: ThreadAutoArchiveDuration.ThreeDays,
|
||||
reason: 'AUTOMATIZADO: Hilo para discutir sobre la sugerencia.',
|
||||
});
|
||||
|
||||
const rowSuccess = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setURL(msg.url)
|
||||
.setLabel('Ver sugerencia')
|
||||
.setStyle(ButtonStyle.Link)
|
||||
);
|
||||
const modalReply = await modal.reply({
|
||||
content: '¡Enviado!',
|
||||
ephemeral: true,
|
||||
components: [rowSuccess],
|
||||
});
|
||||
setTimeout(() => {
|
||||
modalReply.delete().catch(() => {});
|
||||
}, 3000);
|
||||
},
|
||||
});
|
||||
|
||||
function onlySpaces(str: string) {
|
||||
return str.trim().length === 0;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
import { commandModule, CommandType } from "@sern/handler";
|
||||
import db from "../../schemas/suggestions.js";
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import db from '../../utils/db';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
let finalarray
|
||||
await interaction.deferReply({ephemeral: true})
|
||||
const findeverything = await db.find({msgid: interaction.message.id, upordown: -1})
|
||||
const array = findeverything.filter(message => message.msgid)
|
||||
const fetchedids = await Promise.all(array.map(async (user) => {
|
||||
return interaction.client.users.fetch(user.userid)
|
||||
}))
|
||||
if (fetchedids.length === 0) {
|
||||
finalarray = 'Nadie, de momento'
|
||||
} else {
|
||||
finalarray = fetchedids.join(', ')
|
||||
}
|
||||
await interaction.editReply({
|
||||
content: `Gente que ha hecho downvote:\n${finalarray}`,
|
||||
allowedMentions: {repliedUser: false}
|
||||
})
|
||||
}
|
||||
})
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
const votes = await db.suggestion.findMany({
|
||||
where: { msgId: interaction.message.id, upDown: -1 },
|
||||
});
|
||||
const fetchedIds = await Promise.all(
|
||||
votes.map(async (v) => {
|
||||
return interaction.client.users.fetch(v.userId);
|
||||
})
|
||||
);
|
||||
await interaction.editReply({
|
||||
content: `Gente que ha hecho downvote:\n${
|
||||
fetchedIds.length > 0 ? fetchedIds.join(', ') : 'Nadie, de momento'
|
||||
}`,
|
||||
allowedMentions: { repliedUser: false },
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,50 +1,73 @@
|
||||
import { commandModule, CommandType } from "@sern/handler";
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonComponent, ButtonComponentData, ButtonStyle } from "discord.js";
|
||||
import db from "../../schemas/suggestions.js";
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import {
|
||||
ActionRow,
|
||||
ActionRowBuilder,
|
||||
APIButtonComponentWithCustomId,
|
||||
ButtonBuilder,
|
||||
ButtonComponent,
|
||||
ButtonComponentData,
|
||||
ButtonStyle,
|
||||
MessageActionRowComponent,
|
||||
} from 'discord.js';
|
||||
import db from '../../utils/db';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
const convertToNumber = Number((interaction.component as ButtonComponent).label!)
|
||||
const row2 = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(interaction.message!.components[1].components[0].data as ButtonComponentData),
|
||||
new ButtonBuilder(interaction.message!.components[1].components[1].data as ButtonComponentData)
|
||||
)
|
||||
if (await db.exists({msgid: interaction.message.id, userid: interaction.user.id, upordown: 1})) {
|
||||
await db.findOneAndUpdate({msgid: interaction.message.id, userid: interaction.user.id, upordown: 1}, {upordown: -1}, {returnOriginal: false})
|
||||
// god forbid I use any! I'm literally done with trying to solve this dude
|
||||
const upvoteLabel = JSON.stringify(interaction.message!.components[0].components[0].data) as string
|
||||
const downvotebuttons = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(interaction.message!.components[0].components[0].data as ButtonComponentData)
|
||||
.setLabel((Number(JSON.parse(upvoteLabel).label) - 1).toString()),
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-no')
|
||||
.setEmoji('❎')
|
||||
.setLabel((convertToNumber + 1).toString())
|
||||
.setStyle(ButtonStyle.Danger),
|
||||
)
|
||||
await interaction.message.edit({components: [downvotebuttons, row2]})
|
||||
await interaction.deferUpdate()
|
||||
} else if (await db.exists({msgid: interaction.message.id, userid: interaction.user.id, upordown: -1})) {
|
||||
return await interaction.reply({content: 'Ya has hecho downvote.', ephemeral: true})
|
||||
} else {
|
||||
const downvotebuttons = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(interaction.message!.components[0].components[0].data as ButtonComponentData),
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-no')
|
||||
.setEmoji('❎')
|
||||
.setLabel((convertToNumber + 1).toString())
|
||||
.setStyle(ButtonStyle.Danger),
|
||||
)
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
const row1 = interaction.message!.components[0] as ActionRow<MessageActionRowComponent>;
|
||||
const row2 = interaction.message!.components[1] as ActionRow<MessageActionRowComponent>;
|
||||
const rows = {
|
||||
yes: row1.components[0],
|
||||
no: row1.components[1],
|
||||
yesWho: row2.components[0],
|
||||
noWho: row2.components[1],
|
||||
} as {
|
||||
yes: ButtonComponent;
|
||||
no: ButtonComponent;
|
||||
yesWho: ButtonComponent;
|
||||
noWho: ButtonComponent;
|
||||
};
|
||||
const upvoteData = rows.yes.data as APIButtonComponentWithCustomId;
|
||||
const downvoteData = rows.no.data as APIButtonComponentWithCustomId;
|
||||
const userSuggestion = await db.suggestion.findFirst({
|
||||
where: { msgId: interaction.message.id, userId: interaction.user.id },
|
||||
});
|
||||
|
||||
const addToDB = new db({
|
||||
msgid: interaction.message.id,
|
||||
userid: interaction.user.id,
|
||||
upordown: -1
|
||||
})
|
||||
await addToDB.save()
|
||||
await interaction.message.edit({components: [downvotebuttons, row2]})
|
||||
await interaction.deferUpdate()
|
||||
}
|
||||
if (!userSuggestion) {
|
||||
const row1 = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(rows.yes.data),
|
||||
new ButtonBuilder(rows.no.data).setLabel((parseInt(downvoteData.label!) + 1).toString())
|
||||
);
|
||||
|
||||
await db.suggestion.create({
|
||||
data: {
|
||||
msgId: interaction.message.id,
|
||||
userId: interaction.user.id,
|
||||
upDown: -1,
|
||||
},
|
||||
});
|
||||
await interaction.message.edit({ components: [row1, row2] });
|
||||
await interaction.deferUpdate();
|
||||
return;
|
||||
}
|
||||
})
|
||||
|
||||
const userSuggestionUpDown = userSuggestion.upDown === 1;
|
||||
if (userSuggestionUpDown) {
|
||||
await db.suggestion.updateMany({
|
||||
where: { msgId: interaction.message.id, userId: interaction.user.id, upDown: 1 },
|
||||
data: { upDown: -1 },
|
||||
});
|
||||
|
||||
const row1 = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(rows.yes.data).setLabel((parseInt(upvoteData.label!) - 1).toString()),
|
||||
new ButtonBuilder(rows.no.data).setLabel((parseInt(downvoteData.label!) + 1).toString())
|
||||
);
|
||||
await interaction.message.edit({ components: [row1, row2] });
|
||||
await interaction.deferUpdate();
|
||||
return;
|
||||
} else {
|
||||
await interaction.deferUpdate()
|
||||
return;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
import { commandModule, CommandType } from "@sern/handler";
|
||||
import db from "../../schemas/suggestions.js";
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import db from '../../utils/db';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
let finalarray
|
||||
await interaction.deferReply({ephemeral: true})
|
||||
const findeverything = await db.find({msgid: interaction.message.id, upordown: 1})
|
||||
const array = findeverything.filter(message => message.msgid)
|
||||
const fetchedids = await Promise.all(array.map(async (user) => {
|
||||
return interaction.client.users.fetch(user.userid)
|
||||
}))
|
||||
if (fetchedids.length === 0) {
|
||||
finalarray = 'Nadie, de momento'
|
||||
} else {
|
||||
finalarray = fetchedids.join(', ')
|
||||
}
|
||||
await interaction.editReply({
|
||||
content: `Gente que ha hecho upvote:\n${finalarray}`,
|
||||
allowedMentions: {repliedUser: false}
|
||||
})
|
||||
}
|
||||
})
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
await interaction.deferReply({ ephemeral: true });
|
||||
const votes = await db.suggestion.findMany({
|
||||
where: { msgId: interaction.message.id, upDown: 1 },
|
||||
});
|
||||
const fetchedIds = await Promise.all(
|
||||
votes.map(async (v) => {
|
||||
return interaction.client.users.fetch(v.userId);
|
||||
})
|
||||
);
|
||||
await interaction.editReply({
|
||||
content: `Gente que ha hecho upvote:\n${
|
||||
fetchedIds.length > 0 ? fetchedIds.join(', ') : 'Nadie, de momento'
|
||||
}`,
|
||||
allowedMentions: { repliedUser: false },
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,50 +1,73 @@
|
||||
import { commandModule, CommandType } from "@sern/handler";
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonComponent, ButtonComponentData, ButtonStyle } from "discord.js";
|
||||
import db from "../../schemas/suggestions.js";
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import {
|
||||
ActionRow,
|
||||
ActionRowBuilder,
|
||||
APIButtonComponentWithCustomId,
|
||||
ButtonBuilder,
|
||||
ButtonComponent,
|
||||
ButtonComponentData,
|
||||
ButtonStyle,
|
||||
MessageActionRowComponent,
|
||||
} from 'discord.js';
|
||||
import db from '../../utils/db';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
const convertToNumber = Number((interaction.component as ButtonComponent).label!)
|
||||
const row2 = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(interaction.message!.components[1].components[0].data as ButtonComponentData),
|
||||
new ButtonBuilder(interaction.message!.components[1].components[1].data as ButtonComponentData)
|
||||
)
|
||||
if (await db.exists({msgid: interaction.message.id, userid: interaction.user.id, upordown: -1})) {
|
||||
await db.findOneAndUpdate({msgid: interaction.message.id, userid: interaction.user.id, upordown: -1}, {upordown: 1}, {returnOriginal: false})
|
||||
// god forbid I use any! I'm literally done with trying to solve this dude
|
||||
const upvoteLabel = JSON.stringify(interaction.message!.components[0].components[1].data) as string
|
||||
const downvotebuttons = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-yes')
|
||||
.setEmoji('✅')
|
||||
.setLabel((convertToNumber + 1).toString())
|
||||
.setStyle(ButtonStyle.Success),
|
||||
new ButtonBuilder(interaction.message!.components[0].components[1].data as ButtonComponentData)
|
||||
.setLabel((Number(JSON.parse(upvoteLabel).label) - 1).toString()),
|
||||
)
|
||||
await interaction.message.edit({components: [downvotebuttons, row2]})
|
||||
await interaction.deferUpdate()
|
||||
} else if (await db.exists({msgid: interaction.message.id, userid: interaction.user.id, upordown: 1})) {
|
||||
return await interaction.reply({content: 'Ya has hecho upvote.', ephemeral: true})
|
||||
} else {
|
||||
const downvotebuttons = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('suggestions-yes')
|
||||
.setEmoji('✅')
|
||||
.setLabel((convertToNumber + 1).toString())
|
||||
.setStyle(ButtonStyle.Success),
|
||||
new ButtonBuilder(interaction.message!.components[0].components[1].data as ButtonComponentData)
|
||||
)
|
||||
type: CommandType.Button,
|
||||
async execute(interaction) {
|
||||
const row1 = interaction.message!.components[0] as ActionRow<MessageActionRowComponent>;
|
||||
const row2 = interaction.message!.components[1] as ActionRow<MessageActionRowComponent>;
|
||||
const rows = {
|
||||
yes: row1.components[0],
|
||||
no: row1.components[1],
|
||||
yesWho: row2.components[0],
|
||||
noWho: row2.components[1],
|
||||
} as {
|
||||
yes: ButtonComponent;
|
||||
no: ButtonComponent;
|
||||
yesWho: ButtonComponent;
|
||||
noWho: ButtonComponent;
|
||||
};
|
||||
const upvoteData = rows.yes.data as APIButtonComponentWithCustomId;
|
||||
const downvoteData = rows.no.data as APIButtonComponentWithCustomId;
|
||||
const userSuggestion = await db.suggestion.findFirst({
|
||||
where: { msgId: interaction.message.id, userId: interaction.user.id },
|
||||
});
|
||||
|
||||
const addToDB = new db({
|
||||
msgid: interaction.message.id,
|
||||
userid: interaction.user.id,
|
||||
upordown: 1
|
||||
})
|
||||
await addToDB.save()
|
||||
await interaction.message.edit({components: [downvotebuttons, row2]})
|
||||
await interaction.deferUpdate()
|
||||
}
|
||||
if (!userSuggestion) {
|
||||
const row1 = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(rows.yes.data).setLabel((parseInt(upvoteData.label!) + 1).toString()),
|
||||
new ButtonBuilder(rows.no.data)
|
||||
);
|
||||
|
||||
await db.suggestion.create({
|
||||
data: {
|
||||
msgId: interaction.message.id,
|
||||
userId: interaction.user.id,
|
||||
upDown: 1,
|
||||
},
|
||||
});
|
||||
await interaction.message.edit({ components: [row1, row2] });
|
||||
await interaction.deferUpdate();
|
||||
return;
|
||||
}
|
||||
})
|
||||
|
||||
const userSuggestionUpDown = userSuggestion.upDown === 1;
|
||||
if (userSuggestionUpDown) {
|
||||
await interaction.deferUpdate()
|
||||
return;
|
||||
} else {
|
||||
await db.suggestion.updateMany({
|
||||
where: { msgId: interaction.message.id, userId: interaction.user.id, upDown: -1 },
|
||||
data: { upDown: 1 },
|
||||
});
|
||||
|
||||
const row1 = new ActionRowBuilder<ButtonBuilder>().setComponents(
|
||||
new ButtonBuilder(rows.yes.data).setLabel((parseInt(upvoteData.label!) + 1).toString()),
|
||||
new ButtonBuilder(rows.no.data).setLabel((parseInt(downvoteData.label!) - 1).toString())
|
||||
);
|
||||
await interaction.message.edit({ components: [row1, row2] });
|
||||
await interaction.deferUpdate();
|
||||
return;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import { ApplicationCommandOptionType } from "discord.js";
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ApplicationCommandOptionType } from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
name: 'ip',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
//
|
||||
description: 'La IP del servidor de Minecraft',
|
||||
options: [
|
||||
{
|
||||
name: 'usuario',
|
||||
description: 'Menciona al usuario al que va dirigido el comando.',
|
||||
type: ApplicationCommandOptionType.User
|
||||
}
|
||||
],
|
||||
//alias : [],
|
||||
execute: async (ctx, options) => {
|
||||
const usuario = ctx.options.getMember('usuario');
|
||||
name: 'ip',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'La IP del servidor de Minecraft',
|
||||
options: [
|
||||
{
|
||||
name: 'usuario',
|
||||
description: 'Menciona al usuario al que va dirigido el comando.',
|
||||
type: ApplicationCommandOptionType.User,
|
||||
},
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
const usuario = ctx.options.getMember('usuario');
|
||||
const message = 'La IP del servidor de Minecraft es `minecraft.maraturing.com`,\nPide acceso con el comando `/mcform`.'
|
||||
|
||||
if (!usuario) {
|
||||
await ctx.reply({content: "La IP del servidor de Minecraft es `minecraft.maraturing.com`,\nPide acceso con el comando </mcform:1000747672690499594>.", ephemeral: true})
|
||||
} else {
|
||||
await ctx.reply({content: `${usuario}` + ", la IP del servidor de Minecraft es `minecraft.maraturing.com`,\nPide acceso con el comando </mcform:1000747672690499594>."})
|
||||
}
|
||||
},
|
||||
});
|
||||
if (!usuario) {
|
||||
await ctx.reply({
|
||||
content: message,
|
||||
ephemeral: true,
|
||||
});
|
||||
} else {
|
||||
await ctx.reply({
|
||||
content: `${usuario}, ${message}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ModalBuilder,
|
||||
TextInputBuilder,
|
||||
TextInputStyle,
|
||||
ModalActionRowComponentBuilder,
|
||||
ActionRowBuilder,
|
||||
ModalBuilder,
|
||||
TextInputBuilder,
|
||||
TextInputStyle,
|
||||
ModalActionRowComponentBuilder,
|
||||
} from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
name: 'mcform',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Envia el formulario para entrar al servidor.',
|
||||
//alias : [],
|
||||
execute: async (ctx) => {
|
||||
const modal = new ModalBuilder()
|
||||
.setCustomId('mcform-main')
|
||||
.setTitle('Formulario para entrar al servidor');
|
||||
const input = new TextInputBuilder()
|
||||
.setCustomId('mcUsernameInput')
|
||||
.setLabel('Cuál es tu nombre de usuario de Minecraft?')
|
||||
.setStyle(TextInputStyle.Short);
|
||||
const usernameActionRow =
|
||||
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
|
||||
input
|
||||
);
|
||||
modal.addComponents(usernameActionRow);
|
||||
await ctx.interaction.showModal(modal);
|
||||
},
|
||||
name: 'mcform',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Envia el formulario para entrar al servidor.',
|
||||
execute: async (ctx) => {
|
||||
const modal = new ModalBuilder()
|
||||
.setCustomId('mcform-modal')
|
||||
.setTitle('Formulario para entrar al servidor');
|
||||
const input = new TextInputBuilder()
|
||||
.setCustomId('mcUsernameInput')
|
||||
.setLabel('Cuál es tu nombre de usuario de Minecraft?')
|
||||
.setStyle(TextInputStyle.Short);
|
||||
const usernameActionRow = new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
|
||||
input
|
||||
);
|
||||
modal.addComponents(usernameActionRow);
|
||||
await ctx.interaction.showModal(modal);
|
||||
},
|
||||
});
|
||||
|
||||
58
src/commands/misc/acortar.ts
Normal file
58
src/commands/misc/acortar.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ApplicationCommandOptionType } from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'acorta una url',
|
||||
options: [
|
||||
{
|
||||
name: 'url',
|
||||
description: 'la url a acortar',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'alias',
|
||||
description: 'alias opcional para la url acortada',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: false,
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
const url = ctx.options.getString('url', true);
|
||||
const alias = ctx.options.getString('alias');
|
||||
|
||||
const res = await fetch('https://spoo.me', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
url,
|
||||
// idk why copilot did that but ok
|
||||
...(alias && { alias })
|
||||
})
|
||||
}).then(r => r.json());
|
||||
|
||||
if (res.error) {
|
||||
return ctx.reply({
|
||||
content: `Error al acortar la URL: ${res.message}`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (res.short_url) {
|
||||
return ctx.reply({
|
||||
content: `URL acortada: ${res.short_url}`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
return ctx.reply({
|
||||
content: `Algo no ha ido bien!`,
|
||||
ephemeral: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -1,69 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import db from '../../schemas/afk.js';
|
||||
import { ApplicationCommandOptionType, EmbedBuilder } from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'afk command',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'añadir',
|
||||
description: 'Di que estás AFK o inactivo por la razón que quieras.',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: [
|
||||
{
|
||||
name: 'motivo',
|
||||
description: 'El motivo por el que estarás AFK',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'eliminar',
|
||||
description: 'Elimina tu AFK',
|
||||
type: ApplicationCommandOptionType.Subcommand
|
||||
},
|
||||
{
|
||||
name: 'lista',
|
||||
description: 'Listado de todas las personas AFK',
|
||||
type: ApplicationCommandOptionType.Subcommand
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
switch (ctx.options.getSubcommand()) {
|
||||
case 'añadir': {
|
||||
if (await db.exists({ id: ctx.user.id })) return ctx.reply({ content: 'Ya existes en la base de datos!', ephemeral: true })
|
||||
const reason = ctx.options.getString('motivo');
|
||||
|
||||
await (new db({ id: ctx.user.id, reason: reason })).save()
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({ name: ctx.user.username, iconURL: ctx.user.displayAvatarURL() })
|
||||
.setTitle('AFK añadido!')
|
||||
.setColor('Green')
|
||||
.setDescription(`Razón: ${reason}`)
|
||||
|
||||
await ctx.reply({ embeds: [embed] })
|
||||
} break;
|
||||
case 'eliminar': {
|
||||
if (!await db.exists({ id: ctx.user.id })) return ctx.reply({ content: 'No existes en la base de datos!', ephemeral: true })
|
||||
|
||||
await db.deleteOne({ id: ctx.user.id })
|
||||
|
||||
await ctx.reply('Ok, has sido eliminado correctamente de la base de datos.')
|
||||
} break;
|
||||
case 'lista': {
|
||||
const map = await Promise.all((await db.find()).map(async (doc) => {
|
||||
return `${await ctx.client.users.fetch(doc.id)}`
|
||||
}))
|
||||
|
||||
await ctx.reply({
|
||||
content: `Lista de usuarios AFK:\n${(map.length === 0) ? 'Nadie' : map.join(', ')}`,
|
||||
allowedMentions: { repliedUser: false }
|
||||
})
|
||||
} break;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,191 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ModalBuilder,
|
||||
TextInputBuilder,
|
||||
TextInputStyle,
|
||||
ModalActionRowComponentBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
ComponentType,
|
||||
ModalSubmitInteraction,
|
||||
ApplicationCommandOptionType,
|
||||
} from 'discord.js';
|
||||
import padyama from '../../schemas/padyama.js';
|
||||
import { random } from '../../util/randomstring.js';
|
||||
import { disable } from '#plugins';
|
||||
|
||||
export default commandModule({
|
||||
name: 'askjavi',
|
||||
type: CommandType.Slash,
|
||||
plugins: [
|
||||
disable()
|
||||
],
|
||||
description: 'TEMP: Pregunta a Javi LO QUE SEA!',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'new',
|
||||
description: 'Haz una nueva pregunta',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
},
|
||||
{
|
||||
name: 'get',
|
||||
description: 'Mira una pregunta teniendo su ID.',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: [
|
||||
{
|
||||
name: 'id',
|
||||
description: 'El ID de la pregunta',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'you',
|
||||
description: 'Todos los IDs de las preguntas que hayas hecho',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
},
|
||||
{
|
||||
name: 'answered',
|
||||
description:
|
||||
'ORGANIZADOR: Todos los IDs de las preguntas que hayas hecho',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: [
|
||||
{
|
||||
name: 'id',
|
||||
description: 'El ID de la pregunta',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
switch (ctx.interaction.options.getSubcommand()) {
|
||||
case 'new': {
|
||||
const modal = new ModalBuilder()
|
||||
.setCustomId('askjavi')
|
||||
.setTitle('Sugerencias');
|
||||
const input = new TextInputBuilder()
|
||||
.setCustomId('askjavi-prompt')
|
||||
.setLabel('Qué quieres preguntarle?')
|
||||
.setStyle(TextInputStyle.Paragraph);
|
||||
const suggestionsActionRow =
|
||||
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(
|
||||
input
|
||||
);
|
||||
modal.addComponents(suggestionsActionRow);
|
||||
const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('askjavi-buttons-yes')
|
||||
.setLabel('Sí!')
|
||||
.setStyle(ButtonStyle.Success),
|
||||
new ButtonBuilder()
|
||||
.setCustomId('askjavi-buttons-no')
|
||||
.setLabel('Ok mejor no')
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
);
|
||||
const message = await ctx.reply({
|
||||
content: `No puedes enviar sugerencias inútiles o spam.\nSi haces esto, serás descalificado.\nContinuas?`,
|
||||
components: [buttons],
|
||||
ephemeral: true,
|
||||
});
|
||||
const collector = message.createMessageComponentCollector({
|
||||
max: 1,
|
||||
componentType: ComponentType.Button,
|
||||
time: 60_000,
|
||||
});
|
||||
collector.on('collect', async (i) => {
|
||||
if (i.customId === 'askjavi-buttons-yes') {
|
||||
const suggestionid = random(5);
|
||||
await i.showModal(modal);
|
||||
await ctx.interaction.editReply({
|
||||
components: [],
|
||||
});
|
||||
const submitted = (await ctx.interaction
|
||||
.awaitModalSubmit({
|
||||
time: 180000,
|
||||
filter: (i) => i.user.id === ctx.user.id,
|
||||
})
|
||||
.catch((error) => {})) as unknown as ModalSubmitInteraction;
|
||||
const db = new padyama({
|
||||
id: i.user.id,
|
||||
user: i.user.username,
|
||||
suggestionid: suggestionid,
|
||||
suggestion: submitted.fields.getTextInputValue('askjavi-prompt'),
|
||||
});
|
||||
await db.save();
|
||||
await submitted.reply({
|
||||
content: `Tu pregunta ha sido registrada en la base de datos correctamente.\nEl ID de esta pregunta es: \`${suggestionid}\`. Se te contactará por DMs cuando se responda la pregunta.\nPuedes ver tus IDs de preguntas con el comando </askjavi you:1040938647001776199>.`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
if (i.customId === 'askjavi-buttons-no') {
|
||||
await ctx.interaction.editReply({
|
||||
content: 'Ok pues...',
|
||||
components: [],
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
case 'get': {
|
||||
const option = ctx.options.getString('id');
|
||||
const db = await padyama.findOne({ suggestionid: option });
|
||||
if (db?.suggestion !== undefined)
|
||||
return await ctx.reply({
|
||||
content: `La sugerencia es:\n${db?.suggestion}`,
|
||||
ephemeral: true,
|
||||
});
|
||||
else
|
||||
return await ctx.reply({
|
||||
content: `Parece que ese ID no se ha encontrado...`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
case 'you': {
|
||||
const db = await padyama.find({ id: ctx.user.id });
|
||||
await ctx.reply({
|
||||
content: `Los IDs de las preguntas que has hecho:\n${db.map(
|
||||
(doc) => `\`${doc.suggestionid}\``
|
||||
)}`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
case 'answered': {
|
||||
if (ctx.user.id !== '703974042700611634')
|
||||
return await ctx.reply({
|
||||
content: `No puedes usar este comando.`,
|
||||
ephemeral: true,
|
||||
});
|
||||
const option = ctx.options.getString('id');
|
||||
const db = await padyama.findOne({ suggestionid: option });
|
||||
if (db?.user !== undefined) {
|
||||
try {
|
||||
await (await ctx.user.fetch(db?.id))
|
||||
.send({
|
||||
content: `Hola!\nRespecto al AMA del sevidor de Mara:\nTu pregunta con ID \`${option}\` ha sido respondida correctamente!`,
|
||||
})
|
||||
.then(async () => {
|
||||
await ctx.reply({
|
||||
content: `DM enviado correctamente!`,
|
||||
ephemeral: true,
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
await ctx.reply({
|
||||
content: `Parece que no se ha podido enviar el DM...`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await ctx.reply({
|
||||
content: `No se ha encontrado el usuario enlazado con el ID en cuestión...`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,48 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js";
|
||||
|
||||
export default commandModule({
|
||||
name: 'creditos',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Créditos del bot (en inglés)',
|
||||
//alias : [],
|
||||
options: [],
|
||||
execute: async (ctx) => {
|
||||
const baseEmbed = new EmbedBuilder()
|
||||
.setColor('Blurple')
|
||||
.setTitle(`Without these people, the bot wouldn't exist!`)
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setFooter({text: `Created by Sr Izan | This list will be expanded`, iconURL: ctx.client.user?.displayAvatarURL()})
|
||||
const page1 = baseEmbed
|
||||
.setDescription(`**Development**\n
|
||||
<@703974042700611634>: Main development.\n
|
||||
<@464397024247152640>: Trusting me and inviting the bot.\n
|
||||
**For helping me out**\n
|
||||
<@182326315813306368>: sern handler dev, helper at WOK, such a cool guy and helper <3\n
|
||||
<@697795666373640213>: sern handler dev, also helper at WOK, helped me out a ton\n
|
||||
*Some people at the D.JS discord*: yeah\n
|
||||
**Motivation**\n
|
||||
<@719678368173523015>: WHAT ARE YOU DOING ON VINCI RN?!?!?!\n
|
||||
<@530870655005097995>: Gave some ideas on the *original* roadmap\n
|
||||
<@678000774441336842>: My good'ol friend, always has been trying new Vinci stuff\n
|
||||
<@758743564879659069>: Believe it or not, this looper has alvays been beta-testing stuff\n
|
||||
<@697146020647403651>: For always thanking all my work\n
|
||||
<@630502288154427414>: he bans everyone on my twitch\n
|
||||
**And, of course, you <3**\n
|
||||
Thanks everyone, this has been an absolute ride, I don't have words to express my appreciation! <:Pepelove:1030904410307563542>
|
||||
`)
|
||||
const buttons = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel('lol')
|
||||
.setURL('https://discord.com/channels/928018226330337280/928018227156643857/1030480463690731530')
|
||||
.setStyle(ButtonStyle.Link),
|
||||
new ButtonBuilder()
|
||||
.setLabel('<3')
|
||||
.setURL('https://discord.com/channels/928018226330337280/1030913456846680134')
|
||||
.setStyle(ButtonStyle.Link)
|
||||
)
|
||||
await ctx.reply({embeds: [page1], components: [buttons], ephemeral: true})
|
||||
},
|
||||
});
|
||||
@@ -1,56 +1,62 @@
|
||||
import { commandModule, CommandType } from "@sern/handler";
|
||||
import { ApplicationCommandOptionType } from "discord.js";
|
||||
import { readFileSync } from "node:fs";
|
||||
import birthdays from "../../schemas/birthdays.js";
|
||||
import { acceptingBirthday } from "#plugins";
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ApplicationCommandOptionType } from 'discord.js';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
export default commandModule({
|
||||
name: "cumple",
|
||||
type: CommandType.Slash,
|
||||
plugins: [acceptingBirthday()],
|
||||
description: "Pon tu cumpleaños en la base de datos para ser felicitado!",
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: "fecha",
|
||||
description: "La fecha de tu cumple (D-M) (elige en el autocompletado)",
|
||||
type: ApplicationCommandOptionType.String,
|
||||
autocomplete: true,
|
||||
required: true,
|
||||
command: {
|
||||
onEvent: [],
|
||||
execute: async (autocomplete) => {
|
||||
const focusedValue = autocomplete.options.getFocused();
|
||||
let choices = JSON.parse(
|
||||
String(readFileSync("./util/daysinyear.txt"))
|
||||
) as Array<string>;
|
||||
choices = choices.filter((choice) =>
|
||||
choice.toString().startsWith(focusedValue)
|
||||
);
|
||||
choices = choices.slice(0, 25);
|
||||
await autocomplete.respond(
|
||||
choices.map((choice) => ({
|
||||
name: choice.toString(),
|
||||
value: choice,
|
||||
}))
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
const option = ctx.interaction.options.getString("fecha")
|
||||
const array = JSON.parse(
|
||||
String(readFileSync("./util/daysinyear.txt"))
|
||||
) as Array<string>;
|
||||
if (!array.includes(option!)) return await ctx.interaction.editReply('Asegúrate que estás eligiendo una fecha del autocompletado!')
|
||||
if (await birthdays.exists({id: ctx.user.id})) return await ctx.interaction.editReply('No puedes poner tu fecha de nuevo!')
|
||||
const db = new birthdays({
|
||||
id: ctx.user.id,
|
||||
date: option,
|
||||
alreadysent: false
|
||||
});
|
||||
await db.save();
|
||||
await ctx.interaction.editReply('Ok, guardado correctamente. No puedes volver a cambiar la fecha.')
|
||||
},
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Añade tu cumpleaños',
|
||||
options: [
|
||||
{
|
||||
name: 'fecha',
|
||||
description: 'La fecha de tu cumple (D-M) (elige en el autocompletado)',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
autocomplete: true,
|
||||
required: true,
|
||||
command: {
|
||||
onEvent: [],
|
||||
execute: async (autocomplete) => {
|
||||
const focusedValue = autocomplete.options.getFocused();
|
||||
let choices = JSON.parse(readFileSync('./assets/daysinyear.json').toString()) as string[];
|
||||
choices = choices.filter((choice) => choice.startsWith(focusedValue));
|
||||
choices = choices.slice(0, 25);
|
||||
await autocomplete.respond(
|
||||
choices.map((choice) => ({
|
||||
name: choice,
|
||||
value: choice,
|
||||
}))
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
execute: async (ctx, sdt) => {
|
||||
const date = ctx.interaction.options.getString('fecha', true);
|
||||
|
||||
const existing = await sdt.deps.prisma.birthday.findUnique({
|
||||
where: { userId: ctx.user.id },
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
await sdt.deps.prisma.birthday.update({
|
||||
where: { userId: ctx.user.id },
|
||||
data: { date },
|
||||
});
|
||||
await ctx.reply({
|
||||
content: `cumpleaños actualizado a ${date}!`,
|
||||
ephemeral: true,
|
||||
});
|
||||
} else {
|
||||
await sdt.deps.prisma.birthday.create({
|
||||
data: {
|
||||
userId: ctx.user.id,
|
||||
date,
|
||||
},
|
||||
});
|
||||
await ctx.reply({
|
||||
content: `cumpleaños registrado para el ${date}!`,
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import { ApplicationCommandOptionType, ColorResolvable, EmbedBuilder } from 'discord.js';
|
||||
import mctags from '../../../assets/mcTags.json' with { type: "json" };
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Preguntas normalmente preguntadas :pepega:',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'minecraft',
|
||||
description: 'Preguntas normalmente preguntadas de Minecraft',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: [
|
||||
{
|
||||
name: 'pregunta',
|
||||
description: 'La pregunta',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
autocomplete: true,
|
||||
required: true,
|
||||
command: {
|
||||
onEvent: [],
|
||||
execute: async (ctx) => {
|
||||
const query = ctx.options.getFocused()
|
||||
const filter = mctags.filter(obj => obj.title.includes(query))
|
||||
await ctx.respond(
|
||||
filter.map(map => ({ name: map.title.toString(), value: map.title.toString() }))
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'para',
|
||||
description: 'Menciona a la persona a la que vaya esto.',
|
||||
type: ApplicationCommandOptionType.User,
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
switch (ctx.options.getSubcommand()) {
|
||||
case 'minecraft': {
|
||||
const option = ctx.options.getString('pregunta', true)
|
||||
const forusr = ctx.options.getMember('para')
|
||||
const filter = mctags.filter(obj => obj.title.includes(option))[0]
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({ name: ctx.user.username, iconURL: ctx.user.displayAvatarURL() })
|
||||
.setColor(filter.color as ColorResolvable)
|
||||
.setTitle(filter.title)
|
||||
.setDescription(filter.text)
|
||||
if (forusr) {
|
||||
await ctx.reply({
|
||||
content: `Esto es para tí ${forusr}:`,
|
||||
embeds: [embed]
|
||||
})
|
||||
} else {
|
||||
await ctx.reply({ embeds: [embed] })
|
||||
}
|
||||
} break;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import google from 'googlethis'
|
||||
import { ApplicationCommandOptionType } from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Busca cosas en Google.',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'busqueda',
|
||||
description: 'Escribe qué quieres buscar',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
await ctx.interaction.deferReply()
|
||||
const prompt = ctx.options.getString('busqueda', true)
|
||||
|
||||
const search = await Promise.all((await google.search(prompt)).results.map(res => {
|
||||
return `[${res.title}](<${res.url}>)`
|
||||
}).slice(0, 5))
|
||||
await ctx.interaction.editReply({
|
||||
content: `Resultados para la búsqueda \`${prompt}\`:\n${search.join('\n')}`
|
||||
})
|
||||
},
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { publish } from '#plugins';
|
||||
import { AttachmentBuilder, codeBlock } from 'discord.js';
|
||||
import { createCanvas, loadImage } from '@napi-rs/canvas';
|
||||
import sharp from 'sharp';
|
||||
|
||||
export default commandModule({
|
||||
name: 'Clasifica una imagen',
|
||||
type: CommandType.CtxMsg,
|
||||
plugins: [],
|
||||
execute: async (ctx) => {
|
||||
await ctx.deferReply()
|
||||
|
||||
if (ctx.targetMessage.attachments.size === 0) return ctx.editReply('No hay ninguna imagen para clasificar!');
|
||||
const image = ctx.targetMessage.attachments.first()!;
|
||||
if (!image.contentType!.startsWith('image/') && image.contentType !== 'image/gif') return ctx.editReply('El archivo no es una imagen!');
|
||||
|
||||
const imageBuffer = await fetch(image.url).then(async res => await res.arrayBuffer());
|
||||
const compressed = sharp(imageBuffer)
|
||||
.png({quality: 70})
|
||||
.jpeg({quality: 70})
|
||||
.webp({quality: 70})
|
||||
.tiff({quality: 70});
|
||||
const metadata = await compressed.metadata();
|
||||
const imageUint8Array = new Uint8Array(await compressed.toBuffer());
|
||||
|
||||
const request = await fetch(`https://api.cloudflare.com/client/v4/accounts/${process.env.CF_AI_ACC}/ai/run/@cf/facebook/detr-resnet-50`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.CF_AI_TOKEN}`,
|
||||
},
|
||||
body: imageUint8Array,
|
||||
}).then(async res => await res.json());
|
||||
if (request.errors.length > 0) return ctx.editReply(`Hubo un error! ${codeBlock(JSON.stringify(request.errors))}`);
|
||||
|
||||
// all canvas stuff, this was fun to make
|
||||
const canvas = createCanvas(metadata.width!, metadata.height!);
|
||||
const ctxCanvas = canvas.getContext('2d');
|
||||
const img = await loadImage(image.url);
|
||||
ctxCanvas.drawImage(img, 0, 0, metadata.width!, metadata.height!);
|
||||
ctxCanvas.font = '40px sans-serif';
|
||||
ctxCanvas.fillStyle = 'red';
|
||||
ctxCanvas.strokeStyle = 'red';
|
||||
ctxCanvas.lineWidth = 3;
|
||||
for (const result of request.result) {
|
||||
if (result.score < 0.5) continue;
|
||||
const box = result.box;
|
||||
ctxCanvas.strokeRect(box.xmin, box.ymin, box.xmax - box.xmin, box.ymax - box.ymin);
|
||||
ctxCanvas.fillText(result.label, box.xmin, box.ymin - 5);
|
||||
}
|
||||
const canvasBuffer = canvas.toBuffer('image/png');
|
||||
const attachment = new AttachmentBuilder(canvasBuffer, { name: 'generatedImage.png' });
|
||||
|
||||
await ctx.editReply({ files: [attachment] })
|
||||
},
|
||||
});
|
||||
@@ -1,97 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ApplicationCommandOptionType, bold, codeBlock, EmbedBuilder, inlineCode } from 'discord.js';
|
||||
import fs from 'node:fs/promises'
|
||||
import { ICFile } from '../../util/infinitecraft/decompress.js';
|
||||
import Finder from '../../util/infinitecraft/finder.js';
|
||||
|
||||
const recipeFile = JSON.parse(await fs.readFile('./assets/icRecipes.json', 'utf-8')) as ICFile;
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Descifra con un algoritmo cómo llegar a la receta de un objeto en InfiniteCraft',
|
||||
options: [
|
||||
{
|
||||
name: 'objeto',
|
||||
description: 'El objeto que quieres descifrar',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
command: {
|
||||
onEvent: [],
|
||||
async execute(ctx) {
|
||||
const input = ctx.options.getFocused();
|
||||
const choices = recipeFile.items
|
||||
.filter(item => item.toLowerCase().includes(input.toLowerCase()))
|
||||
.slice(0, 25)
|
||||
if (choices.length === 0) return ctx.respond([{ name: 'No se encontraron resultados', value: 'SSError' }]);
|
||||
if (input.length === 0) return ctx.respond([{ name: 'Empieza a escribir', value: 'SSError' }]);
|
||||
await ctx.respond(
|
||||
choices.map(choice => {
|
||||
return ({ name: choice, value: choice })
|
||||
})
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
await ctx.interaction.deferReply()
|
||||
const object = ctx.options.getString('objeto', true)
|
||||
if (object === 'SSError') return ctx.reply({
|
||||
content: 'Has escogido el mensaje de error 💀',
|
||||
ephemeral: true
|
||||
});
|
||||
if (!recipeFile.items.includes(ctx.options.getString('objeto', true))) return ctx.reply({
|
||||
content: 'No se encontró el objeto. Asegúrate de escogerlo del autocompletado.',
|
||||
ephemeral: true
|
||||
});
|
||||
|
||||
let processed = 0
|
||||
let timesBacked = 0
|
||||
const infinitePath = new Finder((progress) => {
|
||||
switch (progress.phase) {
|
||||
case 0:
|
||||
processed = progress.current
|
||||
break;
|
||||
case 1:
|
||||
timesBacked = timesBacked + 1
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
const interval = setInterval(() => {
|
||||
ctx.interaction.editReply({
|
||||
content: `Procesando...\n${inlineCode(processed.toString())} recetas procesadas, ${inlineCode(timesBacked.toString())} veces retrocedido.`,
|
||||
})
|
||||
}, 1250)
|
||||
ctx.interaction.editReply({
|
||||
content: `Procesando...\n${inlineCode(processed.toString())} recetas procesadas, ${inlineCode(timesBacked.toString())} veces retrocedido.`,
|
||||
})
|
||||
const initialTime = performance.now()
|
||||
const path = await infinitePath.findItem(object)
|
||||
const finalTime = performance.now()
|
||||
clearInterval(interval)
|
||||
if (path.length === 0) return ctx.interaction.editReply({
|
||||
content: 'No se encontró la receta de este objeto.'
|
||||
});
|
||||
|
||||
const recipe = path.map(({ first, second, result }) => `${first} + ${second} = ${result}`).join('\n')
|
||||
let paste: string | undefined;
|
||||
if (recipe.length >= 1500) {
|
||||
paste = await fetch('https://fb.srizan.dev/paste', {
|
||||
method: 'POST',
|
||||
body: recipe
|
||||
}).then(async res => await res.text())
|
||||
}
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle(`Receta de ${object.toLowerCase()}`)
|
||||
.setColor('Green')
|
||||
.setDescription(paste ? `La ruta es demasiado grande, así que lo he puesto en un pastebin:\nhttps://fb.srizan.dev/${paste}` : codeBlock(recipe))
|
||||
.setFooter({ text: 'Ya que se usa un algoritmo, puede o no ser la ruta más rápida para llegar al ítem' })
|
||||
return ctx.interaction.editReply({
|
||||
embeds: [embed],
|
||||
content: `Por fin encontrado! La búsqueda tomó ${bold(((finalTime - initialTime) / 1000).toFixed(2))} segundos.`
|
||||
})
|
||||
},
|
||||
});
|
||||
@@ -1,59 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import Genius from 'genius-lyrics'
|
||||
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonStyle, EmbedBuilder } from 'discord.js';
|
||||
|
||||
const genius = new Genius.Client(process.env.GENIUS)
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Busca la letra de una canción (Genius)',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'busqueda',
|
||||
description: 'Qué buscar',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
command: {
|
||||
onEvent: [],
|
||||
execute: async (ctx) => {
|
||||
const input = ctx.options.getFocused();
|
||||
const choices = (await genius.songs.search(input)).map(res => {
|
||||
return `${res.title} - ${res.artist.name}|${res.id}`
|
||||
})
|
||||
await ctx.respond(
|
||||
choices.map(choice => {
|
||||
const [title, id] = choice.split('|')
|
||||
return ({name: title, value: id})
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
await ctx.interaction.deferReply({ ephemeral: true })
|
||||
const prompt = ctx.options.getString('busqueda', true)
|
||||
|
||||
const result = await genius.songs.get(Number(prompt))
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle(`${result.title} - ${result.artist.name}`)
|
||||
.setColor('Random')
|
||||
.setDescription((await result.lyrics()).slice(0, 3000))
|
||||
const button = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel('URL de Genius')
|
||||
.setStyle(ButtonStyle.Link)
|
||||
.setURL(result.url)
|
||||
)
|
||||
|
||||
await ctx.interaction.editReply({
|
||||
embeds: [embed],
|
||||
components: [button]
|
||||
})
|
||||
},
|
||||
});
|
||||
@@ -1,84 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import { createAudioPlayer, createAudioResource, DiscordGatewayAdapterCreator, joinVoiceChannel } from "@discordjs/voice";
|
||||
import got from "got";
|
||||
import { ApplicationCommandOptionType, EmbedBuilder } from "discord.js";
|
||||
const choices = ['Rock FM', 'Cadena 100', 'Cadena Dial', 'Gensokyo Radio', 'BBC 1', 'RNE 1', 'RNE 5', 'Los 40'];
|
||||
|
||||
export default commandModule({
|
||||
name: 'radio',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Reproduce la radio',
|
||||
options: [
|
||||
{
|
||||
name: 'reproducir',
|
||||
description: 'Reproduce una radio de la lista',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
autocomplete: true,
|
||||
required: true,
|
||||
command: {
|
||||
onEvent: [],
|
||||
async execute(ctx){
|
||||
const focusedValue = ctx.options.getFocused();
|
||||
const filtered = choices.filter(choice => choice.startsWith(focusedValue));
|
||||
await ctx.respond(
|
||||
filtered.map(choice => ({ name: choice, value: choice })),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
const radioname = ctx.options.getString("reproducir", true)
|
||||
if (!choices.includes(radioname)) return await ctx.reply('Asegúrate de escoger una radio de la lista.')
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor("Green")
|
||||
.setTitle(`Reproduciendo ${radioname} en Vinci Radio.`)
|
||||
.setDescription(`A veces la radio tarda en cargar, sé paciente :'D`);
|
||||
const notFoundEmbed = new EmbedBuilder()
|
||||
.setColor("Red")
|
||||
.setTitle(`Radio ${radioname} no encontrada.`)
|
||||
.setDescription(`La radio no ha sido encontrada, asegúrate que la radio está escogida de la lista.`);
|
||||
|
||||
async function playRadio(radioname: string) {
|
||||
const stream = got.stream(radioname)
|
||||
const connection = joinVoiceChannel({adapterCreator: ctx.interaction.guild!.voiceAdapterCreator as DiscordGatewayAdapterCreator, channelId: '1008730592835281009',guildId: '928018226330337280',selfDeaf: true});
|
||||
const resource = createAudioResource(stream, { inlineVolume: true });
|
||||
const player = createAudioPlayer();
|
||||
connection.subscribe(player)
|
||||
player.play(resource)
|
||||
resource.volume!.setVolume(0.7)
|
||||
await ctx.reply({embeds: [embed], ephemeral: true})
|
||||
}
|
||||
|
||||
switch (radioname) {
|
||||
case 'Rock FM': {
|
||||
playRadio("https://flucast-m04-06.flumotion.com/cope/rockfm.mp3")
|
||||
} break;
|
||||
case 'Cadena 100': {
|
||||
playRadio("https://server8.emitironline.com:18196/stream")
|
||||
} break;
|
||||
case 'Cadena Dial': {
|
||||
playRadio("http://20853.live.streamtheworld.com/CADENADIAL.mp3")
|
||||
} break;
|
||||
case 'BBC 1': {
|
||||
playRadio("http://stream.live.vc.bbcmedia.co.uk/bbc_radio_one")
|
||||
} break;
|
||||
case 'RNE 1': {
|
||||
playRadio("https://crtve--di--crtve-ice--01--cdn.cast.addradio.de/crtve/rne1/main/mp3/high")
|
||||
} break;
|
||||
case 'RNE 5': {
|
||||
playRadio("https://crtve--di--crtve-ice--01--cdn.cast.addradio.de/crtve/rne5/main/mp3/high")
|
||||
} break;
|
||||
case 'Los 40': {
|
||||
playRadio('http://stream.ondaceronoroeste.es:8000/stream')
|
||||
} break;
|
||||
case 'Gensokyo Radio': {
|
||||
playRadio('https://stream.gensokyoradio.net/3')
|
||||
} break;
|
||||
default: {
|
||||
await ctx.reply({embeds: [notFoundEmbed], ephemeral: true})
|
||||
} break;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,37 +0,0 @@
|
||||
import { commandModule, CommandType } from "@sern/handler";
|
||||
import axios, { AxiosResponse } from "axios";
|
||||
import { ApplicationCommandOptionType } from "discord.js";
|
||||
import { disable } from "#plugins";
|
||||
|
||||
export default commandModule({
|
||||
name: "acortar",
|
||||
type: CommandType.Slash,
|
||||
plugins: [
|
||||
disable()
|
||||
],
|
||||
description: "Acorta una URL a vinci.tk",
|
||||
options: [
|
||||
{
|
||||
name: "url",
|
||||
description: "la URL larga",
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
//alias : [],
|
||||
execute: async (ctx, options) => {
|
||||
const url = ctx.options.getString("url", true);
|
||||
const request = await axios(
|
||||
`https://vinci.tk/yourls-api.php?signature=${process.env.YOURLS_KEY}&action=shorturl&format=json&url=${url}`,
|
||||
{
|
||||
validateStatus: function (status) {
|
||||
return status === 200 || status === 400;
|
||||
},
|
||||
}
|
||||
).then((res: AxiosResponse) => res.data);
|
||||
ctx.reply({
|
||||
content: `URL acortada: <${request.shorturl}>\nURL original: <${url}>`,
|
||||
ephemeral: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -1,44 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import { disable } from "#plugins";
|
||||
import { EmbedBuilder } from "discord.js";
|
||||
import axios from "axios";
|
||||
// @ts-ignore
|
||||
import prettySeconds from 'pretty-seconds-spanish'
|
||||
|
||||
export default commandModule({
|
||||
name: 'stats',
|
||||
type: CommandType.Slash,
|
||||
plugins: [disable()],
|
||||
description: 'Enseña estadísticas del bot.',
|
||||
//alias : [],
|
||||
options: [],
|
||||
execute: async (ctx, options) => {
|
||||
await ctx.interaction.deferReply({ ephemeral: true })
|
||||
const cpubrand = await axios(`http://192.168.1.79:7271/cpubrand`)
|
||||
const cpucores = await axios(`http://192.168.1.79:7271/cpucores`)
|
||||
const ramtotal = await axios(`http://192.168.1.79:7271/ramtotal`)
|
||||
const ramfree = await axios(`http://192.168.1.79:7271/ramfree`)
|
||||
const dockertotal = await axios(`http://192.168.1.79:7271/dockertotal`)
|
||||
const uptime = prettySeconds(process.uptime())
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({name: `${ctx.user.username}`, iconURL: `${ctx.user.displayAvatarURL()}`})
|
||||
.setTitle(`Estadísticas de Vinci.`)
|
||||
.setThumbnail(`https://i.imgur.com/UwC1x8T.png`)
|
||||
.setURL('https://status.vinci.tk')
|
||||
.setColor('Random')
|
||||
.addFields(
|
||||
{name: "Fabricante de CPU", value: `${cpubrand.data}`, inline: true},
|
||||
{name: `Núcleos de CPU`, value: `${cpucores.data}`, inline: true},
|
||||
{name: '\u200B', value: '\u200B', inline: true},
|
||||
{name: `RAM total`, value: `${ramtotal.data}`, inline: true},
|
||||
{name: `RAM libre`, value: `${ramfree.data}`, inline: true},
|
||||
{name: '\u200B', value: '\u200B', inline: true},
|
||||
{name: 'Contenedores de Docker', value: `${dockertotal.data}`, inline: true},
|
||||
{name: '\u200B', value: '\u200B', inline: true},
|
||||
{name: 'Tiempo encendido', value: `${uptime}`},
|
||||
// {name: '\u200B', value: '\u200B', inline: true},
|
||||
// {name: 'Uptime del servidor', value: `${prettySeconds(`${nodeuptime.data}`)}`}
|
||||
)
|
||||
await ctx.interaction.editReply({embeds: [embed]})
|
||||
},
|
||||
});
|
||||
@@ -1,30 +1,27 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import { ActionRowBuilder, ModalBuilder, TextInputBuilder, TextInputStyle, ModalActionRowComponentBuilder } from 'discord.js'
|
||||
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ModalBuilder,
|
||||
TextInputBuilder,
|
||||
TextInputStyle,
|
||||
ModalActionRowComponentBuilder,
|
||||
} from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
name: 'sugerencias',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Envia una sugerencia.',
|
||||
//alias : [],
|
||||
execute: async (ctx) => {
|
||||
const modal = new ModalBuilder()
|
||||
.setCustomId('sugerencias')
|
||||
.setTitle('Sugerencias');
|
||||
name: 'sugerencias',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Envia una sugerencia.',
|
||||
execute: async (ctx) => {
|
||||
const modal = new ModalBuilder().setCustomId('sugerencias').setTitle('Sugerencias');
|
||||
|
||||
// Create the text input components
|
||||
const input = new TextInputBuilder()
|
||||
.setCustomId('sugerenciasInput')
|
||||
// The label is the prompt the user sees for this input
|
||||
.setLabel("Tienes sugerencias?")
|
||||
// Short means only a single line of text
|
||||
.setStyle(TextInputStyle.Paragraph);
|
||||
// An action row only holds one text input,
|
||||
// so you need one action row per text input.
|
||||
const suggestionsActionRow = new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(input);
|
||||
// Add inputs to the modal
|
||||
modal.addComponents(suggestionsActionRow);
|
||||
await ctx.interaction.showModal(modal);
|
||||
}
|
||||
});
|
||||
const input = new TextInputBuilder()
|
||||
.setCustomId('sugerenciasInput')
|
||||
.setLabel('Tienes sugerencias?')
|
||||
.setStyle(TextInputStyle.Paragraph);
|
||||
const suggestionsActionRow =
|
||||
new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(input);
|
||||
modal.addComponents(suggestionsActionRow);
|
||||
await ctx.interaction.showModal(modal);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
|
||||
import axios from 'axios';
|
||||
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonStyle, ComponentType, EmbedBuilder } from 'discord.js';
|
||||
const choices = ['es', 'en', 'fr', 'de', 'hi', 'it', 'ja', 'ko', 'pl']
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
// , '928018226330337280'
|
||||
description: 'Traduce lo que quieras!',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'frase',
|
||||
description: 'La frase que traducir',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'idioma',
|
||||
description: 'El idioma al que quieras traducir',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
command: {
|
||||
onEvent: [],
|
||||
execute: async (interaction) => {
|
||||
const focusedValue = interaction.options.getFocused();
|
||||
const filtered = choices.filter(choice => choice.startsWith(focusedValue))
|
||||
await interaction.respond(
|
||||
filtered.map((choice) => ({
|
||||
name: choice,
|
||||
value: choice,
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
const langToTranslate = ctx.options.getString('idioma', true)
|
||||
const stringToTranslate = ctx.options.getString('frase', true)
|
||||
if (choices.indexOf(langToTranslate) === -1)
|
||||
return ctx.reply({content: 'Elige un idioma del autocompletado.'})
|
||||
|
||||
await ctx.interaction.deferReply()
|
||||
|
||||
const before = performance.now()
|
||||
|
||||
const request = await axios.post('https://translate.nvda.es/translate',
|
||||
{
|
||||
q: stringToTranslate,
|
||||
source: "auto",
|
||||
target: langToTranslate,
|
||||
format: "text",
|
||||
api_key: ""
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
).then(res => res.data)
|
||||
|
||||
const button = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId('translate-original')
|
||||
.setLabel('Texto original')
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
)
|
||||
|
||||
const after = performance.now()
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setAuthor({name: ctx.user.username, iconURL: ctx.user.displayAvatarURL()})
|
||||
.setTitle(`La traducción pedida. He tardado \`${(after - before).toFixed(2)}ms\`.`)
|
||||
.setDescription(request.translatedText as string)
|
||||
.setFooter({text: 'Traducido por LibreTranslate'})
|
||||
|
||||
const message = await ctx.interaction.editReply({embeds: [embed], components: [button]})
|
||||
const collector = message.createMessageComponentCollector({componentType: ComponentType.Button, time: 60_000})
|
||||
|
||||
collector.on('collect', async (i) => {
|
||||
if (i.customId !== 'translate-original') return
|
||||
|
||||
await i.reply({content: `La traducción original es:\n\`\`\`${stringToTranslate}\`\`\``, ephemeral: true})
|
||||
})
|
||||
},
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
// @ts-ignore
|
||||
import prettySeconds from 'pretty-seconds-spanish'
|
||||
|
||||
export default commandModule({
|
||||
name: 'uptime',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Enseña el tiempo que ha estado encendido el bot.',
|
||||
//alias : [],
|
||||
options: [],
|
||||
execute: async (ctx) => {
|
||||
// const uptime = prettyMilliseconds(ctx.client.uptime!)
|
||||
const uptime = prettySeconds(process.uptime())
|
||||
await ctx.reply(`El bot lleva encendido ${uptime}`);
|
||||
},
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
import { ApplicationCommandOptionType, AutocompleteInteraction, CacheType, CommandInteractionOptionResolver } from 'discord.js';
|
||||
import { getWikipedia, searchWikipedia } from '../../util/wikipedia.js';
|
||||
import { getWikipedia, searchWikipedia } from '../../utils/wikipedia';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
@@ -22,7 +22,7 @@ export default commandModule({
|
||||
command: {
|
||||
onEvent: [],
|
||||
execute: async (ctx) => {
|
||||
const search = await searchWikipedia('es', ctx as unknown as AutocompleteInteraction)
|
||||
const search = await searchWikipedia('es', ctx as AutocompleteInteraction)
|
||||
await ctx.respond(
|
||||
search.map(res => ({ name: res.title.toString(), value: res.pageid.toString() }))
|
||||
)
|
||||
@@ -45,7 +45,7 @@ export default commandModule({
|
||||
command: {
|
||||
onEvent: [],
|
||||
execute: async (ctx) => {
|
||||
const search = await searchWikipedia('en', ctx as unknown as AutocompleteInteraction)
|
||||
const search = await searchWikipedia('en', ctx as AutocompleteInteraction)
|
||||
await ctx.respond(
|
||||
search.map(res => ({ name: res.title.toString(), value: res.pageid.toString() }))
|
||||
)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
|
||||
import { ownerOnly } from "#plugins";;
|
||||
import { ApplicationCommandOptionType, TextChannel } from 'discord.js'
|
||||
|
||||
export default commandModule({
|
||||
name: 'prune',
|
||||
type: CommandType.Slash,
|
||||
plugins: [ownerOnly()],
|
||||
description: 'ADMIN: Elimina hasta 100 mensajes',
|
||||
options: [{
|
||||
name: 'numero',
|
||||
description: 'Escribe un número',
|
||||
type: ApplicationCommandOptionType.Number,
|
||||
required: true,
|
||||
min_value: 1,
|
||||
max_value: 100
|
||||
}],
|
||||
//alias : [],
|
||||
execute: async (ctx) => {
|
||||
try {
|
||||
const amount = ctx.options.getNumber('numero', true) as number
|
||||
(ctx.channel as unknown as TextChannel).bulkDelete(amount).catch(err => {
|
||||
console.error(err);
|
||||
ctx.reply({content: 'Ha habido un error eliminando mensajes! (mira la consola, Sr Izan)', ephemeral: true});});
|
||||
await ctx.reply({content: `Se han eliminado ${amount} mensajes.`})
|
||||
const sendToMods = ctx.client.guilds.cache.get(process.env.GUILDID!)!.channels.cache.get(process.env.MODLOGS_CHANNEL!) as unknown as TextChannel
|
||||
await sendToMods.send({content: `Se han eliminado ${amount} mensajes en ${ctx.channel}\nEfectuado por ${ctx.user}.`})
|
||||
} catch {
|
||||
ctx.reply({content: 'Ha habido un error eliminando mensajes! Error reportado automáticamente.', ephemeral: true})};
|
||||
}
|
||||
});
|
||||
@@ -1,40 +0,0 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
|
||||
import { ownerOnly } from "#plugins";
|
||||
import { ApplicationCommandOptionType, TextChannel } from "discord.js";
|
||||
|
||||
export default commandModule({
|
||||
name: 'slowmode',
|
||||
type: CommandType.Slash,
|
||||
plugins: [ownerOnly()],
|
||||
description: 'ADMIN: Pon modo lento a canales de texto',
|
||||
options: [
|
||||
{
|
||||
name: "segundos",
|
||||
description: "Los segundos de modo lento",
|
||||
type: ApplicationCommandOptionType.Number,
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: "razon",
|
||||
description: "La razón del modo lento",
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true
|
||||
}
|
||||
],
|
||||
//alias : [],
|
||||
execute: async (ctx) => {
|
||||
try {
|
||||
const seconds = ctx.options.getNumber("segundos", true);
|
||||
const reason = ctx.options.getString("razon", true);
|
||||
|
||||
(ctx.channel as unknown as TextChannel).setRateLimitPerUser(seconds, reason)
|
||||
|
||||
ctx.reply({content: `Se han añadido ${seconds} segundos de modo lento al canal de voz actual`})
|
||||
const sendToMods = ctx.client.guilds.cache.get(process.env.GUILDID!)!.channels.cache.get(process.env.MODLOGS_CHANNEL!) as unknown as TextChannel
|
||||
await sendToMods.send({content: `Se ha aplicado modo lento al canal ${ctx.channel}.\nEfectuado por ${ctx.user} con ${seconds} segundos de retardo.\nRazón: ${reason}`})
|
||||
} catch {
|
||||
ctx.reply({content: `No se ha podido aplicar modo lento al canal.`})
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,15 +1,11 @@
|
||||
import { commandModule, CommandType } from '@sern/handler'
|
||||
|
||||
import { ownerOnly } from "#plugins"
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
|
||||
export default commandModule({
|
||||
name: 'ping',
|
||||
type: CommandType.Slash,
|
||||
type: CommandType.Both,
|
||||
plugins: [],
|
||||
description: 'A ping command',
|
||||
//alias : [],
|
||||
options: [],
|
||||
execute: async (ctx, options) => {
|
||||
await ctx.reply('Hello World!');
|
||||
execute: async (ctx, args) => {
|
||||
await ctx.reply('Pong 🏓');
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
37
src/commands/silly/8ball.ts
Normal file
37
src/commands/silly/8ball.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ApplicationCommandOptionType } from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
name: '8ball',
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Preguntale a la 8-ball cosas.',
|
||||
//alias : [],
|
||||
options: [
|
||||
{
|
||||
name: 'pregunta',
|
||||
description: 'Escribe lo que le quieres preguntar.',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
var eightballwords = [
|
||||
'Probablemente',
|
||||
'Sí',
|
||||
'No',
|
||||
'Dudable',
|
||||
'Como lo veo, todo indica a que sí',
|
||||
'A lo mejor',
|
||||
'No cuentes con ello',
|
||||
'Buena suerte',
|
||||
'No lo creo',
|
||||
];
|
||||
await ctx.reply({
|
||||
content: `La bola tiene respuesta: ${
|
||||
eightballwords[Math.floor(Math.random() * eightballwords.length)]
|
||||
}.`,
|
||||
ephemeral: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
79
src/commands/silly/a.ts
Normal file
79
src/commands/silly/a.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { createCanvas, loadImage } from '@napi-rs/canvas';
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ApplicationCommandOptionType, AttachmentBuilder, GuildMember } from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'A',
|
||||
options: [
|
||||
{
|
||||
name: 'persona',
|
||||
description: 'Persona para generar la imagen',
|
||||
type: ApplicationCommandOptionType.User,
|
||||
},
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
const member = (ctx.options.getMember('persona') ?? ctx.interaction.member) as GuildMember;
|
||||
if (member.user.bot) {
|
||||
return await ctx.reply({
|
||||
content: 'no he implementado el badge de bot, y me da pereza hacerlo ahora mismo.',
|
||||
ephemeral: true,
|
||||
});
|
||||
}
|
||||
|
||||
const canvas = createCanvas(500, 60);
|
||||
const ctxCanvas = canvas.getContext('2d');
|
||||
|
||||
// canvas background
|
||||
ctxCanvas.fillStyle = '#36393F';
|
||||
ctxCanvas.fillRect(0, 0, canvas.width, canvas.height);
|
||||
ctxCanvas.save();
|
||||
|
||||
// add avatar circle
|
||||
const avatarBuffer = await fetch(member?.displayAvatarURL({ size: 128, extension: 'png' }))
|
||||
.then((res) => res.arrayBuffer());
|
||||
const avatarImage = await loadImage(Buffer.from(avatarBuffer));
|
||||
ctxCanvas.beginPath();
|
||||
ctxCanvas.arc(36, 28, 20, 0, Math.PI * 2);
|
||||
ctxCanvas.clip();
|
||||
ctxCanvas.drawImage(avatarImage, 16, 8, 40, 40);
|
||||
ctxCanvas.restore();
|
||||
ctxCanvas.save();
|
||||
|
||||
// add username and timestamp
|
||||
const now = new Date();
|
||||
const timestamp = now.toLocaleTimeString('en-US', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false
|
||||
});
|
||||
ctxCanvas.fillStyle = member.displayColor ? `#${member.displayColor.toString(16).padStart(6, '0')}` : '#FFFFFF';
|
||||
ctxCanvas.font = '16px Noto Sans';
|
||||
ctxCanvas.fillText(member.displayName, 72, 23);
|
||||
|
||||
// add timestamp
|
||||
const usernameWidth = ctxCanvas.measureText(member.displayName).width;
|
||||
ctxCanvas.fillStyle = '#72767D';
|
||||
ctxCanvas.font = '12px Noto Sans';
|
||||
ctxCanvas.fillText(` ${timestamp}`, 72 + usernameWidth + 8, 23);
|
||||
ctxCanvas.restore();
|
||||
ctxCanvas.save();
|
||||
|
||||
// message content
|
||||
ctxCanvas.fillStyle = '#DCDDDE';
|
||||
ctxCanvas.font = '16px Noto Sans';
|
||||
ctxCanvas.fillText('A', 72, 45);
|
||||
ctxCanvas.restore();
|
||||
ctxCanvas.save();
|
||||
|
||||
|
||||
const attachment = new AttachmentBuilder(await canvas.encode('png'), {
|
||||
name: 'a.png',
|
||||
});
|
||||
await ctx.reply({
|
||||
content: 'A',
|
||||
files: [attachment],
|
||||
});
|
||||
},
|
||||
});
|
||||
39
src/commands/silly/chiste.ts
Normal file
39
src/commands/silly/chiste.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { fisherYatesShuffle } from '../../utils/fisheryates.js';
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { EmbedBuilder } from 'discord.js';
|
||||
import { readFile } from 'fs/promises';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'CHISTE',
|
||||
options: [],
|
||||
execute: async (ctx) => {
|
||||
const fileContent = (
|
||||
JSON.parse(await readFile('./assets/chistes.json', 'utf-8')) as JokesJSON[]
|
||||
)
|
||||
// do not ask
|
||||
.filter((j) => j.category !== 'sexo');
|
||||
|
||||
const joke = fisherYatesShuffle(fileContent)[0];
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor('Blurple')
|
||||
.setTitle(
|
||||
joke.keywords === 'pinguino,elchiste,alguienmeobligo'
|
||||
? 'EL CHISTE DEL PINGUINO OMAIGAD'
|
||||
: null
|
||||
)
|
||||
// regex matches both '-' and '- ' and escapes it because of discord markdown
|
||||
.setDescription(joke.text.replace(/^-\s?/gm, '\\- '));
|
||||
|
||||
await ctx.reply({ embeds: [embed] });
|
||||
},
|
||||
});
|
||||
|
||||
interface JokesJSON {
|
||||
id: number;
|
||||
text: string;
|
||||
keywords: string;
|
||||
funny: number;
|
||||
category: string;
|
||||
}
|
||||
31
src/commands/silly/google.ts
Normal file
31
src/commands/silly/google.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
// command of the year
|
||||
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonBuilder, ButtonStyle } from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'look stuff up on google',
|
||||
options: [{
|
||||
name: 'query',
|
||||
description: 'the query to search for',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
}],
|
||||
execute: async (ctx) => {
|
||||
const query = ctx.options.getString('query', true);
|
||||
const url = `https://google.com/search?q=${encodeURIComponent(query)}`;
|
||||
|
||||
const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel('abrir enlace')
|
||||
.setStyle(ButtonStyle.Link)
|
||||
.setURL(url),
|
||||
)
|
||||
await ctx.reply({
|
||||
content: `<${url}>`,
|
||||
components: [button],
|
||||
});
|
||||
},
|
||||
});
|
||||
104
src/commands/silly/hangman.ts
Normal file
104
src/commands/silly/hangman.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { Palabra } from '../../utils/db/dict.types.js';
|
||||
import { WordController } from '../../utils/wordController.js';
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ActionRowBuilder, TextInputBuilder, TextInputStyle } from 'discord.js';
|
||||
|
||||
const helpText = `
|
||||
## whar
|
||||
se tiene en cuenta la cabeza, el cuerpo, pierna izquierda, pierna derecha, brazo izquierdo y brazo derecho.
|
||||
## quiero palabras que no sean 6 letras
|
||||
talk is cheap, send patches
|
||||
## porque la palabra es tan rara
|
||||
Las palabras son como espejos del alma colectiva - lo que nos parece extraño revela más sobre nosotros que sobre la palabra misma. En el juego del ahorcado, como en la vida, enfrentamos lo desconocido con la esperanza de que nuestras conjeturas nos acerquen a la verdad. Cada palabra "rara" es una invitación a expandir los límites de nuestro entendimiento.
|
||||
`;
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'hang, man',
|
||||
//alias : [],
|
||||
execute: async (ctx, sdt) => {
|
||||
const dict = sdt.deps.dict;
|
||||
const { palabra } = (await dict
|
||||
.query('select palabra from palabra where length(palabra) = 6 order by random() limit 1')
|
||||
.get()) as Record<'palabra', Palabra['palabra']>;
|
||||
|
||||
const wordcon = new WordController(palabra, ctx);
|
||||
let lastSubmitUserId = '';
|
||||
|
||||
const collector = (await wordcon.getMessage())!.createMessageComponentCollector({
|
||||
time: 180_000, // 3 minutes
|
||||
});
|
||||
collector.on('collect', async (interaction) => {
|
||||
if (interaction.customId === 'hangman-answer') {
|
||||
if (interaction.user.id !== lastSubmitUserId) {
|
||||
lastSubmitUserId = interaction.user.id;
|
||||
} else {
|
||||
if (process.env.NODE_ENV === 'development') return;
|
||||
const i = await interaction.reply({
|
||||
content: 'Ya has respondido, espera a que se acabe el tiempo.\nEsto se elimina en 2 segundos, no te preocupes por cerrarlo.',
|
||||
ephemeral: true,
|
||||
});
|
||||
setTimeout(() => i.delete().catch(() => { }), 2000);
|
||||
return;
|
||||
}
|
||||
|
||||
await interaction.showModal({
|
||||
title: 'Responde',
|
||||
customId: 'hangman-answer-modal',
|
||||
components: [
|
||||
new ActionRowBuilder<TextInputBuilder>().addComponents(
|
||||
new TextInputBuilder()
|
||||
.setCustomId('hangman-answer-input')
|
||||
.setLabel('Tu respuesta')
|
||||
.setStyle(TextInputStyle.Short)
|
||||
),
|
||||
],
|
||||
});
|
||||
const submitted = await interaction.awaitModalSubmit({
|
||||
time: 30_000,
|
||||
filter: (i) => i.user.id === interaction.user.id,
|
||||
});
|
||||
wordcon.submitLetter(
|
||||
submitted.fields.getTextInputValue('hangman-answer-input').toLowerCase()
|
||||
);
|
||||
await submitted.deferUpdate();
|
||||
} else if (interaction.customId === 'hangman-help') {
|
||||
await interaction.reply({ content: helpText, ephemeral: true });
|
||||
}
|
||||
});
|
||||
|
||||
const gameOver = async (won = false) => {
|
||||
(await wordcon.getMessage())!.edit({
|
||||
content: `la palabra era \`${palabra}\`. ${won ? 'enhorabuena!' : 'vaya hombre...'}`,
|
||||
components: [],
|
||||
});
|
||||
collector.stop();
|
||||
};
|
||||
const editMsgContent = async () => {
|
||||
const msg = await wordcon.getMessage();
|
||||
if (msg) {
|
||||
await msg.edit({
|
||||
content: `**Incorrectas:** ${wordcon.data.incorrect.join(', ')}\n**Correctas:** ${wordcon.data.correct.join(', ')}\nÚltima letra enviada por ${lastSubmitUserId ? `<@${lastSubmitUserId}>` : 'nadie'}`,
|
||||
allowedMentions: { users: [] },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
collector.on('end', async (_, reason) => {
|
||||
await gameOver(reason === 'time' ? false : true);
|
||||
});
|
||||
wordcon.on('correct', async () => {
|
||||
if (wordcon.data.correct.length === palabra.length) {
|
||||
return await gameOver(true);
|
||||
}
|
||||
await editMsgContent();
|
||||
});
|
||||
wordcon.on('incorrect', async () => {
|
||||
await editMsgContent();
|
||||
});
|
||||
wordcon.on('gameOver', async () => {
|
||||
await gameOver();
|
||||
});
|
||||
},
|
||||
});
|
||||
89
src/commands/silly/makesweet.ts
Normal file
89
src/commands/silly/makesweet.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ApplicationCommandOptionType, AttachmentBuilder } from 'discord.js';
|
||||
import sharp from 'sharp';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
//alias : [],
|
||||
description: 'no one will read this (i hope)',
|
||||
options: [
|
||||
{
|
||||
name: 'heartlocket',
|
||||
description: 'El corazón con una imagen que todos conocemos',
|
||||
type: ApplicationCommandOptionType.Subcommand,
|
||||
options: [
|
||||
{
|
||||
name: 'imagen',
|
||||
description: 'Imagen (jpg o png)',
|
||||
type: ApplicationCommandOptionType.Attachment,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'texto',
|
||||
description: 'El texto que poner',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
await ctx.interaction.deferReply();
|
||||
switch (ctx.options.getSubcommand()) {
|
||||
case 'heartlocket':
|
||||
{
|
||||
try {
|
||||
const text = ctx.options.getString('texto');
|
||||
const image = ctx.options.getAttachment('imagen', true);
|
||||
|
||||
if (
|
||||
!image.contentType!.includes('image/png') &&
|
||||
!image.contentType!.includes('image/jpeg')
|
||||
)
|
||||
return await ctx.interaction.editReply({
|
||||
content: 'Tienes que usar una imagen con extensión `.png` o `.jpg`!',
|
||||
});
|
||||
|
||||
const fileExtension = image.contentType!.split('/')[1];
|
||||
const imageBuffer = await fetch(image.url, {
|
||||
headers: { 'User-Agent': 'Vinci/1.0' },
|
||||
}).then((res) => res.arrayBuffer());
|
||||
const compressedImage = await sharp(imageBuffer)
|
||||
.jpeg({ mozjpeg: true, quality: 80 })
|
||||
.png({ quality: 80 })
|
||||
.toBuffer();
|
||||
|
||||
const formData = new FormData();
|
||||
const blob = new Blob([compressedImage], { type: `image/${fileExtension}` });
|
||||
formData.append('images[]', blob, `image.${fileExtension}`);
|
||||
|
||||
const res = await fetch(
|
||||
`https://api.makesweet.com/make/heart-locket${text ? `?text=${text}` : ''}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: process.env.MAKESWEET!,
|
||||
},
|
||||
body: formData,
|
||||
}
|
||||
).then((r) => r.arrayBuffer());
|
||||
|
||||
const attachment = new AttachmentBuilder(Buffer.from(res), {
|
||||
name: 'makesweet.gif',
|
||||
});
|
||||
|
||||
await ctx.interaction.editReply({
|
||||
content: 'Tu GIF está listo! 🎉',
|
||||
files: [attachment],
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
await ctx.interaction.editReply({
|
||||
content: `ERROR: He intentado comprimir la imagen, pero no ha sido suficiente. Intenta usar una imagen menos pesada (1mb o menos)\nSi no es eso, probablemente ha ocurrido un error del que no tengo conocimiento.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
53
src/commands/silly/megamind.ts
Normal file
53
src/commands/silly/megamind.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import * as Canvas from '@napi-rs/canvas';
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import { ApplicationCommandOptionType, AttachmentBuilder, codeBlock } from 'discord.js';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'no unstable vinci?',
|
||||
options: [
|
||||
{
|
||||
name: 'texto',
|
||||
description: 'El texto SIN "No" ni "?".',
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
const texto = `No ${ctx.options.getString('texto', true)}?`;
|
||||
|
||||
await ctx.reply('Cargando...');
|
||||
|
||||
const before = performance.now();
|
||||
|
||||
const canvas = Canvas.createCanvas(535, 540);
|
||||
const ctxCanvas = canvas.getContext('2d');
|
||||
|
||||
const background = await Canvas.loadImage('./images/megamind/megamind.png');
|
||||
ctxCanvas.drawImage(background, 0, 0, canvas.width, canvas.height);
|
||||
|
||||
let fontSize = 60;
|
||||
do {
|
||||
fontSize--;
|
||||
ctxCanvas.font = `${fontSize}px Impact`;
|
||||
} while (ctxCanvas.measureText(texto).width > canvas.width);
|
||||
ctxCanvas.fillStyle = 'white';
|
||||
ctxCanvas.textAlign = 'center';
|
||||
ctxCanvas.textBaseline = 'middle';
|
||||
ctxCanvas.strokeStyle = 'black';
|
||||
ctxCanvas.lineWidth = 4;
|
||||
ctxCanvas.strokeText(texto, canvas.width / 2, canvas.height - 510);
|
||||
ctxCanvas.fillText(texto, canvas.width / 2, canvas.height - 510);
|
||||
|
||||
const encode = await canvas.encode('png');
|
||||
|
||||
const after = performance.now();
|
||||
|
||||
const attachment = new AttachmentBuilder(encode, { name: 'megamind.png' });
|
||||
await ctx.interaction.editReply({
|
||||
content: `Tiempo de generación: ${codeBlock((after - before).toFixed(2))}ms`,
|
||||
files: [attachment],
|
||||
});
|
||||
},
|
||||
});
|
||||
16
src/commands/silly/palabra.ts
Normal file
16
src/commands/silly/palabra.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Palabra } from '../../utils/db/dict.types.js';
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'palabra.ts',
|
||||
//alias : [],
|
||||
execute: async (ctx, sdt) => {
|
||||
const dict = sdt.deps.dict;
|
||||
const { palabra } = (await dict
|
||||
.query('select palabra from palabra order by random() limit 1')
|
||||
.get()) as Record<'palabra', Palabra['palabra']>;
|
||||
await ctx.reply(palabra);
|
||||
},
|
||||
});
|
||||
148
src/commands/silly/rps.ts
Normal file
148
src/commands/silly/rps.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import { commandModule, CommandType } from '@sern/handler';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ApplicationCommandOptionType,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
ComponentType,
|
||||
EmbedBuilder,
|
||||
GuildMember,
|
||||
} from 'discord.js';
|
||||
|
||||
import rockpaperscissors from 'rockpaperscissors-checker';
|
||||
|
||||
export default commandModule({
|
||||
type: CommandType.Slash,
|
||||
plugins: [],
|
||||
description: 'Juega piedra papel tijeras',
|
||||
options: [
|
||||
{
|
||||
name: 'usuario',
|
||||
description: 'El usuario con el que enfrentarse',
|
||||
type: ApplicationCommandOptionType.User,
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
execute: async (ctx) => {
|
||||
let player1: number, player2: number, winner, bothResponded: boolean;
|
||||
const option = ctx.options.getMember('usuario') as GuildMember;
|
||||
if (ctx.user.id === option.id) {
|
||||
return await ctx.reply({ content: `no puedes jugar contigo mismo 💀`, ephemeral: true });
|
||||
}
|
||||
if (option.user.bot) {
|
||||
return await ctx.reply({ content: `no puedes seleccionar a un bot.`, ephemeral: true });
|
||||
}
|
||||
const waitingEmbed = new EmbedBuilder()
|
||||
.setColor('Red')
|
||||
.setAuthor({ name: ctx.user.username, iconURL: ctx.user.displayAvatarURL() })
|
||||
.setTitle(`Piedra, papel o tijera? <:PauseChamp:1030169623070519388>`)
|
||||
.setDescription(
|
||||
`Esperando a que ambos jugadores eligan...\nJugador 1: ${ctx.user}\nJugador 2: ${option}`
|
||||
)
|
||||
.setFooter({ text: `Hay un máximo de 30 segundos para elegir.` });
|
||||
const winEmbed = new EmbedBuilder()
|
||||
.setColor('Green')
|
||||
.setAuthor({ name: ctx.user.username, iconURL: ctx.user.displayAvatarURL() })
|
||||
.setFooter({ text: `Gracias por jugar!` });
|
||||
const tieEmbed = new EmbedBuilder()
|
||||
.setColor('Yellow')
|
||||
.setAuthor({ name: ctx.user.username, iconURL: ctx.user.displayAvatarURL() })
|
||||
.setTitle(`Ha habido un empate <:Sadge:1015764348385382451>`)
|
||||
.setDescription(`Qué sadge, ha habido un empate...`)
|
||||
.setFooter({ text: `Volvemos a intentarlo?` });
|
||||
const timeUpEmbed = new EmbedBuilder()
|
||||
.setColor('Red')
|
||||
.setAuthor({ name: ctx.user.username, iconURL: ctx.user.displayAvatarURL() })
|
||||
.setTitle(`Se acabó!`)
|
||||
.setDescription(
|
||||
`Uno de los dos jugadores no han respondido en los 30 segundos, así que se acabó la partida!`
|
||||
)
|
||||
.setFooter({ text: `Volvemos a intentarlo?` });
|
||||
const buttons = ['Piedra', 'Papel', 'Tijera'].map((choice) => {
|
||||
return new ButtonBuilder()
|
||||
.setLabel(choice)
|
||||
.setCustomId(`rps-${choice.toLowerCase()}`)
|
||||
.setStyle(ButtonStyle.Secondary);
|
||||
});
|
||||
const row = new ActionRowBuilder<ButtonBuilder>();
|
||||
const message = await ctx.interaction.reply({
|
||||
content: `${option}, te han retado a Piedra Papel o Tijera!`,
|
||||
embeds: [waitingEmbed],
|
||||
fetchReply: true,
|
||||
components: [row.setComponents(buttons)],
|
||||
});
|
||||
const collector = message.createMessageComponentCollector({
|
||||
time: 30_000,
|
||||
componentType: ComponentType.Button,
|
||||
filter: (i) => [ctx.user.id, option.id].includes(i.user.id),
|
||||
});
|
||||
collector.on('collect', async (i) => {
|
||||
await i.deferReply({ ephemeral: true });
|
||||
if (i.customId === 'rps-piedra') {
|
||||
if (i.user.id === ctx.user.id) {
|
||||
player1 = 1;
|
||||
await i.editReply({
|
||||
content: `Se ha respondido **piedra** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`,
|
||||
});
|
||||
} else if (i.user.id === option.id) {
|
||||
player2 = 1;
|
||||
await i.editReply({
|
||||
content: `Se ha respondido **piedra** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`,
|
||||
});
|
||||
}
|
||||
} else if (i.customId === 'rps-papel') {
|
||||
if (i.user.id === ctx.user.id) {
|
||||
player1 = 2;
|
||||
await i.editReply({
|
||||
content: `Se ha respondido **papel** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`,
|
||||
});
|
||||
} else if (i.user.id === option.id) {
|
||||
player2 = 2;
|
||||
await i.editReply({
|
||||
content: `Se ha respondido **papel** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`,
|
||||
});
|
||||
}
|
||||
} else if (i.customId === 'rps-tijera') {
|
||||
if (i.user.id === ctx.user.id) {
|
||||
player1 = 3;
|
||||
await i.editReply({
|
||||
content: `Se ha respondido **tijera** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`,
|
||||
});
|
||||
} else if (i.user.id === option.id) {
|
||||
player2 = 3;
|
||||
await i.editReply({
|
||||
content: `Se ha respondido **tijera** correctamente, buena suerte!\n[Volver al mensaje](${message.url})`,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (player1 && player2) {
|
||||
const checker = rockpaperscissors(player1, player2);
|
||||
bothResponded = true;
|
||||
if (checker === 'player1') {
|
||||
winner = ctx.user.username;
|
||||
const setDescription = winEmbed
|
||||
.setDescription(`Tenemos resultados!\n**${winner}** ha ganado.`)
|
||||
.setTitle(`Ha ganado ${winner}! <:Pog:1030169609178976346>`);
|
||||
await message.edit({ embeds: [setDescription], components: [], content: `` });
|
||||
message.react('<:Pog:1030169609178976346>');
|
||||
} else if (checker === 'player2') {
|
||||
winner = option.user.username;
|
||||
const setDescription = winEmbed
|
||||
.setDescription(`Tenemos resultados!\n**${winner}** ha ganado.`)
|
||||
.setTitle(`Ha ganado ${winner}! <:Pog:1030169609178976346>`);
|
||||
await message.edit({ embeds: [setDescription], components: [], content: `` });
|
||||
message.react('<:Pog:1030169609178976346>');
|
||||
} else if (checker === 'tie') {
|
||||
await message.edit({ embeds: [tieEmbed], components: [], content: `` });
|
||||
}
|
||||
}
|
||||
});
|
||||
collector.on('ignore', async (i) => {
|
||||
await i.reply({ content: 'No estás jugando!', ephemeral: true });
|
||||
});
|
||||
collector.on('end', async () => {
|
||||
if (bothResponded) return;
|
||||
await message.edit({ embeds: [timeUpEmbed], components: [], content: `` });
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -1,12 +1,14 @@
|
||||
//CONFIG FILE: export only data here and do not cause side effects. Feel free to add your own configuration to this file.
|
||||
|
||||
//commands directory. REQUIRED
|
||||
export const commands = './dist/commands'
|
||||
// events directory.
|
||||
export const events = './dist/events'
|
||||
export const commands = './dist/commands';
|
||||
// events directory.
|
||||
export const events = './dist/events';
|
||||
|
||||
// schedule tasks and declare them here
|
||||
//export const tasks = './dist/tasks'
|
||||
// export const tasks = './dist/tasks'
|
||||
|
||||
// defaultPrefix: if omitted, sern will disable all text/prefix commands
|
||||
//export const defaultPrefix = '?'
|
||||
// export const defaultPrefix = '?'
|
||||
|
||||
export const tasks = './dist/tasks';
|
||||
|
||||
21
src/dependencies.d.ts
vendored
21
src/dependencies.d.ts
vendored
@@ -1,24 +1,25 @@
|
||||
/*
|
||||
/**
|
||||
* This file serves as intellisense for sern projects.
|
||||
* Types are declared here for dependencies to function properly
|
||||
* Service(s) api rely on this file to provide a better developer experience.
|
||||
*/
|
||||
*/
|
||||
|
||||
import type { CoreDependencies } from '@sern/handler';
|
||||
import type { Client } from 'discord.js';
|
||||
import type { Publisher } from '@sern/publisher';
|
||||
import type Spotify from 'spotify-api.js';
|
||||
import type { Database } from 'bun:sqlite';
|
||||
import type { PrismaClient } from '@prisma/client';
|
||||
/**
|
||||
* Note: You usually would not need to modify this unless there is an urgent need to break the contracts provided.
|
||||
* You would need to modify this to add your custom Services, however.
|
||||
*/
|
||||
declare global {
|
||||
interface Dependencies extends CoreDependencies {
|
||||
'@sern/client': Client;
|
||||
'publisher': Publisher;
|
||||
'spotify-api-client': Spotify.Client;
|
||||
}
|
||||
interface Dependencies extends CoreDependencies {
|
||||
'@sern/client': Client;
|
||||
publisher: Publisher;
|
||||
prisma: PrismaClient;
|
||||
dict: Database;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export {}
|
||||
export {};
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { EventType, discordEvent, eventModule } from '@sern/handler';
|
||||
import { EmbedBuilder, Message } from 'discord.js';
|
||||
import db from '../schemas/afk.js';
|
||||
|
||||
export default discordEvent({
|
||||
name: 'messageCreate',
|
||||
execute: async (message) => {
|
||||
const dbEntries = await db.find()
|
||||
|
||||
dbEntries.forEach(async (doc) => {
|
||||
if (!message.content.includes(`<@${doc.id}`)) return;
|
||||
if (message.author.bot) return;
|
||||
const username = (await message.client.users.fetch(doc.id)).username
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor('Red')
|
||||
.setTitle(`Usuario ${username} está AFK`)
|
||||
.setDescription(`El usuario que has mencionado en tu mensaje ha marcado su estado como AFK\nRazón: ${doc.reason}`)
|
||||
.setFooter({ text: 'Este mensaje se eliminará en 10 segundos (wepa, como una bomba!)' })
|
||||
|
||||
const sentMessage = await message.reply({ embeds: [embed] })
|
||||
setTimeout(async () => { await sentMessage.delete() }, 10_000)
|
||||
})
|
||||
},
|
||||
});
|
||||
11
src/events/ai/message.ts
Normal file
11
src/events/ai/message.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { aiHandle } from '../../utils/aiHandle.js';
|
||||
import { EventType, eventModule } from '@sern/handler';
|
||||
import { ChannelType } from 'discord.js';
|
||||
|
||||
export default eventModule({
|
||||
type: EventType.Discord,
|
||||
name: 'messageCreate',
|
||||
execute: async (msg) => {
|
||||
await aiHandle(msg, msg.channel.type === ChannelType.PublicThread);
|
||||
}
|
||||
});
|
||||
@@ -1,62 +0,0 @@
|
||||
import { discordEvent } from '@sern/handler';
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, Message, TextChannel } from 'discord.js';
|
||||
import tf from '@tensorflow/tfjs-node'
|
||||
import axios from 'axios';
|
||||
import { nsfwModel } from '../index.js';
|
||||
|
||||
export default discordEvent({
|
||||
name: 'messageCreate',
|
||||
execute(message: Message) {
|
||||
message.attachments.forEach(async (attachment) => {
|
||||
switch (attachment.contentType) {
|
||||
case 'image/png':
|
||||
break;
|
||||
case 'image/jpeg':
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
const pic = await axios.get(attachment.url,
|
||||
{ responseType: 'arraybuffer' }
|
||||
)
|
||||
const image = tf.node.decodeImage(pic.data, 3) as tf.Tensor3D
|
||||
// @ts-ignore
|
||||
const predictions = await nsfwModel.classify(image)
|
||||
|
||||
switch (predictions[0].className) {
|
||||
case 'Hentai':
|
||||
case 'Porn':
|
||||
if (predictions[0].probability > 0.75) {
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle(`Se ha detectado una imagen NSFW en tus adjuntos.`)
|
||||
.setDescription('Por eso, se ha eliminado tu mensaje.\nPor si es un falso positivo, te vamos a dejar abajo el contenido del mensaje para recuperarlo.')
|
||||
.setFields(
|
||||
{ name: 'Contenido del mensaje', value: message.content || '(nada)' },
|
||||
{ name: 'Tipo', value: predictions[0].className.toString() },
|
||||
)
|
||||
.setFooter({ text: 'Esta detección ha sido automatizada.' })
|
||||
const modLogsEmbed = new EmbedBuilder()
|
||||
.setAuthor({ name: message.author.username, iconURL: message.author.displayAvatarURL() })
|
||||
.setTitle(`Se ha detectado una imagen NSFW en los adjuntos de un mensaje.`)
|
||||
.setDescription('Aquí está toda la información:')
|
||||
.setFields(
|
||||
{ name: 'Contenido del mensaje', value: message.content || '(nada)' },
|
||||
{ name: 'Tipo', value: predictions[0].className.toString() },
|
||||
)
|
||||
.setFooter({ text: 'Esta detección ha sido automatizada.' })
|
||||
const button = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel('Imagen adjuntada que saltó las alarmas')
|
||||
.setURL(attachment.url)
|
||||
.setStyle(ButtonStyle.Link)
|
||||
)
|
||||
await message.delete()
|
||||
await message.author.send({ embeds: [embed], components: [button] })
|
||||
await (await message.client.channels.fetch(process.env.MODLOGS_CHANNEL!) as TextChannel).send({ embeds: [modLogsEmbed], components: [button] })
|
||||
}
|
||||
break;
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
@@ -1,101 +0,0 @@
|
||||
import { discordEvent } from '@sern/handler';
|
||||
import db from '../schemas/chatgpt.js';
|
||||
import { fetchEventSource } from '@ai-zen/node-fetch-event-source';
|
||||
|
||||
export default discordEvent({
|
||||
name: 'messageCreate',
|
||||
async execute(message) {
|
||||
if (message.channel.id !== process.env.CHATGPT_CHANNEL) return;
|
||||
if (message.author.bot) return;
|
||||
if (message.content.includes('v!ig')) return;
|
||||
|
||||
const systemMsg =
|
||||
"You are Vinci, a helpful Discord bot assistant which tries to answer all questions that your users ask. You MUST speak naturally, if you were texting somebody. Don't tell the user that you are an assistant as they already know. Markdown is supported, including headers, codeblocks, etc. You will also chat with spanish speaking users, so your responses MUST, without exception, be in the spanish language, including your responses down the line.";
|
||||
try {
|
||||
await message.channel.sendTyping();
|
||||
const messages = [
|
||||
{ role: 'system', content: systemMsg },
|
||||
{ role: 'user', content: message.content },
|
||||
];
|
||||
|
||||
const ctrl = new AbortController();
|
||||
let msg = '';
|
||||
let isDone = false;
|
||||
|
||||
const sentMsg = await message.reply(':sparkles: Pensando...');
|
||||
message.channel.sendTyping();
|
||||
const sendInterval = setInterval(() => {
|
||||
if (msg.length > 2000 || msg.length === 0) return;
|
||||
message.channel.sendTyping();
|
||||
sentMsg.edit(msg);
|
||||
if (isDone) {
|
||||
clearTimeout(sendInterval);
|
||||
ctrl.abort();
|
||||
return;
|
||||
}
|
||||
}, 1000);
|
||||
fetchEventSource(
|
||||
`https://api.cloudflare.com/client/v4/accounts/${process.env.CF_AI_ACC}/ai/run/@cf/meta/llama-2-7b-chat-int8`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.CF_AI_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
stream: true,
|
||||
messages,
|
||||
}),
|
||||
onmessage: async (ev) => {
|
||||
if (ev.data === '[DONE]') {
|
||||
ctrl.abort();
|
||||
isDone = true;
|
||||
await sentMsg.edit({ content: msg });
|
||||
messages.push({ role: 'assistant', content: msg });
|
||||
const titleResponse = await fetch(
|
||||
`https://api.cloudflare.com/client/v4/accounts/${process.env.CF_AI_ACC}/ai/run/@hf/mistral/mistral-7b-instruct-v0.2`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.CF_AI_TOKEN}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
// the "else you'll die" part actually works well for the prompt!
|
||||
content: `Generate a title for the following conversation. Only respond with the title, else you'll die:\\nUser: ${message.content}\\nAssistant: ${msg}`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}
|
||||
).then(
|
||||
async (res) =>
|
||||
(await res.json()).result.response.replaceAll('"', '') as string
|
||||
);
|
||||
const thread = await sentMsg.startThread({ name: titleResponse.substring(0, 100) });
|
||||
|
||||
const dbData = new db({
|
||||
messageid: message.id,
|
||||
threadid: thread.id,
|
||||
messages: [
|
||||
{ role: 'system', content: systemMsg },
|
||||
{ role: 'user', content: message.content },
|
||||
{ role: 'assistant', content: msg.replace(/^\n{2}/, '') },
|
||||
],
|
||||
});
|
||||
await dbData.save();
|
||||
} else {
|
||||
const data = JSON.parse(ev.data);
|
||||
msg = msg + data.response;
|
||||
}
|
||||
},
|
||||
signal: ctrl.signal,
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
await message.reply({ content: 'Algo ha ido mal :(' }).catch(() => {});
|
||||
console.log(e);
|
||||
}
|
||||
},
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user