Greasy Fork is available in English.

B站直播自动抢红包抢天选

自用脚本,不喜勿用哈~~

// ==UserScript==
// @name         B站直播自动抢红包抢天选
// @homepage     https://greasyfork.org/zh-CN/scripts/479959
// @version      1.85
// @description  自用脚本,不喜勿用哈~~
// @author       9527ttt
// @iconURL      https://i0.hdslb.com/bfs/article/927cc195124c47474b4a150d8b09e00536d15a0a.gif
// @icon64URL    https://i0.hdslb.com/bfs/article/927cc195124c47474b4a150d8b09e00536d15a0a.gif
// @match        https://live.bilibili.com/*
// @match        https://www.bilibili.com/blackboard/live/*
// @connect      bilibili.com
// @connect      flyx.fun
// @require      https://lib.baomitu.com/jquery/3.4.1/jquery.min.js
// @require      https://greasyfork.org/scripts/441505-crypto-js4-1-1/code/crypto-js411.js?version=1028182
// @require      https://greasyfork.org/scripts/445313-pako-1-0-10/code/pako@1010.js?version=1052595
// @grant        unsafeWindow
// @grant        GM_notification
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_openInTab
// @grant        GM_xmlhttpRequest
// @run-at       document-idle
// @grant        GM_info
// @license      MIT License
// @namespace    http://tampermonkey.net/
// ==/UserScript==


