Skip to content
@SunnyCord

Sunny

GitHub organization for the Sunny Discord bot.

Hello, traveller! 👋

Welcome to Sunny's organization on GitHub.

Sunny is a microservices-based osu! Discord bot ecosystem with integrated web services. The services communicate via shared database, Redis cache/pub-sub, and RESTful APIs.

ℹ️ You may want to join our Discord server.

Service Architecture

flowchart TB
    subgraph External["External Clients"]
        discord(["Discord Users"])
        webbrowser(["Web Browser"])
    end

    subgraph Public["Public-Facing Services"]
        bot["bot<br/>(Python/discord.py)"]
        website["website<br/>(Vue.js) :3000"]
    end

    subgraph Internal["Internal Services"]
        api["api<br/>(Python/FastAPI) :3001"]
        lavalink["lavalink<br/>(Java/Lavalink) :2333"]
    end

    subgraph Data["Data Stores"]
        mongo[("MongoDB<br/>Primary Database")]
        redis[("Redis<br/>Cache & Pub/Sub")]
    end

    subgraph Init["Initialization"]
        mongoseed["mongo-seed<br/>(Setup Script)"]
    end

    subgraph ExternalAPIs["External APIs"]
        osuapi["osu! API v1/v2"]
        youtube["YouTube/Music Sources"]
        soundcloud["SoundCloud"]
        bandcamp["Bandcamp"]
    end

    %% Client connections
    discord --> bot
    webbrowser --> website

    %% Service-to-service HTTP
    bot -->|"audio streaming"| lavalink
    website -->|"command list"| api
    website -->|"bot stats"| api
    api -->|"OAuth callbacks"| website

    %% External APIs
    bot -->|"beatmaps & users"| osuapi
    lavalink --> youtube
    lavalink --> soundcloud
    lavalink --> bandcamp

    %% Data store connections
    bot --> mongo
    api -->|"saves OAuth tokens"| mongo
    bot -->|"writes stats/commands"| redis
    api -->|"reads stats/commands"| redis
    mongoseed -->|"initializes"| mongo

    %% Styling
    classDef client fill:#e1f5fe,stroke:#01579b,color:#01579b
    classDef public fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20
    classDef internal fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
    classDef data fill:#fce4ec,stroke:#c2185b,color:#880e4f
    classDef external fill:#eceff1,stroke:#546e7a,color:#37474f
    classDef init fill:#fff8e1,stroke:#f57f17,color:#f57f17

    class discord,webbrowser client
    class bot,website public
    class api,lavalink internal
    class mongo,redis data
    class osuapi,youtube,soundcloud,bandcamp external
    class mongoseed init
Loading

Services

Service Language Purpose
bot Python/discord.py Discord bot for moderation, osu!, and music
api Python/FastAPI Statistics API and OAuth2 handler for website
website Vue.js Public website for commands and stats
lavalink Java/Lavalink Audio streaming service for music playback
mongo MongoDB Primary database for persistent storage
redis Redis Cache for bot stats/commands
mongo-seed Node.js/Shell Database initialization and seeding

Communication Patterns

  • MongoDB: Primary database for persistent storage (user data, OAuth tokens)
  • Redis Cache: Bot writes stats/commands; API reads for website
  • HTTP REST: Website fetches data from API; API handles OAuth callbacks
  • Lavalink Protocol: WebSocket connection for audio streaming
  • osu! API: Direct integration using aiosu library (stateless client management)

Data Flow Architecture

Bot → Redis → API → Website:

  1. Bot updates command list and statistics in Redis
  2. API reads from Redis when website requests data
  3. Website displays information to users

osu! Data Flow:

  1. User requests osu! information via Discord
  2. Bot directly queries osu! API v1/v2 using aiosu
  3. Bot processes and displays data in Discord

OAuth Flow:

  1. User initiates osu! login from Discord bot
  2. Bot requests OAuth URL from API (with encrypted Discord user ID as state)
  3. User authenticates with osu! via browser
  4. osu! redirects to API callback endpoint with authorization code
  5. API decrypts state to get Discord user ID
  6. API exchanges code for token using aiosu's process_code
  7. API saves token directly to MongoDB with Discord ID mapping
  8. Bot retrieves tokens from MongoDB via aiosu for stateless API requests
  9. User sees success message in browser

Inter-Service HTTP Calls

