Keking is a Discord bot built with discord.js and TypeScript. It focuses on music playback, text-to-speech, social-link preview helpers, and a small set of utility and admin commands.
- Music playback from YouTube links, Spotify links, and search queries
- Queue controls: play, skip, pause, resume, stop, shuffle, remove, clear, loop
- Lyrics lookup through Genius
- Text-to-speech playback in voice channels
- Social-link preview helpers for X/Twitter, Instagram, Facebook, and Reddit links
- NovelPia search via
/pia - Utility commands such as
/help,/ping, and/server - Admin health commands such as
/botstatsand/guildinfo - Optional PostgreSQL storage for guild-level operational data
- Docker-based local or production deployment
- Node.js 22+
- TypeScript
discord.jsdiscord-player@discordjs/voice- PostgreSQL (
pg) - Docker / Docker Compose
/help- list available commands/ping- show gateway latency/server- show basic server info
/play- play a track from a URL/search- search for a track and pick from buttons/queue- show the current queue/now- show the current track/pause- pause playback/resume- resume playback/skip- skip the current track/stop- stop playback and clear the queue/leave- disconnect from voice/shuffle- shuffle the queue/remove- remove a track from the queue/clear- clear queued tracks/loop- change repeat mode/lyrics- fetch lyrics for the current or requested song/tts- play text-to-speech in voice
/pia- search NovelPia titles
/botstats- show uptime, memory, ping, and voice dependency health/guildinfo- show guild and deployment info
When users post supported links in a guild text channel, Keking can reply with alternative preview-friendly versions.
Supported rewrites in the current codebase:
x.com/twitter.com->fixupx.cominstagram.com->kkinstagram.comfacebook.com/fb.watch->facebed.comreddit.com/redd.it->rxddit.com
This behavior depends on the bot being able to read guild message content.
The bot currently initializes with these intents:
GuildsGuildVoiceStatesGuildMessagesMessageContent
MessageContent is used for:
- social-link preview replies
- mention-based message replies
The current repo does not implement a Presence-based feature.
Create a .env file based on .env.example.
Required:
DISCORD_TOKENDISCORD_CLIENT_ID
Optional:
DISCORD_GUILD_ID- deploy commands to a single guild for faster iterationDATABASE_URL- enable PostgreSQL storagePOSTGRES_DB- used by the bundled Docker Compose databasePOSTGRES_USER- used by the bundled Docker Compose databasePOSTGRES_PASSWORD- used by the bundled Docker Compose databaseYOUTUBE_COOKIES- cookies string used by the YouTube extractor
Example:
DISCORD_TOKEN=your-bot-token
DISCORD_CLIENT_ID=your-application-client-id
DISCORD_GUILD_ID=optional-guild-id-for-faster-command-deploy
DATABASE_URL=postgresql://postgres:password@localhost:5432/keking
POSTGRES_DB=keking
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
YOUTUBE_COOKIES=youtube-cookies-stringInstall dependencies:
pnpm installRun in watch mode:
pnpm devBuild:
pnpm buildStart the compiled bot:
pnpm startDeploy commands:
pnpm deploy:commandsClear deployed commands:
pnpm deploy:clear-commandsIf DISCORD_GUILD_ID is set, command deployment can target a single guild for faster updates.
This repo includes:
- a multi-stage
Dockerfile - a
docker-compose.ymlstack for the bot and PostgreSQL - restart policies
- a Postgres healthcheck before the bot starts
Start the stack:
pnpm docker:upCheck logs:
pnpm docker:logsStop the stack:
pnpm docker:downIf DATABASE_URL is omitted in Docker Compose, it defaults to the bundled db service.
When DATABASE_URL is configured, the bot stores limited guild-level operational data:
- guild ID
- guild name
- command deployment hash
- join timestamp
- update timestamp
It does not intentionally store message-content history in the database as part of normal operation.
Static docs live in docs/, including:
- landing page:
docs/index.html - command reference:
docs/commands.html - privacy policy:
docs/privacy.html
This project is licensed under the ISC License.
- The bot syncs guild records and deploys commands when joining a guild.
- Voice playback depends on system/runtime voice dependencies being available.
- For managed Postgres providers, point
DATABASE_URLat the external database and ignore the localdbservice.