// ==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();
})();

Serv00服务器后台通过devil命令管理,常用功能收集:

  • 开启用户程序或脚本执行权限

    devil binexec on
  • 端口管理

    • 添加端口:

      devil port add [tcp,udp] 54321 # 指定端口
      devil port add [tcp,udp] random # 随机分配端口
    • 查看端口:

      devil port list
    • 删除端口:

      devil port del [tcp,udp] 33333
  • 网站管理

    • 添加网站:

      devil www add xxx.your.domain proxy localhost 54321 # 代理到本地服务
      devil www add xxx.your.domain [php] # php
      devil www add xxx.your.domain pointer www.baidu.com
      devil www add xxx.your.domain [python|nodejs|ruby] /home/xxxx/bin/xxx [production, staging, development, test]
    • 查看网站:

      devil www list
    • 删除站点:

      devil www del xxx.your.domain
  • 查看当前所在服务器IP

    devil vhost list

网上看到的方法,收集一下。
所谓别名就是同一个邮箱,但是地址形式可以多种,以方便多注册……

比如 [email protected] 这个邮箱:

所有邮件接受到[email protected] 这个邮箱