Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
logs/
scores.json
scores.json
*.json
/__pycache__
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,40 @@ ive been spawncamped!
# i made a personal bot
made it for my friend group's discord server
its fun to play with.

# Make it your own
# First time setup
Clone the repo via whichever way you want. I recomment using git for this.

Creating a virtual requirement is recommended, especially for Raspberry PIs.
If you're planning to host this on another linux machine, you may skip this part.

Then you should
```
cd spawncamped (if not in the directory already)
python3 -m venv botenv
source botenv/bin/activate
```
Whenever you want to update the bot, remember to activate the bot's virtual enviroment by typing `source botenv/bin/activate`

Then go ahead and install all dependencies using `pip install -r requirements.txt`

Now you should create these 4 things: (if not already existing.)
- scores.json
- logs/discord.log
- logs/webpanel.log
- .env

Skipping these will make the bot **not** work properly.

In .env, add `DISCORD_TOKEN=""` and insert your bot's token there. Also make sure you add an `owner=""` variable and your discord user id as well.

That's it! You may run the bot via `update.sh`. Make sure to give the script appropiate permissions via chmod first.
Web panel is active at port `8000`. You can change the port at the bottom of `webpanel.py`.

## Updating bot

Always use `update.sh` to update. Make sure git is installed first!

## Important
Some code in this bot is specific to my (closed) discord server and will not work unless you do some editing.
Empty file added logs/discord.log
Empty file.
Empty file added logs/webpanel.log
Empty file.
157 changes: 110 additions & 47 deletions main.py

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ rich
discord.py>=2.0.0
python-dotenv
logging
discord
discord
fastapi>=0.110.0
uvicorn[standard]>=0.27.0
jinja2>=3.1.0
python-multipart>=0.0.9
31 changes: 30 additions & 1 deletion scores.json
Original file line number Diff line number Diff line change
@@ -1 +1,30 @@
{}
{
"429526435732914188": {
"total_score": 48137,
"daily_debt": 4,
"daily_score": 0,
"last_daily_claimed": "2026-01-02",
"bonus_multiplier": 1.5
},
"670703737265848399": {
"total_score": 1480,
"daily_debt": 0,
"daily_score": 0,
"last_daily_claimed": "2025-12-30",
"bonus_multiplier": 1
},
"963491431253676172": {
"total_score": 81,
"daily_debt": 0,
"daily_score": 0,
"last_daily_claimed": "2025-12-30",
"bonus_multiplier": 1
},
"550259849896656907": {
"total_score": 9141,
"daily_debt": 0,
"daily_score": 0,
"last_daily_claimed": "2025-12-31",
"bonus_multiplier": 1.5
}
}
31 changes: 17 additions & 14 deletions starter.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import uvicorn
import os
import logging
from datetime import datetime
import json
from rich import print as say
from fastapi import FastAPI
from fastapi import APIRouter
from fastapi import Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles

app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
import threading
import time
import subprocess

async def stopBot():
bot_thread

if __name__ == "__main__":
# webpanel_process = subprocess.Popen(["uvicorn", "webpanel:app", "--host", "0.0.0.0", "--port", "8000"])

bot_thread = threading.Thread(target=subprocess.run, args=(["python", "main.py"],))
webpanel_thread = threading.Thread(target=subprocess.run, args=(["python", "webpanel.py"],))

bot_thread.start()
webpanel_thread.start()

# This script starts both the bot and the web panel in separate threads.
3 changes: 0 additions & 3 deletions startup.sh

This file was deleted.

25 changes: 25 additions & 0 deletions static/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
async function refreshStatus() {
try {
const response = await fetch("/api/status");
const data = await response.json();

const statusEl = document.getElementById("bot-status");

if (data.online) {
statusEl.textContent = "ONLINE";
statusEl.className = "status-online";
} else {
statusEl.textContent = "OFFLINE";
statusEl.className = "status-offline";
}
} catch (err) {
console.error("Failed to fetch bot status", err);
}
}


// Refresh every 5 seconds
// setInterval(refreshStatus, 5000);

// Run once immediately on page load
//refreshStatus();
101 changes: 98 additions & 3 deletions static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,88 @@ body{
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #000000;
}

