BilibiliExp

B 站经验助手,自动投币视频、模拟移动端分享、经验获取统计、升级时间估计

目前為 2019-11-29 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        BilibiliExp
// @namespace   BilibiliExp
// @match       *://www.bilibili.com/video/*
// @version     1.0
// @author      Dreace
// @license     GPL-3.0
// @description B 站经验助手,自动投币视频、模拟移动端分享、经验获取统计、升级时间估计
// @grant       GM.xmlHttpRequest
// @grant       unsafeWindow
// @require https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js
// @require https://static.hdslb.com/js/md5.js
// ==/UserScript==
// file:///C:/WorkSpace/JavaScript/BilibiliExp/main.js
(function () {
    'use strict';
    const coinUrl = "https://api.bilibili.com/x/web-interface/nav?build=0&mobi_app=web"
    const addCoinUrl = "https://api.bilibili.com/x/web-interface/coin/add"
    const shareUrl = "https://app.bilibili.com/x/v2/view/share/complete"
    const shareUrlPre = "https://app.bilibili.com/x/v2/view/share/click"
    const rewardUrl = "https://account.bilibili.com/home/reward"
    let totalCoin = 0
    let expToday = 0
    let aid = ""
    let bili_jct = getCookie("bili_jct")
    try {
        aid = unsafeWindow.vd ? unsafeWindow.vd.aid : unsafeWindow.aid
    } catch (error) {
        console.log("aid 获取失败")
        return
    }
    function addCoin() {
        return biliAjax({
            url: addCoinUrl,
            type: 'POST',
            dataType: 'json',
            data: {
                aid: aid,
                multiply: "1",
                select_like: 0,
                cross_domain: true,
                csrf: bili_jct
            },
        })
    }
    if (aid) {
        gmAjax({
            url: rewardUrl,
            methon: 'GET',
        }).then((res) => {
            if (res.code == 0) {
                expToday = 50 - res.data.coins_av
            } else {
                console.log("等级信息获取失败");
                return
            }
        })
        gmAjax({
            url: rewardUrl,
            methon: 'GET',
        }).then((res) => {
            if (res.code == 0) {
                expToday = 50 - res.data.coins_av
                if (!res.data.share_av) {
                    let shareData = {
                        access_key: bili_jct,
                        actionKey: "appkey",
                        aid: aid,
                        appkey: "27eb53fc9058f8c3",
                        build: "8960",
                        device: "phone",
                        epid: "",
                        from: "711",
                        mobi_app: "iphone",
                        platform: "ios",
                        season_id: "",
                        share_channel: "qq",
                        share_trace_id: hex_md5(new Date()),
                        statistics: "%7B%22appId%22%3A1%2C%22version%22%3A%225.50.1%22%2C%22abtest%22%3A%22890%22%2C%22platform%22%3A1%7D",
                        ts: new Date().getTime(),
                    }
                    let signed = get_sign(shareData, "c2ed53a74eeefe3cf99fbd01d8c9c375")
                    GM.xmlHttpRequest({
                        method: "POST",
                        url: shareUrl,
                        data: signed.data + "&sign=" + signed.sign,
                        headers: {
                            "Content-Type": "application/x-www-form-urlencoded"
                        },
                        onload: function (response) {
                            let res = JSON.parse(response.responseText)
                            if (res.code == 0) {
                                GM.xmlHttpRequest({
                                    method: "POST",
                                    url: shareUrlPre,
                                    data: signed.data + "&sign=" + signed.sign,
                                    headers: {
                                        "Content-Type": "application/x-www-form-urlencoded"
                                    },
                                    onload: function (response) {
                                        let res = JSON.parse(response.responseText)
                                        console.log(res.data.toast)
                                    }
                                });
                            }
                        }
                    });

                }
            } else {
                console.log("等级信息获取失败");
            }
        }).then(() => {
            return biliAjax({
                url: coinUrl,
                type: 'GET',
                dataType: 'json',
            })
        }).then((res) => {
            totalCoin = res.data.money
            console.log("当前硬币 " + totalCoin + " 个")
            if (totalCoin < 50) {
                console.log("硬币小于 50,暂不投币")
            } else {
                if (expToday == 0) {
                    console.log("今日已获取全部经验")
                }
                return new Promise(function (resolve, reject) {
                    setTimeout(() => {
                        resolve()
                    }, 10000);
                })
            }
        }).then(() => {
            if (totalCoin >= 50 && expToday > 0) {
                console.log("准备投币")
                return addCoin()
            }
        }).then((res) => {
            if (res && res.code == 0) {
                console.log("投了一个币")
                expToday -= 10
                if (expToday > 0) {
                    return addCoin()
                }
            }
        }).then((res) => {
            if (res && res.code == 0) {
                console.log("又投了一个币")
            }
            return gmAjax({
                url: rewardUrl,
                methon: 'GET',
            })
        }).then((res) => {
            if (res.code == 0) {
                let rewardInfo = res.data
                let link = document.createElement('link');
                link.rel = 'stylesheet';
                link.href = "//at.alicdn.com/t/font_1537779_4srood2g1uk.css";
                document.body.appendChild(link);
                let style = "color: inherit;display: inline-block;line-height: 1;"
                let spansData = []
                let total = 0
                total += rewardInfo.login ? 5 : 0
                spansData.push({
                    ok: rewardInfo.login,
                    name: "每日登录",
                    text: `${rewardInfo.login ? 5 : 0}/5`,
                    className: "icon-login"
                })
                total += rewardInfo.share_av ? 5 : 0
                spansData.push({
                    ok: rewardInfo.share_av,
                    name: "分享视频",
                    text: `${rewardInfo.share_av ? 5 : 0}/5`,
                    className: "icon-share"
                })
                total += rewardInfo.watch_av ? 5 : 0
                spansData.push({
                    ok: rewardInfo.watch_av,
                    name: "观看视频",
                    text: `${rewardInfo.watch_av ? 5 : 0}/5`,
                    className: "icon-play"
                })
                total += rewardInfo.coins_av
                spansData.push({
                    ok: rewardInfo.coins_av == 50,
                    name: "视频投币",
                    text: `${rewardInfo.coins_av}/50`,
                    className: "icon-coin"
                })
                spansData.push({
                    ok: total == 65,
                    name: "总计",
                    text: `${total}/65`,
                    className: "icon-total"
                })
                spansData.push({
                    ok: false,
                    name: `最快到 ${rewardInfo.level_info.current_level + 1} 级剩余天数`,
                    text: `${Math.ceil((rewardInfo.level_info.next_exp - rewardInfo.level_info.current_exp) / 65)} 天`,
                    className: "icon-day"
                })
                let bar = document.getElementById("arc_toolbar_report")
                bar.style.height = "60px"
                let ops = document.createElement('div')
                ops.className = "ops"

                spansData.forEach((item) => {
                    let span = document.createElement("span")
                    if (item.ok) {
                        span.style = "color:rgb(251, 114, 153);"
                    } else {
                        span.style = "color:rgb(80, 80, 80);"
                    }
                    span.title = item.name
                    span.innerHTML = `<i class="${item.className} iconfont" style="${style}"></i>${item.text}`
                    ops.appendChild(span.cloneNode(true))
                })
                ops.style.marginTop = "10px"
                bar.appendChild(ops)
            }
        })
    }
})();
function gmAjax(opt) {
    return new Promise((resolve, reject) => {
        GM.xmlHttpRequest({
            method: opt.methon,
            url: opt.url,
            data: opt.data ? opt.data : "",
            headers: opt.headers ? opt.headers : "",
            onload: function (response) {
                let res = JSON.parse(response.responseText)
                resolve(res)
            },
            onError: function (error) {
                reject(error)
            }
        });
    })
}
function request(opt) {
    return $.ajax(opt)
}
function createPromise() {
    return $.Deferred()
}
function biliAjax(opt) {
    let req
    opt.xhrFields = {
        withCredentials: true
    }
    opt.crossDomain = true
    let defer = createPromise()
    req = request(opt)
    req.done(function (d) {
        defer.resolve(d)
    })
    req.fail(d => {
        defer.reject(d)
    })

    return defer
}
function get_sign(params, key) {
    var s_keys = []
    for (var i in params) {
        s_keys.push(i)
    }
    s_keys.sort()
    var data = ""
    for (var i = 0; i < s_keys.length; i++) {
        data += (data ? "&" : "") + s_keys[i] + "=" + params[s_keys[i]]
    }
    return { sign: hex_md5(data + key), data: data }
}
function getCookie(cname) {
    var name = cname + "=";
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i].trim();
        if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
    }
    return "";
}