// ==UserScript==
// @name SillyDev Auto Renewal
// @namespace http://tampermonkey.net/
// @version 1.3
// @description Automatically renew servers on panel.sillydev.co.uk
// @author Your name
// @match https://panel.sillydev.co.uk/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const RENEWAL_COST = 175; // Cost per renewal
const DAYS_PER_RENEWAL = 7; // Days added per renewal
const MAX_RENEWAL_DAYS = 21; // Maximum renewal days allowed
const CHECK_INTERVAL = 30 * 60 * 1000; // Check every 30 minutes
// Helper function to get XSRF token from cookie
function getXsrfToken() {
const cookies = document.cookie.split(';');
for (const cookie of cookies) {
const [name, value] = cookie.trim().split('=');
if (name === 'XSRF-TOKEN') {
return decodeURIComponent(value);
}
}
return null;
}
// Helper function to make API requests
async function makeRequest(endpoint, method = 'GET', body = null) {
const xsrfToken = getXsrfToken();
if (!xsrfToken) {
console.error('XSRF token not found in cookies');
return null;
}
const options = {
method: method,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-XSRF-TOKEN': xsrfToken
},
credentials: 'include'
};
if (body) {
options.body = JSON.stringify(body);
}
try {
const response = await fetch(`https://panel.sillydev.co.uk${endpoint}`, options);
// Handle non-OK responses
if (!response.ok) {
const errorData = await response.json();
throw new Error(JSON.stringify(errorData));
}
// For successful responses, check if there's actual content
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
}
// If no JSON content but response is OK, return true to indicate success
return true;
} catch (error) {
console.error(`API request failed:`, error);
return null;
}
}
// Get user's current balance
async function getUserBalance() {
const userData = await makeRequest('/api/client/store');
return userData?.attributes?.balance || 0;
}
// Get list of all servers
async function getServers() {
const serversData = await makeRequest('/api/client?page=1');
return serversData?.data || [];
}
// Renew a specific server
async function renewServer(serverUuid) {
return await makeRequest(`/api/client/servers/${serverUuid}/renew`, 'POST');
}
// Calculate optimal renewals based on current balance and server states
function calculateOptimalRenewals(servers, balance) {
// Calculate how many renewals we can afford
const maxRenewals = Math.floor(balance / RENEWAL_COST);
if (maxRenewals === 0) return [];
// Sort servers by a combination of days remaining and potential waste
const sortedServers = servers.map(server => {
const daysRemaining = server.attributes.renewal;
// Calculate potential waste (days that would exceed MAX_RENEWAL_DAYS)
const potentialWaste = Math.max(0, (daysRemaining + DAYS_PER_RENEWAL) - MAX_RENEWAL_DAYS);
// Calculate urgency score (lower is more urgent)
const urgencyScore = (daysRemaining * 2) + (potentialWaste * 3);
return {
server: server,
daysRemaining: daysRemaining,
potentialWaste: potentialWaste,
urgencyScore: urgencyScore
};
}).sort((a, b) => a.urgencyScore - b.urgencyScore);
const renewalPlan = [];
let remainingBalance = balance;
// Consider each server for renewal
for (const serverInfo of sortedServers) {
// Stop if we can't afford more renewals
if (remainingBalance < RENEWAL_COST) break;
const daysRemaining = serverInfo.daysRemaining;
const newTotalDays = daysRemaining + DAYS_PER_RENEWAL;
// Only renew if:
// 1. The new total won't exceed MAX_RENEWAL_DAYS
// 2. Current days are less than 14 (to ensure we always have a buffer for renewal)
if (newTotalDays <= MAX_RENEWAL_DAYS && daysRemaining < 14) {
renewalPlan.push({
uuid: serverInfo.server.attributes.uuid,
currentDays: daysRemaining,
newTotal: newTotalDays,
needsRenewal: true
});
remainingBalance -= RENEWAL_COST;
}
}
return renewalPlan;
}
// Main function to check and renew servers
async function checkAndRenewServers() {
console.log('Checking server renewals...');
// Get current balance and servers
const balance = await getUserBalance();
const servers = await getServers();
if (!balance || !servers) {
console.log('Failed to fetch necessary data');
return;
}
console.log(`Current balance: ${balance}`);
console.log('Current servers:', servers.map(s => ({
name: s.attributes.name,
days: s.attributes.renewal
})));
// Calculate optimal renewals
const renewalPlan = calculateOptimalRenewals(servers, balance);
// Execute renewals
for (const plan of renewalPlan) {
console.log(`Renewing server ${plan.uuid} (current days: ${plan.currentDays}, will have: ${plan.newTotal})`);
try {
const result = await renewServer(plan.uuid);
if (result === true) {
console.log(`Successfully renewed server ${plan.uuid}`);
} else {
console.error(`Failed to renew server ${plan.uuid}`);
}
} catch (error) {
console.error(`Failed to renew server ${plan.uuid}:`, error);
}
// Add a small delay between renewals to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 2000));
}
console.log('Renewal check completed');
}
// Function to wait for XSRF token to be available in cookies
function waitForXsrfToken() {
return new Promise((resolve) => {
const checkToken = () => {
const token = getXsrfToken();
if (token) {
resolve();
} else {
setTimeout(checkToken, 100);
}
};
checkToken();
});
}
// Start the periodic checks
async function initialize() {
console.log('SillyDev Auto Renewal script started, waiting for XSRF token...');
await waitForXsrfToken();
console.log('XSRF token found, starting renewal checks...');
checkAndRenewServers(); // Initial check
setInterval(checkAndRenewServers, CHECK_INTERVAL); // Periodic checks
}
initialize();
})();