微博精选蓝V互动
// ==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 = `
<h3 style="margin:0 0 10px 0; font-size:16px;">自动评论状态</h3>
<p>今日已评论:<span id="commentCount">0</span>/${CONFIG.maxCommentsPerDay}</p>
<button id="toggleBtn">启动</button>
`;
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);
}
})();