您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Discord自动点击Midjourney的U1、U2、U3、U4,自动下载所有图片,满80张会自动下载zip包,不到80张点关闭即可自动下载。
当前为
// ==UserScript== // @name Midjourney Autopic // @namespace http://tampermonkey.net/ // @version 1.2.8 // @description Discord自动点击Midjourney的U1、U2、U3、U4,自动下载所有图片,满80张会自动下载zip包,不到80张点关闭即可自动下载。 // @author 老陆(vx:laolu2045) // @match https://discord.com/channels/*/* // @icon https://www.midjourney.com/favicon.ico // @grant unsafeWindow // @require https://code.jquery.com/jquery-3.6.0.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.5.0/jszip.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.8/xlsx.full.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js // @license MIT License // ==/UserScript== (function () { ("use strict"); const sessionId = "ea8816d857ba9ae2f74c59ae1a953afe"; function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } async function clickButtons(lastMsg) { const buttonArr = Array.from(lastMsg.querySelectorAll("button")).filter( (button) => ["U1", "U2", "U3", "U4"].some( (text) => button.textContent.trim() === text ) ); if (buttonArr.length >= 4) { for (let i = 0; i < 4; i++) { buttonArr[i].click(); console.log("点击1下U按钮"); await sleep(3000); // 在每次点击后等待3秒,1秒=1000 } } } //midjourney机器人 function sendMessage(token, channelId, guildId, sessionId, content) { const url = `https://discord.com/api/v9/interactions`; const payload = { type: 2, application_id: "936929561302675456", guild_id: guildId, channel_id: channelId, session_id: sessionId, data: { version: "1166847114203123795", id: "938956540159881230", name: "imagine", type: 1, options: [ { type: 3, name: "prompt", value: content, }, ], application_command: { id: "938956540159881230", application_id: "936929561302675456", version: "1166847114203123795", default_member_permissions: null, type: 1, nsfw: false, name: "imagine", description: "Create images with Midjourney", dm_permission: true, contexts: [0, 1, 2], options: [ { type: 3, name: "prompt", description: "The prompt to imagine", required: true, }, ], }, attachments: [], }, nonce: Date.now().toString(), }; console.log(payload); const request = new XMLHttpRequest(); request.open("POST", url, true); request.setRequestHeader("Content-Type", "application/json"); request.setRequestHeader("Authorization", token); request.send(JSON.stringify(payload)); } //niji机器人 function sendMessageNiji(token, channelId, guildId, sessionId, content) { const url = `https://discord.com/api/v9/interactions`; const payload = { type: 2, application_id: "1022952195194359889", guild_id: guildId, channel_id: channelId, session_id: sessionId, data: { version: "1166842163141816443", id: "1023054140580057099", name: "imagine", type: 1, options: [ { type: 3, name: "prompt", value: content, }, ], application_command: { id: "1023054140580057099", application_id: "1022952195194359889", version: "1166842163141816443", default_member_permissions: null, type: 1, nsfw: false, name: "imagine", description: "Create images with Niji journey", dm_permission: true, contexts: [0, 1, 2], options: [ { type: 3, name: "prompt", description: "The prompt to imagine", required: true, }, ], }, attachments: [], }, nonce: Date.now().toString(), }; console.log(payload); const request = new XMLHttpRequest(); request.open("POST", url, true); request.setRequestHeader("Content-Type", "application/json"); request.setRequestHeader("Authorization", token); request.send(JSON.stringify(payload)); } function getToken() { const webpackChunkdiscord_app = unsafeWindow.webpackChunkdiscord_app; const m = []; webpackChunkdiscord_app.push([ [""], {}, (e) => { for (let c in e.c) m.push(e.c[c]); }, ]); const tokenModule = m.find((m) => m?.exports?.default?.getToken !== void 0); const token = tokenModule.exports.default.getToken(); return token; } const token = getToken(); let messages = []; let urls = []; let commandInterval = []; let roundInterval = []; let commandsPerRound = 0; async function paotu() { createModal(); } let downloads = "cut"; let bot = "mj"; let paotuisRunning = false; async function createModal() { // 创建一个半透明的背景 const overlay = document.createElement("div"); overlay.style = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(5px); `; // 创建一个带有毛玻璃效果的窗口 const modal = document.createElement("div"); modal.style = ` width: 50%; padding: 40px; background: rgba(225, 225, 225, 0.7); border-radius: 10px; backdrop-filter: blur(10px); box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); border: 1px solid rgba(255, 255, 255, 0.18); text-align: center; `; const label1 = document.createElement("label"); label1.textContent = "顺序读取表格第1列的数据"; label1.style = `margin-right: 10px;`; // 创建选择命令表格的按钮 const commandTableButton = document.createElement("button"); commandTableButton.textContent = "选择MJ命令xlsx表格"; commandTableButton.style = ` margin: 10px; padding: 10px; font-size: 18px; border-radius: 5px; background: linear-gradient(90deg, rgba(0, 121, 191, 0.8) 0%, rgba(0, 212, 255, 0.8) 100%); color: white; cursor: pointer; border: none; transition: background 0.5s; `; // 创建单选框组 const radioGroupDiv = document.createElement("div"); // MJ机器人选项 const mjRobotRadio = document.createElement("input"); mjRobotRadio.type = "radio"; mjRobotRadio.name = "robotSelection"; mjRobotRadio.id = "mjRobot"; mjRobotRadio.value = "MJ机器人"; mjRobotRadio.checked = true; // 默认选择MJ机器人 const mjRobotLabel = document.createElement("label"); mjRobotLabel.htmlFor = "mjRobot"; mjRobotLabel.textContent = "MJ机器人"; mjRobotRadio.addEventListener("change", function () { if (this.checked) { bot = "mj"; } }); // Niji机器人选项 const nijiRobotRadio = document.createElement("input"); nijiRobotRadio.type = "radio"; nijiRobotRadio.name = "robotSelection"; nijiRobotRadio.id = "nijiRobot"; nijiRobotRadio.value = "Niji机器人"; const nijiRobotLabel = document.createElement("label"); nijiRobotLabel.htmlFor = "nijiRobot"; nijiRobotLabel.textContent = "Niji机器人"; nijiRobotRadio.addEventListener("change", function () { if (this.checked) { bot = "niji"; } }); if (bot === "mj") { mjRobotRadio.checked = true; } else if (bot === "niji") { nijiRobotRadio.checked = true; } // 将单选框和对应的标签添加到单选框组中 radioGroupDiv.appendChild(mjRobotRadio); radioGroupDiv.appendChild(mjRobotLabel); radioGroupDiv.appendChild(nijiRobotRadio); radioGroupDiv.appendChild(nijiRobotLabel); // 创建下载单选框组 const downloadGroupDiv = document.createElement("div"); // 全部下载 const downloadAllRadio = document.createElement("input"); downloadAllRadio.type = "radio"; downloadAllRadio.name = "downloadSelection"; downloadAllRadio.id = "downloadAll"; downloadAllRadio.value = "全部下载"; downloadAllRadio.checked = true; // 默认选择 const downloadAllLabel = document.createElement("label"); downloadAllLabel.htmlFor = "downloadAll"; downloadAllLabel.textContent = "全部下载"; downloadAllRadio.addEventListener("change", function () { if (this.checked) { downloads = "all"; console.log("downloads", downloads); } }); // 跳过4宫格下载 const downloadSkipRadio = document.createElement("input"); downloadSkipRadio.type = "radio"; downloadSkipRadio.name = "downloadSelection"; downloadSkipRadio.id = "downloadSkip"; downloadSkipRadio.value = "跳过4宫格下载"; const downloadSkipLabel = document.createElement("label"); downloadSkipLabel.htmlFor = "downloadSkip"; downloadSkipLabel.textContent = "跳过4宫格下载"; downloadSkipRadio.addEventListener("change", function () { if (this.checked) { downloads = "skip"; console.log("downloads", downloads); } }); // 自动切割并下载 const downloadCutRadio = document.createElement("input"); downloadCutRadio.type = "radio"; downloadCutRadio.name = "downloadSelection"; downloadCutRadio.id = "downloadCut"; downloadCutRadio.value = "自动切割并下载大图"; const downloadCutLabel = document.createElement("label"); downloadCutLabel.htmlFor = "downloadCut"; downloadCutLabel.textContent = "自动切割并下载大图"; downloadCutRadio.addEventListener("change", function () { if (this.checked) { downloads = "cut"; console.log("downloads", downloads); } }); if (downloads === "all") { downloadAllRadio.checked = true; } else if (downloads === "skip") { downloadSkipRadio.checked = true; } else if (downloads === "cut") { downloadCutRadio.checked = true; } // 将单选框和对应的标签添加到单选框组中 downloadGroupDiv.appendChild(downloadAllRadio); downloadGroupDiv.appendChild(downloadAllLabel); downloadGroupDiv.appendChild(downloadSkipRadio); downloadGroupDiv.appendChild(downloadSkipLabel); downloadGroupDiv.appendChild(downloadCutRadio); downloadGroupDiv.appendChild(downloadCutLabel); modal.appendChild(radioGroupDiv); const brElement = document.createElement("br"); modal.appendChild(brElement); modal.appendChild(downloadGroupDiv); modal.appendChild(label1); modal.appendChild(commandTableButton); // 创建输入字段 const fields = [ { label: "命令发送间隔时间(秒)【推荐6-10】", id: "command-interval", isRange: true, }, { label: "每轮间隔时间(秒)【推荐800-1000】", id: "round-interval", isRange: true, }, { label: "每轮命令数", id: "round-command-count", isRange: false }, ]; fields.forEach((field) => { const fieldContainer = document.createElement("div"); fieldContainer.style = `display: flex; justify-content: center; align-items: center; margin: 20px;`; const label = document.createElement("label"); label.textContent = field.label; label.style = `margin-right: 10px;`; if (field.isRange) { const labelDash = document.createElement("label"); labelDash.textContent = "-"; labelDash.style = `margin: 0 10px;`; const input = document.createElement("input"); input.id = `${field.id}-1`; // 添加 ID input.style = ` padding: 10px; font-size: 16px; border-radius: 5px; border: 1px solid rgba(0, 0, 0, 0.3); `; const input2 = document.createElement("input"); input2.id = `${field.id}-2`; // 添加 ID input2.style = ` padding: 10px; font-size: 16px; border-radius: 5px; border: 1px solid rgba(0, 0, 0, 0.3); `; fieldContainer.appendChild(label); fieldContainer.appendChild(input); fieldContainer.appendChild(labelDash); fieldContainer.appendChild(input2); } else { const input = document.createElement("input"); input.style = ` padding: 10px; font-size: 16px; border-radius: 5px; border: 1px solid rgba(0, 0, 0, 0.3); `; input.id = field.id; fieldContainer.appendChild(label); fieldContainer.appendChild(input); } modal.appendChild(fieldContainer); }); // 创建开始按钮 const startButton = document.createElement("button"); if (paotuisRunning) { startButton.textContent = "停止跑图"; startButton.style = ` display: block; margin-top: 20px; margin-left: auto; margin-right: auto; padding: 10px 20px; font-size: 18px; border: none; border-radius: 5px; background: linear-gradient(90deg, rgba(235, 52, 52, 1) 0%, rgba(236, 116, 116, 1) 100%); box-shadow: 0px 3px 15px rgba(0,0,0,0.2); color: white; cursor: pointer; transition: background 0.5s; `; } else { startButton.textContent = "开始跑图"; startButton.style = ` display: block; margin-top: 20px; margin-left: auto; margin-right: auto; padding: 10px 20px; font-size: 18px; border: none; border-radius: 5px; background: linear-gradient(90deg, rgba(39, 174, 96, 0.8) 0%, rgba(0, 230, 64, 0.8) 100%); box-shadow: 0px 3px 15px rgba(0,0,0,0.2); color: white; cursor: pointer; transition: background 0.5s; `; } modal.appendChild(startButton); // 创建关闭按钮 const closeButton = document.createElement("button"); closeButton.textContent = "关闭"; closeButton.style = ` display: block; margin-top: 20px; margin-left: auto; margin-right: auto; padding: 10px 20px; border: none; border-radius: 5px; background: linear-gradient(90deg, rgba(235, 52, 52, 1) 0%, rgba(236, 116, 116, 1) 100%); box-shadow: 0px 3px 15px rgba(0,0,0,0.2); color: white; cursor: pointer; transition: background 0.5s; `; closeButton.addEventListener("mouseover", () => { closeButton.style.background = "rgba(236, 116, 116, 1)"; }); closeButton.addEventListener("mouseout", () => { closeButton.style.background = "linear-gradient(90deg, rgba(235, 52, 52, 1) 0%, rgba(236, 116, 116, 1) 100%)"; }); closeButton.addEventListener("click", () => { document.body.removeChild(overlay); }); modal.appendChild(closeButton); // 将窗口添加到背景上,然后将背景添加到文档上 overlay.appendChild(modal); document.body.appendChild(overlay); const fileInput = document.createElement("input"); fileInput.type = "file"; fileInput.accept = ".xlsx"; fileInput.style.display = "none"; modal.appendChild(fileInput); commandTableButton.addEventListener("click", () => { fileInput.click(); }); fileInput.addEventListener("change", handleFileSelect, false); function handleFileSelect(evt) { var files = evt.target.files; var f = files[0]; var reader = new FileReader(); reader.onload = function (e) { var data = new Uint8Array(e.target.result); var workbook = XLSX.read(data, { type: "array" }); var worksheet = workbook.Sheets[workbook.SheetNames[0]]; var jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); messages = jsonData.map((row) => row[0]); }; reader.readAsArrayBuffer(f); } startButton.addEventListener("click", () => { const { commandInterval, roundInterval, roundCommandCount } = getFieldValues(); if (!paotuisRunning) { // Start running paotuisRunning = true; urls = []; startButton.textContent = "停止跑图"; startButton.style = ` display: block; margin-top: 20px; margin-left: auto; margin-right: auto; padding: 10px 20px; font-size: 18px; border: none; border-radius: 5px; background: linear-gradient(90deg, rgba(235, 52, 52, 1) 0%, rgba(236, 116, 116, 1) 100%); box-shadow: 0px 3px 15px rgba(0,0,0,0.2); color: white; cursor: pointer; transition: background 0.5s; `; sendCommands(commandInterval, roundInterval, roundCommandCount); } else { // Stop running paotuisRunning = false; startButton.textContent = "开始跑图"; startButton.style = ` display: block; margin-top: 20px; margin-left: auto; margin-right: auto; padding: 10px 20px; font-size: 18px; border: none; border-radius: 5px; background: linear-gradient(90deg, rgba(39, 174, 96, 0.8) 0%, rgba(0, 230, 64, 0.8) 100%); box-shadow: 0px 3px 15px rgba(0,0,0,0.2); color: white; cursor: pointer; transition: background 0.5s; `; } }); async function sendCommands( commandInterval, roundInterval, commandsPerRound ) { let counter = 0; let channelId = window.location.href.substring( window.location.href.lastIndexOf("/") + 1, window.location.href.length ); let urlParts = window.location.href.split("/"); let guildId = urlParts[urlParts.length - 2]; for (let i = 0; i < messages.length; i++) { if (!paotuisRunning) { // Stop sending commands if the running state is set to false break; } if (bot === "mj") { sendMessage(token, channelId, guildId, sessionId, messages[i]); } else if (bot === "niji") { sendMessageNiji(token, channelId, guildId, sessionId, messages[i]); } await sleeps(getRandom(commandInterval[0], commandInterval[1])); counter++; if (counter >= commandsPerRound) { counter = 0; await sleeps(getRandom(roundInterval[0], roundInterval[1])); } } paotuisRunning = false; startButton.textContent = "开始跑图"; startButton.style = ` display: block; margin-top: 20px; margin-left: auto; margin-right: auto; padding: 10px 20px; font-size: 18px; border: none; border-radius: 5px; background: linear-gradient(90deg, rgba(39, 174, 96, 0.8) 0%, rgba(0, 230, 64, 0.8) 100%); box-shadow: 0px 3px 15px rgba(0,0,0,0.2); color: white; cursor: pointer; transition: background 0.5s; `; } function sleeps(ms) { return new Promise((resolve) => setTimeout(resolve, ms * 1000)); } function getRandom(min, max) { return Math.random() * (max - min) + min; } function getFieldValues() { let commandInterval = [ Number(document.querySelector("#command-interval-1").value), Number(document.querySelector("#command-interval-2").value), ]; let roundInterval = [ Number(document.querySelector("#round-interval-1").value), Number(document.querySelector("#round-interval-2").value), ]; let roundCommandCount = Number( document.querySelector("#round-command-count").value ); return { commandInterval, roundInterval, roundCommandCount }; } } //自动下载 // utils.ts 的内容 function saveFile(content, fileName) { const link = document.createElement("a"); link.style.display = "none"; link.download = fileName; link.href = URL.createObjectURL(content); document.body.appendChild(link); link.click(); document.body.removeChild(link); } async function getUrlBlob(url) { try { const res = await fetch(url); return res.blob(); } catch { return null; } } // 主要的代码 function checkIsMidjourneyBot(li) { if (!li) { return false; } var userName = li.querySelector( "h3[class^=header] span[class^=username]" )?.textContent; if (userName === "Midjourney Bot" || userName === "niji・journey Bot") { return true; } if (!userName) { return checkIsMidjourneyBot(li.previousElementSibling); } } function matchMidjourneyLis(li) { if (checkIsMidjourneyBot(li)) { const id = li.id.substring(14); let bs = 0; const prompts = Array.from( li.querySelector("div[id^=message-content-]>strong")?.childNodes ?? [] ) .map((node) => node.textContent) .join(" "); const url = li.querySelector( "div[class^=messageAttachment] div[class^=imageWrapper] a[data-role=img]" )?.href; const isFourGrid = Array.from(li.querySelectorAll("button")) ?.map((_) => _.textContent) ?.join("") === "U1U2U3U4V1V2V3V4"; if (isFourGrid) { bs = 0; } else { bs = 1; } if (downloads === "all") { return { id, prompts, url, bs, }; } else if (downloads === "skip") { if (!isFourGrid) { return { id, prompts, url, bs, }; } } else if (downloads === "cut") { if (isFourGrid) { return { id, prompts, url, bs, }; } } } } let currentZip = new JSZip(); let zipCount = 0; let zipBatch = new Set(); //图片打包数量 const flushThreshold = 80; let mutationObserver; //分割图片 async function splitImageIntoFour(url) { const image = new Image(); image.crossOrigin = "Anonymous"; const loadPromise = new Promise((resolve, reject) => { image.onload = () => resolve(); image.onerror = reject; }); image.src = url; await loadPromise; const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); const width = image.width; const height = image.height; const midWidth = Math.floor(width / 2); const midHeight = Math.floor(height / 2); canvas.width = midWidth; canvas.height = midHeight; const blobs = []; const coordinates = [ [0, 0, midWidth - 1, midHeight - 1], // Upper Left [midWidth, 0, width, midHeight - 1], // Upper Right [0, midHeight, midWidth - 1, height], // Lower Left [midWidth, midHeight, width, height], // Lower Right ]; for (let i = 0; i < 4; i++) { ctx.clearRect(0, 0, midWidth, midHeight); const [sourceX1, sourceY1, sourceX2, sourceY2] = coordinates[i]; ctx.drawImage( image, sourceX1, sourceY1, sourceX2 - sourceX1, sourceY2 - sourceY1, 0, 0, midWidth, midHeight ); const blob = await new Promise((resolve) => canvas.toBlob(resolve)); blobs.push(blob); } return blobs; } function processImage(data) { const regexFilename = /^.+\/(.+?)\.png.*$/; const matchResult = data.url.match(regexFilename); const fileName = matchResult ? matchResult[1] : null; const regexDigits = /_(\d{4})_/; if (fileName) { splitImageIntoFour(data.url).then((blobs) => { blobs.forEach((blob, index) => { let newFileName; if (regexDigits.test(fileName)) { newFileName = fileName.replace( regexDigits, `_${RegExp.$1}_U${index + 1}_` ); } else { newFileName = fileName + "_" + "U" + (index + 1); } currentZip.file(`${newFileName}.png`, blob, { binary: true }); zipCount++; // 添加对应的url if (data.bs === 0) { // 修改的部分开始 const matchResults = data.prompts.match(/\d{4}/); const numberInPrompt = matchResults ? matchResults[0] : null; if (numberInPrompt) { for (let i = 0; i < messages.length; i++) { if (messages[i].includes(numberInPrompt)) { const indexInUrls = urls.findIndex( (entry) => entry.index === i ); if (indexInUrls !== -1) { urls.splice(indexInUrls, 1); } urls.push({ url: data.url, index: i }); console.log(urls); break; } } } // 修改的部分结束 } console.log( `[新的图片] ${newFileName}`, `[ZIP 计数] ${zipCount} / ${flushThreshold}` ); if (zipCount >= flushThreshold) { flush(); } }); }); } } function parseLiNode(node) { const data = matchMidjourneyLis(node); if (data?.url) { const matchResult = data.url.match(/^.+\/(.+?)\.png.*$/); const fileName = matchResult ? matchResult[1] : null; if (fileName && !zipBatch.has(fileName)) { zipBatch.add(fileName); // 如果 downloads 为 "cut",则处理和切割图片 if (downloads === "cut") { processImage(data); } else { getUrlBlob(data.url).then((binaryBlob) => { if (binaryBlob && currentZip) { currentZip.file(`${fileName}.png`, binaryBlob, { binary: true, }); } zipCount++; // 添加对应的url if (data.bs === 0) { // 修改的部分开始 const matchResults = data.prompts.match(/\d{4}/); const numberInPrompt = matchResults ? matchResults[0] : null; if (numberInPrompt) { for (let i = 0; i < messages.length; i++) { if (messages[i].includes(numberInPrompt)) { const indexInUrls = urls.findIndex( (entry) => entry.index === i ); if (indexInUrls !== -1) { urls.splice(indexInUrls, 1); } urls.push({ url: data.url, index: i }); console.log(urls); break; } } } // 修改的部分结束 } console.log( `[新的图片] ${data.url}`, `[ZIP 计数] ${zipCount} / ${flushThreshold}` ); if (zipCount >= flushThreshold) { flush(); } }); } } } } function startObserve() { mutationObserver = new MutationObserver((records) => { records.forEach((record) => { const addNodes = record.addedNodes; if ( record.type === "childList" && addNodes && addNodes?.length && record.target.tagName === "OL" ) { addNodes.forEach((node) => { const li = node; if (li.tagName === "LI" && li.id.startsWith("chat-messages-")) { parseLiNode(li); } }); } else if ( record.type === "attributes" && record.attributeName === "class" && record.target.tagName === "DIV" && record.target.className.includes("imageWrapper") ) { let li = record.target; while (li && li.tagName !== "LI") { li = li.parentElement; } if (li) { parseLiNode(li); } } }); }); const contentList = document.querySelector('ol[class^="scrollerInner"]'); if (contentList) { mutationObserver.observe(contentList, { attributes: true, childList: true, subtree: true, }); } } async function flush() { if (zipCount) { const prevZip = currentZip; currentZip = new JSZip(); zipCount = 0; zipBatch.clear(); const zipContent = await prevZip.generateAsync({ type: "blob" }); saveFile(zipContent, `midjourney-${Date.now()}.zip`); } } //导出excel function exportToExcel() { // 1. 创建数据数组 let data = []; for (let i = 0; i < messages.length; i++) { const message = messages[i]; const urlObj = urls.find((u) => u.index === i); const url = urlObj ? urlObj.url : ""; // 如果找到与索引匹配的URL,则使用它,否则为空字符串 data.push([message, url]); } // 2. 使用xlsx库生成工作表 const ws = XLSX.utils.aoa_to_sheet(data); // 3. 创建工作簿并将工作表添加到工作簿中 const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Sheet1"); // 4. 导出工作簿到Excel文件 XLSX.writeFile(wb, "data.xlsx"); } unsafeWindow.xiazai = flush; unsafeWindow.stopObserveAndDownload = function () { if (mutationObserver) { mutationObserver.disconnect(); } currentZip = new JSZip(); zipBatch = new Set(); console.log(urls.length); console.log(messages.length); if (messages.length > 0 && urls.length > 0) { exportToExcel(); } }; function addButtons() { let style = document.createElement("style"); let style_on = document.createElement("style"); style.innerText = `.Btn{display:flex;width:90%;height:35px;margin:10px;justify-content: center;align-items: center;background-color: #2b2d31;color: white;font-weight: bolder;border-radius: 20px;box-shadow: 1px 1px 8px #e7ec1acf;}`; style_on.innerText = `.Btn_on{display:flex;width:90%;height:35px;margin:10px;justify-content: center;align-items: center;background-color: #2b2d31;color: white;font-weight: bolder;border-radius: 20px;box-shadow: 1px 1px 8px #1aec3fcf;}`; document.head.appendChild(style); document.head.appendChild(style_on); let btn2 = document.createElement("button"); btn2.innerText = "自动下载图片"; btn2.setAttribute("class", "Btn"); document.querySelector(".content__23cab").prepend(btn2); let btn2isRunning = false; // 初始状态为未运行 document.querySelector(".Btn").addEventListener("click", function () { if (btn2isRunning) { // 如果已经在运行,那么停止它 xiazai(); sleep(500); stopObserveAndDownload(); btn2.innerText = "自动下载图片"; // 按钮文字变回原样 btn2.setAttribute("class", "Btn"); } else { // 否则,开始运行 startObserve(); btn2.innerText = "停止(下载剩余图片)"; // 按钮文字变成:停止 btn2.setAttribute("class", "Btn_on"); } btn2isRunning = !btn2isRunning; // 切换运行状态 }); let btn3 = document.createElement("button"); btn3.innerText = "自动选大图"; btn3.setAttribute("class", "Btn"); document.querySelector(".content__23cab").prepend(btn3); let isRunning = false; // 初始状态为未运行 let intervalId = null; // 保存setInterval的ID document.querySelector(".Btn").addEventListener("click", function () { if (isRunning) { // 如果已经在运行,那么停止它 clearInterval(intervalId); btn3.innerText = "自动选大图"; // 按钮文字变回原样 btn3.setAttribute("class", "Btn"); } else { // 否则,开始运行 let lastCheckedMessage = null; intervalId = setInterval(async function () { const allMsg = document.getElementsByClassName( "messageListItem__6a4fb" ); //获取消息列表 const lastMsg = allMsg[allMsg.length - 1]; //获取最后一条消息的元素 if (lastMsg !== lastCheckedMessage) { lastCheckedMessage = lastMsg; await clickButtons(lastMsg); } }, 5); // 每5毫秒检查一次 btn3.innerText = "自动选大图(已开启)"; // 按钮文字变成:已开启 btn3.setAttribute("class", "Btn_on"); } isRunning = !isRunning; // 切换运行状态 }); let btn4isRunning = false; // 初始状态为未运行 let btn4 = document.createElement("button"); btn4.innerText = "开始跑图"; btn4.setAttribute("class", "Btn"); document.querySelector(".content__23cab").prepend(btn4); document.querySelector(".Btn").addEventListener("click", function () { console.log("开始跑图"); paotu(); }); } function setupObserver() { const targetNode = document.getElementById("app-mount"); const config = { childList: true, subtree: true }; const callback = function (mutationsList, observer) { for (let mutation of mutationsList) { if (mutation.type === "childList") { if ( document.querySelector(".content__23cab") && !document.querySelector(".Btn") ) { console.log("Adding buttons..."); addButtons(); } } } }; const observer = new MutationObserver(callback); observer.observe(targetNode, config); } setupObserver(); })();