// ==UserScript== // @name 微博精选蓝V互动 // @namespace http://tampermonkey.net/ // @version 1.2 // @description 微博精选蓝V互动 // @match https://*.weibo.com/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @connect weibo.com // @connect ark.cn-beijing.volces.com // @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js // ==/UserScript== (function () { 'use strict'; // 动态获取当前域名 const currentDomain = window.location.hostname; // 返回类似 "weibo.com" 或 "m.weibo.com" // 将密钥转换为字节数组 function keyToBytes(key) { const bytes = []; for (let i = 0; i < key.length; i += 2) { bytes.push(parseInt(key.substr(i, 2), 16)); } return bytes; } // XOR 加密/解密函数 function xorCrypto(input, keyBytes) { let output = ""; for (let i = 0; i < input.length; i++) { const charCode = input.charCodeAt(i) ^ keyBytes[i % keyBytes.length]; output += String.fromCharCode(charCode); } return output; } // 加密函数 function encrypt(plaintext, SECRET_KEY) { const keyBytes = keyToBytes(SECRET_KEY); return btoa(xorCrypto(plaintext, keyBytes)); // 使用 Base64 编码 } // 解密函数 function decryptToken(ciphertext, SECRET_KEY) { const keyBytes = keyToBytes(SECRET_KEY); const decoded = atob(ciphertext); // 使用 Base64 解码 return xorCrypto(decoded, keyBytes); } // 使用示例 --------------------------------------------------- // 生成密钥(推荐使用安全随机数生成) const secretKey = "666f2fdde94d9f0d1120404a85b1d800494556a7815bef3c526389ea523c45f4"; // CryptoJS.lib.WordArray.random(256/8).toString(); const encryptedToken = "A1wd698rqTw8QyUvt5zsYnEge57iOd0RYga60mBfJ5JUWRbq"; //"e3266f61-cee2-4b8e-9cb2-0e382cbf2697" // 解密验证 // const decryptToken = (encryptedToken, secretKey) => { // const bytes = CryptoJS.AES.decrypt(encryptedToken, secretKey); // return bytes.toString(CryptoJS.enc.Utf8); // }; const decryptedToken = decryptToken(encryptedToken, secretKey); const CONFIG = { checkInterval: 300000, maxCommentsPerDay: 20, since_id: GM_getValue('since_id', '0'), deepseekToken: decryptedToken, pageSize: 20, // 每页请求数量 maxPages: 5, // 最大翻页次数 //verifiedType: true // 认证类型 verifiedType: 3, blueVContainerId: "102803600057", // 蓝V集中板块 minFollowers: 100000 // 最小粉丝数要求 // verified_type 的其他常见值: // 1:企业认证用户 // 2:媒体认证用户 // 3:政府机构认证用户 // 4:校园认证用户 // verified_type_ext 的其他常见值: // 0:无额外认证信息 // 1:蓝V用户(通常是企业或组织) // 3:黄V用户(通常是政务账号) }; // 全局状态 let timer = null; let toggleButton = null; let countElement = null; // 初始化入口 function init() { initPanel(); initEventListeners(); resetDailyCount(); updateCounter(); } // 获取CSRF Token function getXsrfToken() { const match = document.cookie.match(/XSRF-TOKEN=([^;])/); return match ? decodeURIComponent(match[1]) : ''; } // 初始化控制面板 function initPanel() { GM_addStyle(` #weibo-comment-panel { position: fixed; top: 100px; right: 20px; background: #fff; padding: 15px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); z-index: 99999; } #toggleBtn { margin-top: 10px; padding: 5px 15px; cursor: pointer; } `); const panelHTML = `

自动评论状态

今日已评论:0/${CONFIG.maxCommentsPerDay}