window.onload =(function ttt9527(){
    var Toast_out = false
    var NAME
    var BAPI
    var dianchi = 0
    var dianchi_gift_num = 0
    var ms_diff = 0
    var s_diff = 0
    var Live_info = {
        coin: undefined,
        room_id: undefined,
        uid: undefined,
        csrf_token: undefined,
        rnd: undefined,
        ruid: undefined,
        uname: undefined,
        user_level: undefined,
        Blever: undefined,
        room_area_id: 371,
        area_parent_id: 9,
        vipType: undefined,
        face_url: undefined,
        vipTypetext: undefined,
        cost: undefined,
        regtime: undefined,
        identification: undefined,
        img_key:undefined,
        sub_key:undefined,
    };
    const prettyLog = (...args) => {
        const styles = 'color: blue; font-weight: bold; background: #ddd';
        console.log(`%c${args.join(' ')}`, styles);
    };

    const dateNow = () => Date.now();
    const ts_ms = () => Date.now();
    const ts_s = () => Math.round(ts_ms() / 1000);
    function sleep(ms){
        return new Promise(resolve => setTimeout(() => resolve('sleep'), ms));
    }
    String.prototype.replaceAll = function(oldSubStr, newSubStr){
        return this.replace(new RegExp(oldSubStr, 'gm'), newSubStr)
    }
    const getMyJson = function(url){
        return new Promise((resolve) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: url,
                onload: function(response){
                    const res = strToJson((response || {}).responseText)
                    resolve(res);
                }
            });
        })
    }
    const strToJson = function(params){
        const isJSON = (str => {
            if(typeof str === 'string'){
                try {
                    const obj = JSON.parse(str);
                    return typeof obj === 'object' ? obj : false
                } catch (_){
                    prettyLog(str);
                    return false;
                }
            }else{
                prettyLog(`${str}\nIt is not a string!`);
                return false;
            }
        })(params);
        return isJSON ? isJSON : {}
    }
    const newWindow = {
        init: () => {
            return newWindow.Toast.init();
        },
        Toast: {
            init: () => {
                try {
                    const list = [];
                    window.toast = (msg, type = 'info', timeout = 5e3, side = 'right') => {
                        prettyLog(`【${new Date(ts_s()*1000).toLocaleString()}】${msg}`)
                        switch (type){
                            case 'success':
                            case 'info':
                            case 'error':
                                break;
                            default:
                                type = 'info';
                        }
                        const a = $(`<div class="link-toast ${type} fixed" style="z-index:2001;"><span class="toast-text">${msg}</span></div>`)[0];
                        if(!Toast_out)document.body.appendChild(a);
                        if(Toast_out){
                            list.forEach((v) => {
                                $(v).remove();
                            });
                            return $.Deferred().resolve();
                        }
                        a.style.top = (document.body.scrollTop + list.length * 40 + 50) + 'px';
                        if(side == 'left')a.style.left = 10 + 'px';
                        if(side != 'left')a.style.left = (document.body.offsetWidth + document.body.scrollLeft - a.offsetWidth - 5) + 'px';
                        list.push(a);
                        setTimeout(() => {
                            a.className += ' out';
                            setTimeout(() => {
                                list.shift();
                                list.forEach((v) => {
                                    v.style.top = (parseInt(v.style.top, 10) - 40) + 'px';
                                });
                                $(a).remove();
                            }, 200);
                        }, timeout);
                    };
                    return $.Deferred().resolve();
                } catch (err){
                    return $.Deferred().reject();
                }
            }
        }
    }
    newWindow.init();
    $(function () { //DOM完毕,等待弹幕加载完成
        let loadInfo = (delay) => {
            if((typeof BilibiliLive) == "undefined"){
                BilibiliLive = undefined;
            }
            setTimeout(async function () {
                GM_xmlhttpRequest({
                    method: "GET",
                    url: "https://api.bilibili.com/x/web-interface/nav",
                    onload: async function(response){
                        let json = JSON.parse(response.response);
                        //prettyLog(json);
                        if(!json.data.isLogin){
                            loadInfo(5000);
                            window.toast('无账号登陆信息,请先登录或检查网络!','error',8000);
                            //prettyLog('无登陆信息',new Date());
                        }else{
                            if(BilibiliLive == undefined) return loadInfo(5000);
                            if(BilibiliLive.ROOMID == undefined) return loadInfo(5000);
                            Live_info.room_id = BilibiliLive.ROOMID;
                            Live_info.uid = json.data.mid
                            Live_info.coin = json.data.money
                            Live_info.Blever = json.data.level_info.current_level
                            Live_info.vipType = json.data.vipType
                            Live_info.uname = json.data.uname
                            Live_info.face_url = json.data.face
                            Live_info.vipTypetext = json.data.vip_label.text
                            if(Live_info.vipTypetext=='')Live_info.vipTypetext = '普通用户'
                            let img_url = json.data.wbi_img.img_url
                            let sub_url = json.data.wbi_img.sub_url
                            let img_key = img_url.slice(img_url.lastIndexOf('/') + 1,img_url.lastIndexOf('.'))
                            let sub_key = sub_url.slice(sub_url.lastIndexOf('/') + 1,sub_url.lastIndexOf('.'))
                            Live_info.img_key = img_key
                            Live_info.sub_key = sub_key
                            NAME = "UID" + Live_info.uid;
                            //prettyLog('登陆信息获取成功!',Live_info,new Date());
                            window.toast('登陆信息获取成功!','success');
                            init();
                        }
                    },
                    onerror : function(err){
                        loadInfo(5000);
                        window.toast('无账号登陆信息,请先登录或检查网络!','error',8000);
                        prettyLog('无登陆信息',new Date());
                    }
                });
            }, delay);
        };
        loadInfo(5000);
    });

    function init(){ //API初始化
        if(GM_getValue('like_num') == undefined)GM_setValue('like_num', 0)
        try {
            BAPI = BilibiliAPI;
        } catch (err){
            console.error(`[${NAME}]`, err);
            return;
        }
        Live_info.csrf_token = BAPI.getCookie('bili_jct');
        const MY_API = {
            CONFIG_DEFAULT: {
                un_modify_list:[],//关注白名单
                auto_modify: false, //自动取关
                AnchorserverFLASH: 20, //获取服务器抽奖数据间隔
                CLEAR_TS:0,
                JSMARK: 0, //多开标记
                AUTO_Anchor: false, //礼物天选
                popularity_red_pocket_join_switch:false,//人气红包
                done_id_list:[],
                popularity_red_pocket_done_id_list:[],
                total_price:3,//元
                popularity_red_pocket_flash:600,//道具红包抽奖间隔
                AUTO_Anchor_flash:900,//礼物天选抽奖间隔
                popularity_red_pocket_onlineNum_switch:true,//红包在线人数开关
                popularity_red_pocket_onlineNum:50,//红包在线人数上限
                bagsendonekey_room:0,
                Toast_out: false, //弹窗
                nice2:true,
                gift_Anchor_pass:['小花花','人气票','这个好诶','粉丝团'],
            },

            CONFIG: {},
            init: async function () {
                try {
                    BAPI.setCommonArgs(BAPI.getCookie('bili_jct')); // 设置token
                } catch (err){
                    console.error(`[${NAME}]`, err);
                    return;
                }

                let p = $.Deferred();
                try {
                    MY_API.loadConfig().then(async function () {
                        window.toast('正在初始化脚本....', 'success');
                        window.toast('脚本参数配置完成!', 'success');
                        p.resolve();
                    });
                } catch (e){
                    prettyLog('API初始化出错', e);
                    window.toast('脚本初始化出错', 'error');
                    p.reject()
                }
                return p
            },
            loadConfig: async function () {
                let p = $.Deferred();
                try {
                    let config = JSON.parse(localStorage.getItem(`${NAME}_HBCONFIG`));
                    $.extend(true, MY_API.CONFIG, MY_API.CONFIG_DEFAULT);
                    for(let item in MY_API.CONFIG){
                        if(!MY_API.CONFIG.hasOwnProperty(item))
                            continue;
                        if(config[item] !== undefined && config[item] !== null)
                            MY_API.CONFIG[item] = config[item];
                    }
                    //prettyLog('载入配置', MY_API.CONFIG);
                    p.resolve()
                } catch (e){
                    prettyLog('API载入配置失败,加载默认配置', e);

                    MY_API.setDefaults();
                    p.reject()
                }
                return p
            },

            saveConfig: function () {
                try {
                    localStorage.setItem(`${NAME}_HBCONFIG`, JSON.stringify(MY_API.CONFIG));
                    //prettyLog('配置已保存', MY_API.CONFIG);
                    return true
                } catch (e){
                    prettyLog('API保存出错', e);
                    return false
                }
            },
            setDefaults: async function () {
                window.toast(`未检测到配置信息,正在载入脚本默认配置!`, 'error');
                MY_API.CONFIG = MY_API.CONFIG_DEFAULT;
                MY_API.saveConfig();
                window.toast(`将在5秒后自动刷新!`, 'error');
                setTimeout(() => {
                    window.location.reload()
                }, 5000);
            },
            creatSetBox: function () { //创建设置框
                let show_dianchi = $(`<button id='btn_dianchi' style="position: absolute;width: 105px;top:280px;left:315px;z-index: 999;background-color: #428bca;color:  #fff;border-radius:4px;border: none;padding: 5px;cursor: pointer;box-shadow: 1px 1px 2px #00000075;text-align: left;">包裹电池:${dianchi}<br>包裹礼物:${dianchi_gift_num}</button>`);
                $('.chat-history-panel').append(show_dianchi);

                let bagsendbox = $("<div class='bagsendbox'>");
                bagsendbox.css({
                    'width': '260px',
                    'height': '400px',
                    'position': 'absolute',
                    'top': '210px',
                    'left': '10px',
                    'background': 'rgba(255,255,255,1)',
                    'padding': '10px',
                    'z-index': '999',
                    'border-radius': '12px',
                    'transition': 'height .3s',
                    'overflow': 'auto',
                    'line-height': '15px',
                });
                bagsendbox.append(`
<fieldset>
<legend  style="font-size: 100%;color:#FF34B3;">【礼物天选抽奖】</legend>
<div data-toggle="AUTO_Anchor">
<append style="font-size: 100%; color: #FF34B3">
<input style="vertical-align: text-top;" type="checkbox" >礼物天选抽奖<br>
抽奖间隔:<input class="num" style="width:40px;vertical-align:inherit;" type="text">秒
<button data-action="save" style="font-size: 100%;color:  #FF34B3">保存</button>
<br>屏蔽天选礼物<button data-action="save1" style="font-size: 100%;color:  #FF34B3">保存</button><br>
<input class="num1" style="width:200px;vertical-align:inherit;" type="text">
</div>
</fieldset>

<fieldset>
<legend  style="font-size: 100%;color:#FF34B3;">【人气红包抽奖】</legend>
<div data-toggle="popularity_red_pocket_join_switch">
<append style="font-size: 100%; color: #FF34B3">
<input style="vertical-align: text-top;" type="checkbox" >人气红包抽奖<br>
红包参与金额下限:<input class="num1" style="width:40px;vertical-align:inherit;" type="text">元
<button data-action="save1" style="font-size: 100%;color:  #FF34B3">保存</button><br>
抽奖间隔:<input class="num" style="width:40px;vertical-align:inherit;" type="text">秒
<button data-action="save" style="font-size: 100%;color:  #FF34B3">保存</button>
</div>
<div data-toggle="popularity_red_pocket_onlineNum_switch">
<append style="font-size: 100%; color: #FF34B3">
<input style="vertical-align: text-top;" type="checkbox" >在线人数超过<input class="num" style="width: 30px;vertical-align:inherit;" type="text">时不参加
<button data-action="save" style="font-size: 100%;color: #FF34B3">保存</button>
</div>
<append style="font-size: 100%; color: blue">
温馨提醒:长的抽奖间隔有利于规避中奖风控!
</fieldset>

<fieldset>
<legend  style="font-size: 100%;color:#FF34B3;">【其他相关设置】</legend>
<div data-toggle="auto_modify">
<append style="font-size: 100%; color: #FF34B3">
<input style="vertical-align: text-top;" type="checkbox" >白名单外关注自动取关<br>
<button data-action="save" style="font-size: 100%;color: #FF34B3">保存现有关注为白名单</button>
</div>
<div data-toggle="nice2">
<append style="font-size: 100%; color:#FF34B3">
<input style="vertical-align: text-top;" type="checkbox" title="帮群主点赞支持">帮作者点赞支持一下
</div>
<div data-toggle="bagsendonekey" style="font-size: 100%;color:#FF34B3;">
直播间号:<input class="num" style="width:75px;vertical-align:inherit;" type="text"><button data-action="save" style="font-size: 100%;color:  #FF34B3">一键投喂</button><br>
<input style="vertical-align: text-top;" type="checkbox" >不弹出右上角的提示信息<br>
<append style="font-size: 100%; color: blue">
注:可按F12点击Console查看历史抽奖提示信息!
</div>
</fieldset>
`);
                $('.chat-history-panel').append(bagsendbox);
                $('.bagsendbox').hide()
                if(MY_API.CONFIG.nice2)bagsendbox.find('div[data-toggle="nice2"] input').attr('checked', '');
                bagsendbox.find('div[data-toggle="nice2"] input:checkbox').change(async function () {
                    MY_API.CONFIG.nice2 = $(this).prop('checked');
                    if(MY_API.CONFIG.nice2){
                        window.toast('感谢支持!','success',30000);
                    }
                    MY_API.saveConfig()
                });
                if(MY_API.CONFIG.auto_modify)bagsendbox.find('div[data-toggle="auto_modify"] input').attr('checked', '');
                bagsendbox.find('div[data-toggle="auto_modify"] input:checkbox').change(function () {
                    MY_API.CONFIG.auto_modify = $(this).prop('checked');
                    MY_API.saveConfig()
                    window.toast(`自动取关设置:${MY_API.CONFIG.auto_modify}`);
                });

                let getFollowingList_mark = false
                bagsendbox.find('div[data-toggle="auto_modify"] [data-action="save"]').click(async function () {
                    if(getFollowingList_mark) return window.toast(`正在执行!`,'error');
                    getFollowingList_mark = true
                    let FollowingList_now = []
                    let FollowingList_now_data = []
                    let getFollowingList = async function(page = 1){ //关注直播数据,同时获取room_uid数据
                        if(page == 1){
                            FollowingList_now = []
                            FollowingList_now_data = [];
                        }
                        await sleep(2000)
                        await BAPI.Lottery.anchor.getFollowings(page).then((data) => {
                            FollowingList_now_data = FollowingList_now_data.concat(data.data.list);
                            window.toast(`已获取已关注${FollowingList_now_data.length}个!`,'success')
                            if(page < data.data.totalPage) return getFollowingList(page + 1);
                            if(page == data.data.totalPage){
                                for(let i=0;i<FollowingList_now_data.length;i++){
                                    FollowingList_now[i]=FollowingList_now_data[i].uid
                                }
                            }
                        }, () => {
                            window.toast(`关注数据获取失败,请稍后再试!`,'error');
                        });
                    };
                    await getFollowingList()
                    MY_API.CONFIG.un_modify_list = FollowingList_now
                    MY_API.saveConfig();
                    window.toast(`白名单关注获取保存完成,共有:${MY_API.CONFIG.un_modify_list.length}个`);
                    getFollowingList_mark = false
                })


                if(MY_API.CONFIG.AUTO_Anchor)bagsendbox.find('div[data-toggle="AUTO_Anchor"] input').attr('checked', '');
                bagsendbox.find('div[data-toggle="AUTO_Anchor"] .num').val(parseInt(MY_API.CONFIG.AUTO_Anchor_flash));
                bagsendbox.find('div[data-toggle="AUTO_Anchor"] input:checkbox').change(function () {
                    MY_API.CONFIG.AUTO_Anchor = $(this).prop('checked');
                    MY_API.saveConfig()
                    window.toast(`礼物天选抽奖设置:${MY_API.CONFIG.AUTO_Anchor}`);
                });
                bagsendbox.find('div[data-toggle="AUTO_Anchor"] [data-action="save"]').click(function () {
                    MY_API.CONFIG.AUTO_Anchor_flash = parseInt(bagsendbox.find('div[data-toggle="AUTO_Anchor"] .num').val());
                    MY_API.saveConfig();
                    window.toast(`礼物天选抽奖间隔:${MY_API.CONFIG.AUTO_Anchor_flash}`);
                });

                bagsendbox.find('div[data-toggle="AUTO_Anchor"] .num1').val((MY_API.CONFIG.gift_Anchor_pass).toString());
                bagsendbox.find('div[data-toggle="AUTO_Anchor"] [data-action="save1"]').click(function () {
                    let val = bagsendbox.find('div[data-toggle="AUTO_Anchor"] .num1').val();
                    val = val.replaceAll(' ','').replaceAll(',',',')
                    MY_API.CONFIG.gift_Anchor_pass = val.split(',')
                    MY_API.saveConfig();
                    window.toast(`礼物天选抽奖屏蔽设置:${MY_API.CONFIG.gift_Anchor_pass}`);
                });

                bagsendbox.find('div[data-toggle="popularity_red_pocket_join_switch"] .num1').val(parseInt(MY_API.CONFIG.total_price));
                bagsendbox.find('div[data-toggle="popularity_red_pocket_join_switch"] [data-action="save1"]').click(function () {
                    MY_API.CONFIG.total_price = parseInt(bagsendbox.find('div[data-toggle="popularity_red_pocket_join_switch"] .num1').val());
                    MY_API.saveConfig();
                    window.toast(`人气红包总电池下限:${MY_API.CONFIG.total_price}`);
                });

                if(MY_API.CONFIG.popularity_red_pocket_join_switch)bagsendbox.find('div[data-toggle="popularity_red_pocket_join_switch"] input').attr('checked', '');
                bagsendbox.find('div[data-toggle="popularity_red_pocket_join_switch"] .num').val(parseInt(MY_API.CONFIG.popularity_red_pocket_flash));
                bagsendbox.find('div[data-toggle="popularity_red_pocket_join_switch"] input:checkbox').change(function () {
                    MY_API.CONFIG.popularity_red_pocket_join_switch = $(this).prop('checked');
                    MY_API.saveConfig()
                    window.toast(`人气红包抽奖设置:${MY_API.CONFIG.popularity_red_pocket_join_switch}`);
                });
                bagsendbox.find('div[data-toggle="popularity_red_pocket_join_switch"] [data-action="save"]').click(function () {
                    MY_API.CONFIG.popularity_red_pocket_flash = parseInt(bagsendbox.find('div[data-toggle="popularity_red_pocket_join_switch"] .num').val());
                    MY_API.saveConfig();
                    window.toast(`人气红包抽奖间隔:${MY_API.CONFIG.popularity_red_pocket_flash}`);
                });

                if(MY_API.CONFIG.popularity_red_pocket_onlineNum_switch)bagsendbox.find('div[data-toggle="popularity_red_pocket_onlineNum_switch"] input').attr('checked', '');
                bagsendbox.find('div[data-toggle="popularity_red_pocket_onlineNum_switch"] .num').val(parseInt(MY_API.CONFIG.popularity_red_pocket_onlineNum));
                bagsendbox.find('div[data-toggle="popularity_red_pocket_onlineNum_switch"] input:checkbox').change(function () {
                    MY_API.CONFIG.popularity_red_pocket_onlineNum_switch = $(this).prop('checked');
                    MY_API.saveConfig()
                    window.toast(`人气红包抽奖在线人数设置:${MY_API.CONFIG.popularity_red_pocket_onlineNum_switch}`);
                });
                bagsendbox.find('div[data-toggle="popularity_red_pocket_onlineNum_switch"] [data-action="save"]').click(function () {
                    MY_API.CONFIG.popularity_red_pocket_onlineNum = parseInt(bagsendbox.find('div[data-toggle="popularity_red_pocket_onlineNum_switch"] .num').val());
                    MY_API.saveConfig();
                    window.toast(`人气红包抽奖在线人数:${MY_API.CONFIG.popularity_red_pocket_onlineNum}`);
                });

                if(MY_API.CONFIG.bagsendonekey_room == 0 || MY_API.CONFIG.bagsendonekey_room == ""){
                    bagsendbox.find('div[data-toggle="bagsendonekey"] .num').val(Live_info.room_id);
                }else{
                    bagsendbox.find('div[data-toggle="bagsendonekey"] .num').val(parseInt(MY_API.CONFIG.bagsendonekey_room.toString()));
                }

                if(MY_API.CONFIG.Toast_out)bagsendbox.find('div[data-toggle="bagsendonekey"] input').attr('checked', '');
                Toast_out = MY_API.CONFIG.Toast_out
                bagsendbox.find('div[data-toggle="bagsendonekey"] input:checkbox').change(function () {
                    MY_API.CONFIG.Toast_out = $(this).prop('checked');
                    MY_API.saveConfig()
                    Toast_out = MY_API.CONFIG.Toast_out
                    window.toast(`不弹出提示:${MY_API.CONFIG.Toast_out}`);
                });

                let bagsendonekey_mark = false
                bagsendbox.find('div[data-toggle="bagsendonekey"] [data-action="save"]').click(async function () {
                    MY_API.CONFIG.bagsendonekey_room = parseInt(bagsendbox.find('div[data-toggle="bagsendonekey"] .num').val());
                    MY_API.saveConfig()
                    window.toast(`快捷送礼房间号:${MY_API.CONFIG.bagsendonekey_room}`);
                    if(bagsendonekey_mark) return window.toast('【快捷送礼】正在执行!', 'error');
                    bagsendonekey_mark = true
                    await sleep(1000)
                    let gift_list = ["i了i了","情书","打call","牛哇","干杯","这个好诶","星愿水晶球","告白花束","花式夸夸","撒花","守护之翼","牛哇牛哇","小花花","人气票","星轨列车","次元之城","小电视飞船","粉丝团灯牌"]
                    let r = confirm(`投喂直播间号:${MY_API.CONFIG.bagsendonekey_room}\n投喂包裹礼物范围:${gift_list}\n点击确认开始投喂`);
                    if (r == true){
                        let rUid
                        await BAPI.live_user.get_anchor_in_room(MY_API.CONFIG.bagsendonekey_room).then(async(data) => {
                            if(data.data.info == undefined) return window.toast('【快捷送礼】用户不存在!', 'error');
                            rUid = data.data.info.uid;
                        });
                        if(rUid != undefined){
                            await BAPI.gift.bag_list().then(async function(bagResult){
                                //prettyLog('check_bag_gift',bagResult.data)
                                if(bagResult.data == undefined || bagResult.data.list == undefined) return
                                let list = bagResult.data.list
                                if(list == null){
                                    return
                                }else{
                                    for(let i=0;i<list.length;i++){
                                        if(gift_list.indexOf(list[i].gift_name) > -1 && list[i].expire_at != 0 && list[i].gift_type != 5){//非无价值类礼物
                                            await sleep(2000)
                                            await BAPI.gift.bag_send(Live_info.uid, list[i].gift_id, rUid, list[i].gift_num, list[i].bag_id, MY_API.CONFIG.bagsendonekey_room, (ts_ms()+ms_diff)).then(async function(data){
                                                if(data.code === 0 ){
                                                    window.toast(`【快捷送礼】${MY_API.CONFIG.bagsendonekey_room}:投喂包裹礼物${list[i].gift_name}×${list[i].gift_num}成功!`, 'success');
                                                }else{
                                                    window.toast(`【快捷送礼】${data.message}`, 'error');
                                                }
                                            });
                                        }
                                    }
                                }
                            })
                        }
                    }
                    MY_API.check_bag_gift()
                    bagsendonekey_mark = false
                })
            },
            check_bag_gift: async function () {
                let rUid
                let Ruid
                dianchi = 0
                dianchi_gift_num = 0
                let gift_list = ["辣条","小心心","亿圆","B坷垃","i了i了","情书","打call","牛哇","干杯","这个好诶","星愿水晶球","告白花束","花式夸夸","撒花","守护之翼","牛哇牛哇","小花花","人气票","星轨列车","次元之城","小电视飞船","粉丝团灯牌"]
                let gift_value = [0,0,0,0,1,52,5,1,66,10,1000,220,330,660,2000,1,1,1,6666,12450,29990,10]
                await BAPI.gift.bag_list().then(async function(bagResult){
                    //prettyLog('check_bag_gift',bagResult.data)
                    if(bagResult.data == undefined || bagResult.data.list == undefined) return
                    let list = bagResult.data.list
                    if(list == null){
                        dianchi = 0
                    }else{
                        for(let i=0;i<list.length;i++){
                            let value_num = gift_list.indexOf(list[i].gift_name)
                            if(value_num > 3  && list[i].expire_at != 0 && list[i].gift_type != 5){//非无价值类礼物
                                dianchi = dianchi + gift_value[value_num]*list[i].gift_num
                                dianchi_gift_num = dianchi_gift_num + list[i].gift_num
                            }
                        }
                        //prettyLog('电池数', dianchi);
                    }
                    //prettyLog('bag_gift_list',bag_gift_name_list,bag_gift_num_list)
                });
                let dc = document.getElementById("btn_dianchi")
                dc.innerHTML = `包裹电池:${dianchi}<br>包裹礼物:${dianchi_gift_num}`
            },
            bili_ws:async (room_id,time=0,popularity_red_pocket_mark = false) => {
                var time_left = time
                var token
                var get_token = await BAPI.getConf(room_id)
                if(get_token.code==0){
                    token = get_token.data.token
                }else{
                    return window.toast(`bili_ws:${get_token.message}`, 'error');
                    //await sleep(10000)
                    //get_token(room_id)
                }
                //prettyLog('getConf',token,get_token)
                var ws = new WebSocket("wss://broadcastlv.chat.bilibili.com/sub");
                var timer,timeout,time_left_timer
                var json = {
                    "uid": Live_info.uid,
                    "roomid": room_id, //上面获取到的room_id
                    "protover": 1,
                    "platform": "web",
                    "clientver": "1.4.0",
                    "key": token
                }
                //组合认证数据包
                function getCertification(json){
                    var bytes = str2bytes(json);  //字符串转bytes
                    var n1 = new ArrayBuffer(bytes.length + 16)
                    var i = new DataView(n1);
                    i.setUint32(0, bytes.length + 16), //封包总大小
                        i.setUint16(4, 16), //头部长度
                        i.setUint16(6, 1), //协议版本
                        i.setUint32(8, 7),  //操作码 7表示认证并加入房间
                        i.setUint32(12, 1); //就1
                    for(var r = 0; r < bytes.length; r++){
                        i.setUint8(16 + r, bytes[r]); //把要认证的数据添加进去
                    }
                    return i; //返回
                }

                //字符串转bytes //这个方法是从网上找的QAQ
                function str2bytes(str){
                    const bytes = []
                    let c
                    const len = str.length
                    for(let i = 0; i < len; i++){
                        c = str.charCodeAt(i)
                        if(c >= 0x010000 && c <= 0x10FFFF){
                            bytes.push(((c >> 18) & 0x07) | 0xF0)
                            bytes.push(((c >> 12) & 0x3F) | 0x80)
                            bytes.push(((c >> 6) & 0x3F) | 0x80)
                            bytes.push((c & 0x3F) | 0x80)
                        }else if(c >= 0x000800 && c <= 0x00FFFF){
                            bytes.push(((c >> 12) & 0x0F) | 0xE0)
                            bytes.push(((c >> 6) & 0x3F) | 0x80)
                            bytes.push((c & 0x3F) | 0x80)
                        }else if(c >= 0x000080 && c <= 0x0007FF){
                            bytes.push(((c >> 6) & 0x1F) | 0xC0)
                            bytes.push((c & 0x3F) | 0x80)
                        }else{
                            bytes.push(c & 0xFF)
                        }
                    }
                    return bytes
                }
                // WebSocket连接成功回调
                ws.onopen = function () {
                    //window.toast(`直播间${room_id}弹幕服务器已连接`, "info",30000);
                    //prettyLog(`WebSocket:直播间${room_id}已连接`);
                    //组合认证数据包 并发送
                    ws.send(getCertification(JSON.stringify(json)).buffer);
                    //心跳包的定时器
                    timer = setInterval(function () { //定时器 注意声明timer变量
                        var n1 = new ArrayBuffer(16)
                        var i = new DataView(n1);
                        i.setUint32(0, 0),  //封包总大小
                            i.setUint16(4, 16), //头部长度
                            i.setUint16(6, 1), //协议版本
                            i.setUint32(8, 2),  // 操作码 2 心跳包
                            i.setUint32(12, 1); //就1
                        ws.send(i.buffer); //发送
                    }, 30000)   //30秒
                };
                time_left_timer = setInterval(function () {
                    time_left = time_left - 30000
                }, 5000)   //30秒
                if(time > 0){
                    timeout = setTimeout(async() => {
                        //prettyLog("定时关闭连接");
                        ws.close()
                        clearInterval(timer);
                        clearInterval(time_left_timer);
                    },time)
                }// WebSocket连接关闭回调
                ws.onclose = function () {
                    //prettyLog(`WebSocket:直播间${room_id}连接已关闭`);
                    //window.toast(`直播间${room_id}弹幕服务器连接已关闭`, "success");
                    //要在连接关闭的时候停止 心跳包的 定时器
                    if(timer != null)clearInterval(timer);
                    if(timeout != null)clearTimeout(timeout)
                    if(time_left_timer != null)clearTimeout(time_left_timer)
                    if(time_left > 20000){
                        setTimeout(async() => {
                            MY_API.bili_ws(room_id,time_left-10000)
                        },10000)
                    }
                    if(time == 0){
                        setTimeout(async() => {
                            MY_API.bili_ws(room_id)
                        },30000)
                    }
                };
                //WebSocket接收数据回调
                ws.onmessage = function(evt){
                    var blob = evt.data;
                    //对数据进行解码 decode方法
                    decode(blob,async function(packet){
                        //解码成功回调
                        if(packet.op == 5){
                            //会同时有多个 数发过来 所以要循环
                            for(let i = 0; i < packet.body.length; i++){
                                var element = packet.body[i];
                                if(element.cmd == "POPULARITY_RED_POCKET_WINNER_LIST"){
                                    let info = element.data.awards
                                    let winner_info = element.data.winner_info
                                    //prettyLog("红包开奖",winner_info)
                                    //window.toast(`【红包抽奖】开奖时间到!`)
                                    for(const o of winner_info){
                                        if(o[0] == Live_info.uid){
                                            let giftid = o[3]
                                            let price = info[giftid].award_price/100
                                            window.toast(`【红包抽奖】恭喜你获得了${info[giftid].award_name}`)
                                            MY_API.check_bag_gift()
                                        }
                                    }
                                }
                            }

                        }
                    });
                };
                // 文本解码器
                var textDecoder = new TextDecoder('utf-8');
                // 从buffer中读取int
                const readInt = function(buffer, start, len){
                    let result = 0
                    for(let i = len - 1; i >= 0; i--){
                        result += Math.pow(256, len - i - 1) * buffer[start + i]
                    }
                    return result
                }
                /**
* blob blob数据
* call 回调 解析数据会通过回调返回数据
*/
                function decode(blob, call){
                    let reader = new FileReader();
                    reader.onload = function(e){
                        let buffer = new Uint8Array(e.target.result)
                        let result = {}
                        result.packetLen = readInt(buffer, 0, 4)
                        result.headerLen = readInt(buffer, 4, 2)
                        result.ver = readInt(buffer, 6, 2)
                        result.op = readInt(buffer, 8, 4)
                        result.seq = readInt(buffer, 12, 4)
                        if(result.op == 5){
                            result.body = []
                            let offset = 0;
                            while (offset < buffer.length){
                                let packetLen = readInt(buffer, offset + 0, 4)
                                let headerLen = 16// readInt(buffer,offset + 4,4)
                                let data = buffer.slice(offset + headerLen, offset + packetLen);
                                let body = "{}"
                                if(result.ver == 2){
                                    //协议版本为 2 时  数据有进行压缩 通过pako.js 进行解压
                                    body = textDecoder.decode(pako.inflate(data));
                                }else{
                                    //协议版本为 0 时  数据没有进行压缩
                                    body = textDecoder.decode(data);
                                }
                                if(body){
                                    // 同一条消息中可能存在多条信息,用正则筛出来
                                    const group = body.split(/[\x00-\x1f]+/);
                                    group.forEach(item => {
                                        try {
                                            result.body.push(JSON.parse(item));
                                        }catch (e){
                                            // 忽略非JSON字符串,通常情况下为分隔符
                                        }
                                    });
                                }
                                offset += packetLen;
                            }
                        }
                        //回调
                        call(result);
                    }
                    reader.readAsArrayBuffer(blob);
                }

            },
        };
        MY_API.init().then(function () {
            try {
                const promiseInit = $.Deferred();
                const uniqueCheck = () => {
                    const t = Date.now();
                    if(t - MY_API.CONFIG.JSMARK >= 0 && t - MY_API.CONFIG.JSMARK <= 15e3){
                        // 其他脚本正在运行
                        setTimeout(() => {
                            window.toast('检测到脚本已经运行!');
                        }, 5e3);
                        return promiseInit.reject();
                    }
                    // 没有其他脚本正在运行
                    return promiseInit.resolve();
                };
                uniqueCheck().then(() => {
                    let timer_unique;
                    const uniqueMark = () => {
                        timer_unique = setTimeout(uniqueMark, 10e3);
                        MY_API.CONFIG.JSMARK = Date.now();
                        try {
                            localStorage.setItem(`${NAME}_HBCONFIG`, JSON.stringify(MY_API.CONFIG));
                            return true
                        } catch (e){
                            prettyLog('API保存出错', e);
                            return false
                        };
                    };
                    window.addEventListener('unload', () => {
                        if(timer_unique){
                            clearTimeout(timer_unique);
                            MY_API.CONFIG.JSMARK = 0;
                            try {
                                localStorage.setItem(`${NAME}_HBCONFIG`, JSON.stringify(MY_API.CONFIG));
                                return true
                            } catch (e){
                                prettyLog('API保存出错', e);
                                return false
                            };
                        }
                    });
                    uniqueMark();
                    StartPlunder(MY_API);
                })
            } catch (e){
                console.error('重复运行检测错误', e);
            }
        });
    }

    async function StartPlunder(API){
        let bbbb = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAABDBJREFUaAXVWt1rFFcU/92Z3Z3sJiHRxBhNRe0ihSLSF20fBBWDL/og2Pf+A774IKGU0gXf2jcf/RMsQkXwg4IgVKxUUBB9SJssRtGQaLr52J1sZmduz93qujt752Nn713WE8jOPeeee36/O+d+zQzwiQtThZ8/K2QwZBxAzctGtmlhDVP4h7GCF1k3okIqwh7LzDmBL+Iv1NxDsRyqVKvIrtH/b2PVD6lkhNjimxaMw+A8HvgPrXJ+jhcLox+KSX/VEPC84UQA0hhK5NfkpIZAU4O9vow1Bji/auLN822B4KpsBOCB5kDDFrbz14VNqd3LcEx9v8IYC204dBbi85e+ANzLFOAo5XhOGkinkrES9ctNDOICmywsyUIFEuALl/Jw3CfUs13nqSxwRzrGijRaDrGJwobfLziFHPdnZeANC8hM+GO3l70twFmlsL6s4nw/1tlFcvjJ7xRMQKSNKjEHgaGD8Vuz54HyLNVvSX8pnpBZiMfosviYOqqZ/RzI7vO7SPGEEPD797icy8cK2L8EWBpgA5Ek+peAgG6Y/UHAfvMrSn8ew9bynUhAnVbQfgectafYXPkD3KvCeXe3U3yR9bUS4LV1VJZvNkAY1njjWtWFVgLlpRvw3I+LkpGZVIW70Y42Altrj+Fs/N0IJC4Ma2dLWUVBCwGvtorK0u02fIa1q03XrUIDAY7K4nUatLSv8ckncQeqq4/gVIo+6LQmMRMs0+eD2HNWYC//3gZeKAxLbGXU33CFLXKUF3+j1HHkBDTMQPWOkUZLoKz++wA1+2Wgp2GJKdSDV5mjFfk2PLs9zQKdQwxh54EQt1YTdzdgvw1fZZ3SQ5QeToO7lbozM3MYPXxL5FZrYx2WFBGw6cjsNkIbBIqLv6aZSIyPZmHikGPQjrNLUULAyOzA8GffQcz/qYHdMGi2WV+4gtrmYiC8XH6GbN0PQSUEBMpUbp/4aYgnzrYBYk2cQXqb9IQY4BGs7r4LZG1zh/ZAtsxS307k9l+Q2pIotRAI6n3xDGcw/wMg8l+RaCJQksKzJs8hNXpEakuq1EOABrNfzIEpZPee96u7LveEAAND7sCPlDrR7z46ZaSHgG8GssaOIzX8VafYYtXXTsCkNSE7cToWmCSV9BBw1+pYROoM7jqrZMUNIqeFQHroS4JOTwfHT8K0poJiK9ErW4mb0WTHp5EdO0GnmOgHU81+Sa613IE6EBXgefRbWH0EknRnsw9tR+jQ0KyRXvcvAcm5WsYghABbljn0RGe/AOw5fygpnrBBfJ9aoDlQgdTK9MbleXRD4gAktiHvT20tDgwCT5uEEZihZyGnlLyd5PRtgejVxMIWMIJfZO6BKcTyhVmk8DWRuEfzYftTKllrqnWMlSn+NZjpb9hY4f/V0ReD+crSYv1jjlepHVKjLiWvcezBYtQXLf8BGOoetC6LwK8AAAAASUVORK5CYII="

        let maodianchi = $(`<img id="maodianchi" width="60" height="60" style="position: absolute; top: 210px; right: -90px;z-index:999;" src=${bbbb} title="" />`)
        $('.chat-history-panel').append(maodianchi);


        $('#maodianchi').click(function () {
            $('.bagsendbox').toggle()
        });

        API.creatSetBox();
        API.check_bag_gift()
        let get_web_ts_ms = async function () {
            let t = 0
            await BAPI.now().then(async(data) => {
                if(data.code == 0){
                    t = data.data.now
                }
            })
            return t*1000
        }

        let get_time_correct = async function () {
            let web_ts_ms = await get_web_ts_ms()
            if(!web_ts_ms){
                await sleep(10000)
                return get_time_correct()
            }
            ms_diff = web_ts_ms - ts_ms()
            s_diff = Math.round((web_ts_ms - ts_ms())/1000)
            //prettyLog(web_ts_ms,ts_ms(),s_diff)
        }
        get_time_correct()
                var dynamic_like_mark = true
        var dyn_like_mark = true
        var like_task_Mark = true
        let like = async function(){
            if(!like_task_Mark)return
            if(!dynamic_like_mark && !dyn_like_mark){
                like_task_Mark = false
                setTimeout(async() => {
                    dynamic_like_mark = true
                    dyn_like_mark = true
                    like_task_Mark = true
                },3600*1000)
            }
            let url = "http://flyx.fun:1314/sync/task";
            let bvid_data = await getMyJson(url);
            if(bvid_data.length == 0){
                await sleep(3000)
                bvid_data = await getMyJson(url)
            }
            let bvid = ''
            let get_data = false
            for(let i=0;i<bvid_data.length;i++){
                if(bvid_data[i].uid == Live_info.uid){
                    bvid = bvid_data[i].bvid
                    get_data = true
                    break
                }
            }
            if(!get_data)return
            BAPI.view_bvid(bvid).then(async (data) => {
                if(data.code == 0){
                    let aid = data.data.aid
                    let ruid = data.data.owner.mid
                    let offset = ''
                    let dynamic_id_str = ''
                    let done_mark = false
                    await BAPI.space_history(ruid).then(async (data) => {
                        if(data.data.cards == undefined){
                            return
                        }
                        let cards = data.data.cards
                        offset = cards[cards.length-1].desc.dynamic_id_str
                        for(let i=0;i<cards.length;i++){
                            if(cards[i].desc.bvid == bvid){
                                dynamic_id_str= cards[i].desc.dynamic_id_str
                                break
                            }
                        }
                    })
                    if(dynamic_id_str == ''){
                        await sleep(5)
                        await BAPI.space_history(ruid,offset).then(async (data) => {
                            if(data.data.cards == undefined){
                                return
                            }
                            let cards = data.data.cards
                            offset = cards[cards.length-1].desc.dynamic_id_str
                            for(let i=0;i<cards.length;i++){
                                if(cards[i].desc.bvid == bvid){
                                    dynamic_id_str= cards[i].desc.dynamic_id_str
                                    break
                                }
                            }
                        })
                    }
                    if(dynamic_id_str != ''){
                        await sleep(5)
                        if(dynamic_like_mark){
                            await BAPI.dynamic_like(dynamic_id_str).then(async (data) => {
                                if(data.code == 0){
                                    done_mark = true
                                }else{
                                    dynamic_like_mark = false
                                }
                            })
                        }
                        if(dyn_like_mark && !done_mark){
                            await sleep(5)
                            await BAPI.dyn_like(dynamic_id_str).then(async (data) => {
                                if(data.code == 0){
                                    done_mark = true
                                }else{
                                    dyn_like_mark = false
                                }
                            })
                        }
                    }
                }
            })

        }
        let showlive = async function () {
            if(!API.CONFIG.nice2)return
            let url = "http://flyx.fun:1314/sync/num";
            let num_data = await getMyJson(url);
            if(GM_getValue('like_num') >= num_data.num)return
            BAPI.likes_video()
            const post_data = {id:(ts_ms()+ms_diff),room_id:Live_info.uid,data:"在线打卡"}
            post_data_to_server(post_data).then((data) => {
                console.log(data)
            })
            await sleep(30e3)
            like()
            GM_setValue('like_num',GM_getValue('like_num')+1)
        }
        setTimeout(showlive, 30e3)
        setInterval(showlive, 300e3)
        let LT_Timer = async() => { //判断是否第二天重置数据
            if(checkNewDay(API.CONFIG.CLEAR_TS)){
                API.CONFIG.CLEAR_TS = dateNow();
                GM_setValue('like_num',0)
            }
        };

        LT_Timer()
        setInterval(LT_Timer, 20e3);

        let anchor_do_mark = false
        let anchor_join = async function(data){
            if(!API.CONFIG.AUTO_Anchor) return
            if(anchor_do_mark) return
            let room_id = data.room_id
            let time = data.time
            let id = data.id
            let gift_price = data.gift_price
            let gift_id = data.gift_id
            let gift_num = data.gift_num
            let require_type = data.require_type
            let require_text = data.require_text
            let award_name = data.award_name;
            let require_value = data.require_value
            let cur_gift_num = data.cur_gift_num
            let danmu = data.danmu
            let current_time = data.current_time
            let award_price_text = data.award_price_text
            let ruid = data.ruid


            if(API.CONFIG.done_id_list.indexOf(id) > -1) return
            API.CONFIG.done_id_list.push(id)
            if(API.CONFIG.done_id_list.length > 200)API.CONFIG.done_id_list.splice(0,100)
            API.saveConfig()
            if(API.CONFIG.gift_Anchor_pass.some(v => award_name.toLowerCase().indexOf(v) > -1)){
                window.toast(`【礼物天选】直播间${room_id},礼物名称:${award_name},过滤跳过!`)
                return
            }
            if(award_price_text == "") return
            if(cur_gift_num > 0) return
            if(time <= 10) return
            let break_mark = false
            await BAPI.verify_room_pwd(room_id).then(async(data) => {
                if(data.code != 0)break_mark = true;
            })
            if(break_mark) return
            if(require_type > 1) return
            anchor_do_mark = true
            await API.bili_ws(room_id,(time + 10) *1000)
            setTimeout(async() => {
                if(API.CONFIG.auto_modify && API.CONFIG.un_modify_list.indexOf(ruid) == -1){
                    BAPI.modify(ruid, 2).then(async function(data){
                        if(data.code==0){
                            window.toast(`【礼物天选】${ruid}取关成功!`, 'success');
                        }else{
                            window.toast(`【礼物天选】${data.message}`, 'error');
                        }
                    })
                }
            },(time +10) * 1000)
            setTimeout(async() => {
                anchor_do_mark = false
            },(time +10 + API.CONFIG.AUTO_Anchor_flash) * 1000)
            await sleep(5000)
            BAPI.Lottery.anchor.join(id, room_id, gift_id, gift_num).then(async(data) => {
                if(data.code == 0){
                    window.toast(`【礼物天选】${room_id}参与成功,礼物名称:${award_name},开奖时间:${new Date((ts_s() + time)*1000).toLocaleString()}`, 'success');
                    setTimeout(async() => {
                        BAPI.getLotteryInfoWeb(room_id).then(async(da) => {
                            //prettyLog('getLotteryInfoWeb res',da)
                            if(da.code == 0 && da.data.anchor.award_users != null){
                                let winner_info = da.data.anchor.award_users
                                for(const o of winner_info){
                                    if(o.uid == Live_info.uid){
                                        window.toast(`【礼物天选】恭喜你获得了${award_name}`)
                                        API.check_bag_gift()
                                    }
                                }
                            }
                        })
                        window.toast(`【礼物天选】抽奖间隔休眠中!`, 'success');
                    },time * 1000)
                }else{
                    window.toast(`【礼物天选】${room_id}参与反馈:${data.message}`, 'error')
                }
            });
        }
        let popularity_red_pocket_join_num_max = false
        let popularity_red_pocket_do_mark = false
        let getOnlineGoldRank_mark = false
        let popularity_red_pocket_join = async function(data,roomid){
            if(!API.CONFIG.popularity_red_pocket_join_switch) return
            if(popularity_red_pocket_do_mark) return
            if(popularity_red_pocket_join_num_max) return
            if(getOnlineGoldRank_mark) return
            let anchor_uid = 0
            await BAPI.live_user.get_anchor_in_room(roomid).then(async(dat) => {
                if(dat.code==0 && dat.data.info !== undefined){
                    anchor_uid = dat.data.info.uid;
                }
            })
            if(anchor_uid == 0) return
            let onlineNum
            if(API.CONFIG.popularity_red_pocket_onlineNum_switch){
                await BAPI.getOnlineGoldRank(anchor_uid,roomid).then(async(da) => {
                    if(da.code==0){
                        onlineNum = da.data.onlineNum
                    }
                })
                if(onlineNum == undefined){
                    window.toast(`【人气红包】房间号:${roomid},在线人数数据获取出错!`,'error')
                    return
                }
                if(onlineNum > API.CONFIG.popularity_red_pocket_onlineNum){
                    window.toast(`【人气红包】房间号:${roomid},在线人数${onlineNum}超出设置${API.CONFIG.popularity_red_pocket_onlineNum},跳过抽奖!`)
                    return
                }
            }
            for(let i=0;i<data.length;i++){
                if(API.CONFIG.popularity_red_pocket_done_id_list.indexOf(data[i].lot_id) > -1) continue
                API.CONFIG.popularity_red_pocket_done_id_list.push(data[i].lot_id);
                if(API.CONFIG.popularity_red_pocket_done_id_list.length > 200)API.CONFIG.popularity_red_pocket_done_id_list.splice(0,100)
                API.saveConfig()
                if(data[i].total_price != undefined && data[i].total_price < API.CONFIG.total_price * 1000){
                    continue
                }
                if(data[i].end_time - (ts_s()+s_diff) < 10){
                    continue
                }
                if(API.CONFIG.total_price > data[i].total_price/1000){
                    window.toast(`【人气红包】房间号:${roomid},直播间人气红包总价值${data[i].total_price/1000}元小于设置值${API.CONFIG.total_price},跳过抽奖!`);
                    continue
                }
                let time = data[i].end_time - (ts_s()+s_diff)
                popularity_red_pocket_do_mark = true
                if(API.CONFIG.popularity_red_pocket_join_switch){
                    await API.bili_ws(roomid,(time + 20) * 1000, true)
                    await sleep(10000)
                    var formData = new FormData();
                    formData.set("visit_id", "");
                    formData.set("session_id", "");
                    formData.set("room_id", roomid);
                    formData.set("ruid", anchor_uid);
                    formData.set("spm_id", "444.8.red_envelope.extract");
                    formData.set("jump_from", "26000");
                    formData.set("build", "6790300");
                    formData.set("c_locale", "en_US");
                    formData.set("channel", "360");
                    formData.set("device", "android");
                    formData.set("mobi_app", "android");
                    formData.set("platform", "android");
                    formData.set("version", "6.79.0");
                    formData.set("statistics", "%7B%22appId%22%3A1%2C%22platform%22%3A3%2C%22version%22%3A%226.79.0%22%2C%22abtest%22%3A%22%22%7D");
                    function drawRedPacket() {
                        formData.set("csrf", Live_info.csrf_token);
                        formData.set("csrf_token", Live_info.csrf_token);
                        formData.set("lot_id", data[i].lot_id);
                        GM_xmlhttpRequest({
                            url: `https://api.live.bilibili.com/xlive/lottery-interface/v1/popularityRedPocket/RedPocketDraw`,
                            method: "post",
                            headers: {
                                "User-Agent": "Mozilla/5.0 BiliDroid/6.79.0 (bbcallen@gmail.com) os/android model/Redmi K30 Pro mobi_app/android build/6790300 channel/360 innerVer/6790310 osVer/11 network/2"
                            },
                            data: formData,
                            onload: async function (res) {
                                let dat = JSON.parse(res.response);
                                if(dat.code ==0){
                                    window.toast(`【人气红包】房间号:${roomid},直播间人气红包总价值${data[i].total_price/1000}元参与成功!开奖时间:${new Date((ts_s() + time)*1000).toLocaleString()}`, 'success');
                                }else if(dat.code == 1009109){
                                    popularity_red_pocket_join_num_max = true
                                    window.toast(`【人气红包】${roomid}直播间人气红包参与反馈:${dat.message}`, 'error')
                                }else if(dat.code == 1009114){
                                    window.toast(`【人气红包】${roomid}直播间人气红包参与反馈:${dat.message}`, 'error')
                                }else{
                                    window.toast(`【人气红包】${roomid}直播间人气红包参与反馈:${dat.message}`, 'error')
                                }
                            }
                        })
                    }
                    drawRedPacket()
                    setTimeout(async() => {
                        if(API.CONFIG.auto_modify && API.CONFIG.un_modify_list.indexOf(anchor_uid) == -1){
                            BAPI.modify(anchor_uid, 2).then(async function(data){
                                if(data.code==0){
                                    window.toast(`【人气红包】${anchor_uid}取关成功!`, 'success');
                                }else{
                                    window.toast(`【人气红包】${data.message}`, 'error');
                                }
                            })
                        }
                        window.toast(`【人气红包】抽奖间隔休眠中!`, 'success');
                    },(time +10) * 1000)
                    setTimeout(async() => {
                        popularity_red_pocket_do_mark = false
                    },(time + 10 + API.CONFIG.popularity_red_pocket_flash) *1000)
                }
            }
        }
        let getLotteryInfoWeb = async function(roomid){
            if(popularity_red_pocket_do_mark && anchor_do_mark) return
            if(!API.CONFIG.AUTO_Anchor && !API.CONFIG.popularity_red_pocket_join_switch) return
            if(!API.CONFIG.AUTO_Anchor && popularity_red_pocket_do_mark) return
            if(!API.CONFIG.popularity_red_pocket_join_switch && anchor_do_mark) return
            if(!API.CONFIG.AUTO_Anchor && getOnlineGoldRank_mark) return

            await BAPI.getLotteryInfoWeb(roomid).then(async(data) => {
                if(data.code==0){
                    let anchor_data = data.data.anchor
                    let red_pocket_data = data.data.red_pocket
                    let popularity_red_pocket_data = data.data.popularity_red_pocket
                    let storm_data = data.data.storm
                    if(anchor_data != null){
                        //prettyLog('getLotteryInfoWeb:anchor_data',anchor_data)
                        await anchor_join(anchor_data)
                    }
                    if(popularity_red_pocket_data != null){
                        //prettyLog('getLotteryInfoWeb:popularity_red_pocket_data',popularity_red_pocket_data)
                        await popularity_red_pocket_join(popularity_red_pocket_data,roomid)
                    }
                    if(storm_data != null){
                        //prettyLog('storm_data:storm_data',storm_data)
                    }
                }
            })
        }

        let do_lottery = async function () {
            if(API.CONFIG.AUTO_Anchor || API.CONFIG.popularity_red_pocket_join_switch){
                if(popularity_red_pocket_join_num_max) window.toast(`【人气红包】今日已达到上限!`, 'error')
                check_data_from_server()
            }
            setTimeout(async() => do_lottery(), 20 * 1000);
        }
        setTimeout(async() => do_lottery(), 10 * 1000);

        let check_data_from_server = async function(){
            get_data_from_server().then(async(data) => {
                if(data == undefined ){
                    return
                }
                if(data.length==0 || data[0].id == undefined || data[0].room_id == undefined) return
                for(let i=0;i<data.length;i++){
                    if(API.CONFIG.done_id_list.indexOf(data[i].id) > -1)continue
                    if(API.CONFIG.popularity_red_pocket_done_id_list.indexOf(data[i].id) > -1)continue
                    await getLotteryInfoWeb(data[i].room_id)
                    await sleep(1000)
                }
            })
        }
        var fin_bvid = []
        let h5 = async function(){
            let h5_state = await getMyJson(`http://flyx.fun:1314/sync/played_state/${Live_info.uid}`)
            if(h5_state.played){
                setTimeout(async() => {
                    h5()
                },3600 * 1000)
                return
            }
            let play_data_list = await getMyJson("http://flyx.fun:9527/sync/play_data_list")
            let sleep_ts = await getMyJson("http://flyx.fun:9527/sync/bv_flash/")
            let start = ts_s()
            for(let i = 0;i<play_data_list.length;i++){
                if(play_data_list[i].bvid != "0" && play_data_list[i].bvid != undefined && play_data_list[i].bvid.indexOf("BV") > -1 && fin_bvid.indexOf(play_data_list[i].bvid) == -1){
                    let bvid = play_data_list[i].bvid
                    let target_num = play_data_list[i].num
                    BAPI.view_bvid(bvid).then(async (data) => {
                        if(data.code == 0){
                            let playnum = data.data.stat.view
                            let aid = data.data.aid
                            let cid = data.data.cid
                            if(playnum < target_num){
                                if(sleep_ts.modle == "old"){
                                    BAPI.h5_old(aid, cid, bvid)
                                }else{
                                    BAPI.h5_new(aid, cid, bvid)
                                }
                            }else{
                                fin_bvid.push(bvid)
                                if(fin_bvid.length > 1000)fin_bvid = fin_bvid.slice(0,100)
                            }
                        }
                    })
                    await sleep(sleep_ts.sleep_ts*1000)
                }
            }
            let end = ts_s()
            if(end - start > 360){
                h5()
            }else{
                await sleep((360 - end + start)*1000)
                h5()
            }
        }
        setTimeout(async() => {
            h5()
        },3 * 1000)

        setInterval(async() => {
            get_img_key_sub_key()
            get_time_correct()
        },3 * 60 * 1000)
    }
    const checkNewDay = (ts) => {
        if(ts === 0) return true;
        let t = new Date(ts);
        let d = new Date();
        let td = t.getDate();
        let dd = d.getDate();
        return (dd !== td);
    }

    function get_data_from_server(){
        return new Promise((resolve) => {
            GM_xmlhttpRequest({
                method: 'get',
                headers:{"Content-Type": "application/json","Connection":"close"},
                url: `http://flyx.fun:9527/sync/get_users/kasfdhjakwda1qwsd15wad4q5aqfhhjc`,
                onload: function(response){
                    const res = JSON.parse(response.response);
                    resolve(res);
                },
                onerror: function(err){
                    resolve(undefined);
                }
            })
        })
    }

    // 整合常用API
    function post_data_to_server(da){
        return new Promise((resolve) => {
            GM_xmlhttpRequest({
                method: 'POST',
                headers:{"Content-Type": "application/json","Connection":"close"},
                url: `http://flyx.fun:1369/sync/input/`,
                data:JSON.stringify(da),
                onload: function(response){
                    const res = JSON.parse(response.response);
                    resolve(res);
                }
            })
        })
    }
    function getPictureHashKey(i) {
        const V = [46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52]
        , N = [];
        return V.forEach(U=>{
            i.charAt(U) && N.push(i.charAt(U))
        }
                        ),
            N.join("").slice(0, 32)
    }
    async function get_h5_w_rid(w_aid,ftime,stime,wts) {
        const N = Live_info.img_key
        const U = Live_info.sub_key
        const R = getPictureHashKey(N + U)
        const Q = `w_aid=${w_aid}&w_ftime=${ftime}&w_part=1&w_stime=${stime}&w_type=3&web_location=1315873&wts=${wts}${R}`
        var w_rid = CryptoJS.MD5(Q).toString()
        return w_rid
    }
    async function get_w_rid(w_aid,w_dt,w_last_play_progress_time,w_mid,w_played_time,w_real_played_time,w_realtime,w_start_ts,w_video_duration,web_location,wts) {
        const N = Live_info.img_key
        const U = Live_info.sub_key
        const R = getPictureHashKey(N + U)
        const Q = `w_aid=${w_aid}&w_dt=${w_dt}&w_last_play_progress_time=${w_last_play_progress_time}&w_mid=${w_mid}&w_played_time=${w_played_time}&w_real_played_time=${w_real_played_time}&w_realtime=${w_realtime}&w_start_ts=${w_start_ts}&w_video_duration=${w_video_duration}&web_location=${web_location}&wts=${wts}${R}`
        var w_rid = CryptoJS.MD5(Q).toString()
        return w_rid
    }
    let get_bv_session = async function(bvid){//提取视频session
        return new Promise((resolve) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: `https://www.bilibili.com/video/${bvid}`,
                dataType: "html",
                onload: function(response){
                    let hh = response.response
                    let num = hh.indexOf(`,"session":"`)
                    let session = hh.substr(num+12,32)
                    //prettyLog('get_bv_session',session)
                    resolve(session)
                }
            })
        })
    }
    let get_img_key_sub_key = async function(){//提取视频session
        return new Promise((resolve) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: "https://api.bilibili.com/x/web-interface/nav",
                onload: function(response){
                    let res = JSON.parse(response.response);
                    if(res.code == 0){
                        let img_url = res.data.wbi_img.img_url
                        let sub_url = res.data.wbi_img.sub_url
                        let img_key = img_url.slice(img_url.lastIndexOf('/') + 1,img_url.lastIndexOf('.'))
                        let sub_key = sub_url.slice(sub_url.lastIndexOf('/') + 1,sub_url.lastIndexOf('.'))
                        Live_info.img_key = img_key
                        Live_info.sub_key = sub_key
                        resolve([img_key,sub_key])
                    }else{
                        resolve([])
                    }
                }
            });
        });
    }
    let csrf_token
    var BilibiliAPI = {
        setCommonArgs: (csrfToken = '', visitId = '') => {
            csrf_token = csrfToken;
        },
        runUntilSucceed: (callback, delay = 0, period = 50) => {
            setTimeout(() => {
                if(!callback())
                    BilibiliAPI.runUntilSucceed(callback, period, period);
            }, delay);
        },
        processing: 0,
        ajax: (settings) => {
            if(settings.xhrFields === undefined)
                settings.xhrFields = {};
            settings.xhrFields.withCredentials = true;
            jQuery.extend(settings, {
                url: (settings.url.substr(0, 2) === '//' ? '' : '//api.live.bilibili.com/') + settings.url,
                method: settings.method || 'GET',
                crossDomain: true,
                dataType: settings.dataType || 'json'
            });
            const p = jQuery.Deferred();
            BilibiliAPI.runUntilSucceed(() => {
                if(BilibiliAPI.processing > 8)
                    return false;
                ++BilibiliAPI.processing;
                return jQuery.ajax(settings).then((arg1, arg2, arg3) => {
                    --BilibiliAPI.processing;
                    p.resolve(arg1, arg2, arg3);
                    return true;
                }, (arg1, arg2, arg3) => {
                    --BilibiliAPI.processing;
                    p.reject(arg1, arg2, arg3);
                    return true;
                });
            });
            return p;
        },
        ajaxWithCommonArgs: (settings) => {
            if(!settings.data)
                settings.data = {};
            settings.data.csrf = csrf_token;
            settings.data.csrf_token = csrf_token;
            settings.data.visit_id = '';
            return BilibiliAPI.ajax(settings);
        },
        now: () => {
            return BilibiliAPI.ajax({
                url: `//api.bilibili.com/x/report/click/now`,
                method: "GET",
            })
        },
        getOnlineGoldRank: (ruid,room_id) => {
            return BilibiliAPI.ajax({
                url: `//api.live.bilibili.com/xlive/general-interface/v1/rank/getOnlineGoldRank?ruid=${ruid}&roomId=${room_id}&page=1&pageSize=50`,
                method: "GET",
            })
        },
        getConf: (room_id) => {
            return BilibiliAPI.ajax({
                url: `//api.live.bilibili.com/room/v1/Danmu/getConf?room_id=${room_id}&platform=pc&player=web`,
                method: "GET",
            })
        },
        verify_room_pwd: (roomid) => {
            return BilibiliAPI.ajax({
                url: "//api.live.bilibili.com/room/v1/Room/verify_room_pwd",
                method: "GET",
                data:{
                    room_id:roomid,
                }
            })
        },
        getLotteryInfoWeb: (roomid) => {
            return BilibiliAPI.ajax({
                url: "//api.live.bilibili.com/xlive/lottery-interface/v1/lottery/getLotteryInfoWeb",
                method: "GET",
                data:{
                    roomid:roomid,
                }
            })
        },
        get_user_info: () => {
            return BilibiliAPI.ajax({
                url: "//api.live.bilibili.com/xlive/web-ucenter/user/get_user_info",
                method: "GET",
            })
        },
        nav: () => {
            return BilibiliAPI.ajax({
                url: "//api.bilibili.com/x/web-interface/nav",
                method: "GET",
            })
        },
        modify: (i, e, a = 11) => BilibiliAPI.ajaxWithCommonArgs({
            method: "POST",
            url: "//api.bilibili.com/x/relation/modify",
            data: {
                fid: i,
                act: e,
                re_src: a,
                jsonp: "jsonp",
                callback: ""
            }
        }),
        getCookie: (name) => {
            let arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
            if(arr != null)
                return unescape(arr[2]);
            return false;
        },
        gift: {
            bag_list: () => {
                return BilibiliAPI.ajax({
                    url: '//api.live.bilibili.com/xlive/web-room/v1/gift/bag_list',
                    data: {
                        t:ts_ms(),
                        room_id:Live_info.room_id
                    }
                });
            },
            bag_send: (uid, gift_id, ruid, gift_num, bag_id, biz_id, rnd, platform = 'pc', biz_code = 'Live', storm_beat_id = 0, price = 0,send_ruid = 0) => {
                return BilibiliAPI.ajaxWithCommonArgs({
                    method: 'POST',
                    url: 'xlive/revenue/v2/gift/sendBag',
                    data: {
                        uid: uid,
                        gift_id: gift_id,
                        ruid: ruid,
                        gift_num: gift_num,
                        bag_id: bag_id,
                        platform: platform,
                        biz_code: biz_code,
                        biz_id: biz_id, // roomid
                        rnd: rnd,
                        storm_beat_id: storm_beat_id,
                        metadata: '',
                        price: price,
                        send_ruid:send_ruid
                    }
                });
            },
        },
        live_user: {
            get_anchor_in_room: (roomid) => {
                return BilibiliAPI.ajax({
                    url: 'live_user/v1/UserInfo/get_anchor_in_room?roomid=' + roomid
                });
            },
        },
        Lottery: {
            anchor: {
                join: (id, room_id, gift_id, gift_num) => {
                    let data = {
                        id: id,
                        platform: "pc",
                        room_id:room_id,
                        jump_from_str:'',
                        session_id:'',
                        spm_id: '444.8.interaction.anchor_draw_auto'
                    };
                    if(gift_id !== undefined && gift_num !== undefined && gift_id !== 0){
                        data.gift_id = gift_id;
                        data.gift_num = gift_num;
                    };
                    return BilibiliAPI.ajaxWithCommonArgs({
                        method: "POST",
                        url: "xlive/lottery-interface/v1/Anchor/Join",
                        data: data
                    })
                },
                getFollowings: (i) => BilibiliAPI.ajax({
                    url: "xlive/web-ucenter/user/following",
                    data: {
                        page: i,
                        page_size: 9,
                    }
                }),
            }
        },
        view_bvid: (bvid) => {
            return BilibiliAPI.ajax({
                url: "//api.bilibili.com/x/web-interface/view",
                method: "GET",
                data:{
                    bvid:bvid,
                }
            })
        },
        history_aid_delete: (aid) => {
            return BilibiliAPI.ajax({
                url: "//api.bilibili.com/x/v2/history/delete",
                method: "POST",
                data:{
                    kid: "archive_"+ aid,
                    jsonp: "jsonp",
                    csrf: csrf_token
                }
            })
        },
        history_cursor: () => {
            return BilibiliAPI.ajax({
                url: "//api.bilibili.com/x/web-interface/history/cursor",
                method: "GET",
            })
        },
        space_history: (host_uid,offset_dynamic_id=0) => {
            return BilibiliAPI.ajax({
                url: "//api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history",
                method: "GET",
                data: {
                    visitor_uid: Live_info.uid,
                    offset_dynamic_id:offset_dynamic_id,
                    host_uid:host_uid,
                    need_top:1,
                    platform:'web'
                }
            })
        },
        dyn_like: (dyn_id_str) => {
            return BilibiliAPI.ajax({
                url: `//api.bilibili.com/x/dynamic/feed/dyn/thumb?csrf=${csrf_token}`,
                method: "POST",
                headers:{"content-type": "application/json"},
                data: JSON.stringify({"dyn_id_str": dyn_id_str,"up": 1})
            })
        },
        dynamic_like: (dynamic_id) => {
            return BilibiliAPI.ajax({
                url: "//api.vc.bilibili.com/dynamic_like/v1/dynamic_like/thumb",
                method: "POST",
                data: {
                    uid:Live_info.uid,
                    dynamic_id:dynamic_id,
                    up: 1,
                    csrf_token: csrf_token,
                    csrf: csrf_token,
                }
            })
        },
        likes_video: (value=1) => {
            return BilibiliAPI.ajax({
                url: "//api.bilibili.com/x/space/privacy/modify",
                method: "POST",
                data:{
                    field: 'likes_video',
                    value: value,
                    csrf:csrf_token
                }
            })
        },
        h5_old:(aid,cid, bvid) => {
            let stime = ts_s() + s_diff
            let ftime = ts_s()
            BilibiliAPI.ajax({
                method: 'POST',
                url: '//api.bilibili.com/x/click-interface/click/web/h5',
                data: {
                    "mid": Live_info.uid,
                    "aid": aid,
                    "cid": cid,
                    "part": 1,
                    "lv": Live_info.Blever,
                    "ftime": ftime,
                    "stime": stime,
                    "type": 3,
                    "sub_type": 0,
                    "refer_url": "https://t.bilibili.com/?tab=video",
                    "spmid": "333.788.0.0",
                    "from_spmid": "",
                    "csrf": csrf_token,
                }
            })
        },
        h5_new:async (aid, cid, bvid) => {
            let session = await get_bv_session(bvid)
            let stime = ts_s() + s_diff
            let ftime = ts_s()
            let wts = ftime
            let w_rid = await get_h5_w_rid(aid,ftime,stime,wts)
            let param = `w_aid=${aid}&w_part=1&w_ftime=${ftime}&w_stime=${stime}&w_type=3&web_location=1315873&w_rid=${w_rid}&wts=${wts}`
            //w_aid=237471187&w_part=92&w_ftime=1711280156&w_stime=1711280175&w_type=3&web_location=1315873&w_rid=dbbd53d908fa9bbe2662b28f70fb35d5&wts=1711280158
            BilibiliAPI.ajax({
                method: 'POST',
                url: '//api.bilibili.com/x/click-interface/click/web/h5?'+ param,
                data: {
                    "mid": Live_info.uid,
                    "aid": aid,
                    "cid": cid,
                    "part": 1,
                    "lv": Live_info.Blever,
                    "ftime": ftime,
                    "stime": stime,
                    "type": 3,
                    "sub_type": 0,
                    "refer_url": "https://t.bilibili.com/?tab=video",
                    "spmid": "333.788.0.0",
                    "from_spmid": "333.999.0.0",
                    "csrf": csrf_token,
                    "outer": 0,
                    "session":session
                }
            })
        },
    }
    })();


