CherryPinBot in action showing reaction-based meme curation
CherryPinBot
Discord community management bot that automates timezone coordination and content curation

What It Does


CherryPinBot active in Discord server The bot active in a Discord server, monitoring channels for reactions.

Why I Built This

A few friends and I ran a Discord community with members scattered across multiple US timezones. Coordination was a constant headache—before scheduling gaming sessions or meetings, someone always had to ask "What time is it for you?" We also generated tons of memes across various channels, but the best ones got lost in the chaos. Discord's 50-pin limit per channel meant we constantly ran out of space.

Traditional solutions like asking everyone to manually convert timezones or manually pinning messages were inconsistent and required active moderation. We needed something that worked passively in the background: always-visible timezone information and a way for members to collectively curate content without needing moderator permissions.


Simple ping command showing bot responsiveness Simple health check command to verify the bot is responsive.

How It Works

CherryPinBot is built on Node.js with Discord.js v12, using an event-driven architecture that monitors Discord WebSocket events. The timezone display feature cleverly uses Discord voice channels as persistent status boards—by programmatically updating voice channel names every 5 minutes, the bot creates always-visible time displays without relying on message pins or channel topics (which are less visible).

The reaction system uses a modular plugin pattern: each emoji reaction (🍒 for casual saves, ⭐ for exceptional content) is handled by a separate module that exports onReaction, filter, and channels properties. When someone reacts to a message, the bot fetches the message content (handling Discord's caching limitations), checks if the reaction matches a registered handler, and automatically reposts the content to the designated curation channel.

A critical technical decision involved rate limiting: Discord allows only 2 channel name changes per 10 minutes. I calculated a safe update interval of 5 minutes + 1 second to stay comfortably within limits while providing reasonably current time displays. This constraint also drove the decision to use HH:mm format instead of including seconds.


CherryPinBot profile in Discord The bot's Discord profile showing its online status.

Impact

By the numbers:

What changed:


Challenges & Solutions

The Discord API heavily rate-limits channel name changes (2 per 10 minutes), which initially broke the timezone display feature. I solved this by calculating safe update intervals and simplifying the time format to reduce update frequency needs. The 5-minute + 1-second interval keeps the bot comfortably within limits.

Another challenge was reaction events on uncached messages failing silently. Discord doesn't cache all message history, so reactions on older messages wouldn't trigger handlers. I implemented a defensive partial message fetching pattern that explicitly calls fetch() when reaction.partial === true, ensuring the bot handles old messages correctly.

The clock channel feature required extensive iteration—30+ commits in November 2021 alone—to get the asynchronous channel update logic working reliably. Debugging complex async patterns with Discord's API taught me the value of incremental commits and extensive console logging. The commit message "Dad is amazing The Bot works" captures the collaborative debugging moment when the reaction handler finally clicked.


What I Learned

Rate limits should drive architecture, not be an afterthought. Discord's 2 changes per 10 minutes limit forced strategic decisions about update frequency and data format. Understanding external API constraints early saves significant refactoring later.

Event-driven systems need defensive data fetching. The Discord API's caching policies taught me to never assume data is available—always implement fallback fetch logic at system boundaries.

Modular architecture scales learning. The plugin pattern for commands and reaction handlers made it easy to add features incrementally without understanding the entire codebase. This approach is valuable for projects where features are added over time or by multiple contributors.

Future improvements (if I revisited this):


Status Update (November 2022)

The platform I was using to host the bot (Heroku) discontinued their free tier services. The bot is now archived and sitting in the repository, waiting for the day I bring it back to life on a new hosting platform. This project served its purpose as both a practical community tool and a deep learning experience with event-driven architecture and API rate limiting.


Links