`; const panel = document.createElement('div'); panel.id = 'weibo-comment-panel'; panel.innerHTML = panelHTML; document.body.appendChild(panel); // 获取元素引用 toggleButton = document.getElementById('toggleBtn'); countElement = document.getElementById('commentCount'); } // 初始化事件监听 function initEventListeners() { if (toggleButton) { toggleButton.addEventListener('click', handleToggle); } else { console.error('无法找到切换按钮'); } } // 主流程控制 async function mainProcess() { try { const todayCount = GM_getValue('dailyCount', 0); if (todayCount >= CONFIG.maxCommentsPerDay) { stopTimer(); return; } await processWeibo(); updateCounter(); } catch (e) { console.error('处理失败:', e); } } // 获取微博列表(修改版) function fetchWeiboList(max_id = 0) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", // url: `https://weibo.com/ajax/feed/hottimeline?since_id=0&refresh=0&group_id=102803&containerid=102803&extparam=discover%7Cnew_feed&max_id=0&count=10`, // url: `https://weibo.com/ajax/feed/hottimeline?refresh=1&group_id=102803&containerid=102803&extparam=discover%7Cnew_feed&count=${CONFIG.pageSize}&max_id=${max_id}`, url: `https://${currentDomain}/ajax/feed/hottimeline?since_id=0&refresh=1&group_id=${CONFIG.blueVContainerId}&containerid=102803_ctg1_600057_-_ctg1_600057&extparam=discover%7Cnew_feed%7Cblue_v&count=${CONFIG.pageSize}&max_id=${max_id}`, headers: { "X-Requested-With": "XMLHttpRequest", "Cookie": document.cookie }, onload: (res) => { try { const data = JSON.parse(res.responseText); if (data.ok === 1) { resolve({ statuses: data.statuses, next_max_id: data.max_id }); console.debug('蓝V列表获取成功:', data.statuses.length, '条'); } } catch (e) { reject(e) } }, onerror: reject }); }); } function postComment(weiboId, content) { console.log('评论内容:', content); return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "POST", url: `https://${currentDomain}/ajax/comments/create`, headers: { "Content-Type": "application/x-www-form-urlencoded", "X-XSRF-TOKEN": document.cookie.match(/(^|; )XSRF-TOKEN=([^;]+)/)?.[2] || '', "Cookie": document.cookie }, data: `id=${weiboId}&comment=${encodeURIComponent(content)}&pic_id=&is_repost=0&comment_ori=0&is_comment=0`, onload: function(res) { try { const data = JSON.parse(res.responseText); // 双重校验机制 if (res.status === 200 && data?.ok === 1) { console.log('评论成功:', data); resolve(data); } else { console.error('评论失败:', data?.msg || '未知错误'); reject(new Error(data?.msg || `HTTP ${res.status}`)); } } catch (e) { reject(e); } }, onerror: function(err) { reject(err); } }); }); } // 处理微博内容(修改版) async function processWeibo() { try { const todayCount = GM_getValue('dailyCount', 0); if (todayCount >= CONFIG.maxCommentsPerDay) return; let currentMaxId = 0; let remainingPages = CONFIG.maxPages; let totalProcessed = 0; while (remainingPages-- > 0 && totalProcessed < CONFIG.maxCommentsPerDay) { const { statuses, next_max_id } = await fetchWeiboList(currentMaxId); currentMaxId = next_max_id; const targetWeibos = statuses.filter(weibo => weibo.user?.verified_type == CONFIG.verifiedType // && // weibo.user?.followers_count >= CONFIG.minFollowers && // 粉丝数过滤 // CONFIG.keywords.some(keyword => // weibo.text_raw.includes(keyword) // ) ); console.log(`本轮获取${statuses.length}条,蓝V有效微博${targetWeibos.length}条`); for (const weibo of targetWeibos) { if (GM_getValue('dailyCount', 0) >= CONFIG.maxCommentsPerDay) break; await new Promise(r => setTimeout(r, 2000)); const content = await generateContent(weibo.text_raw); await postComment(weibo.id, content); GM_setValue('dailyCount', GM_getValue('dailyCount', 0) + 1); totalProcessed; } if (!currentMaxId || currentMaxId === "0") { console.log('已达列表末尾,停止翻页'); break; } // if (!currentMaxId || targetWeibos.length >= CONFIG.pageSize) break; } } catch (e) { console.error('处理失败:', e); } } // 按钮点击处理(修复版) function handleToggle() { if (timer) { stopTimer(); } else { startTimer(); // 立即执行一次 mainProcess().catch(console.error); } updateButtonState(); } // 启动定时器 function startTimer() { if (!timer) { timer = setInterval(() => { mainProcess().catch(console.error); }, CONFIG.checkInterval); } } // 停止定时器 function stopTimer() { if (timer) { clearInterval(timer); timer = null; } } // 更新按钮状态 function updateButtonState() { if (toggleButton) { toggleButton.textContent = timer ? '暂停' : '启动'; toggleButton.style.backgroundColor = timer ? '#ff4444' : '#4CAF50'; } } // 更新计数器 function updateCounter() { if (countElement) { countElement.textContent = GM_getValue('dailyCount', 0); } } // 每日重置计数器 function resetDailyCount() { const lastDate = GM_getValue('lastDate', ''); const today = new Date().toDateString(); if (lastDate !== today) { GM_setValue('dailyCount', 0); GM_setValue('lastDate', today); updateCounter(); } } function generateContent(content) { // button.disabled = true; // button.textContent = '生成中...'; console.log("需要回复的内容:", content) const prompt = `根据以下微博内容生成一句积极温暖的回复(口语化、带表情符号、不超过20字):${content}`; return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "POST", url: "https://ark.cn-beijing.volces.com/api/v3/chat/completions", headers: { Authorization: `Bearer ${CONFIG.deepseekToken}`, "Content-Type": "application/json", }, data: JSON.stringify({ model: "deepseek-v3-241226", messages: [ { role: "user", content: prompt, }, ], stream: false, max_tokens: 150, stop: ["思考:", "分析:", "首先"], temperature: 0.5, top_p: 0.8, frequency_penalty: 0.3, 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); } }); }); } // 页面加载完成后初始化 if (document.readyState === 'complete') { init(); } else { window.addEventListener('load', init); } })();