Internals - Package-by-Package Walkthrough
This document provides a deep dive into every package in the Solstice codebase, explaining the internal APIs, design decisions, and how components interact.
Package Map
musicbot/
├── cmd/bot/ → Application entrypoint and bootstrap
├── internal/
│ ├── config/ → Environment variable loading
│ ├── database/ → MongoDB client and all collection helpers
│ ├── i18n/ → YAML-based internationalization
│ ├── queue/ → Thread-safe per-chat song queue
│ ├── telegram/ → Bot command handlers and VC management
│ └── youtube/ → Search, extraction, caching, and proxies
└── strings/langs/ → Language YAML filescmd/bot/main.go
The application entrypoint. Orchestrates the startup sequence:
- Load
.envviagodotenv - Call
config.LoadConfig()to populate the globalconfig.Config - Load i18n strings from
strings/langs/en.yml - Resolve
MONGO_URIfrom environment (tries 3 variable names) - Initialize MongoDB via
database.InitDB() - Load YouTube cookies (MongoDB → env var → disk)
- Load Pyrogram session string (env var)
- Create
VoiceChatManager(spawns Python daemon) - Create
BotHandler(registers all command routes) - Wire up
OnStreamEndcallback for auto-queue advancement - Start bot polling in a goroutine
- Block on
SIGINT/SIGTERMfor graceful shutdown
internal/config/
config.go
A singleton AppConfig struct populated from environment variables. Loaded once via LoadConfig() and accessed globally via config.Config.
Key design decisions:
- Uses raw
os.Getenv()rather than a config framework - keeps dependencies minimal - Space-separated lists (
START_IMG_URL,EMOJIS) are split viastrings.Fields() - Provides sensible defaults for all optional values
- Prints a warning (not fatal) when required tokens are missing - allows partial startup for testing
internal/database/
db.go
The centralized data access layer. Contains a global MongoDB client and exposes functions (not methods) for all collections.
Pattern: All database functions are package-level functions, not methods on a struct. This matches Go's convention for singleton services:
// Usage:
database.InitDB(uri)
database.IsSudoer(userID)
database.GetAutoplay(chatID)Connection management:
- Single
*mongo.Clientcreated at startup - All operations use the same client (connection pooling handled by the driver)
- No explicit connection closing - relies on process termination
See Database Schema for collection documentation.
internal/i18n/
strings.go
Minimal internationalization system using YAML files.
How it works:
LoadStrings(path)reads a YAML file and flattens it intomap[string]stringGetString(key, args...)retrieves a string and replaces{0},{1}, etc. with provided arguments
// strings/langs/en.yml:
// start_2: "👋 Hey {0}! I'm {1}"
i18n.GetString("start_2", "Stark", "Solstice")
// → "👋 Hey Stark! I'm Solstice"Design notes:
- Custom
{N}placeholder format instead of Go'sfmt.Sprintf- matches common i18n conventions - Graceful fallback: returns the key itself if not found
- Supports
string,int, and generic types viafmt.Sprintf("%v", v)
internal/queue/
queue.go
Thread-safe per-chat song queue. The QueueManager is the shared state between all command handlers and the stream-end callback.
Key struct:
type QueueManager struct {
mu sync.Mutex
queues map[int64][]Song // chatID → ordered song slice
}Concurrency guarantees:
- Every operation acquires the mutex before reading or writing
- The
Shuffle()method preserves index 0 (currently playing song) and only shuffles the rest Advance()atomically pops the first element and returns the new first elementGetActiveChats()returns a snapshot of chat IDs with non-empty queues
Song struct:
type Song struct {
Title string
Link string
Duration string
Thumbnail string
StreamURL string
RequesterID int64
RequesterName string
Video bool // true = video stream, false = audio only
}internal/telegram/
The largest package, containing all bot logic split across multiple files.
bot.go - Core Handler (~1230 lines)
Contains:
BotHandlerstruct definition (the central struct holdingBot,VC,Queue,voteSkips)NewBot()- constructor that creates the telebot instance and registers all routesregisterRoutes()- calls allInit*()methods to register handlershandlePlay()/handleVPlay()- the main play command logichandleForcePlay()/handleVForcePlay()- force-play variantshandlePause(),handleResume(),handleStop(),handleSkip()handleSeek(),handleSeekBack(),handleVolume(),handleSpeed()handleQueue()- paginated queue displayhandleLoop(),handleShuffle(),handleAutoplay()handleSuggest()- song suggestion with inline buttonshandleVoteSkip()- vote skip button callbackHandleStreamEnd()- auto-advance callback (called frommain.gowire-up)voteSkipStore- in-memory vote tracking
Play command flow (simplified):
func (h *BotHandler) handlePlay(c telebot.Context, isVideo, isForce bool) {
// 1. Auth check
// 2. Parse query from payload or reply
// 3. Send "Searching..." message
// 4. youtube.SearchVideo(query, 1)
// 5. youtube.GetStreamURL(result.ID, isVideo)
// 6. Create Song struct
// 7. h.Queue.Add(chatID, song)
// 8. If queue length == 1 (first song):
// h.VC.Play(chatID, streamURL, isVideo, title)
// 9. Send "Now Playing" card with inline keyboard
// 10. h.logPlay(chat, song)
}vc.go - Voice Chat Manager
See Voice Chat System for full documentation.
admins.go - Group Admin Commands (~858 lines)
All group moderation commands organized into modules:
- Ban module:
/ban,/unban,/tban,/dban - Mute module:
/mute,/tmute,/unmute - Purge module:
/purge,/spurge,/del - Pin module:
/pin,/unpin,/unpinall(with confirmation dialog) - Promote module:
/promote,/fullpromote,/demote,/setadmintitle - Kick module:
/kick,/unbanall
Helper functions:
getTargetUser()- resolves target from reply → text mention → @username → numeric IDextractReason()- extracts reason text from command payloadparseDuration()- parses human-friendly duration (5m,2h,3d)mention()- creates HTML mention link
sudo.go - Superuser Commands (~401 lines)
Owner/sudoer-only commands:
- Sudoer management:
/addsudo,/delsudo,/sudolist - Global ban:
/gban,/ungban(async enforcement across all served chats) - Broadcast:
/broadcast(iterates all chats/users with 100ms delay) - Active info:
/activevc,/activevideo,/ac - Cookie management:
/setcookies,/checkcookies - Bot control:
/reboot
utils.go - Permission & Logging (~342 lines)
Core utility functions used across all handlers:
Permission hierarchy:
func IsAdmin(c, chat, userID) bool {
// 1. Owner (config.Config.OwnerID)
// 2. Sudoer (database.IsSudoer)
// 3. Private chat (always admin)
// 4. Authorized user (database.IsAuthUser)
// 5. Telegram group admin/creator
}CheckAdminSassy() - The central permission middleware:
- Checks if the command is a "music command" (hardcoded list)
- For music commands, respects
admin_cmd_modesetting (everyonevsadmin) - Authorized users bypass admin check for music commands
- Returns sassy denial messages for unauthorized users
Logging functions:
logError()- Sends error details to logger channel (with thread ID support)logActivity()- Sends admin action logslogPlay()- Sends play event logs
Permission checks:
CheckBotCanRestrict()- Verifies bot has Restrict Members permissionCheckBotCanPin()- Verifies bot has Pin Messages permissionCheckBotCanDelete()- Verifies bot has Delete Messages permission
fun.go - Reaction Commands (~480 lines)
Interactive reaction system using nekos.best API:
- Interactive (Accept/Reject):
/hug,/kiss,/cuddle,/propose - One-way:
/slap,/kill,/crush - Mood:
/cry,/blush,/smile,/happy,/dance,/bully
Callback pattern: Each interactive command creates an inline keyboard with callback data encoding senderID_targetID. Only the target can accept/reject.
tools.go - Utility Commands (~660 lines)
Mixed utility and fun commands:
- Fun:
/truth,/dare,/couples,/wish,/cute - Utility:
/song,/lyrics(via LrcLib API),/tr(Google Translate) - System:
/reload,/lang,/afk - Couples image: Downloads profile photos, composites them with a background image, crops to circles using pure Go
imagepackage (no CGo)
AFK Middleware: AFKMiddleware() is a telebot middleware that checks every message:
- If sender was AFK → remove AFK, announce return
- If replying to AFK user → show AFK notice
- If mentioning AFK user → show AFK notice
whisper.go - Inline Whisper (~178 lines)
Secret message system using Telegram's inline mode:
- In-memory storage via
map[string]stringwithsync.RWMutex - Supports normal and one-time (self-destructing) whispers
- Unauthorized read attempts trigger notification to the sender
start.go - Start & Welcome (~153 lines)
/startin PM → photo + welcome text + navigation keyboard/startin group → group welcome cardOnAddedToGroup→ automatic welcome message/owner→ developer info card with links
help.go - Help Menu System (~227 lines)
Hierarchical help menu using inline keyboard navigation:
Help Menu
├── Admin
│ ├── Music Control
│ └── Group Management
├── Play
├── Sudo (restricted to sudoers)
│ ├── User Management
│ ├── Chat Management
│ └── Bot Control
└── Extra
├── Utility
└── FunEach section is rendered by editing the same message with new content and keyboard buttons.
internal/youtube/
See YouTube & Search Pipeline for full documentation.
strings/langs/
en.yml
YAML file containing all English language strings. Format:
key: "Message text with {0} placeholders for {1} arguments"Currently contains ~142 string entries covering:
- Start/welcome messages
- Help text for all command categories
- Admin action confirmations
- Error messages (all with "sassy" personality)
- UI button labels
- Settings descriptions
