您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
批量修改微博可见范围
// ==UserScript== // @name Weibo All Hidden // @namespace http://tampermonkey.net/ // @version 0.1.5 // @description 批量修改微博可见范围 // @author Wei // @match http*://*weibo.com* // @match https://weibo.com/comment/outbox // @match https://weibo.com/u/* // @icon https://www.google.com/s2/favicons?sz=64&domain=weibo.com // @grant none // @license MIT // ==/UserScript== class W { privateAttributes = [// 0: ref; 1: original event; 2: css; 3: w label {name: 'w-group', typ: 3}, {name: 'w-verify', typ: 3}, {name: 'w-ref', typ: 0}, {name: 'w-click', typ: 1}, {name: 'w-display', typ: 2}, {name: 'w-weight', typ: 2}, {name: 'w-height', typ: 2}, ] constructor() { this.ref = {} this.v2H = [] this.variable = (v) => { setTimeout(() => { this.updateHtml(); }, 1) return v; } } init() { let wEle = document.getElementsByClassName('w') // 判断元素中是否有privateAttributes for (let i = 0; i < wEle.length; i++) { let ele = wEle[i] let group = null let verify = false this.privateAttributes.forEach((att) => { let attValue = ele.getAttribute(att.name) if (attValue !== null) { const name = att.name.replace('w-', '') if (att.typ === 0) { // w-ref this.ref[attValue] = ele } else if (att.typ === 1) { // event let f = eval(attValue) if (group) { group.forEach((item) => { item.addEventListener(name, () => { f(item.value) }, false) }) } else { ele.addEventListener(name, () => { verify ? (window.confirm("确定执行么?") ? f(ele.id) : '') : f(ele.id) }, false) } } else if (att.typ === 2) { // css ele.style[name] = attValue } else if (att.typ === 3) { // group if (name === 'group') group = Array.from(ele.getElementsByClassName(attValue)) if (name === 'verify') verify = true; } } //正则匹配 ele.innerHTML 中是否含有 {{xxx}} 并且ele要为最小元素 匹配所有结果 let reg = /{{(.*?)}}/g let matches; let v2HInfo = { element: ele, orgHTML: ele.innerHTML, mv: [] } let matchFlag = false while ((matches = reg.exec(ele.innerHTML)) !== null && ele.childElementCount === 0) { matchFlag = true; let match = matches[0]; // 匹配的完整字符串,例如 "{{var1}}" let variable = matches[1]; v2HInfo.mv.push({ match: match, variable: variable, }) } if (matchFlag) { //console.log(v2HInfo) this.v2H.push(v2HInfo) } }) } this.updateHtml() } updateHtml() { this.v2H.forEach((v2HInfo) => { let orgHTML = v2HInfo.orgHTML v2HInfo.mv.forEach((item) => { orgHTML = orgHTML.replace(item.match, eval(item.variable)) }) v2HInfo.element.innerHTML !== orgHTML ? (v2HInfo.element.innerHTML = orgHTML): '' }) } } let w = new W() let f1 = true let f2 = true let userInfo = { X_XSRF_TOKEN: null, uid: null, status: null, name: null, count: null, wbInfo: [], wbVisibleInfo: { 0: 0, 10: 0, 2: 0, 1: 0 }, processGet: 0, processSkip: 0, modifyVisibleType: null, modifyVisibleTextList: { 0: "公开", 10: "粉丝", 2: "朋友", 1: "仅自己", }, processModifyVisible: 0, error: "点击查看错误", hasWWW: false, cmtTotal: 0, cmtPublicTotal: 0, cmtGet: 0, }; function get(url, data, callback){ //创建异步对象 var xhr = null if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else if(window.ActiveXObject) {//IE6及以下 xhr = new ActiveXObject('Microsoft.XMLHTTP'); } //判断data是否为空 if(data){ url=url+'?'+params(data); } //设置请求行 xhr.open('get',url); //设置请求头(get可以省略) xhr.setRequestHeader("x-xsrf-token",userInfo.X_XSRF_TOKEN); //注册回调函数 xhr.onreadystatechange = function(){ if(xhr.readyState==4&&xhr.status==200){ //调用传递的回调函数 callback(xhr.responseText); } } //发送请求主体 xhr.send(null); } function post(url, data, callback){ //创建异步对象 var xhr = null if (window.XMLHttpRequest) { xhr = new XMLHttpRequest(); } else if(window.ActiveXObject) {//IE6及以下 xhr = new ActiveXObject('Microsoft.XMLHTTP'); } //设置请求行 xhr.open('post',url); //设置请求头(post有数据发送才需要设置请求头) //判断是否有数据发送 xhr.setRequestHeader("x-xsrf-token",userInfo.X_XSRF_TOKEN); if(data){ xhr.setRequestHeader("Content-type","application/json; charset=utf-8"); } //注册回调函数 xhr.onreadystatechange = function(){ if(xhr.readyState==4&&xhr.status==200){ //调用传递的回调函数 callback(xhr.responseText); } else { throw new Error('error'); } } //发送请求主体 xhr.send(JSON.stringify(data)); } let getWb = () => { const paramsStr = window.location.href userInfo.hasWWW = paramsStr.search('www') === -1 ? '' : 'www.'; userInfo.uid = paramsStr.split("/").pop(); get(`https://${userInfo.hasWWW}weibo.com/ajax/profile/info?uid=${userInfo.uid}`, null, (e) => { let recvJson = JSON.parse(e); console.log(recvJson, recvJson.ok); userInfo.status = recvJson.ok; userInfo.name = recvJson.data.user.screen_name; userInfo.count = recvJson.data.user.statuses_count; w.updateHtml(); }) } let getAllWbID = () => { if (!userInfo.count || !userInfo.status) return; const pageCount = Math.ceil(userInfo.count/20); userInfo.wbInfo = []; userInfo.wbVisibleInfo = { 0:0, 10:0, 2:0, 1:0 } userInfo.processGet = w.variable(0); for (let i = 0; i < pageCount; i++) { //for (let i = 0; i < 1; i++) { setTimeout(() => { get(`https://${userInfo.hasWWW}weibo.com/ajax/statuses/mymblog?uid=${userInfo.uid}&page=${i+1}&feature=0`, null, (e) => { let recvJson = JSON.parse(e); let dataList = recvJson.data.list; for (let j =0; j<dataList.length;j++ ){ let item = dataList[j]; userInfo.wbInfo.push({ id: item.id, visible: item.visible.type, mblogid: item.mblogid }) userInfo.wbVisibleInfo[item.visible.type] += 1; userInfo.processGet += 1; w.updateHtml(); } }); }, 500 * i) } } let modifyVisible = () => { if(userInfo.modifyVisibleType === null) return; userInfo.processSkip = 0; userInfo.processModifyVisible = 0; let wbInfoNeedModify = []; let errorIndexList = []; for (let i = 0; i <userInfo.count; i++) { //for (let i = 0; i < 1; i++) { if(String(userInfo.wbInfo[i].visible) === userInfo.modifyVisibleType) { userInfo.processSkip += 1; userInfo.processModifyVisible += 1; w.updateHtml(); continue; } else { wbInfoNeedModify.push(i); errorIndexList.push(i); } } for (let i = 0; i <wbInfoNeedModify.length; i++) { setTimeout(() => { try{ post(`https://${userInfo.hasWWW}weibo.com/ajax/statuses/modifyVisible`, { ids:String(userInfo.wbInfo[wbInfoNeedModify[i]].id), visible:String(userInfo.modifyVisibleType), }, (e)=>{ userInfo.processModifyVisible += 1; errorIndexList.filter(item => item === wbInfoNeedModify[i]); w.updateHtml(); }) } catch (e) { userInfo.error += `<br>${e}<a href="https://weibo.com/${userInfo.uid}/${userInfo.wbInfo[errorIndexList[i]].mblogid}">${userInfo.wbInfo[errorIndexList[i]].mblogid}</a>` w.updateHtml(); } }, 1000 * i) } w.updateHtml(); } let getMyCmt = () => { userInfo.cmtGet = 0; userInfo.cmtPublicTotal = 0; let i = 0 let g = (nc) => { i += 1; if (i > 2) return get(`https://weibo.com/ajax/message/myCmt${nc ? '?max_id='+nc : ''}`, null, (e)=>{ let recvJson = JSON.parse(e); userInfo.cmtGet += recvJson.data.comments.length; userInfo.cmtTotal = w.variable(recvJson.data.total_number); recvJson.data.comments.forEach((item)=>{ // if (item.status.user.verified && item.status.user.verified_type in [0, 2]) { // userInfo.cmtPublicTotal += 1; // console.log(item.text) // } console.log(item.text, item.status.user.verified, item.status.user.verified_type) }); if (recvJson.data.comments.length > 1) { let nextCursor = recvJson.data.next_cursor; g(nextCursor) } }) }; g() } let initHtml = () => { var htmlCode = ` <style> .wb-tool { width: 300px; bottom: 20px; right: 20px; padding: 10px 10px 8px 10px; background-color: #eee; z-index: 9999; position: fixed; overflow: hidden; border-radius: 10px; transition: all 0.5s; box-shadow: 0 0 5px 2px rgba(0, 0, 0, .2); } .title { font-size: 22px; font-weight: 600; text-align: center; margin-top: 5px; } .note { font-size: 14px; font-weight: 600; color: #EE0000; } .info { font-size: 14px; font-weight: 600; color: #000; margin: 3px 0; } .btn { border: none; background-color: #fff; width: 100%; margin-top: 8px; padding: 8px; border-radius: 4px; transition: all 0.2s; display: inline-block; cursor: pointer; } .btn:hover { box-shadow: 0 0 5px 2px rgba(0, 0, 255, .2); } .btn-sm { width: 80%; margin: 0 10%; background-color: #f1f1f1; } .card { width: 100%; /*min-height: 100px;*/ background-color: #fff; border-radius: 10px; margin-top: 8px; overflow: hidden; transition: all 0.2s; } .card-title { font-size: 14px; font-weight: 600; color: #222; margin: 5px; } .card-info { margin: 5px; font-size: 14px; color: #000; } .error { width: calc(100% - 10px); height: 92px; border-radius: 8px; color: red; background-color: antiquewhite; overflow: auto; } </style> <div class="w wb-tool"> <div class="w title">微博工具</div> <p class="w note"> 注意事项: <br>1. 请谨慎使用,部分操作无法恢复! <br>2. "仅自己可见"无法隐藏"快转"的内容! </p> <div class="w info" id="info-token">Token状态:{{userInfo.X_XSRF_TOKEN?'获取成功':'获取失败'}}</div> <div class="w info" id="info-status">状态:{{userInfo.status?'Success':'Error'}}</div> <div class="w info" id="info-name">昵称:{{userInfo.name}}</div> <div class="w info" id="info-count">总微博数:{{userInfo.count}}</div> <button class="w btn" id="showCardModifyVisibleWb" w-click="onCardClick">微博可见范围修改</button> <button class="w btn" id="showCardDeletePublicCmt" w-click="onCardClick">微博公开评论删除</button> <div class="w card" w-ref="cardMVW" w-height="0"> <div class="w card-title">微博可见范围修改</div> <button class="w btn btn-sm" id="btnGetAllWb" w-verify w-click="getAllWbID">获取全部微博信息</button> <div class="w card-info">进度:{{userInfo.processGet}} / {{userInfo.count}}</div> <div class="w card-info" id="visibleInfo"> 公开:{{userInfo.wbVisibleInfo[0]}},粉丝:{{userInfo.wbVisibleInfo[10]}}, 朋友:{{userInfo.wbVisibleInfo[2]}},仅自己:{{userInfo.wbVisibleInfo[1]}} </div> <div class="w card-info" w-group="radio" w-click="(value) => userInfo.modifyVisibleType = w.variable(value)"> <input name="radio" type="radio" id="public" class="w radio" value="0"/> <label for="public">公开</label> <input name="radio" type="radio" id="fans" class="w radio" value="10"/> <label for="fans">粉丝</label> <input name="radio" type="radio" id="friends" class="w radio" value="2"/> <label for="friends">朋友</label> <input name="radio" type="radio" id="me" class="w radio" value="1"/> <label for="me">仅自己</label> </div> <button class="w btn btn-sm" id="btnModifyVisible" w-verify w-click="modifyVisible"> 全部转换到{{userInfo.modifyVisibleTextList[userInfo.modifyVisibleType]}} </button> <div class="w card-info" id="processModifyVisible"> 进度:{{userInfo.processModifyVisible}} / {{userInfo.count}}, 跳过:{{userInfo.processSkip}} / {{userInfo.count}} </div> <div class="w card-info error" id="error">{{userInfo.error}}</div> </div> <div class="w card" w-ref="cardDPC" w-height="0"> <div class="w card-title">微博公开评论删除</div> <button class="w btn btn-sm" id="btnGetAllCmt" w-click="getMyCmt">获取公开评论信息</button> <div class="w card-info">总共发出评论:{{userInfo.cmtTotal}}</div> <div class="w card-info">已经获取评论:{{userInfo.cmtGet}}</div> <div class="w card-info">公开评论数:{{userInfo.cmtPublicTotal}}</div> </div> </div> `; let insertElement = document.createElement("div"); insertElement.innerHTML = htmlCode; document.body.append(insertElement); } let onCardClick = (id) => { console.log(id) if (id === 'showCardModifyVisibleWb') { w.ref.cardMVW.style.height = (f1) ? '300px' : '0px' f1 = !f1 } if (id === 'showCardDeletePublicCmt') { w.ref.cardDPC.style.height = (f2) ? '200px' : '0px'; f2 = !f2 } } (function() { 'use strict'; window.onload=function(){ initHtml(); w.init() getWb(); // 劫持所有请求获取X__XSRF__TOKEN function addXMLRequestCallback(callback) { var oldSend, i; if (XMLHttpRequest.callbacks) { XMLHttpRequest.callbacks.push(callback); } else { XMLHttpRequest.callbacks = [callback]; oldSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function () { for (i = 0; i < XMLHttpRequest.callbacks.length; i++) { XMLHttpRequest.callbacks[i](this); } return oldSend.apply(this, arguments); }; } } XMLHttpRequest.prototype.wrappedSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader; XMLHttpRequest.prototype.setRequestHeader = function(header, value) { this.wrappedSetRequestHeader(header, value); if(!this.headers) { this.headers = {}; } header = header.replaceAll('-', '__') this.headers[header] = value; } let flag = false; addXMLRequestCallback(function (xhr) { xhr.addEventListener("load", function () { if (xhr.readyState == 4 && xhr.status == 200) { if(!flag && xhr.headers.hasOwnProperty('X__XSRF__TOKEN')) { userInfo.X_XSRF_TOKEN = w.variable(xhr.headers.X__XSRF__TOKEN) flag = true; } } }); }); } })();