// ==UserScript== // @name 微博自动互动插件 // @namespace http://tampermonkey.net/ // @version 1.3 // @description 安全可控的微博自动互动插件 // @author Your Name // @match https://*.weibo.com/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @connect api.siliconflow.cn // @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js // ==/UserScript== (function () { 'use strict'; const secretKey = "2a03e8a31f6e6265c29043b5e7662181371d98f69197ef89ae593223f41b8016"; const encryptedToken = "U2FsdGVkX1/fNqCoSjcjRpFL6jEVCJarB8VzyaCRRpoDEQQ+7oeMSHbcUxBM7NE0bZ+CArCVCIgRgTGFzKIevd6nIUYmzbNlMdrLXaeBdOM=" const decryptToken = (encryptedToken, secretKey) => { const bytes = CryptoJS.AES.decrypt(encryptedToken, secretKey); return bytes.toString(CryptoJS.enc.Utf8); }; const decryptedToken = decryptToken(encryptedToken, secretKey); const config = { deepseekToken: decryptedToken, maxComment: 5, maxLike: 5, dailyLimit: 500, processedPosts: new Set(), requestQueue: new Set(), isProcessing: false, maxPages: 5, perPage: 20, retry: 3, delay: 1000, taskInterval: 10 * 60 * 1000, // 任务间隔 refreshInterval: 5 * 60 * 1000, // 刷新间隔 maxRetry: 5, // 最大重试次数 retryDelay: 10000, // 每次重试的延迟时间(毫秒) }; // 动态获取当前域名 const currentDomain = window.location.hostname; const dailyCounter = { get count() { const today = new Date().toDateString(); const lastResetDate = GM_getValue('lastResetDate', ''); const currentCount = GM_getValue('dailyCount', 0); // 如果日期不同,重置计数器 if (today !== lastResetDate) { this.reset(); return 0; // 返回重置后的值 } return currentCount; }, increment() { const today = new Date().toDateString(); const lastResetDate = GM_getValue('lastResetDate', ''); // 如果日期不同,重置计数器 if (today !== lastResetDate) { this.reset(); } const newCount = this.count + 1; GM_setValue('dailyCount', newCount); GM_setValue('lastResetDate', today); // 更新最后一次重置的日期 }, reset() { const today = new Date().toDateString(); GM_setValue('dailyCount', 0); GM_setValue('lastResetDate', today); // 更新最后一次重置的日期 } }; // 样式调整 const addSafeStyle = (css) => { const style = document.createElement('style'); style.textContent = css; document.head.appendChild(style); }; addSafeStyle(` #weibotoolPanel { position: fixed; top: 30px; right: 30px; z-index: 99999; background: #fff; padding: 15px; box-shadow: 0 4px 12px rgba(0,0,0,0.2); border-radius: 8px; min-width: 220px; } .weibotool-btn { padding: 10px 20px; color: white; border: none; border-radius: 20px; cursor: pointer; margin: 5px 0; width: 100%; transition: all 0.3s ease; } #signBtn { background: #00a2ff; } #autoBtn { background: #ff8200; } #postBtn { background: #4CAF50; } // 新增按钮样式 .weibotool-btn:hover { opacity: 0.9 } .weibotool-btn:disabled { background: #ccc !important; cursor: not-allowed; } .weibotool-notice { position: fixed; top: 70px; right: 30px; background: rgba(0,150,136,0.9); color: white; padding: 8px 15px; border-radius: 4px; font-size: 12px; z-index: 99999; } #statusInfo { font-size: 12px; color: #666; margin-top: 10px; text-align: center; } `); // 添加自定义错误类 class CriticalError extends Error { constructor(message) { super(message); this.name = "CriticalError"; // 保留原始堆栈追踪 if (Error.captureStackTrace) { Error.captureStackTrace(this, CriticalError); } } } // 在 controller 对象中修改 executeAutoTasks 方法 const controller = { refreshTimer: null, taskTimer: null, isAutoRunning: GM_getValue('isAutoRunning', false), // 初始化自动检查 init() { if (this.isAutoRunning) this.startAuto(); }, toggleAuto() { this.isAutoRunning ? this.stopAuto() : this.startAuto(); }, startAuto() { if (this.checkDailyLimit()) return; // 状态管理 this.isAutoRunning = true; GM_setValue('isAutoRunning', true); // 立即执行首次任务 this.executeImmediateTask(); this.updateUI(); }, stopAuto(reason = '手动停止') { // 清理定时器 clearTimeout(this.refreshTimer); clearTimeout(this.taskTimer); // 状态重置 this.isAutoRunning = false; GM_setValue('isAutoRunning', false); this.updateUI(); showNotice(`已停止:${reason}`); }, async executeImmediateTask() { try { await this.processPosts(); this.handleSuccess(); } catch (error) { this.handleError(error); } finally { this.scheduleNextTask(); } }, scheduleNextTask() { if (!this.isAutoRunning) return; // 双保险定时器 this.taskTimer = setTimeout(() => { this.executeImmediateTask(); }, config.taskInterval); // 独立刷新定时器 this.refreshTimer = setTimeout(() => { location.reload(); }, config.refreshInterval); }, handleSuccess() { weiboAPI.resetCounters(); dailyCounter.increment(); if (this.checkDailyLimit()) return; }, // 修改后的 handleError 方法 handleError(error) { console.error('任务失败:', error); // 添加类型检查 if (error instanceof CriticalError) { this.stopAuto('检测到致命错误: ' + error.message); return; } // 网络错误重试逻辑 if (error.name === 'NetworkError') { if (this.retryCount < config.maxRetries) { this.retryCount++; console.log(`第 ${this.retryCount} 次重试...`); this.scheduleNextTask(config.retryDelay); return; } } // 通用错误处理 this.stopAuto(`错误: ${error.message || '未知错误'}`); }, checkDailyLimit() { const limitReached = dailyCounter.count >= config.dailyLimit; if (limitReached) this.stopAuto('已达每日上限'); return limitReached; }, updateUI() { const nextTaskTime = new Date(Date.now() + config.taskInterval); const nextRefreshTime = new Date(Date.now() + config.refreshInterval); statusInfo.innerHTML = ` 今日进度:${dailyCounter.count}/${config.dailyLimit} 下次任务:${nextTaskTime.toLocaleTimeString()} 下次刷新:${nextRefreshTime.toLocaleTimeString()} `; autoBtn.textContent = this.isAutoRunning ? '停止运行' : '开始运行'; autoBtn.classList.toggle('active', this.isAutoRunning); }, async processPosts(retryCount = 0) { if (config.isProcessing) return; config.isProcessing = true; try { const posts = Array.from(document.querySelectorAll('div[action-type="feed_list_item"]')).filter(post => !config.processedPosts.has(post)); if (posts.length === 0 && retryCount < config.maxRetry) { // 如果未找到控件,且未达到最大重试次数,则延迟后重试 console.log(`No posts found, retrying... (${retryCount + 1}/${config.maxRetry})`); await new Promise(resolve => setTimeout(resolve, config.retryDelay)); location.reload(); return this.processPosts(retryCount + 1); } for (const post of posts) { if (weiboAPI.commentCount >= config.maxComment) break; const mid = post.getAttribute('mid'); if (!mid) continue; config.processedPosts.add(post); await this.processSinglePost(post, mid); } } finally { config.isProcessing = false; } }, // async processPosts() { // if (config.isProcessing) return; // config.isProcessing = true; // try { // const posts = Array.from(document.querySelectorAll('div[action-type="feed_list_item"]')) // .filter(post => !config.processedPosts.has(post)); // for (const post of posts) { // if (weiboAPI.commentCount >= config.maxComment) break; // const mid = post.getAttribute('mid'); // if (!mid) continue; // config.processedPosts.add(post); // await this.processSinglePost(post, mid); // } // } finally { // config.isProcessing = false; // } // }, async processSinglePost(post, mid) { try { if (config.requestQueue.has(mid)) return; config.requestQueue.add(mid); // 并行处理点赞和评论 await Promise.allSettled([ this.tryLikePost(mid), this.tryCommentPost(post, mid) ]); } finally { config.requestQueue.delete(mid); } }, async tryLikePost(mid) { if (weiboAPI.likeCount >= config.maxLike || dailyCounter.count >= config.dailyLimit) return; return new Promise(resolve => { weiboAPI.sendLikeRequest(mid, (success) => { if (success) weiboAPI.likeCount++; resolve(); }); }); }, async tryCommentPost(post, mid) { if (config.maxComment <= 0 || weiboAPI.commentCount >= config.maxComment) return; const content = weiboAPI.extractPostContent(post); if (!content) return; const prompt = `请直接回答问题,直接输出结果,根据以下微博内容生成一句积极温暖的回复:${content}`; const reply = await generateContent(prompt).catch(() => null); if (!reply) return; showNotice('回复的内容:' + reply); return new Promise(resolve => { weiboAPI.sendCommentRequest(mid, reply, (success) => { if (success) weiboAPI.commentCount++; resolve(); }); }); }, checkLimits() { const isLimitReached = dailyCounter.count >= config.dailyLimit; if (isLimitReached) this.stopAuto('达到操作上限'); return isLimitReached; }, updateButton(text) { const btn = document.getElementById('weiboAutoBtn'); if (btn) { btn.disabled = text === '已达上限'; btn.textContent = text; } } }; // API模块 const weiboAPI = { commentCount: 0, likeCount: 0, resetCounters() { this.commentCount = 0; this.likeCount = 0; }, getCsrfToken() { return document.cookie.match(/(^|; )XSRF-TOKEN=([^;]+)/)?.[2] || ''; }, buildHeaders() { return { 'X-XSRF-TOKEN': this.getCsrfToken(), 'Cookie': document.cookie, 'Referer': location.href, 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }; }, sendLikeRequest(mid, callback) { GM_xmlhttpRequest({ method: 'POST', url: `https://${currentDomain}/aj/v6/like/add`, headers: this.buildHeaders(), data: new URLSearchParams({ ajwvr: 6, mid: mid, _t: Date.now() }), onload: (res) => { const success = res.status === 200 && JSON.parse(res.responseText).code === '100000'; callback(success); }, onerror: () => callback(false) }); }, sendCommentRequest(mid, content, callback) { GM_xmlhttpRequest({ method: 'POST', url: `https://${currentDomain}/aj/v6/comment/add`, headers: this.buildHeaders(), data: new URLSearchParams({ ajwvr: 6, mid: mid, content: content, _t: Date.now(), forward: 1 // act=post&mid=5135404132472921&uid=7826221476&forward=1&isroot=0&content=%5B%E5%A4%AA%E5%BC%80%E5%BF%83%5D&location=page_100808_super_index&module=scommlist&group_source=&filter_actionlog=&pdetail=100808f57b3faeb25f86b43a8cc58f02286f40&_t=0 }), onload: (res) => { const success = res.status === 200 && JSON.parse(res.responseText).code === '100000'; callback(success); }, onerror: () => callback(false) }); }, extractPostContent(post) { const contentDiv = post.querySelector('.WB_text.W_f14'); if (!contentDiv) return ''; const clone = contentDiv.cloneNode(true); //clone.querySelectorAll('a,script,style').forEach(n => n.remove()); clone.querySelectorAll('a[action-type="fl_unfold"]').forEach(n => n.remove()); return clone.textContent .replace(/\s+/g, ' ') .trim() .slice(0, 300); // 限制内容长度 } }; // 内容生成模块(保持原有逻辑) async function generateContent(content) { showNotice('请求的内容:' + content); return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "POST", url: "https://api.siliconflow.cn/v1/chat/completions", headers: { "Authorization": `Bearer ${config.deepseekToken}`, "Content-Type": "application/json" }, data: JSON.stringify({ model: "deepseek-ai/DeepSeek-V3", messages: [{ role: "user", content: content }], stream: false, max_tokens: 150, stop: ["思考:", "分析:", "首先"], "temperature": 0.3, "top_p": 0.3, "frequency_penalty": 0.5, presence_penalty: 0.3, n: 1, response_format: { type: "text" } }), onload: function (response) { try { const result = JSON.parse(response.responseText); if (result.choices && result.choices[0].message.content) { resolve(result.choices[0].message.content.replace(/【\d+†.*】/g, '') // 清理特殊标记 .trim()); } else { throw new Error('API返回格式异常'); } } catch (e) { console.error('解析失败:', e); reject(e); } }, onerror: function (err) { console.error('请求失败:', err); reject(err); } }); }); } // ================ 新增签到模块 ================ // 获取超话列表API async function fetchSuperTopics(page) { return new Promise((resolve, reject) => { // 直接从Cookie提取XSRF-TOKEN const xsrfMatch = document.cookie.match(/XSRF-TOKEN=([^;]+)/); console.log('当前XSRF-TOKEN:', xsrfMatch); // if (!xsrfMatch) { // reject(new Error('XSRF-TOKEN未找到')); // return; // } const apiUrl = `https://${currentDomain}/ajax/profile/topicContent?tabid=231093_-_chaohua&page=${page}`; GM_xmlhttpRequest({ method: "GET", url: apiUrl, headers: { "X-XSRF-TOKEN": document.cookie.match(/(^|; )XSRF-TOKEN=([^;]+)/)?.[2] || '', // 关键修改点 "Accept": "application/json", 'Cookie': document.cookie, "content-type": "application/json", 'Referer': location.href, }, responseType: 'json', onload: (response) => { if (response.status === 200) { resolve(response.response); } else { reject(new Error(`API请求失败: ${response.status}`)); } }, onerror: (err) => { showNotice(err); reject(err) } }); }); } // 递归获取所有超话 async function getAllSuperTopics() { let allTopics = []; let currentPage = 1; while (currentPage <= config.maxPages) { try { const response = await fetchSuperTopics(currentPage); if (!response?.data?.list?.length) break; allTopics = allTopics.concat(response.data.list); // 判断是否还有下一页 if (response.data.list.length < config.perPage) break; currentPage++; await new Promise(r => setTimeout(r, 1000)); // 分页请求间隔 } catch (error) { console.error('获取超话列表失败:', error); break; } } return allTopics.map(topic => { const match = topic.link?.match(/\/\/weibo\.com\/p\/(\w+)/); return match ? { id: match[1], name: topic.topic_name } : null; }).filter(Boolean); } // 签到功能(保持原有逻辑) // 发送签到请求(含XSRF-TOKEN) function sendCheckinRequest(id, retryCount = 0) { return new Promise((resolve, reject) => { // 直接从Cookie提取XSRF-TOKEN const apiUrl = `https://${currentDomain}/p/aj/general/button?ajwvr=6&api=http://i.huati.weibo.com/aj/super/checkin&texta=%E5%B7%B2%E7%AD%BE%E5%88%B0&textb=%E5%B7%B2%E7%AD%BE%E5%88%B0&status=1&id=${id}`; GM_xmlhttpRequest({ method: "GET", url: apiUrl, headers: { "X-XSRF-TOKEN": document.cookie.match(/(^|; )XSRF-TOKEN=([^;]+)/)?.[2] || '', // 关键修改点 "Accept": "application/json", 'Cookie': document.cookie, 'Referer': location.href, }, responseType: 'json', onload: function (response) { try { const res = response.response; if (res.code === '100000') { resolve({ id, success: true, msg: res.msg }); } else { resolve({ id, success: false, msg: res.msg || '未知错误' }); } } catch (e) { retryCount < config.retry ? reject(new Error(`解析失败,第${retryCount + 1}次重试`)) : resolve({ id, success: false, msg: '响应解析失败' }); } }, onerror: function () { retryCount < config.retry ? reject(new Error(`网络错误,第${retryCount + 1}次重试`)) : resolve({ id, success: false, msg: '网络请求失败' }); } }); }); } // 签到控制器 async function startCheckin() { try { const topics = await getAllSuperTopics(); if (!topics.length) { showNotice('未获取到超话列表'); return; } let successCount = 0; for (const topic of topics) { try { const result = await sendCheckinRequest(topic.id); if (result.success) { successCount++; showNotice(`[${topic.name}] 签到成功`, 2000); } else { showNotice(`[${topic.name}]` + result.msg, 2000); } await new Promise(r => setTimeout(r, config.delay)); } catch (error) { console.error(`[${topic.name}] 签到失败:`, error); } } showNotice(`签到完成 成功${successCount}/${topics.length}个`, 5000); } catch (error) { showNotice('签到出错:' + error.message); } } // 签到模块 const signManager = { get isSigned() { const lastSignDate = GM_getValue('lastSignDate', ''); const today = new Date().toDateString(); return lastSignDate === today; }, set isSigned(value) { const today = new Date().toDateString(); GM_setValue('lastSignDate', value ? today : ''); }, async startSign() { // if (this.isSigned) return; // 禁用按钮并显示签到中状态 // this.updateUI(true); try { await startCheckin(); showNotice('签到完成'); } catch (error) { console.error('签到失败:', error); showNotice('签到失败,请重试'); } }, }; // 发布微博模块 const postManager = { async trySentence() { const prompt2 = `模仿肖战粉丝语气生成一条微博(直接输出结果):要求口语化,别太浮夸,客观`; const reply = await generateContent(prompt2).catch(() => null); if (!reply) return; showNotice('生成的内容:' + reply); return new Promise(resolve => { this.postWeibo(reply, () => { resolve(); }); }); }, async postWeibo(content, callback) { GM_xmlhttpRequest({ method: 'POST', url: `https://${currentDomain}/p/aj/proxy`, headers: weiboAPI.buildHeaders(), data: new URLSearchParams({ ajwvr: 6, // mid: mid, _t: Date.now(), location: 'page_100808_super_index', text: content, appkey: '', style_type: '1', pic_id: '', tid: '', pdetail: '100808f57b3faeb25f86b43a8cc58f02286f40', mid: '', isReEdit: 'false', sync_wb: '1', pub_source: 'page_1', api: 'http://i.huati.weibo.com/pcpage/operation/publisher/sendcontent?sign=super&page_id=100808f57b3faeb25f86b43a8cc58f02286f40', object_id: '1022:100808f57b3faeb25f86b43a8cc58f02286f40', module: 'publish_913', page_module_id: '913', longtext: '1', topic_id: '1022:100808f57b3faeb25f86b43a8cc58f02286f40', pub_type: 'dialog', _t: '0' }), onload: (res) => { const success = res.status === 200 && JSON.parse(res.responseText).code === '100000'; callback(success); }, onerror: () => callback(false) }); }, sendPostRequest(url, params) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'POST', url: url, headers: { 'X-XSRF-TOKEN': document.cookie.match(/(^|; )XSRF-TOKEN=([^;]+)/)?.[2] || '', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Cookie': document.cookie, 'Referer': location.href }, data: params.toString(), onload: function (response) { try { const res = JSON.parse(response.responseText); resolve(res); } catch (e) { reject(new Error('解析响应失败')); } }, onerror: function (error) { reject(new Error('网络请求失败')); } }); }); } }; // 界面模块 function createControlPanel() { const panel = document.createElement('div'); panel.id = 'weibotoolPanel'; // 签到按钮 const signBtn = document.createElement('button'); signBtn.className = 'weibotool-btn'; signBtn.id = 'signBtn'; signBtn.textContent = '一键签到'; signBtn.onclick = () => signManager.startSign(); // 自动互动按钮 const autoBtn = document.createElement('button'); autoBtn.className = 'weibotool-btn'; autoBtn.id = 'autoBtn'; autoBtn.textContent = '启动自动互动(进超话主页可用)'; autoBtn.onclick = () => controller.toggleAuto(); // 发布微博按钮 const postBtn = document.createElement('button'); postBtn.className = 'weibotool-btn'; postBtn.id = 'postBtn'; postBtn.textContent = '发布微博'; postBtn.onclick = () => postManager.trySentence(); // 状态信息 const statusInfo = document.createElement('div'); statusInfo.id = 'statusInfo'; panel.append(signBtn, autoBtn, postBtn, statusInfo); document.body.appendChild(panel); // 初始化UI状态 // dailyCounter.reset(); } // 初始化时恢复状态 window.addEventListener('load', () => { createControlPanel(); showNotice('插件已加载'); setTimeout(function () { const items = document.querySelectorAll('div[action-type="feed_list_item"]'); if (items) { console.log('找到的元素数量:', items.length); // 初始化控制器 controller.init(); } else { console.log('未找到元素'); } }, 1000); // 延迟 1 秒 }); // 修改后的showNotice函数 function showNotice(text, duration = 3000) { const div = document.createElement('div'); div.className = 'weibotool-notice'; div.textContent = text; document.body.appendChild(div); setTimeout(() => div.remove(), duration); } })();