A modern Discord bot built with Deno 2 and Discordeno v21, featuring smart link previews, music playback, and fun interactions.
Landing page at https://meoww.weikuwu.me with EN and 繁體中文 support.
| Route | Language |
|---|---|
/en/ |
English |
/zh-TW/ |
繁體中文 |
Tech Stack: Astro + SSG
Commands:
cd website
yarn install
yarn dev # Development server
yarn build # Production build
yarn preview # Preview production buildEnvironment:
- Node.js >= 22.12.0
Preview links from popular platforms directly in Discord. Supported platforms:
| Platform | Support Type | Auto Preview |
|---|---|---|
| Twitter / X | Full | Yes |
| Threads | Full | Yes |
| Pornhub | Full | Yes |
| Pixiv | Full | Yes |
| WNACG | Full | Yes |
| nHentai | Full | Yes |
Lavalink-based music system with rich features:
- Queue Management: Add, remove, and organize your music queue
- Auto-Disconnect: Automatically leaves when the voice channel is empty
- Now Playing: Displays current track information with controls
- High Quality: Streams audio without quality loss
Express yourself with animated GIF interactions:
- Patpat Command: Use
/patpatas a slash command or right-click menu action - Animated GIFs: Custom GIF generation with avatar overlays
- Smooth Animations: Frame-based GIF creation for fluid motion
- NSFW Detection: Automatically detects and handles NSFW content appropriately
- Channel Validation: Ensures commands are used in appropriate channels
Built with modern development practices:
- Modular Commands: Clean, organized command structure
- Component V2 UI: Modern Discord interaction components
- Event-Driven: Responsive event handling system
- LogTape Logging: Structured, performant logging
- Deno 2.x — Install Deno
- Discord Bot Token — Create a Discord Application
- Lavalink Server (optional) — Required for music playback
Your bot requires the following intents:
| Intent | Purpose |
|---|---|
| Guilds | Access to server information |
| GuildMessages | Message events in servers |
| MessageContent | Read message content |
| GuildVoiceStates | Voice state updates for music |
git clone https://github.com/AiverAiva/meoww.git
cd meoww
cp .env.example .envEdit the .env file with your credentials:
DISCORD_TOKEN=your_discord_bot_token_here
LAVALINK_HOST=localhost:2333
LAVALINK_PASSWORD=your_lavalink_passwordDevelopment mode (with file watching):
deno task devProduction mode:
deno task startdocker build -t meoww-bot .docker run -d \
--name meoww \
-e DISCORD_TOKEN=your_token \
-e LAVALINK_HOST=lavalink-server \
-e LAVALINK_PASSWORD=your_password \
meoww-botCreate a docker-compose.yml file:
version: "3.8"
services:
meoww:
build: .
container_name: meoww
environment:
DISCORD_TOKEN: your_discord_bot_token_here
LAVALINK_HOST: lavalink:2333
LAVALINK_PASSWORD: your_lavalink_password
depends_on:
- lavalink
lavalink:
image: ghcr.io/lavalink-devs/lavalink:4
container_name: lavalink
environment:
SERVER_PORT: 2333
LAVALINK_ADMIN_PASSWORD: your_lavalink_password
volumes:
- lavalink_data:/home/lavalink
volumes:
lavalink_data:Start with:
docker-compose up -dmeoww/
├── assets/
│ └── patpat/
│ ├── bg.png # Patpat GIF background
│ ├── overlay.png # Avatar overlay mask
│ ├── cat.png # Cat ears overlay
│ ├── cat Overlay.png # Secondary cat overlay
│ ├── 1.png to 24.png # GIF animation frames
│ └── fonts/
│ └── impact.ttf # Font for text rendering
│
├── commands/ # Bot commands
│ ├── mod.ts # Command module exports
│ ├── registry.ts # Command registry and mapping
│ ├── ping.ts # Ping command (Component V2 example)
│ ├── patpat.ts # Patpat GIF generation command
│ ├── preview.ts # Link preview command
│ └── music.ts # Music playback commands
│
├── events/ # Event handlers
│ ├── mod.ts # Event module exports
│ ├── ready.ts # Bot ready event handler
│ ├── interactionCreate.ts # Slash/button/select menu handlers
│ └── messageCreate.ts # Message event handlers
│
├── interactions/ # Interaction definitions
│ ├── commands/ # Slash command definitions
│ ├── components/ # Button and select menu handlers
│ └── messages/ # Message component handlers
│
├── listeners/
│ └── message/ # Message-based listeners
│ └── autoResponders.ts # Auto-response handlers
│
├── utils/ # Utility modules
│ ├── previewers/ # Link preview fetchers
│ │ ├── mod.ts # Preview aggregator (getAnyPreview)
│ │ ├── twitter.ts # Twitter/X preview
│ │ ├── threads.ts # Threads preview
│ │ ├── pornhub.ts # Pornhub preview
│ │ ├── pixiv.ts # Pixiv preview
│ │ ├── wnacg.ts # WNACG preview
│ │ └── nhentai.ts # nHentai preview
│ │
│ ├── gif/ # GIF generation utilities
│ │ └── patpat_generator.ts # Patpat GIF builder
│ │
│ ├── logger.ts # LogTape logger configuration
│ ├── lavalink.ts # Lavalink manager setup
│ ├── components_v2.ts # Component V2 helpers
│ └── ui_factory.ts # UI element factory
│
├── main.ts # Bot entry point
├── deno.json # Deno configuration
├── Dockerfile # Docker build file
├── .env.example # Environment template
├── .gitignore # Git ignore rules
└── LICENSE # MIT License
| Variable | Required | Default | Description |
|---|---|---|---|
DISCORD_TOKEN |
Yes | — | Your Discord bot token |
LAVALINK_HOST |
No | localhost:2333 | Lavalink server (include port like localhost:2333) |
LAVALINK_PASSWORD |
No | youshallnotpass | Lavalink server password |
| Intent | Enabled | Reason |
|---|---|---|
| Guilds | Yes | Required for server access |
| GuildMessages | Yes | Message event handling |
| MessageContent | Yes | Link detection |
| GuildVoiceStates | Yes | Music playback |
| Command | Description |
|---|---|
/ping |
Basic ping command to verify bot is responsive |
/patpat [user] |
Send a patpat GIF to the specified user |
| Command | Description |
|---|---|
| Preview Link | Right-click any message with a link to preview it |
| Command | Description |
|---|---|
| patpat | Right-click a user to send them a patpat GIF |
Create a new command file in commands/:
// commands/mycommand.ts
import { type Command, createCommand } from "../deps.ts";
export const myCommand = createCommand({
meta: {
name: "mycommand",
description: "Description of my command",
},
contextMenu: {
type: "message" as const, // or "user"
// For slash commands, omit contextMenu
},
run(ctx) {
// Your command logic here
return ctx.respond({
content: "Hello from my command!",
});
},
});Register in commands/mod.ts:
import { myCommand } from "./mycommand.ts";
export const commands = [pingCommand, previewCommand, patpatCommand, myCommand];Create a new previewer in utils/previewers/:
// utils/previewers/myplatform.ts
import type { PreviewResult } from "./mod.ts";
const MYPLATFORM_REGEX = /myplatform\.com\/watch\?v=(\w+)/;
export async function fetchMyPlatform(url: string): Promise<PreviewResult | null> {
const match = url.match(MYPLATFORM_REGEX);
if (!match) return null;
// Fetch and parse the page
const response = await fetch(url);
const html = await response.text();
// Extract metadata
const title = extractTitle(html);
const thumbnail = extractThumbnail(html);
return {
title,
description: "My platform content",
thumbnail,
url,
};
}Register in utils/previewers/mod.ts:
import { fetchMyPlatform } from "./myplatform.ts";
export async function getAnyPreview(url: string): Promise<PreviewResult | null> {
// Chain through existing previewers
return (
await fetchTwitter(url) ||
await fetchPornhub(url) ||
await fetchPixiv(url) ||
await fetchWNACG(url) ||
await fetchNhentai(url) ||
await fetchMyPlatform(url) || // Add your new previewer here
null
);
}Create an event file in events/:
// events/myEvent.ts
import type { Bot, EventOptions } from "../deps.ts";
export const myEvent: EventOptions = {
name: "myEvent",
type: "once" as const, // or "every"
run(bot: Bot) {
// Your event logic
console.log("My event fired!");
},
};Register in events/mod.ts:
import { myEvent } from "./myEvent.ts";
export const events = [readyEvent, interactionCreateEvent, messageCreateEvent, myEvent];Contributions are welcome! Feel free to submit issues and pull requests.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Website: https://meoww.weikuwu.me
- Discord: Join Support Server
- GitHub: Open an Issue
This project is licensed under the MIT License.
View the full license: LICENSE
Created by AiverAiva💜
- Discordeno — Powerful Discord API wrapper for Deno
- LogTape — Structured logging for Deno applications
- lavalink-client — Lavalink integration for Discord bots
- jimp — Image processing in pure JavaScript
Made with ❤️ and Deno