微博ip属地显示助手

新浪微博显示用户ip属地

// ==UserScript==
// @name                微博ip属地显示助手
// @name:zh             微博ip属地显示助手
// @name:zh-CN          微博ip属地显示助手
// @description         新浪微博显示用户ip属地
// @description:zh      新浪微博显示用户ip属地
// @description:zh-CN   新浪微博显示用户ip属地
// @version             1.3.1
// @author              NiaoBlush
// @license             GPL
// @namespace           https://github.com/NiaoBlush/weibo-ip-location
// @homepageURL         https://github.com/NiaoBlush/weibo-ip-location
// @supportURL          https://github.com/NiaoBlush/weibo-ip-location/issues
// @match               https://weibo.com/*
// @match               https://m.weibo.cn/*
// @require             https://libs.baidu.com/jquery/2.0.3/jquery.min.js
// @grant               GM.xmlHttpRequest
// @connect             weibo.com
// ==/UserScript==

(function () {
    "use strict";

    // 获取用户 IP 属地(桌面版)
    function getRegion(uid) {
        return new Promise((resolve) => {
            $.get(`https://weibo.com/ajax/profile/detail?uid=${uid}`, function (res) {
                if (res.data && res.data.ip_location) {
                    const array = /IP属地:(.+)/.exec(res.data.ip_location);
                    resolve(array ? array[1] : "");
                } else {
                    resolve("");
                }
            });
        });
    }

    // 获取用户 IP 属地(移动版)
    function getRegionGM(uid) {
        return new Promise((resolve) => {
            GM.xmlHttpRequest({
                url: `https://weibo.com/ajax/profile/detail?uid=${uid}`,
                method: "GET",
                onload: function (xhr) {
                    const res = JSON.parse(xhr.responseText);
                    if (res.data && res.data.ip_location) {
                        const array = /IP属地:(.+)/.exec(res.data.ip_location);
                        resolve(array ? array[1] : "");
                    } else {
                        resolve("");
                    }
                }
            });
        });
    }

    // 国内省市列表,用于标识境外
    const district = ["北京", "天津", "河北", "山西", "内蒙古", "辽宁", "吉林", "黑龙江",
        "上海", "江苏", "浙江", "安徽", "福建", "江西", "山东", "河南", "湖北", "湖南",
        "广东", "广西", "海南", "重庆", "四川", "贵州", "云南", "西藏", "陕西", "甘肃",
        "青海", "宁夏", "新疆", "台湾", "中国香港", "澳门"];

    // 在用户昵称元素后添加 IP 属地标识
    function mark($obj, region) {
        const markedClass = "weibo-ip-marked";
        if (!region || $obj.hasClass(markedClass)) return;
        $obj.addClass(markedClass);
        const foreign = district.indexOf(region) === -1;
        const html = foreign
            ? `<span style="background-color:red;color:#FFF;margin-left:5px;font-weight:bold;border-radius:8px;padding:2px 5px;">${region}</span>`
            : `<span style="color:#00d0ff;margin-left:5px;font-weight:normal;border-radius:8px;padding:2px 5px;">(${region})</span>`;
        $obj.append(html);
    }

    // 缓存已获取的属地
    const regionMap = {};

    // 创建一个 MutationObserver,监听容器内新增节点
    function createInsertionObserver(container, callback) {
        const observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                if (mutation.type === 'childList' && mutation.addedNodes.length) {
                    const nodes = Array.from(mutation.addedNodes).filter(node => node.nodeType === 1);
                    if (nodes.length) callback(nodes);
                }
            });
        });
        observer.observe(container, {childList: true, subtree: true});
        return observer;
    }

    // 处理桌面版微博列表
    function processList($ele) {
        const list = $ele.find("a[class^='ALink_default']:not([aria-label]), .WB_info>a[usercard]");
        list.each(async function () {
            const href = $(this).attr("href");
            const array = /\/u\/(\d+)/.exec(href);
            if (array) {
                const uid = array[1];
                let region = regionMap[uid];
                if (region === undefined) {
                    region = await getRegion(uid);
                    regionMap[uid] = region;
                }
                mark($(this), region);
            }
        });
    }

    // 处理移动版微博列表
    function processMobileList($ele) {
        const list = $ele.find(".weibo-top .m-text-box> a, .weibo-text> span>a:not([data-hide])");
        list.each(async function () {
            let $target = $(this);
            const href = $target.attr("href");
            const array = /\/profile\/(\d+)/.exec(href);
            if ($target.parent().hasClass("m-text-box")) {
                $target = $target.find("h3").first();
            }
            if (array) {
                const uid = array[1];
                let region = regionMap[uid];
                if (region === undefined) {
                    region = await getRegionGM(uid);
                    regionMap[uid] = region;
                }
                mark($target, region);
            }
        });
    }

    // 桌面版 v6
    const mainContainer = document.querySelector('.WB_main');
    if (mainContainer) {
        processList($(mainContainer));
        createInsertionObserver(mainContainer, nodes => {
            nodes.forEach(node => processList($(node)));
        });
    }

    // 桌面版 v7
    const homeFeeds = document.querySelectorAll("[class^='Home_feed']");
    homeFeeds.forEach(container => {
        processList($(container));
        createInsertionObserver(container, nodes => {
            nodes.forEach(node => processList($(node)));
        });
    });

    // 移动版
    if (location.host === "m.weibo.cn") {
        const appEl = document.getElementById('app');
        if (appEl) {
            processMobileList($(appEl));
            createInsertionObserver(appEl, nodes => {
                nodes.forEach(node => {
                    const $node = $(node);
                    if ($node.hasClass('main-wrap') || $node.hasClass('pannelwrap')) {
                        processMobileList($node);
                    }
                });
            });
        }
    }
})();
长期地址
遇到问题?请前往 GitHub 提 Issues。