The Ugvs Auto Message V3

You Can Do Auto Message And Raid Server

// ==UserScript==
// @name         The Ugvs Auto Message V3
// @namespace    http://tampermonkey.net/
// @version      5.0
// @description  You Can Do Auto Message And Raid Server
// @match        *://discord.com/*
// @grant        none
// @require      https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
// ==/UserScript==

(async function () {
    'use strict';
    const ENCRYPTION_KEY = "super_secret_internal_key_123";
    const html = `
    <div id="dms-wrapper" style="position:fixed;top:50px;right:50px;z-index:9999;background:#51fcf4;color:white;border-radius:8px;font-size:13px;width:300px;box-shadow:0 0 8px rgba(0,0,0,0.6);user-select:none;font-family:Arial,sans-serif;">
      <div id="dms-titlebar" style="cursor:move;background:#27b0cf;padding:6px 10px;border-radius:8px 8px 0 0;display:flex;justify-content:space-between;align-items:center;user-select:none;">
        <span style="font-weight:bold;">The Ugvs Auto Message V3</span>
        <div style="display:flex;align-items:center;gap:10px;">
          <span id="dms-status" style="font-weight:bold;color:#ff4d4d;">Stop</span>
          <button id="dms-toggle" style="background:none;border:none;color:white;font-size:18px;cursor:pointer;line-height:1;">−</button>
        </div>
      </div>
      <div id="dms-body" style="padding:10px 12px;display:flex;flex-direction:column;gap:6px;user-select:text;">
        <div>
          <label style="font-weight:bold;">Discord Account Tokens:</label>
          <div id="dms-tokens-container" style="max-height:130px;overflow-y:auto;border:1px solid #7cfcf6;padding:4px;border-radius:4px;margin-top:3px;"></div>
          <button id="dms-add-token" style="margin-top:4px;width:100%;height:28px;font-weight:bold;cursor:pointer;">+ Add Discord Account Token</button>
          <button id="dms-gettoken" style="margin-top:5px;width:100%;height:28px;">Get Discord Account Token</button>
        </div>
        <div>
          <label style="font-weight:bold;">Server Channel ID:</label><br>
          <input id="dms-channel" style="width:100%;height:26px;margin-top:3px;"/>
          <button id="dms-getchannelid" style="margin-top:5px;width:100%;height:28px;">Get Server Channel ID</button>
        </div>
        <div>
          <label style="font-weight:bold;">Message:</label><br>
          <textarea id="dms-message" style="width:100%;height:50px;resize:vertical;margin-top:3px;"></textarea>
        </div>
        <div>
          <label style="font-weight:bold;">Interval (ms):</label><br>
          <input type="number" id="dms-interval" style="width:100%;height:26px;margin-top:3px;"/>
        </div>
      </div>
      <div id="dms-sendstop-container" style="display:flex;gap:8px;justify-content:flex-start;align-items:center;padding:8px 12px;border-top:1px solid #444;">
        <button id="dms-send" style="flex:1;height:30px;">Send</button>
        <button id="dms-stop" disabled style="flex:1;height:30px;">Stop</button>
      </div>
      <div id="dms-bypass-container" style="display:flex;gap:8px;align-items:center;font-size:13px;user-select:none;padding:0 12px 8px 12px;">
        <label style="display:flex;align-items:center;gap:4px;cursor:pointer;margin:0;">
          <input type="checkbox" id="dms-bypass" style="margin:0;vertical-align:middle;">Bypass
        </label>
        <label style="display:flex;align-items:center;gap:4px;cursor:default;margin:0;">
          <span>txt num:</span>
          <input type="number" id="dms-bypass-length" value="8" min="1" max="64" style="width:48px;height:24px;padding:2px 4px;text-align:center;"/>
        </label>
        <label style="display:flex;align-items:center;gap:4px;cursor:pointer;margin:0 0 0 8px;">
          <input type="checkbox" id="dms-splitmsg" style="margin:0;vertical-align:middle;">Return it
        </label>
      </div>
      <div style="display:flex;gap:8px;justify-content:center;padding:8px 12px;">
        <button id="dms-load" style="flex:1;height:28px;"> Load</button>
        <button id="dms-save" style="flex:1;height:28px;"> Save</button>
      </div>
      <div id="dms-log" style="max-height:90px;overflow:auto;background:#85d6bb;padding:6px;border-radius:4px;font-size:11px;margin:10px 12px 10px 12px;line-height:1.2;"></div>
    </div>`;

    let intervalId = null, currentTokenIndex = 0, simpleMode = false;

    // 改行分割メッセージ管理用
    let splitMessages = [];
    let splitMessageIndex = 0;

    const storedTokens = (() => {
        let val = localStorage.getItem("token") || "";
        val = val.replace(/^"(.*)"$/, "$1");
        return val.split(",").map(s => s.trim()).filter(Boolean);
    })();

    function log(msg, isError = false) {
        const logBox = document.getElementById("dms-log");
        if (!logBox) return;
        const line = document.createElement("div");
        line.style.color = isError ? "#ff4d4d" : "#80ff80";
        line.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
        logBox.appendChild(line);
        logBox.scrollTop = logBox.scrollHeight;
    }

    function setStatus(running) {
        const el = document.getElementById("dms-status");
        if (!el) return;
        if (running) {
            el.textContent = "Running";
            el.style.color = "#80ff80";
        } else {
            el.textContent = "Stop";
            el.style.color = "#ff4d4d";
        }
    }

    function encryptData(data, key) {
        const json = JSON.stringify(data);
        return CryptoJS.AES.encrypt(json, key).toString();
    }

    function decryptData(ciphertext, key) {
        const bytes = CryptoJS.AES.decrypt(ciphertext, key);
        const json = bytes.toString(CryptoJS.enc.Utf8);
        return JSON.parse(json);
    }

    async function loadFromFile() {
        try {
            const [handle] = await window.showOpenFilePicker({
                types: [{
                    description: 'Discord Send Config File',
                    accept: { 'application/octet-stream': ['.dis'] }
                }],
                multiple: false
            });
            const file = await handle.getFile();
            const text = await file.text();
            const decrypted = decryptData(text, ENCRYPTION_KEY);
            const tokens = decrypted.tokens || (decrypted.token ? [decrypted.token] : []);
            const container = document.getElementById("dms-tokens-container");
            container.innerHTML = "";
            for (const t of tokens) addTokenInput(t);
            document.getElementById("dms-channel").value = decrypted.channel || "";
            document.getElementById("dms-message").value = decrypted.message || "";
            document.getElementById("dms-interval").value = decrypted.interval || "";
            log("Loaded settings in files");
        } catch (e) {
            log("Failed to load settings in files", true);
        }
    }

    function downloadToFile() {
        try {
            const tokens = Array.from(document.querySelectorAll(".dms-token-input")).map(input => input.value).filter(Boolean);
            const data = {
                tokens,
                channel: document.getElementById("dms-channel").value,
                message: document.getElementById("dms-message").value,
                interval: document.getElementById("dms-interval").value
            };
            const encrypted = encryptData(data, ENCRYPTION_KEY);
            const blob = new Blob([encrypted], { type: 'application/octet-stream' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'dispam_config.dis';
            document.body.appendChild(a);
            a.click();
            setTimeout(() => {
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
            }, 100);
            log("File download started");
        } catch (e) {
            log("Failed to download files: " + e.message, true);
        }
    }

    function generateRandomChars(length) {
        const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        let result = '';
        for (let i = 0; i < length; i++) result += chars.charAt(Math.floor(Math.random() * chars.length));
        return result;
    }

    async function sendMessage() {
        const channelId = document.getElementById("dms-channel").value;
        let message = document.getElementById("dms-message").value;
        const bypassChecked = document.getElementById("dms-bypass")?.checked || false;
        const bypassLength = parseInt(document.getElementById("dms-bypass-length").value) || 8;
        const splitChecked = document.getElementById("dms-splitmsg")?.checked || false;

        if (!channelId) return;

        if (splitChecked) {
            if (splitMessages.length === 0) {
                splitMessages = message.split(/\r?\n/).map(s => s.trim()).filter(Boolean);
                splitMessageIndex = 0;
                if (splitMessages.length === 0) return;
            }
            message = splitMessages[splitMessageIndex];
            splitMessageIndex++;
            if (splitMessageIndex >= splitMessages.length) {
                splitMessageIndex = 0;
            }
        }

        if (!message) return;

        const tokens = Array.from(document.querySelectorAll(".dms-token-input")).map(input => input.value).filter(Boolean);
        if (tokens.length === 0) return;
        const token = tokens[currentTokenIndex];
        currentTokenIndex = (currentTokenIndex + 1) % tokens.length;

        let sendMsg = message;
        if (bypassChecked) sendMsg += ' ' + generateRandomChars(bypassLength);

        try {
            const response = await fetch(`https://discord.com/api/v9/channels/${channelId}/messages`, {
                method: 'POST',
                headers: {
                    'Authorization': token,
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ content: sendMsg })
            });
            const json = await response.json().catch(() => ({}));
            if (response.status === 200) {
                log("✔Message Sended");
            } else if (response.status === 429) {
                log("⚠Rate Limit: retry_after=" + json.retry_after + "ms", true);
            } else {
                log(`❌️Failed to send: ${response.status}`, true);
            }
        } catch (err) {
            log("❌️Failed to send: " + err.message, true);
        }

        if (!splitChecked) {
            splitMessages = [];
            splitMessageIndex = 0;
        }
    }

    function startSending() {
        currentTokenIndex = 0;
        splitMessages = [];
        splitMessageIndex = 0;
        const interval = parseInt(document.getElementById("dms-interval").value) || 1000;
        if (intervalId) clearInterval(intervalId);
        intervalId = setInterval(sendMessage, interval);
        document.getElementById("dms-send").disabled = true;
        document.getElementById("dms-stop").disabled = false;
        setStatus(true);
        log("Send starting...");
    }

    function stopSending() {
        if (intervalId) clearInterval(intervalId);
        intervalId = null;
        document.getElementById("dms-send").disabled = false;
        document.getElementById("dms-stop").disabled = true;
        setStatus(false);
        log("Stop sending...");

        splitMessages = [];
        splitMessageIndex = 0;
    }

    function getChannelIdFromUrl() {
        const url = window.location.href;
        const match = url.match(/discord\.com\/channels\/\d+\/(\d+)/);
        return (match && match[1]) ? match[1] : null;
    }

    function addTokenInput(value = "") {
        const container = document.getElementById("dms-tokens-container");
        const wrapper = document.createElement("div");
        wrapper.style.display = "flex";
        wrapper.style.gap = "4px";
        wrapper.style.marginBottom = "3px";
        const input = document.createElement("input");
        input.type = "text";
        input.className = "dms-token-input";
        input.style.flexGrow = "1";
        input.style.width = "100%";
        input.style.height = "24px";
        input.value = value;
        const delBtn = document.createElement("button");
        delBtn.textContent = "×";
        delBtn.style.width = "26px";
        delBtn.style.height = "24px";
        delBtn.style.cursor = "pointer";
        delBtn.title = "このtokenを削除";
        delBtn.onclick = () => container.removeChild(wrapper);
        wrapper.appendChild(input);
        wrapper.appendChild(delBtn);
        container.appendChild(wrapper);
    }

    function toggleSimpleMode() {
        const body = document.getElementById("dms-body");
        const sendStop = document.getElementById("dms-sendstop-container");
        const bypass = document.getElementById("dms-bypass-container");
        const loadSave = bypass.nextElementSibling; // 読み込み・保存ボタン
        const logBox = document.getElementById("dms-log");
        const toggleBtn = document.getElementById("dms-toggle");
        if (!simpleMode) {
            // シンプルモード:トークン・チャネル・メッセージ等は非表示
            body.style.display = "none";
            sendStop.style.display = "flex";
            bypass.style.display = "none";
            if (loadSave) loadSave.style.display = "none";
            logBox.style.display = "block";
            toggleBtn.textContent = "+";
            simpleMode = true;
        } else {
            // フル表示モード
            body.style.display = "flex";
            sendStop.style.display = "flex";
            bypass.style.display = "flex";
            if (loadSave) loadSave.style.display = "flex";
            logBox.style.display = "block";
            toggleBtn.textContent = "−";
            simpleMode = false;
        }
    }

    function createUI() {
        if (document.getElementById("dms-wrapper")) return;
        document.body.insertAdjacentHTML('beforeend', html);
        document.getElementById("dms-send").onclick = startSending;
        document.getElementById("dms-stop").onclick = stopSending;
        document.getElementById("dms-load").onclick = loadFromFile;
        document.getElementById("dms-save").onclick = downloadToFile;
        document.getElementById("dms-add-token").onclick = () => addTokenInput("");
        document.getElementById("dms-gettoken").onclick = () => {
            if (storedTokens.length > 0) {
                const container = document.getElementById("dms-tokens-container");
                const inputs = container.querySelectorAll(".dms-token-input");
                if (inputs.length === 0) addTokenInput(storedTokens[0]);
                else if (!inputs[0].value.trim()) inputs[0].value = storedTokens[0];
                log("Pasted Token");
            } else {
                log("Couldn't found Token", true);
            }
        };
        document.getElementById("dms-getchannelid").onclick = () => {
            const id = getChannelIdFromUrl();
            if (id) {
                document.getElementById("dms-channel").value = id;
                log("Pasted ChannelID");
            } else {
                log("Couldn't found ChannelID", true);
            }
        };
        document.getElementById("dms-toggle").onclick = toggleSimpleMode;

        const wrapper = document.getElementById("dms-wrapper");
        const title = document.getElementById("dms-titlebar");
        let isDragging = false, offsetX = 0, offsetY = 0;
        title.addEventListener("mousedown", e => {
            isDragging = true;
            offsetX = e.clientX - wrapper.offsetLeft;
            offsetY = e.clientY - wrapper.offsetTop;
            e.preventDefault();
        });
        document.addEventListener("mousemove", e => {
            if (!isDragging) return;
            wrapper.style.left = (e.clientX - offsetX) + "px";
            wrapper.style.top = (e.clientY - offsetY) + "px";
            wrapper.style.right = "auto";
        });
        document.addEventListener("mouseup", () => { isDragging = false; });

        setStatus(false);
        addTokenInput("");
    }

    if (document.readyState === "complete" || document.readyState === "interactive") setTimeout(createUI, 100);
    else window.addEventListener("DOMContentLoaded", () => setTimeout(createUI, 100));
    setInterval(() => { if (!document.getElementById("dms-wrapper")) createUI(); }, 2000);
})();