微博批量删除隐藏助手(适配新版微博)

可指定日期、关键字对微博进行批量删除或设置为仅个人可见,可自动翻页

// ==UserScript==
// @name         微博批量删除隐藏助手(适配新版微博)
// @namespace    https://github.com/Meteor8
// @version      4.6
// @description  可指定日期、关键字对微博进行批量删除或设置为仅个人可见,可自动翻页
// @author       Meteora
// @match        *.weibo.com/*/profile*
// @match        *.weibo.com/p/*
// @match        *.weibo.com/u/*
// @grant        none
// @license      MIT
// ==/UserScript==

var intervalTime = 1500;    //操作间隔时间ms
var versionSel = 0; //微博版本选择
var keyWord = "";   //关键字
var endFlag = 0;    //尾页标志
var scrollCnt = 0;  //下滑次数
var failCnt = 0;    //失败次数
var failThreshold = 1;  //失败阈值
var dateFrom, dateTo;
var allFailCnt, allSucCnt;
var notComp = 0;  //是否为快转
allSucCnt = allFailCnt = 0
var episodeSucCnt = 0
dateFrom = "0-0-0";
dateTo = "9999-99-99"
var exeSelect=-1;   //操作类型:-1测试,0删除,1隐藏,2取消快转

var itemCntLast = 0;
var itemCntNew = 0;

function $(elem) {
    return document.querySelector(elem);
}
function $All(elem) {
    return document.querySelectorAll(elem);
}
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms))
}
function isDatePart(dateStr) {
    var parts;
    if (dateStr.indexOf("-") > -1) {
        parts = dateStr.split('-');
    } else if (dateStr.indexOf("/") > -1) {
        parts = dateStr.split('/');
    } else {
        return false;
    }
    if (parts.length < 3) {
        return false;
    }
    for (let i = 0; i < 3; i++) {
        if (isNaN(parts[i])) {
            return false;
        }
    }
    let y = parts[0];//年
    let m = parts[1];//月
    let d = parts[2];//日
    if (y > 9999) {
        return false;
    }
    if (m < 1 || m > 12) {
        return false;
    }
    switch (d) {
        case 29:
            if (m == 2) {
                if ((y / 100) * 100 == y && (y / 400) * 400 != y) {
                } else {
                    return false;
                }
            }
            break;
        case 30:
            if (m == 2) {
                return false;
            }
            break;
        case 31:
            if (m == 2 || m == 4 || m == 6 || m == 9 || m == 11) {
                return false;
            }
            break;
        default:
    }
    return true;
}
function dateComp(myDate, setDate){
    var md = new Array();
    var d0 = new Array();
    d0 = setDate.split("-")
    if(myDate[0]=="今" || myDate[myDate.length-1]=="前"){   //今天,10分钟前
        md = (new Date()).toLocaleDateString().split("/")
    }else if(myDate[myDate.length-1]=="日"){    // 1月1日
        md[0] = (new Date()).getFullYear()
        md[1] = myDate.split("月")[0]
        md[2] = myDate.split("月")[1].split("日")[0]
    }else{  //2012-1-15
        md = myDate.split("-")
    }
    for(let i in md) md[i]=parseInt(md[i]);
    for(let i in d0) d0[i]=parseInt(d0[i]);

    if(md[0]>d0[0]){
        return 1;
    }else if(md[0]==d0[0]){
        if(md[1]>d0[1]){
            return 1;
        }else if(md[1]==d0[1]){
            if(md[2]>d0[2]){
                return 1;
            }else if(md[2]==d0[2]){
                return 0;
            }
        }
    }
    return -1;
}