.online-badge {
p{
color: #ccc;
}

h1{
color:#ccc;
}

h2{
color: #ccc;
}

button {
margin: 10px;
padding: 14px 28px;
font-size: 18px;
border-radius: 10px;
border: none;
cursor: pointer;
transition: transform .2s;
}

button:hover {
transform: scale(1.05);
}

table {
margin: auto;
border-collapse: collapse;
}

th, td {
padding: 8px 12px;
border: 1px solid #444;
color:#ccc;
}

input {
width: 100px;
padding: 4px;
text-align: center;
color: #ccc;
}

.scores-form{
padding-top: 5px;
}

.submit-div{
margin: 20px auto;
padding-left: 50%;

}

.heading{
border: 2px solid #ffffff;
border-bottom: #ffffff;
border-style: none none solid none;
border-radius: 15px;
border-width: 5%;
text-align: center;
padding-top: 15px;
padding-bottom: 5px;
margin-left: 5%;
margin-right: 5%;
}

.panel{
color: #ccc;
width: 80%;
margin: 20px auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 8px;
background-color: #252323;
box-shadow: 4px 4px 8px 8px rgba(53, 53, 53, 0.2), 2px 6px 20px 2px rgba(78, 73, 73, 0.19);
}

.status-online {
display: inline-block;
background-color: #4CAF50; /* Green color */
color: white;
Expand All @@ -13,12 +92,28 @@ body{
font-size: 14px;
font-weight: bold;
}
.offline-badge {
.status-offline {
display: inline-block;
background-color: #f44336; /* Red color */
color: white;
padding: 5px 10px;
border-radius: 12px;
font-size: 14px;
font-weight: bold;
}
}

.msg{
color:#ccc;
}

.displayDiv{
overflow-wrap: break-word;
text-wrap: initial;
background-color: #252323;
border: #ccc solid 2px;
box-shadow: 4px 4px 8px 8px rgba(53, 53, 53, 0.2), 2px 6px 20px 2px rgba(78, 73, 73, 0.19);
width: 80%;
border-radius: 8px;
font: Consolas, 'Courier New', monospace;
}

26 changes: 22 additions & 4 deletions templates/index.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
<html>
<head>
<title>spawncamped control panel</title>
<link rel="stylesheet" type="text/css" href="/static/styles.css">
<link rel="stylesheet" href="/static/style.css">
<script src="/static/index.js" href="/static/index.js"></script>
</head>
<body>
<h1>Control Panel</h1>
<ul>
<li><a href="/logs/discord.log">Logs</a></li>
<div class="heading">
<h1>Control Panel</h1>
</div>

<div class="panel">

<h2>Bot Status: <strong><span id="bot-status" class="{{STATUS_CLASS}}">{{STATUS_TEXT}}</span></h2></strong>

<div class="btn-row">
<a href="/shutdown_bot"><button class="shutdown">Shutdown Bot</button></a>
<a href="/start_bot"><button class="start">Start Bot</button></a>
<a href="/logs"><button class="logs">View Bot Logs</button></a>
<a href="/panel_logs"><button class="panel_logs">View webpanel logs</button></a>
<a href="/scores"><button class="editscores">Edit scores.json</button></a>
</div>

<p class="msg" id="msg">{{MESSAGE}}</p>
<div class="displayDiv">{{LOGS}}</div>

</div>
</body>
</html>
33 changes: 33 additions & 0 deletions templates/scores.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<html>
<head>
<title>Edit Scores</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div class="heading">
<h1>Score Editor</h1>
</div>

</br>

<form class="scores-form" method="post" action="/scores/update">
<table>
<tr>
<th>User ID</th>
<th>Total Score</th>
<th>Daily Debt</th>
<th>Bonus Multiplier</th>
</tr>

{{ROWS}}
</table>

<br>
<div class="submit-div"><button class="submit-button" type="submit">Save Changes</button></div>
</form>

<br>
<a href="/"><button>← Back to Dashboard</button></a>

</body>
</html>
2 changes: 1 addition & 1 deletion update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ echo ""
echo "--------------------------------"
echo ""

nohup python3 main.py
nohup python3 starter.py
Loading