fixed queue skip error, implemented more /commands.

This commit is contained in:
2025-11-27 20:24:51 +00:00
parent a36977b000
commit 7f8f77fb76
4 changed files with 420 additions and 26 deletions

353
web_dhasboard_plan.md Normal file
View File

@@ -0,0 +1,353 @@
# Astro Bot Web Dashboard Architecture
## Overview
A real-time web dashboard for controlling the Discord music bot from a browser. Users can manage queues, adjust settings, and control playback without Discord.
## Tech Stack
### Backend (Flask/FastAPI)
**Recommended: FastAPI** (modern, async, WebSocket support built-in)
```python
# Dependencies
fastapi==0.104.1
uvicorn[standard]==0.24.0
websockets==12.0
python-socketio==5.10.0 # For real-time updates
aioredis==2.0.1 # For session management
```
**Why FastAPI:**
- Native async support (works well with discord.py)
- Built-in WebSocket support
- Auto-generated API docs
- Fast performance
### Frontend
**Recommended: React + Tailwind CSS**
```
React 18
Tailwind CSS
Socket.IO client (for real-time)
Axios (for API calls)
```
**Alternative (simpler):** Vanilla JS + Tailwind if you want less complexity
---
## Architecture Diagram
```
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Browser │◄───────►│ FastAPI │◄───────►│ Discord Bot │
│ (React UI) │ HTTP/WS │ Backend │ IPC │ (Python) │
└─────────────┘ └──────────────┘ └─────────────┘
┌──────────────┐
│ Database │
│ (SQLite) │
└──────────────┘
```
---
## Communication Flow
### 1. Bot → Web (Status Updates)
Discord bot sends real-time updates to web backend via:
- **Shared Database** (simplest) - Bot writes to DB, web reads
- **Redis Pub/Sub** (better) - Bot publishes events, web subscribes
- **WebSocket/Socket.IO** (best) - Direct real-time connection
### 2. Web → Bot (Commands)
Web backend sends commands to bot via:
- **Database flags** (simplest) - Web writes commands, bot polls
- **Redis Queue** (better) - Web publishes, bot consumes
- **Direct IPC** (best) - Web calls bot functions directly
---
## Detailed Implementation
### Phase 1: Database-Based (Easiest Start)
**How it works:**
1. Bot writes current state to database
2. Web reads database and displays
3. Web writes commands to "commands" table
4. Bot polls table every second
**Pros:**
- Simple to implement
- No new dependencies
- Works immediately
**Cons:**
- Not truly real-time (polling delay)
- Database writes on every update
### Phase 2: Redis-Based (Production Ready)
**How it works:**
1. Bot publishes events to Redis: `PUBLISH bot:status {"song": "...", "queue": [...]}`
2. Web subscribes to Redis channel
3. Web publishes commands: `PUBLISH bot:commands {"action": "skip"}`
4. Bot subscribes and executes
**Pros:**
- True real-time
- Fast and efficient
- Decoupled architecture
**Cons:**
- Requires Redis server
- More complex setup
---
## API Endpoints
### GET Endpoints (Read)
```
GET /api/servers # List all servers bot is in
GET /api/servers/{id}/queue # Get current queue
GET /api/servers/{id}/status # Get playback status
GET /api/servers/{id}/settings # Get volume/loop/effect
```
### POST Endpoints (Write)
```
POST /api/servers/{id}/play # Add song to queue
POST /api/servers/{id}/skip # Skip current song
POST /api/servers/{id}/volume # Set volume
POST /api/servers/{id}/loop # Set loop mode
POST /api/servers/{id}/effect # Set audio effect
POST /api/servers/{id}/shuffle # Shuffle queue
POST /api/servers/{id}/clear # Clear queue
```
### WebSocket Events
```
ws://localhost:8000/ws/{server_id}
# Bot → Web
{"event": "song_changed", "data": {...}}
{"event": "queue_updated", "data": [...]}
{"event": "volume_changed", "data": 150}
# Web → Bot
{"action": "skip"}
{"action": "volume", "value": 120}
```
---
## Example Code Structure
### Backend (FastAPI)
```python
# main.py
from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
import asyncio
import sqlite3
app = FastAPI()
# Allow frontend to connect
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# WebSocket connection for real-time updates
@app.websocket("/ws/{server_id}")
async def websocket_endpoint(websocket: WebSocket, server_id: str):
await websocket.accept()
# Send updates every second
while True:
# Read from database
queue_data = get_queue_from_db(server_id)
await websocket.send_json(queue_data)
await asyncio.sleep(1)
# API endpoint to skip song
@app.post("/api/servers/{server_id}/skip")
async def skip_song(server_id: str):
# Write command to database
conn = sqlite3.connect("./data/music.db")
cursor = conn.cursor()
cursor.execute("INSERT INTO commands (server_id, action) VALUES (?, ?)",
(server_id, "skip"))
conn.commit()
conn.close()
return {"status": "ok"}
```
### Bot Integration
```python
# In your bot code, add command polling
@tasks.loop(seconds=1)
async def process_web_commands():
"""Check for commands from web dashboard"""
conn = sqlite3.connect("./data/music.db")
cursor = conn.cursor()
cursor.execute("SELECT * FROM commands WHERE processed = 0")
commands = cursor.fetchall()
for cmd in commands:
server_id, action, data = cmd[1], cmd[2], cmd[3]
# Execute command
if action == "skip":
guild = bot.get_guild(int(server_id))
if guild and guild.voice_client:
guild.voice_client.stop()
# Mark as processed
cursor.execute("UPDATE commands SET processed = 1 WHERE id = ?", (cmd[0],))
conn.commit()
conn.close()
```
### Frontend (React)
```javascript
// Dashboard.jsx
import { useEffect, useState } from 'react';
function Dashboard({ serverId }) {
const [queue, setQueue] = useState([]);
const [ws, setWs] = useState(null);
useEffect(() => {
// Connect to WebSocket
const websocket = new WebSocket(`ws://localhost:8000/ws/${serverId}`);
websocket.onmessage = (event) => {
const data = JSON.parse(event.data);
setQueue(data.queue);
};
setWs(websocket);
return () => websocket.close();
}, [serverId]);
const skipSong = async () => {
await fetch(`http://localhost:8000/api/servers/${serverId}/skip`, {
method: 'POST',
});
};
return (
<div>
<h1>Now Playing: {queue[0]?.title}</h1>
<button onClick={skipSong}>Skip</button>
<ul>
{queue.map((song, i) => (
<li key={i}>{song.title}</li>
))}
</ul>
</div>
);
}
```
---
## Authentication (Important!)
**Problem:** Anyone with the URL can control your bot.
**Solutions:**
1. **Discord OAuth2** (Recommended)
- Users log in with Discord
- Check if user is in the server
- Only show servers they're members of
2. **API Keys**
- Generate unique key per server
- Server admins share key with trusted users
3. **IP Whitelist**
- Only allow specific IPs to access
---
## Deployment
### Development
```bash
# Backend
cd backend
uvicorn main:app --reload --port 8000
# Frontend
cd frontend
npm run dev
```
### Production
```bash
# Backend (systemd service)
uvicorn main:app --host 0.0.0.0 --port 8000
# Frontend (build static files)
npm run build
# Serve with nginx or deploy to Vercel/Netlify
```
---
## File Structure
```
astro-bot/
├── bot.py # Discord bot
├── cogs/
│ └── music/
│ ├── main.py
│ ├── queue.py
│ └── util.py
├── web/
│ ├── backend/
│ │ ├── main.py # FastAPI app
│ │ ├── routes/
│ │ │ ├── servers.py
│ │ │ └── playback.py
│ │ └── websockets.py
│ └── frontend/
│ ├── src/
│ │ ├── components/
│ │ │ ├── Queue.jsx
│ │ │ ├── Controls.jsx
│ │ │ └── NowPlaying.jsx
│ │ ├── App.jsx
│ │ └── main.jsx
│ └── package.json
└── data/
└── music.db
```
---
## Next Steps
1. **Start with database-based approach** - Get it working first
2. **Add WebSocket for real-time** - Once basic functionality works
3. **Build simple UI** - Focus on core features (play, queue, skip)
4. **Add authentication** - Discord OAuth2
5. **Polish and deploy** - Make it production-ready