您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Send DM messages via Discord API with toggle visibility, customizable button names, and instructions. Supports "Shift + Enter" for new line and "Enter" for sending messages.
// ==UserScript== // @name Discord DM Sender with Input Box and Toggle // @namespace http://tampermonkey.net/ // @version 2.2 // @description Send DM messages via Discord API with toggle visibility, customizable button names, and instructions. Supports "Shift + Enter" for new line and "Enter" for sending messages. // @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 isBoxVisible = GM_getValue('isBoxVisible', true); let isTokenVisible = GM_getValue('isTokenVisible', true); let areChannelsVisible = GM_getValue('areChannelsVisible', true); let channelId = ''; const initialWidth = '280px'; const initialHeight = '500px'; 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'; container.style.display = isBoxVisible ? 'block' : 'none'; document.body.appendChild(container); makeElementDraggable(container); const hideTokenButton = document.createElement('button'); hideTokenButton.innerText = isTokenVisible ? 'Hide Token' : 'View Token'; hideTokenButton.style.marginBottom = '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'; hideTokenButton.addEventListener('click', () => { isTokenVisible = !isTokenVisible; GM_setValue('isTokenVisible', isTokenVisible); tokenBox.style.display = isTokenVisible ? 'block' : 'none'; hideTokenButton.innerText = isTokenVisible ? 'Hide Token' : 'View Token'; }); container.appendChild(hideTokenButton); 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'; tokenBox.style.display = isTokenVisible ? 'block' : 'none'; tokenBox.value = GM_getValue('tokenBoxValue', ''); tokenBox.addEventListener('input', () => { GM_setValue('tokenBoxValue', tokenBox.value); }); container.appendChild(tokenBox); const toggleChannelsButton = document.createElement('button'); toggleChannelsButton.innerText = areChannelsVisible ? 'Hide Channel IDs' : 'View Channel IDs'; toggleChannelsButton.style.marginTop = '10px'; toggleChannelsButton.style.width = '100%'; toggleChannelsButton.style.backgroundColor = '#575757'; toggleChannelsButton.style.color = '#ffffff'; toggleChannelsButton.style.border = 'none'; toggleChannelsButton.style.borderRadius = '3px'; toggleChannelsButton.style.cursor = 'pointer'; toggleChannelsButton.addEventListener('click', () => { areChannelsVisible = !areChannelsVisible; GM_setValue('areChannelsVisible', areChannelsVisible); channelBoxes.forEach((channelBox) => { channelBox.style.display = areChannelsVisible ? 'block' : 'none'; }); toggleChannelsButton.innerText = areChannelsVisible ? 'Hide Channel IDs' : 'View Channel IDs'; }); container.appendChild(toggleChannelsButton); const channelBoxes = []; const channelBoxPlaceholders = [ '荒らし雑談用匿名BOTのDMチャンネルIDを入力', '情勢雑談用BOTの匿名BOTのDMチャンネルIDを入力', '依頼支部用匿名BOTのDMチャンネルIDを入力' ]; channelBoxPlaceholders.forEach((placeholder, index) => { const channelBox = document.createElement('textarea'); channelBox.placeholder = placeholder; channelBox.style.width = '100%'; channelBox.style.height = '40px'; channelBox.style.resize = 'none'; channelBox.style.backgroundColor = '#000000'; channelBox.style.color = '#00FF00'; channelBox.style.display = areChannelsVisible ? 'block' : 'none'; channelBox.value = GM_getValue(`channelBox${index + 1}Value`, ''); channelBox.addEventListener('input', () => { GM_setValue(`channelBox${index + 1}Value`, channelBox.value); }); channelBoxes.push(channelBox); container.appendChild(channelBox); }); const inputBox = document.createElement('textarea'); inputBox.placeholder = 'Enter message (⚠️:初回はcaptchaにかかる事がある為、初回送信時はbotに1回手動でDMを送ってから使用してください。DMチャンネルIDはBOT IDではありません)'; inputBox.style.width = '100%'; inputBox.style.height = '100px'; inputBox.style.resize = 'none'; inputBox.style.backgroundColor = '#000000'; inputBox.style.color = '#00FF00'; inputBox.style.marginTop = '10px'; inputBox.value = GM_getValue('inputBoxValue', ''); inputBox.addEventListener('input', () => { GM_setValue('inputBoxValue', inputBox.value); }); inputBox.addEventListener('keydown', (event) => { if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); 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; } sendMessage(channelId, message, token).then((success) => { if (success) { inputBox.value = ''; GM_setValue('inputBoxValue', ''); } else { alert('Failed to send message'); } }); } }); container.appendChild(inputBox); const selectChannelsLabel = document.createElement('div'); selectChannelsLabel.innerText = 'Select channels'; selectChannelsLabel.style.marginTop = '10px'; selectChannelsLabel.style.marginBottom = '5px'; selectChannelsLabel.style.fontSize = '14px'; selectChannelsLabel.style.textAlign = 'left'; container.appendChild(selectChannelsLabel); const buttonContainer = document.createElement('div'); buttonContainer.style.display = 'flex'; buttonContainer.style.justifyContent = 'space-between'; const buttonNames = ['荒らし雑談', '情勢雑談', '依頼支部']; channelBoxes.forEach((channelBox, index) => { const channelButton = document.createElement('button'); channelButton.innerText = buttonNames[index]; channelButton.style.width = '30%'; channelButton.style.backgroundColor = '#575757'; channelButton.style.color = '#ffffff'; channelButton.style.border = 'none'; channelButton.style.borderRadius = '3px'; channelButton.style.cursor = 'pointer'; channelButton.addEventListener('click', () => { channelId = channelBox.value.trim(); updateButtonStyles(channelButton); }); buttonContainer.appendChild(channelButton); }); function updateButtonStyles(activeButton) { Array.from(buttonContainer.children).forEach((button) => { button.style.backgroundColor = button === activeButton ? '#047500' : '#575757'; }); } container.appendChild(buttonContainer); const sendButton = document.createElement('button'); sendButton.innerText = 'Send DM'; sendButton.style.marginTop = '10px'; sendButton.style.width = '100%'; sendButton.style.backgroundColor = '#575757'; sendButton.style.color = '#ffffff'; sendButton.style.border = 'none'; sendButton.style.borderRadius = '3px'; sendButton.style.cursor = 'pointer'; sendButton.addEventListener('click', async () => { 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; } const success = await sendMessage(channelId, message, token); if (success) { inputBox.value = ''; GM_setValue('inputBoxValue', ''); } else { alert('Failed to send message'); } }); container.appendChild(sendButton); const toggleImage = document.createElement('img'); toggleImage.src = 'https://i.imgur.com/FL6WD8a.png'; toggleImage.style.position = 'fixed'; toggleImage.style.width = '30px'; toggleImage.style.height = '30px'; toggleImage.style.cursor = 'pointer'; toggleImage.style.zIndex = '1001'; toggleImage.style.left = '75px'; toggleImage.style.bottom = '222px'; document.body.appendChild(toggleImage); toggleImage.addEventListener('click', () => { isBoxVisible = !isBoxVisible; GM_setValue('isBoxVisible', isBoxVisible); container.style.display = isBoxVisible ? 'block' : 'none'; }); function makeElementDraggable(el) { el.onmousedown = function(event) { if (event.target.tagName === 'TEXTAREA') return; event.preventDefault(); let shiftX = event.clientX - el.getBoundingClientRect().left; let shiftY = event.clientY - el.getBoundingClientRect().top; function moveAt(pageX, pageY) { const newLeft = Math.min(Math.max(0, pageX - shiftX), window.innerWidth - el.offsetWidth); const newTop = Math.min(Math.max(0, pageY - shiftY), window.innerHeight - el.offsetHeight); el.style.left = `${newLeft}px`; el.style.top = `${newTop}px`; } function stopDragging() { document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', stopDragging); } function onMouseMove(event) { moveAt(event.pageX, event.pageY); } document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', stopDragging); }; 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, 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)}`; } })();