Discord DM Sender with Input Box

Send DM messages via Discord API

目前為 2024-12-24 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Discord DM Sender with Input Box
// @namespace    http://tampermonkey.net/
// @version      1.7
// @description  Send DM messages via Discord API
// @author       Your Name
// @match        https://discord.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @license      You can modify as long as you credit me
// ==/UserScript==

(function() {
    'use strict';

    let channelId = '';

    const initialWidth = '280px';
    const initialHeight = '450px';

    const container = document.createElement('div');
    container.style.position = 'fixed';
    container.style.bottom = '10px';
    container.style.left = '10px';
    container.style.backgroundColor = '#2f3136';
    container.style.color = '#ffffff';
    container.style.padding = '10px';
    container.style.borderRadius = '5px';
    container.style.zIndex = '1000';
    container.style.width = initialWidth;
    container.style.height = initialHeight;
    container.style.maxHeight = '90vh';
    container.style.overflow = 'auto';
    document.body.appendChild(container);

    makeElementDraggable(container);

    const tokenBox = document.createElement('textarea');
    tokenBox.placeholder = 'Enter your token';
    tokenBox.style.width = '100%';
    tokenBox.style.height = '40px';
    tokenBox.style.resize = 'none';
    tokenBox.style.backgroundColor = '#000000';
    tokenBox.style.color = '#00FF00';
    container.appendChild(tokenBox);

    const hideTokenButton = document.createElement('button');
    hideTokenButton.innerText = 'Hide Token';
    hideTokenButton.style.marginTop = '10px';
    hideTokenButton.style.width = '100%';
    hideTokenButton.style.backgroundColor = '#575757';
    hideTokenButton.style.color = '#ffffff';
    hideTokenButton.style.border = 'none';
    hideTokenButton.style.borderRadius = '3px';
    hideTokenButton.style.cursor = 'pointer';
    container.appendChild(hideTokenButton);

    hideTokenButton.addEventListener('click', () => {
        if (tokenBox.style.display === 'none') {
            tokenBox.style.display = 'block';
            hideTokenButton.innerText = 'Hide Token';
        } else {
            tokenBox.style.display = 'none';
            hideTokenButton.innerText = 'Show Token';
        }
    });

    const inputBox = document.createElement('textarea');
    inputBox.placeholder = 'Enter your secret message to aarr';
    inputBox.style.width = '100%';
    inputBox.style.height = '100px';
    inputBox.style.resize = 'none';
    inputBox.style.backgroundColor = '#000000';
    inputBox.style.color = '#00FF00';
    container.appendChild(inputBox);

    const channelBox1 = document.createElement('textarea');
    channelBox1.placeholder = '荒らし雑談のBOTのDMチャンネルIDを入力';
    channelBox1.style.width = '100%';
    channelBox1.style.height = '40px';
    channelBox1.style.resize = 'none';
    channelBox1.style.backgroundColor = '#000000';
    channelBox1.style.color = '#00FF00';
    container.appendChild(channelBox1);

    const channelBox2 = document.createElement('textarea');
    channelBox2.placeholder = '情勢雑談のBOTのDMチャンネルIDを入力';
    channelBox2.style.width = '100%';
    channelBox2.style.height = '40px';
    channelBox2.style.resize = 'none';
    channelBox2.style.backgroundColor = '#000000';
    channelBox2.style.color = '#00FF00';
    container.appendChild(channelBox2);

    const channelBox3 = document.createElement('textarea');
    channelBox3.placeholder = '依頼支部のBOTのDMチャンネルIDを入力';
    channelBox3.style.width = '100%';
    channelBox3.style.height = '40px';
    channelBox3.style.resize = 'none';
    channelBox3.style.backgroundColor = '#000000';
    channelBox3.style.color = '#00FF00';
    container.appendChild(channelBox3);

    const button = document.createElement('button');
    button.innerText = 'Send DM';
    button.style.marginTop = '10px';
    button.style.width = '100%';
    button.style.backgroundColor = '#575757';
    button.style.color = '#ffffff';
    button.style.border = 'none';
    button.style.borderRadius = '3px';
    button.style.cursor = 'pointer';
    container.appendChild(button);

    const buttonContainer = document.createElement('div');
    buttonContainer.style.marginTop = '10px';
    buttonContainer.style.display = 'flex';
    buttonContainer.style.justifyContent = 'space-between';

    const channelButton1 = document.createElement('button');
    channelButton1.innerText = '1荒らし雑談';
    channelButton1.style.width = '30%';
    channelButton1.style.backgroundColor = '#575757';
    channelButton1.style.color = '#ffffff';
    channelButton1.style.border = 'none';
    channelButton1.style.borderRadius = '3px';
    channelButton1.style.cursor = 'pointer';
    channelButton1.addEventListener('click', () => {
        channelId = channelBox1.value.trim();
        updateButtonStyles(channelButton1);
        GM_setValue('channelBox1Value', channelId);
    });

    const channelButton2 = document.createElement('button');
    channelButton2.innerText = '2情勢雑談';
    channelButton2.style.width = '30%';
    channelButton2.style.backgroundColor = '#575757';
    channelButton2.style.color = '#ffffff';
    channelButton2.style.border = 'none';
    channelButton2.style.borderRadius = '3px';
    channelButton2.style.cursor = 'pointer';
    channelButton2.addEventListener('click', () => {
        channelId = channelBox2.value.trim();
        updateButtonStyles(channelButton2);
        GM_setValue('channelBox2Value', channelId);
    });

    const channelButton3 = document.createElement('button');
    channelButton3.innerText = '3依頼版';
    channelButton3.style.width = '30%';
    channelButton3.style.backgroundColor = '#575757';
    channelButton3.style.color = '#ffffff';
    channelButton3.style.border = 'none';
    channelButton3.style.borderRadius = '3px';
    channelButton3.style.cursor = 'pointer';
    channelButton3.addEventListener('click', () => {
        channelId = channelBox3.value.trim();
        updateButtonStyles(channelButton3);
        GM_setValue('channelBox3Value', channelId);
    });

    buttonContainer.appendChild(channelButton1);
    buttonContainer.appendChild(channelButton2);
    buttonContainer.appendChild(channelButton3);
    container.appendChild(buttonContainer);

    function updateButtonStyles(activeButton) {
        [channelButton1, channelButton2, channelButton3].forEach(button => {
            if (button === activeButton) {
                button.style.backgroundColor = '#047500';
            } else {
                button.style.backgroundColor = '#575757';
            }
        });
    }

    inputBox.value = GM_getValue('inputBoxValue', '');
    tokenBox.value = GM_getValue('tokenBoxValue', '');
    channelBox1.value = GM_getValue('channelBox1Value', '');
    channelBox2.value = GM_getValue('channelBox2Value', '');
    channelBox3.value = GM_getValue('channelBox3Value', '');

    async function sendDM() {
        const token = tokenBox.value.trim();
        if (!token) {
            alert('Token is required');
            return;
        }

        const message = inputBox.value.trim();
        if (!message) {
            alert('Message cannot be empty');
            return;
        }

        tokenBox.style.display = 'none';
        GM_setValue('tokenBoxValue', token);

        const success = await sendMessage(channelId, message, token);
        if (success) {
            inputBox.value = '';
            GM_setValue('inputBoxValue', '');
        } else {
            alert('Failed to send message');
        }
    }

    button.addEventListener('click', sendDM);

    inputBox.addEventListener('keydown', (event) => {
        if (event.key === 'Enter' && !event.shiftKey) {
            event.preventDefault();
            sendDM();
        } else if (event.key === 'Enter' && event.shiftKey) {
            event.preventDefault();
            const cursorPos = inputBox.selectionStart;
            const textBefore = inputBox.value.substring(0, cursorPos);
            const textAfter = inputBox.value.substring(cursorPos);
            inputBox.value = `${textBefore}\n${textAfter}`;
            inputBox.selectionStart = cursorPos + 1;
            inputBox.selectionEnd = cursorPos + 1;
        }
    });

    inputBox.addEventListener('input', () => {
        GM_setValue('inputBoxValue', inputBox.value);
    });

    tokenBox.addEventListener('input', () => {
        GM_setValue('tokenBoxValue', tokenBox.value);
    });

    function makeElementDraggable(el) {
        el.onmousedown = function(event) {
            if (event.target === inputBox || event.target === tokenBox || event.target === channelBox1 || event.target === channelBox2 || event.target ===             channelBox3) {
                return;
            }

            event.preventDefault();

            let shiftX = event.clientX - el.getBoundingClientRect().left;
            let shiftY = event.clientY - el.getBoundingClientRect().top;

            function moveAt(pageX, pageY) {
                el.style.left = Math.min(Math.max(0, pageX - shiftX), window.innerWidth - el.offsetWidth) + 'px';
                el.style.top = Math.min(Math.max(0, pageY - shiftY), window.innerHeight - el.offsetHeight) + 'px';
            }

            function onMouseMove(event) {
                moveAt(event.pageX, event.pageY);
            }

            document.addEventListener('mousemove', onMouseMove);

            el.onmouseup = function() {
                document.removeEventListener('mousemove', onMouseMove);
                el.onmouseup = null;
            };
        };

        el.ondragstart = function() {
            return false;
        };
    }

    async function sendMessage(channelId, message, token) {
        const nonce = generateNonce();
        return new Promise((resolve) => {
            GM_xmlhttpRequest({
                method: 'POST',
                url: `https://discord.com/api/v9/channels/${channelId}/messages`,
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': token
                },
                data: JSON.stringify({
                    content: message,
                    flags: 0,
                    mobile_network_type: "unknown",
                    nonce: nonce,
                    tts: false
                }),
                onload: (response) => {
                    resolve(response.status === 200);
                },
                onerror: () => resolve(false)
            });
        });
    }

    function generateNonce() {
        const now = Date.now();
        return `${now}${Math.floor(Math.random() * 1000)}`;
    }
})();