Bilibili关注迁移

将bilibili关注从一个账号转移到另一个账号

// ==UserScript==
// @name         Bilibili关注迁移
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  将bilibili关注从一个账号转移到另一个账号
// @author       Todd
// @match        https://space.bilibili.com/*/fans/follow*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @grant        none
// @license      MIT
// ==/UserScript==

const title_seletor = "#page-follows > div > div.follow-main > div.follow-header.follow-header-info > div";

let WaitForLoaded = (parentNode, checkFuntion) => {
    let option = {
        'childList': true,
        'subtree': true
    };

    let promise = new Promise((resolve, reject) => {
        let mo = new MutationObserver((mutations, obs) => {
            try {
                if (checkFuntion(mutations)) {
                    resolve(obs);
                }
            } catch (e) {
                reject(e);
            }
        })

        mo.observe(parentNode, option);
    })

    return promise;
}

function getUid() {
    let regExp = new RegExp('(?<=https://space.bilibili.com/)[\\d]+')
    let url = window.location.href;
    return regExp.exec(url)[0];
}

async function getFollowListPromise(uid, pn) {
    let url = `https://api.bilibili.com/x/relation/followings?vmid=${uid}&pn=${pn}&ps=50`
    let promise = fetch(url, {
        "headers": {
            "accept": "*/*",
            "accept-language": "zh-CN,zh;q=0.9",
            "sec-ch-ua": "\"Not_A Brand\";v=\"99\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\"",
            "sec-fetch-dest": "script",
            "sec-fetch-mode": "no-cors",
            "sec-fetch-site": "same-site"
        },
        "referrer": "https://space.bilibili.com/5919189/fans/follow?spm_id_from=333.788.0.0",
        "referrerPolicy": "no-referrer-when-downgrade",
        "body": null,
        "method": "GET",
        "mode": "cors",
        "credentials": "include"
    });

    let res = await promise;
    let body = await res.json();
    let follow_array = body.data.list;
    return follow_array.map((val) => val.mid).flat();
}

let ALL_COUNT = 0;
let CUR_COUNT = 0;
async function getFollowPromise(id, csrf) {
    await fetch("https://api.bilibili.com/x/relation/modify", {
        "headers": {
            "accept": "application/json, text/plain, */*",
            "accept-language": "zh-CN,zh;q=0.9",
            "content-type": "application/x-www-form-urlencoded",
            "sec-ch-ua": "\"Not_A Brand\";v=\"99\", \"Google Chrome\";v=\"109\", \"Chromium\";v=\"109\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\"",
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "same-site"
        },
        "body": `fid=${id}&act=1&csrf=${csrf}`,
        "method": "POST",
        "mode": "cors",
        "credentials": "include"
    });
    console.log(`Finished ${++CUR_COUNT} of ${ALL_COUNT}`)
}

async function backup() {
    let uid = getUid();
    let follow_count_selector = '#page-follows > div > div.follow-sidenav > div.nav-container.follow-container > div.be-scrollbar.follow-list-container.ps > ul > li.follow-item.cur > span.num'
    let follow_count = document.querySelector(follow_count_selector).innerHTML
    follow_count = parseInt(follow_count);

    let loop_count = Math.ceil(follow_count / 50);
    let promise_array = [];
    for (let i = 1; i <= loop_count; i++) {
        promise_array.push(getFollowListPromise(uid, i))
    }

    let follows = await Promise.all(promise_array);
    await navigator.clipboard.writeText(follows.toString());
    alert("所有关注已复制至剪切板,粘贴至还原按钮弹出的对话框即可");
}

async function restore() {
    let follow_id = prompt();
    let follow_id_array = follow_id.split(",");
    let cookie = document.cookie;
    let reg = /(?<=bili_jct=)(.+?)(?=;)/
    let csrf = reg.exec(cookie)[0];
    ALL_COUNT = follow_id_array.length;
    console.log(csrf);
    console.log(follow_id_array);
    let id = setInterval(async ()=>{
        await getFollowPromise(follow_id_array.pop(), csrf);
        if(CUR_COUNT >= ALL_COUNT){
            clearInterval(id);
        }
    }, 1000); //1秒发送一次关注请求
    //await Promise.all(promise_array);
}

function insertBtn() {
    let title = document.querySelector(title_seletor);
    let backup_btn = document.createElement("button");
    let restore_btn = document.createElement("button");
    backup_btn.style.fontSize = "12px";
    restore_btn.style.fontSize = "12px";
    backup_btn.onclick = backup;
    restore_btn.onclick = restore;
    backup_btn.innerHTML = "备份";
    restore_btn.innerHTML = "还原";
    title.appendChild(backup_btn);
    title.appendChild(restore_btn);

    const search_seletor = "#page-follows > div > div.follow-main > div.follow-header.follow-header-info > div > div"
    document.querySelector(search_seletor).style.order = 1;
}

async function main() {
    let obs = await WaitForLoaded(document.body, () => {
        return document.querySelectorAll(title_seletor).length > 0
    });
    obs.disconnect();
    insertBtn();
}

main();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址