(function() {
    'use strict';
    window.onload = () => {
        //扫面页面,滑动到页面最底端
        async function scanPage(){
            var state = false;
            while(!state){
                scrollBy(0, 2000);
                scrollCnt++;
                console.log("*下滑"+scrollCnt)
                await sleep(1000);
                state = $('[node-type="feed_list_page"]') || (scrollCnt>15 && !($('[node-type="lazyload"]')))
            }
            console.log("#到底")
            scrollCnt = 0;
            if(!$('.page.next')){
                endFlag = 1;
                console.log("#尾页");
            }
        }

        async function nextPage(){
            $('.page.next').click();
            console.log("*翻页");
            await sleep(5000);
        }

        async function exeOp(){
            let allItems = $All('[action-type="feed_list_item"]');
            console.log("#本页共"+allItems.length+"条微博");
            for(let i=0;i<allItems.length;i++){
                let item = allItems[i];
                let content = item.querySelector('[node-type="feed_list_content"]').innerText;
                let wdate = item.querySelector(".S_txt2 > a").getAttribute("title").split(" ")[0]

                if(content.indexOf(keyWord)!=-1 && dateComp(wdate,dateFrom)>=0 && dateComp(wdate,dateTo)<=0){
                    item.querySelector('a[action-type="fl_menu"]').click();
                    await sleep(500);
                    if(exeSelect==-1){
                        console.log(wdate);
                        // if(dateComp(wdate,dateFrom)>=0 && dateComp(wdate,dateTo)<=0){
                        //     item.style.color = "blue";
                        // }
                        // item.remove();
                    }else if (exeSelect == 1 && item.getAttribute("action-data") == "cur_visible=0") { // 设为仅个人可见
                        let btntemp = item.querySelector('a[action-type="fl_personalVisible"]') || 
                                      Array.from(item.querySelectorAll('div.woo-box-flex.woo-box-alignCenter.woo-pop-item-main'))
                                          .find(el => el.textContent.includes("转换为自己可见"));
                    
                        if (btntemp) {
                            btntemp.click(); // 点击“设为仅个人可见”
                            await sleep(500);
                    
                            // 点击确认按钮
                            const confirmButton = item.querySelector('a[action-type="ok"]');
                            if (confirmButton) {
                                confirmButton.click();
                                await sleep(intervalTime);
                                console.log("*尝试隐藏" + i);
                            } else {
                                console.error("未找到确认按钮");
                            }
                        } else {
                            console.error("未找到设为仅个人可见的按钮");
                        }
                    }else if(exeSelect==0){ //删除微博
                        const delBtn = item.querySelector('a[action-type="feed_list_delete"]');
                        if(delBtn != null){
                            delBtn.click();
                            await sleep(500);
                            item.querySelector('a[action-type="ok"]').click();
                            await sleep(intervalTime);
                            console.log("*尝试删除"+i);
                        }else{
                            notComp = 1;
                        }
                    }else if(exeSelect==2){ //取消快转
                        const unFastBtn = item.querySelector('a[action-type="feed_list_delete_fast_reported"]');
                        if (unFastBtn != null){
                            unFastBtn.click();
                            await sleep(intervalTime);
                            console.log("*尝试取消快转"+i);
                        }else{
                            notComp = 1;
                        }
                    }

                    // 操作失败,否则成功
                    if($('[action-type="ok"]')){
                        if($('[node-type="text"]').innerText.indexOf("繁忙")!=-1 && failCnt<=failThreshold){
                            failCnt++;
                            console.log("#系统繁忙,3s后进行第"+(failCnt+1)+"次尝试"+i);
                            i--;
                            await sleep(3000);
                        }else{
                            failCnt = 0
                            allFailCnt++;
                            console.log("#操作失败"+i)  //打印失败原因
                        }
                        $('[action-type="ok"]').click();
                    }else{
                        if(notComp == 1){
                            notComp = 0;
                        }else{
                            allSucCnt++;
                            episodeSucCnt++;
                            console.log("#操作成功"+i);
                        }
                    }
                }
            }
        }

        async function mainLoop(){
            while(1){
                await scanPage();
                await exeOp();
                // await sleep(1000*15);
                if(endFlag) break;
                await nextPage();
            }
            alert("操作执行完毕\n共匹配符合条件微博:"+(allSucCnt+allFailCnt)+"条\n其中,操作成功"+allSucCnt+"条,失败"+allFailCnt+"条")
            console.log("#结束")
        }

        async function scrollPage(){
            while(scrollCnt < 2){
                scrollBy(0, 2000);
                scrollCnt++;
                console.log("*下滑"+scrollCnt)
                await sleep(1000);
            }
            scrollCnt = 0;
        }

        async function exeOpNew(item,i){
            let content = item.querySelector(".detail_wbtext_4CRf9").innerText;
            let wdate = item.querySelector(".head-info_time_6sFQg").getAttribute("title").split(" ")[0]

            if(content.indexOf(keyWord)!=-1 && dateComp(wdate,dateFrom)>=0 && dateComp(wdate,dateTo)<=0){
                // item.querySelector('.woo-pop-ctrl > div >i').click();
                // await sleep(500);
                if(exeSelect==-1){
                    console.log(wdate);
                    if(dateComp(wdate,dateFrom)>=0 && dateComp(wdate,dateTo)<=0){
                        item.style.color = "blue";
                    }
                    // item.remove();
                    await sleep(intervalTime);
                }else if (exeSelect == 1 && item.querySelector('.title_wrap_3e__u') == null && item.querySelector('.head_fastbehind_1StRl') == null) { // 设为仅个人可见
                    const ctrlButton = item.querySelector('.woo-pop-ctrl > div > i');
                    if (ctrlButton) {
                        ctrlButton.click(); // 点击弹出菜单
                        await sleep(800);
                
                        // 尝试找到“转换为自己可见”按钮
                        const options = Array.from(item.querySelectorAll('div.woo-pop-wrap-main > div')).slice(-4); // 检索最后几个菜单项
                        const targetButton = options.find(option => option.innerText.trim() === '转换为自己可见');
                
                        if (targetButton) {
                            targetButton.click(); // 点击“转换为自己可见”
                            console.log(`*成功找到并点击隐藏按钮 ${i}`);
                        } else {
                            console.log(`*未找到隐藏按钮 ${i}`);
                        }
                    } else {
                        console.log(`*未找到弹出菜单按钮 ${i}`);
                    }
                
                    await sleep(intervalTime);
                }
                else if (exeSelect == 0 && item.querySelector('.head_fastbehind_1StRl') == null) { // 删除微博
                    const ctrlButton = item.querySelector('.woo-pop-ctrl > div > i');
                    if (ctrlButton) {
                        ctrlButton.click(); // 点击弹出菜单
                        await sleep(800);
                
                        // 动态查找“删除”按钮
                        const options = Array.from(item.querySelectorAll('div.woo-pop-wrap-main > div')).slice(-3); // 检索最后三个菜单项
                        const delBtn = options.find(option => option.innerText.trim() === '删除');
                
                        if (delBtn) {
                            delBtn.click(); // 点击“删除”按钮
                            await sleep(500);
                
                            // 点击确认删除的按钮
                            const confirmButton = document.querySelectorAll(".woo-button-round.woo-dialog-btn")[1];
                            if (confirmButton) {
                                confirmButton.click();
                                await sleep(intervalTime);
                                console.log(`*尝试删除微博 ${i}`);
                            } else {
                                console.error(`*未找到确认删除按钮 ${i}`);
                            }
                        } else {
                            console.log(`*未找到删除按钮 ${i}`);
                            notComp = 1;
                        }
                    } else {
                        console.log(`*未找到弹出菜单按钮 ${i}`);
                        notComp = 1;
                    }
                }                
                else if (exeSelect == 2 && item.querySelector('.head_fastbehind_1StRl') != null) { // 取消快转
                    const ctrlButton = item.querySelector('.woo-pop-ctrl > div > i');
                    if (ctrlButton) {
                        ctrlButton.click(); // 点击弹出菜单
                        await sleep(800);
                
                        // 动态查找“取消快转”按钮
                        const options = Array.from(item.querySelectorAll('div.woo-pop-wrap-main > div')).slice(-3); // 检索最后三个菜单项
                        const unFastBtn = options.find(option => option.innerText.trim() === '取消快转');
                
                        if (unFastBtn) {
                            unFastBtn.click(); // 点击“取消快转”按钮
                            await sleep(500);
                
                            // 点击确认按钮
                            const confirmButton = document.querySelectorAll(".woo-button-round.woo-dialog-btn")[1];
                            if (confirmButton) {
                                confirmButton.click();
                                await sleep(intervalTime);
                                console.log(`*尝试取消快转 ${i}`);
                            } else {
                                console.error(`*未找到确认取消快转按钮 ${i}`);
                            }
                        } else {
                            console.error(`*未找到取消快转按钮 ${i}`);
                            notComp = 1;
                        }
                    } else {
                        console.error(`*未找到弹出菜单按钮 ${i}`);
                        notComp = 1;
                    }
                }
                else{
                    allSucCnt--;
                    episodeSucCnt--;
                }

                // 操作失败,否则成功
                if($('[action-type="ok"]')){
                    if($('[node-type="text"]').innerText.indexOf("繁忙")!=-1 && failCnt<=failThreshold){
                        failCnt++;
                        console.log("#系统繁忙,3s后进行第"+(failCnt+1)+"次尝试"+i);
                        i--;
                        await sleep(3000);
                    }else{
                        failCnt = 0
                        allFailCnt++;
                        console.log("#操作失败"+i)  //打印失败原因
                    }
                    $('[action-type="ok"]').click();
                }else{
                    if(notComp == 1){
                        notComp = 0;
                    }else{
                        allSucCnt++;
                        episodeSucCnt++;
                        console.log("#操作成功"+i);
                    }
                }
            }
        }



        async function mainLoopNew(){
            await sleep(1500);

            while(!endFlag){
                episodeSucCnt = 0;
                // 获取微博
                let allItems = $All('.vue-recycle-scroller__item-view');

                for(let i=0; i<allItems.length; i++){
                    await exeOpNew(allItems[i],i);
                }

                // 判断结尾
                if($('.Bottom_text_1kFLe')!=null){
                    endFlag = 1;
                    console.log("#尾页");
                }

                // 没有可操作的任务再下滑
                if(episodeSucCnt==0){
                    await scrollPage();
                }
            }

            alert("操作执行完毕\n共匹配符合条件微博:"+(allSucCnt+allFailCnt)+"条\n其中,操作成功"+allSucCnt+"条,失败"+allFailCnt+"条")
            console.log("#结束")
        }

        function setUp(){
            exeSelect = -1;
            keyWord;
            dateFrom = "2018-11-15";
            dateTo = "2018-11-15";
            while(1){
                versionSel = prompt("请输入当前微博类型(输入数字)\n【0】旧版微博\n【1】新版微博")
                if(versionSel=="0" || versionSel=="1" ) break;
                alert("请按提示操作")
            }
            while(1){
                exeSelect = prompt("请输入操作类型(输入数字)\n【0】删除微博(不可恢复,谨慎操作!)\n【1】隐藏微博(设为仅个人可见,推荐)\n【2】取消快转")
                if(exeSelect=="0" || exeSelect=="1" || exeSelect=="2" || exeSelect=="-1") break;
                alert("请按提示操作")
            }
            keyWord = prompt("请输入要操作微博的关键字。\n【默认不填为全匹配】");
            while(1){
                dateFrom = prompt("请输入要操作微博的发布日期时间段的【开始日期】(包括当日)。\n【请按格式填写,例:2021-2-29】\n【默认不填为全匹配】");
                if (dateFrom == "") dateFrom = "0000-1-1";
                dateTo = prompt("请输入要操作微博的发布日期时间段的【截至日期】(包括当日)。\n【请按格式填写,例:2021-2-29】\n【默认不填为全匹配】")
                if (dateTo == "") dateTo = "9999-12-31";
                if(isDatePart(dateFrom) && isDatePart(dateTo) && dateComp(dateFrom,dateTo)<=0) break;
                alert("错误,请重新输入:\n1.请检查开始日期是否小于或等于截止日期\n2.请检查日期格式是否正确")
            }
            // inTim = prompt("设置两次操作间隙时间(单位:秒)\n【间隔过短容易被服务器检测异常,推荐1.5秒】【不填默认为1.5秒】")
        }
        // 创建一个按钮元素
        var button = document.createElement("button");
        button.innerHTML = "开始程序";
        button.style.position = "fixed";
        button.style.bottom = "20px"; // 距离底部的距离
        button.style.left = "20px"; // 距离左侧的距离
        button.style.zIndex = "9999"; // 确保按钮在最顶层

        button.style.padding = "10px 20px";
        button.style.backgroundColor = "#3498db";
        button.style.color = "#fff";
        button.style.border = "none";
        button.style.borderRadius = "5px";
        button.style.fontFamily = "Arial, sans-serif";
        button.style.fontSize = "14px";
        button.style.cursor = "pointer";
        button.style.boxShadow = "0 4px 6px rgba(0, 0, 0, 0.1)";



        // 将按钮添加到页面中
        document.body.appendChild(button);

        // 为按钮添加点击事件监听器
        button.addEventListener("click", function() {
            //开始
            var w = confirm("欢迎使用微博删除助手,单击“确认”开始配置删除设置,单击“取消”退出");
            if (w === true) {
                setUp();
                var exeStr = "";
                var verStr = "";
                if(exeSelect=="0"){
                    exeStr = "删除微博"
                }else if(exeSelect=="1"){
                    exeStr = "隐藏微博"
                }else if(exeSelect=="2"){
                    exeStr = "取消快转"
                }else{
                    exeStr = "测试"
                }
                if (versionSel=="0"){
                    verStr = "旧版微博";
                }else{
                    verStr = "新版微博";
                }
                var c = confirm("配置完毕。\n【微博版本】:"+verStr+"\n【操作类型】:"+exeStr+"\n【微博内容包括】:"+keyWord+"\n【微博发布日期】:从 "+dateFrom+"(包括) 至 "+dateTo+"(包括) \n单击”确认“开始")
                if(c===true){
                    if (versionSel=="0"){
                        mainLoop();
                    }else{
                        mainLoopNew();
                    }
                }
            }
        });
    };
})();