Greasy Fork is available in English.

bilibili-hook-vip

共享大会员 修改于PC6live的bilibili-joybook,免登陆带会员的账号,直接输入Cookie

// ==UserScript==
// @name          bilibili-hook-vip
// @description   共享大会员 修改于PC6live的bilibili-joybook,免登陆带会员的账号,直接输入Cookie
// @author        PeterGang
// @namespace     https://github.com/GangPeter
// @match         *://*.bilibili.com/*
// @exclude       *://passport.bilibili.com/*
// @license       MIT
// @grant         GM_setValue
// @grant         GM_getValue
// @grant         GM_xmlhttpRequest
// @grant         GM_registerMenuCommand
// @grant         unsafeWindow
// @run-at        document-start
// @noframes      true
// @connect       bilibili.com
// @version       0.0.1
// ==/UserScript==
(function () {
    'use strict';
    function __awaiter(thisArg, _arguments, P, generator) {
        function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
        return new (P || (P = Promise))(function (resolve, reject) {
            function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
            function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
            function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
            step((generator = generator.apply(thisArg, _arguments || [])).next());
        });
    }
    typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
        var e = new Error(message);
        return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
    };
    const REAL_XHR = "_xhr";
    function setConfig(target, p, args) {
        if (p === "open") {
            target.method = args[0];
            target.url = args[1];
            target.async = args[2];
            target.user = args[3];
            target.password = args[4];
        }
        if (p === "send") {
            target.body = args[0];
        }
        if (p === "setRequestHeader") {
            target.headers = {};
            target.headers[args[0].toLowerCase()] = args[1];
        }
    }
    function proxy(options, win) {
        // 保存真实 XMLHttpRequest
        win[REAL_XHR] = win[REAL_XHR] || win.XMLHttpRequest;
        win.XMLHttpRequest = new Proxy(win.XMLHttpRequest, {
            construct(Target) {
                // 代理 new 操作符
                const xhr = new Target();
                const xhrProxy = new Proxy(xhr, {
                    get: getterFactory,
                    set: setterFactory,
                });
                return xhrProxy;
            },
        });
        const getterFactory = (target, p, receiver) => {
            const value = Reflect.get(target, p);
            const hook = Reflect.get(options, p);
            // 拦截函数
            if (hook && typeof hook === "function")
                return (...args) => {
                    setConfig(target, p.toString(), args);
                    return hook(target, value, receiver) || value.call(target, ...args);//去广告插件可能会报错误
                };
            if (typeof value === "function")
                return value.bind(target);
            // 使用缓存值
            return Reflect.get(target, `_${p.toString()}`) || value;
        };
        const setterFactory = (target, p, value, receiver) => {
            const hook = Reflect.get(options, p);
            if (hook && typeof hook === "function")
                return Reflect.set(target, p, () => {
                    hook(target, value, receiver) || value(target);
                });
            return Reflect.set(target, p, typeof value === "function" ? value.bind(target) : value);
        };
    }
    const proxyUrls = [
        // 视频信息
        "api.bilibili.com/x/player/wbi/playurl",
        // 用户信息
        "api.bilibili.com/x/player/wbi/v2",
        // bangumi 信息
        "api.bilibili.com/pgc/player/web/v2/playurl",
    ];
    // 需要代理的链接
    const handleUrl = (url) => {
        if (!GM_getValue('vipCookie'))
            return false;
        if (proxyUrls.findIndex((v) => url.includes(v)) > -1)
            return true;
        return false;
    };
    function handleResponse(xhr) {
        return __awaiter(this, void 0, void 0, function* () {
            const url = new URL(xhr.url, window.location.href);
            xhr.url = url.href;
            // 使用vip账号获取数据
            const request = yield GM.xmlHttpRequest({
                method: xhr.method,
                url: xhr.url,
                anonymous: true,
                cookie: GM_getValue('vipCookie'),
                headers: {
                    referer: window.location.href,
                },
            }).catch((e) => console.error(e));
            if (!request)
                return;
            // 重新打开链接
            xhr.open(xhr.method, xhr.url, xhr.async !== false, xhr.user, xhr.password);
            for (const key in xhr.headers) {
                xhr.setRequestHeader(key, xhr.headers[key]);
            }
            // 替换必要的数据
            // TODO: catch 数据结构变化输出错误
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4) {
                    const originResponse = JSON.parse(xhr.response);
                    const proxyResponse = JSON.parse(request.response);
                    // video
                    if (xhr.url.includes(proxyUrls[0]))
                        originResponse.data = proxyResponse.data;
                    // response 中包含上次播放时间
                    if (xhr.url.includes(proxyUrls[1]))
                        originResponse.data.vip = proxyResponse.data.vip;
                    // bangumi
                    if (xhr.url.includes(proxyUrls[2]))
                        originResponse.result = proxyResponse.result;
                    xhr._responseText = JSON.stringify(originResponse);
                }
            };
            // 发送链接
            xhr.send(xhr.body);
        });
    }
    function listenerAjax() {
        const config = {
            open(xhr) {
                if (handleUrl(xhr.url)) {
                    handleResponse(xhr);
                    return true;
                }
                return false;
            },
            send(xhr) {
                if (handleUrl(xhr.url))
                    return true;
                return false;
            },
            setRequestHeader(xhr) {
                if (handleUrl(xhr.url))
                    return true;
                return false;
            },
        };
        proxy(config, unsafeWindow);
    }
    const promptCookieInput = () => {
        const cookie = prompt("Bilibili 大会员共享:直接复制全部 Cookie");
        let newCookie = '';
        if (cookie) {
            for (const cookieValue of cookie.split(';'))
                if (["SESSDATA", "DedeUserID", "DedeUserID__ckMd5", "bili_jct"].includes(cookieValue.split('=')[0]))
                    newCookie += (cookieValue + ';');
            GM_setValue("vipCookie", newCookie.slice(0, -1));
        }
        location.reload();
    };
    GM_registerMenuCommand("重设大会员 Cookie", promptCookieInput);
    (() => {
        if (!GM_getValue("vipCookie")) {
            promptCookieInput();
            return;
        }
        listenerAjax();// 监听XHR
    })();
})();