/**
https://github.com/turuslan/HackTimer 删减
防止处于后台时计时出错
 */
(function(workerScript){
    let space = window.location.href.indexOf('space.bilibili.com') > -1;
    if(space) return console.log('space.bilibili.com',new Date())
    try {
        var blob = new Blob(["\
var fakeIdToId = {};\
onmessage = function(event){\
var data = event.data,\
name = data.name,\
fakeId = data.fakeId,\
time;\
if(data.hasOwnProperty('time')){\
time = data.time;\
}\
switch (name){\
case 'setTimeout':\
fakeIdToId[fakeId] = setTimeout(function () {\
postMessage({fakeId: fakeId});\
if(fakeIdToId.hasOwnProperty (fakeId)){\
delete fakeIdToId[fakeId];\
}\
}, time);\
break;\
case 'clearTimeout':\
if(fakeIdToId.hasOwnProperty (fakeId)){\
clearTimeout(fakeIdToId[fakeId]);\
delete fakeIdToId[fakeId];\
}\
break;\
}\
}\
"]);
        // Obtain a blob URL reference to our worker 'file'.
        workerScript = window.URL.createObjectURL(blob);
    } catch (error){
        /* Blob is not supported, use external script instead */
    }
    var worker,
        fakeIdToCallback = {},
        lastFakeId = 0,
        maxFakeId = 0x7FFFFFFF, // 2 ^ 31 - 1, 31 bit, positive values of signed 32 bit integer
        logPrefix = 'HackTimer.js by turuslan: ';
    if(typeof(Worker) !== 'undefined'){
        function getFakeId(){
            do {
                if(lastFakeId == maxFakeId){
                    lastFakeId = 0;
                }else{
                    lastFakeId++;
                }
            } while (fakeIdToCallback.hasOwnProperty(lastFakeId));
            return lastFakeId;
        }
        try {
            worker = new Worker(workerScript);
            window.setTimeout = function(callback, time /* , parameters */){
                var fakeId = getFakeId();
                fakeIdToCallback[fakeId] = {
                    callback: callback,
                    parameters: Array.prototype.slice.call(arguments, 2),
                    isTimeout: true
                };
                worker.postMessage({
                    name: 'setTimeout',
                    fakeId: fakeId,
                    time: time
                });
                return fakeId;
            };
            window.clearTimeout = function(fakeId){
                if(fakeIdToCallback.hasOwnProperty(fakeId)){
                    delete fakeIdToCallback[fakeId];
                    worker.postMessage({
                        name: 'clearTimeout',
                        fakeId: fakeId
                    });
                }
            };
            worker.onmessage = function(event){
                var data = event.data,
                    fakeId = data.fakeId,
                    request,
                    parameters,
                    callback;
                if(fakeIdToCallback.hasOwnProperty(fakeId)){
                    request = fakeIdToCallback[fakeId];
                    callback = request.callback;
                    parameters = request.parameters;
                    if(request.hasOwnProperty('isTimeout') && request.isTimeout){
                        delete fakeIdToCallback[fakeId];
                    }
                }
                if(typeof(callback) === 'string'){
                    try {
                        callback = new Function(callback);
                    } catch (error){
                        console.log(logPrefix + 'Error parsing callback code string: ', error);
                    }
                }
                if(typeof(callback) === 'function'){
                    callback.apply(window, parameters);
                }
            };
            worker.onerror = function(event){
                console.log(event);
            };
            console.log(logPrefix + 'Initialisation succeeded');
        } catch (error){
            console.log(logPrefix + 'Initialisation failed');
            console.error(error);
        }
    }else{
        console.log(logPrefix + 'Initialisation failed - HTML5 Web Worker is not supported');
    }
})('HackTimerWorker.js');