Caller Target Purpose
bot lavalink Audio track loading and playback
website api Command list retrieval
website api Bot statistics display
osu! api OAuth2 callback redirect

Redis Cache Keys

Key Pattern Writer Reader TTL Purpose
sunny:guild-count bot api - Total number of guilds bot is in
sunny:cog-count bot api - Number of loaded cogs/extensions
sunny:command-count bot api - Total number of available commands
sunny:user-count bot api - Total number of users bot can see
sunny:{channel_id}:beatmap bot bot - Last referenced beatmap in Discord channel
sunny:{osu_id}:{mode_id}:graph bot bot 24h Cached user ranking graph (PNG bytes)

Key Features

Discord Bot Capabilities

osu! Integration (27 commands):

  • Direct osu! API v1/v2 integration (no intermediate service)
  • Beatmap information and difficulty calculation
  • Player statistics and rankings (all 4 modes: std, taiko, ctb, mania)
  • Recent score tracking and comparisons
  • Top plays display per gamemode
  • PP calculation and simulation (pp, whatif, ppforrank, bonus, recalcpp)
  • Replay recording and rendering with customizable skins
  • Recording settings (volume, dim, cursor size)
  • Ranking graph generation with Redis caching (24h)
  • Per-channel beatmap context for convenient commands

Music Playback (19 commands):

  • YouTube, SoundCloud, and Bandcamp support
  • Queue management and playback controls
  • Audio streaming via Lavalink
  • Premium audio effects (nightcore, vaporwave, lowpass, vibrato, tremolo)
  • Track recommendations (premium)
  • DJ role permissions
  • Auto-disconnect and autoplay features
  • Volume control and seeking
  • Loop modes and shuffle

Fun & Games (12 commands):

  • osudle guessing game (song and background modes)
  • Coin flips, dice rolls, magic 8ball
  • User duels and love calculator
  • Reaction polls

Moderation (2 commands):

  • Message pruning
  • Bot message cleanup

Image & Social (5 commands):

  • Avatar display
  • Animal images
  • Reaction GIFs (wink, pat, hug)

Server Management:

  • Custom prefix configuration
  • Premium server boosting
  • Message listener toggles
  • User data management (GDPR-compliant forgetme)

Utility:

  • Weather forecasts with unit customization
  • Bot and server information
  • Comprehensive help system

Authentication Flow

  1. User initiates OAuth2 flow via Discord bot command
  2. Bot uses a shared secret with the API and generates an osu! OAuth URL with an encrypted ID as the state
  3. Bot sends URL to user in Discord
  4. User clicks link and authenticates with osu! in browser
  5. osu! redirects to API callback endpoint with authorization code and encrypted state
  6. API decrypts state to retrieve Discord user ID (session_id)
  7. API uses aiosu's process_code() to exchange code for OAuth token
  8. API saves token to MongoDB using aiosu's add_client() with Discord ID mapping
  9. User sees success message in browser
  10. Bot retrieves tokens from MongoDB using aiosu for future API requests (stateless)

Beatmap Data Pipeline

  1. User requests beatmap information in Discord
  2. Bot directly queries osu! API v1/v2 using aiosu
  3. Bot processes beatmap data and calculates difficulty
  4. Bot stores beatmap data in Redis per-channel context
  5. Bot displays formatted information in Discord embed
  6. Future commands in same channel can reference "recent map"
  7. No API service involvement - direct bot ↔ osu! communication

Statistics Publishing

  1. Bot tracks command usage, guild count, cog count, and user count
  2. Bot writes statistics to Redis keys:
    • sunny:guild-count - Number of guilds
    • sunny:user-count - Number of users
    • sunny:cog-count - Number of loaded cogs
    • sunny:command-count - Number of commands
  3. Website requests data from API
  4. API reads current values from Redis
  5. API returns JSON to website
  6. Website displays real-time bot statistics

Beatmap Context Tracking

Discord channels maintain context of the last referenced beatmap:

  1. User mentions a beatmap in a Discord channel (via link, ID, or command)
  2. Bot stores beatmap data in Redis: sunny:{channel_id}:beatmap
  3. Users can reference "recent map" without specifying ID
  4. Bot retrieves last beatmap from channel context
  5. Enables convenient follow-up commands on same map

Graph Caching

User ranking graphs are cached to improve performance:

  1. User requests ranking graph (e.g., PP progression over time)
  2. Bot generates graph visualization (PNG)
  3. Bot caches graph in Redis: sunny:{osu_id}:{mode_id}:graph
  4. Cache expires after 24 hours (86400 seconds)
  5. Subsequent requests within 24h return cached graph
  6. Reduces computational load and API calls

