要AV号,不要BV码

Make AV number, not BV code. F**k you BiliBili

目前为 2020-03-23 提交的版本。查看 最新版本

// ==UserScript==
// @name           要AV号,不要BV码
// @name:en        Make AV number, not BV code
// @namespace      https://pilipili.com/bv10492
// @version        0.1.1
// @description    Make AV number, not BV code. F**k you BiliBili
// @description:en Make AV number, not BV code. F**k you BiliBili
// @author         jk1551
// @require        https://unpkg.com/[email protected]/dist/ajaxhook.min.js
// @nocompat       Safari
// @match          https://www.bilibili.com/video/*
// @match          http://www.bilibili.com/video/*
// @match          https://acg.tv/*
// @match          http://acg.tv/*
// @match          https://b23.tv/*
// @match          http://b23.tv/*
// @grant          none
// ==/UserScript==

/* jshint esversion: 6 */

const CONFIG = {
    autoJump: false
};

// GM代码构思来自 https://gf.qytechs.cn/zh-CN/scripts/398526-give-me-av-not-bv

(() => {
    if (typeof BigInt !== "function") {
        console.warn("Your browser does not support BigInt. AV/BV conversion is disabled.");
        return;
    }

    const bv2av = (() => {
        // https://www.zhihu.com/question/381784377/answer/1099438784
        const table = "fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF";
        const tr = Object.create(null);

        for (let i = 0; i < 58; i += 1) {
            tr[table[i]] = BigInt(i);
        }

        const s = [11, 10, 3, 8, 4, 6];
        const xor = BigInt(177451812);
        const add = BigInt(8728348608);
        const pow58 = [];
        
        // 58进制下2^32的最大位数(=6),也就是在此之前变动的最多位数,也就是s表的长度
        const highestDigit = 6;
        
        for (let i = 0; i < highestDigit; i += 1) {
            pow58.push(BigInt(Math.pow(58, i)));
        }

        /**
         * @param s {string}
         */
        function list(s) {
            return s.split("");
        }

        /**
         * @param x {string} BV string; including the beginning "BV" (e.g. "BV17x411w7KC")
         */
        function dec(x) {
            let r = BigInt(0);

            for (let i = 0; i < highestDigit; i += 1) {
                r += tr[x[s[i]]] * pow58[i];
            }

            return Number((r - add) ^ xor);
        }

        /**
         * @param x {number} Exsiting AV number
         */
        function enc(x) {
            x = BigInt(x);
            x = (x ^ xor) + add;

            const r = list("BV1  4 1 7  ");

            for (let i = 0; i < highestDigit; i += 1) {
                const index = (x / pow58[i]) % BigInt(58);
                r[s[i]] = table[index];
            }

            return r.join("");
        }

        return {
            enc: enc,
            dec: dec
        };
    })();

    /**
     * @param avNumber {number | string}
     */
    function getAvUrl(avNumber) {
        return "//www.bilibili.com/video/av" + avNumber.toString();
    }

    /**
     * @param avNumber {number | string}
     */
    function appendOrUpdateAvNumberLink(avNumber) {
        const avInfoLabels = document.getElementsByClassName("video-data");
        // 分区和日期
        const infoLabel1 = avInfoLabels[0];
        // 直接塞到和infoLabel1同级会导致谜之排版错误
        const info1 = infoLabel1.children[0];
        let link;

        if (info1.children.length === 2) {
            // 原始状态(只有分区和日期两个span)
            const span = document.createElement("span");
            link = document.createElement("a");
            link.textContent = "av" + avNumber.toString();
            link.href = getAvUrl(avNumber);
            info1.appendChild(span);
        } else if (info1.children.length > 2) {
            // pilipili的谜之DOM更新,又不像是VDOM
            // 本来添加了一个span和a,但是刷新之后反而变成了a是info1的第一个子元素
            link = info1.children[0];
            link.textContent = "av" + avNumber.toString();
            link.href = getAvUrl(avNumber);
            link.style.marginRight = "16px";
        }
    }

    (() => {
        const bvUrlRE = /www\.bilibili\.com\/video\/(BV[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)/;
        const bvmatch = bvUrlRE.exec(window.location.href);

        if (bvmatch) {
            console.log("F**k You BV Number!");

            if (CONFIG.autoJump) {
                const bvstr = bvmatch[1];
                const avNumber = bv2av.dec(bvstr);
                const url = getAvUrl(avNumber);
                window.location.href = url;
            }
        }
    })();

    let isContentRefreshed = false;
    let isAvNumberWritten = false;
    let avNumber = Number.NaN;

    // TODO: 处理 HTML5 History 相关

    const bvidRE = /bvid=(BV[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)/;
    const aidRE = /aid=(\d+)/;

    ah.proxy({
        //请求发起前进入
        onRequest: (config, handler) => {
            while (config.url.indexOf("api.bilibili.com/x/web-interface/view") > 0) {
                let match = bvidRE.exec(config.url);

                if (match) {
                    // https://api.bilibili.com/x/web-interface/view?cid=167028524&bvid=BV1TE411A7VJ
                    avNumber = bv2av.dec(match[1]);
                    isContentRefreshed = true;
                    break;
                }

                match = aidRE.exec(config.url);

                if (match) {
                    // https://api.bilibili.com/x/web-interface/view?cid=167028524&aid=97836354
                    avNumber = Number.parseInt(match[1]);
                    isContentRefreshed = true;
                    break;
                }

                break;
            }

            handler.next(config);
        },

        //请求成功后进入
        onResponse: (response, handler) => {
            if (isContentRefreshed) {
                if (isAvNumberWritten) {
                    if (!Number.isNaN(avNumber)) {
                        setTimeout(() => {
                            appendOrUpdateAvNumberLink(avNumber);
                        });
                        isAvNumberWritten = true;
                    }
                } else {
                    if (!Number.isNaN(avNumber)) {
                        setTimeout(() => {
                            appendOrUpdateAvNumberLink(avNumber);
                        });
                    }
                }
            }

            handler.next(response);
        }
    });
})();

QingJ © 2025

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