osu! API Integration

Both bot and API use the aiosu library for osu! API interaction:

Bot Usage:

  • Retrieves OAuth tokens from MongoDB
  • Creates stateless API clients for authenticated requests
  • Fetches beatmap metadata, user statistics, recent scores
  • Caches results in Redis for performance

API Usage:

  • Handles OAuth2 callback from osu!
  • Exchanges authorization code for access token
  • Saves tokens to MongoDB with Discord ID mapping
  • Manages token lifecycle and refresh

Tech Stack

Category Technologies
Languages Python, TypeScript, Java
Web Frameworks FastAPI, Vue.js
Databases MongoDB, Redis
Discord Library discord.py
osu! Library aiosu (async osu! API wrapper)
Audio Streaming Lavalink
Container Docker, Docker Compose
CI/CD GitHub Actions, Webhook deployment
External APIs osu! API v1/v2, YouTube, SoundCloud, Bandcamp

Infrastructure

Deployment Architecture

Services are containerized and orchestrated via Docker Compose with two compose files:

Main Stack (docker-compose.yml):

Docker Host
├── bot (discord.py) - Main Discord bot
├── api (FastAPI) - REST API service :3001
├── website (Vue.js) - Frontend :3000
├── mongo (MongoDB) - Primary database
├── redis (Redis) - Cache and pub/sub
└── mongo-seed (initialization) - Database seeding

Audio Stack (docker-compose.lavalink.yml):

Docker Host
└── lavalink (Java/Lavalink) - Audio streaming :2333

Container Configuration

Main Stack Features:

  • Container registry: GitHub Container Registry (ghcr.io/sunnycord)
  • Images: bot, api, website (tagged with :master)
  • Health checks for MongoDB and Redis
  • Dependency management with wait conditions
  • Volume mounts for configs and data persistence
  • Network: sunny-network (bridge mode)

CI/CD Pipeline

Deployment Flow:

GitHub Repository → GitHub Actions → Webhook → Docker Host
  1. Manual workflow dispatch from GitHub Actions
  2. Restricted to repository owner (NiceAesth)
  3. Webhook POST to deployment server with secret authentication
  4. Server pulls latest :master images from GHCR
  5. Docker Compose performs rolling restart
  6. Services restart with dependency order

Deployment Trigger:

# Manual deployment via GitHub Actions
workflow_dispatch → webhook → redeploy.sh

Container Images

All images hosted on GitHub Container Registry:

  • ghcr.io/sunnycord/bot:master
  • ghcr.io/sunnycord/api:master
  • ghcr.io/sunnycord/website:master

Base images:

  • mongo:latest - Official MongoDB
  • redis:latest - Official Redis
  • ghcr.io/lavalink-devs/lavalink:latest - Official Lavalink

Code Style

Language Standards
Python Python 3.9+, type hints, Black formatter, isort
TypeScript ESLint, Prettier, Vue 3 Composition API
C# .NET 6+, async/await, standard C# conventions

Service Dependencies

The stack uses health checks and dependency conditions:

mongo-seed → requires mongo (healthy)
bot → requires mongo-seed (completed) + redis (healthy)
api → requires bot (started)
website → requires api (started)

Redeploying Services

Production Deployment: Trigger the GitHub Actions workflow to redeploy:

  1. Go to Actions tab in GitHub
  2. Select "Redeploy Sunny Stack"
  3. Click "Run workflow"
  4. Webhook triggers redeploy.sh

Features by Service

bot (Discord Bot)

Command Categories:

The bot organizes commands into 10 categories with 70+ total commands:

  1. Admin (2 commands) - Server management

    • /prune - Delete multiple messages
    • /clean - Clean bot messages
  2. Fun (8 commands) - Entertainment

    • /ping - Bot latency
    • /poll - Reaction polls
    • /roll - Random number
    • /flip - Coin flip
    • /8ball - Magic 8ball
    • /duel - User duel
    • /love - Love calculator
    • /rollduel - Roll duel
  3. Image (5 commands) - Images and reactions

    • /avatar - User avatars
    • /animal - Random animals
    • /wink, /pat, /hug - Reaction GIFs
  4. Information (3 commands) - Bot and server info

    • /botinfo - Bot statistics
    • /serverinfo - Server information
    • /help - Command help
  5. Music (19 commands) - Audio playback

    • /play - Play from YouTube/SoundCloud/Bandcamp
    • /playing - Current track
    • /queue - View queue
    • /search - Search tracks
    • /seek - Seek position
    • /pause, /resume, /skip, /stop - Playback control
    • /shuffle - Shuffle queue
    • /volume - Adjust volume
    • /loop - Set loop mode
    • /autoplay - Toggle autoplay
    • /autodisconnect - Auto-disconnect settings
    • /djrole - Set DJ role
    • /clearfilters - Remove filters
    • Premium effects: /nightcore, /vaporwave, /lowpass, /vibrato, /tremolo, /recommend
  6. osu! (27 commands) - osu! integration

    • /recent - Recent scores (with list and failed options)
    • /pinned - Pinned scores
    • /compare - Compare scores
    • /scores - Beatmap scores
    • /pp - PP calculation
    • /whatif - PP simulation
    • /ppforrank - PP for rank
    • /bonus - Bonus PP
    • /recalcpp - Recalculate PP
    • /record - Record replay
    • /osu, /mania, /taiko, /ctb - Mode stats (with extended option)
    • /osutop, /maniatop, /taikotop, /ctbtop - Top plays (with recent sort and position options)
    • Recording settings: /show, /skins, /toggle, /volume, /dim, /cursorsize
  7. osudle (4 commands) - Guessing game

    • /song - Guess by audio
    • /background - Guess by image
    • /skip - Skip beatmap
    • /stop - End game
  8. Premium (4 commands) - Premium features

    • /info - Premium info
    • /boost - Boost server
    • /unboost - Remove boost
    • /guildinfo - Server premium status
  9. Settings (3 commands) - Configuration

    • /forgetme - Delete user data (GDPR)
    • /prefix - Change prefix
    • /togglelisteners - Toggle listeners
  10. Weather (2 commands) - Weather info

    • /forecast - Get forecast
    • /units - Set units

Command Features:

  • Hybrid Commands: Most commands support both slash (/) and prefix modes
  • Premium Commands: Music effects and recommendations require premium
  • Context-Aware: osu! commands can reference "recent map" in channel

Data Handling:

  • Direct integration with osu! API v1/v2 using aiosu library
  • Retrieves OAuth tokens from MongoDB for authenticated requests
  • Writes statistics to Redis (guild/user/command/cog counts)
  • Stores user links and persistent data in MongoDB
  • Caches per-channel beatmap context in Redis
  • Caches generated ranking graphs in Redis (24h TTL)
  • Stateless API client management via aiosu

api (Backend Service)

Endpoints:

  • GET /api/stats - Bot statistics from Redis (guild/user/command/cog counts)
  • GET /api/commands - Command list with categories, parameters, and metadata
  • GET /api/auth/callback - OAuth2 callback handler (saves to MongoDB)

Command Data Structure: Each command includes:

  • Name and description
  • Parameters with descriptions
  • is_hybrid flag (slash + text command support)
  • is_premium flag (requires premium subscription)
  • Category/cog assignment

Purpose:

  • Serve bot statistics and command list to website
  • Handle osu! OAuth2 callbacks and token exchange
  • Save OAuth tokens directly to MongoDB using aiosu
  • Read-only access to Redis for statistics

Technology:

  • FastAPI for REST API
  • aiosu library for stateless osu! client management
  • Encrypted state parameter for Discord ID tracking
  • MongoDB for OAuth token persistence

Port: 3001

website (Frontend)

Pages:

  • Command list with search/filtering (10 categories, 70+ commands)
  • Bot statistics landing page
  • Bot versioning
  • Documentation (premium, team, tos, privacy policy)

Features:

  • Real-time stats updates from API
  • Command categorization by cog
  • Premium command badges
  • Hybrid command indicators

Port: 3000

lavalink (Audio Service)

Audio Sources:

  • YouTube (with search support)
  • SoundCloud (with search support)
  • Bandcamp
  • HTTP streams

Port: 2333

License

Copyright (c) 2023 NiceAesth, Sunny Bot Developers. Source available, all rights reserved.

See individual repository LICENSE files for complete terms.

Pinned Loading

  1. bot bot Public

    Discord.py bot for moderation, osu! and various other things.

    Python 33 10

Repositories

Showing 3 of 3 repositories

Top languages

Loading…

Most used topics

Loading…